##// END OF EJS Templates
(•̀ᴗ•́)و ̑̑ Some cleaning, remover previous implementation of VariableController...
jeandet -
r1349:3fc54ca0e4e0
parent child
Show More
@@ -1,405 +1,404
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>
37 #include <Visualization/VisualizationController.h>
36 #include <Visualization/VisualizationController.h>
38
37
39 #include <QAction>
38 #include <QAction>
40 #include <QCloseEvent>
39 #include <QCloseEvent>
41 #include <QDate>
40 #include <QDate>
42 #include <QDir>
41 #include <QDir>
43 #include <QFileDialog>
42 #include <QFileDialog>
44 #include <QMessageBox>
43 #include <QMessageBox>
45 #include <QToolBar>
44 #include <QToolBar>
46 #include <QToolButton>
45 #include <QToolButton>
47 #include <memory.h>
46 #include <memory.h>
48
47
49 #include "iostream"
48 #include "iostream"
50
49
51 Q_LOGGING_CATEGORY(LOG_MainWindow, "MainWindow")
50 Q_LOGGING_CATEGORY(LOG_MainWindow, "MainWindow")
52
51
53 namespace {
52 namespace {
54 const auto LEFTMAININSPECTORWIDGETSPLITTERINDEX = 0;
53 const auto LEFTMAININSPECTORWIDGETSPLITTERINDEX = 0;
55 const auto LEFTINSPECTORSIDEPANESPLITTERINDEX = 1;
54 const auto LEFTINSPECTORSIDEPANESPLITTERINDEX = 1;
56 const auto VIEWPLITTERINDEX = 2;
55 const auto VIEWPLITTERINDEX = 2;
57 const auto RIGHTINSPECTORSIDEPANESPLITTERINDEX = 3;
56 const auto RIGHTINSPECTORSIDEPANESPLITTERINDEX = 3;
58 const auto RIGHTMAININSPECTORWIDGETSPLITTERINDEX = 4;
57 const auto RIGHTMAININSPECTORWIDGETSPLITTERINDEX = 4;
59 }
58 }
60
59
61 class MainWindow::MainWindowPrivate {
60 class MainWindow::MainWindowPrivate {
62 public:
61 public:
63 explicit MainWindowPrivate(MainWindow *mainWindow)
62 explicit MainWindowPrivate(MainWindow *mainWindow)
64 : m_LastOpenLeftInspectorSize{},
63 : m_LastOpenLeftInspectorSize{},
65 m_LastOpenRightInspectorSize{},
64 m_LastOpenRightInspectorSize{},
66 m_GeneralSettingsWidget{new SqpSettingsGeneralWidget{mainWindow}},
65 m_GeneralSettingsWidget{new SqpSettingsGeneralWidget{mainWindow}},
67 m_SettingsDialog{new SqpSettingsDialog{mainWindow}},
66 m_SettingsDialog{new SqpSettingsDialog{mainWindow}},
68 m_CatalogExplorer{new CatalogueExplorer{mainWindow}}
67 m_CatalogExplorer{new CatalogueExplorer{mainWindow}}
69 {
68 {
70 }
69 }
71
70
72 QSize m_LastOpenLeftInspectorSize;
71 QSize m_LastOpenLeftInspectorSize;
73 QSize m_LastOpenRightInspectorSize;
72 QSize m_LastOpenRightInspectorSize;
74 /// General settings widget. MainWindow has the ownership
73 /// General settings widget. MainWindow has the ownership
75 SqpSettingsGeneralWidget *m_GeneralSettingsWidget;
74 SqpSettingsGeneralWidget *m_GeneralSettingsWidget;
76 /// Settings dialog. MainWindow has the ownership
75 /// Settings dialog. MainWindow has the ownership
77 SqpSettingsDialog *m_SettingsDialog;
76 SqpSettingsDialog *m_SettingsDialog;
78 /// Catalogue dialog. MainWindow has the ownership
77 /// Catalogue dialog. MainWindow has the ownership
79 CatalogueExplorer *m_CatalogExplorer;
78 CatalogueExplorer *m_CatalogExplorer;
80
79
81 bool checkDataToSave(QWidget *parentWidget);
80 bool checkDataToSave(QWidget *parentWidget);
82 };
81 };
83
82
84 MainWindow::MainWindow(QWidget *parent)
83 MainWindow::MainWindow(QWidget *parent)
85 : QMainWindow{parent},
84 : QMainWindow{parent},
86 m_Ui{new Ui::MainWindow},
85 m_Ui{new Ui::MainWindow},
87 impl{spimpl::make_unique_impl<MainWindowPrivate>(this)}
86 impl{spimpl::make_unique_impl<MainWindowPrivate>(this)}
88 {
87 {
89 m_Ui->setupUi(this);
88 m_Ui->setupUi(this);
90
89
91 m_Ui->splitter->setCollapsible(LEFTINSPECTORSIDEPANESPLITTERINDEX, false);
90 m_Ui->splitter->setCollapsible(LEFTINSPECTORSIDEPANESPLITTERINDEX, false);
92 m_Ui->splitter->setCollapsible(RIGHTINSPECTORSIDEPANESPLITTERINDEX, false);
91 m_Ui->splitter->setCollapsible(RIGHTINSPECTORSIDEPANESPLITTERINDEX, false);
93
92
94 impl->m_CatalogExplorer->setVisualizationWidget(m_Ui->view);
93 impl->m_CatalogExplorer->setVisualizationWidget(m_Ui->view);
95
94
96
95
97 auto leftSidePane = m_Ui->leftInspectorSidePane->sidePane();
96 auto leftSidePane = m_Ui->leftInspectorSidePane->sidePane();
98 auto openLeftInspectorAction = new QAction{QIcon{
97 auto openLeftInspectorAction = new QAction{QIcon{
99 ":/icones/previous.png",
98 ":/icones/previous.png",
100 },
99 },
101 tr("Show/hide the left inspector"), this};
100 tr("Show/hide the left inspector"), this};
102
101
103
102
104 auto spacerLeftTop = new QWidget{};
103 auto spacerLeftTop = new QWidget{};
105 spacerLeftTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
104 spacerLeftTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
106
105
107 auto spacerLeftBottom = new QWidget{};
106 auto spacerLeftBottom = new QWidget{};
108 spacerLeftBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
107 spacerLeftBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
109
108
110 leftSidePane->addWidget(spacerLeftTop);
109 leftSidePane->addWidget(spacerLeftTop);
111 leftSidePane->addAction(openLeftInspectorAction);
110 leftSidePane->addAction(openLeftInspectorAction);
112 leftSidePane->addWidget(spacerLeftBottom);
111 leftSidePane->addWidget(spacerLeftBottom);
113
112
114
113
115 auto rightSidePane = m_Ui->rightInspectorSidePane->sidePane();
114 auto rightSidePane = m_Ui->rightInspectorSidePane->sidePane();
116 auto openRightInspectorAction = new QAction{QIcon{
115 auto openRightInspectorAction = new QAction{QIcon{
117 ":/icones/next.png",
116 ":/icones/next.png",
118 },
117 },
119 tr("Show/hide the right inspector"), this};
118 tr("Show/hide the right inspector"), this};
120
119
121 auto spacerRightTop = new QWidget{};
120 auto spacerRightTop = new QWidget{};
122 spacerRightTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
121 spacerRightTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
123
122
124 auto spacerRightBottom = new QWidget{};
123 auto spacerRightBottom = new QWidget{};
125 spacerRightBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
124 spacerRightBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
126
125
127 rightSidePane->addWidget(spacerRightTop);
126 rightSidePane->addWidget(spacerRightTop);
128 rightSidePane->addAction(openRightInspectorAction);
127 rightSidePane->addAction(openRightInspectorAction);
129 rightSidePane->addWidget(spacerRightBottom);
128 rightSidePane->addWidget(spacerRightBottom);
130
129
131 openLeftInspectorAction->setCheckable(true);
130 openLeftInspectorAction->setCheckable(true);
132 openRightInspectorAction->setCheckable(true);
131 openRightInspectorAction->setCheckable(true);
133
132
134 auto openInspector = [this](bool checked, bool right, auto action) {
133 auto openInspector = [this](bool checked, bool right, auto action) {
135
134
136 action->setIcon(QIcon{(checked ^ right) ? ":/icones/next.png" : ":/icones/previous.png"});
135 action->setIcon(QIcon{(checked ^ right) ? ":/icones/next.png" : ":/icones/previous.png"});
137
136
138 auto &lastInspectorSize
137 auto &lastInspectorSize
139 = right ? impl->m_LastOpenRightInspectorSize : impl->m_LastOpenLeftInspectorSize;
138 = right ? impl->m_LastOpenRightInspectorSize : impl->m_LastOpenLeftInspectorSize;
140
139
141 auto nextInspectorSize = right ? m_Ui->rightMainInspectorWidget->size()
140 auto nextInspectorSize = right ? m_Ui->rightMainInspectorWidget->size()
142 : m_Ui->leftMainInspectorWidget->size();
141 : m_Ui->leftMainInspectorWidget->size();
143
142
144 // Update of the last opened geometry
143 // Update of the last opened geometry
145 if (checked) {
144 if (checked) {
146 lastInspectorSize = nextInspectorSize;
145 lastInspectorSize = nextInspectorSize;
147 }
146 }
148
147
149 auto startSize = lastInspectorSize;
148 auto startSize = lastInspectorSize;
150 auto endSize = startSize;
149 auto endSize = startSize;
151 endSize.setWidth(0);
150 endSize.setWidth(0);
152
151
153 auto splitterInspectorIndex
152 auto splitterInspectorIndex
154 = right ? RIGHTMAININSPECTORWIDGETSPLITTERINDEX : LEFTMAININSPECTORWIDGETSPLITTERINDEX;
153 = right ? RIGHTMAININSPECTORWIDGETSPLITTERINDEX : LEFTMAININSPECTORWIDGETSPLITTERINDEX;
155
154
156 auto currentSizes = m_Ui->splitter->sizes();
155 auto currentSizes = m_Ui->splitter->sizes();
157 if (checked) {
156 if (checked) {
158 // adjust sizes individually here, e.g.
157 // adjust sizes individually here, e.g.
159 currentSizes[splitterInspectorIndex] -= lastInspectorSize.width();
158 currentSizes[splitterInspectorIndex] -= lastInspectorSize.width();
160 currentSizes[VIEWPLITTERINDEX] += lastInspectorSize.width();
159 currentSizes[VIEWPLITTERINDEX] += lastInspectorSize.width();
161 m_Ui->splitter->setSizes(currentSizes);
160 m_Ui->splitter->setSizes(currentSizes);
162 }
161 }
163 else {
162 else {
164 // adjust sizes individually here, e.g.
163 // adjust sizes individually here, e.g.
165 currentSizes[splitterInspectorIndex] += lastInspectorSize.width();
164 currentSizes[splitterInspectorIndex] += lastInspectorSize.width();
166 currentSizes[VIEWPLITTERINDEX] -= lastInspectorSize.width();
165 currentSizes[VIEWPLITTERINDEX] -= lastInspectorSize.width();
167 m_Ui->splitter->setSizes(currentSizes);
166 m_Ui->splitter->setSizes(currentSizes);
168 }
167 }
169
168
170 };
169 };
171
170
172
171
173 connect(openLeftInspectorAction, &QAction::triggered,
172 connect(openLeftInspectorAction, &QAction::triggered,
174 [openInspector, openLeftInspectorAction](bool checked) {
173 [openInspector, openLeftInspectorAction](bool checked) {
175 openInspector(checked, false, openLeftInspectorAction);
174 openInspector(checked, false, openLeftInspectorAction);
176 });
175 });
177 connect(openRightInspectorAction, &QAction::triggered,
176 connect(openRightInspectorAction, &QAction::triggered,
178 [openInspector, openRightInspectorAction](bool checked) {
177 [openInspector, openRightInspectorAction](bool checked) {
179 openInspector(checked, true, openRightInspectorAction);
178 openInspector(checked, true, openRightInspectorAction);
180 });
179 });
181
180
182 // //////////////// //
181 // //////////////// //
183 // Menu and Toolbar //
182 // Menu and Toolbar //
184 // //////////////// //
183 // //////////////// //
185 this->menuBar()->addAction(tr("File"));
184 this->menuBar()->addAction(tr("File"));
186 auto toolsMenu = this->menuBar()->addMenu(tr("Tools"));
185 auto toolsMenu = this->menuBar()->addMenu(tr("Tools"));
187 toolsMenu->addAction(tr("Settings..."), [this]() {
186 toolsMenu->addAction(tr("Settings..."), [this]() {
188 // Loads settings
187 // Loads settings
189 impl->m_SettingsDialog->loadSettings();
188 impl->m_SettingsDialog->loadSettings();
190
189
191 // Open settings dialog and save settings if the dialog is accepted
190 // Open settings dialog and save settings if the dialog is accepted
192 if (impl->m_SettingsDialog->exec() == QDialog::Accepted) {
191 if (impl->m_SettingsDialog->exec() == QDialog::Accepted) {
193 impl->m_SettingsDialog->saveSettings();
192 impl->m_SettingsDialog->saveSettings();
194 }
193 }
195
194
196 });
195 });
197
196
198 auto mainToolBar = this->addToolBar(QStringLiteral("MainToolBar"));
197 auto mainToolBar = this->addToolBar(QStringLiteral("MainToolBar"));
199
198
200 auto timeWidget = new TimeWidget{};
199 auto timeWidget = new TimeWidget{};
201 mainToolBar->addWidget(timeWidget);
200 mainToolBar->addWidget(timeWidget);
202
201
203 // Interaction modes
202 // Interaction modes
204 auto actionPointerMode = new QAction{QIcon(":/icones/pointer.png"), "Move", this};
203 auto actionPointerMode = new QAction{QIcon(":/icones/pointer.png"), "Move", this};
205 actionPointerMode->setCheckable(true);
204 actionPointerMode->setCheckable(true);
206 actionPointerMode->setChecked(sqpApp->plotsInteractionMode()
205 actionPointerMode->setChecked(sqpApp->plotsInteractionMode()
207 == SqpApplication::PlotsInteractionMode::None);
206 == SqpApplication::PlotsInteractionMode::None);
208 connect(actionPointerMode, &QAction::triggered,
207 connect(actionPointerMode, &QAction::triggered,
209 []() { sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::None); });
208 []() { sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::None); });
210
209
211 auto actionZoomMode = new QAction{QIcon(":/icones/zoom.png"), "Zoom", this};
210 auto actionZoomMode = new QAction{QIcon(":/icones/zoom.png"), "Zoom", this};
212 actionZoomMode->setCheckable(true);
211 actionZoomMode->setCheckable(true);
213 actionZoomMode->setChecked(sqpApp->plotsInteractionMode()
212 actionZoomMode->setChecked(sqpApp->plotsInteractionMode()
214 == SqpApplication::PlotsInteractionMode::ZoomBox);
213 == SqpApplication::PlotsInteractionMode::ZoomBox);
215 connect(actionZoomMode, &QAction::triggered, []() {
214 connect(actionZoomMode, &QAction::triggered, []() {
216 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::ZoomBox);
215 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::ZoomBox);
217 });
216 });
218
217
219 auto actionOrganisationMode = new QAction{QIcon(":/icones/drag.png"), "Organize", this};
218 auto actionOrganisationMode = new QAction{QIcon(":/icones/drag.png"), "Organize", this};
220 actionOrganisationMode->setCheckable(true);
219 actionOrganisationMode->setCheckable(true);
221 actionOrganisationMode->setChecked(sqpApp->plotsInteractionMode()
220 actionOrganisationMode->setChecked(sqpApp->plotsInteractionMode()
222 == SqpApplication::PlotsInteractionMode::DragAndDrop);
221 == SqpApplication::PlotsInteractionMode::DragAndDrop);
223 connect(actionOrganisationMode, &QAction::triggered, []() {
222 connect(actionOrganisationMode, &QAction::triggered, []() {
224 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::DragAndDrop);
223 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::DragAndDrop);
225 });
224 });
226
225
227 auto actionZonesMode = new QAction{QIcon(":/icones/rectangle.png"), "Zones", this};
226 auto actionZonesMode = new QAction{QIcon(":/icones/rectangle.png"), "Zones", this};
228 actionZonesMode->setCheckable(true);
227 actionZonesMode->setCheckable(true);
229 actionZonesMode->setChecked(sqpApp->plotsInteractionMode()
228 actionZonesMode->setChecked(sqpApp->plotsInteractionMode()
230 == SqpApplication::PlotsInteractionMode::SelectionZones);
229 == SqpApplication::PlotsInteractionMode::SelectionZones);
231 connect(actionZonesMode, &QAction::triggered, []() {
230 connect(actionZonesMode, &QAction::triggered, []() {
232 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::SelectionZones);
231 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::SelectionZones);
233 });
232 });
234
233
235 auto modeActionGroup = new QActionGroup{this};
234 auto modeActionGroup = new QActionGroup{this};
236 modeActionGroup->addAction(actionZoomMode);
235 modeActionGroup->addAction(actionZoomMode);
237 modeActionGroup->addAction(actionZonesMode);
236 modeActionGroup->addAction(actionZonesMode);
238 modeActionGroup->addAction(actionOrganisationMode);
237 modeActionGroup->addAction(actionOrganisationMode);
239 modeActionGroup->addAction(actionPointerMode);
238 modeActionGroup->addAction(actionPointerMode);
240 modeActionGroup->setExclusive(true);
239 modeActionGroup->setExclusive(true);
241
240
242 mainToolBar->addSeparator();
241 mainToolBar->addSeparator();
243 mainToolBar->addAction(actionPointerMode);
242 mainToolBar->addAction(actionPointerMode);
244 mainToolBar->addAction(actionZoomMode);
243 mainToolBar->addAction(actionZoomMode);
245 mainToolBar->addAction(actionOrganisationMode);
244 mainToolBar->addAction(actionOrganisationMode);
246 mainToolBar->addAction(actionZonesMode);
245 mainToolBar->addAction(actionZonesMode);
247 mainToolBar->addSeparator();
246 mainToolBar->addSeparator();
248
247
249 // Cursors
248 // Cursors
250 auto btnCursor = new QToolButton{this};
249 auto btnCursor = new QToolButton{this};
251 btnCursor->setIcon(QIcon(":/icones/cursor.png"));
250 btnCursor->setIcon(QIcon(":/icones/cursor.png"));
252 btnCursor->setText("Cursor");
251 btnCursor->setText("Cursor");
253 btnCursor->setToolTip("Cursor");
252 btnCursor->setToolTip("Cursor");
254 btnCursor->setPopupMode(QToolButton::InstantPopup);
253 btnCursor->setPopupMode(QToolButton::InstantPopup);
255 auto cursorMenu = new QMenu("CursorMenu", this);
254 auto cursorMenu = new QMenu("CursorMenu", this);
256 btnCursor->setMenu(cursorMenu);
255 btnCursor->setMenu(cursorMenu);
257
256
258 auto noCursorAction = cursorMenu->addAction("No Cursor");
257 auto noCursorAction = cursorMenu->addAction("No Cursor");
259 noCursorAction->setCheckable(true);
258 noCursorAction->setCheckable(true);
260 noCursorAction->setChecked(sqpApp->plotsCursorMode()
259 noCursorAction->setChecked(sqpApp->plotsCursorMode()
261 == SqpApplication::PlotsCursorMode::NoCursor);
260 == SqpApplication::PlotsCursorMode::NoCursor);
262 connect(noCursorAction, &QAction::triggered,
261 connect(noCursorAction, &QAction::triggered,
263 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::NoCursor); });
262 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::NoCursor); });
264
263
265 cursorMenu->addSeparator();
264 cursorMenu->addSeparator();
266 auto verticalCursorAction = cursorMenu->addAction("Vertical Cursor");
265 auto verticalCursorAction = cursorMenu->addAction("Vertical Cursor");
267 verticalCursorAction->setCheckable(true);
266 verticalCursorAction->setCheckable(true);
268 verticalCursorAction->setChecked(sqpApp->plotsCursorMode()
267 verticalCursorAction->setChecked(sqpApp->plotsCursorMode()
269 == SqpApplication::PlotsCursorMode::Vertical);
268 == SqpApplication::PlotsCursorMode::Vertical);
270 connect(verticalCursorAction, &QAction::triggered,
269 connect(verticalCursorAction, &QAction::triggered,
271 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Vertical); });
270 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Vertical); });
272
271
273 auto temporalCursorAction = cursorMenu->addAction("Temporal Cursor");
272 auto temporalCursorAction = cursorMenu->addAction("Temporal Cursor");
274 temporalCursorAction->setCheckable(true);
273 temporalCursorAction->setCheckable(true);
275 temporalCursorAction->setChecked(sqpApp->plotsCursorMode()
274 temporalCursorAction->setChecked(sqpApp->plotsCursorMode()
276 == SqpApplication::PlotsCursorMode::Temporal);
275 == SqpApplication::PlotsCursorMode::Temporal);
277 connect(temporalCursorAction, &QAction::triggered,
276 connect(temporalCursorAction, &QAction::triggered,
278 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Temporal); });
277 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Temporal); });
279
278
280 auto horizontalCursorAction = cursorMenu->addAction("Horizontal Cursor");
279 auto horizontalCursorAction = cursorMenu->addAction("Horizontal Cursor");
281 horizontalCursorAction->setCheckable(true);
280 horizontalCursorAction->setCheckable(true);
282 horizontalCursorAction->setChecked(sqpApp->plotsCursorMode()
281 horizontalCursorAction->setChecked(sqpApp->plotsCursorMode()
283 == SqpApplication::PlotsCursorMode::Horizontal);
282 == SqpApplication::PlotsCursorMode::Horizontal);
284 connect(horizontalCursorAction, &QAction::triggered,
283 connect(horizontalCursorAction, &QAction::triggered,
285 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Horizontal); });
284 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Horizontal); });
286
285
287 auto crossCursorAction = cursorMenu->addAction("Cross Cursor");
286 auto crossCursorAction = cursorMenu->addAction("Cross Cursor");
288 crossCursorAction->setCheckable(true);
287 crossCursorAction->setCheckable(true);
289 crossCursorAction->setChecked(sqpApp->plotsCursorMode()
288 crossCursorAction->setChecked(sqpApp->plotsCursorMode()
290 == SqpApplication::PlotsCursorMode::Cross);
289 == SqpApplication::PlotsCursorMode::Cross);
291 connect(crossCursorAction, &QAction::triggered,
290 connect(crossCursorAction, &QAction::triggered,
292 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Cross); });
291 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Cross); });
293
292
294 mainToolBar->addWidget(btnCursor);
293 mainToolBar->addWidget(btnCursor);
295
294
296 auto cursorModeActionGroup = new QActionGroup{this};
295 auto cursorModeActionGroup = new QActionGroup{this};
297 cursorModeActionGroup->setExclusive(true);
296 cursorModeActionGroup->setExclusive(true);
298 cursorModeActionGroup->addAction(noCursorAction);
297 cursorModeActionGroup->addAction(noCursorAction);
299 cursorModeActionGroup->addAction(verticalCursorAction);
298 cursorModeActionGroup->addAction(verticalCursorAction);
300 cursorModeActionGroup->addAction(temporalCursorAction);
299 cursorModeActionGroup->addAction(temporalCursorAction);
301 cursorModeActionGroup->addAction(horizontalCursorAction);
300 cursorModeActionGroup->addAction(horizontalCursorAction);
302 cursorModeActionGroup->addAction(crossCursorAction);
301 cursorModeActionGroup->addAction(crossCursorAction);
303
302
304 // Catalog
303 // Catalog
305 mainToolBar->addSeparator();
304 mainToolBar->addSeparator();
306 mainToolBar->addAction(QIcon(":/icones/catalogue.png"), "Catalogues",
305 mainToolBar->addAction(QIcon(":/icones/catalogue.png"), "Catalogues",
307 [this]() { impl->m_CatalogExplorer->show(); });
306 [this]() { impl->m_CatalogExplorer->show(); });
308
307
309 // //////// //
308 // //////// //
310 // Settings //
309 // Settings //
311 // //////// //
310 // //////// //
312
311
313 // Registers "general settings" widget to the settings dialog
312 // Registers "general settings" widget to the settings dialog
314 impl->m_SettingsDialog->registerWidget(QStringLiteral("General"),
313 impl->m_SettingsDialog->registerWidget(QStringLiteral("General"),
315 impl->m_GeneralSettingsWidget);
314 impl->m_GeneralSettingsWidget);
316
315
317 // /////////// //
316 // /////////// //
318 // Connections //
317 // Connections //
319 // /////////// //
318 // /////////// //
320
319
321 // Controllers / controllers connections
320 // Controllers / controllers connections
322 // connect(&sqpApp->timeController(), SIGNAL(timeUpdated(DateTimeRange)), &sqpApp->variableController(),
321 // connect(&sqpApp->timeController(), SIGNAL(timeUpdated(DateTimeRange)), &sqpApp->variableController(),
323 // SLOT(onDateTimeOnSelection(DateTimeRange)));
322 // SLOT(onDateTimeOnSelection(DateTimeRange)));
324
323
325 // Widgets / controllers connections
324 // Widgets / controllers connections
326
325
327 // DataSource
326 // DataSource
328 connect(&sqpApp->dataSourceController(), SIGNAL(dataSourceItemSet(DataSourceItem *)),
327 connect(&sqpApp->dataSourceController(), SIGNAL(dataSourceItemSet(DataSourceItem *)),
329 m_Ui->dataSourceWidget, SLOT(addDataSource(DataSourceItem *)));
328 m_Ui->dataSourceWidget, SLOT(addDataSource(DataSourceItem *)));
330
329
331 // Time
330 // Time
332 connect(timeWidget, SIGNAL(timeUpdated(DateTimeRange)), &sqpApp->timeController(),
331 connect(timeWidget, SIGNAL(timeUpdated(DateTimeRange)), &sqpApp->timeController(),
333 SLOT(onTimeToUpdate(DateTimeRange)));
332 SLOT(onTimeToUpdate(DateTimeRange)));
334
333
335 // Visualization
334 // Visualization
336 connect(&sqpApp->visualizationController(),
335 connect(&sqpApp->visualizationController(),
337 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), m_Ui->view,
336 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), m_Ui->view,
338 SLOT(onVariableAboutToBeDeleted(std::shared_ptr<Variable>)));
337 SLOT(onVariableAboutToBeDeleted(std::shared_ptr<Variable>)));
339
338
340 connect(&sqpApp->visualizationController(),
339 connect(&sqpApp->visualizationController(),
341 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const DateTimeRange &)), m_Ui->view,
340 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const DateTimeRange &)), m_Ui->view,
342 SLOT(onRangeChanged(std::shared_ptr<Variable>, const DateTimeRange &)));
341 SLOT(onRangeChanged(std::shared_ptr<Variable>, const DateTimeRange &)));
343
342
344 // Widgets / widgets connections
343 // Widgets / widgets connections
345
344
346 // For the following connections, we use DirectConnection to allow each widget that can
345 // 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.
346 // 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
347 // The order of connections is also important, since it determines the order in which each
349 // widget will attach its menu
348 // widget will attach its menu
350 connect(
349 connect(
351 m_Ui->variableInspectorWidget,
350 m_Ui->variableInspectorWidget,
352 SIGNAL(tableMenuAboutToBeDisplayed(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
351 SIGNAL(tableMenuAboutToBeDisplayed(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
353 m_Ui->view, SLOT(attachVariableMenu(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
352 m_Ui->view, SLOT(attachVariableMenu(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
354 Qt::DirectConnection);
353 Qt::DirectConnection);
355 }
354 }
356
355
357 MainWindow::~MainWindow()
356 MainWindow::~MainWindow()
358 {
357 {
359 }
358 }
360
359
361 void MainWindow::changeEvent(QEvent *e)
360 void MainWindow::changeEvent(QEvent *e)
362 {
361 {
363 QMainWindow::changeEvent(e);
362 QMainWindow::changeEvent(e);
364 switch (e->type()) {
363 switch (e->type()) {
365 case QEvent::LanguageChange:
364 case QEvent::LanguageChange:
366 m_Ui->retranslateUi(this);
365 m_Ui->retranslateUi(this);
367 break;
366 break;
368 default:
367 default:
369 break;
368 break;
370 }
369 }
371 }
370 }
372
371
373 void MainWindow::closeEvent(QCloseEvent *event)
372 void MainWindow::closeEvent(QCloseEvent *event)
374 {
373 {
375 if (!impl->checkDataToSave(this)) {
374 if (!impl->checkDataToSave(this)) {
376 event->ignore();
375 event->ignore();
377 }
376 }
378 else {
377 else {
379 event->accept();
378 event->accept();
380 }
379 }
381 }
380 }
382
381
383 bool MainWindow::MainWindowPrivate::checkDataToSave(QWidget *parentWidget)
382 bool MainWindow::MainWindowPrivate::checkDataToSave(QWidget *parentWidget)
384 {
383 {
385 auto hasChanges = sqpApp->catalogueController().hasChanges();
384 auto hasChanges = sqpApp->catalogueController().hasChanges();
386 if (hasChanges) {
385 if (hasChanges) {
387 // There are some unsaved changes
386 // There are some unsaved changes
388 switch (QMessageBox::question(
387 switch (QMessageBox::question(
389 parentWidget, tr("Save changes"),
388 parentWidget, tr("Save changes"),
390 tr("The catalogue controller has unsaved changes.\nDo you want to save them ?"),
389 tr("The catalogue controller has unsaved changes.\nDo you want to save them ?"),
391 QMessageBox::SaveAll | QMessageBox::Discard | QMessageBox::Cancel,
390 QMessageBox::SaveAll | QMessageBox::Discard | QMessageBox::Cancel,
392 QMessageBox::SaveAll)) {
391 QMessageBox::SaveAll)) {
393 case QMessageBox::SaveAll:
392 case QMessageBox::SaveAll:
394 sqpApp->catalogueController().saveAll();
393 sqpApp->catalogueController().saveAll();
395 break;
394 break;
396 case QMessageBox::Discard:
395 case QMessageBox::Discard:
397 break;
396 break;
398 case QMessageBox::Cancel:
397 case QMessageBox::Cancel:
399 default:
398 default:
400 return false;
399 return false;
401 }
400 }
402 }
401 }
403
402
404 return true;
403 return true;
405 }
404 }
@@ -1,1 +1,1
1 Subproject commit 5f4f9560990ba00394322fa1d06d4a30feaf7075
1 Subproject commit de55e7be90966d1efbd34a10df9a3231c50e245b
@@ -1,616 +1,615
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>
9 #include <DBEventProduct.h>
10 #include <DataSource/DataSourceController.h>
10 #include <DataSource/DataSourceController.h>
11 #include <DataSource/DataSourceItem.h>
11 #include <DataSource/DataSourceItem.h>
12 #include <SqpApplication.h>
12 #include <SqpApplication.h>
13 #include <Variable/Variable.h>
13 #include <Variable/Variable.h>
14 #include <Variable/VariableController.h>
15 #include <Variable/VariableController2.h>
14 #include <Variable/VariableController2.h>
16 #include <Visualization/VisualizationGraphWidget.h>
15 #include <Visualization/VisualizationGraphWidget.h>
17 #include <Visualization/VisualizationTabWidget.h>
16 #include <Visualization/VisualizationTabWidget.h>
18 #include <Visualization/VisualizationWidget.h>
17 #include <Visualization/VisualizationWidget.h>
19 #include <Visualization/VisualizationZoneWidget.h>
18 #include <Visualization/VisualizationZoneWidget.h>
20
19
21 #include <QActionGroup>
20 #include <QActionGroup>
22 #include <QDialog>
21 #include <QDialog>
23 #include <QDialogButtonBox>
22 #include <QDialogButtonBox>
24 #include <QKeyEvent>
23 #include <QKeyEvent>
25 #include <QListWidget>
24 #include <QListWidget>
26 #include <QMenu>
25 #include <QMenu>
27 #include <QMessageBox>
26 #include <QMessageBox>
28
27
29 Q_LOGGING_CATEGORY(LOG_CatalogueEventsWidget, "CatalogueEventsWidget")
28 Q_LOGGING_CATEGORY(LOG_CatalogueEventsWidget, "CatalogueEventsWidget")
30
29
31 /// Percentage added to the range of a event when it is displayed
30 /// Percentage added to the range of a event when it is displayed
32 const auto EVENT_RANGE_MARGE = 30; // in %
31 const auto EVENT_RANGE_MARGE = 30; // in %
33
32
34 const QString NEW_ZONE_TEXT = QStringLiteral("New Zone");
33 const QString NEW_ZONE_TEXT = QStringLiteral("New Zone");
35
34
36 struct CatalogueEventsWidget::CatalogueEventsWidgetPrivate {
35 struct CatalogueEventsWidget::CatalogueEventsWidgetPrivate {
37
36
38 CatalogueEventsModel *m_Model = nullptr;
37 CatalogueEventsModel *m_Model = nullptr;
39 QStringList m_ZonesForTimeMode;
38 QStringList m_ZonesForTimeMode;
40 QString m_ZoneForGraphMode;
39 QString m_ZoneForGraphMode;
41 QVector<std::shared_ptr<DBCatalogue> > m_DisplayedCatalogues;
40 QVector<std::shared_ptr<DBCatalogue> > m_DisplayedCatalogues;
42 bool m_AllEventDisplayed = false;
41 bool m_AllEventDisplayed = false;
43 QVector<VisualizationGraphWidget *> m_CustomGraphs;
42 QVector<VisualizationGraphWidget *> m_CustomGraphs;
44
43
45 VisualizationWidget *m_VisualizationWidget = nullptr;
44 VisualizationWidget *m_VisualizationWidget = nullptr;
46
45
47 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events, CatalogueEventsWidget *widget)
46 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events, CatalogueEventsWidget *widget)
48 {
47 {
49 widget->ui->treeView->setSortingEnabled(false);
48 widget->ui->treeView->setSortingEnabled(false);
50 m_Model->setSourceCatalogues(m_DisplayedCatalogues);
49 m_Model->setSourceCatalogues(m_DisplayedCatalogues);
51 m_Model->setEvents(events);
50 m_Model->setEvents(events);
52 widget->ui->treeView->setSortingEnabled(true);
51 widget->ui->treeView->setSortingEnabled(true);
53
52
54 for (auto event : events) {
53 for (auto event : events) {
55 if (sqpApp->catalogueController().eventHasChanges(event)) {
54 if (sqpApp->catalogueController().eventHasChanges(event)) {
56 auto index = m_Model->indexOf(event);
55 auto index = m_Model->indexOf(event);
57 widget->setEventChanges(event, true);
56 widget->setEventChanges(event, true);
58 }
57 }
59 }
58 }
60 }
59 }
61
60
62 void addEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
61 void addEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
63 {
62 {
64 treeView->setSortingEnabled(false);
63 treeView->setSortingEnabled(false);
65 m_Model->addEvent(event);
64 m_Model->addEvent(event);
66 treeView->setSortingEnabled(true);
65 treeView->setSortingEnabled(true);
67 }
66 }
68
67
69 void removeEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
68 void removeEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
70 {
69 {
71 treeView->setSortingEnabled(false);
70 treeView->setSortingEnabled(false);
72 m_Model->removeEvent(event);
71 m_Model->removeEvent(event);
73 treeView->setSortingEnabled(true);
72 treeView->setSortingEnabled(true);
74 }
73 }
75
74
76 QStringList getAvailableVisualizationZoneList() const
75 QStringList getAvailableVisualizationZoneList() const
77 {
76 {
78 if (m_VisualizationWidget) {
77 if (m_VisualizationWidget) {
79 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
78 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
80 return tab->availableZoneWidgets();
79 return tab->availableZoneWidgets();
81 }
80 }
82 }
81 }
83
82
84 return QStringList{};
83 return QStringList{};
85 }
84 }
86
85
87 QStringList selectZone(QWidget *parent, const QStringList &selectedZones,
86 QStringList selectZone(QWidget *parent, const QStringList &selectedZones,
88 bool allowMultiSelection, bool addNewZoneOption, const QPoint &location)
87 bool allowMultiSelection, bool addNewZoneOption, const QPoint &location)
89 {
88 {
90 auto availableZones = getAvailableVisualizationZoneList();
89 auto availableZones = getAvailableVisualizationZoneList();
91 if (!addNewZoneOption && availableZones.isEmpty()) {
90 if (!addNewZoneOption && availableZones.isEmpty()) {
92 return QStringList{};
91 return QStringList{};
93 }
92 }
94
93
95 QActionGroup actionGroup{parent};
94 QActionGroup actionGroup{parent};
96 actionGroup.setExclusive(!allowMultiSelection);
95 actionGroup.setExclusive(!allowMultiSelection);
97
96
98 QVector<QAction *> zoneActions;
97 QVector<QAction *> zoneActions;
99
98
100 QMenu selectionMenu{parent};
99 QMenu selectionMenu{parent};
101
100
102 if (addNewZoneOption) {
101 if (addNewZoneOption) {
103 availableZones.prepend(NEW_ZONE_TEXT);
102 availableZones.prepend(NEW_ZONE_TEXT);
104 }
103 }
105
104
106 selectionMenu.addSeparator();
105 selectionMenu.addSeparator();
107 for (auto zone : availableZones) {
106 for (auto zone : availableZones) {
108 auto zoneAction = selectionMenu.addAction(zone);
107 auto zoneAction = selectionMenu.addAction(zone);
109 zoneAction->setCheckable(true);
108 zoneAction->setCheckable(true);
110 zoneAction->setChecked(selectedZones.contains(zone));
109 zoneAction->setChecked(selectedZones.contains(zone));
111 actionGroup.addAction(zoneAction);
110 actionGroup.addAction(zoneAction);
112 zoneActions << zoneAction;
111 zoneActions << zoneAction;
113 }
112 }
114
113
115 auto resultAction = selectionMenu.exec(QCursor::pos());
114 auto resultAction = selectionMenu.exec(QCursor::pos());
116
115
117 QStringList result;
116 QStringList result;
118
117
119 if (resultAction == nullptr) {
118 if (resultAction == nullptr) {
120 result = selectedZones;
119 result = selectedZones;
121 }
120 }
122 else {
121 else {
123 for (auto zoneAction : zoneActions) {
122 for (auto zoneAction : zoneActions) {
124 if (zoneAction->isChecked()) {
123 if (zoneAction->isChecked()) {
125 result << zoneAction->text();
124 result << zoneAction->text();
126 }
125 }
127 }
126 }
128 }
127 }
129
128
130 return result;
129 return result;
131 }
130 }
132
131
133 void updateForTimeMode(QTreeView *treeView)
132 void updateForTimeMode(QTreeView *treeView)
134 {
133 {
135 auto selectedRows = treeView->selectionModel()->selectedRows();
134 auto selectedRows = treeView->selectionModel()->selectedRows();
136
135
137 if (selectedRows.count() == 1) {
136 if (selectedRows.count() == 1) {
138 auto event = m_Model->getEvent(selectedRows.first());
137 auto event = m_Model->getEvent(selectedRows.first());
139 if (event) {
138 if (event) {
140 if (m_VisualizationWidget) {
139 if (m_VisualizationWidget) {
141 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
140 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
142
141
143 for (auto zoneName : m_ZonesForTimeMode) {
142 for (auto zoneName : m_ZonesForTimeMode) {
144 if (auto zone = tab->getZoneWithName(zoneName)) {
143 if (auto zone = tab->getZoneWithName(zoneName)) {
145 DateTimeRange eventRange;
144 DateTimeRange eventRange;
146 eventRange.m_TStart = event->getTStart();
145 eventRange.m_TStart = event->getTStart();
147 eventRange.m_TEnd = event->getTEnd();
146 eventRange.m_TEnd = event->getTEnd();
148 zone->setZoneRange(eventRange);
147 zone->setZoneRange(eventRange);
149 }
148 }
150 }
149 }
151 }
150 }
152 else {
151 else {
153 qCWarning(LOG_CatalogueEventsWidget())
152 qCWarning(LOG_CatalogueEventsWidget())
154 << "updateTimeZone: no tab found in the visualization";
153 << "updateTimeZone: no tab found in the visualization";
155 }
154 }
156 }
155 }
157 else {
156 else {
158 qCWarning(LOG_CatalogueEventsWidget())
157 qCWarning(LOG_CatalogueEventsWidget())
159 << "updateTimeZone: visualization widget not found";
158 << "updateTimeZone: visualization widget not found";
160 }
159 }
161 }
160 }
162 }
161 }
163 else {
162 else {
164 qCWarning(LOG_CatalogueEventsWidget())
163 qCWarning(LOG_CatalogueEventsWidget())
165 << "updateTimeZone: not compatible with multiple events selected";
164 << "updateTimeZone: not compatible with multiple events selected";
166 }
165 }
167 }
166 }
168
167
169 QVector<DateTimeRange> getGraphRanges(const std::shared_ptr<DBEvent> &event)
168 QVector<DateTimeRange> getGraphRanges(const std::shared_ptr<DBEvent> &event)
170 {
169 {
171 // Retrieves the range of each product and the maximum size
170 // Retrieves the range of each product and the maximum size
172 QVector<DateTimeRange> graphRanges;
171 QVector<DateTimeRange> graphRanges;
173 double maxDt = 0;
172 double maxDt = 0;
174 for (auto eventProduct : event->getEventProducts()) {
173 for (auto eventProduct : event->getEventProducts()) {
175 DateTimeRange eventRange;
174 DateTimeRange eventRange;
176 eventRange.m_TStart = eventProduct.getTStart();
175 eventRange.m_TStart = eventProduct.getTStart();
177 eventRange.m_TEnd = eventProduct.getTEnd();
176 eventRange.m_TEnd = eventProduct.getTEnd();
178 graphRanges << eventRange;
177 graphRanges << eventRange;
179
178
180 auto dt = eventRange.m_TEnd - eventRange.m_TStart;
179 auto dt = eventRange.m_TEnd - eventRange.m_TStart;
181 if (dt > maxDt) {
180 if (dt > maxDt) {
182 maxDt = dt;
181 maxDt = dt;
183 }
182 }
184 }
183 }
185
184
186 // Adds the marge
185 // Adds the marge
187 maxDt *= (100.0 + EVENT_RANGE_MARGE) / 100.0;
186 maxDt *= (100.0 + EVENT_RANGE_MARGE) / 100.0;
188
187
189 // Corrects the graph ranges so that they all have the same size
188 // Corrects the graph ranges so that they all have the same size
190 QVector<DateTimeRange> correctedGraphRanges;
189 QVector<DateTimeRange> correctedGraphRanges;
191 for (auto range : graphRanges) {
190 for (auto range : graphRanges) {
192 auto dt = range.m_TEnd - range.m_TStart;
191 auto dt = range.m_TEnd - range.m_TStart;
193 auto diff = qAbs((maxDt - dt) / 2.0);
192 auto diff = qAbs((maxDt - dt) / 2.0);
194
193
195 DateTimeRange correctedRange;
194 DateTimeRange correctedRange;
196 correctedRange.m_TStart = range.m_TStart - diff;
195 correctedRange.m_TStart = range.m_TStart - diff;
197 correctedRange.m_TEnd = range.m_TEnd + diff;
196 correctedRange.m_TEnd = range.m_TEnd + diff;
198
197
199 correctedGraphRanges << correctedRange;
198 correctedGraphRanges << correctedRange;
200 }
199 }
201
200
202 return correctedGraphRanges;
201 return correctedGraphRanges;
203 }
202 }
204
203
205 void updateForGraphMode(CatalogueEventsWidget *catalogueEventWidget)
204 void updateForGraphMode(CatalogueEventsWidget *catalogueEventWidget)
206 {
205 {
207 auto selectedRows = catalogueEventWidget->ui->treeView->selectionModel()->selectedRows();
206 auto selectedRows = catalogueEventWidget->ui->treeView->selectionModel()->selectedRows();
208 if (selectedRows.count() != 1) {
207 if (selectedRows.count() != 1) {
209 qCWarning(LOG_CatalogueEventsWidget())
208 qCWarning(LOG_CatalogueEventsWidget())
210 << "updateGraphMode: not compatible with multiple events selected";
209 << "updateGraphMode: not compatible with multiple events selected";
211 return;
210 return;
212 }
211 }
213
212
214 if (!m_VisualizationWidget) {
213 if (!m_VisualizationWidget) {
215 qCWarning(LOG_CatalogueEventsWidget())
214 qCWarning(LOG_CatalogueEventsWidget())
216 << "updateGraphMode: visualization widget not found";
215 << "updateGraphMode: visualization widget not found";
217 return;
216 return;
218 }
217 }
219
218
220 auto event = m_Model->getEvent(selectedRows.first());
219 auto event = m_Model->getEvent(selectedRows.first());
221 if (!event) {
220 if (!event) {
222 // A event product is probably selected
221 // A event product is probably selected
223 qCInfo(LOG_CatalogueEventsWidget()) << "updateGraphMode: no events are selected";
222 qCInfo(LOG_CatalogueEventsWidget()) << "updateGraphMode: no events are selected";
224 return;
223 return;
225 }
224 }
226
225
227 auto tab = m_VisualizationWidget->currentTabWidget();
226 auto tab = m_VisualizationWidget->currentTabWidget();
228 if (!tab) {
227 if (!tab) {
229 qCWarning(LOG_CatalogueEventsWidget())
228 qCWarning(LOG_CatalogueEventsWidget())
230 << "updateGraphMode: no tab found in the visualization";
229 << "updateGraphMode: no tab found in the visualization";
231 return;
230 return;
232 }
231 }
233
232
234 auto isNewZone = m_ZoneForGraphMode == NEW_ZONE_TEXT;
233 auto isNewZone = m_ZoneForGraphMode == NEW_ZONE_TEXT;
235 auto zone = tab->getZoneWithName(m_ZoneForGraphMode);
234 auto zone = tab->getZoneWithName(m_ZoneForGraphMode);
236 if (!isNewZone && !zone) {
235 if (!isNewZone && !zone) {
237 qCWarning(LOG_CatalogueEventsWidget()) << "updateGraphMode: zone not found";
236 qCWarning(LOG_CatalogueEventsWidget()) << "updateGraphMode: zone not found";
238 return;
237 return;
239 }
238 }
240
239
241 // Closes the previous graph and delete the asociated variables
240 // Closes the previous graph and delete the asociated variables
242 for (auto graph : m_CustomGraphs) {
241 for (auto graph : m_CustomGraphs) {
243 graph->close();
242 graph->close();
244 auto variables = graph->variables();
243 auto variables = graph->variables();
245 for(const auto& variable:variables)
244 for(const auto& variable:variables)
246 sqpApp->variableController().deleteVariable(variable);
245 sqpApp->variableController().deleteVariable(variable);
247 }
246 }
248 m_CustomGraphs.clear();
247 m_CustomGraphs.clear();
249
248
250 // Closes the remaining graphs inside the zone
249 // Closes the remaining graphs inside the zone
251 if (zone) {
250 if (zone) {
252 zone->closeAllGraphs();
251 zone->closeAllGraphs();
253 }
252 }
254
253
255 // Creates the zone if needed
254 // Creates the zone if needed
256 if (isNewZone) {
255 if (isNewZone) {
257 zone = tab->createEmptyZone(0);
256 zone = tab->createEmptyZone(0);
258 m_ZoneForGraphMode = zone->name();
257 m_ZoneForGraphMode = zone->name();
259 }
258 }
260
259
261 // Calculates the range of each graph which will be created
260 // Calculates the range of each graph which will be created
262 auto graphRange = getGraphRanges(event);
261 auto graphRange = getGraphRanges(event);
263
262
264 // Loops through the event products and create the graph
263 // Loops through the event products and create the graph
265 auto itRange = graphRange.cbegin();
264 auto itRange = graphRange.cbegin();
266 for (auto eventProduct : event->getEventProducts()) {
265 for (auto eventProduct : event->getEventProducts()) {
267 auto productId = eventProduct.getProductId();
266 auto productId = eventProduct.getProductId();
268
267
269 auto range = *itRange;
268 auto range = *itRange;
270 ++itRange;
269 ++itRange;
271
270
272 DateTimeRange productRange;
271 DateTimeRange productRange;
273 productRange.m_TStart = eventProduct.getTStart();
272 productRange.m_TStart = eventProduct.getTStart();
274 productRange.m_TEnd = eventProduct.getTEnd();
273 productRange.m_TEnd = eventProduct.getTEnd();
275
274
276 auto context = new QObject{catalogueEventWidget};
275 auto context = new QObject{catalogueEventWidget};
277 QObject::connect(
276 QObject::connect(
278 &sqpApp->variableController(), &VariableController2::variableAdded, context,
277 &sqpApp->variableController(), &VariableController2::variableAdded, context,
279 [this, catalogueEventWidget, zone, context, event, range, productRange,
278 [this, catalogueEventWidget, zone, context, event, range, productRange,
280 productId](auto variable) {
279 productId](auto variable) {
281
280
282 if (variable->metadata().value(DataSourceItem::ID_DATA_KEY).toString()
281 if (variable->metadata().value(DataSourceItem::ID_DATA_KEY).toString()
283 == productId) {
282 == productId) {
284 auto graph = zone->createGraph(variable);
283 auto graph = zone->createGraph(variable);
285 graph->setAutoRangeOnVariableInitialization(false);
284 graph->setAutoRangeOnVariableInitialization(false);
286
285
287 auto selectionZone
286 auto selectionZone
288 = graph->addSelectionZone(event->getName(), productRange);
287 = graph->addSelectionZone(event->getName(), productRange);
289 emit catalogueEventWidget->selectionZoneAdded(event, productId,
288 emit catalogueEventWidget->selectionZoneAdded(event, productId,
290 selectionZone);
289 selectionZone);
291 m_CustomGraphs << graph;
290 m_CustomGraphs << graph;
292
291
293 graph->setGraphRange(range, true);
292 graph->setGraphRange(range, true);
294
293
295 // Removes the graph from the graph list if it is closed manually
294 // Removes the graph from the graph list if it is closed manually
296 QObject::connect(graph, &VisualizationGraphWidget::destroyed,
295 QObject::connect(graph, &VisualizationGraphWidget::destroyed,
297 [this, graph]() { m_CustomGraphs.removeAll(graph); });
296 [this, graph]() { m_CustomGraphs.removeAll(graph); });
298
297
299 delete context; // removes the connection
298 delete context; // removes the connection
300 }
299 }
301 },
300 },
302 Qt::QueuedConnection);
301 Qt::QueuedConnection);
303
302
304 QMetaObject::invokeMethod(&sqpApp->dataSourceController(),
303 QMetaObject::invokeMethod(&sqpApp->dataSourceController(),
305 "requestVariableFromProductIdKey", Qt::QueuedConnection,
304 "requestVariableFromProductIdKey", Qt::QueuedConnection,
306 Q_ARG(QString, productId));
305 Q_ARG(QString, productId));
307 }
306 }
308 }
307 }
309
308
310 void getSelectedItems(
309 void getSelectedItems(
311 QTreeView *treeView, QVector<std::shared_ptr<DBEvent> > &events,
310 QTreeView *treeView, QVector<std::shared_ptr<DBEvent> > &events,
312 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > &eventProducts)
311 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > &eventProducts)
313 {
312 {
314 for (auto rowIndex : treeView->selectionModel()->selectedRows()) {
313 for (auto rowIndex : treeView->selectionModel()->selectedRows()) {
315 auto itemType = m_Model->itemTypeOf(rowIndex);
314 auto itemType = m_Model->itemTypeOf(rowIndex);
316 if (itemType == CatalogueEventsModel::ItemType::Event) {
315 if (itemType == CatalogueEventsModel::ItemType::Event) {
317 events << m_Model->getEvent(rowIndex);
316 events << m_Model->getEvent(rowIndex);
318 }
317 }
319 else if (itemType == CatalogueEventsModel::ItemType::EventProduct) {
318 else if (itemType == CatalogueEventsModel::ItemType::EventProduct) {
320 eventProducts << qMakePair(m_Model->getParentEvent(rowIndex),
319 eventProducts << qMakePair(m_Model->getParentEvent(rowIndex),
321 m_Model->getEventProduct(rowIndex));
320 m_Model->getEventProduct(rowIndex));
322 }
321 }
323 }
322 }
324 }
323 }
325 };
324 };
326
325
327 CatalogueEventsWidget::CatalogueEventsWidget(QWidget *parent)
326 CatalogueEventsWidget::CatalogueEventsWidget(QWidget *parent)
328 : QWidget(parent),
327 : QWidget(parent),
329 ui(new Ui::CatalogueEventsWidget),
328 ui(new Ui::CatalogueEventsWidget),
330 impl{spimpl::make_unique_impl<CatalogueEventsWidgetPrivate>()}
329 impl{spimpl::make_unique_impl<CatalogueEventsWidgetPrivate>()}
331 {
330 {
332 ui->setupUi(this);
331 ui->setupUi(this);
333
332
334 impl->m_Model = new CatalogueEventsModel{this};
333 impl->m_Model = new CatalogueEventsModel{this};
335 ui->treeView->setModel(impl->m_Model);
334 ui->treeView->setModel(impl->m_Model);
336
335
337 ui->treeView->setSortingEnabled(true);
336 ui->treeView->setSortingEnabled(true);
338 ui->treeView->setDragDropMode(QAbstractItemView::DragDrop);
337 ui->treeView->setDragDropMode(QAbstractItemView::DragDrop);
339 ui->treeView->setDragEnabled(true);
338 ui->treeView->setDragEnabled(true);
340
339
341
340
342 connect(ui->btnTime, &QToolButton::clicked, [this](auto checked) {
341 connect(ui->btnTime, &QToolButton::clicked, [this](auto checked) {
343 if (checked) {
342 if (checked) {
344 ui->btnChart->setChecked(false);
343 ui->btnChart->setChecked(false);
345 impl->m_ZonesForTimeMode
344 impl->m_ZonesForTimeMode
346 = impl->selectZone(this, impl->m_ZonesForTimeMode, true, false,
345 = impl->selectZone(this, impl->m_ZonesForTimeMode, true, false,
347 this->mapToGlobal(ui->btnTime->frameGeometry().center()));
346 this->mapToGlobal(ui->btnTime->frameGeometry().center()));
348
347
349 impl->updateForTimeMode(ui->treeView);
348 impl->updateForTimeMode(ui->treeView);
350 }
349 }
351 });
350 });
352
351
353 connect(ui->btnChart, &QToolButton::clicked, [this](auto checked) {
352 connect(ui->btnChart, &QToolButton::clicked, [this](auto checked) {
354 if (checked) {
353 if (checked) {
355 ui->btnTime->setChecked(false);
354 ui->btnTime->setChecked(false);
356
355
357 impl->m_ZoneForGraphMode
356 impl->m_ZoneForGraphMode
358 = impl->selectZone(this, {impl->m_ZoneForGraphMode}, false, true,
357 = impl->selectZone(this, {impl->m_ZoneForGraphMode}, false, true,
359 this->mapToGlobal(ui->btnChart->frameGeometry().center()))
358 this->mapToGlobal(ui->btnChart->frameGeometry().center()))
360 .value(0);
359 .value(0);
361
360
362 impl->updateForGraphMode(this);
361 impl->updateForGraphMode(this);
363 }
362 }
364 });
363 });
365
364
366 connect(ui->btnRemove, &QToolButton::clicked, [this]() {
365 connect(ui->btnRemove, &QToolButton::clicked, [this]() {
367 QVector<std::shared_ptr<DBEvent> > events;
366 QVector<std::shared_ptr<DBEvent> > events;
368 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
367 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
369 impl->getSelectedItems(ui->treeView, events, eventProducts);
368 impl->getSelectedItems(ui->treeView, events, eventProducts);
370
369
371 if (!events.isEmpty() && eventProducts.isEmpty()) {
370 if (!events.isEmpty() && eventProducts.isEmpty()) {
372
371
373 auto canRemoveEvent
372 auto canRemoveEvent
374 = !this->isAllEventsDisplayed()
373 = !this->isAllEventsDisplayed()
375 || (QMessageBox::warning(
374 || (QMessageBox::warning(
376 this, tr("Remove Event(s)"),
375 this, tr("Remove Event(s)"),
377 tr("The selected event(s) will be permanently removed "
376 tr("The selected event(s) will be permanently removed "
378 "from the repository!\nAre you sure you want to continue?"),
377 "from the repository!\nAre you sure you want to continue?"),
379 QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
378 QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
380 == QMessageBox::Yes);
379 == QMessageBox::Yes);
381
380
382 if (canRemoveEvent) {
381 if (canRemoveEvent) {
383 for (auto event : events) {
382 for (auto event : events) {
384 if (this->isAllEventsDisplayed()) {
383 if (this->isAllEventsDisplayed()) {
385 sqpApp->catalogueController().removeEvent(event);
384 sqpApp->catalogueController().removeEvent(event);
386 impl->removeEvent(event, ui->treeView);
385 impl->removeEvent(event, ui->treeView);
387 }
386 }
388 else {
387 else {
389 QVector<std::shared_ptr<DBCatalogue> > modifiedCatalogues;
388 QVector<std::shared_ptr<DBCatalogue> > modifiedCatalogues;
390 for (auto catalogue : this->displayedCatalogues()) {
389 for (auto catalogue : this->displayedCatalogues()) {
391 if (catalogue->removeEvent(event->getUniqId())) {
390 if (catalogue->removeEvent(event->getUniqId())) {
392 sqpApp->catalogueController().updateCatalogue(catalogue);
391 sqpApp->catalogueController().updateCatalogue(catalogue);
393 modifiedCatalogues << catalogue;
392 modifiedCatalogues << catalogue;
394 }
393 }
395 }
394 }
396 if (!modifiedCatalogues.empty()) {
395 if (!modifiedCatalogues.empty()) {
397 emit eventCataloguesModified(modifiedCatalogues);
396 emit eventCataloguesModified(modifiedCatalogues);
398 }
397 }
399 }
398 }
400 impl->m_Model->removeEvent(event);
399 impl->m_Model->removeEvent(event);
401 }
400 }
402
401
403
402
404 emit this->eventsRemoved(events);
403 emit this->eventsRemoved(events);
405 }
404 }
406 }
405 }
407 });
406 });
408
407
409 connect(ui->treeView, &QTreeView::clicked, this, &CatalogueEventsWidget::emitSelection);
408 connect(ui->treeView, &QTreeView::clicked, this, &CatalogueEventsWidget::emitSelection);
410 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
409 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
411 &CatalogueEventsWidget::emitSelection);
410 &CatalogueEventsWidget::emitSelection);
412
411
413 ui->btnRemove->setEnabled(false); // Disabled by default when nothing is selected
412 ui->btnRemove->setEnabled(false); // Disabled by default when nothing is selected
414 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, [this]() {
413 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, [this]() {
415 auto isNotMultiSelection = ui->treeView->selectionModel()->selectedRows().count() <= 1;
414 auto isNotMultiSelection = ui->treeView->selectionModel()->selectedRows().count() <= 1;
416 ui->btnChart->setEnabled(isNotMultiSelection);
415 ui->btnChart->setEnabled(isNotMultiSelection);
417 ui->btnTime->setEnabled(isNotMultiSelection);
416 ui->btnTime->setEnabled(isNotMultiSelection);
418
417
419 if (isNotMultiSelection && ui->btnTime->isChecked()) {
418 if (isNotMultiSelection && ui->btnTime->isChecked()) {
420 impl->updateForTimeMode(ui->treeView);
419 impl->updateForTimeMode(ui->treeView);
421 }
420 }
422 else if (isNotMultiSelection && ui->btnChart->isChecked()) {
421 else if (isNotMultiSelection && ui->btnChart->isChecked()) {
423 impl->updateForGraphMode(this);
422 impl->updateForGraphMode(this);
424 }
423 }
425
424
426 QVector<std::shared_ptr<DBEvent> > events;
425 QVector<std::shared_ptr<DBEvent> > events;
427 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
426 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
428 impl->getSelectedItems(ui->treeView, events, eventProducts);
427 impl->getSelectedItems(ui->treeView, events, eventProducts);
429 ui->btnRemove->setEnabled(!events.isEmpty() && eventProducts.isEmpty());
428 ui->btnRemove->setEnabled(!events.isEmpty() && eventProducts.isEmpty());
430 });
429 });
431
430
432 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
431 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
433 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Tags,
432 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Tags,
434 QHeaderView::Stretch);
433 QHeaderView::Stretch);
435 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Validation,
434 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Validation,
436 QHeaderView::ResizeToContents);
435 QHeaderView::ResizeToContents);
437 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Name,
436 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Name,
438 QHeaderView::Interactive);
437 QHeaderView::Interactive);
439 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::TStart,
438 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::TStart,
440 QHeaderView::ResizeToContents);
439 QHeaderView::ResizeToContents);
441 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::TEnd,
440 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::TEnd,
442 QHeaderView::ResizeToContents);
441 QHeaderView::ResizeToContents);
443 ui->treeView->header()->setSortIndicatorShown(true);
442 ui->treeView->header()->setSortIndicatorShown(true);
444
443
445 connect(impl->m_Model, &CatalogueEventsModel::modelSorted, [this]() {
444 connect(impl->m_Model, &CatalogueEventsModel::modelSorted, [this]() {
446 auto allEvents = impl->m_Model->events();
445 auto allEvents = impl->m_Model->events();
447 for (auto event : allEvents) {
446 for (auto event : allEvents) {
448 setEventChanges(event, sqpApp->catalogueController().eventHasChanges(event));
447 setEventChanges(event, sqpApp->catalogueController().eventHasChanges(event));
449 }
448 }
450 });
449 });
451
450
452 populateWithAllEvents();
451 populateWithAllEvents();
453 }
452 }
454
453
455 CatalogueEventsWidget::~CatalogueEventsWidget()
454 CatalogueEventsWidget::~CatalogueEventsWidget()
456 {
455 {
457 delete ui;
456 delete ui;
458 }
457 }
459
458
460 void CatalogueEventsWidget::setVisualizationWidget(VisualizationWidget *visualization)
459 void CatalogueEventsWidget::setVisualizationWidget(VisualizationWidget *visualization)
461 {
460 {
462 impl->m_VisualizationWidget = visualization;
461 impl->m_VisualizationWidget = visualization;
463 }
462 }
464
463
465 void CatalogueEventsWidget::addEvent(const std::shared_ptr<DBEvent> &event)
464 void CatalogueEventsWidget::addEvent(const std::shared_ptr<DBEvent> &event)
466 {
465 {
467 impl->addEvent(event, ui->treeView);
466 impl->addEvent(event, ui->treeView);
468 }
467 }
469
468
470 void CatalogueEventsWidget::setEventChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges)
469 void CatalogueEventsWidget::setEventChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges)
471 {
470 {
472 impl->m_Model->refreshEvent(event);
471 impl->m_Model->refreshEvent(event);
473
472
474 auto eventIndex = impl->m_Model->indexOf(event);
473 auto eventIndex = impl->m_Model->indexOf(event);
475 auto validationIndex
474 auto validationIndex
476 = eventIndex.sibling(eventIndex.row(), (int)CatalogueEventsModel::Column::Validation);
475 = eventIndex.sibling(eventIndex.row(), (int)CatalogueEventsModel::Column::Validation);
477
476
478 if (validationIndex.isValid()) {
477 if (validationIndex.isValid()) {
479 if (hasChanges) {
478 if (hasChanges) {
480 if (ui->treeView->indexWidget(validationIndex) == nullptr) {
479 if (ui->treeView->indexWidget(validationIndex) == nullptr) {
481 auto widget = CatalogueExplorerHelper::buildValidationWidget(
480 auto widget = CatalogueExplorerHelper::buildValidationWidget(
482 ui->treeView,
481 ui->treeView,
483 [this, event]() {
482 [this, event]() {
484 sqpApp->catalogueController().saveEvent(event);
483 sqpApp->catalogueController().saveEvent(event);
485 setEventChanges(event, false);
484 setEventChanges(event, false);
486 },
485 },
487 [this, event]() {
486 [this, event]() {
488 bool removed = false;
487 bool removed = false;
489 sqpApp->catalogueController().discardEvent(event, removed);
488 sqpApp->catalogueController().discardEvent(event, removed);
490 if (removed) {
489 if (removed) {
491 impl->m_Model->removeEvent(event);
490 impl->m_Model->removeEvent(event);
492 }
491 }
493 else {
492 else {
494 setEventChanges(event, false);
493 setEventChanges(event, false);
495 impl->m_Model->refreshEvent(event, true);
494 impl->m_Model->refreshEvent(event, true);
496 }
495 }
497 emitSelection();
496 emitSelection();
498 });
497 });
499 ui->treeView->setIndexWidget(validationIndex, widget);
498 ui->treeView->setIndexWidget(validationIndex, widget);
500 ui->treeView->header()->resizeSection((int)CatalogueEventsModel::Column::Validation,
499 ui->treeView->header()->resizeSection((int)CatalogueEventsModel::Column::Validation,
501 QHeaderView::ResizeToContents);
500 QHeaderView::ResizeToContents);
502 }
501 }
503 }
502 }
504 else {
503 else {
505 // Note: the widget is destroyed
504 // Note: the widget is destroyed
506 ui->treeView->setIndexWidget(validationIndex, nullptr);
505 ui->treeView->setIndexWidget(validationIndex, nullptr);
507 }
506 }
508 }
507 }
509 else {
508 else {
510 qCWarning(LOG_CatalogueEventsWidget())
509 qCWarning(LOG_CatalogueEventsWidget())
511 << "setEventChanges: the event is not displayed in the model.";
510 << "setEventChanges: the event is not displayed in the model.";
512 }
511 }
513 }
512 }
514
513
515 QVector<std::shared_ptr<DBCatalogue> > CatalogueEventsWidget::displayedCatalogues() const
514 QVector<std::shared_ptr<DBCatalogue> > CatalogueEventsWidget::displayedCatalogues() const
516 {
515 {
517 return impl->m_DisplayedCatalogues;
516 return impl->m_DisplayedCatalogues;
518 }
517 }
519
518
520 bool CatalogueEventsWidget::isAllEventsDisplayed() const
519 bool CatalogueEventsWidget::isAllEventsDisplayed() const
521 {
520 {
522 return impl->m_AllEventDisplayed;
521 return impl->m_AllEventDisplayed;
523 }
522 }
524
523
525 bool CatalogueEventsWidget::isEventDisplayed(const std::shared_ptr<DBEvent> &event) const
524 bool CatalogueEventsWidget::isEventDisplayed(const std::shared_ptr<DBEvent> &event) const
526 {
525 {
527 return impl->m_Model->indexOf(event).isValid();
526 return impl->m_Model->indexOf(event).isValid();
528 }
527 }
529
528
530 void CatalogueEventsWidget::refreshEvent(const std::shared_ptr<DBEvent> &event)
529 void CatalogueEventsWidget::refreshEvent(const std::shared_ptr<DBEvent> &event)
531 {
530 {
532 impl->m_Model->refreshEvent(event, true);
531 impl->m_Model->refreshEvent(event, true);
533 }
532 }
534
533
535 void CatalogueEventsWidget::populateWithCatalogues(
534 void CatalogueEventsWidget::populateWithCatalogues(
536 const QVector<std::shared_ptr<DBCatalogue> > &catalogues)
535 const QVector<std::shared_ptr<DBCatalogue> > &catalogues)
537 {
536 {
538 impl->m_DisplayedCatalogues = catalogues;
537 impl->m_DisplayedCatalogues = catalogues;
539 impl->m_AllEventDisplayed = false;
538 impl->m_AllEventDisplayed = false;
540
539
541 QSet<QUuid> eventIds;
540 QSet<QUuid> eventIds;
542 QVector<std::shared_ptr<DBEvent> > events;
541 QVector<std::shared_ptr<DBEvent> > events;
543
542
544 for (auto catalogue : catalogues) {
543 for (auto catalogue : catalogues) {
545 auto catalogueEvents = sqpApp->catalogueController().retrieveEventsFromCatalogue(catalogue);
544 auto catalogueEvents = sqpApp->catalogueController().retrieveEventsFromCatalogue(catalogue);
546 for (auto event : catalogueEvents) {
545 for (auto event : catalogueEvents) {
547 if (!eventIds.contains(event->getUniqId())) {
546 if (!eventIds.contains(event->getUniqId())) {
548 events << event;
547 events << event;
549 eventIds.insert(event->getUniqId());
548 eventIds.insert(event->getUniqId());
550 }
549 }
551 }
550 }
552 }
551 }
553
552
554 impl->setEvents(events, this);
553 impl->setEvents(events, this);
555 }
554 }
556
555
557 void CatalogueEventsWidget::populateWithAllEvents()
556 void CatalogueEventsWidget::populateWithAllEvents()
558 {
557 {
559 impl->m_DisplayedCatalogues.clear();
558 impl->m_DisplayedCatalogues.clear();
560 impl->m_AllEventDisplayed = true;
559 impl->m_AllEventDisplayed = true;
561
560
562 auto allEvents = sqpApp->catalogueController().retrieveAllEvents();
561 auto allEvents = sqpApp->catalogueController().retrieveAllEvents();
563
562
564 QVector<std::shared_ptr<DBEvent> > events;
563 QVector<std::shared_ptr<DBEvent> > events;
565 for (auto event : allEvents) {
564 for (auto event : allEvents) {
566 events << event;
565 events << event;
567 }
566 }
568
567
569 impl->setEvents(events, this);
568 impl->setEvents(events, this);
570 }
569 }
571
570
572 void CatalogueEventsWidget::clear()
571 void CatalogueEventsWidget::clear()
573 {
572 {
574 impl->m_DisplayedCatalogues.clear();
573 impl->m_DisplayedCatalogues.clear();
575 impl->m_AllEventDisplayed = false;
574 impl->m_AllEventDisplayed = false;
576 impl->setEvents({}, this);
575 impl->setEvents({}, this);
577 }
576 }
578
577
579 void CatalogueEventsWidget::refresh()
578 void CatalogueEventsWidget::refresh()
580 {
579 {
581 if (isAllEventsDisplayed()) {
580 if (isAllEventsDisplayed()) {
582 populateWithAllEvents();
581 populateWithAllEvents();
583 }
582 }
584 else if (!impl->m_DisplayedCatalogues.isEmpty()) {
583 else if (!impl->m_DisplayedCatalogues.isEmpty()) {
585 populateWithCatalogues(impl->m_DisplayedCatalogues);
584 populateWithCatalogues(impl->m_DisplayedCatalogues);
586 }
585 }
587 }
586 }
588
587
589 void CatalogueEventsWidget::emitSelection()
588 void CatalogueEventsWidget::emitSelection()
590 {
589 {
591 QVector<std::shared_ptr<DBEvent> > events;
590 QVector<std::shared_ptr<DBEvent> > events;
592 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
591 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
593 impl->getSelectedItems(ui->treeView, events, eventProducts);
592 impl->getSelectedItems(ui->treeView, events, eventProducts);
594
593
595 if (!events.isEmpty() && eventProducts.isEmpty()) {
594 if (!events.isEmpty() && eventProducts.isEmpty()) {
596 emit eventsSelected(events);
595 emit eventsSelected(events);
597 }
596 }
598 else if (events.isEmpty() && !eventProducts.isEmpty()) {
597 else if (events.isEmpty() && !eventProducts.isEmpty()) {
599 emit eventProductsSelected(eventProducts);
598 emit eventProductsSelected(eventProducts);
600 }
599 }
601 else {
600 else {
602 emit selectionCleared();
601 emit selectionCleared();
603 }
602 }
604 }
603 }
605
604
606
605
607 void CatalogueEventsWidget::keyPressEvent(QKeyEvent *event)
606 void CatalogueEventsWidget::keyPressEvent(QKeyEvent *event)
608 {
607 {
609 switch (event->key()) {
608 switch (event->key()) {
610 case Qt::Key_Delete: {
609 case Qt::Key_Delete: {
611 ui->btnRemove->click();
610 ui->btnRemove->click();
612 }
611 }
613 default:
612 default:
614 break;
613 break;
615 }
614 }
616 }
615 }
@@ -1,202 +1,200
1 #include "SqpApplication.h"
1 #include "SqpApplication.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 <Data/IDataProvider.h>
5 #include <Data/IDataProvider.h>
6 #include <DataSource/DataSourceController.h>
6 #include <DataSource/DataSourceController.h>
7 #include <DragAndDrop/DragDropGuiController.h>
7 #include <DragAndDrop/DragDropGuiController.h>
8 #include <Network/NetworkController.h>
8 #include <Network/NetworkController.h>
9 #include <QThread>
9 #include <QThread>
10 #include <Time/TimeController.h>
10 #include <Time/TimeController.h>
11 #include <Variable/Variable.h>
11 #include <Variable/Variable.h>
12 #include <Variable/VariableController.h>
13 #include <Variable/VariableController2.h>
12 #include <Variable/VariableController2.h>
14 #include <Variable/VariableModel2.h>
13 #include <Variable/VariableModel2.h>
15 #include <Variable/VariableModel.h>
16 #include <Visualization/VisualizationController.h>
14 #include <Visualization/VisualizationController.h>
17
15
18 Q_LOGGING_CATEGORY(LOG_SqpApplication, "SqpApplication")
16 Q_LOGGING_CATEGORY(LOG_SqpApplication, "SqpApplication")
19
17
20 class SqpApplication::SqpApplicationPrivate {
18 class SqpApplication::SqpApplicationPrivate {
21 public:
19 public:
22 SqpApplicationPrivate()
20 SqpApplicationPrivate()
23 : m_VariableController{std::make_shared<VariableController2>()},
21 : m_VariableController{std::make_shared<VariableController2>()},
24 m_VariableModel{m_VariableController},
22 m_VariableModel{m_VariableController},
25 m_PlotInterractionMode(SqpApplication::PlotsInteractionMode::None),
23 m_PlotInterractionMode(SqpApplication::PlotsInteractionMode::None),
26 m_PlotCursorMode(SqpApplication::PlotsCursorMode::NoCursor)
24 m_PlotCursorMode(SqpApplication::PlotsCursorMode::NoCursor)
27 {
25 {
28 // /////////////////////////////// //
26 // /////////////////////////////// //
29 // Connections between controllers //
27 // Connections between controllers //
30 // /////////////////////////////// //
28 // /////////////////////////////// //
31
29
32 // VariableController <-> DataSourceController
30 // VariableController <-> DataSourceController
33 connect(&m_DataSourceController,
31 connect(&m_DataSourceController,
34 SIGNAL(variableCreationRequested(const QString &, const QVariantHash &,
32 SIGNAL(variableCreationRequested(const QString &, const QVariantHash &,
35 std::shared_ptr<IDataProvider>)),
33 std::shared_ptr<IDataProvider>)),
36 m_VariableController.get(),
34 m_VariableController.get(),
37 SLOT(createVariable(const QString &, const QVariantHash &,
35 SLOT(createVariable(const QString &, const QVariantHash &,
38 std::shared_ptr<IDataProvider>)));
36 std::shared_ptr<IDataProvider>)));
39
37
40 // connect(m_VariableController->variableModel(), &VariableModel::requestVariable,
38 // connect(m_VariableController->variableModel(), &VariableModel::requestVariable,
41 // m_DataSourceController.get(), &DataSourceController::requestVariable);
39 // m_DataSourceController.get(), &DataSourceController::requestVariable);
42
40
43 // VariableController <-> VisualizationController
41 // VariableController <-> VisualizationController
44 // connect(m_VariableController.get(),
42 // connect(m_VariableController.get(),
45 // SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)),
43 // SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)),
46 // m_VisualizationController.get(),
44 // m_VisualizationController.get(),
47 // SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), Qt::DirectConnection);
45 // SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), Qt::DirectConnection);
48
46
49 // connect(m_VariableController.get(),
47 // connect(m_VariableController.get(),
50 // SIGNAL(rangeChanged(std::shared_ptr<Variable>, const DateTimeRange &)),
48 // SIGNAL(rangeChanged(std::shared_ptr<Variable>, const DateTimeRange &)),
51 // m_VisualizationController.get(),
49 // m_VisualizationController.get(),
52 // SIGNAL(rangeChanged(std::shared_ptr<Variable>, const DateTimeRange &)));
50 // SIGNAL(rangeChanged(std::shared_ptr<Variable>, const DateTimeRange &)));
53
51
54
52
55 m_DataSourceController.moveToThread(&m_DataSourceControllerThread);
53 m_DataSourceController.moveToThread(&m_DataSourceControllerThread);
56 m_DataSourceControllerThread.setObjectName("DataSourceControllerThread");
54 m_DataSourceControllerThread.setObjectName("DataSourceControllerThread");
57 m_NetworkController.moveToThread(&m_NetworkControllerThread);
55 m_NetworkController.moveToThread(&m_NetworkControllerThread);
58 m_NetworkControllerThread.setObjectName("NetworkControllerThread");
56 m_NetworkControllerThread.setObjectName("NetworkControllerThread");
59 m_VisualizationController.moveToThread(&m_VisualizationControllerThread);
57 m_VisualizationController.moveToThread(&m_VisualizationControllerThread);
60 m_VisualizationControllerThread.setObjectName("VsualizationControllerThread");
58 m_VisualizationControllerThread.setObjectName("VsualizationControllerThread");
61
59
62 // Additionnal init
60 // Additionnal init
63 //m_VariableController->setTimeController(m_TimeController.get());
61 //m_VariableController->setTimeController(m_TimeController.get());
64 }
62 }
65
63
66 virtual ~SqpApplicationPrivate()
64 virtual ~SqpApplicationPrivate()
67 {
65 {
68 m_DataSourceControllerThread.quit();
66 m_DataSourceControllerThread.quit();
69 m_DataSourceControllerThread.wait();
67 m_DataSourceControllerThread.wait();
70
68
71 m_NetworkControllerThread.quit();
69 m_NetworkControllerThread.quit();
72 m_NetworkControllerThread.wait();
70 m_NetworkControllerThread.wait();
73
71
74 m_VisualizationControllerThread.quit();
72 m_VisualizationControllerThread.quit();
75 m_VisualizationControllerThread.wait();
73 m_VisualizationControllerThread.wait();
76 }
74 }
77
75
78 DataSourceController m_DataSourceController;
76 DataSourceController m_DataSourceController;
79 std::shared_ptr<VariableController2> m_VariableController;
77 std::shared_ptr<VariableController2> m_VariableController;
80 TimeController m_TimeController;
78 TimeController m_TimeController;
81 NetworkController m_NetworkController;
79 NetworkController m_NetworkController;
82 VisualizationController m_VisualizationController;
80 VisualizationController m_VisualizationController;
83 CatalogueController m_CatalogueController;
81 CatalogueController m_CatalogueController;
84 VariableModel2 m_VariableModel;
82 VariableModel2 m_VariableModel;
85
83
86 QThread m_DataSourceControllerThread;
84 QThread m_DataSourceControllerThread;
87 QThread m_NetworkControllerThread;
85 QThread m_NetworkControllerThread;
88 QThread m_VisualizationControllerThread;
86 QThread m_VisualizationControllerThread;
89
87
90 DragDropGuiController m_DragDropGuiController;
88 DragDropGuiController m_DragDropGuiController;
91 ActionsGuiController m_ActionsGuiController;
89 ActionsGuiController m_ActionsGuiController;
92
90
93 SqpApplication::PlotsInteractionMode m_PlotInterractionMode;
91 SqpApplication::PlotsInteractionMode m_PlotInterractionMode;
94 SqpApplication::PlotsCursorMode m_PlotCursorMode;
92 SqpApplication::PlotsCursorMode m_PlotCursorMode;
95 };
93 };
96
94
97
95
98 SqpApplication::SqpApplication(int &argc, char **argv)
96 SqpApplication::SqpApplication(int &argc, char **argv)
99 : QApplication{argc, argv}, impl{spimpl::make_unique_impl<SqpApplicationPrivate>()}
97 : QApplication{argc, argv}, impl{spimpl::make_unique_impl<SqpApplicationPrivate>()}
100 {
98 {
101 qCDebug(LOG_SqpApplication()) << tr("SqpApplication construction") << QThread::currentThread();
99 qCDebug(LOG_SqpApplication()) << tr("SqpApplication construction") << QThread::currentThread();
102
100
103 QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
101 QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
104
102
105 connect(&impl->m_DataSourceControllerThread, &QThread::started,
103 connect(&impl->m_DataSourceControllerThread, &QThread::started,
106 &impl->m_DataSourceController, &DataSourceController::initialize);
104 &impl->m_DataSourceController, &DataSourceController::initialize);
107 connect(&impl->m_DataSourceControllerThread, &QThread::finished,
105 connect(&impl->m_DataSourceControllerThread, &QThread::finished,
108 &impl->m_DataSourceController, &DataSourceController::finalize);
106 &impl->m_DataSourceController, &DataSourceController::finalize);
109
107
110 connect(&impl->m_NetworkControllerThread, &QThread::started, &impl->m_NetworkController,
108 connect(&impl->m_NetworkControllerThread, &QThread::started, &impl->m_NetworkController,
111 &NetworkController::initialize);
109 &NetworkController::initialize);
112 connect(&impl->m_NetworkControllerThread, &QThread::finished, &impl->m_NetworkController,
110 connect(&impl->m_NetworkControllerThread, &QThread::finished, &impl->m_NetworkController,
113 &NetworkController::finalize);
111 &NetworkController::finalize);
114
112
115 connect(&impl->m_VisualizationControllerThread, &QThread::started,
113 connect(&impl->m_VisualizationControllerThread, &QThread::started,
116 &impl->m_VisualizationController, &VisualizationController::initialize);
114 &impl->m_VisualizationController, &VisualizationController::initialize);
117 connect(&impl->m_VisualizationControllerThread, &QThread::finished,
115 connect(&impl->m_VisualizationControllerThread, &QThread::finished,
118 &impl->m_VisualizationController, &VisualizationController::finalize);
116 &impl->m_VisualizationController, &VisualizationController::finalize);
119
117
120 impl->m_DataSourceControllerThread.start();
118 impl->m_DataSourceControllerThread.start();
121 impl->m_NetworkControllerThread.start();
119 impl->m_NetworkControllerThread.start();
122 impl->m_VisualizationControllerThread.start();
120 impl->m_VisualizationControllerThread.start();
123 impl->m_CatalogueController.initialize();
121 impl->m_CatalogueController.initialize();
124 }
122 }
125
123
126 SqpApplication::~SqpApplication()
124 SqpApplication::~SqpApplication()
127 {
125 {
128 }
126 }
129
127
130 void SqpApplication::initialize()
128 void SqpApplication::initialize()
131 {
129 {
132 }
130 }
133
131
134 DataSourceController &SqpApplication::dataSourceController() noexcept
132 DataSourceController &SqpApplication::dataSourceController() noexcept
135 {
133 {
136 return impl->m_DataSourceController;
134 return impl->m_DataSourceController;
137 }
135 }
138
136
139 NetworkController &SqpApplication::networkController() noexcept
137 NetworkController &SqpApplication::networkController() noexcept
140 {
138 {
141 return impl->m_NetworkController;
139 return impl->m_NetworkController;
142 }
140 }
143
141
144 TimeController &SqpApplication::timeController() noexcept
142 TimeController &SqpApplication::timeController() noexcept
145 {
143 {
146 return impl->m_TimeController;
144 return impl->m_TimeController;
147 }
145 }
148
146
149 VariableController2 &SqpApplication::variableController() noexcept
147 VariableController2 &SqpApplication::variableController() noexcept
150 {
148 {
151 return *impl->m_VariableController;
149 return *impl->m_VariableController;
152 }
150 }
153
151
154 std::shared_ptr<VariableController2> SqpApplication::variableControllerOwner() noexcept
152 std::shared_ptr<VariableController2> SqpApplication::variableControllerOwner() noexcept
155 {
153 {
156 return impl->m_VariableController;
154 return impl->m_VariableController;
157 }
155 }
158
156
159 //VariableModel2 &SqpApplication::variableModel() noexcept
157 //VariableModel2 &SqpApplication::variableModel() noexcept
160 //{
158 //{
161 // return impl->m_VariableModel;
159 // return impl->m_VariableModel;
162 //}
160 //}
163
161
164 VisualizationController &SqpApplication::visualizationController() noexcept
162 VisualizationController &SqpApplication::visualizationController() noexcept
165 {
163 {
166 return impl->m_VisualizationController;
164 return impl->m_VisualizationController;
167 }
165 }
168
166
169 CatalogueController &SqpApplication::catalogueController() noexcept
167 CatalogueController &SqpApplication::catalogueController() noexcept
170 {
168 {
171 return impl->m_CatalogueController;
169 return impl->m_CatalogueController;
172 }
170 }
173
171
174 DragDropGuiController &SqpApplication::dragDropGuiController() noexcept
172 DragDropGuiController &SqpApplication::dragDropGuiController() noexcept
175 {
173 {
176 return impl->m_DragDropGuiController;
174 return impl->m_DragDropGuiController;
177 }
175 }
178
176
179 ActionsGuiController &SqpApplication::actionsGuiController() noexcept
177 ActionsGuiController &SqpApplication::actionsGuiController() noexcept
180 {
178 {
181 return impl->m_ActionsGuiController;
179 return impl->m_ActionsGuiController;
182 }
180 }
183
181
184 SqpApplication::PlotsInteractionMode SqpApplication::plotsInteractionMode() const
182 SqpApplication::PlotsInteractionMode SqpApplication::plotsInteractionMode() const
185 {
183 {
186 return impl->m_PlotInterractionMode;
184 return impl->m_PlotInterractionMode;
187 }
185 }
188
186
189 void SqpApplication::setPlotsInteractionMode(SqpApplication::PlotsInteractionMode mode)
187 void SqpApplication::setPlotsInteractionMode(SqpApplication::PlotsInteractionMode mode)
190 {
188 {
191 impl->m_PlotInterractionMode = mode;
189 impl->m_PlotInterractionMode = mode;
192 }
190 }
193
191
194 SqpApplication::PlotsCursorMode SqpApplication::plotsCursorMode() const
192 SqpApplication::PlotsCursorMode SqpApplication::plotsCursorMode() const
195 {
193 {
196 return impl->m_PlotCursorMode;
194 return impl->m_PlotCursorMode;
197 }
195 }
198
196
199 void SqpApplication::setPlotsCursorMode(SqpApplication::PlotsCursorMode mode)
197 void SqpApplication::setPlotsCursorMode(SqpApplication::PlotsCursorMode mode)
200 {
198 {
201 impl->m_PlotCursorMode = mode;
199 impl->m_PlotCursorMode = mode;
202 }
200 }
@@ -1,1083 +1,1083
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 <Actions/FilteringAction.h>
15 #include <Actions/FilteringAction.h>
16 #include <Common/MimeTypesDef.h>
16 #include <Common/MimeTypesDef.h>
17 #include <Data/ArrayData.h>
17 #include <Data/ArrayData.h>
18 #include <Data/IDataSeries.h>
18 #include <Data/IDataSeries.h>
19 #include <Data/SpectrogramSeries.h>
19 #include <Data/SpectrogramSeries.h>
20 #include <DragAndDrop/DragDropGuiController.h>
20 #include <DragAndDrop/DragDropGuiController.h>
21 #include <Settings/SqpSettingsDefs.h>
21 #include <Settings/SqpSettingsDefs.h>
22 #include <SqpApplication.h>
22 #include <SqpApplication.h>
23 #include <Time/TimeController.h>
23 #include <Time/TimeController.h>
24 #include <Variable/Variable.h>
24 #include <Variable/Variable.h>
25 #include <Variable/VariableController.h>
25 #include <Variable/VariableController2.h>
26
26
27 #include <unordered_map>
27 #include <unordered_map>
28
28
29 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
29 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
30
30
31 namespace {
31 namespace {
32
32
33 /// Key pressed to enable drag&drop in all modes
33 /// Key pressed to enable drag&drop in all modes
34 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
34 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
35
35
36 /// Key pressed to enable zoom on horizontal axis
36 /// Key pressed to enable zoom on horizontal axis
37 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
37 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
38
38
39 /// Key pressed to enable zoom on vertical axis
39 /// Key pressed to enable zoom on vertical axis
40 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
40 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
41
41
42 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
42 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
43 const auto PAN_SPEED = 5;
43 const auto PAN_SPEED = 5;
44
44
45 /// Key pressed to enable a calibration pan
45 /// Key pressed to enable a calibration pan
46 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
46 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
47
47
48 /// Key pressed to enable multi selection of selection zones
48 /// Key pressed to enable multi selection of selection zones
49 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
49 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
50
50
51 /// Minimum size for the zoom box, in percentage of the axis range
51 /// Minimum size for the zoom box, in percentage of the axis range
52 const auto ZOOM_BOX_MIN_SIZE = 0.8;
52 const auto ZOOM_BOX_MIN_SIZE = 0.8;
53
53
54 /// Format of the dates appearing in the label of a cursor
54 /// Format of the dates appearing in the label of a cursor
55 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
55 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
56
56
57 } // namespace
57 } // namespace
58
58
59 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
59 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
60
60
61 explicit VisualizationGraphWidgetPrivate(const QString &name)
61 explicit VisualizationGraphWidgetPrivate(const QString &name)
62 : m_Name{name},
62 : m_Name{name},
63 m_Flags{GraphFlag::EnableAll},
63 m_Flags{GraphFlag::EnableAll},
64 m_IsCalibration{false},
64 m_IsCalibration{false},
65 m_RenderingDelegate{nullptr}
65 m_RenderingDelegate{nullptr}
66 {
66 {
67 }
67 }
68
68
69 void updateData(PlottablesMap &plottables, std::shared_ptr<Variable> variable,
69 void updateData(PlottablesMap &plottables, std::shared_ptr<Variable> variable,
70 const DateTimeRange &range)
70 const DateTimeRange &range)
71 {
71 {
72 VisualizationGraphHelper::updateData(plottables, variable, range);
72 VisualizationGraphHelper::updateData(plottables, variable, range);
73
73
74 // Prevents that data has changed to update rendering
74 // Prevents that data has changed to update rendering
75 m_RenderingDelegate->onPlotUpdated();
75 m_RenderingDelegate->onPlotUpdated();
76 }
76 }
77
77
78 QString m_Name;
78 QString m_Name;
79 // 1 variable -> n qcpplot
79 // 1 variable -> n qcpplot
80 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
80 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
81 GraphFlags m_Flags;
81 GraphFlags m_Flags;
82 bool m_IsCalibration;
82 bool m_IsCalibration;
83 /// Delegate used to attach rendering features to the plot
83 /// Delegate used to attach rendering features to the plot
84 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
84 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
85
85
86 QCPItemRect *m_DrawingZoomRect = nullptr;
86 QCPItemRect *m_DrawingZoomRect = nullptr;
87 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
87 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
88
88
89 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
89 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
90 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
90 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
91
91
92 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
92 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
93 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
93 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
94 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
94 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
95
95
96 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
96 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
97
97
98 bool m_VariableAutoRangeOnInit = true;
98 bool m_VariableAutoRangeOnInit = true;
99
99
100 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
100 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
101 {
101 {
102 removeDrawingRect(plot);
102 removeDrawingRect(plot);
103
103
104 auto axisPos = posToAxisPos(pos, plot);
104 auto axisPos = posToAxisPos(pos, plot);
105
105
106 m_DrawingZoomRect = new QCPItemRect{&plot};
106 m_DrawingZoomRect = new QCPItemRect{&plot};
107 QPen p;
107 QPen p;
108 p.setWidth(2);
108 p.setWidth(2);
109 m_DrawingZoomRect->setPen(p);
109 m_DrawingZoomRect->setPen(p);
110
110
111 m_DrawingZoomRect->topLeft->setCoords(axisPos);
111 m_DrawingZoomRect->topLeft->setCoords(axisPos);
112 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
112 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
113 }
113 }
114
114
115 void removeDrawingRect(QCustomPlot &plot)
115 void removeDrawingRect(QCustomPlot &plot)
116 {
116 {
117 if (m_DrawingZoomRect) {
117 if (m_DrawingZoomRect) {
118 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
118 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
119 m_DrawingZoomRect = nullptr;
119 m_DrawingZoomRect = nullptr;
120 plot.replot(QCustomPlot::rpQueuedReplot);
120 plot.replot(QCustomPlot::rpQueuedReplot);
121 }
121 }
122 }
122 }
123
123
124 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
124 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
125 {
125 {
126 endDrawingZone(graph);
126 endDrawingZone(graph);
127
127
128 auto axisPos = posToAxisPos(pos, graph->plot());
128 auto axisPos = posToAxisPos(pos, graph->plot());
129
129
130 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
130 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
131 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
131 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
132 m_DrawingZone->setEditionEnabled(false);
132 m_DrawingZone->setEditionEnabled(false);
133 }
133 }
134
134
135 void endDrawingZone(VisualizationGraphWidget *graph)
135 void endDrawingZone(VisualizationGraphWidget *graph)
136 {
136 {
137 if (m_DrawingZone) {
137 if (m_DrawingZone) {
138 auto drawingZoneRange = m_DrawingZone->range();
138 auto drawingZoneRange = m_DrawingZone->range();
139 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
139 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
140 m_DrawingZone->setEditionEnabled(true);
140 m_DrawingZone->setEditionEnabled(true);
141 addSelectionZone(m_DrawingZone);
141 addSelectionZone(m_DrawingZone);
142 }
142 }
143 else {
143 else {
144 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
144 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
145 }
145 }
146
146
147 graph->plot().replot(QCustomPlot::rpQueuedReplot);
147 graph->plot().replot(QCustomPlot::rpQueuedReplot);
148 m_DrawingZone = nullptr;
148 m_DrawingZone = nullptr;
149 }
149 }
150 }
150 }
151
151
152 void setSelectionZonesEditionEnabled(bool value)
152 void setSelectionZonesEditionEnabled(bool value)
153 {
153 {
154 for (auto s : m_SelectionZones) {
154 for (auto s : m_SelectionZones) {
155 s->setEditionEnabled(value);
155 s->setEditionEnabled(value);
156 }
156 }
157 }
157 }
158
158
159 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
159 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
160
160
161 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
161 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
162 const QCustomPlot &plot) const
162 const QCustomPlot &plot) const
163 {
163 {
164 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
164 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
165 auto minDistanceToZone = -1;
165 auto minDistanceToZone = -1;
166 for (auto zone : m_SelectionZones) {
166 for (auto zone : m_SelectionZones) {
167 auto distanceToZone = zone->selectTest(pos, false);
167 auto distanceToZone = zone->selectTest(pos, false);
168 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
168 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
169 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
169 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
170 selectionZoneItemUnderCursor = zone;
170 selectionZoneItemUnderCursor = zone;
171 }
171 }
172 }
172 }
173
173
174 return selectionZoneItemUnderCursor;
174 return selectionZoneItemUnderCursor;
175 }
175 }
176
176
177 QVector<VisualizationSelectionZoneItem *> selectionZonesAt(const QPoint &pos,
177 QVector<VisualizationSelectionZoneItem *> selectionZonesAt(const QPoint &pos,
178 const QCustomPlot &plot) const
178 const QCustomPlot &plot) const
179 {
179 {
180 QVector<VisualizationSelectionZoneItem *> zones;
180 QVector<VisualizationSelectionZoneItem *> zones;
181 for (auto zone : m_SelectionZones) {
181 for (auto zone : m_SelectionZones) {
182 auto distanceToZone = zone->selectTest(pos, false);
182 auto distanceToZone = zone->selectTest(pos, false);
183 if (distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
183 if (distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
184 zones << zone;
184 zones << zone;
185 }
185 }
186 }
186 }
187
187
188 return zones;
188 return zones;
189 }
189 }
190
190
191 void moveSelectionZoneOnTop(VisualizationSelectionZoneItem *zone, QCustomPlot &plot)
191 void moveSelectionZoneOnTop(VisualizationSelectionZoneItem *zone, QCustomPlot &plot)
192 {
192 {
193 if (!m_SelectionZones.isEmpty() && m_SelectionZones.last() != zone) {
193 if (!m_SelectionZones.isEmpty() && m_SelectionZones.last() != zone) {
194 zone->moveToTop();
194 zone->moveToTop();
195 m_SelectionZones.removeAll(zone);
195 m_SelectionZones.removeAll(zone);
196 m_SelectionZones.append(zone);
196 m_SelectionZones.append(zone);
197 }
197 }
198 }
198 }
199
199
200 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
200 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
201 {
201 {
202 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
202 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
203 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
203 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
204 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
204 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
205 }
205 }
206
206
207 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
207 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
208 {
208 {
209 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
209 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
210 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
210 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
211 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
211 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
212 }
212 }
213 };
213 };
214
214
215 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
215 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
216 : VisualizationDragWidget{parent},
216 : VisualizationDragWidget{parent},
217 ui{new Ui::VisualizationGraphWidget},
217 ui{new Ui::VisualizationGraphWidget},
218 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
218 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
219 {
219 {
220 ui->setupUi(this);
220 ui->setupUi(this);
221
221
222 // 'Close' options : widget is deleted when closed
222 // 'Close' options : widget is deleted when closed
223 setAttribute(Qt::WA_DeleteOnClose);
223 setAttribute(Qt::WA_DeleteOnClose);
224
224
225 // Set qcpplot properties :
225 // Set qcpplot properties :
226 // - zoom is enabled
226 // - zoom is enabled
227 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
227 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
228 ui->widget->setInteractions(QCP::iRangeZoom);
228 ui->widget->setInteractions(QCP::iRangeZoom);
229 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
229 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
230
230
231 // The delegate must be initialized after the ui as it uses the plot
231 // The delegate must be initialized after the ui as it uses the plot
232 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
232 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
233
233
234 // Init the cursors
234 // Init the cursors
235 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
235 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
236 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
236 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
237 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
237 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
238 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
238 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
239
239
240 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
240 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
241 connect(ui->widget, &QCustomPlot::mouseRelease, this,
241 connect(ui->widget, &QCustomPlot::mouseRelease, this,
242 &VisualizationGraphWidget::onMouseRelease);
242 &VisualizationGraphWidget::onMouseRelease);
243 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
243 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
244 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
244 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
245 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
245 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
246 &VisualizationGraphWidget::onMouseDoubleClick);
246 &VisualizationGraphWidget::onMouseDoubleClick);
247 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
247 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
248 &QCPAxis::rangeChanged),
248 &QCPAxis::rangeChanged),
249 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
249 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
250
250
251 // Activates menu when right clicking on the graph
251 // Activates menu when right clicking on the graph
252 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
252 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
253 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
253 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
254 &VisualizationGraphWidget::onGraphMenuRequested);
254 &VisualizationGraphWidget::onGraphMenuRequested);
255
255
256 //@TODO implement this :)
256 //@TODO implement this :)
257 // connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
257 // connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
258 // &VariableController::onRequestDataLoading);
258 // &VariableController::onRequestDataLoading);
259
259
260 // connect(&sqpApp->variableController(), &VariableController2::updateVarDisplaying, this,
260 // connect(&sqpApp->variableController(), &VariableController2::updateVarDisplaying, this,
261 // &VisualizationGraphWidget::onUpdateVarDisplaying);
261 // &VisualizationGraphWidget::onUpdateVarDisplaying);
262
262
263 // Necessary for all platform since Qt::AA_EnableHighDpiScaling is enable.
263 // Necessary for all platform since Qt::AA_EnableHighDpiScaling is enable.
264 plot().setPlottingHint(QCP::phFastPolylines, true);
264 plot().setPlottingHint(QCP::phFastPolylines, true);
265 }
265 }
266
266
267
267
268 VisualizationGraphWidget::~VisualizationGraphWidget()
268 VisualizationGraphWidget::~VisualizationGraphWidget()
269 {
269 {
270 delete ui;
270 delete ui;
271 }
271 }
272
272
273 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
273 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
274 {
274 {
275 auto parent = parentWidget();
275 auto parent = parentWidget();
276 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
276 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
277 parent = parent->parentWidget();
277 parent = parent->parentWidget();
278 }
278 }
279
279
280 return qobject_cast<VisualizationZoneWidget *>(parent);
280 return qobject_cast<VisualizationZoneWidget *>(parent);
281 }
281 }
282
282
283 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
283 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
284 {
284 {
285 auto parent = parentWidget();
285 auto parent = parentWidget();
286 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
286 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
287 parent = parent->parentWidget();
287 parent = parent->parentWidget();
288 }
288 }
289
289
290 return qobject_cast<VisualizationWidget *>(parent);
290 return qobject_cast<VisualizationWidget *>(parent);
291 }
291 }
292
292
293 void VisualizationGraphWidget::setFlags(GraphFlags flags)
293 void VisualizationGraphWidget::setFlags(GraphFlags flags)
294 {
294 {
295 impl->m_Flags = std::move(flags);
295 impl->m_Flags = std::move(flags);
296 }
296 }
297
297
298 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, DateTimeRange range)
298 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, DateTimeRange range)
299 {
299 {
300 /// Lambda used to set graph's units and range according to the variable passed in parameter
300 /// Lambda used to set graph's units and range according to the variable passed in parameter
301 auto loadRange = [this](std::shared_ptr<Variable> variable, const DateTimeRange &range) {
301 auto loadRange = [this](std::shared_ptr<Variable> variable, const DateTimeRange &range) {
302 impl->m_RenderingDelegate->setAxesUnits(*variable);
302 impl->m_RenderingDelegate->setAxesUnits(*variable);
303
303
304 this->setFlags(GraphFlag::DisableAll);
304 this->setFlags(GraphFlag::DisableAll);
305 setGraphRange(range);
305 setGraphRange(range);
306 this->setFlags(GraphFlag::EnableAll);
306 this->setFlags(GraphFlag::EnableAll);
307 emit requestDataLoading({variable}, range, false);
307 emit requestDataLoading({variable}, range, false);
308 };
308 };
309
309
310 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
310 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
311
311
312 // Calls update of graph's range and units when the data of the variable have been initialized.
312 // Calls update of graph's range and units when the data of the variable have been initialized.
313 // Note: we use QueuedConnection here as the update event must be called in the UI thread
313 // Note: we use QueuedConnection here as the update event must be called in the UI thread
314 connect(variable.get(), &Variable::dataInitialized, this,
314 connect(variable.get(), &Variable::dataInitialized, this,
315 [ varW = std::weak_ptr<Variable>{variable}, range, loadRange, this ]() {
315 [ varW = std::weak_ptr<Variable>{variable}, range, loadRange, this ]() {
316 if (auto var = varW.lock()) {
316 if (auto var = varW.lock()) {
317 // If the variable is the first added in the graph, we load its range
317 // If the variable is the first added in the graph, we load its range
318 auto firstVariableInGraph = range == INVALID_RANGE;
318 auto firstVariableInGraph = range == INVALID_RANGE;
319 auto loadedRange = graphRange();
319 auto loadedRange = graphRange();
320 if (impl->m_VariableAutoRangeOnInit) {
320 if (impl->m_VariableAutoRangeOnInit) {
321 loadedRange = firstVariableInGraph ? var->range() : range;
321 loadedRange = firstVariableInGraph ? var->range() : range;
322 }
322 }
323 loadRange(var, loadedRange);
323 loadRange(var, loadedRange);
324 setYRange(var);
324 setYRange(var);
325 }
325 }
326 },
326 },
327 Qt::QueuedConnection);
327 Qt::QueuedConnection);
328
328
329 // Uses delegate to create the qcpplot components according to the variable
329 // Uses delegate to create the qcpplot components according to the variable
330 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
330 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
331
331
332 // Sets graph properties
332 // Sets graph properties
333 impl->m_RenderingDelegate->setGraphProperties(*variable, createdPlottables);
333 impl->m_RenderingDelegate->setGraphProperties(*variable, createdPlottables);
334
334
335 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
335 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
336
336
337 // If the variable already has its data loaded, load its units and its range in the graph
337 // If the variable already has its data loaded, load its units and its range in the graph
338 if (variable->dataSeries() != nullptr) {
338 if (variable->dataSeries() != nullptr) {
339 loadRange(variable, range);
339 loadRange(variable, range);
340 }
340 }
341
341
342 emit variableAdded(variable);
342 emit variableAdded(variable);
343 }
343 }
344
344
345 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
345 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
346 {
346 {
347 // Each component associated to the variable :
347 // Each component associated to the variable :
348 // - is removed from qcpplot (which deletes it)
348 // - is removed from qcpplot (which deletes it)
349 // - is no longer referenced in the map
349 // - is no longer referenced in the map
350 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
350 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
351 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
351 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
352 emit variableAboutToBeRemoved(variable);
352 emit variableAboutToBeRemoved(variable);
353
353
354 auto &plottablesMap = variableIt->second;
354 auto &plottablesMap = variableIt->second;
355
355
356 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
356 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
357 plottableIt != plottableEnd;) {
357 plottableIt != plottableEnd;) {
358 ui->widget->removePlottable(plottableIt->second);
358 ui->widget->removePlottable(plottableIt->second);
359 plottableIt = plottablesMap.erase(plottableIt);
359 plottableIt = plottablesMap.erase(plottableIt);
360 }
360 }
361
361
362 impl->m_VariableToPlotMultiMap.erase(variableIt);
362 impl->m_VariableToPlotMultiMap.erase(variableIt);
363 }
363 }
364
364
365 // Updates graph
365 // Updates graph
366 ui->widget->replot();
366 ui->widget->replot();
367 }
367 }
368
368
369 std::vector<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
369 std::vector<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
370 {
370 {
371 auto variables = std::vector<std::shared_ptr<Variable> >{};
371 auto variables = std::vector<std::shared_ptr<Variable> >{};
372 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
372 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
373 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
373 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
374 variables.push_back (it->first);
374 variables.push_back (it->first);
375 }
375 }
376
376
377 return variables;
377 return variables;
378 }
378 }
379
379
380 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
380 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
381 {
381 {
382 if (!variable) {
382 if (!variable) {
383 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";
384 return;
384 return;
385 }
385 }
386
386
387 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
387 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
388 }
388 }
389
389
390 DateTimeRange VisualizationGraphWidget::graphRange() const noexcept
390 DateTimeRange VisualizationGraphWidget::graphRange() const noexcept
391 {
391 {
392 auto graphRange = ui->widget->xAxis->range();
392 auto graphRange = ui->widget->xAxis->range();
393 return DateTimeRange{graphRange.lower, graphRange.upper};
393 return DateTimeRange{graphRange.lower, graphRange.upper};
394 }
394 }
395
395
396 void VisualizationGraphWidget::setGraphRange(const DateTimeRange &range, bool calibration)
396 void VisualizationGraphWidget::setGraphRange(const DateTimeRange &range, bool calibration)
397 {
397 {
398 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
398 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
399
399
400 if (calibration) {
400 if (calibration) {
401 impl->m_IsCalibration = true;
401 impl->m_IsCalibration = true;
402 }
402 }
403
403
404 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
404 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
405 ui->widget->replot();
405 ui->widget->replot();
406
406
407 if (calibration) {
407 if (calibration) {
408 impl->m_IsCalibration = false;
408 impl->m_IsCalibration = false;
409 }
409 }
410
410
411 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
411 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
412 }
412 }
413
413
414 void VisualizationGraphWidget::setAutoRangeOnVariableInitialization(bool value)
414 void VisualizationGraphWidget::setAutoRangeOnVariableInitialization(bool value)
415 {
415 {
416 impl->m_VariableAutoRangeOnInit = value;
416 impl->m_VariableAutoRangeOnInit = value;
417 }
417 }
418
418
419 QVector<DateTimeRange> VisualizationGraphWidget::selectionZoneRanges() const
419 QVector<DateTimeRange> VisualizationGraphWidget::selectionZoneRanges() const
420 {
420 {
421 QVector<DateTimeRange> ranges;
421 QVector<DateTimeRange> ranges;
422 for (auto zone : impl->m_SelectionZones) {
422 for (auto zone : impl->m_SelectionZones) {
423 ranges << zone->range();
423 ranges << zone->range();
424 }
424 }
425
425
426 return ranges;
426 return ranges;
427 }
427 }
428
428
429 void VisualizationGraphWidget::addSelectionZones(const QVector<DateTimeRange> &ranges)
429 void VisualizationGraphWidget::addSelectionZones(const QVector<DateTimeRange> &ranges)
430 {
430 {
431 for (const auto &range : ranges) {
431 for (const auto &range : ranges) {
432 // note: ownership is transfered to QCustomPlot
432 // note: ownership is transfered to QCustomPlot
433 auto zone = new VisualizationSelectionZoneItem(&plot());
433 auto zone = new VisualizationSelectionZoneItem(&plot());
434 zone->setRange(range.m_TStart, range.m_TEnd);
434 zone->setRange(range.m_TStart, range.m_TEnd);
435 impl->addSelectionZone(zone);
435 impl->addSelectionZone(zone);
436 }
436 }
437
437
438 plot().replot(QCustomPlot::rpQueuedReplot);
438 plot().replot(QCustomPlot::rpQueuedReplot);
439 }
439 }
440
440
441 VisualizationSelectionZoneItem *VisualizationGraphWidget::addSelectionZone(const QString &name,
441 VisualizationSelectionZoneItem *VisualizationGraphWidget::addSelectionZone(const QString &name,
442 const DateTimeRange &range)
442 const DateTimeRange &range)
443 {
443 {
444 // note: ownership is transfered to QCustomPlot
444 // note: ownership is transfered to QCustomPlot
445 auto zone = new VisualizationSelectionZoneItem(&plot());
445 auto zone = new VisualizationSelectionZoneItem(&plot());
446 zone->setName(name);
446 zone->setName(name);
447 zone->setRange(range.m_TStart, range.m_TEnd);
447 zone->setRange(range.m_TStart, range.m_TEnd);
448 impl->addSelectionZone(zone);
448 impl->addSelectionZone(zone);
449
449
450 plot().replot(QCustomPlot::rpQueuedReplot);
450 plot().replot(QCustomPlot::rpQueuedReplot);
451
451
452 return zone;
452 return zone;
453 }
453 }
454
454
455 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
455 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
456 {
456 {
457 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
457 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
458
458
459 if (impl->m_HoveredZone == selectionZone) {
459 if (impl->m_HoveredZone == selectionZone) {
460 impl->m_HoveredZone = nullptr;
460 impl->m_HoveredZone = nullptr;
461 setCursor(Qt::ArrowCursor);
461 setCursor(Qt::ArrowCursor);
462 }
462 }
463
463
464 impl->m_SelectionZones.removeAll(selectionZone);
464 impl->m_SelectionZones.removeAll(selectionZone);
465 plot().removeItem(selectionZone);
465 plot().removeItem(selectionZone);
466 plot().replot(QCustomPlot::rpQueuedReplot);
466 plot().replot(QCustomPlot::rpQueuedReplot);
467 }
467 }
468
468
469 void VisualizationGraphWidget::undoZoom()
469 void VisualizationGraphWidget::undoZoom()
470 {
470 {
471 auto zoom = impl->m_ZoomStack.pop();
471 auto zoom = impl->m_ZoomStack.pop();
472 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
472 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
473 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
473 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
474
474
475 axisX->setRange(zoom.first);
475 axisX->setRange(zoom.first);
476 axisY->setRange(zoom.second);
476 axisY->setRange(zoom.second);
477
477
478 plot().replot(QCustomPlot::rpQueuedReplot);
478 plot().replot(QCustomPlot::rpQueuedReplot);
479 }
479 }
480
480
481 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
481 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
482 {
482 {
483 if (visitor) {
483 if (visitor) {
484 visitor->visit(this);
484 visitor->visit(this);
485 }
485 }
486 else {
486 else {
487 qCCritical(LOG_VisualizationGraphWidget())
487 qCCritical(LOG_VisualizationGraphWidget())
488 << tr("Can't visit widget : the visitor is null");
488 << tr("Can't visit widget : the visitor is null");
489 }
489 }
490 }
490 }
491
491
492 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
492 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
493 {
493 {
494 auto isSpectrogram = [](const auto &variable) {
494 auto isSpectrogram = [](const auto &variable) {
495 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
495 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
496 };
496 };
497
497
498 // - 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
499 // - 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
500 return isSpectrogram(variable)
500 return isSpectrogram(variable)
501 ? impl->m_VariableToPlotMultiMap.empty()
501 ? impl->m_VariableToPlotMultiMap.empty()
502 : std::none_of(
502 : std::none_of(
503 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
503 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
504 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
504 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
505 }
505 }
506
506
507 bool VisualizationGraphWidget::contains(const Variable &variable) const
507 bool VisualizationGraphWidget::contains(const Variable &variable) const
508 {
508 {
509 // Finds the variable among the keys of the map
509 // Finds the variable among the keys of the map
510 auto variablePtr = &variable;
510 auto variablePtr = &variable;
511 auto findVariable
511 auto findVariable
512 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
512 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
513
513
514 auto end = impl->m_VariableToPlotMultiMap.cend();
514 auto end = impl->m_VariableToPlotMultiMap.cend();
515 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
515 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
516 return it != end;
516 return it != end;
517 }
517 }
518
518
519 QString VisualizationGraphWidget::name() const
519 QString VisualizationGraphWidget::name() const
520 {
520 {
521 return impl->m_Name;
521 return impl->m_Name;
522 }
522 }
523
523
524 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
524 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
525 {
525 {
526 auto mimeData = new QMimeData;
526 auto mimeData = new QMimeData;
527
527
528 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
528 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
529 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
529 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
530 && selectionZoneItemUnderCursor) {
530 && selectionZoneItemUnderCursor) {
531 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
531 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
532 selectionZoneItemUnderCursor->range()));
532 selectionZoneItemUnderCursor->range()));
533 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
533 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
534 selectionZoneItemUnderCursor->range()));
534 selectionZoneItemUnderCursor->range()));
535 }
535 }
536 else {
536 else {
537 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
537 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
538
538
539 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
539 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
540 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
540 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
541 }
541 }
542
542
543 return mimeData;
543 return mimeData;
544 }
544 }
545
545
546 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
546 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
547 {
547 {
548 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
548 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
549 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
549 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
550 && selectionZoneItemUnderCursor) {
550 && selectionZoneItemUnderCursor) {
551
551
552 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
552 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
553 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
553 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
554
554
555 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
555 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
556 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
556 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
557 .toSize();
557 .toSize();
558
558
559 auto pixmap = QPixmap(zoneSize);
559 auto pixmap = QPixmap(zoneSize);
560 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
560 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
561
561
562 return pixmap;
562 return pixmap;
563 }
563 }
564
564
565 return QPixmap();
565 return QPixmap();
566 }
566 }
567
567
568 bool VisualizationGraphWidget::isDragAllowed() const
568 bool VisualizationGraphWidget::isDragAllowed() const
569 {
569 {
570 return true;
570 return true;
571 }
571 }
572
572
573 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
573 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
574 {
574 {
575 if (highlighted) {
575 if (highlighted) {
576 plot().setBackground(QBrush(QColor("#BBD5EE")));
576 plot().setBackground(QBrush(QColor("#BBD5EE")));
577 }
577 }
578 else {
578 else {
579 plot().setBackground(QBrush(Qt::white));
579 plot().setBackground(QBrush(Qt::white));
580 }
580 }
581
581
582 plot().update();
582 plot().update();
583 }
583 }
584
584
585 void VisualizationGraphWidget::addVerticalCursor(double time)
585 void VisualizationGraphWidget::addVerticalCursor(double time)
586 {
586 {
587 impl->m_VerticalCursor->setPosition(time);
587 impl->m_VerticalCursor->setPosition(time);
588 impl->m_VerticalCursor->setVisible(true);
588 impl->m_VerticalCursor->setVisible(true);
589
589
590 auto text
590 auto text
591 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
591 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
592 impl->m_VerticalCursor->setLabelText(text);
592 impl->m_VerticalCursor->setLabelText(text);
593 }
593 }
594
594
595 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
595 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
596 {
596 {
597 impl->m_VerticalCursor->setAbsolutePosition(position);
597 impl->m_VerticalCursor->setAbsolutePosition(position);
598 impl->m_VerticalCursor->setVisible(true);
598 impl->m_VerticalCursor->setVisible(true);
599
599
600 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
600 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
601 auto text
601 auto text
602 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
602 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
603 impl->m_VerticalCursor->setLabelText(text);
603 impl->m_VerticalCursor->setLabelText(text);
604 }
604 }
605
605
606 void VisualizationGraphWidget::removeVerticalCursor()
606 void VisualizationGraphWidget::removeVerticalCursor()
607 {
607 {
608 impl->m_VerticalCursor->setVisible(false);
608 impl->m_VerticalCursor->setVisible(false);
609 plot().replot(QCustomPlot::rpQueuedReplot);
609 plot().replot(QCustomPlot::rpQueuedReplot);
610 }
610 }
611
611
612 void VisualizationGraphWidget::addHorizontalCursor(double value)
612 void VisualizationGraphWidget::addHorizontalCursor(double value)
613 {
613 {
614 impl->m_HorizontalCursor->setPosition(value);
614 impl->m_HorizontalCursor->setPosition(value);
615 impl->m_HorizontalCursor->setVisible(true);
615 impl->m_HorizontalCursor->setVisible(true);
616 impl->m_HorizontalCursor->setLabelText(QString::number(value));
616 impl->m_HorizontalCursor->setLabelText(QString::number(value));
617 }
617 }
618
618
619 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
619 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
620 {
620 {
621 impl->m_HorizontalCursor->setAbsolutePosition(position);
621 impl->m_HorizontalCursor->setAbsolutePosition(position);
622 impl->m_HorizontalCursor->setVisible(true);
622 impl->m_HorizontalCursor->setVisible(true);
623
623
624 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
624 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
625 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
625 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
626 }
626 }
627
627
628 void VisualizationGraphWidget::removeHorizontalCursor()
628 void VisualizationGraphWidget::removeHorizontalCursor()
629 {
629 {
630 impl->m_HorizontalCursor->setVisible(false);
630 impl->m_HorizontalCursor->setVisible(false);
631 plot().replot(QCustomPlot::rpQueuedReplot);
631 plot().replot(QCustomPlot::rpQueuedReplot);
632 }
632 }
633
633
634 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
634 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
635 {
635 {
636 Q_UNUSED(event);
636 Q_UNUSED(event);
637
637
638 for (auto i : impl->m_SelectionZones) {
638 for (auto i : impl->m_SelectionZones) {
639 parentVisualizationWidget()->selectionZoneManager().setSelected(i, false);
639 parentVisualizationWidget()->selectionZoneManager().setSelected(i, false);
640 }
640 }
641
641
642 // Prevents that all variables will be removed from graph when it will be closed
642 // Prevents that all variables will be removed from graph when it will be closed
643 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
643 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
644 emit variableAboutToBeRemoved(variableEntry.first);
644 emit variableAboutToBeRemoved(variableEntry.first);
645 }
645 }
646 }
646 }
647
647
648 void VisualizationGraphWidget::enterEvent(QEvent *event)
648 void VisualizationGraphWidget::enterEvent(QEvent *event)
649 {
649 {
650 Q_UNUSED(event);
650 Q_UNUSED(event);
651 impl->m_RenderingDelegate->showGraphOverlay(true);
651 impl->m_RenderingDelegate->showGraphOverlay(true);
652 }
652 }
653
653
654 void VisualizationGraphWidget::leaveEvent(QEvent *event)
654 void VisualizationGraphWidget::leaveEvent(QEvent *event)
655 {
655 {
656 Q_UNUSED(event);
656 Q_UNUSED(event);
657 impl->m_RenderingDelegate->showGraphOverlay(false);
657 impl->m_RenderingDelegate->showGraphOverlay(false);
658
658
659 if (auto parentZone = parentZoneWidget()) {
659 if (auto parentZone = parentZoneWidget()) {
660 parentZone->notifyMouseLeaveGraph(this);
660 parentZone->notifyMouseLeaveGraph(this);
661 }
661 }
662 else {
662 else {
663 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
663 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
664 }
664 }
665
665
666 if (impl->m_HoveredZone) {
666 if (impl->m_HoveredZone) {
667 impl->m_HoveredZone->setHovered(false);
667 impl->m_HoveredZone->setHovered(false);
668 impl->m_HoveredZone = nullptr;
668 impl->m_HoveredZone = nullptr;
669 }
669 }
670 }
670 }
671
671
672 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
672 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
673 {
673 {
674 return *ui->widget;
674 return *ui->widget;
675 }
675 }
676
676
677 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
677 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
678 {
678 {
679 QMenu graphMenu{};
679 QMenu graphMenu{};
680
680
681 // Iterates on variables (unique keys)
681 // Iterates on variables (unique keys)
682 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
682 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
683 end = impl->m_VariableToPlotMultiMap.cend();
683 end = impl->m_VariableToPlotMultiMap.cend();
684 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
684 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
685 // 'Remove variable' action
685 // 'Remove variable' action
686 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
686 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
687 [ this, var = it->first ]() { removeVariable(var); });
687 [ this, var = it->first ]() { removeVariable(var); });
688 }
688 }
689
689
690 if (!impl->m_ZoomStack.isEmpty()) {
690 if (!impl->m_ZoomStack.isEmpty()) {
691 if (!graphMenu.isEmpty()) {
691 if (!graphMenu.isEmpty()) {
692 graphMenu.addSeparator();
692 graphMenu.addSeparator();
693 }
693 }
694
694
695 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
695 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
696 }
696 }
697
697
698 // Selection Zone Actions
698 // Selection Zone Actions
699 auto selectionZoneItem = impl->selectionZoneAt(pos, plot());
699 auto selectionZoneItem = impl->selectionZoneAt(pos, plot());
700 if (selectionZoneItem) {
700 if (selectionZoneItem) {
701 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
701 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
702 selectedItems.removeAll(selectionZoneItem);
702 selectedItems.removeAll(selectionZoneItem);
703 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
703 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
704
704
705 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
705 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
706 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
706 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
707 graphMenu.addSeparator();
707 graphMenu.addSeparator();
708 }
708 }
709
709
710 QHash<QString, QMenu *> subMenus;
710 QHash<QString, QMenu *> subMenus;
711 QHash<QString, bool> subMenusEnabled;
711 QHash<QString, bool> subMenusEnabled;
712 QHash<QString, FilteringAction *> filteredMenu;
712 QHash<QString, FilteringAction *> filteredMenu;
713
713
714 for (auto zoneAction : zoneActions) {
714 for (auto zoneAction : zoneActions) {
715
715
716 auto isEnabled = zoneAction->isEnabled(selectedItems);
716 auto isEnabled = zoneAction->isEnabled(selectedItems);
717
717
718 auto menu = &graphMenu;
718 auto menu = &graphMenu;
719 QString menuPath;
719 QString menuPath;
720 for (auto subMenuName : zoneAction->subMenuList()) {
720 for (auto subMenuName : zoneAction->subMenuList()) {
721 menuPath += '/';
721 menuPath += '/';
722 menuPath += subMenuName;
722 menuPath += subMenuName;
723
723
724 if (!subMenus.contains(menuPath)) {
724 if (!subMenus.contains(menuPath)) {
725 menu = menu->addMenu(subMenuName);
725 menu = menu->addMenu(subMenuName);
726 subMenus[menuPath] = menu;
726 subMenus[menuPath] = menu;
727 subMenusEnabled[menuPath] = isEnabled;
727 subMenusEnabled[menuPath] = isEnabled;
728 }
728 }
729 else {
729 else {
730 menu = subMenus.value(menuPath);
730 menu = subMenus.value(menuPath);
731 if (isEnabled) {
731 if (isEnabled) {
732 // The sub menu is enabled if at least one of its actions is enabled
732 // The sub menu is enabled if at least one of its actions is enabled
733 subMenusEnabled[menuPath] = true;
733 subMenusEnabled[menuPath] = true;
734 }
734 }
735 }
735 }
736 }
736 }
737
737
738 FilteringAction *filterAction = nullptr;
738 FilteringAction *filterAction = nullptr;
739 if (sqpApp->actionsGuiController().isMenuFiltered(zoneAction->subMenuList())) {
739 if (sqpApp->actionsGuiController().isMenuFiltered(zoneAction->subMenuList())) {
740 filterAction = filteredMenu.value(menuPath);
740 filterAction = filteredMenu.value(menuPath);
741 if (!filterAction) {
741 if (!filterAction) {
742 filterAction = new FilteringAction{this};
742 filterAction = new FilteringAction{this};
743 filteredMenu[menuPath] = filterAction;
743 filteredMenu[menuPath] = filterAction;
744 menu->addAction(filterAction);
744 menu->addAction(filterAction);
745 }
745 }
746 }
746 }
747
747
748 auto action = menu->addAction(zoneAction->name());
748 auto action = menu->addAction(zoneAction->name());
749 action->setEnabled(isEnabled);
749 action->setEnabled(isEnabled);
750 action->setShortcut(zoneAction->displayedShortcut());
750 action->setShortcut(zoneAction->displayedShortcut());
751 QObject::connect(action, &QAction::triggered,
751 QObject::connect(action, &QAction::triggered,
752 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
752 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
753
753
754 if (filterAction && zoneAction->isFilteringAllowed()) {
754 if (filterAction && zoneAction->isFilteringAllowed()) {
755 filterAction->addActionToFilter(action);
755 filterAction->addActionToFilter(action);
756 }
756 }
757 }
757 }
758
758
759 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) {
759 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) {
760 it.value()->setEnabled(subMenusEnabled[it.key()]);
760 it.value()->setEnabled(subMenusEnabled[it.key()]);
761 }
761 }
762 }
762 }
763
763
764 if (!graphMenu.isEmpty()) {
764 if (!graphMenu.isEmpty()) {
765 graphMenu.exec(QCursor::pos());
765 graphMenu.exec(QCursor::pos());
766 }
766 }
767 }
767 }
768
768
769 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
769 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
770 {
770 {
771 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
771 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
772 << QThread::currentThread()->objectName() << "DoAcqui"
772 << QThread::currentThread()->objectName() << "DoAcqui"
773 << impl->m_Flags.testFlag(GraphFlag::EnableAcquisition);
773 << impl->m_Flags.testFlag(GraphFlag::EnableAcquisition);
774
774
775 auto graphRange = DateTimeRange{t1.lower, t1.upper};
775 auto graphRange = DateTimeRange{t1.lower, t1.upper};
776 auto oldGraphRange = DateTimeRange{t2.lower, t2.upper};
776 auto oldGraphRange = DateTimeRange{t2.lower, t2.upper};
777
777
778 if (impl->m_Flags.testFlag(GraphFlag::EnableAcquisition)) {
778 if (impl->m_Flags.testFlag(GraphFlag::EnableAcquisition)) {
779 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
779 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
780
780
781 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
781 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
782 end = impl->m_VariableToPlotMultiMap.end();
782 end = impl->m_VariableToPlotMultiMap.end();
783 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
783 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
784 variableUnderGraphVector.push_back(it->first);
784 variableUnderGraphVector.push_back(it->first);
785 }
785 }
786 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
786 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
787 !impl->m_IsCalibration);
787 !impl->m_IsCalibration);
788 }
788 }
789
789
790 if (impl->m_Flags.testFlag(GraphFlag::EnableSynchronization) && !impl->m_IsCalibration) {
790 if (impl->m_Flags.testFlag(GraphFlag::EnableSynchronization) && !impl->m_IsCalibration) {
791 qCDebug(LOG_VisualizationGraphWidget())
791 qCDebug(LOG_VisualizationGraphWidget())
792 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
792 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
793 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
793 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
794 emit synchronize(graphRange, oldGraphRange);
794 emit synchronize(graphRange, oldGraphRange);
795 }
795 }
796
796
797 auto pos = mapFromGlobal(QCursor::pos());
797 auto pos = mapFromGlobal(QCursor::pos());
798 auto axisPos = impl->posToAxisPos(pos, plot());
798 auto axisPos = impl->posToAxisPos(pos, plot());
799 if (auto parentZone = parentZoneWidget()) {
799 if (auto parentZone = parentZoneWidget()) {
800 if (impl->pointIsInAxisRect(axisPos, plot())) {
800 if (impl->pointIsInAxisRect(axisPos, plot())) {
801 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
801 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
802 }
802 }
803 else {
803 else {
804 parentZone->notifyMouseLeaveGraph(this);
804 parentZone->notifyMouseLeaveGraph(this);
805 }
805 }
806 }
806 }
807 else {
807 else {
808 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
808 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
809 }
809 }
810
810
811 // Quits calibration
811 // Quits calibration
812 impl->m_IsCalibration = false;
812 impl->m_IsCalibration = false;
813 }
813 }
814
814
815 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
815 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
816 {
816 {
817 impl->m_RenderingDelegate->onMouseDoubleClick(event);
817 impl->m_RenderingDelegate->onMouseDoubleClick(event);
818 }
818 }
819
819
820 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
820 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
821 {
821 {
822 // Handles plot rendering when mouse is moving
822 // Handles plot rendering when mouse is moving
823 impl->m_RenderingDelegate->onMouseMove(event);
823 impl->m_RenderingDelegate->onMouseMove(event);
824
824
825 auto axisPos = impl->posToAxisPos(event->pos(), plot());
825 auto axisPos = impl->posToAxisPos(event->pos(), plot());
826
826
827 // Zoom box and zone drawing
827 // Zoom box and zone drawing
828 if (impl->m_DrawingZoomRect) {
828 if (impl->m_DrawingZoomRect) {
829 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
829 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
830 }
830 }
831 else if (impl->m_DrawingZone) {
831 else if (impl->m_DrawingZone) {
832 impl->m_DrawingZone->setEnd(axisPos.x());
832 impl->m_DrawingZone->setEnd(axisPos.x());
833 }
833 }
834
834
835 // Cursor
835 // Cursor
836 if (auto parentZone = parentZoneWidget()) {
836 if (auto parentZone = parentZoneWidget()) {
837 if (impl->pointIsInAxisRect(axisPos, plot())) {
837 if (impl->pointIsInAxisRect(axisPos, plot())) {
838 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
838 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
839 }
839 }
840 else {
840 else {
841 parentZone->notifyMouseLeaveGraph(this);
841 parentZone->notifyMouseLeaveGraph(this);
842 }
842 }
843 }
843 }
844 else {
844 else {
845 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
845 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
846 }
846 }
847
847
848 // Search for the selection zone under the mouse
848 // Search for the selection zone under the mouse
849 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
849 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
850 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
850 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
851 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
851 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
852
852
853 // Sets the appropriate cursor shape
853 // Sets the appropriate cursor shape
854 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
854 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
855 setCursor(cursorShape);
855 setCursor(cursorShape);
856
856
857 // Manages the hovered zone
857 // Manages the hovered zone
858 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
858 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
859 if (impl->m_HoveredZone) {
859 if (impl->m_HoveredZone) {
860 impl->m_HoveredZone->setHovered(false);
860 impl->m_HoveredZone->setHovered(false);
861 }
861 }
862 selectionZoneItemUnderCursor->setHovered(true);
862 selectionZoneItemUnderCursor->setHovered(true);
863 impl->m_HoveredZone = selectionZoneItemUnderCursor;
863 impl->m_HoveredZone = selectionZoneItemUnderCursor;
864 plot().replot(QCustomPlot::rpQueuedReplot);
864 plot().replot(QCustomPlot::rpQueuedReplot);
865 }
865 }
866 }
866 }
867 else {
867 else {
868 // There is no zone under the mouse or the interaction mode is not "selection zones"
868 // There is no zone under the mouse or the interaction mode is not "selection zones"
869 if (impl->m_HoveredZone) {
869 if (impl->m_HoveredZone) {
870 impl->m_HoveredZone->setHovered(false);
870 impl->m_HoveredZone->setHovered(false);
871 impl->m_HoveredZone = nullptr;
871 impl->m_HoveredZone = nullptr;
872 }
872 }
873
873
874 setCursor(Qt::ArrowCursor);
874 setCursor(Qt::ArrowCursor);
875 }
875 }
876
876
877 impl->m_HasMovedMouse = true;
877 impl->m_HasMovedMouse = true;
878 VisualizationDragWidget::mouseMoveEvent(event);
878 VisualizationDragWidget::mouseMoveEvent(event);
879 }
879 }
880
880
881 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
881 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
882 {
882 {
883 // Processes event only if the wheel occurs on axis rect
883 // Processes event only if the wheel occurs on axis rect
884 if (!dynamic_cast<QCPAxisRect *>(ui->widget->layoutElementAt(event->posF()))) {
884 if (!dynamic_cast<QCPAxisRect *>(ui->widget->layoutElementAt(event->posF()))) {
885 return;
885 return;
886 }
886 }
887
887
888 auto value = event->angleDelta().x() + event->angleDelta().y();
888 auto value = event->angleDelta().x() + event->angleDelta().y();
889 if (value != 0) {
889 if (value != 0) {
890
890
891 auto direction = value > 0 ? 1.0 : -1.0;
891 auto direction = value > 0 ? 1.0 : -1.0;
892 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
892 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
893 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
893 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
894 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
894 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
895
895
896 auto zoomOrientations = QFlags<Qt::Orientation>{};
896 auto zoomOrientations = QFlags<Qt::Orientation>{};
897 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
897 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
898 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
898 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
899
899
900 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
900 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
901
901
902 if (!isZoomX && !isZoomY) {
902 if (!isZoomX && !isZoomY) {
903 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
903 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
904 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
904 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
905
905
906 axis->setRange(axis->range() + diff);
906 axis->setRange(axis->range() + diff);
907
907
908 if (plot().noAntialiasingOnDrag()) {
908 if (plot().noAntialiasingOnDrag()) {
909 plot().setNotAntialiasedElements(QCP::aeAll);
909 plot().setNotAntialiasedElements(QCP::aeAll);
910 }
910 }
911
911
912 plot().replot(QCustomPlot::rpQueuedReplot);
912 plot().replot(QCustomPlot::rpQueuedReplot);
913 }
913 }
914 }
914 }
915 }
915 }
916
916
917 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
917 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
918 {
918 {
919 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
919 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
920 auto isSelectionZoneMode
920 auto isSelectionZoneMode
921 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
921 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
922 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
922 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
923
923
924 if (!isDragDropClick && isLeftClick) {
924 if (!isDragDropClick && isLeftClick) {
925 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
925 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
926 // Starts a zoom box
926 // Starts a zoom box
927 impl->startDrawingRect(event->pos(), plot());
927 impl->startDrawingRect(event->pos(), plot());
928 }
928 }
929 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
929 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
930 // Starts a new selection zone
930 // Starts a new selection zone
931 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
931 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
932 if (!zoneAtPos) {
932 if (!zoneAtPos) {
933 impl->startDrawingZone(event->pos(), this);
933 impl->startDrawingZone(event->pos(), this);
934 }
934 }
935 }
935 }
936 }
936 }
937
937
938 // Allows mouse panning only in default mode
938 // Allows mouse panning only in default mode
939 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
939 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
940 == SqpApplication::PlotsInteractionMode::None
940 == SqpApplication::PlotsInteractionMode::None
941 && !isDragDropClick);
941 && !isDragDropClick);
942
942
943 // Allows zone edition only in selection zone mode without drag&drop
943 // Allows zone edition only in selection zone mode without drag&drop
944 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
944 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
945
945
946 // Selection / Deselection
946 // Selection / Deselection
947 if (isSelectionZoneMode) {
947 if (isSelectionZoneMode) {
948 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
948 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
949 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
949 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
950
950
951
951
952 if (selectionZoneItemUnderCursor && !selectionZoneItemUnderCursor->selected()
952 if (selectionZoneItemUnderCursor && !selectionZoneItemUnderCursor->selected()
953 && !isMultiSelectionClick) {
953 && !isMultiSelectionClick) {
954 parentVisualizationWidget()->selectionZoneManager().select(
954 parentVisualizationWidget()->selectionZoneManager().select(
955 {selectionZoneItemUnderCursor});
955 {selectionZoneItemUnderCursor});
956 }
956 }
957 else if (!selectionZoneItemUnderCursor && !isMultiSelectionClick && isLeftClick) {
957 else if (!selectionZoneItemUnderCursor && !isMultiSelectionClick && isLeftClick) {
958 parentVisualizationWidget()->selectionZoneManager().clearSelection();
958 parentVisualizationWidget()->selectionZoneManager().clearSelection();
959 }
959 }
960 else {
960 else {
961 // No selection change
961 // No selection change
962 }
962 }
963
963
964 if (selectionZoneItemUnderCursor && isLeftClick) {
964 if (selectionZoneItemUnderCursor && isLeftClick) {
965 selectionZoneItemUnderCursor->setAssociatedEditedZones(
965 selectionZoneItemUnderCursor->setAssociatedEditedZones(
966 parentVisualizationWidget()->selectionZoneManager().selectedItems());
966 parentVisualizationWidget()->selectionZoneManager().selectedItems());
967 }
967 }
968 }
968 }
969
969
970
970
971 impl->m_HasMovedMouse = false;
971 impl->m_HasMovedMouse = false;
972 VisualizationDragWidget::mousePressEvent(event);
972 VisualizationDragWidget::mousePressEvent(event);
973 }
973 }
974
974
975 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
975 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
976 {
976 {
977 if (impl->m_DrawingZoomRect) {
977 if (impl->m_DrawingZoomRect) {
978
978
979 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
979 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
980 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
980 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
981
981
982 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
982 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
983 impl->m_DrawingZoomRect->bottomRight->coords().x()};
983 impl->m_DrawingZoomRect->bottomRight->coords().x()};
984
984
985 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
985 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
986 impl->m_DrawingZoomRect->bottomRight->coords().y()};
986 impl->m_DrawingZoomRect->bottomRight->coords().y()};
987
987
988 impl->removeDrawingRect(plot());
988 impl->removeDrawingRect(plot());
989
989
990 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
990 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
991 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
991 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
992 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
992 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
993 axisX->setRange(newAxisXRange);
993 axisX->setRange(newAxisXRange);
994 axisY->setRange(newAxisYRange);
994 axisY->setRange(newAxisYRange);
995
995
996 plot().replot(QCustomPlot::rpQueuedReplot);
996 plot().replot(QCustomPlot::rpQueuedReplot);
997 }
997 }
998 }
998 }
999
999
1000 impl->endDrawingZone(this);
1000 impl->endDrawingZone(this);
1001
1001
1002 // Selection / Deselection
1002 // Selection / Deselection
1003 auto isSelectionZoneMode
1003 auto isSelectionZoneMode
1004 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
1004 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
1005 if (isSelectionZoneMode) {
1005 if (isSelectionZoneMode) {
1006 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
1006 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
1007 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
1007 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
1008 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton
1008 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton
1009 && !impl->m_HasMovedMouse) {
1009 && !impl->m_HasMovedMouse) {
1010
1010
1011 auto zonesUnderCursor = impl->selectionZonesAt(event->pos(), plot());
1011 auto zonesUnderCursor = impl->selectionZonesAt(event->pos(), plot());
1012 if (zonesUnderCursor.count() > 1) {
1012 if (zonesUnderCursor.count() > 1) {
1013 // There are multiple zones under the mouse.
1013 // There are multiple zones under the mouse.
1014 // Performs the selection with a selection dialog.
1014 // Performs the selection with a selection dialog.
1015 VisualizationMultiZoneSelectionDialog dialog{this};
1015 VisualizationMultiZoneSelectionDialog dialog{this};
1016 dialog.setZones(zonesUnderCursor);
1016 dialog.setZones(zonesUnderCursor);
1017 dialog.move(mapToGlobal(event->pos() - QPoint(dialog.width() / 2, 20)));
1017 dialog.move(mapToGlobal(event->pos() - QPoint(dialog.width() / 2, 20)));
1018 dialog.activateWindow();
1018 dialog.activateWindow();
1019 dialog.raise();
1019 dialog.raise();
1020 if (dialog.exec() == QDialog::Accepted) {
1020 if (dialog.exec() == QDialog::Accepted) {
1021 auto selection = dialog.selectedZones();
1021 auto selection = dialog.selectedZones();
1022
1022
1023 if (!isMultiSelectionClick) {
1023 if (!isMultiSelectionClick) {
1024 parentVisualizationWidget()->selectionZoneManager().clearSelection();
1024 parentVisualizationWidget()->selectionZoneManager().clearSelection();
1025 }
1025 }
1026
1026
1027 for (auto it = selection.cbegin(); it != selection.cend(); ++it) {
1027 for (auto it = selection.cbegin(); it != selection.cend(); ++it) {
1028 auto zone = it.key();
1028 auto zone = it.key();
1029 auto isSelected = it.value();
1029 auto isSelected = it.value();
1030 parentVisualizationWidget()->selectionZoneManager().setSelected(zone,
1030 parentVisualizationWidget()->selectionZoneManager().setSelected(zone,
1031 isSelected);
1031 isSelected);
1032
1032
1033 if (isSelected) {
1033 if (isSelected) {
1034 // Puts the zone on top of the stack so it can be moved or resized
1034 // Puts the zone on top of the stack so it can be moved or resized
1035 impl->moveSelectionZoneOnTop(zone, plot());
1035 impl->moveSelectionZoneOnTop(zone, plot());
1036 }
1036 }
1037 }
1037 }
1038 }
1038 }
1039 }
1039 }
1040 else {
1040 else {
1041 if (!isMultiSelectionClick) {
1041 if (!isMultiSelectionClick) {
1042 parentVisualizationWidget()->selectionZoneManager().select(
1042 parentVisualizationWidget()->selectionZoneManager().select(
1043 {selectionZoneItemUnderCursor});
1043 {selectionZoneItemUnderCursor});
1044 impl->moveSelectionZoneOnTop(selectionZoneItemUnderCursor, plot());
1044 impl->moveSelectionZoneOnTop(selectionZoneItemUnderCursor, plot());
1045 }
1045 }
1046 else {
1046 else {
1047 parentVisualizationWidget()->selectionZoneManager().setSelected(
1047 parentVisualizationWidget()->selectionZoneManager().setSelected(
1048 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
1048 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
1049 || event->button() == Qt::RightButton);
1049 || event->button() == Qt::RightButton);
1050 }
1050 }
1051 }
1051 }
1052 }
1052 }
1053 else {
1053 else {
1054 // No selection change
1054 // No selection change
1055 }
1055 }
1056 }
1056 }
1057 }
1057 }
1058
1058
1059 void VisualizationGraphWidget::onDataCacheVariableUpdated()
1059 void VisualizationGraphWidget::onDataCacheVariableUpdated()
1060 {
1060 {
1061 auto graphRange = ui->widget->xAxis->range();
1061 auto graphRange = ui->widget->xAxis->range();
1062 auto dateTime = DateTimeRange{graphRange.lower, graphRange.upper};
1062 auto dateTime = DateTimeRange{graphRange.lower, graphRange.upper};
1063
1063
1064 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
1064 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
1065 auto variable = variableEntry.first;
1065 auto variable = variableEntry.first;
1066 qCDebug(LOG_VisualizationGraphWidget())
1066 qCDebug(LOG_VisualizationGraphWidget())
1067 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
1067 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
1068 qCDebug(LOG_VisualizationGraphWidget())
1068 qCDebug(LOG_VisualizationGraphWidget())
1069 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
1069 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
1070 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
1070 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
1071 impl->updateData(variableEntry.second, variable, variable->range());
1071 impl->updateData(variableEntry.second, variable, variable->range());
1072 }
1072 }
1073 }
1073 }
1074 }
1074 }
1075
1075
1076 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
1076 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
1077 const DateTimeRange &range)
1077 const DateTimeRange &range)
1078 {
1078 {
1079 auto it = impl->m_VariableToPlotMultiMap.find(variable);
1079 auto it = impl->m_VariableToPlotMultiMap.find(variable);
1080 if (it != impl->m_VariableToPlotMultiMap.end()) {
1080 if (it != impl->m_VariableToPlotMultiMap.end()) {
1081 impl->updateData(it->second, variable, range);
1081 impl->updateData(it->second, variable, range);
1082 }
1082 }
1083 }
1083 }
@@ -1,268 +1,267
1 #include "FuzzingOperations.h"
1 #include "FuzzingOperations.h"
2 #include "FuzzingUtils.h"
2 #include "FuzzingUtils.h"
3
3
4 #include <Data/IDataProvider.h>
4 #include <Data/IDataProvider.h>
5
5
6 #include <Variable/Variable.h>
6 #include <Variable/Variable.h>
7 #include <Variable/VariableController.h>
7 #include <Variable/VariableController2.h>
8
8
9 #include <QUuid>
9 #include <QUuid>
10
10
11 #include <functional>
11 #include <functional>
12
12
13 Q_LOGGING_CATEGORY(LOG_FuzzingOperations, "FuzzingOperations")
13 Q_LOGGING_CATEGORY(LOG_FuzzingOperations, "FuzzingOperations")
14
14
15 namespace {
15 namespace {
16
16
17 struct CreateOperation : public IFuzzingOperation {
17 struct CreateOperation : public IFuzzingOperation {
18 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
18 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
19 {
19 {
20 // A variable can be created only if it doesn't exist yet
20 // A variable can be created only if it doesn't exist yet
21 return fuzzingState.variableState(variableId).m_Variable == nullptr;
21 return fuzzingState.variableState(variableId).m_Variable == nullptr;
22 }
22 }
23
23
24 void execute(VariableId variableId, FuzzingState &fuzzingState,
24 void execute(VariableId variableId, FuzzingState &fuzzingState,
25 VariableController &variableController,
25 VariableController2 &variableController,
26 const Properties &properties) const override
26 const Properties &properties) const override
27 {
27 {
28 // Retrieves metadata pool from properties, and choose one of the metadata entries to
28 // Retrieves metadata pool from properties, and choose one of the metadata entries to
29 // associate it with the variable
29 // associate it with the variable
30 auto metaDataPool = properties.value(METADATA_POOL_PROPERTY).value<MetadataPool>();
30 auto metaDataPool = properties.value(METADATA_POOL_PROPERTY).value<MetadataPool>();
31 auto variableMetadata = RandomGenerator::instance().randomChoice(metaDataPool);
31 auto variableMetadata = RandomGenerator::instance().randomChoice(metaDataPool);
32
32
33 // Retrieves provider
33 // Retrieves provider
34 auto variableProvider
34 auto variableProvider
35 = properties.value(PROVIDER_PROPERTY).value<std::shared_ptr<IDataProvider> >();
35 = properties.value(PROVIDER_PROPERTY).value<std::shared_ptr<IDataProvider> >();
36
36
37 auto variableName = QString{"Var_%1"}.arg(QUuid::createUuid().toString());
37 auto variableName = QString{"Var_%1"}.arg(QUuid::createUuid().toString());
38 qCInfo(LOG_FuzzingOperations()).noquote() << "Creating variable" << variableName
38 qCInfo(LOG_FuzzingOperations()).noquote() << "Creating variable" << variableName
39 << "(metadata:" << variableMetadata << ")...";
39 << "(metadata:" << variableMetadata << ")...";
40
40
41 auto newVariable
41 auto newVariable
42 = variableController.createVariable(variableName, variableMetadata, variableProvider, properties.value(INITIAL_RANGE_PROPERTY).value<DateTimeRange>());
42 = variableController.createVariable(variableName, variableMetadata, variableProvider, properties.value(INITIAL_RANGE_PROPERTY).value<DateTimeRange>());
43
43
44 // Updates variable's state
44 // Updates variable's state
45 auto &variableState = fuzzingState.variableState(variableId);
45 auto &variableState = fuzzingState.variableState(variableId);
46 variableState.m_Range = properties.value(INITIAL_RANGE_PROPERTY).value<DateTimeRange>();
46 variableState.m_Range = properties.value(INITIAL_RANGE_PROPERTY).value<DateTimeRange>();
47 std::swap(variableState.m_Variable, newVariable);
47 std::swap(variableState.m_Variable, newVariable);
48 }
48 }
49 };
49 };
50
50
51 struct DeleteOperation : public IFuzzingOperation {
51 struct DeleteOperation : public IFuzzingOperation {
52 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
52 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
53 {
53 {
54 // A variable can be delete only if it exists
54 // A variable can be delete only if it exists
55 return fuzzingState.variableState(variableId).m_Variable != nullptr;
55 return fuzzingState.variableState(variableId).m_Variable != nullptr;
56 }
56 }
57
57
58 void execute(VariableId variableId, FuzzingState &fuzzingState,
58 void execute(VariableId variableId, FuzzingState &fuzzingState,
59 VariableController &variableController, const Properties &) const override
59 VariableController2 &variableController, const Properties &) const override
60 {
60 {
61 auto &variableState = fuzzingState.variableState(variableId);
61 auto &variableState = fuzzingState.variableState(variableId);
62
62
63 qCInfo(LOG_FuzzingOperations()).noquote() << "Deleting variable"
63 qCInfo(LOG_FuzzingOperations()).noquote() << "Deleting variable"
64 << variableState.m_Variable->name() << "...";
64 << variableState.m_Variable->name() << "...";
65 variableController.deleteVariable(variableState.m_Variable);
65 variableController.deleteVariable(variableState.m_Variable);
66
66
67 // Updates variable's state
67 // Updates variable's state
68 variableState.m_Range = INVALID_RANGE;
68 variableState.m_Range = INVALID_RANGE;
69 variableState.m_Variable = nullptr;
69 variableState.m_Variable = nullptr;
70
70
71 // Desynchronizes the variable if it was in a sync group
71 // Desynchronizes the variable if it was in a sync group
72 auto syncGroupId = fuzzingState.syncGroupId(variableId);
72 auto syncGroupId = fuzzingState.syncGroupId(variableId);
73 fuzzingState.desynchronizeVariable(variableId, syncGroupId);
73 fuzzingState.desynchronizeVariable(variableId, syncGroupId);
74 }
74 }
75 };
75 };
76
76
77 /**
77 /**
78 * Defines a move operation through a range.
78 * Defines a move operation through a range.
79 *
79 *
80 * A move operation is determined by three functions:
80 * A move operation is determined by three functions:
81 * - Two 'move' functions, used to indicate in which direction the beginning and the end of a range
81 * - Two 'move' functions, used to indicate in which direction the beginning and the end of a range
82 * are going during the operation. These functions will be:
82 * are going during the operation. These functions will be:
83 * -- {<- / <-} for pan left
83 * -- {<- / <-} for pan left
84 * -- {-> / ->} for pan right
84 * -- {-> / ->} for pan right
85 * -- {-> / <-} for zoom in
85 * -- {-> / <-} for zoom in
86 * -- {<- / ->} for zoom out
86 * -- {<- / ->} for zoom out
87 * - One 'max move' functions, used to compute the max delta at which the operation can move a
87 * - One 'max move' functions, used to compute the max delta at which the operation can move a
88 * range, according to a max range. For exemple, for a range of {1, 5} and a max range of {0, 10},
88 * range, according to a max range. For exemple, for a range of {1, 5} and a max range of {0, 10},
89 * max deltas will be:
89 * max deltas will be:
90 * -- {0, 4} for pan left
90 * -- {0, 4} for pan left
91 * -- {6, 10} for pan right
91 * -- {6, 10} for pan right
92 * -- {3, 3} for zoom in
92 * -- {3, 3} for zoom in
93 * -- {0, 6} for zoom out (same spacing left and right)
93 * -- {0, 6} for zoom out (same spacing left and right)
94 */
94 */
95 struct MoveOperation : public IFuzzingOperation {
95 struct MoveOperation : public IFuzzingOperation {
96 using MoveFunction = std::function<double(double currentValue, double maxValue)>;
96 using MoveFunction = std::function<double(double currentValue, double maxValue)>;
97 using MaxMoveFunction = std::function<double(const DateTimeRange &range, const DateTimeRange &maxRange)>;
97 using MaxMoveFunction = std::function<double(const DateTimeRange &range, const DateTimeRange &maxRange)>;
98
98
99 explicit MoveOperation(MoveFunction rangeStartMoveFun, MoveFunction rangeEndMoveFun,
99 explicit MoveOperation(MoveFunction rangeStartMoveFun, MoveFunction rangeEndMoveFun,
100 MaxMoveFunction maxMoveFun,
100 MaxMoveFunction maxMoveFun,
101 const QString &label = QStringLiteral("Move operation"))
101 const QString &label = QStringLiteral("Move operation"))
102 : m_RangeStartMoveFun{std::move(rangeStartMoveFun)},
102 : m_RangeStartMoveFun{std::move(rangeStartMoveFun)},
103 m_RangeEndMoveFun{std::move(rangeEndMoveFun)},
103 m_RangeEndMoveFun{std::move(rangeEndMoveFun)},
104 m_MaxMoveFun{std::move(maxMoveFun)},
104 m_MaxMoveFun{std::move(maxMoveFun)},
105 m_Label{label}
105 m_Label{label}
106 {
106 {
107 }
107 }
108
108
109 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
109 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
110 {
110 {
111 return fuzzingState.variableState(variableId).m_Variable != nullptr;
111 return fuzzingState.variableState(variableId).m_Variable != nullptr;
112 }
112 }
113
113
114 void execute(VariableId variableId, FuzzingState &fuzzingState,
114 void execute(VariableId variableId, FuzzingState &fuzzingState,
115 VariableController &variableController,
115 VariableController2 &variableController,
116 const Properties &properties) const override
116 const Properties &properties) const override
117 {
117 {
118 auto &variableState = fuzzingState.variableState(variableId);
118 auto &variableState = fuzzingState.variableState(variableId);
119 auto variable = variableState.m_Variable;
119 auto variable = variableState.m_Variable;
120
120
121 // Gets the max range defined
121 // Gets the max range defined
122 auto maxRange = properties.value(MAX_RANGE_PROPERTY, QVariant::fromValue(INVALID_RANGE))
122 auto maxRange = properties.value(MAX_RANGE_PROPERTY, QVariant::fromValue(INVALID_RANGE))
123 .value<DateTimeRange>();
123 .value<DateTimeRange>();
124 auto variableRange = variableState.m_Range;
124 auto variableRange = variableState.m_Range;
125
125
126 if (maxRange == INVALID_RANGE || variableRange.m_TStart < maxRange.m_TStart
126 if (maxRange == INVALID_RANGE || variableRange.m_TStart < maxRange.m_TStart
127 || variableRange.m_TEnd > maxRange.m_TEnd) {
127 || variableRange.m_TEnd > maxRange.m_TEnd) {
128 qCWarning(LOG_FuzzingOperations()) << "Can't execute operation: invalid max range";
128 qCWarning(LOG_FuzzingOperations()) << "Can't execute operation: invalid max range";
129 return;
129 return;
130 }
130 }
131
131
132 // Computes the max delta at which the variable can move, up to the limits of the max range
132 // Computes the max delta at which the variable can move, up to the limits of the max range
133 auto deltaMax = m_MaxMoveFun(variableRange, maxRange);
133 auto deltaMax = m_MaxMoveFun(variableRange, maxRange);
134
134
135 // Generates random delta that will be used to move variable
135 // Generates random delta that will be used to move variable
136 auto delta = RandomGenerator::instance().generateDouble(0, deltaMax);
136 auto delta = RandomGenerator::instance().generateDouble(0, deltaMax);
137
137
138 // Moves variable to its new range
138 // Moves variable to its new range
139 auto isSynchronized = !fuzzingState.syncGroupId(variableId).isNull();
139 auto isSynchronized = !fuzzingState.syncGroupId(variableId).isNull();
140 auto newVariableRange = DateTimeRange{m_RangeStartMoveFun(variableRange.m_TStart, delta),
140 auto newVariableRange = DateTimeRange{m_RangeStartMoveFun(variableRange.m_TStart, delta),
141 m_RangeEndMoveFun(variableRange.m_TEnd, delta)};
141 m_RangeEndMoveFun(variableRange.m_TEnd, delta)};
142 qCInfo(LOG_FuzzingOperations()).noquote() << "Performing" << m_Label << "on"
142 qCInfo(LOG_FuzzingOperations()).noquote() << "Performing" << m_Label << "on"
143 << variable->name() << "(from" << variableRange
143 << variable->name() << "(from" << variableRange
144 << "to" << newVariableRange << ")...";
144 << "to" << newVariableRange << ")...";
145 variableController.onRequestDataLoading({variable}, newVariableRange, isSynchronized);
145 variableController.changeRange({variable}, newVariableRange);
146
146
147 // Updates state
147 // Updates state
148 fuzzingState.updateRanges(variableId, newVariableRange);
148 fuzzingState.updateRanges(variableId, newVariableRange);
149 }
149 }
150
150
151 MoveFunction m_RangeStartMoveFun;
151 MoveFunction m_RangeStartMoveFun;
152 MoveFunction m_RangeEndMoveFun;
152 MoveFunction m_RangeEndMoveFun;
153 MaxMoveFunction m_MaxMoveFun;
153 MaxMoveFunction m_MaxMoveFun;
154 QString m_Label;
154 QString m_Label;
155 };
155 };
156
156
157 struct SynchronizeOperation : public IFuzzingOperation {
157 struct SynchronizeOperation : public IFuzzingOperation {
158 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
158 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
159 {
159 {
160 auto variable = fuzzingState.variableState(variableId).m_Variable;
160 auto variable = fuzzingState.variableState(variableId).m_Variable;
161 return variable != nullptr && !fuzzingState.m_SyncGroupsPool.empty()
161 return variable != nullptr && !fuzzingState.m_SyncGroupsPool.empty()
162 && fuzzingState.syncGroupId(variableId).isNull();
162 && fuzzingState.syncGroupId(variableId).isNull();
163 }
163 }
164
164
165 void execute(VariableId variableId, FuzzingState &fuzzingState,
165 void execute(VariableId variableId, FuzzingState &fuzzingState,
166 VariableController &variableController, const Properties &) const override
166 VariableController2 &variableController, const Properties &) const override
167 {
167 {
168 auto &variableState = fuzzingState.variableState(variableId);
168 auto &variableState = fuzzingState.variableState(variableId);
169
169
170 // Chooses a random synchronization group and adds the variable into sync group
170 // Chooses a random synchronization group and adds the variable into sync group
171 auto syncGroupId = RandomGenerator::instance().randomChoice(fuzzingState.syncGroupsIds());
171 auto syncGroupId = RandomGenerator::instance().randomChoice(fuzzingState.syncGroupsIds());
172 qCInfo(LOG_FuzzingOperations()).noquote() << "Adding" << variableState.m_Variable->name()
172 qCInfo(LOG_FuzzingOperations()).noquote() << "Adding" << variableState.m_Variable->name()
173 << "into synchronization group" << syncGroupId
173 << "into synchronization group" << syncGroupId
174 << "...";
174 << "...";
175 variableController.onAddSynchronized(variableState.m_Variable, syncGroupId);
175 //variableController.onAddSynchronized(variableState.m_Variable, syncGroupId);
176
176
177 // Updates state
177 // Updates state
178 fuzzingState.synchronizeVariable(variableId, syncGroupId);
178 fuzzingState.synchronizeVariable(variableId, syncGroupId);
179
179
180 variableController.onRequestDataLoading({variableState.m_Variable}, variableState.m_Range,
180 variableController.changeRange({variableState.m_Variable}, variableState.m_Range);
181 false);
182 }
181 }
183 };
182 };
184
183
185 struct DesynchronizeOperation : public IFuzzingOperation {
184 struct DesynchronizeOperation : public IFuzzingOperation {
186 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
185 bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const override
187 {
186 {
188 auto variable = fuzzingState.variableState(variableId).m_Variable;
187 auto variable = fuzzingState.variableState(variableId).m_Variable;
189 return variable != nullptr && !fuzzingState.syncGroupId(variableId).isNull();
188 return variable != nullptr && !fuzzingState.syncGroupId(variableId).isNull();
190 }
189 }
191
190
192 void execute(VariableId variableId, FuzzingState &fuzzingState,
191 void execute(VariableId variableId, FuzzingState &fuzzingState,
193 VariableController &variableController, const Properties &) const override
192 VariableController2 &variableController, const Properties &) const override
194 {
193 {
195 auto &variableState = fuzzingState.variableState(variableId);
194 auto &variableState = fuzzingState.variableState(variableId);
196
195
197 // Gets the sync group of the variable
196 // Gets the sync group of the variable
198 auto syncGroupId = fuzzingState.syncGroupId(variableId);
197 auto syncGroupId = fuzzingState.syncGroupId(variableId);
199
198
200 qCInfo(LOG_FuzzingOperations()).noquote() << "Removing" << variableState.m_Variable->name()
199 qCInfo(LOG_FuzzingOperations()).noquote() << "Removing" << variableState.m_Variable->name()
201 << "from synchronization group" << syncGroupId
200 << "from synchronization group" << syncGroupId
202 << "...";
201 << "...";
203 variableController.desynchronize(variableState.m_Variable, syncGroupId);
202 //variableController.desynchronize(variableState.m_Variable, syncGroupId);
204
203
205 // Updates state
204 // Updates state
206 fuzzingState.desynchronizeVariable(variableId, syncGroupId);
205 fuzzingState.desynchronizeVariable(variableId, syncGroupId);
207 }
206 }
208 };
207 };
209
208
210 struct UnknownOperation : public IFuzzingOperation {
209 struct UnknownOperation : public IFuzzingOperation {
211 bool canExecute(VariableId, const FuzzingState &) const override { return false; }
210 bool canExecute(VariableId, const FuzzingState &) const override { return false; }
212
211
213 void execute(VariableId, FuzzingState &, VariableController &,
212 void execute(VariableId, FuzzingState &, VariableController2 &,
214 const Properties &) const override
213 const Properties &) const override
215 {
214 {
216 }
215 }
217 };
216 };
218
217
219 } // namespace
218 } // namespace
220
219
221 std::unique_ptr<IFuzzingOperation> FuzzingOperationFactory::create(FuzzingOperationType type)
220 std::unique_ptr<IFuzzingOperation> FuzzingOperationFactory::create(FuzzingOperationType type)
222 {
221 {
223 switch (type) {
222 switch (type) {
224 case FuzzingOperationType::CREATE:
223 case FuzzingOperationType::CREATE:
225 return std::make_unique<CreateOperation>();
224 return std::make_unique<CreateOperation>();
226 case FuzzingOperationType::DELETE:
225 case FuzzingOperationType::DELETE:
227 return std::make_unique<DeleteOperation>();
226 return std::make_unique<DeleteOperation>();
228 case FuzzingOperationType::PAN_LEFT:
227 case FuzzingOperationType::PAN_LEFT:
229 return std::make_unique<MoveOperation>(
228 return std::make_unique<MoveOperation>(
230 std::minus<double>(), std::minus<double>(),
229 std::minus<double>(), std::minus<double>(),
231 [](const DateTimeRange &range, const DateTimeRange &maxRange) {
230 [](const DateTimeRange &range, const DateTimeRange &maxRange) {
232 return range.m_TStart - maxRange.m_TStart;
231 return range.m_TStart - maxRange.m_TStart;
233 },
232 },
234 QStringLiteral("Pan left operation"));
233 QStringLiteral("Pan left operation"));
235 case FuzzingOperationType::PAN_RIGHT:
234 case FuzzingOperationType::PAN_RIGHT:
236 return std::make_unique<MoveOperation>(
235 return std::make_unique<MoveOperation>(
237 std::plus<double>(), std::plus<double>(),
236 std::plus<double>(), std::plus<double>(),
238 [](const DateTimeRange &range, const DateTimeRange &maxRange) {
237 [](const DateTimeRange &range, const DateTimeRange &maxRange) {
239 return maxRange.m_TEnd - range.m_TEnd;
238 return maxRange.m_TEnd - range.m_TEnd;
240 },
239 },
241 QStringLiteral("Pan right operation"));
240 QStringLiteral("Pan right operation"));
242 case FuzzingOperationType::ZOOM_IN:
241 case FuzzingOperationType::ZOOM_IN:
243 return std::make_unique<MoveOperation>(
242 return std::make_unique<MoveOperation>(
244 std::plus<double>(), std::minus<double>(),
243 std::plus<double>(), std::minus<double>(),
245 [](const DateTimeRange &range, const DateTimeRange &maxRange) {
244 [](const DateTimeRange &range, const DateTimeRange &maxRange) {
246 Q_UNUSED(maxRange)
245 Q_UNUSED(maxRange)
247 return range.m_TEnd - (range.m_TStart + range.m_TEnd) / 2.;
246 return range.m_TEnd - (range.m_TStart + range.m_TEnd) / 2.;
248 },
247 },
249 QStringLiteral("Zoom in operation"));
248 QStringLiteral("Zoom in operation"));
250 case FuzzingOperationType::ZOOM_OUT:
249 case FuzzingOperationType::ZOOM_OUT:
251 return std::make_unique<MoveOperation>(
250 return std::make_unique<MoveOperation>(
252 std::minus<double>(), std::plus<double>(),
251 std::minus<double>(), std::plus<double>(),
253 [](const DateTimeRange &range, const DateTimeRange &maxRange) {
252 [](const DateTimeRange &range, const DateTimeRange &maxRange) {
254 return std::min(range.m_TStart - maxRange.m_TStart,
253 return std::min(range.m_TStart - maxRange.m_TStart,
255 maxRange.m_TEnd - range.m_TEnd);
254 maxRange.m_TEnd - range.m_TEnd);
256 },
255 },
257 QStringLiteral("Zoom out operation"));
256 QStringLiteral("Zoom out operation"));
258 case FuzzingOperationType::SYNCHRONIZE:
257 case FuzzingOperationType::SYNCHRONIZE:
259 return std::make_unique<SynchronizeOperation>();
258 return std::make_unique<SynchronizeOperation>();
260 case FuzzingOperationType::DESYNCHRONIZE:
259 case FuzzingOperationType::DESYNCHRONIZE:
261 return std::make_unique<DesynchronizeOperation>();
260 return std::make_unique<DesynchronizeOperation>();
262 default:
261 default:
263 // Default case returns unknown operation
262 // Default case returns unknown operation
264 break;
263 break;
265 }
264 }
266
265
267 return std::make_unique<UnknownOperation>();
266 return std::make_unique<UnknownOperation>();
268 }
267 }
@@ -1,56 +1,57
1 #ifndef SCIQLOP_FUZZINGOPERATIONS_H
1 #ifndef SCIQLOP_FUZZINGOPERATIONS_H
2 #define SCIQLOP_FUZZINGOPERATIONS_H
2 #define SCIQLOP_FUZZINGOPERATIONS_H
3
3
4 #include "FuzzingDefs.h"
4 #include "FuzzingDefs.h"
5
5
6 #include <memory>
6 #include <memory>
7 #include <set>
7 #include <set>
8
8
9 #include <QLoggingCategory>
9 #include <QLoggingCategory>
10 #include <QMetaType>
10 #include <QMetaType>
11 #include <Variable/VariableController2.h>
11
12
12 Q_DECLARE_LOGGING_CATEGORY(LOG_FuzzingOperations)
13 Q_DECLARE_LOGGING_CATEGORY(LOG_FuzzingOperations)
13
14
14 class VariableController;
15 class VariableController;
15
16
16 /**
17 /**
17 * Enumeration of types of existing fuzzing operations
18 * Enumeration of types of existing fuzzing operations
18 */
19 */
19 enum class FuzzingOperationType {
20 enum class FuzzingOperationType {
20 CREATE,
21 CREATE,
21 DELETE,
22 DELETE,
22 PAN_LEFT,
23 PAN_LEFT,
23 PAN_RIGHT,
24 PAN_RIGHT,
24 ZOOM_IN,
25 ZOOM_IN,
25 ZOOM_OUT,
26 ZOOM_OUT,
26 SYNCHRONIZE,
27 SYNCHRONIZE,
27 DESYNCHRONIZE
28 DESYNCHRONIZE
28 };
29 };
29
30
30 /// Interface that represents an operation that can be executed during a fuzzing test
31 /// Interface that represents an operation that can be executed during a fuzzing test
31 struct IFuzzingOperation {
32 struct IFuzzingOperation {
32 virtual ~IFuzzingOperation() noexcept = default;
33 virtual ~IFuzzingOperation() noexcept = default;
33
34
34 /// Checks if the operation can be executed according to the current test's state for the
35 /// Checks if the operation can be executed according to the current test's state for the
35 /// variable passed in parameter
36 /// variable passed in parameter
36 virtual bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const = 0;
37 virtual bool canExecute(VariableId variableId, const FuzzingState &fuzzingState) const = 0;
37 /// Executes the operation on the variable for which its identifier is passed in parameter
38 /// Executes the operation on the variable for which its identifier is passed in parameter
38 /// @param variableId the variable identifier
39 /// @param variableId the variable identifier
39 /// @param fuzzingState the current test's state on which to find the variable and execute the
40 /// @param fuzzingState the current test's state on which to find the variable and execute the
40 /// operation
41 /// operation
41 /// @param variableController the controller associated to the operation
42 /// @param variableController the controller associated to the operation
42 /// @param properties properties that can be used to configure the operation
43 /// @param properties properties that can be used to configure the operation
43 /// @remarks fuzzingState is passed as a reference because, according to the operation, it can
44 /// @remarks fuzzingState is passed as a reference because, according to the operation, it can
44 /// be modified (in/out parameter)
45 /// be modified (in/out parameter)
45 virtual void execute(VariableId variableId, FuzzingState &fuzzingState,
46 virtual void execute(VariableId variableId, FuzzingState &fuzzingState,
46 VariableController &variableController,
47 VariableController2 &variableController,
47 const Properties &properties = {}) const = 0;
48 const Properties &properties = {}) const = 0;
48 };
49 };
49
50
50 /// Factory of @sa IFuzzingOperation
51 /// Factory of @sa IFuzzingOperation
51 struct FuzzingOperationFactory {
52 struct FuzzingOperationFactory {
52 /// Creates a fuzzing operation from a type
53 /// Creates a fuzzing operation from a type
53 static std::unique_ptr<IFuzzingOperation> create(FuzzingOperationType type);
54 static std::unique_ptr<IFuzzingOperation> create(FuzzingOperationType type);
54 };
55 };
55
56
56 #endif // SCIQLOP_FUZZINGOPERATIONS_H
57 #endif // SCIQLOP_FUZZINGOPERATIONS_H
General Comments 0
You need to be logged in to leave comments. Login now