##// END OF EJS Templates
All the codebase is modified to build with new Variable Controller...
jeandet -
r1348:ea7d1a66f4ab
parent child
Show More
@@ -1,54 +1,60
1 cmake_minimum_required(VERSION 3.6)
1 cmake_minimum_required(VERSION 3.6)
2 project(SciQLOP CXX)
2 project(SciQLOP CXX)
3
3
4 include(GNUInstallDirs)
4 include(GNUInstallDirs)
5
5
6 SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/cmake")
6 SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/cmake")
7
7
8 OPTION (CPPCHECK "Analyzes the source code with cppcheck" OFF)
8 OPTION (CPPCHECK "Analyzes the source code with cppcheck" OFF)
9 OPTION (CLANG_TIDY "Analyzes the source code with Clang Tidy" OFF)
9 OPTION (CLANG_TIDY "Analyzes the source code with Clang Tidy" OFF)
10 OPTION (IWYU "Analyzes the source code with Include What You Use" OFF)
10 OPTION (IWYU "Analyzes the source code with Include What You Use" OFF)
11
11
12 set(CMAKE_CXX_STANDARD 17)
12 set(CMAKE_CXX_STANDARD 17)
13
13
14 set(CMAKE_AUTOMOC ON)
14 set(CMAKE_AUTOMOC ON)
15 #https://gitlab.kitware.com/cmake/cmake/issues/15227
15 #https://gitlab.kitware.com/cmake/cmake/issues/15227
16 #set(CMAKE_AUTOUIC ON)
16 #set(CMAKE_AUTOUIC ON)
17 if(POLICY CMP0071)
17 if(POLICY CMP0071)
18 cmake_policy(SET CMP0071 OLD)
18 cmake_policy(SET CMP0071 OLD)
19 endif()
19 endif()
20 set(CMAKE_AUTORCC ON)
20 set(CMAKE_AUTORCC ON)
21 set(CMAKE_INCLUDE_CURRENT_DIR ON)
21 set(CMAKE_INCLUDE_CURRENT_DIR ON)
22
22
23 if(NOT DEFINED CMAKE_INSTALL_RPATH_USE_LINK_PATH)
23 if(NOT DEFINED CMAKE_INSTALL_RPATH_USE_LINK_PATH)
24 set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
24 set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
25 endif()
25 endif()
26 if(NOT DEFINED CMAKE_MACOSX_RPATH)
26 if(NOT DEFINED CMAKE_MACOSX_RPATH)
27 set(CMAKE_MACOSX_RPATH TRUE)
27 set(CMAKE_MACOSX_RPATH TRUE)
28 endif()
28 endif()
29
29
30 if(NOT CMAKE_BUILD_TYPE)
30 if(NOT CMAKE_BUILD_TYPE)
31 set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE)
31 set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE)
32 endif()
32 endif()
33
33
34 find_package(Qt5 COMPONENTS Core Widgets Network PrintSupport Svg Test REQUIRED)
34 find_package(Qt5 COMPONENTS Core Widgets Network PrintSupport Svg Test REQUIRED)
35
35
36 IF(CPPCHECK)
36 IF(CPPCHECK)
37 set(CMAKE_CXX_CPPCHECK "cppcheck;--enable=warning,style")
37 set(CMAKE_CXX_CPPCHECK "cppcheck;--enable=warning,style")
38 ENDIF(CPPCHECK)
38 ENDIF(CPPCHECK)
39
39
40 IF(CLANG_TIDY)
40 IF(CLANG_TIDY)
41 set(CMAKE_CXX_CLANG_TIDY "clang-tidy;-style=file;-checks=*")
41 set(CMAKE_CXX_CLANG_TIDY "clang-tidy;-style=file;-checks=*")
42 ENDIF(CLANG_TIDY)
42 ENDIF(CLANG_TIDY)
43
43
44 IF(IWYU)
44 IF(IWYU)
45 set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "include-what-you-use")
45 set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "include-what-you-use")
46 ENDIF(IWYU)
46 ENDIF(IWYU)
47
47
48 enable_testing()
48 enable_testing()
49
49
50 add_subdirectory(core)
50 find_package(core CONFIG QUIET)
51 if (NOT sciqlopcore_FOUND)
52 execute_process(COMMAND git submodule init core WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
53 execute_process(COMMAND git submodule update core WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
54 add_subdirectory(core)
55 endif()
56
51 add_subdirectory(gui)
57 add_subdirectory(gui)
52 add_subdirectory(app)
58 add_subdirectory(app)
53 add_subdirectory(plugins)
59 add_subdirectory(plugins)
54 add_subdirectory(docs)
60 add_subdirectory(docs)
@@ -1,405 +1,405
1 /*------------------------------------------------------------------------------
1 /*------------------------------------------------------------------------------
2 -- This file is a part of the SciQLop Software
2 -- This file is a part of the SciQLop Software
3 -- Copyright (C) 2017, Plasma Physics Laboratory - CNRS
3 -- Copyright (C) 2017, Plasma Physics Laboratory - CNRS
4 --
4 --
5 -- This program is free software; you can redistribute it and/or modify
5 -- This program is free software; you can redistribute it and/or modify
6 -- it under the terms of the GNU General Public License as published by
6 -- it under the terms of the GNU General Public License as published by
7 -- the Free Software Foundation; either version 2 of the License, or
7 -- the Free Software Foundation; either version 2 of the License, or
8 -- (at your option) any later version.
8 -- (at your option) any later version.
9 --
9 --
10 -- This program is distributed in the hope that it will be useful,
10 -- This program is distributed in the hope that it will be useful,
11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 -- GNU General Public License for more details.
13 -- GNU General Public License for more details.
14 --
14 --
15 -- You should have received a copy of the GNU General Public License
15 -- You should have received a copy of the GNU General Public License
16 -- along with this program; if not, write to the Free Software
16 -- along with this program; if not, write to the Free Software
17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 -------------------------------------------------------------------------------*/
18 -------------------------------------------------------------------------------*/
19 /*-- Author : Alexis Jeandet
19 /*-- Author : Alexis Jeandet
20 -- Mail : alexis.jeandet@member.fsf.org
20 -- Mail : alexis.jeandet@member.fsf.org
21 ----------------------------------------------------------------------------*/
21 ----------------------------------------------------------------------------*/
22 #include "MainWindow.h"
22 #include "MainWindow.h"
23 #include "ui_MainWindow.h"
23 #include "ui_MainWindow.h"
24
24
25 #include <Catalogue/CatalogueController.h>
25 #include <Catalogue/CatalogueController.h>
26 #include <Catalogue/CatalogueExplorer.h>
26 #include <Catalogue/CatalogueExplorer.h>
27 #include <DataSource/DataSourceController.h>
27 #include <DataSource/DataSourceController.h>
28 #include <DataSource/DataSourceWidget.h>
28 #include <DataSource/DataSourceWidget.h>
29 #include <Settings/SqpSettingsDialog.h>
29 #include <Settings/SqpSettingsDialog.h>
30 #include <Settings/SqpSettingsGeneralWidget.h>
30 #include <Settings/SqpSettingsGeneralWidget.h>
31 #include <SidePane/SqpSidePane.h>
31 #include <SidePane/SqpSidePane.h>
32 #include <SqpApplication.h>
32 #include <SqpApplication.h>
33 #include <Time/TimeController.h>
33 #include <Time/TimeController.h>
34 #include <TimeWidget/TimeWidget.h>
34 #include <TimeWidget/TimeWidget.h>
35 #include <Variable/Variable.h>
35 #include <Variable/Variable.h>
36 #include <Variable/VariableController.h>
36 #include <Variable/VariableController.h>
37 #include <Visualization/VisualizationController.h>
37 #include <Visualization/VisualizationController.h>
38
38
39 #include <QAction>
39 #include <QAction>
40 #include <QCloseEvent>
40 #include <QCloseEvent>
41 #include <QDate>
41 #include <QDate>
42 #include <QDir>
42 #include <QDir>
43 #include <QFileDialog>
43 #include <QFileDialog>
44 #include <QMessageBox>
44 #include <QMessageBox>
45 #include <QToolBar>
45 #include <QToolBar>
46 #include <QToolButton>
46 #include <QToolButton>
47 #include <memory.h>
47 #include <memory.h>
48
48
49 #include "iostream"
49 #include "iostream"
50
50
51 Q_LOGGING_CATEGORY(LOG_MainWindow, "MainWindow")
51 Q_LOGGING_CATEGORY(LOG_MainWindow, "MainWindow")
52
52
53 namespace {
53 namespace {
54 const auto LEFTMAININSPECTORWIDGETSPLITTERINDEX = 0;
54 const auto LEFTMAININSPECTORWIDGETSPLITTERINDEX = 0;
55 const auto LEFTINSPECTORSIDEPANESPLITTERINDEX = 1;
55 const auto LEFTINSPECTORSIDEPANESPLITTERINDEX = 1;
56 const auto VIEWPLITTERINDEX = 2;
56 const auto VIEWPLITTERINDEX = 2;
57 const auto RIGHTINSPECTORSIDEPANESPLITTERINDEX = 3;
57 const auto RIGHTINSPECTORSIDEPANESPLITTERINDEX = 3;
58 const auto RIGHTMAININSPECTORWIDGETSPLITTERINDEX = 4;
58 const auto RIGHTMAININSPECTORWIDGETSPLITTERINDEX = 4;
59 }
59 }
60
60
61 class MainWindow::MainWindowPrivate {
61 class MainWindow::MainWindowPrivate {
62 public:
62 public:
63 explicit MainWindowPrivate(MainWindow *mainWindow)
63 explicit MainWindowPrivate(MainWindow *mainWindow)
64 : m_LastOpenLeftInspectorSize{},
64 : m_LastOpenLeftInspectorSize{},
65 m_LastOpenRightInspectorSize{},
65 m_LastOpenRightInspectorSize{},
66 m_GeneralSettingsWidget{new SqpSettingsGeneralWidget{mainWindow}},
66 m_GeneralSettingsWidget{new SqpSettingsGeneralWidget{mainWindow}},
67 m_SettingsDialog{new SqpSettingsDialog{mainWindow}},
67 m_SettingsDialog{new SqpSettingsDialog{mainWindow}},
68 m_CatalogExplorer{new CatalogueExplorer{mainWindow}}
68 m_CatalogExplorer{new CatalogueExplorer{mainWindow}}
69 {
69 {
70 }
70 }
71
71
72 QSize m_LastOpenLeftInspectorSize;
72 QSize m_LastOpenLeftInspectorSize;
73 QSize m_LastOpenRightInspectorSize;
73 QSize m_LastOpenRightInspectorSize;
74 /// General settings widget. MainWindow has the ownership
74 /// General settings widget. MainWindow has the ownership
75 SqpSettingsGeneralWidget *m_GeneralSettingsWidget;
75 SqpSettingsGeneralWidget *m_GeneralSettingsWidget;
76 /// Settings dialog. MainWindow has the ownership
76 /// Settings dialog. MainWindow has the ownership
77 SqpSettingsDialog *m_SettingsDialog;
77 SqpSettingsDialog *m_SettingsDialog;
78 /// Catalogue dialog. MainWindow has the ownership
78 /// Catalogue dialog. MainWindow has the ownership
79 CatalogueExplorer *m_CatalogExplorer;
79 CatalogueExplorer *m_CatalogExplorer;
80
80
81 bool checkDataToSave(QWidget *parentWidget);
81 bool checkDataToSave(QWidget *parentWidget);
82 };
82 };
83
83
84 MainWindow::MainWindow(QWidget *parent)
84 MainWindow::MainWindow(QWidget *parent)
85 : QMainWindow{parent},
85 : QMainWindow{parent},
86 m_Ui{new Ui::MainWindow},
86 m_Ui{new Ui::MainWindow},
87 impl{spimpl::make_unique_impl<MainWindowPrivate>(this)}
87 impl{spimpl::make_unique_impl<MainWindowPrivate>(this)}
88 {
88 {
89 m_Ui->setupUi(this);
89 m_Ui->setupUi(this);
90
90
91 m_Ui->splitter->setCollapsible(LEFTINSPECTORSIDEPANESPLITTERINDEX, false);
91 m_Ui->splitter->setCollapsible(LEFTINSPECTORSIDEPANESPLITTERINDEX, false);
92 m_Ui->splitter->setCollapsible(RIGHTINSPECTORSIDEPANESPLITTERINDEX, false);
92 m_Ui->splitter->setCollapsible(RIGHTINSPECTORSIDEPANESPLITTERINDEX, false);
93
93
94 impl->m_CatalogExplorer->setVisualizationWidget(m_Ui->view);
94 impl->m_CatalogExplorer->setVisualizationWidget(m_Ui->view);
95
95
96
96
97 auto leftSidePane = m_Ui->leftInspectorSidePane->sidePane();
97 auto leftSidePane = m_Ui->leftInspectorSidePane->sidePane();
98 auto openLeftInspectorAction = new QAction{QIcon{
98 auto openLeftInspectorAction = new QAction{QIcon{
99 ":/icones/previous.png",
99 ":/icones/previous.png",
100 },
100 },
101 tr("Show/hide the left inspector"), this};
101 tr("Show/hide the left inspector"), this};
102
102
103
103
104 auto spacerLeftTop = new QWidget{};
104 auto spacerLeftTop = new QWidget{};
105 spacerLeftTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
105 spacerLeftTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
106
106
107 auto spacerLeftBottom = new QWidget{};
107 auto spacerLeftBottom = new QWidget{};
108 spacerLeftBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
108 spacerLeftBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
109
109
110 leftSidePane->addWidget(spacerLeftTop);
110 leftSidePane->addWidget(spacerLeftTop);
111 leftSidePane->addAction(openLeftInspectorAction);
111 leftSidePane->addAction(openLeftInspectorAction);
112 leftSidePane->addWidget(spacerLeftBottom);
112 leftSidePane->addWidget(spacerLeftBottom);
113
113
114
114
115 auto rightSidePane = m_Ui->rightInspectorSidePane->sidePane();
115 auto rightSidePane = m_Ui->rightInspectorSidePane->sidePane();
116 auto openRightInspectorAction = new QAction{QIcon{
116 auto openRightInspectorAction = new QAction{QIcon{
117 ":/icones/next.png",
117 ":/icones/next.png",
118 },
118 },
119 tr("Show/hide the right inspector"), this};
119 tr("Show/hide the right inspector"), this};
120
120
121 auto spacerRightTop = new QWidget{};
121 auto spacerRightTop = new QWidget{};
122 spacerRightTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
122 spacerRightTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
123
123
124 auto spacerRightBottom = new QWidget{};
124 auto spacerRightBottom = new QWidget{};
125 spacerRightBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
125 spacerRightBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
126
126
127 rightSidePane->addWidget(spacerRightTop);
127 rightSidePane->addWidget(spacerRightTop);
128 rightSidePane->addAction(openRightInspectorAction);
128 rightSidePane->addAction(openRightInspectorAction);
129 rightSidePane->addWidget(spacerRightBottom);
129 rightSidePane->addWidget(spacerRightBottom);
130
130
131 openLeftInspectorAction->setCheckable(true);
131 openLeftInspectorAction->setCheckable(true);
132 openRightInspectorAction->setCheckable(true);
132 openRightInspectorAction->setCheckable(true);
133
133
134 auto openInspector = [this](bool checked, bool right, auto action) {
134 auto openInspector = [this](bool checked, bool right, auto action) {
135
135
136 action->setIcon(QIcon{(checked ^ right) ? ":/icones/next.png" : ":/icones/previous.png"});
136 action->setIcon(QIcon{(checked ^ right) ? ":/icones/next.png" : ":/icones/previous.png"});
137
137
138 auto &lastInspectorSize
138 auto &lastInspectorSize
139 = right ? impl->m_LastOpenRightInspectorSize : impl->m_LastOpenLeftInspectorSize;
139 = right ? impl->m_LastOpenRightInspectorSize : impl->m_LastOpenLeftInspectorSize;
140
140
141 auto nextInspectorSize = right ? m_Ui->rightMainInspectorWidget->size()
141 auto nextInspectorSize = right ? m_Ui->rightMainInspectorWidget->size()
142 : m_Ui->leftMainInspectorWidget->size();
142 : m_Ui->leftMainInspectorWidget->size();
143
143
144 // Update of the last opened geometry
144 // Update of the last opened geometry
145 if (checked) {
145 if (checked) {
146 lastInspectorSize = nextInspectorSize;
146 lastInspectorSize = nextInspectorSize;
147 }
147 }
148
148
149 auto startSize = lastInspectorSize;
149 auto startSize = lastInspectorSize;
150 auto endSize = startSize;
150 auto endSize = startSize;
151 endSize.setWidth(0);
151 endSize.setWidth(0);
152
152
153 auto splitterInspectorIndex
153 auto splitterInspectorIndex
154 = right ? RIGHTMAININSPECTORWIDGETSPLITTERINDEX : LEFTMAININSPECTORWIDGETSPLITTERINDEX;
154 = right ? RIGHTMAININSPECTORWIDGETSPLITTERINDEX : LEFTMAININSPECTORWIDGETSPLITTERINDEX;
155
155
156 auto currentSizes = m_Ui->splitter->sizes();
156 auto currentSizes = m_Ui->splitter->sizes();
157 if (checked) {
157 if (checked) {
158 // adjust sizes individually here, e.g.
158 // adjust sizes individually here, e.g.
159 currentSizes[splitterInspectorIndex] -= lastInspectorSize.width();
159 currentSizes[splitterInspectorIndex] -= lastInspectorSize.width();
160 currentSizes[VIEWPLITTERINDEX] += lastInspectorSize.width();
160 currentSizes[VIEWPLITTERINDEX] += lastInspectorSize.width();
161 m_Ui->splitter->setSizes(currentSizes);
161 m_Ui->splitter->setSizes(currentSizes);
162 }
162 }
163 else {
163 else {
164 // adjust sizes individually here, e.g.
164 // adjust sizes individually here, e.g.
165 currentSizes[splitterInspectorIndex] += lastInspectorSize.width();
165 currentSizes[splitterInspectorIndex] += lastInspectorSize.width();
166 currentSizes[VIEWPLITTERINDEX] -= lastInspectorSize.width();
166 currentSizes[VIEWPLITTERINDEX] -= lastInspectorSize.width();
167 m_Ui->splitter->setSizes(currentSizes);
167 m_Ui->splitter->setSizes(currentSizes);
168 }
168 }
169
169
170 };
170 };
171
171
172
172
173 connect(openLeftInspectorAction, &QAction::triggered,
173 connect(openLeftInspectorAction, &QAction::triggered,
174 [openInspector, openLeftInspectorAction](bool checked) {
174 [openInspector, openLeftInspectorAction](bool checked) {
175 openInspector(checked, false, openLeftInspectorAction);
175 openInspector(checked, false, openLeftInspectorAction);
176 });
176 });
177 connect(openRightInspectorAction, &QAction::triggered,
177 connect(openRightInspectorAction, &QAction::triggered,
178 [openInspector, openRightInspectorAction](bool checked) {
178 [openInspector, openRightInspectorAction](bool checked) {
179 openInspector(checked, true, openRightInspectorAction);
179 openInspector(checked, true, openRightInspectorAction);
180 });
180 });
181
181
182 // //////////////// //
182 // //////////////// //
183 // Menu and Toolbar //
183 // Menu and Toolbar //
184 // //////////////// //
184 // //////////////// //
185 this->menuBar()->addAction(tr("File"));
185 this->menuBar()->addAction(tr("File"));
186 auto toolsMenu = this->menuBar()->addMenu(tr("Tools"));
186 auto toolsMenu = this->menuBar()->addMenu(tr("Tools"));
187 toolsMenu->addAction(tr("Settings..."), [this]() {
187 toolsMenu->addAction(tr("Settings..."), [this]() {
188 // Loads settings
188 // Loads settings
189 impl->m_SettingsDialog->loadSettings();
189 impl->m_SettingsDialog->loadSettings();
190
190
191 // Open settings dialog and save settings if the dialog is accepted
191 // Open settings dialog and save settings if the dialog is accepted
192 if (impl->m_SettingsDialog->exec() == QDialog::Accepted) {
192 if (impl->m_SettingsDialog->exec() == QDialog::Accepted) {
193 impl->m_SettingsDialog->saveSettings();
193 impl->m_SettingsDialog->saveSettings();
194 }
194 }
195
195
196 });
196 });
197
197
198 auto mainToolBar = this->addToolBar(QStringLiteral("MainToolBar"));
198 auto mainToolBar = this->addToolBar(QStringLiteral("MainToolBar"));
199
199
200 auto timeWidget = new TimeWidget{};
200 auto timeWidget = new TimeWidget{};
201 mainToolBar->addWidget(timeWidget);
201 mainToolBar->addWidget(timeWidget);
202
202
203 // Interaction modes
203 // Interaction modes
204 auto actionPointerMode = new QAction{QIcon(":/icones/pointer.png"), "Move", this};
204 auto actionPointerMode = new QAction{QIcon(":/icones/pointer.png"), "Move", this};
205 actionPointerMode->setCheckable(true);
205 actionPointerMode->setCheckable(true);
206 actionPointerMode->setChecked(sqpApp->plotsInteractionMode()
206 actionPointerMode->setChecked(sqpApp->plotsInteractionMode()
207 == SqpApplication::PlotsInteractionMode::None);
207 == SqpApplication::PlotsInteractionMode::None);
208 connect(actionPointerMode, &QAction::triggered,
208 connect(actionPointerMode, &QAction::triggered,
209 []() { sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::None); });
209 []() { sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::None); });
210
210
211 auto actionZoomMode = new QAction{QIcon(":/icones/zoom.png"), "Zoom", this};
211 auto actionZoomMode = new QAction{QIcon(":/icones/zoom.png"), "Zoom", this};
212 actionZoomMode->setCheckable(true);
212 actionZoomMode->setCheckable(true);
213 actionZoomMode->setChecked(sqpApp->plotsInteractionMode()
213 actionZoomMode->setChecked(sqpApp->plotsInteractionMode()
214 == SqpApplication::PlotsInteractionMode::ZoomBox);
214 == SqpApplication::PlotsInteractionMode::ZoomBox);
215 connect(actionZoomMode, &QAction::triggered, []() {
215 connect(actionZoomMode, &QAction::triggered, []() {
216 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::ZoomBox);
216 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::ZoomBox);
217 });
217 });
218
218
219 auto actionOrganisationMode = new QAction{QIcon(":/icones/drag.png"), "Organize", this};
219 auto actionOrganisationMode = new QAction{QIcon(":/icones/drag.png"), "Organize", this};
220 actionOrganisationMode->setCheckable(true);
220 actionOrganisationMode->setCheckable(true);
221 actionOrganisationMode->setChecked(sqpApp->plotsInteractionMode()
221 actionOrganisationMode->setChecked(sqpApp->plotsInteractionMode()
222 == SqpApplication::PlotsInteractionMode::DragAndDrop);
222 == SqpApplication::PlotsInteractionMode::DragAndDrop);
223 connect(actionOrganisationMode, &QAction::triggered, []() {
223 connect(actionOrganisationMode, &QAction::triggered, []() {
224 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::DragAndDrop);
224 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::DragAndDrop);
225 });
225 });
226
226
227 auto actionZonesMode = new QAction{QIcon(":/icones/rectangle.png"), "Zones", this};
227 auto actionZonesMode = new QAction{QIcon(":/icones/rectangle.png"), "Zones", this};
228 actionZonesMode->setCheckable(true);
228 actionZonesMode->setCheckable(true);
229 actionZonesMode->setChecked(sqpApp->plotsInteractionMode()
229 actionZonesMode->setChecked(sqpApp->plotsInteractionMode()
230 == SqpApplication::PlotsInteractionMode::SelectionZones);
230 == SqpApplication::PlotsInteractionMode::SelectionZones);
231 connect(actionZonesMode, &QAction::triggered, []() {
231 connect(actionZonesMode, &QAction::triggered, []() {
232 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::SelectionZones);
232 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::SelectionZones);
233 });
233 });
234
234
235 auto modeActionGroup = new QActionGroup{this};
235 auto modeActionGroup = new QActionGroup{this};
236 modeActionGroup->addAction(actionZoomMode);
236 modeActionGroup->addAction(actionZoomMode);
237 modeActionGroup->addAction(actionZonesMode);
237 modeActionGroup->addAction(actionZonesMode);
238 modeActionGroup->addAction(actionOrganisationMode);
238 modeActionGroup->addAction(actionOrganisationMode);
239 modeActionGroup->addAction(actionPointerMode);
239 modeActionGroup->addAction(actionPointerMode);
240 modeActionGroup->setExclusive(true);
240 modeActionGroup->setExclusive(true);
241
241
242 mainToolBar->addSeparator();
242 mainToolBar->addSeparator();
243 mainToolBar->addAction(actionPointerMode);
243 mainToolBar->addAction(actionPointerMode);
244 mainToolBar->addAction(actionZoomMode);
244 mainToolBar->addAction(actionZoomMode);
245 mainToolBar->addAction(actionOrganisationMode);
245 mainToolBar->addAction(actionOrganisationMode);
246 mainToolBar->addAction(actionZonesMode);
246 mainToolBar->addAction(actionZonesMode);
247 mainToolBar->addSeparator();
247 mainToolBar->addSeparator();
248
248
249 // Cursors
249 // Cursors
250 auto btnCursor = new QToolButton{this};
250 auto btnCursor = new QToolButton{this};
251 btnCursor->setIcon(QIcon(":/icones/cursor.png"));
251 btnCursor->setIcon(QIcon(":/icones/cursor.png"));
252 btnCursor->setText("Cursor");
252 btnCursor->setText("Cursor");
253 btnCursor->setToolTip("Cursor");
253 btnCursor->setToolTip("Cursor");
254 btnCursor->setPopupMode(QToolButton::InstantPopup);
254 btnCursor->setPopupMode(QToolButton::InstantPopup);
255 auto cursorMenu = new QMenu("CursorMenu", this);
255 auto cursorMenu = new QMenu("CursorMenu", this);
256 btnCursor->setMenu(cursorMenu);
256 btnCursor->setMenu(cursorMenu);
257
257
258 auto noCursorAction = cursorMenu->addAction("No Cursor");
258 auto noCursorAction = cursorMenu->addAction("No Cursor");
259 noCursorAction->setCheckable(true);
259 noCursorAction->setCheckable(true);
260 noCursorAction->setChecked(sqpApp->plotsCursorMode()
260 noCursorAction->setChecked(sqpApp->plotsCursorMode()
261 == SqpApplication::PlotsCursorMode::NoCursor);
261 == SqpApplication::PlotsCursorMode::NoCursor);
262 connect(noCursorAction, &QAction::triggered,
262 connect(noCursorAction, &QAction::triggered,
263 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::NoCursor); });
263 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::NoCursor); });
264
264
265 cursorMenu->addSeparator();
265 cursorMenu->addSeparator();
266 auto verticalCursorAction = cursorMenu->addAction("Vertical Cursor");
266 auto verticalCursorAction = cursorMenu->addAction("Vertical Cursor");
267 verticalCursorAction->setCheckable(true);
267 verticalCursorAction->setCheckable(true);
268 verticalCursorAction->setChecked(sqpApp->plotsCursorMode()
268 verticalCursorAction->setChecked(sqpApp->plotsCursorMode()
269 == SqpApplication::PlotsCursorMode::Vertical);
269 == SqpApplication::PlotsCursorMode::Vertical);
270 connect(verticalCursorAction, &QAction::triggered,
270 connect(verticalCursorAction, &QAction::triggered,
271 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Vertical); });
271 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Vertical); });
272
272
273 auto temporalCursorAction = cursorMenu->addAction("Temporal Cursor");
273 auto temporalCursorAction = cursorMenu->addAction("Temporal Cursor");
274 temporalCursorAction->setCheckable(true);
274 temporalCursorAction->setCheckable(true);
275 temporalCursorAction->setChecked(sqpApp->plotsCursorMode()
275 temporalCursorAction->setChecked(sqpApp->plotsCursorMode()
276 == SqpApplication::PlotsCursorMode::Temporal);
276 == SqpApplication::PlotsCursorMode::Temporal);
277 connect(temporalCursorAction, &QAction::triggered,
277 connect(temporalCursorAction, &QAction::triggered,
278 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Temporal); });
278 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Temporal); });
279
279
280 auto horizontalCursorAction = cursorMenu->addAction("Horizontal Cursor");
280 auto horizontalCursorAction = cursorMenu->addAction("Horizontal Cursor");
281 horizontalCursorAction->setCheckable(true);
281 horizontalCursorAction->setCheckable(true);
282 horizontalCursorAction->setChecked(sqpApp->plotsCursorMode()
282 horizontalCursorAction->setChecked(sqpApp->plotsCursorMode()
283 == SqpApplication::PlotsCursorMode::Horizontal);
283 == SqpApplication::PlotsCursorMode::Horizontal);
284 connect(horizontalCursorAction, &QAction::triggered,
284 connect(horizontalCursorAction, &QAction::triggered,
285 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Horizontal); });
285 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Horizontal); });
286
286
287 auto crossCursorAction = cursorMenu->addAction("Cross Cursor");
287 auto crossCursorAction = cursorMenu->addAction("Cross Cursor");
288 crossCursorAction->setCheckable(true);
288 crossCursorAction->setCheckable(true);
289 crossCursorAction->setChecked(sqpApp->plotsCursorMode()
289 crossCursorAction->setChecked(sqpApp->plotsCursorMode()
290 == SqpApplication::PlotsCursorMode::Cross);
290 == SqpApplication::PlotsCursorMode::Cross);
291 connect(crossCursorAction, &QAction::triggered,
291 connect(crossCursorAction, &QAction::triggered,
292 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Cross); });
292 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Cross); });
293
293
294 mainToolBar->addWidget(btnCursor);
294 mainToolBar->addWidget(btnCursor);
295
295
296 auto cursorModeActionGroup = new QActionGroup{this};
296 auto cursorModeActionGroup = new QActionGroup{this};
297 cursorModeActionGroup->setExclusive(true);
297 cursorModeActionGroup->setExclusive(true);
298 cursorModeActionGroup->addAction(noCursorAction);
298 cursorModeActionGroup->addAction(noCursorAction);
299 cursorModeActionGroup->addAction(verticalCursorAction);
299 cursorModeActionGroup->addAction(verticalCursorAction);
300 cursorModeActionGroup->addAction(temporalCursorAction);
300 cursorModeActionGroup->addAction(temporalCursorAction);
301 cursorModeActionGroup->addAction(horizontalCursorAction);
301 cursorModeActionGroup->addAction(horizontalCursorAction);
302 cursorModeActionGroup->addAction(crossCursorAction);
302 cursorModeActionGroup->addAction(crossCursorAction);
303
303
304 // Catalog
304 // Catalog
305 mainToolBar->addSeparator();
305 mainToolBar->addSeparator();
306 mainToolBar->addAction(QIcon(":/icones/catalogue.png"), "Catalogues",
306 mainToolBar->addAction(QIcon(":/icones/catalogue.png"), "Catalogues",
307 [this]() { impl->m_CatalogExplorer->show(); });
307 [this]() { impl->m_CatalogExplorer->show(); });
308
308
309 // //////// //
309 // //////// //
310 // Settings //
310 // Settings //
311 // //////// //
311 // //////// //
312
312
313 // Registers "general settings" widget to the settings dialog
313 // Registers "general settings" widget to the settings dialog
314 impl->m_SettingsDialog->registerWidget(QStringLiteral("General"),
314 impl->m_SettingsDialog->registerWidget(QStringLiteral("General"),
315 impl->m_GeneralSettingsWidget);
315 impl->m_GeneralSettingsWidget);
316
316
317 // /////////// //
317 // /////////// //
318 // Connections //
318 // Connections //
319 // /////////// //
319 // /////////// //
320
320
321 // Controllers / controllers connections
321 // Controllers / controllers connections
322 connect(&sqpApp->timeController(), SIGNAL(timeUpdated(DateTimeRange)), &sqpApp->variableController(),
322 // connect(&sqpApp->timeController(), SIGNAL(timeUpdated(DateTimeRange)), &sqpApp->variableController(),
323 SLOT(onDateTimeOnSelection(DateTimeRange)));
323 // SLOT(onDateTimeOnSelection(DateTimeRange)));
324
324
325 // Widgets / controllers connections
325 // Widgets / controllers connections
326
326
327 // DataSource
327 // DataSource
328 connect(&sqpApp->dataSourceController(), SIGNAL(dataSourceItemSet(DataSourceItem *)),
328 connect(&sqpApp->dataSourceController(), SIGNAL(dataSourceItemSet(DataSourceItem *)),
329 m_Ui->dataSourceWidget, SLOT(addDataSource(DataSourceItem *)));
329 m_Ui->dataSourceWidget, SLOT(addDataSource(DataSourceItem *)));
330
330
331 // Time
331 // Time
332 connect(timeWidget, SIGNAL(timeUpdated(DateTimeRange)), &sqpApp->timeController(),
332 connect(timeWidget, SIGNAL(timeUpdated(DateTimeRange)), &sqpApp->timeController(),
333 SLOT(onTimeToUpdate(DateTimeRange)));
333 SLOT(onTimeToUpdate(DateTimeRange)));
334
334
335 // Visualization
335 // Visualization
336 connect(&sqpApp->visualizationController(),
336 connect(&sqpApp->visualizationController(),
337 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), m_Ui->view,
337 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), m_Ui->view,
338 SLOT(onVariableAboutToBeDeleted(std::shared_ptr<Variable>)));
338 SLOT(onVariableAboutToBeDeleted(std::shared_ptr<Variable>)));
339
339
340 connect(&sqpApp->visualizationController(),
340 connect(&sqpApp->visualizationController(),
341 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const DateTimeRange &)), m_Ui->view,
341 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const DateTimeRange &)), m_Ui->view,
342 SLOT(onRangeChanged(std::shared_ptr<Variable>, const DateTimeRange &)));
342 SLOT(onRangeChanged(std::shared_ptr<Variable>, const DateTimeRange &)));
343
343
344 // Widgets / widgets connections
344 // Widgets / widgets connections
345
345
346 // For the following connections, we use DirectConnection to allow each widget that can
346 // For the following connections, we use DirectConnection to allow each widget that can
347 // potentially attach a menu to the variable's menu to do so before this menu is displayed.
347 // potentially attach a menu to the variable's menu to do so before this menu is displayed.
348 // The order of connections is also important, since it determines the order in which each
348 // The order of connections is also important, since it determines the order in which each
349 // widget will attach its menu
349 // widget will attach its menu
350 connect(
350 connect(
351 m_Ui->variableInspectorWidget,
351 m_Ui->variableInspectorWidget,
352 SIGNAL(tableMenuAboutToBeDisplayed(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
352 SIGNAL(tableMenuAboutToBeDisplayed(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
353 m_Ui->view, SLOT(attachVariableMenu(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
353 m_Ui->view, SLOT(attachVariableMenu(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
354 Qt::DirectConnection);
354 Qt::DirectConnection);
355 }
355 }
356
356
357 MainWindow::~MainWindow()
357 MainWindow::~MainWindow()
358 {
358 {
359 }
359 }
360
360
361 void MainWindow::changeEvent(QEvent *e)
361 void MainWindow::changeEvent(QEvent *e)
362 {
362 {
363 QMainWindow::changeEvent(e);
363 QMainWindow::changeEvent(e);
364 switch (e->type()) {
364 switch (e->type()) {
365 case QEvent::LanguageChange:
365 case QEvent::LanguageChange:
366 m_Ui->retranslateUi(this);
366 m_Ui->retranslateUi(this);
367 break;
367 break;
368 default:
368 default:
369 break;
369 break;
370 }
370 }
371 }
371 }
372
372
373 void MainWindow::closeEvent(QCloseEvent *event)
373 void MainWindow::closeEvent(QCloseEvent *event)
374 {
374 {
375 if (!impl->checkDataToSave(this)) {
375 if (!impl->checkDataToSave(this)) {
376 event->ignore();
376 event->ignore();
377 }
377 }
378 else {
378 else {
379 event->accept();
379 event->accept();
380 }
380 }
381 }
381 }
382
382
383 bool MainWindow::MainWindowPrivate::checkDataToSave(QWidget *parentWidget)
383 bool MainWindow::MainWindowPrivate::checkDataToSave(QWidget *parentWidget)
384 {
384 {
385 auto hasChanges = sqpApp->catalogueController().hasChanges();
385 auto hasChanges = sqpApp->catalogueController().hasChanges();
386 if (hasChanges) {
386 if (hasChanges) {
387 // There are some unsaved changes
387 // There are some unsaved changes
388 switch (QMessageBox::question(
388 switch (QMessageBox::question(
389 parentWidget, tr("Save changes"),
389 parentWidget, tr("Save changes"),
390 tr("The catalogue controller has unsaved changes.\nDo you want to save them ?"),
390 tr("The catalogue controller has unsaved changes.\nDo you want to save them ?"),
391 QMessageBox::SaveAll | QMessageBox::Discard | QMessageBox::Cancel,
391 QMessageBox::SaveAll | QMessageBox::Discard | QMessageBox::Cancel,
392 QMessageBox::SaveAll)) {
392 QMessageBox::SaveAll)) {
393 case QMessageBox::SaveAll:
393 case QMessageBox::SaveAll:
394 sqpApp->catalogueController().saveAll();
394 sqpApp->catalogueController().saveAll();
395 break;
395 break;
396 case QMessageBox::Discard:
396 case QMessageBox::Discard:
397 break;
397 break;
398 case QMessageBox::Cancel:
398 case QMessageBox::Cancel:
399 default:
399 default:
400 return false;
400 return false;
401 }
401 }
402 }
402 }
403
403
404 return true;
404 return true;
405 }
405 }
@@ -1,1 +1,1
1 Subproject commit 5a50815a763fb421298a06a6d0380b8f5364e7cd
1 Subproject commit 5f4f9560990ba00394322fa1d06d4a30feaf7075
@@ -1,71 +1,76
1 #ifndef SCIQLOP_SQPAPPLICATION_H
1 #ifndef SCIQLOP_SQPAPPLICATION_H
2 #define SCIQLOP_SQPAPPLICATION_H
2 #define SCIQLOP_SQPAPPLICATION_H
3
3
4 #include "SqpApplication.h"
4 #include "SqpApplication.h"
5
5
6 #include <QApplication>
6 #include <QApplication>
7 #include <QLoggingCategory>
7 #include <QLoggingCategory>
8
8
9 #include <Common/spimpl.h>
9 #include <Common/spimpl.h>
10
10
11 Q_DECLARE_LOGGING_CATEGORY(LOG_SqpApplication)
11 Q_DECLARE_LOGGING_CATEGORY(LOG_SqpApplication)
12
12
13 #if defined(sqpApp)
13 #if defined(sqpApp)
14 #undef sqpApp
14 #undef sqpApp
15 #endif
15 #endif
16 #define sqpApp (static_cast<SqpApplication *>(QCoreApplication::instance()))
16 #define sqpApp (static_cast<SqpApplication *>(QCoreApplication::instance()))
17
17
18 class DataSourceController;
18 class DataSourceController;
19 class NetworkController;
19 class NetworkController;
20 class TimeController;
20 class TimeController;
21 class VariableController;
21 class VariableController;
22 class VariableController2;
23 class VariableModel2;
22 class VisualizationController;
24 class VisualizationController;
23 class DragDropGuiController;
25 class DragDropGuiController;
24 class ActionsGuiController;
26 class ActionsGuiController;
25 class CatalogueController;
27 class CatalogueController;
26
28
27 /**
29 /**
28 * @brief The SqpApplication class aims to make the link between SciQlop
30 * @brief The SqpApplication class aims to make the link between SciQlop
29 * and its plugins. This is the intermediate class that SciQlop has to use
31 * and its plugins. This is the intermediate class that SciQlop has to use
30 * in the way to connect a data source. Please first use load method to initialize
32 * in the way to connect a data source. Please first use load method to initialize
31 * a plugin specified by its metadata name (JSON plugin source) then others specifics
33 * a plugin specified by its metadata name (JSON plugin source) then others specifics
32 * method will be able to access it.
34 * method will be able to access it.
33 * You can load a data source driver plugin then create a data source.
35 * You can load a data source driver plugin then create a data source.
34 */
36 */
35
37
36 class SqpApplication : public QApplication {
38 class SqpApplication : public QApplication {
37 Q_OBJECT
39 Q_OBJECT
38 public:
40 public:
39 explicit SqpApplication(int &argc, char **argv);
41 explicit SqpApplication(int &argc, char **argv);
40 virtual ~SqpApplication();
42 ~SqpApplication() override;
41 void initialize();
43 void initialize();
42
44
43 /// Accessors for the differents sciqlop controllers
45 /// Accessors for the differents sciqlop controllers
44 DataSourceController &dataSourceController() noexcept;
46 DataSourceController &dataSourceController() noexcept;
45 NetworkController &networkController() noexcept;
47 NetworkController &networkController() noexcept;
46 TimeController &timeController() noexcept;
48 TimeController &timeController() noexcept;
47 VariableController &variableController() noexcept;
49 VariableController2 &variableController() noexcept;
50 std::shared_ptr<VariableController2> variableControllerOwner() noexcept;
51 //@TODO there should not be any global model it's just GUI impl detail
52 // VariableModel2 &variableModel() noexcept;
48 VisualizationController &visualizationController() noexcept;
53 VisualizationController &visualizationController() noexcept;
49 CatalogueController &catalogueController() noexcept;
54 CatalogueController &catalogueController() noexcept;
50
55
51 /// Accessors for the differents sciqlop helpers, these helpers classes are like controllers but
56 /// Accessors for the differents sciqlop helpers, these helpers classes are like controllers but
52 /// doesn't live in a thread and access gui
57 /// doesn't live in a thread and access gui
53 DragDropGuiController &dragDropGuiController() noexcept;
58 DragDropGuiController &dragDropGuiController() noexcept;
54 ActionsGuiController &actionsGuiController() noexcept;
59 ActionsGuiController &actionsGuiController() noexcept;
55
60
56 enum class PlotsInteractionMode { None, ZoomBox, DragAndDrop, SelectionZones };
61 enum class PlotsInteractionMode { None, ZoomBox, DragAndDrop, SelectionZones };
57
62
58 enum class PlotsCursorMode { NoCursor, Vertical, Temporal, Horizontal, Cross };
63 enum class PlotsCursorMode { NoCursor, Vertical, Temporal, Horizontal, Cross };
59
64
60 PlotsInteractionMode plotsInteractionMode() const;
65 PlotsInteractionMode plotsInteractionMode() const;
61 void setPlotsInteractionMode(PlotsInteractionMode mode);
66 void setPlotsInteractionMode(PlotsInteractionMode mode);
62
67
63 PlotsCursorMode plotsCursorMode() const;
68 PlotsCursorMode plotsCursorMode() const;
64 void setPlotsCursorMode(PlotsCursorMode mode);
69 void setPlotsCursorMode(PlotsCursorMode mode);
65
70
66 private:
71 private:
67 class SqpApplicationPrivate;
72 class SqpApplicationPrivate;
68 spimpl::unique_impl_ptr<SqpApplicationPrivate> impl;
73 spimpl::unique_impl_ptr<SqpApplicationPrivate> impl;
69 };
74 };
70
75
71 #endif // SCIQLOP_SQPAPPLICATION_H
76 #endif // SCIQLOP_SQPAPPLICATION_H
@@ -1,56 +1,59
1 #ifndef SCIQLOP_VARIABLEINSPECTORWIDGET_H
1 #ifndef SCIQLOP_VARIABLEINSPECTORWIDGET_H
2 #define SCIQLOP_VARIABLEINSPECTORWIDGET_H
2 #define SCIQLOP_VARIABLEINSPECTORWIDGET_H
3
3
4 #include <QLoggingCategory>
4 #include <QLoggingCategory>
5 #include <QMenu>
5 #include <QMenu>
6 #include <QWidget>
6 #include <QWidget>
7
7
8 #include <memory>
8 #include <memory>
9
9
10 #include <Variable/VariableModel2.h>
11
10 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableInspectorWidget)
12 Q_DECLARE_LOGGING_CATEGORY(LOG_VariableInspectorWidget)
11
13
12 class Variable;
14 class Variable;
13
15
14 class QProgressBarItemDelegate;
16 class QProgressBarItemDelegate;
15
17
16 namespace Ui {
18 namespace Ui {
17 class VariableInspectorWidget;
19 class VariableInspectorWidget;
18 } // Ui
20 } // Ui
19
21
20 /**
22 /**
21 * @brief The VariableInspectorWidget class representes represents the variable inspector, from
23 * @brief The VariableInspectorWidget class representes represents the variable inspector, from
22 * which it is possible to view the loaded variables, handle them or trigger their display in
24 * which it is possible to view the loaded variables, handle them or trigger their display in
23 * visualization
25 * visualization
24 */
26 */
25 class VariableInspectorWidget : public QWidget {
27 class VariableInspectorWidget : public QWidget {
26 Q_OBJECT
28 Q_OBJECT
27
29
28 public:
30 public:
29 explicit VariableInspectorWidget(QWidget *parent = 0);
31 explicit VariableInspectorWidget(QWidget *parent = 0);
30 virtual ~VariableInspectorWidget();
32 virtual ~VariableInspectorWidget();
31
33
32 signals:
34 signals:
33 /**
35 /**
34 * Signal emitted before a menu concerning variables is displayed. It is used for other widgets
36 * Signal emitted before a menu concerning variables is displayed. It is used for other widgets
35 * to complete the menu.
37 * to complete the menu.
36 * @param tableMenu the menu to be completed
38 * @param tableMenu the menu to be completed
37 * @param variables the variables concerned by the menu
39 * @param variables the variables concerned by the menu
38 * @remarks To make the dynamic addition of menus work, the connections to this signal must be
40 * @remarks To make the dynamic addition of menus work, the connections to this signal must be
39 * in Qt :: DirectConnection
41 * in Qt :: DirectConnection
40 */
42 */
41 void tableMenuAboutToBeDisplayed(QMenu *tableMenu,
43 void tableMenuAboutToBeDisplayed(QMenu *tableMenu,
42 const QVector<std::shared_ptr<Variable> > &variables);
44 const QVector<std::shared_ptr<Variable> > &variables);
43
45
44 private:
46 private:
45 Ui::VariableInspectorWidget *ui;
47 Ui::VariableInspectorWidget *ui;
46
48
47 QProgressBarItemDelegate *m_ProgressBarItemDelegate;
49 QProgressBarItemDelegate *m_ProgressBarItemDelegate;
50 VariableModel2* m_model;
48
51
49 private slots:
52 private slots:
50 /// Slot called when right clicking on an variable in the table (displays a menu)
53 /// Slot called when right clicking on an variable in the table (displays a menu)
51 void onTableMenuRequested(const QPoint &pos) noexcept;
54 void onTableMenuRequested(const QPoint &pos) noexcept;
52 /// Refreshes instantly the variable view
55 /// Refreshes instantly the variable view
53 void refresh() noexcept;
56 void refresh() noexcept;
54 };
57 };
55
58
56 #endif // SCIQLOP_VARIABLEINSPECTORWIDGET_H
59 #endif // SCIQLOP_VARIABLEINSPECTORWIDGET_H
@@ -1,158 +1,158
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
3
3
4 #include "Visualization/IVisualizationWidget.h"
4 #include "Visualization/IVisualizationWidget.h"
5 #include "Visualization/VisualizationDragWidget.h"
5 #include "Visualization/VisualizationDragWidget.h"
6
6
7 #include <QLoggingCategory>
7 #include <QLoggingCategory>
8 #include <QWidget>
8 #include <QWidget>
9
9
10 #include <memory>
10 #include <memory>
11
11
12 #include <Common/spimpl.h>
12 #include <Common/spimpl.h>
13
13
14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
15
15
16 class QCPRange;
16 class QCPRange;
17 class QCustomPlot;
17 class QCustomPlot;
18 class DateTimeRange;
18 class DateTimeRange;
19 class Variable;
19 class Variable;
20 class VisualizationWidget;
20 class VisualizationWidget;
21 class VisualizationZoneWidget;
21 class VisualizationZoneWidget;
22 class VisualizationSelectionZoneItem;
22 class VisualizationSelectionZoneItem;
23
23
24 namespace Ui {
24 namespace Ui {
25 class VisualizationGraphWidget;
25 class VisualizationGraphWidget;
26 } // namespace Ui
26 } // namespace Ui
27
27
28 /// Defines options that can be associated with the graph
28 /// Defines options that can be associated with the graph
29 enum GraphFlag {
29 enum GraphFlag {
30 DisableAll = 0x0, ///< Disables acquisition and synchronization
30 DisableAll = 0x0, ///< Disables acquisition and synchronization
31 EnableAcquisition = 0x1, ///< When this flag is set, the change of the graph's range leads to
31 EnableAcquisition = 0x1, ///< When this flag is set, the change of the graph's range leads to
32 /// the acquisition of data
32 /// the acquisition of data
33 EnableSynchronization = 0x2, ///< When this flag is set, the change of the graph's range causes
33 EnableSynchronization = 0x2, ///< When this flag is set, the change of the graph's range causes
34 /// the call to the synchronization of the graphs contained in the
34 /// the call to the synchronization of the graphs contained in the
35 /// same zone of this graph
35 /// same zone of this graph
36 EnableAll = ~DisableAll ///< Enables acquisition and synchronization
36 EnableAll = ~DisableAll ///< Enables acquisition and synchronization
37 };
37 };
38
38
39 Q_DECLARE_FLAGS(GraphFlags, GraphFlag)
39 Q_DECLARE_FLAGS(GraphFlags, GraphFlag)
40 Q_DECLARE_OPERATORS_FOR_FLAGS(GraphFlags)
40 Q_DECLARE_OPERATORS_FOR_FLAGS(GraphFlags)
41
41
42 class VisualizationGraphWidget : public VisualizationDragWidget, public IVisualizationWidget {
42 class VisualizationGraphWidget : public VisualizationDragWidget, public IVisualizationWidget {
43 Q_OBJECT
43 Q_OBJECT
44
44
45 friend class QCustomPlotSynchronizer;
45 friend class QCustomPlotSynchronizer;
46 friend class VisualizationGraphRenderingDelegate;
46 friend class VisualizationGraphRenderingDelegate;
47
47
48 public:
48 public:
49 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
49 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
50 virtual ~VisualizationGraphWidget();
50 virtual ~VisualizationGraphWidget();
51
51
52 /// Returns the VisualizationZoneWidget which contains the graph or nullptr
52 /// Returns the VisualizationZoneWidget which contains the graph or nullptr
53 VisualizationZoneWidget *parentZoneWidget() const noexcept;
53 VisualizationZoneWidget *parentZoneWidget() const noexcept;
54
54
55 /// Returns the main VisualizationWidget which contains the graph or nullptr
55 /// Returns the main VisualizationWidget which contains the graph or nullptr
56 VisualizationWidget *parentVisualizationWidget() const;
56 VisualizationWidget *parentVisualizationWidget() const;
57
57
58 /// Sets graph options
58 /// Sets graph options
59 void setFlags(GraphFlags flags);
59 void setFlags(GraphFlags flags);
60
60
61 void addVariable(std::shared_ptr<Variable> variable, DateTimeRange range);
61 void addVariable(std::shared_ptr<Variable> variable, DateTimeRange range);
62
62
63 /// Removes a variable from the graph
63 /// Removes a variable from the graph
64 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
64 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
65
65
66 /// Returns the list of all variables used in the graph
66 /// Returns the list of all variables used in the graph
67 QList<std::shared_ptr<Variable> > variables() const;
67 std::vector<std::shared_ptr<Variable> > variables() const;
68
68
69 /// Sets the y-axis range based on the data of a variable
69 /// Sets the y-axis range based on the data of a variable
70 void setYRange(std::shared_ptr<Variable> variable);
70 void setYRange(std::shared_ptr<Variable> variable);
71 DateTimeRange graphRange() const noexcept;
71 DateTimeRange graphRange() const noexcept;
72 void setGraphRange(const DateTimeRange &range, bool calibration = false);
72 void setGraphRange(const DateTimeRange &range, bool calibration = false);
73 void setAutoRangeOnVariableInitialization(bool value);
73 void setAutoRangeOnVariableInitialization(bool value);
74
74
75 // Zones
75 // Zones
76 /// Returns the ranges of all the selection zones on the graph
76 /// Returns the ranges of all the selection zones on the graph
77 QVector<DateTimeRange> selectionZoneRanges() const;
77 QVector<DateTimeRange> selectionZoneRanges() const;
78 /// Adds new selection zones in the graph
78 /// Adds new selection zones in the graph
79 void addSelectionZones(const QVector<DateTimeRange> &ranges);
79 void addSelectionZones(const QVector<DateTimeRange> &ranges);
80 /// Adds a new selection zone in the graph
80 /// Adds a new selection zone in the graph
81 VisualizationSelectionZoneItem *addSelectionZone(const QString &name, const DateTimeRange &range);
81 VisualizationSelectionZoneItem *addSelectionZone(const QString &name, const DateTimeRange &range);
82 /// Removes the specified selection zone
82 /// Removes the specified selection zone
83 void removeSelectionZone(VisualizationSelectionZoneItem *selectionZone);
83 void removeSelectionZone(VisualizationSelectionZoneItem *selectionZone);
84
84
85 /// Undo the last zoom done with a zoom box
85 /// Undo the last zoom done with a zoom box
86 void undoZoom();
86 void undoZoom();
87
87
88 // IVisualizationWidget interface
88 // IVisualizationWidget interface
89 void accept(IVisualizationWidgetVisitor *visitor) override;
89 void accept(IVisualizationWidgetVisitor *visitor) override;
90 bool canDrop(const Variable &variable) const override;
90 bool canDrop(const Variable &variable) const override;
91 bool contains(const Variable &variable) const override;
91 bool contains(const Variable &variable) const override;
92 QString name() const override;
92 QString name() const override;
93
93
94 // VisualisationDragWidget
94 // VisualisationDragWidget
95 QMimeData *mimeData(const QPoint &position) const override;
95 QMimeData *mimeData(const QPoint &position) const override;
96 QPixmap customDragPixmap(const QPoint &dragPosition) override;
96 QPixmap customDragPixmap(const QPoint &dragPosition) override;
97 bool isDragAllowed() const override;
97 bool isDragAllowed() const override;
98 void highlightForMerge(bool highlighted) override;
98 void highlightForMerge(bool highlighted) override;
99
99
100 // Cursors
100 // Cursors
101 /// Adds or moves the vertical cursor at the specified value on the x-axis
101 /// Adds or moves the vertical cursor at the specified value on the x-axis
102 void addVerticalCursor(double time);
102 void addVerticalCursor(double time);
103 /// Adds or moves the vertical cursor at the specified value on the x-axis
103 /// Adds or moves the vertical cursor at the specified value on the x-axis
104 void addVerticalCursorAtViewportPosition(double position);
104 void addVerticalCursorAtViewportPosition(double position);
105 void removeVerticalCursor();
105 void removeVerticalCursor();
106 /// Adds or moves the vertical cursor at the specified value on the y-axis
106 /// Adds or moves the vertical cursor at the specified value on the y-axis
107 void addHorizontalCursor(double value);
107 void addHorizontalCursor(double value);
108 /// Adds or moves the vertical cursor at the specified value on the y-axis
108 /// Adds or moves the vertical cursor at the specified value on the y-axis
109 void addHorizontalCursorAtViewportPosition(double position);
109 void addHorizontalCursorAtViewportPosition(double position);
110 void removeHorizontalCursor();
110 void removeHorizontalCursor();
111
111
112 signals:
112 signals:
113 void synchronize(const DateTimeRange &range, const DateTimeRange &oldRange);
113 void synchronize(const DateTimeRange &range, const DateTimeRange &oldRange);
114 void requestDataLoading(QVector<std::shared_ptr<Variable> > variable, const DateTimeRange &range,
114 void requestDataLoading(QVector<std::shared_ptr<Variable> > variable, const DateTimeRange &range,
115 bool synchronise);
115 bool synchronise);
116
116
117 /// Signal emitted when the variable is about to be removed from the graph
117 /// Signal emitted when the variable is about to be removed from the graph
118 void variableAboutToBeRemoved(std::shared_ptr<Variable> var);
118 void variableAboutToBeRemoved(std::shared_ptr<Variable> var);
119 /// Signal emitted when the variable has been added to the graph
119 /// Signal emitted when the variable has been added to the graph
120 void variableAdded(std::shared_ptr<Variable> var);
120 void variableAdded(std::shared_ptr<Variable> var);
121
121
122 protected:
122 protected:
123 void closeEvent(QCloseEvent *event) override;
123 void closeEvent(QCloseEvent *event) override;
124 void enterEvent(QEvent *event) override;
124 void enterEvent(QEvent *event) override;
125 void leaveEvent(QEvent *event) override;
125 void leaveEvent(QEvent *event) override;
126
126
127 QCustomPlot &plot() const noexcept;
127 QCustomPlot &plot() const noexcept;
128
128
129 private:
129 private:
130 Ui::VisualizationGraphWidget *ui;
130 Ui::VisualizationGraphWidget *ui;
131
131
132 class VisualizationGraphWidgetPrivate;
132 class VisualizationGraphWidgetPrivate;
133 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
133 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
134
134
135 private slots:
135 private slots:
136 /// Slot called when right clicking on the graph (displays a menu)
136 /// Slot called when right clicking on the graph (displays a menu)
137 void onGraphMenuRequested(const QPoint &pos) noexcept;
137 void onGraphMenuRequested(const QPoint &pos) noexcept;
138
138
139 /// Rescale the X axe to range parameter
139 /// Rescale the X axe to range parameter
140 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
140 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
141
141
142 /// Slot called when a mouse double click was made
142 /// Slot called when a mouse double click was made
143 void onMouseDoubleClick(QMouseEvent *event) noexcept;
143 void onMouseDoubleClick(QMouseEvent *event) noexcept;
144 /// Slot called when a mouse move was made
144 /// Slot called when a mouse move was made
145 void onMouseMove(QMouseEvent *event) noexcept;
145 void onMouseMove(QMouseEvent *event) noexcept;
146 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
146 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
147 void onMouseWheel(QWheelEvent *event) noexcept;
147 void onMouseWheel(QWheelEvent *event) noexcept;
148 /// Slot called when a mouse press was made, to activate the calibration of a graph
148 /// Slot called when a mouse press was made, to activate the calibration of a graph
149 void onMousePress(QMouseEvent *event) noexcept;
149 void onMousePress(QMouseEvent *event) noexcept;
150 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
150 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
151 void onMouseRelease(QMouseEvent *event) noexcept;
151 void onMouseRelease(QMouseEvent *event) noexcept;
152
152
153 void onDataCacheVariableUpdated();
153 void onDataCacheVariableUpdated();
154
154
155 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const DateTimeRange &range);
155 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const DateTimeRange &range);
156 };
156 };
157
157
158 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
158 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
@@ -1,88 +1,88
1 #ifndef SCIQLOP_VISUALIZATIONTABWIDGET_H
1 #ifndef SCIQLOP_VISUALIZATIONTABWIDGET_H
2 #define SCIQLOP_VISUALIZATIONTABWIDGET_H
2 #define SCIQLOP_VISUALIZATIONTABWIDGET_H
3
3
4 #include "Visualization/IVisualizationWidget.h"
4 #include "Visualization/IVisualizationWidget.h"
5
5
6 #include <Common/spimpl.h>
6 #include <Common/spimpl.h>
7
7
8 #include <QLoggingCategory>
8 #include <QLoggingCategory>
9 #include <QMimeData>
9 #include <QMimeData>
10 #include <QWidget>
10 #include <QWidget>
11
11
12 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationTabWidget)
12 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationTabWidget)
13
13
14 class Variable;
14 class Variable;
15 class VisualizationZoneWidget;
15 class VisualizationZoneWidget;
16
16
17 namespace Ui {
17 namespace Ui {
18 class VisualizationTabWidget;
18 class VisualizationTabWidget;
19 } // namespace Ui
19 } // namespace Ui
20
20
21 class VisualizationTabWidget : public QWidget, public IVisualizationWidget {
21 class VisualizationTabWidget : public QWidget, public IVisualizationWidget {
22 Q_OBJECT
22 Q_OBJECT
23
23
24 public:
24 public:
25 explicit VisualizationTabWidget(const QString &name = {}, QWidget *parent = 0);
25 explicit VisualizationTabWidget(const QString &name = {}, QWidget *parent = 0);
26 virtual ~VisualizationTabWidget();
26 virtual ~VisualizationTabWidget();
27
27
28 /// Adds a zone widget
28 /// Adds a zone widget
29 void addZone(VisualizationZoneWidget *zoneWidget);
29 void addZone(VisualizationZoneWidget *zoneWidget);
30
30
31 /// Inserts a zone widget at the specified position
31 /// Inserts a zone widget at the specified position
32 void insertZone(int index, VisualizationZoneWidget *zoneWidget);
32 void insertZone(int index, VisualizationZoneWidget *zoneWidget);
33
33
34 /// Returns the list of zone widget names in the order they are displayed
34 /// Returns the list of zone widget names in the order they are displayed
35 QStringList availableZoneWidgets() const;
35 QStringList availableZoneWidgets() const;
36
36
37 /// Returns the zone with the specified name.
37 /// Returns the zone with the specified name.
38 /// If multiple zone with the same name exist, the first one is returned.
38 /// If multiple zone with the same name exist, the first one is returned.
39 VisualizationZoneWidget *getZoneWithName(const QString &zoneName);
39 VisualizationZoneWidget *getZoneWithName(const QString &zoneName);
40
40
41 /**
41 /**
42 * Creates a zone using a variable. The variable will be displayed in a new graph of the new
42 * Creates a zone using a variable. The variable will be displayed in a new graph of the new
43 * zone. The zone is added at the end.
43 * zone. The zone is added at the end.
44 * @param variable the variable for which to create the zone
44 * @param variable the variable for which to create the zone
45 * @return the pointer to the created zone
45 * @return the pointer to the created zone
46 */
46 */
47 VisualizationZoneWidget *createZone(std::shared_ptr<Variable> variable);
47 VisualizationZoneWidget *createZone(std::shared_ptr<Variable> variable);
48
48
49 /**
49 /**
50 * Creates a zone using a list of variables. The variables will be displayed in a new graph of
50 * Creates a zone using a list of variables. The variables will be displayed in a new graph of
51 * the new zone. The zone is inserted at the specified index.
51 * the new zone. The zone is inserted at the specified index.
52 * @param variables the variables for which to create the zone
52 * @param variables the variables for which to create the zone
53 * @param index The index where the zone should be inserted in the layout
53 * @param index The index where the zone should be inserted in the layout
54 * @return the pointer to the created zone
54 * @return the pointer to the created zone
55 */
55 */
56 VisualizationZoneWidget *createZone(const QList<std::shared_ptr<Variable> > &variables,
56 VisualizationZoneWidget *createZone(const std::vector<std::shared_ptr<Variable> > &variables,
57 int index);
57 int index);
58
58
59 /**
59 /**
60 * Creates a zone which is empty (no variables). The zone is inserted at the specified index.
60 * Creates a zone which is empty (no variables). The zone is inserted at the specified index.
61 * @param index The index where the zone should be inserted in the layout
61 * @param index The index where the zone should be inserted in the layout
62 * @return the pointer to the created zone
62 * @return the pointer to the created zone
63 */
63 */
64 VisualizationZoneWidget *createEmptyZone(int index);
64 VisualizationZoneWidget *createEmptyZone(int index);
65
65
66 // IVisualizationWidget interface
66 // IVisualizationWidget interface
67 void accept(IVisualizationWidgetVisitor *visitor) override;
67 void accept(IVisualizationWidgetVisitor *visitor) override;
68 bool canDrop(const Variable &variable) const override;
68 bool canDrop(const Variable &variable) const override;
69 bool contains(const Variable &variable) const override;
69 bool contains(const Variable &variable) const override;
70 QString name() const override;
70 QString name() const override;
71
71
72 protected:
72 protected:
73 void closeEvent(QCloseEvent *event) override;
73 void closeEvent(QCloseEvent *event) override;
74
74
75 private:
75 private:
76 /// @return the layout of tab in which zones are added
76 /// @return the layout of tab in which zones are added
77 QLayout &tabLayout() const noexcept;
77 QLayout &tabLayout() const noexcept;
78
78
79 Ui::VisualizationTabWidget *ui;
79 Ui::VisualizationTabWidget *ui;
80
80
81 class VisualizationTabWidgetPrivate;
81 class VisualizationTabWidgetPrivate;
82 spimpl::unique_impl_ptr<VisualizationTabWidgetPrivate> impl;
82 spimpl::unique_impl_ptr<VisualizationTabWidgetPrivate> impl;
83
83
84 private slots:
84 private slots:
85 void dropMimeData(int index, const QMimeData *mimeData);
85 void dropMimeData(int index, const QMimeData *mimeData);
86 };
86 };
87
87
88 #endif // SCIQLOP_VISUALIZATIONTABWIDGET_H
88 #endif // SCIQLOP_VISUALIZATIONTABWIDGET_H
@@ -1,106 +1,106
1 #ifndef SCIQLOP_VISUALIZATIONZONEWIDGET_H
1 #ifndef SCIQLOP_VISUALIZATIONZONEWIDGET_H
2 #define SCIQLOP_VISUALIZATIONZONEWIDGET_H
2 #define SCIQLOP_VISUALIZATIONZONEWIDGET_H
3
3
4 #include "Data/DateTimeRange.h"
4 #include "Data/DateTimeRange.h"
5 #include "Visualization/IVisualizationWidget.h"
5 #include "Visualization/IVisualizationWidget.h"
6 #include "Visualization/VisualizationDragWidget.h"
6 #include "Visualization/VisualizationDragWidget.h"
7
7
8 #include <QLoggingCategory>
8 #include <QLoggingCategory>
9 #include <QWidget>
9 #include <QWidget>
10
10
11 #include <memory>
11 #include <memory>
12
12
13 #include <Common/spimpl.h>
13 #include <Common/spimpl.h>
14
14
15 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationZoneWidget)
15 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationZoneWidget)
16
16
17 namespace Ui {
17 namespace Ui {
18 class VisualizationZoneWidget;
18 class VisualizationZoneWidget;
19 } // namespace Ui
19 } // namespace Ui
20
20
21 class Variable;
21 class Variable;
22 class VisualizationGraphWidget;
22 class VisualizationGraphWidget;
23
23
24 class VisualizationZoneWidget : public VisualizationDragWidget, public IVisualizationWidget {
24 class VisualizationZoneWidget : public VisualizationDragWidget, public IVisualizationWidget {
25 Q_OBJECT
25 Q_OBJECT
26
26
27 public:
27 public:
28 explicit VisualizationZoneWidget(const QString &name = {}, QWidget *parent = 0);
28 explicit VisualizationZoneWidget(const QString &name = {}, QWidget *parent = 0);
29 virtual ~VisualizationZoneWidget();
29 virtual ~VisualizationZoneWidget();
30
30
31 /// Sets the range of the zone, only works if there is at least one graph in the zone
31 /// Sets the range of the zone, only works if there is at least one graph in the zone
32 /// Note: calibrations between graphs are lost.
32 /// Note: calibrations between graphs are lost.
33 void setZoneRange(const DateTimeRange &range);
33 void setZoneRange(const DateTimeRange &range);
34
34
35 /// Adds a graph widget
35 /// Adds a graph widget
36 void addGraph(VisualizationGraphWidget *graphWidget);
36 void addGraph(VisualizationGraphWidget *graphWidget);
37
37
38 /// Inserts a graph widget
38 /// Inserts a graph widget
39 void insertGraph(int index, VisualizationGraphWidget *graphWidget);
39 void insertGraph(int index, VisualizationGraphWidget *graphWidget);
40
40
41 /**
41 /**
42 * Creates a graph using a variable. The variable will be displayed in the new graph.
42 * Creates a graph using a variable. The variable will be displayed in the new graph.
43 * The graph is added at the end.
43 * The graph is added at the end.
44 * @param variable the variable for which to create the graph
44 * @param variable the variable for which to create the graph
45 * @return the pointer to the created graph
45 * @return the pointer to the created graph
46 */
46 */
47 VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable);
47 VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable);
48
48
49 /**
49 /**
50 * Creates a graph using a variable. The variable will be displayed in the new graph.
50 * Creates a graph using a variable. The variable will be displayed in the new graph.
51 * The graph is inserted at the specified index.
51 * The graph is inserted at the specified index.
52 * @param variable the variable for which to create the graph
52 * @param variable the variable for which to create the graph
53 * @param index The index where the graph should be inserted in the layout
53 * @param index The index where the graph should be inserted in the layout
54 * @return the pointer to the created graph
54 * @return the pointer to the created graph
55 */
55 */
56 VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable, int index);
56 VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable, int index);
57
57
58 /**
58 /**
59 * Creates a graph using a list of variables. The variables will be displayed in the new graph.
59 * Creates a graph using a list of variables. The variables will be displayed in the new graph.
60 * The graph is inserted at the specified index.
60 * The graph is inserted at the specified index.
61 * @param variables List of variables to be added to the graph
61 * @param variables List of variables to be added to the graph
62 * @param index The index where the graph should be inserted in the layout
62 * @param index The index where the graph should be inserted in the layout
63 * @return the pointer to the created graph
63 * @return the pointer to the created graph
64 */
64 */
65 VisualizationGraphWidget *createGraph(const QList<std::shared_ptr<Variable> > variables,
65 VisualizationGraphWidget *createGraph( std::vector<std::shared_ptr<Variable> > variables,
66 int index);
66 int index);
67
67
68 /// Returns the first graph in the zone or nullptr if there is no graph inside
68 /// Returns the first graph in the zone or nullptr if there is no graph inside
69 VisualizationGraphWidget *firstGraph() const;
69 VisualizationGraphWidget *firstGraph() const;
70
70
71 /// Closes all graphes inside the zone
71 /// Closes all graphes inside the zone
72 void closeAllGraphs();
72 void closeAllGraphs();
73
73
74 // IVisualizationWidget interface
74 // IVisualizationWidget interface
75 void accept(IVisualizationWidgetVisitor *visitor) override;
75 void accept(IVisualizationWidgetVisitor *visitor) override;
76 bool canDrop(const Variable &variable) const override;
76 bool canDrop(const Variable &variable) const override;
77 bool contains(const Variable &variable) const override;
77 bool contains(const Variable &variable) const override;
78 QString name() const override;
78 QString name() const override;
79
79
80 // VisualisationDragWidget
80 // VisualisationDragWidget
81 QMimeData *mimeData(const QPoint &position) const override;
81 QMimeData *mimeData(const QPoint &position) const override;
82 bool isDragAllowed() const override;
82 bool isDragAllowed() const override;
83
83
84 void notifyMouseMoveInGraph(const QPointF &graphPosition, const QPointF &plotPosition,
84 void notifyMouseMoveInGraph(const QPointF &graphPosition, const QPointF &plotPosition,
85 VisualizationGraphWidget *graphWidget);
85 VisualizationGraphWidget *graphWidget);
86 void notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget);
86 void notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget);
87
87
88 protected:
88 protected:
89 void closeEvent(QCloseEvent *event) override;
89 void closeEvent(QCloseEvent *event) override;
90
90
91 private:
91 private:
92 Ui::VisualizationZoneWidget *ui;
92 Ui::VisualizationZoneWidget *ui;
93
93
94 class VisualizationZoneWidgetPrivate;
94 class VisualizationZoneWidgetPrivate;
95 spimpl::unique_impl_ptr<VisualizationZoneWidgetPrivate> impl;
95 spimpl::unique_impl_ptr<VisualizationZoneWidgetPrivate> impl;
96
96
97 private slots:
97 private slots:
98 void onVariableAdded(std::shared_ptr<Variable> variable);
98 void onVariableAdded(std::shared_ptr<Variable> variable);
99 /// Slot called when a variable is about to be removed from a graph contained in the zone
99 /// Slot called when a variable is about to be removed from a graph contained in the zone
100 void onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable);
100 void onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable);
101
101
102 void dropMimeData(int index, const QMimeData *mimeData);
102 void dropMimeData(int index, const QMimeData *mimeData);
103 void dropMimeDataOnGraph(VisualizationDragWidget *dragWidget, const QMimeData *mimeData);
103 void dropMimeDataOnGraph(VisualizationDragWidget *dragWidget, const QMimeData *mimeData);
104 };
104 };
105
105
106 #endif // SCIQLOP_VISUALIZATIONZONEWIDGET_H
106 #endif // SCIQLOP_VISUALIZATIONZONEWIDGET_H
@@ -1,617 +1,616
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>
14 #include <Variable/VariableController.h>
15 #include <Variable/VariableController2.h>
15 #include <Visualization/VisualizationGraphWidget.h>
16 #include <Visualization/VisualizationGraphWidget.h>
16 #include <Visualization/VisualizationTabWidget.h>
17 #include <Visualization/VisualizationTabWidget.h>
17 #include <Visualization/VisualizationWidget.h>
18 #include <Visualization/VisualizationWidget.h>
18 #include <Visualization/VisualizationZoneWidget.h>
19 #include <Visualization/VisualizationZoneWidget.h>
19
20
20 #include <QActionGroup>
21 #include <QActionGroup>
21 #include <QDialog>
22 #include <QDialog>
22 #include <QDialogButtonBox>
23 #include <QDialogButtonBox>
23 #include <QKeyEvent>
24 #include <QKeyEvent>
24 #include <QListWidget>
25 #include <QListWidget>
25 #include <QMenu>
26 #include <QMenu>
26 #include <QMessageBox>
27 #include <QMessageBox>
27
28
28 Q_LOGGING_CATEGORY(LOG_CatalogueEventsWidget, "CatalogueEventsWidget")
29 Q_LOGGING_CATEGORY(LOG_CatalogueEventsWidget, "CatalogueEventsWidget")
29
30
30 /// Percentage added to the range of a event when it is displayed
31 /// Percentage added to the range of a event when it is displayed
31 const auto EVENT_RANGE_MARGE = 30; // in %
32 const auto EVENT_RANGE_MARGE = 30; // in %
32
33
33 const QString NEW_ZONE_TEXT = QStringLiteral("New Zone");
34 const QString NEW_ZONE_TEXT = QStringLiteral("New Zone");
34
35
35 struct CatalogueEventsWidget::CatalogueEventsWidgetPrivate {
36 struct CatalogueEventsWidget::CatalogueEventsWidgetPrivate {
36
37
37 CatalogueEventsModel *m_Model = nullptr;
38 CatalogueEventsModel *m_Model = nullptr;
38 QStringList m_ZonesForTimeMode;
39 QStringList m_ZonesForTimeMode;
39 QString m_ZoneForGraphMode;
40 QString m_ZoneForGraphMode;
40 QVector<std::shared_ptr<DBCatalogue> > m_DisplayedCatalogues;
41 QVector<std::shared_ptr<DBCatalogue> > m_DisplayedCatalogues;
41 bool m_AllEventDisplayed = false;
42 bool m_AllEventDisplayed = false;
42 QVector<VisualizationGraphWidget *> m_CustomGraphs;
43 QVector<VisualizationGraphWidget *> m_CustomGraphs;
43
44
44 VisualizationWidget *m_VisualizationWidget = nullptr;
45 VisualizationWidget *m_VisualizationWidget = nullptr;
45
46
46 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events, CatalogueEventsWidget *widget)
47 void setEvents(const QVector<std::shared_ptr<DBEvent> > &events, CatalogueEventsWidget *widget)
47 {
48 {
48 widget->ui->treeView->setSortingEnabled(false);
49 widget->ui->treeView->setSortingEnabled(false);
49 m_Model->setSourceCatalogues(m_DisplayedCatalogues);
50 m_Model->setSourceCatalogues(m_DisplayedCatalogues);
50 m_Model->setEvents(events);
51 m_Model->setEvents(events);
51 widget->ui->treeView->setSortingEnabled(true);
52 widget->ui->treeView->setSortingEnabled(true);
52
53
53 for (auto event : events) {
54 for (auto event : events) {
54 if (sqpApp->catalogueController().eventHasChanges(event)) {
55 if (sqpApp->catalogueController().eventHasChanges(event)) {
55 auto index = m_Model->indexOf(event);
56 auto index = m_Model->indexOf(event);
56 widget->setEventChanges(event, true);
57 widget->setEventChanges(event, true);
57 }
58 }
58 }
59 }
59 }
60 }
60
61
61 void addEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
62 void addEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
62 {
63 {
63 treeView->setSortingEnabled(false);
64 treeView->setSortingEnabled(false);
64 m_Model->addEvent(event);
65 m_Model->addEvent(event);
65 treeView->setSortingEnabled(true);
66 treeView->setSortingEnabled(true);
66 }
67 }
67
68
68 void removeEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
69 void removeEvent(const std::shared_ptr<DBEvent> &event, QTreeView *treeView)
69 {
70 {
70 treeView->setSortingEnabled(false);
71 treeView->setSortingEnabled(false);
71 m_Model->removeEvent(event);
72 m_Model->removeEvent(event);
72 treeView->setSortingEnabled(true);
73 treeView->setSortingEnabled(true);
73 }
74 }
74
75
75 QStringList getAvailableVisualizationZoneList() const
76 QStringList getAvailableVisualizationZoneList() const
76 {
77 {
77 if (m_VisualizationWidget) {
78 if (m_VisualizationWidget) {
78 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
79 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
79 return tab->availableZoneWidgets();
80 return tab->availableZoneWidgets();
80 }
81 }
81 }
82 }
82
83
83 return QStringList{};
84 return QStringList{};
84 }
85 }
85
86
86 QStringList selectZone(QWidget *parent, const QStringList &selectedZones,
87 QStringList selectZone(QWidget *parent, const QStringList &selectedZones,
87 bool allowMultiSelection, bool addNewZoneOption, const QPoint &location)
88 bool allowMultiSelection, bool addNewZoneOption, const QPoint &location)
88 {
89 {
89 auto availableZones = getAvailableVisualizationZoneList();
90 auto availableZones = getAvailableVisualizationZoneList();
90 if (!addNewZoneOption && availableZones.isEmpty()) {
91 if (!addNewZoneOption && availableZones.isEmpty()) {
91 return QStringList{};
92 return QStringList{};
92 }
93 }
93
94
94 QActionGroup actionGroup{parent};
95 QActionGroup actionGroup{parent};
95 actionGroup.setExclusive(!allowMultiSelection);
96 actionGroup.setExclusive(!allowMultiSelection);
96
97
97 QVector<QAction *> zoneActions;
98 QVector<QAction *> zoneActions;
98
99
99 QMenu selectionMenu{parent};
100 QMenu selectionMenu{parent};
100
101
101 if (addNewZoneOption) {
102 if (addNewZoneOption) {
102 availableZones.prepend(NEW_ZONE_TEXT);
103 availableZones.prepend(NEW_ZONE_TEXT);
103 }
104 }
104
105
105 selectionMenu.addSeparator();
106 selectionMenu.addSeparator();
106 for (auto zone : availableZones) {
107 for (auto zone : availableZones) {
107 auto zoneAction = selectionMenu.addAction(zone);
108 auto zoneAction = selectionMenu.addAction(zone);
108 zoneAction->setCheckable(true);
109 zoneAction->setCheckable(true);
109 zoneAction->setChecked(selectedZones.contains(zone));
110 zoneAction->setChecked(selectedZones.contains(zone));
110 actionGroup.addAction(zoneAction);
111 actionGroup.addAction(zoneAction);
111 zoneActions << zoneAction;
112 zoneActions << zoneAction;
112 }
113 }
113
114
114 auto resultAction = selectionMenu.exec(QCursor::pos());
115 auto resultAction = selectionMenu.exec(QCursor::pos());
115
116
116 QStringList result;
117 QStringList result;
117
118
118 if (resultAction == nullptr) {
119 if (resultAction == nullptr) {
119 result = selectedZones;
120 result = selectedZones;
120 }
121 }
121 else {
122 else {
122 for (auto zoneAction : zoneActions) {
123 for (auto zoneAction : zoneActions) {
123 if (zoneAction->isChecked()) {
124 if (zoneAction->isChecked()) {
124 result << zoneAction->text();
125 result << zoneAction->text();
125 }
126 }
126 }
127 }
127 }
128 }
128
129
129 return result;
130 return result;
130 }
131 }
131
132
132 void updateForTimeMode(QTreeView *treeView)
133 void updateForTimeMode(QTreeView *treeView)
133 {
134 {
134 auto selectedRows = treeView->selectionModel()->selectedRows();
135 auto selectedRows = treeView->selectionModel()->selectedRows();
135
136
136 if (selectedRows.count() == 1) {
137 if (selectedRows.count() == 1) {
137 auto event = m_Model->getEvent(selectedRows.first());
138 auto event = m_Model->getEvent(selectedRows.first());
138 if (event) {
139 if (event) {
139 if (m_VisualizationWidget) {
140 if (m_VisualizationWidget) {
140 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
141 if (auto tab = m_VisualizationWidget->currentTabWidget()) {
141
142
142 for (auto zoneName : m_ZonesForTimeMode) {
143 for (auto zoneName : m_ZonesForTimeMode) {
143 if (auto zone = tab->getZoneWithName(zoneName)) {
144 if (auto zone = tab->getZoneWithName(zoneName)) {
144 DateTimeRange eventRange;
145 DateTimeRange eventRange;
145 eventRange.m_TStart = event->getTStart();
146 eventRange.m_TStart = event->getTStart();
146 eventRange.m_TEnd = event->getTEnd();
147 eventRange.m_TEnd = event->getTEnd();
147 zone->setZoneRange(eventRange);
148 zone->setZoneRange(eventRange);
148 }
149 }
149 }
150 }
150 }
151 }
151 else {
152 else {
152 qCWarning(LOG_CatalogueEventsWidget())
153 qCWarning(LOG_CatalogueEventsWidget())
153 << "updateTimeZone: no tab found in the visualization";
154 << "updateTimeZone: no tab found in the visualization";
154 }
155 }
155 }
156 }
156 else {
157 else {
157 qCWarning(LOG_CatalogueEventsWidget())
158 qCWarning(LOG_CatalogueEventsWidget())
158 << "updateTimeZone: visualization widget not found";
159 << "updateTimeZone: visualization widget not found";
159 }
160 }
160 }
161 }
161 }
162 }
162 else {
163 else {
163 qCWarning(LOG_CatalogueEventsWidget())
164 qCWarning(LOG_CatalogueEventsWidget())
164 << "updateTimeZone: not compatible with multiple events selected";
165 << "updateTimeZone: not compatible with multiple events selected";
165 }
166 }
166 }
167 }
167
168
168 QVector<DateTimeRange> getGraphRanges(const std::shared_ptr<DBEvent> &event)
169 QVector<DateTimeRange> getGraphRanges(const std::shared_ptr<DBEvent> &event)
169 {
170 {
170 // Retrieves the range of each product and the maximum size
171 // Retrieves the range of each product and the maximum size
171 QVector<DateTimeRange> graphRanges;
172 QVector<DateTimeRange> graphRanges;
172 double maxDt = 0;
173 double maxDt = 0;
173 for (auto eventProduct : event->getEventProducts()) {
174 for (auto eventProduct : event->getEventProducts()) {
174 DateTimeRange eventRange;
175 DateTimeRange eventRange;
175 eventRange.m_TStart = eventProduct.getTStart();
176 eventRange.m_TStart = eventProduct.getTStart();
176 eventRange.m_TEnd = eventProduct.getTEnd();
177 eventRange.m_TEnd = eventProduct.getTEnd();
177 graphRanges << eventRange;
178 graphRanges << eventRange;
178
179
179 auto dt = eventRange.m_TEnd - eventRange.m_TStart;
180 auto dt = eventRange.m_TEnd - eventRange.m_TStart;
180 if (dt > maxDt) {
181 if (dt > maxDt) {
181 maxDt = dt;
182 maxDt = dt;
182 }
183 }
183 }
184 }
184
185
185 // Adds the marge
186 // Adds the marge
186 maxDt *= (100.0 + EVENT_RANGE_MARGE) / 100.0;
187 maxDt *= (100.0 + EVENT_RANGE_MARGE) / 100.0;
187
188
188 // Corrects the graph ranges so that they all have the same size
189 // Corrects the graph ranges so that they all have the same size
189 QVector<DateTimeRange> correctedGraphRanges;
190 QVector<DateTimeRange> correctedGraphRanges;
190 for (auto range : graphRanges) {
191 for (auto range : graphRanges) {
191 auto dt = range.m_TEnd - range.m_TStart;
192 auto dt = range.m_TEnd - range.m_TStart;
192 auto diff = qAbs((maxDt - dt) / 2.0);
193 auto diff = qAbs((maxDt - dt) / 2.0);
193
194
194 DateTimeRange correctedRange;
195 DateTimeRange correctedRange;
195 correctedRange.m_TStart = range.m_TStart - diff;
196 correctedRange.m_TStart = range.m_TStart - diff;
196 correctedRange.m_TEnd = range.m_TEnd + diff;
197 correctedRange.m_TEnd = range.m_TEnd + diff;
197
198
198 correctedGraphRanges << correctedRange;
199 correctedGraphRanges << correctedRange;
199 }
200 }
200
201
201 return correctedGraphRanges;
202 return correctedGraphRanges;
202 }
203 }
203
204
204 void updateForGraphMode(CatalogueEventsWidget *catalogueEventWidget)
205 void updateForGraphMode(CatalogueEventsWidget *catalogueEventWidget)
205 {
206 {
206 auto selectedRows = catalogueEventWidget->ui->treeView->selectionModel()->selectedRows();
207 auto selectedRows = catalogueEventWidget->ui->treeView->selectionModel()->selectedRows();
207 if (selectedRows.count() != 1) {
208 if (selectedRows.count() != 1) {
208 qCWarning(LOG_CatalogueEventsWidget())
209 qCWarning(LOG_CatalogueEventsWidget())
209 << "updateGraphMode: not compatible with multiple events selected";
210 << "updateGraphMode: not compatible with multiple events selected";
210 return;
211 return;
211 }
212 }
212
213
213 if (!m_VisualizationWidget) {
214 if (!m_VisualizationWidget) {
214 qCWarning(LOG_CatalogueEventsWidget())
215 qCWarning(LOG_CatalogueEventsWidget())
215 << "updateGraphMode: visualization widget not found";
216 << "updateGraphMode: visualization widget not found";
216 return;
217 return;
217 }
218 }
218
219
219 auto event = m_Model->getEvent(selectedRows.first());
220 auto event = m_Model->getEvent(selectedRows.first());
220 if (!event) {
221 if (!event) {
221 // A event product is probably selected
222 // A event product is probably selected
222 qCInfo(LOG_CatalogueEventsWidget()) << "updateGraphMode: no events are selected";
223 qCInfo(LOG_CatalogueEventsWidget()) << "updateGraphMode: no events are selected";
223 return;
224 return;
224 }
225 }
225
226
226 auto tab = m_VisualizationWidget->currentTabWidget();
227 auto tab = m_VisualizationWidget->currentTabWidget();
227 if (!tab) {
228 if (!tab) {
228 qCWarning(LOG_CatalogueEventsWidget())
229 qCWarning(LOG_CatalogueEventsWidget())
229 << "updateGraphMode: no tab found in the visualization";
230 << "updateGraphMode: no tab found in the visualization";
230 return;
231 return;
231 }
232 }
232
233
233 auto isNewZone = m_ZoneForGraphMode == NEW_ZONE_TEXT;
234 auto isNewZone = m_ZoneForGraphMode == NEW_ZONE_TEXT;
234 auto zone = tab->getZoneWithName(m_ZoneForGraphMode);
235 auto zone = tab->getZoneWithName(m_ZoneForGraphMode);
235 if (!isNewZone && !zone) {
236 if (!isNewZone && !zone) {
236 qCWarning(LOG_CatalogueEventsWidget()) << "updateGraphMode: zone not found";
237 qCWarning(LOG_CatalogueEventsWidget()) << "updateGraphMode: zone not found";
237 return;
238 return;
238 }
239 }
239
240
240 // Closes the previous graph and delete the asociated variables
241 // Closes the previous graph and delete the asociated variables
241 for (auto graph : m_CustomGraphs) {
242 for (auto graph : m_CustomGraphs) {
242 graph->close();
243 graph->close();
243 auto variables = graph->variables().toVector();
244 auto variables = graph->variables();
244
245 for(const auto& variable:variables)
245 QMetaObject::invokeMethod(&sqpApp->variableController(), "deleteVariables",
246 sqpApp->variableController().deleteVariable(variable);
246 Qt::QueuedConnection,
247 Q_ARG(QVector<std::shared_ptr<Variable> >, variables));
248 }
247 }
249 m_CustomGraphs.clear();
248 m_CustomGraphs.clear();
250
249
251 // Closes the remaining graphs inside the zone
250 // Closes the remaining graphs inside the zone
252 if (zone) {
251 if (zone) {
253 zone->closeAllGraphs();
252 zone->closeAllGraphs();
254 }
253 }
255
254
256 // Creates the zone if needed
255 // Creates the zone if needed
257 if (isNewZone) {
256 if (isNewZone) {
258 zone = tab->createEmptyZone(0);
257 zone = tab->createEmptyZone(0);
259 m_ZoneForGraphMode = zone->name();
258 m_ZoneForGraphMode = zone->name();
260 }
259 }
261
260
262 // Calculates the range of each graph which will be created
261 // Calculates the range of each graph which will be created
263 auto graphRange = getGraphRanges(event);
262 auto graphRange = getGraphRanges(event);
264
263
265 // Loops through the event products and create the graph
264 // Loops through the event products and create the graph
266 auto itRange = graphRange.cbegin();
265 auto itRange = graphRange.cbegin();
267 for (auto eventProduct : event->getEventProducts()) {
266 for (auto eventProduct : event->getEventProducts()) {
268 auto productId = eventProduct.getProductId();
267 auto productId = eventProduct.getProductId();
269
268
270 auto range = *itRange;
269 auto range = *itRange;
271 ++itRange;
270 ++itRange;
272
271
273 DateTimeRange productRange;
272 DateTimeRange productRange;
274 productRange.m_TStart = eventProduct.getTStart();
273 productRange.m_TStart = eventProduct.getTStart();
275 productRange.m_TEnd = eventProduct.getTEnd();
274 productRange.m_TEnd = eventProduct.getTEnd();
276
275
277 auto context = new QObject{catalogueEventWidget};
276 auto context = new QObject{catalogueEventWidget};
278 QObject::connect(
277 QObject::connect(
279 &sqpApp->variableController(), &VariableController::variableAdded, context,
278 &sqpApp->variableController(), &VariableController2::variableAdded, context,
280 [this, catalogueEventWidget, zone, context, event, range, productRange,
279 [this, catalogueEventWidget, zone, context, event, range, productRange,
281 productId](auto variable) {
280 productId](auto variable) {
282
281
283 if (variable->metadata().value(DataSourceItem::ID_DATA_KEY).toString()
282 if (variable->metadata().value(DataSourceItem::ID_DATA_KEY).toString()
284 == productId) {
283 == productId) {
285 auto graph = zone->createGraph(variable);
284 auto graph = zone->createGraph(variable);
286 graph->setAutoRangeOnVariableInitialization(false);
285 graph->setAutoRangeOnVariableInitialization(false);
287
286
288 auto selectionZone
287 auto selectionZone
289 = graph->addSelectionZone(event->getName(), productRange);
288 = graph->addSelectionZone(event->getName(), productRange);
290 emit catalogueEventWidget->selectionZoneAdded(event, productId,
289 emit catalogueEventWidget->selectionZoneAdded(event, productId,
291 selectionZone);
290 selectionZone);
292 m_CustomGraphs << graph;
291 m_CustomGraphs << graph;
293
292
294 graph->setGraphRange(range, true);
293 graph->setGraphRange(range, true);
295
294
296 // Removes the graph from the graph list if it is closed manually
295 // Removes the graph from the graph list if it is closed manually
297 QObject::connect(graph, &VisualizationGraphWidget::destroyed,
296 QObject::connect(graph, &VisualizationGraphWidget::destroyed,
298 [this, graph]() { m_CustomGraphs.removeAll(graph); });
297 [this, graph]() { m_CustomGraphs.removeAll(graph); });
299
298
300 delete context; // removes the connection
299 delete context; // removes the connection
301 }
300 }
302 },
301 },
303 Qt::QueuedConnection);
302 Qt::QueuedConnection);
304
303
305 QMetaObject::invokeMethod(&sqpApp->dataSourceController(),
304 QMetaObject::invokeMethod(&sqpApp->dataSourceController(),
306 "requestVariableFromProductIdKey", Qt::QueuedConnection,
305 "requestVariableFromProductIdKey", Qt::QueuedConnection,
307 Q_ARG(QString, productId));
306 Q_ARG(QString, productId));
308 }
307 }
309 }
308 }
310
309
311 void getSelectedItems(
310 void getSelectedItems(
312 QTreeView *treeView, QVector<std::shared_ptr<DBEvent> > &events,
311 QTreeView *treeView, QVector<std::shared_ptr<DBEvent> > &events,
313 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > &eventProducts)
312 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > &eventProducts)
314 {
313 {
315 for (auto rowIndex : treeView->selectionModel()->selectedRows()) {
314 for (auto rowIndex : treeView->selectionModel()->selectedRows()) {
316 auto itemType = m_Model->itemTypeOf(rowIndex);
315 auto itemType = m_Model->itemTypeOf(rowIndex);
317 if (itemType == CatalogueEventsModel::ItemType::Event) {
316 if (itemType == CatalogueEventsModel::ItemType::Event) {
318 events << m_Model->getEvent(rowIndex);
317 events << m_Model->getEvent(rowIndex);
319 }
318 }
320 else if (itemType == CatalogueEventsModel::ItemType::EventProduct) {
319 else if (itemType == CatalogueEventsModel::ItemType::EventProduct) {
321 eventProducts << qMakePair(m_Model->getParentEvent(rowIndex),
320 eventProducts << qMakePair(m_Model->getParentEvent(rowIndex),
322 m_Model->getEventProduct(rowIndex));
321 m_Model->getEventProduct(rowIndex));
323 }
322 }
324 }
323 }
325 }
324 }
326 };
325 };
327
326
328 CatalogueEventsWidget::CatalogueEventsWidget(QWidget *parent)
327 CatalogueEventsWidget::CatalogueEventsWidget(QWidget *parent)
329 : QWidget(parent),
328 : QWidget(parent),
330 ui(new Ui::CatalogueEventsWidget),
329 ui(new Ui::CatalogueEventsWidget),
331 impl{spimpl::make_unique_impl<CatalogueEventsWidgetPrivate>()}
330 impl{spimpl::make_unique_impl<CatalogueEventsWidgetPrivate>()}
332 {
331 {
333 ui->setupUi(this);
332 ui->setupUi(this);
334
333
335 impl->m_Model = new CatalogueEventsModel{this};
334 impl->m_Model = new CatalogueEventsModel{this};
336 ui->treeView->setModel(impl->m_Model);
335 ui->treeView->setModel(impl->m_Model);
337
336
338 ui->treeView->setSortingEnabled(true);
337 ui->treeView->setSortingEnabled(true);
339 ui->treeView->setDragDropMode(QAbstractItemView::DragDrop);
338 ui->treeView->setDragDropMode(QAbstractItemView::DragDrop);
340 ui->treeView->setDragEnabled(true);
339 ui->treeView->setDragEnabled(true);
341
340
342
341
343 connect(ui->btnTime, &QToolButton::clicked, [this](auto checked) {
342 connect(ui->btnTime, &QToolButton::clicked, [this](auto checked) {
344 if (checked) {
343 if (checked) {
345 ui->btnChart->setChecked(false);
344 ui->btnChart->setChecked(false);
346 impl->m_ZonesForTimeMode
345 impl->m_ZonesForTimeMode
347 = impl->selectZone(this, impl->m_ZonesForTimeMode, true, false,
346 = impl->selectZone(this, impl->m_ZonesForTimeMode, true, false,
348 this->mapToGlobal(ui->btnTime->frameGeometry().center()));
347 this->mapToGlobal(ui->btnTime->frameGeometry().center()));
349
348
350 impl->updateForTimeMode(ui->treeView);
349 impl->updateForTimeMode(ui->treeView);
351 }
350 }
352 });
351 });
353
352
354 connect(ui->btnChart, &QToolButton::clicked, [this](auto checked) {
353 connect(ui->btnChart, &QToolButton::clicked, [this](auto checked) {
355 if (checked) {
354 if (checked) {
356 ui->btnTime->setChecked(false);
355 ui->btnTime->setChecked(false);
357
356
358 impl->m_ZoneForGraphMode
357 impl->m_ZoneForGraphMode
359 = impl->selectZone(this, {impl->m_ZoneForGraphMode}, false, true,
358 = impl->selectZone(this, {impl->m_ZoneForGraphMode}, false, true,
360 this->mapToGlobal(ui->btnChart->frameGeometry().center()))
359 this->mapToGlobal(ui->btnChart->frameGeometry().center()))
361 .value(0);
360 .value(0);
362
361
363 impl->updateForGraphMode(this);
362 impl->updateForGraphMode(this);
364 }
363 }
365 });
364 });
366
365
367 connect(ui->btnRemove, &QToolButton::clicked, [this]() {
366 connect(ui->btnRemove, &QToolButton::clicked, [this]() {
368 QVector<std::shared_ptr<DBEvent> > events;
367 QVector<std::shared_ptr<DBEvent> > events;
369 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
368 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
370 impl->getSelectedItems(ui->treeView, events, eventProducts);
369 impl->getSelectedItems(ui->treeView, events, eventProducts);
371
370
372 if (!events.isEmpty() && eventProducts.isEmpty()) {
371 if (!events.isEmpty() && eventProducts.isEmpty()) {
373
372
374 auto canRemoveEvent
373 auto canRemoveEvent
375 = !this->isAllEventsDisplayed()
374 = !this->isAllEventsDisplayed()
376 || (QMessageBox::warning(
375 || (QMessageBox::warning(
377 this, tr("Remove Event(s)"),
376 this, tr("Remove Event(s)"),
378 tr("The selected event(s) will be permanently removed "
377 tr("The selected event(s) will be permanently removed "
379 "from the repository!\nAre you sure you want to continue?"),
378 "from the repository!\nAre you sure you want to continue?"),
380 QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
379 QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
381 == QMessageBox::Yes);
380 == QMessageBox::Yes);
382
381
383 if (canRemoveEvent) {
382 if (canRemoveEvent) {
384 for (auto event : events) {
383 for (auto event : events) {
385 if (this->isAllEventsDisplayed()) {
384 if (this->isAllEventsDisplayed()) {
386 sqpApp->catalogueController().removeEvent(event);
385 sqpApp->catalogueController().removeEvent(event);
387 impl->removeEvent(event, ui->treeView);
386 impl->removeEvent(event, ui->treeView);
388 }
387 }
389 else {
388 else {
390 QVector<std::shared_ptr<DBCatalogue> > modifiedCatalogues;
389 QVector<std::shared_ptr<DBCatalogue> > modifiedCatalogues;
391 for (auto catalogue : this->displayedCatalogues()) {
390 for (auto catalogue : this->displayedCatalogues()) {
392 if (catalogue->removeEvent(event->getUniqId())) {
391 if (catalogue->removeEvent(event->getUniqId())) {
393 sqpApp->catalogueController().updateCatalogue(catalogue);
392 sqpApp->catalogueController().updateCatalogue(catalogue);
394 modifiedCatalogues << catalogue;
393 modifiedCatalogues << catalogue;
395 }
394 }
396 }
395 }
397 if (!modifiedCatalogues.empty()) {
396 if (!modifiedCatalogues.empty()) {
398 emit eventCataloguesModified(modifiedCatalogues);
397 emit eventCataloguesModified(modifiedCatalogues);
399 }
398 }
400 }
399 }
401 impl->m_Model->removeEvent(event);
400 impl->m_Model->removeEvent(event);
402 }
401 }
403
402
404
403
405 emit this->eventsRemoved(events);
404 emit this->eventsRemoved(events);
406 }
405 }
407 }
406 }
408 });
407 });
409
408
410 connect(ui->treeView, &QTreeView::clicked, this, &CatalogueEventsWidget::emitSelection);
409 connect(ui->treeView, &QTreeView::clicked, this, &CatalogueEventsWidget::emitSelection);
411 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
410 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
412 &CatalogueEventsWidget::emitSelection);
411 &CatalogueEventsWidget::emitSelection);
413
412
414 ui->btnRemove->setEnabled(false); // Disabled by default when nothing is selected
413 ui->btnRemove->setEnabled(false); // Disabled by default when nothing is selected
415 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, [this]() {
414 connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, [this]() {
416 auto isNotMultiSelection = ui->treeView->selectionModel()->selectedRows().count() <= 1;
415 auto isNotMultiSelection = ui->treeView->selectionModel()->selectedRows().count() <= 1;
417 ui->btnChart->setEnabled(isNotMultiSelection);
416 ui->btnChart->setEnabled(isNotMultiSelection);
418 ui->btnTime->setEnabled(isNotMultiSelection);
417 ui->btnTime->setEnabled(isNotMultiSelection);
419
418
420 if (isNotMultiSelection && ui->btnTime->isChecked()) {
419 if (isNotMultiSelection && ui->btnTime->isChecked()) {
421 impl->updateForTimeMode(ui->treeView);
420 impl->updateForTimeMode(ui->treeView);
422 }
421 }
423 else if (isNotMultiSelection && ui->btnChart->isChecked()) {
422 else if (isNotMultiSelection && ui->btnChart->isChecked()) {
424 impl->updateForGraphMode(this);
423 impl->updateForGraphMode(this);
425 }
424 }
426
425
427 QVector<std::shared_ptr<DBEvent> > events;
426 QVector<std::shared_ptr<DBEvent> > events;
428 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
427 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
429 impl->getSelectedItems(ui->treeView, events, eventProducts);
428 impl->getSelectedItems(ui->treeView, events, eventProducts);
430 ui->btnRemove->setEnabled(!events.isEmpty() && eventProducts.isEmpty());
429 ui->btnRemove->setEnabled(!events.isEmpty() && eventProducts.isEmpty());
431 });
430 });
432
431
433 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
432 ui->treeView->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
434 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Tags,
433 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Tags,
435 QHeaderView::Stretch);
434 QHeaderView::Stretch);
436 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Validation,
435 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Validation,
437 QHeaderView::ResizeToContents);
436 QHeaderView::ResizeToContents);
438 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Name,
437 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::Name,
439 QHeaderView::Interactive);
438 QHeaderView::Interactive);
440 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::TStart,
439 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::TStart,
441 QHeaderView::ResizeToContents);
440 QHeaderView::ResizeToContents);
442 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::TEnd,
441 ui->treeView->header()->setSectionResizeMode((int)CatalogueEventsModel::Column::TEnd,
443 QHeaderView::ResizeToContents);
442 QHeaderView::ResizeToContents);
444 ui->treeView->header()->setSortIndicatorShown(true);
443 ui->treeView->header()->setSortIndicatorShown(true);
445
444
446 connect(impl->m_Model, &CatalogueEventsModel::modelSorted, [this]() {
445 connect(impl->m_Model, &CatalogueEventsModel::modelSorted, [this]() {
447 auto allEvents = impl->m_Model->events();
446 auto allEvents = impl->m_Model->events();
448 for (auto event : allEvents) {
447 for (auto event : allEvents) {
449 setEventChanges(event, sqpApp->catalogueController().eventHasChanges(event));
448 setEventChanges(event, sqpApp->catalogueController().eventHasChanges(event));
450 }
449 }
451 });
450 });
452
451
453 populateWithAllEvents();
452 populateWithAllEvents();
454 }
453 }
455
454
456 CatalogueEventsWidget::~CatalogueEventsWidget()
455 CatalogueEventsWidget::~CatalogueEventsWidget()
457 {
456 {
458 delete ui;
457 delete ui;
459 }
458 }
460
459
461 void CatalogueEventsWidget::setVisualizationWidget(VisualizationWidget *visualization)
460 void CatalogueEventsWidget::setVisualizationWidget(VisualizationWidget *visualization)
462 {
461 {
463 impl->m_VisualizationWidget = visualization;
462 impl->m_VisualizationWidget = visualization;
464 }
463 }
465
464
466 void CatalogueEventsWidget::addEvent(const std::shared_ptr<DBEvent> &event)
465 void CatalogueEventsWidget::addEvent(const std::shared_ptr<DBEvent> &event)
467 {
466 {
468 impl->addEvent(event, ui->treeView);
467 impl->addEvent(event, ui->treeView);
469 }
468 }
470
469
471 void CatalogueEventsWidget::setEventChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges)
470 void CatalogueEventsWidget::setEventChanges(const std::shared_ptr<DBEvent> &event, bool hasChanges)
472 {
471 {
473 impl->m_Model->refreshEvent(event);
472 impl->m_Model->refreshEvent(event);
474
473
475 auto eventIndex = impl->m_Model->indexOf(event);
474 auto eventIndex = impl->m_Model->indexOf(event);
476 auto validationIndex
475 auto validationIndex
477 = eventIndex.sibling(eventIndex.row(), (int)CatalogueEventsModel::Column::Validation);
476 = eventIndex.sibling(eventIndex.row(), (int)CatalogueEventsModel::Column::Validation);
478
477
479 if (validationIndex.isValid()) {
478 if (validationIndex.isValid()) {
480 if (hasChanges) {
479 if (hasChanges) {
481 if (ui->treeView->indexWidget(validationIndex) == nullptr) {
480 if (ui->treeView->indexWidget(validationIndex) == nullptr) {
482 auto widget = CatalogueExplorerHelper::buildValidationWidget(
481 auto widget = CatalogueExplorerHelper::buildValidationWidget(
483 ui->treeView,
482 ui->treeView,
484 [this, event]() {
483 [this, event]() {
485 sqpApp->catalogueController().saveEvent(event);
484 sqpApp->catalogueController().saveEvent(event);
486 setEventChanges(event, false);
485 setEventChanges(event, false);
487 },
486 },
488 [this, event]() {
487 [this, event]() {
489 bool removed = false;
488 bool removed = false;
490 sqpApp->catalogueController().discardEvent(event, removed);
489 sqpApp->catalogueController().discardEvent(event, removed);
491 if (removed) {
490 if (removed) {
492 impl->m_Model->removeEvent(event);
491 impl->m_Model->removeEvent(event);
493 }
492 }
494 else {
493 else {
495 setEventChanges(event, false);
494 setEventChanges(event, false);
496 impl->m_Model->refreshEvent(event, true);
495 impl->m_Model->refreshEvent(event, true);
497 }
496 }
498 emitSelection();
497 emitSelection();
499 });
498 });
500 ui->treeView->setIndexWidget(validationIndex, widget);
499 ui->treeView->setIndexWidget(validationIndex, widget);
501 ui->treeView->header()->resizeSection((int)CatalogueEventsModel::Column::Validation,
500 ui->treeView->header()->resizeSection((int)CatalogueEventsModel::Column::Validation,
502 QHeaderView::ResizeToContents);
501 QHeaderView::ResizeToContents);
503 }
502 }
504 }
503 }
505 else {
504 else {
506 // Note: the widget is destroyed
505 // Note: the widget is destroyed
507 ui->treeView->setIndexWidget(validationIndex, nullptr);
506 ui->treeView->setIndexWidget(validationIndex, nullptr);
508 }
507 }
509 }
508 }
510 else {
509 else {
511 qCWarning(LOG_CatalogueEventsWidget())
510 qCWarning(LOG_CatalogueEventsWidget())
512 << "setEventChanges: the event is not displayed in the model.";
511 << "setEventChanges: the event is not displayed in the model.";
513 }
512 }
514 }
513 }
515
514
516 QVector<std::shared_ptr<DBCatalogue> > CatalogueEventsWidget::displayedCatalogues() const
515 QVector<std::shared_ptr<DBCatalogue> > CatalogueEventsWidget::displayedCatalogues() const
517 {
516 {
518 return impl->m_DisplayedCatalogues;
517 return impl->m_DisplayedCatalogues;
519 }
518 }
520
519
521 bool CatalogueEventsWidget::isAllEventsDisplayed() const
520 bool CatalogueEventsWidget::isAllEventsDisplayed() const
522 {
521 {
523 return impl->m_AllEventDisplayed;
522 return impl->m_AllEventDisplayed;
524 }
523 }
525
524
526 bool CatalogueEventsWidget::isEventDisplayed(const std::shared_ptr<DBEvent> &event) const
525 bool CatalogueEventsWidget::isEventDisplayed(const std::shared_ptr<DBEvent> &event) const
527 {
526 {
528 return impl->m_Model->indexOf(event).isValid();
527 return impl->m_Model->indexOf(event).isValid();
529 }
528 }
530
529
531 void CatalogueEventsWidget::refreshEvent(const std::shared_ptr<DBEvent> &event)
530 void CatalogueEventsWidget::refreshEvent(const std::shared_ptr<DBEvent> &event)
532 {
531 {
533 impl->m_Model->refreshEvent(event, true);
532 impl->m_Model->refreshEvent(event, true);
534 }
533 }
535
534
536 void CatalogueEventsWidget::populateWithCatalogues(
535 void CatalogueEventsWidget::populateWithCatalogues(
537 const QVector<std::shared_ptr<DBCatalogue> > &catalogues)
536 const QVector<std::shared_ptr<DBCatalogue> > &catalogues)
538 {
537 {
539 impl->m_DisplayedCatalogues = catalogues;
538 impl->m_DisplayedCatalogues = catalogues;
540 impl->m_AllEventDisplayed = false;
539 impl->m_AllEventDisplayed = false;
541
540
542 QSet<QUuid> eventIds;
541 QSet<QUuid> eventIds;
543 QVector<std::shared_ptr<DBEvent> > events;
542 QVector<std::shared_ptr<DBEvent> > events;
544
543
545 for (auto catalogue : catalogues) {
544 for (auto catalogue : catalogues) {
546 auto catalogueEvents = sqpApp->catalogueController().retrieveEventsFromCatalogue(catalogue);
545 auto catalogueEvents = sqpApp->catalogueController().retrieveEventsFromCatalogue(catalogue);
547 for (auto event : catalogueEvents) {
546 for (auto event : catalogueEvents) {
548 if (!eventIds.contains(event->getUniqId())) {
547 if (!eventIds.contains(event->getUniqId())) {
549 events << event;
548 events << event;
550 eventIds.insert(event->getUniqId());
549 eventIds.insert(event->getUniqId());
551 }
550 }
552 }
551 }
553 }
552 }
554
553
555 impl->setEvents(events, this);
554 impl->setEvents(events, this);
556 }
555 }
557
556
558 void CatalogueEventsWidget::populateWithAllEvents()
557 void CatalogueEventsWidget::populateWithAllEvents()
559 {
558 {
560 impl->m_DisplayedCatalogues.clear();
559 impl->m_DisplayedCatalogues.clear();
561 impl->m_AllEventDisplayed = true;
560 impl->m_AllEventDisplayed = true;
562
561
563 auto allEvents = sqpApp->catalogueController().retrieveAllEvents();
562 auto allEvents = sqpApp->catalogueController().retrieveAllEvents();
564
563
565 QVector<std::shared_ptr<DBEvent> > events;
564 QVector<std::shared_ptr<DBEvent> > events;
566 for (auto event : allEvents) {
565 for (auto event : allEvents) {
567 events << event;
566 events << event;
568 }
567 }
569
568
570 impl->setEvents(events, this);
569 impl->setEvents(events, this);
571 }
570 }
572
571
573 void CatalogueEventsWidget::clear()
572 void CatalogueEventsWidget::clear()
574 {
573 {
575 impl->m_DisplayedCatalogues.clear();
574 impl->m_DisplayedCatalogues.clear();
576 impl->m_AllEventDisplayed = false;
575 impl->m_AllEventDisplayed = false;
577 impl->setEvents({}, this);
576 impl->setEvents({}, this);
578 }
577 }
579
578
580 void CatalogueEventsWidget::refresh()
579 void CatalogueEventsWidget::refresh()
581 {
580 {
582 if (isAllEventsDisplayed()) {
581 if (isAllEventsDisplayed()) {
583 populateWithAllEvents();
582 populateWithAllEvents();
584 }
583 }
585 else if (!impl->m_DisplayedCatalogues.isEmpty()) {
584 else if (!impl->m_DisplayedCatalogues.isEmpty()) {
586 populateWithCatalogues(impl->m_DisplayedCatalogues);
585 populateWithCatalogues(impl->m_DisplayedCatalogues);
587 }
586 }
588 }
587 }
589
588
590 void CatalogueEventsWidget::emitSelection()
589 void CatalogueEventsWidget::emitSelection()
591 {
590 {
592 QVector<std::shared_ptr<DBEvent> > events;
591 QVector<std::shared_ptr<DBEvent> > events;
593 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
592 QVector<QPair<std::shared_ptr<DBEvent>, std::shared_ptr<DBEventProduct> > > eventProducts;
594 impl->getSelectedItems(ui->treeView, events, eventProducts);
593 impl->getSelectedItems(ui->treeView, events, eventProducts);
595
594
596 if (!events.isEmpty() && eventProducts.isEmpty()) {
595 if (!events.isEmpty() && eventProducts.isEmpty()) {
597 emit eventsSelected(events);
596 emit eventsSelected(events);
598 }
597 }
599 else if (events.isEmpty() && !eventProducts.isEmpty()) {
598 else if (events.isEmpty() && !eventProducts.isEmpty()) {
600 emit eventProductsSelected(eventProducts);
599 emit eventProductsSelected(eventProducts);
601 }
600 }
602 else {
601 else {
603 emit selectionCleared();
602 emit selectionCleared();
604 }
603 }
605 }
604 }
606
605
607
606
608 void CatalogueEventsWidget::keyPressEvent(QKeyEvent *event)
607 void CatalogueEventsWidget::keyPressEvent(QKeyEvent *event)
609 {
608 {
610 switch (event->key()) {
609 switch (event->key()) {
611 case Qt::Key_Delete: {
610 case Qt::Key_Delete: {
612 ui->btnRemove->click();
611 ui->btnRemove->click();
613 }
612 }
614 default:
613 default:
615 break;
614 break;
616 }
615 }
617 }
616 }
@@ -1,308 +1,308
1 #include "DragAndDrop/DragDropGuiController.h"
1 #include "DragAndDrop/DragDropGuiController.h"
2 #include "DragAndDrop/DragDropScroller.h"
2 #include "DragAndDrop/DragDropScroller.h"
3 #include "DragAndDrop/DragDropTabSwitcher.h"
3 #include "DragAndDrop/DragDropTabSwitcher.h"
4 #include "SqpApplication.h"
4 #include "SqpApplication.h"
5 #include "Visualization/VisualizationDragDropContainer.h"
5 #include "Visualization/VisualizationDragDropContainer.h"
6 #include "Visualization/VisualizationDragWidget.h"
6 #include "Visualization/VisualizationDragWidget.h"
7 #include "Visualization/VisualizationWidget.h"
7 #include "Visualization/VisualizationWidget.h"
8 #include "Visualization/operations/FindVariableOperation.h"
8 #include "Visualization/operations/FindVariableOperation.h"
9
9
10 #include "DataSource/DataSourceController.h"
10 #include "DataSource/DataSourceController.h"
11 #include "Variable/Variable.h"
11 #include "Variable/Variable.h"
12 #include "Variable/VariableController.h"
12 #include "Variable/VariableController2.h"
13
13
14 #include "Common/MimeTypesDef.h"
14 #include "Common/MimeTypesDef.h"
15 #include "Common/VisualizationDef.h"
15 #include "Common/VisualizationDef.h"
16
16
17 #include <QDir>
17 #include <QDir>
18 #include <QLabel>
18 #include <QLabel>
19 #include <QUrl>
19 #include <QUrl>
20 #include <QVBoxLayout>
20 #include <QVBoxLayout>
21
21
22
22
23 Q_LOGGING_CATEGORY(LOG_DragDropGuiController, "DragDropGuiController")
23 Q_LOGGING_CATEGORY(LOG_DragDropGuiController, "DragDropGuiController")
24
24
25
25
26 struct DragDropGuiController::DragDropGuiControllerPrivate {
26 struct DragDropGuiController::DragDropGuiControllerPrivate {
27
27
28 VisualizationDragWidget *m_CurrentDragWidget = nullptr;
28 VisualizationDragWidget *m_CurrentDragWidget = nullptr;
29 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
29 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
30 QLabel *m_PlaceHolderLabel;
30 QLabel *m_PlaceHolderLabel;
31 QWidget *m_PlaceBackground;
31 QWidget *m_PlaceBackground;
32 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
32 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
33 std::unique_ptr<DragDropTabSwitcher> m_DragDropTabSwitcher = nullptr;
33 std::unique_ptr<DragDropTabSwitcher> m_DragDropTabSwitcher = nullptr;
34 QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using
34 QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using
35 // QTemporaryFile to have a name which is not generated.
35 // QTemporaryFile to have a name which is not generated.
36
36
37 VisualizationDragWidget *m_HighlightedDragWidget = nullptr;
37 VisualizationDragWidget *m_HighlightedDragWidget = nullptr;
38
38
39 QMetaObject::Connection m_DragWidgetDestroyedConnection;
39 QMetaObject::Connection m_DragWidgetDestroyedConnection;
40 QMetaObject::Connection m_HighlightedWidgetDestroyedConnection;
40 QMetaObject::Connection m_HighlightedWidgetDestroyedConnection;
41
41
42 QList<QWidget *> m_WidgetToClose;
42 QList<QWidget *> m_WidgetToClose;
43
43
44 explicit DragDropGuiControllerPrivate()
44 explicit DragDropGuiControllerPrivate()
45 : m_PlaceHolder{std::make_unique<QWidget>()},
45 : m_PlaceHolder{std::make_unique<QWidget>()},
46 m_DragDropScroller{std::make_unique<DragDropScroller>()},
46 m_DragDropScroller{std::make_unique<DragDropScroller>()},
47 m_DragDropTabSwitcher{std::make_unique<DragDropTabSwitcher>()}
47 m_DragDropTabSwitcher{std::make_unique<DragDropTabSwitcher>()}
48 {
48 {
49
49
50 auto layout = new QVBoxLayout{m_PlaceHolder.get()};
50 auto layout = new QVBoxLayout{m_PlaceHolder.get()};
51 layout->setSpacing(0);
51 layout->setSpacing(0);
52 layout->setContentsMargins(0, 0, 0, 0);
52 layout->setContentsMargins(0, 0, 0, 0);
53
53
54 m_PlaceHolderLabel = new QLabel{"", m_PlaceHolder.get()};
54 m_PlaceHolderLabel = new QLabel{"", m_PlaceHolder.get()};
55 m_PlaceHolderLabel->setMinimumHeight(25);
55 m_PlaceHolderLabel->setMinimumHeight(25);
56 layout->addWidget(m_PlaceHolderLabel);
56 layout->addWidget(m_PlaceHolderLabel);
57
57
58 m_PlaceBackground = new QWidget{m_PlaceHolder.get()};
58 m_PlaceBackground = new QWidget{m_PlaceHolder.get()};
59 m_PlaceBackground->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
59 m_PlaceBackground->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
60 layout->addWidget(m_PlaceBackground);
60 layout->addWidget(m_PlaceBackground);
61
61
62 sqpApp->installEventFilter(m_DragDropScroller.get());
62 sqpApp->installEventFilter(m_DragDropScroller.get());
63 sqpApp->installEventFilter(m_DragDropTabSwitcher.get());
63 sqpApp->installEventFilter(m_DragDropTabSwitcher.get());
64
64
65 m_ImageTempUrl = QDir::temp().absoluteFilePath("Sciqlop_graph.png");
65 m_ImageTempUrl = QDir::temp().absoluteFilePath("Sciqlop_graph.png");
66 }
66 }
67
67
68 void preparePlaceHolder(DragDropGuiController::PlaceHolderType type,
68 void preparePlaceHolder(DragDropGuiController::PlaceHolderType type,
69 const QString &topLabelText) const
69 const QString &topLabelText) const
70 {
70 {
71 if (m_CurrentDragWidget) {
71 if (m_CurrentDragWidget) {
72 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
72 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
73 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
73 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
74 }
74 }
75 else {
75 else {
76 // Configuration of the placeHolder when there is no dragWidget
76 // Configuration of the placeHolder when there is no dragWidget
77 // (for instance with a drag from a variable)
77 // (for instance with a drag from a variable)
78
78
79 m_PlaceHolder->setMinimumSize(0, GRAPH_MINIMUM_HEIGHT);
79 m_PlaceHolder->setMinimumSize(0, GRAPH_MINIMUM_HEIGHT);
80 m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
80 m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
81 }
81 }
82
82
83 switch (type) {
83 switch (type) {
84 case DragDropGuiController::PlaceHolderType::Graph:
84 case DragDropGuiController::PlaceHolderType::Graph:
85 m_PlaceBackground->setStyleSheet(
85 m_PlaceBackground->setStyleSheet(
86 "background-color: #BBD5EE; border: 1px solid #2A7FD4");
86 "background-color: #BBD5EE; border: 1px solid #2A7FD4");
87 break;
87 break;
88 case DragDropGuiController::PlaceHolderType::Zone:
88 case DragDropGuiController::PlaceHolderType::Zone:
89 case DragDropGuiController::PlaceHolderType::Default:
89 case DragDropGuiController::PlaceHolderType::Default:
90 m_PlaceBackground->setStyleSheet(
90 m_PlaceBackground->setStyleSheet(
91 "background-color: #BBD5EE; border: 2px solid #2A7FD4");
91 "background-color: #BBD5EE; border: 2px solid #2A7FD4");
92 m_PlaceHolderLabel->setStyleSheet("color: #2A7FD4");
92 m_PlaceHolderLabel->setStyleSheet("color: #2A7FD4");
93 break;
93 break;
94 }
94 }
95
95
96 m_PlaceHolderLabel->setText(topLabelText);
96 m_PlaceHolderLabel->setText(topLabelText);
97 m_PlaceHolderLabel->setVisible(!topLabelText.isEmpty());
97 m_PlaceHolderLabel->setVisible(!topLabelText.isEmpty());
98 }
98 }
99 };
99 };
100
100
101
101
102 DragDropGuiController::DragDropGuiController()
102 DragDropGuiController::DragDropGuiController()
103 : impl{spimpl::make_unique_impl<DragDropGuiControllerPrivate>()}
103 : impl{spimpl::make_unique_impl<DragDropGuiControllerPrivate>()}
104 {
104 {
105 }
105 }
106
106
107 DragDropGuiController::~DragDropGuiController()
107 DragDropGuiController::~DragDropGuiController()
108 {
108 {
109 QFile::remove(impl->m_ImageTempUrl);
109 QFile::remove(impl->m_ImageTempUrl);
110 }
110 }
111
111
112 void DragDropGuiController::resetDragAndDrop()
112 void DragDropGuiController::resetDragAndDrop()
113 {
113 {
114 setCurrentDragWidget(nullptr);
114 setCurrentDragWidget(nullptr);
115 impl->m_HighlightedDragWidget = nullptr;
115 impl->m_HighlightedDragWidget = nullptr;
116 }
116 }
117
117
118 void DragDropGuiController::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
118 void DragDropGuiController::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
119 {
119 {
120 if (impl->m_CurrentDragWidget) {
120 if (impl->m_CurrentDragWidget) {
121
121
122 QObject::disconnect(impl->m_DragWidgetDestroyedConnection);
122 QObject::disconnect(impl->m_DragWidgetDestroyedConnection);
123 }
123 }
124
124
125 if (dragWidget) {
125 if (dragWidget) {
126 // ensures the impl->m_CurrentDragWidget is reset when the widget is destroyed
126 // ensures the impl->m_CurrentDragWidget is reset when the widget is destroyed
127 impl->m_DragWidgetDestroyedConnection
127 impl->m_DragWidgetDestroyedConnection
128 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
128 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
129 [this]() { impl->m_CurrentDragWidget = nullptr; });
129 [this]() { impl->m_CurrentDragWidget = nullptr; });
130 }
130 }
131
131
132 impl->m_CurrentDragWidget = dragWidget;
132 impl->m_CurrentDragWidget = dragWidget;
133 }
133 }
134
134
135 VisualizationDragWidget *DragDropGuiController::getCurrentDragWidget() const
135 VisualizationDragWidget *DragDropGuiController::getCurrentDragWidget() const
136 {
136 {
137 return impl->m_CurrentDragWidget;
137 return impl->m_CurrentDragWidget;
138 }
138 }
139
139
140 QWidget &DragDropGuiController::placeHolder() const
140 QWidget &DragDropGuiController::placeHolder() const
141 {
141 {
142 return *impl->m_PlaceHolder;
142 return *impl->m_PlaceHolder;
143 }
143 }
144
144
145 void DragDropGuiController::insertPlaceHolder(QVBoxLayout *layout, int index, PlaceHolderType type,
145 void DragDropGuiController::insertPlaceHolder(QVBoxLayout *layout, int index, PlaceHolderType type,
146 const QString &topLabelText)
146 const QString &topLabelText)
147 {
147 {
148 removePlaceHolder();
148 removePlaceHolder();
149 impl->preparePlaceHolder(type, topLabelText);
149 impl->preparePlaceHolder(type, topLabelText);
150 layout->insertWidget(index, impl->m_PlaceHolder.get());
150 layout->insertWidget(index, impl->m_PlaceHolder.get());
151 impl->m_PlaceHolder->show();
151 impl->m_PlaceHolder->show();
152 }
152 }
153
153
154 void DragDropGuiController::removePlaceHolder()
154 void DragDropGuiController::removePlaceHolder()
155 {
155 {
156 auto parentWidget = impl->m_PlaceHolder->parentWidget();
156 auto parentWidget = impl->m_PlaceHolder->parentWidget();
157 if (parentWidget) {
157 if (parentWidget) {
158 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
158 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
159 impl->m_PlaceHolder->setParent(nullptr);
159 impl->m_PlaceHolder->setParent(nullptr);
160 impl->m_PlaceHolder->hide();
160 impl->m_PlaceHolder->hide();
161 }
161 }
162 }
162 }
163
163
164 bool DragDropGuiController::isPlaceHolderSet() const
164 bool DragDropGuiController::isPlaceHolderSet() const
165 {
165 {
166 return impl->m_PlaceHolder->parentWidget();
166 return impl->m_PlaceHolder->parentWidget();
167 }
167 }
168
168
169 void DragDropGuiController::addDragDropScrollArea(QScrollArea *scrollArea)
169 void DragDropGuiController::addDragDropScrollArea(QScrollArea *scrollArea)
170 {
170 {
171 impl->m_DragDropScroller->addScrollArea(scrollArea);
171 impl->m_DragDropScroller->addScrollArea(scrollArea);
172 }
172 }
173
173
174 void DragDropGuiController::removeDragDropScrollArea(QScrollArea *scrollArea)
174 void DragDropGuiController::removeDragDropScrollArea(QScrollArea *scrollArea)
175 {
175 {
176 impl->m_DragDropScroller->removeScrollArea(scrollArea);
176 impl->m_DragDropScroller->removeScrollArea(scrollArea);
177 }
177 }
178
178
179 void DragDropGuiController::addDragDropTabBar(QTabBar *tabBar)
179 void DragDropGuiController::addDragDropTabBar(QTabBar *tabBar)
180 {
180 {
181 impl->m_DragDropTabSwitcher->addTabBar(tabBar);
181 impl->m_DragDropTabSwitcher->addTabBar(tabBar);
182 }
182 }
183
183
184 void DragDropGuiController::removeDragDropTabBar(QTabBar *tabBar)
184 void DragDropGuiController::removeDragDropTabBar(QTabBar *tabBar)
185 {
185 {
186 impl->m_DragDropTabSwitcher->removeTabBar(tabBar);
186 impl->m_DragDropTabSwitcher->removeTabBar(tabBar);
187 }
187 }
188
188
189 QUrl DragDropGuiController::imageTemporaryUrl(const QImage &image) const
189 QUrl DragDropGuiController::imageTemporaryUrl(const QImage &image) const
190 {
190 {
191 image.save(impl->m_ImageTempUrl);
191 image.save(impl->m_ImageTempUrl);
192 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
192 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
193 }
193 }
194
194
195 void DragDropGuiController::setHightlightedDragWidget(VisualizationDragWidget *dragWidget)
195 void DragDropGuiController::setHightlightedDragWidget(VisualizationDragWidget *dragWidget)
196 {
196 {
197 if (impl->m_HighlightedDragWidget) {
197 if (impl->m_HighlightedDragWidget) {
198 impl->m_HighlightedDragWidget->highlightForMerge(false);
198 impl->m_HighlightedDragWidget->highlightForMerge(false);
199 QObject::disconnect(impl->m_HighlightedWidgetDestroyedConnection);
199 QObject::disconnect(impl->m_HighlightedWidgetDestroyedConnection);
200 }
200 }
201
201
202 if (dragWidget) {
202 if (dragWidget) {
203 dragWidget->highlightForMerge(true);
203 dragWidget->highlightForMerge(true);
204
204
205 // ensures the impl->m_HighlightedDragWidget is reset when the widget is destroyed
205 // ensures the impl->m_HighlightedDragWidget is reset when the widget is destroyed
206 impl->m_DragWidgetDestroyedConnection
206 impl->m_DragWidgetDestroyedConnection
207 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
207 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
208 [this]() { impl->m_HighlightedDragWidget = nullptr; });
208 [this]() { impl->m_HighlightedDragWidget = nullptr; });
209 }
209 }
210
210
211 impl->m_HighlightedDragWidget = dragWidget;
211 impl->m_HighlightedDragWidget = dragWidget;
212 }
212 }
213
213
214 VisualizationDragWidget *DragDropGuiController::getHightlightedDragWidget() const
214 VisualizationDragWidget *DragDropGuiController::getHightlightedDragWidget() const
215 {
215 {
216 return impl->m_HighlightedDragWidget;
216 return impl->m_HighlightedDragWidget;
217 }
217 }
218
218
219 void DragDropGuiController::delayedCloseWidget(QWidget *widget)
219 void DragDropGuiController::delayedCloseWidget(QWidget *widget)
220 {
220 {
221 widget->hide();
221 widget->hide();
222 impl->m_WidgetToClose << widget;
222 impl->m_WidgetToClose << widget;
223 }
223 }
224
224
225 void DragDropGuiController::doCloseWidgets()
225 void DragDropGuiController::doCloseWidgets()
226 {
226 {
227 for (auto widget : impl->m_WidgetToClose) {
227 for (auto widget : impl->m_WidgetToClose) {
228 widget->close();
228 widget->close();
229 }
229 }
230
230
231 impl->m_WidgetToClose.clear();
231 impl->m_WidgetToClose.clear();
232 }
232 }
233
233
234 bool DragDropGuiController::checkMimeDataForVisualization(
234 bool DragDropGuiController::checkMimeDataForVisualization(
235 const QMimeData *mimeData, VisualizationDragDropContainer *dropContainer)
235 const QMimeData *mimeData, VisualizationDragDropContainer *dropContainer)
236 {
236 {
237 if (!mimeData || !dropContainer) {
237 if (!mimeData || !dropContainer) {
238 qCWarning(LOG_DragDropGuiController()) << QObject::tr(
238 qCWarning(LOG_DragDropGuiController()) << QObject::tr(
239 "DragDropGuiController::checkMimeDataForVisualization, invalid input parameters.");
239 "DragDropGuiController::checkMimeDataForVisualization, invalid input parameters.");
240 Q_ASSERT(false);
240 Q_ASSERT(false);
241 return false;
241 return false;
242 }
242 }
243
243
244 auto result = false;
244 auto result = false;
245
245
246 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
246 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
247 auto variables = sqpApp->variableController().variablesForMimeData(
247 auto variables = sqpApp->variableController().variables(
248 mimeData->data(MIME_TYPE_VARIABLE_LIST));
248 mimeData->data(MIME_TYPE_VARIABLE_LIST));
249
249
250 if (variables.count() == 1) {
250 if (variables.size() == 1) {
251
251
252 auto variable = variables.first();
252 auto variable = variables[0];
253 if (variable->dataSeries() != nullptr) {
253 if (variable->dataSeries() != nullptr) {
254
254
255 // Check that the variable is not already in a graph
255 // Check that the variable is not already in a graph
256
256
257 auto parent = dropContainer->parentWidget();
257 auto parent = dropContainer->parentWidget();
258 while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) {
258 while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) {
259 parent = parent->parentWidget(); // Search for the top level VisualizationWidget
259 parent = parent->parentWidget(); // Search for the top level VisualizationWidget
260 }
260 }
261
261
262 if (parent) {
262 if (parent) {
263 auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
263 auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
264
264
265 FindVariableOperation findVariableOperation{variable};
265 FindVariableOperation findVariableOperation{variable};
266 visualizationWidget->accept(&findVariableOperation);
266 visualizationWidget->accept(&findVariableOperation);
267 auto variableContainers = findVariableOperation.result();
267 auto variableContainers = findVariableOperation.result();
268 if (variableContainers.empty()) {
268 if (variableContainers.empty()) {
269 result = true;
269 result = true;
270 }
270 }
271 else {
271 else {
272 // result = false: the variable already exist in the visualisation
272 // result = false: the variable already exist in the visualisation
273 }
273 }
274 }
274 }
275 else {
275 else {
276 qCWarning(LOG_DragDropGuiController()) << QObject::tr(
276 qCWarning(LOG_DragDropGuiController()) << QObject::tr(
277 "DragDropGuiController::checkMimeDataForVisualization, the parent "
277 "DragDropGuiController::checkMimeDataForVisualization, the parent "
278 "VisualizationWidget cannot be found. Cannot check if the variable is "
278 "VisualizationWidget cannot be found. Cannot check if the variable is "
279 "already used or not.");
279 "already used or not.");
280 }
280 }
281 }
281 }
282 else {
282 else {
283 // result = false: the variable is not fully loaded
283 // result = false: the variable is not fully loaded
284 }
284 }
285 }
285 }
286 else {
286 else {
287 // result = false: cannot drop multiple variables in the visualisation
287 // result = false: cannot drop multiple variables in the visualisation
288 }
288 }
289 }
289 }
290 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
290 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
291 auto productDataList = sqpApp->dataSourceController().productsDataForMimeData(
291 auto productDataList = sqpApp->dataSourceController().productsDataForMimeData(
292 mimeData->data(MIME_TYPE_PRODUCT_LIST));
292 mimeData->data(MIME_TYPE_PRODUCT_LIST));
293 if (productDataList.count() == 1) {
293 if (productDataList.count() == 1) {
294 result = true;
294 result = true;
295 }
295 }
296 else {
296 else {
297 // result = false: cannot drop multiple products in the visualisation
297 // result = false: cannot drop multiple products in the visualisation
298 }
298 }
299 }
299 }
300 else {
300 else {
301 // Other MIME data
301 // Other MIME data
302 // no special rules, accepted by default
302 // no special rules, accepted by default
303 result = true;
303 result = true;
304 }
304 }
305
305
306
306
307 return result;
307 return result;
308 }
308 }
@@ -1,207 +1,202
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>
12 #include <Variable/VariableController.h>
13 #include <Variable/VariableController2.h>
14 #include <Variable/VariableModel2.h>
13 #include <Variable/VariableModel.h>
15 #include <Variable/VariableModel.h>
14 #include <Visualization/VisualizationController.h>
16 #include <Visualization/VisualizationController.h>
15
17
16 Q_LOGGING_CATEGORY(LOG_SqpApplication, "SqpApplication")
18 Q_LOGGING_CATEGORY(LOG_SqpApplication, "SqpApplication")
17
19
18 class SqpApplication::SqpApplicationPrivate {
20 class SqpApplication::SqpApplicationPrivate {
19 public:
21 public:
20 SqpApplicationPrivate()
22 SqpApplicationPrivate()
21 : m_DataSourceController{std::make_unique<DataSourceController>()},
23 : m_VariableController{std::make_shared<VariableController2>()},
22 m_VariableController{std::make_unique<VariableController>()},
24 m_VariableModel{m_VariableController},
23 m_TimeController{std::make_unique<TimeController>()},
24 m_NetworkController{std::make_unique<NetworkController>()},
25 m_VisualizationController{std::make_unique<VisualizationController>()},
26 m_DragDropGuiController{std::make_unique<DragDropGuiController>()},
27 m_CatalogueController{std::make_unique<CatalogueController>()},
28 m_ActionsGuiController{std::make_unique<ActionsGuiController>()},
29 m_PlotInterractionMode(SqpApplication::PlotsInteractionMode::None),
25 m_PlotInterractionMode(SqpApplication::PlotsInteractionMode::None),
30 m_PlotCursorMode(SqpApplication::PlotsCursorMode::NoCursor)
26 m_PlotCursorMode(SqpApplication::PlotsCursorMode::NoCursor)
31 {
27 {
32 // /////////////////////////////// //
28 // /////////////////////////////// //
33 // Connections between controllers //
29 // Connections between controllers //
34 // /////////////////////////////// //
30 // /////////////////////////////// //
35
31
36 // VariableController <-> DataSourceController
32 // VariableController <-> DataSourceController
37 connect(m_DataSourceController.get(),
33 connect(&m_DataSourceController,
38 SIGNAL(variableCreationRequested(const QString &, const QVariantHash &,
34 SIGNAL(variableCreationRequested(const QString &, const QVariantHash &,
39 std::shared_ptr<IDataProvider>)),
35 std::shared_ptr<IDataProvider>)),
40 m_VariableController.get(),
36 m_VariableController.get(),
41 SLOT(createVariable(const QString &, const QVariantHash &,
37 SLOT(createVariable(const QString &, const QVariantHash &,
42 std::shared_ptr<IDataProvider>)));
38 std::shared_ptr<IDataProvider>)));
43
39
44 connect(m_VariableController->variableModel(), &VariableModel::requestVariable,
40 // connect(m_VariableController->variableModel(), &VariableModel::requestVariable,
45 m_DataSourceController.get(), &DataSourceController::requestVariable);
41 // m_DataSourceController.get(), &DataSourceController::requestVariable);
46
42
47 // VariableController <-> VisualizationController
43 // VariableController <-> VisualizationController
48 connect(m_VariableController.get(),
44 // connect(m_VariableController.get(),
49 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)),
45 // SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)),
50 m_VisualizationController.get(),
46 // m_VisualizationController.get(),
51 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), Qt::DirectConnection);
47 // SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), Qt::DirectConnection);
52
48
53 connect(m_VariableController.get(),
49 // connect(m_VariableController.get(),
54 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const DateTimeRange &)),
50 // SIGNAL(rangeChanged(std::shared_ptr<Variable>, const DateTimeRange &)),
55 m_VisualizationController.get(),
51 // m_VisualizationController.get(),
56 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const DateTimeRange &)));
52 // SIGNAL(rangeChanged(std::shared_ptr<Variable>, const DateTimeRange &)));
57
53
58
54
59 m_DataSourceController->moveToThread(&m_DataSourceControllerThread);
55 m_DataSourceController.moveToThread(&m_DataSourceControllerThread);
60 m_DataSourceControllerThread.setObjectName("DataSourceControllerThread");
56 m_DataSourceControllerThread.setObjectName("DataSourceControllerThread");
61 m_NetworkController->moveToThread(&m_NetworkControllerThread);
57 m_NetworkController.moveToThread(&m_NetworkControllerThread);
62 m_NetworkControllerThread.setObjectName("NetworkControllerThread");
58 m_NetworkControllerThread.setObjectName("NetworkControllerThread");
63 m_VariableController->moveToThread(&m_VariableControllerThread);
59 m_VisualizationController.moveToThread(&m_VisualizationControllerThread);
64 m_VariableControllerThread.setObjectName("VariableControllerThread");
65 m_VisualizationController->moveToThread(&m_VisualizationControllerThread);
66 m_VisualizationControllerThread.setObjectName("VsualizationControllerThread");
60 m_VisualizationControllerThread.setObjectName("VsualizationControllerThread");
67
61
68 // Additionnal init
62 // Additionnal init
69 //m_VariableController->setTimeController(m_TimeController.get());
63 //m_VariableController->setTimeController(m_TimeController.get());
70 }
64 }
71
65
72 virtual ~SqpApplicationPrivate()
66 virtual ~SqpApplicationPrivate()
73 {
67 {
74 m_DataSourceControllerThread.quit();
68 m_DataSourceControllerThread.quit();
75 m_DataSourceControllerThread.wait();
69 m_DataSourceControllerThread.wait();
76
70
77 m_NetworkControllerThread.quit();
71 m_NetworkControllerThread.quit();
78 m_NetworkControllerThread.wait();
72 m_NetworkControllerThread.wait();
79
73
80 m_VariableControllerThread.quit();
81 m_VariableControllerThread.wait();
82
83 m_VisualizationControllerThread.quit();
74 m_VisualizationControllerThread.quit();
84 m_VisualizationControllerThread.wait();
75 m_VisualizationControllerThread.wait();
85 }
76 }
86
77
87 std::unique_ptr<DataSourceController> m_DataSourceController;
78 DataSourceController m_DataSourceController;
88 std::unique_ptr<VariableController> m_VariableController;
79 std::shared_ptr<VariableController2> m_VariableController;
89 std::unique_ptr<TimeController> m_TimeController;
80 TimeController m_TimeController;
90 std::unique_ptr<NetworkController> m_NetworkController;
81 NetworkController m_NetworkController;
91 std::unique_ptr<VisualizationController> m_VisualizationController;
82 VisualizationController m_VisualizationController;
92 std::unique_ptr<CatalogueController> m_CatalogueController;
83 CatalogueController m_CatalogueController;
84 VariableModel2 m_VariableModel;
93
85
94 QThread m_DataSourceControllerThread;
86 QThread m_DataSourceControllerThread;
95 QThread m_NetworkControllerThread;
87 QThread m_NetworkControllerThread;
96 QThread m_VariableControllerThread;
97 QThread m_VisualizationControllerThread;
88 QThread m_VisualizationControllerThread;
98
89
99 std::unique_ptr<DragDropGuiController> m_DragDropGuiController;
90 DragDropGuiController m_DragDropGuiController;
100 std::unique_ptr<ActionsGuiController> m_ActionsGuiController;
91 ActionsGuiController m_ActionsGuiController;
101
92
102 SqpApplication::PlotsInteractionMode m_PlotInterractionMode;
93 SqpApplication::PlotsInteractionMode m_PlotInterractionMode;
103 SqpApplication::PlotsCursorMode m_PlotCursorMode;
94 SqpApplication::PlotsCursorMode m_PlotCursorMode;
104 };
95 };
105
96
106
97
107 SqpApplication::SqpApplication(int &argc, char **argv)
98 SqpApplication::SqpApplication(int &argc, char **argv)
108 : QApplication{argc, argv}, impl{spimpl::make_unique_impl<SqpApplicationPrivate>()}
99 : QApplication{argc, argv}, impl{spimpl::make_unique_impl<SqpApplicationPrivate>()}
109 {
100 {
110 qCDebug(LOG_SqpApplication()) << tr("SqpApplication construction") << QThread::currentThread();
101 qCDebug(LOG_SqpApplication()) << tr("SqpApplication construction") << QThread::currentThread();
111
102
112 QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
103 QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
113
104
114 connect(&impl->m_DataSourceControllerThread, &QThread::started,
105 connect(&impl->m_DataSourceControllerThread, &QThread::started,
115 impl->m_DataSourceController.get(), &DataSourceController::initialize);
106 &impl->m_DataSourceController, &DataSourceController::initialize);
116 connect(&impl->m_DataSourceControllerThread, &QThread::finished,
107 connect(&impl->m_DataSourceControllerThread, &QThread::finished,
117 impl->m_DataSourceController.get(), &DataSourceController::finalize);
108 &impl->m_DataSourceController, &DataSourceController::finalize);
118
109
119 connect(&impl->m_NetworkControllerThread, &QThread::started, impl->m_NetworkController.get(),
110 connect(&impl->m_NetworkControllerThread, &QThread::started, &impl->m_NetworkController,
120 &NetworkController::initialize);
111 &NetworkController::initialize);
121 connect(&impl->m_NetworkControllerThread, &QThread::finished, impl->m_NetworkController.get(),
112 connect(&impl->m_NetworkControllerThread, &QThread::finished, &impl->m_NetworkController,
122 &NetworkController::finalize);
113 &NetworkController::finalize);
123
114
124 connect(&impl->m_VariableControllerThread, &QThread::started, impl->m_VariableController.get(),
125 &VariableController::initialize);
126 connect(&impl->m_VariableControllerThread, &QThread::finished, impl->m_VariableController.get(),
127 &VariableController::finalize);
128
129 connect(&impl->m_VisualizationControllerThread, &QThread::started,
115 connect(&impl->m_VisualizationControllerThread, &QThread::started,
130 impl->m_VisualizationController.get(), &VisualizationController::initialize);
116 &impl->m_VisualizationController, &VisualizationController::initialize);
131 connect(&impl->m_VisualizationControllerThread, &QThread::finished,
117 connect(&impl->m_VisualizationControllerThread, &QThread::finished,
132 impl->m_VisualizationController.get(), &VisualizationController::finalize);
118 &impl->m_VisualizationController, &VisualizationController::finalize);
133
119
134 impl->m_DataSourceControllerThread.start();
120 impl->m_DataSourceControllerThread.start();
135 impl->m_NetworkControllerThread.start();
121 impl->m_NetworkControllerThread.start();
136 impl->m_VariableControllerThread.start();
137 impl->m_VisualizationControllerThread.start();
122 impl->m_VisualizationControllerThread.start();
138 impl->m_CatalogueController->initialize();
123 impl->m_CatalogueController.initialize();
139 }
124 }
140
125
141 SqpApplication::~SqpApplication()
126 SqpApplication::~SqpApplication()
142 {
127 {
143 }
128 }
144
129
145 void SqpApplication::initialize()
130 void SqpApplication::initialize()
146 {
131 {
147 }
132 }
148
133
149 DataSourceController &SqpApplication::dataSourceController() noexcept
134 DataSourceController &SqpApplication::dataSourceController() noexcept
150 {
135 {
151 return *impl->m_DataSourceController;
136 return impl->m_DataSourceController;
152 }
137 }
153
138
154 NetworkController &SqpApplication::networkController() noexcept
139 NetworkController &SqpApplication::networkController() noexcept
155 {
140 {
156 return *impl->m_NetworkController;
141 return impl->m_NetworkController;
157 }
142 }
158
143
159 TimeController &SqpApplication::timeController() noexcept
144 TimeController &SqpApplication::timeController() noexcept
160 {
145 {
161 return *impl->m_TimeController;
146 return impl->m_TimeController;
162 }
147 }
163
148
164 VariableController &SqpApplication::variableController() noexcept
149 VariableController2 &SqpApplication::variableController() noexcept
165 {
150 {
166 return *impl->m_VariableController;
151 return *impl->m_VariableController;
167 }
152 }
168
153
154 std::shared_ptr<VariableController2> SqpApplication::variableControllerOwner() noexcept
155 {
156 return impl->m_VariableController;
157 }
158
159 //VariableModel2 &SqpApplication::variableModel() noexcept
160 //{
161 // return impl->m_VariableModel;
162 //}
163
169 VisualizationController &SqpApplication::visualizationController() noexcept
164 VisualizationController &SqpApplication::visualizationController() noexcept
170 {
165 {
171 return *impl->m_VisualizationController;
166 return impl->m_VisualizationController;
172 }
167 }
173
168
174 CatalogueController &SqpApplication::catalogueController() noexcept
169 CatalogueController &SqpApplication::catalogueController() noexcept
175 {
170 {
176 return *impl->m_CatalogueController;
171 return impl->m_CatalogueController;
177 }
172 }
178
173
179 DragDropGuiController &SqpApplication::dragDropGuiController() noexcept
174 DragDropGuiController &SqpApplication::dragDropGuiController() noexcept
180 {
175 {
181 return *impl->m_DragDropGuiController;
176 return impl->m_DragDropGuiController;
182 }
177 }
183
178
184 ActionsGuiController &SqpApplication::actionsGuiController() noexcept
179 ActionsGuiController &SqpApplication::actionsGuiController() noexcept
185 {
180 {
186 return *impl->m_ActionsGuiController;
181 return impl->m_ActionsGuiController;
187 }
182 }
188
183
189 SqpApplication::PlotsInteractionMode SqpApplication::plotsInteractionMode() const
184 SqpApplication::PlotsInteractionMode SqpApplication::plotsInteractionMode() const
190 {
185 {
191 return impl->m_PlotInterractionMode;
186 return impl->m_PlotInterractionMode;
192 }
187 }
193
188
194 void SqpApplication::setPlotsInteractionMode(SqpApplication::PlotsInteractionMode mode)
189 void SqpApplication::setPlotsInteractionMode(SqpApplication::PlotsInteractionMode mode)
195 {
190 {
196 impl->m_PlotInterractionMode = mode;
191 impl->m_PlotInterractionMode = mode;
197 }
192 }
198
193
199 SqpApplication::PlotsCursorMode SqpApplication::plotsCursorMode() const
194 SqpApplication::PlotsCursorMode SqpApplication::plotsCursorMode() const
200 {
195 {
201 return impl->m_PlotCursorMode;
196 return impl->m_PlotCursorMode;
202 }
197 }
203
198
204 void SqpApplication::setPlotsCursorMode(SqpApplication::PlotsCursorMode mode)
199 void SqpApplication::setPlotsCursorMode(SqpApplication::PlotsCursorMode mode)
205 {
200 {
206 impl->m_PlotCursorMode = mode;
201 impl->m_PlotCursorMode = mode;
207 }
202 }
@@ -1,240 +1,241
1 #include <Variable/RenameVariableDialog.h>
1 #include <Variable/RenameVariableDialog.h>
2 #include <Variable/Variable.h>
2 #include <Variable/Variable.h>
3 #include <Variable/VariableController.h>
3 #include <Variable/VariableController2.h>
4 #include <Variable/VariableInspectorWidget.h>
4 #include <Variable/VariableInspectorWidget.h>
5 #include <Variable/VariableMenuHeaderWidget.h>
5 #include <Variable/VariableMenuHeaderWidget.h>
6 #include <Variable/VariableModel.h>
6 #include <Variable/VariableModel2.h>
7
7
8 #include <ui_VariableInspectorWidget.h>
8 #include <ui_VariableInspectorWidget.h>
9
9
10 #include <QMouseEvent>
10 #include <QMouseEvent>
11 #include <QSortFilterProxyModel>
11 #include <QSortFilterProxyModel>
12 #include <QStyledItemDelegate>
12 #include <QStyledItemDelegate>
13 #include <QWidgetAction>
13 #include <QWidgetAction>
14
14
15 #include <DragAndDrop/DragDropGuiController.h>
15 #include <DragAndDrop/DragDropGuiController.h>
16 #include <SqpApplication.h>
16 #include <SqpApplication.h>
17
17
18 Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget")
18 Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget")
19
19
20
20
21 class QProgressBarItemDelegate : public QStyledItemDelegate {
21 class QProgressBarItemDelegate : public QStyledItemDelegate {
22
22
23 public:
23 public:
24 QProgressBarItemDelegate(QObject *parent) : QStyledItemDelegate{parent} {}
24 QProgressBarItemDelegate(QObject *parent) : QStyledItemDelegate{parent} {}
25
25
26 void paint(QPainter *painter, const QStyleOptionViewItem &option,
26 void paint(QPainter *painter, const QStyleOptionViewItem &option,
27 const QModelIndex &index) const
27 const QModelIndex &index) const
28 {
28 {
29 auto data = index.data(Qt::DisplayRole);
29 auto data = index.data(Qt::DisplayRole);
30 auto progressData = index.data(VariableRoles::ProgressRole);
30 auto progressData = index.data(VariableRoles::ProgressRole);
31 if (data.isValid() && progressData.isValid()) {
31 if (data.isValid() && progressData.isValid()) {
32 auto name = data.value<QString>();
32 auto name = data.value<QString>();
33 auto progress = progressData.value<double>();
33 auto progress = progressData.value<double>();
34 if (progress > 0) {
34 if (progress > 0) {
35 auto cancelButtonWidth = 20;
35 auto cancelButtonWidth = 20;
36 auto progressBarOption = QStyleOptionProgressBar{};
36 auto progressBarOption = QStyleOptionProgressBar{};
37 auto progressRect = option.rect;
37 auto progressRect = option.rect;
38 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
38 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
39 progressBarOption.rect = progressRect;
39 progressBarOption.rect = progressRect;
40 progressBarOption.minimum = 0;
40 progressBarOption.minimum = 0;
41 progressBarOption.maximum = 100;
41 progressBarOption.maximum = 100;
42 progressBarOption.progress = progress;
42 progressBarOption.progress = progress;
43 progressBarOption.text
43 progressBarOption.text
44 = QString("%1 %2").arg(name).arg(QString::number(progress, 'f', 2) + "%");
44 = QString("%1 %2").arg(name).arg(QString::number(progress, 'f', 2) + "%");
45 progressBarOption.textVisible = true;
45 progressBarOption.textVisible = true;
46 progressBarOption.textAlignment = Qt::AlignCenter;
46 progressBarOption.textAlignment = Qt::AlignCenter;
47
47
48
48
49 QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption,
49 QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption,
50 painter);
50 painter);
51
51
52 // Cancel button
52 // Cancel button
53 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
53 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
54 option.rect.height());
54 option.rect.height());
55 auto buttonOption = QStyleOptionButton{};
55 auto buttonOption = QStyleOptionButton{};
56 buttonOption.rect = buttonRect;
56 buttonOption.rect = buttonRect;
57 buttonOption.text = "X";
57 buttonOption.text = "X";
58
58
59 QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter);
59 QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter);
60 }
60 }
61 else {
61 else {
62 QStyledItemDelegate::paint(painter, option, index);
62 QStyledItemDelegate::paint(painter, option, index);
63 }
63 }
64 }
64 }
65 else {
65 else {
66 QStyledItemDelegate::paint(painter, option, index);
66 QStyledItemDelegate::paint(painter, option, index);
67 }
67 }
68 }
68 }
69
69
70 bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
70 bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
71 const QModelIndex &index)
71 const QModelIndex &index)
72 {
72 {
73 if (event->type() == QEvent::MouseButtonRelease) {
73 if (event->type() == QEvent::MouseButtonRelease) {
74 auto data = index.data(Qt::DisplayRole);
74 auto data = index.data(Qt::DisplayRole);
75 auto progressData = index.data(VariableRoles::ProgressRole);
75 auto progressData = index.data(VariableRoles::ProgressRole);
76 if (data.isValid() && progressData.isValid()) {
76 if (data.isValid() && progressData.isValid()) {
77 auto cancelButtonWidth = 20;
77 auto cancelButtonWidth = 20;
78 auto progressRect = option.rect;
78 auto progressRect = option.rect;
79 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
79 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
80 // Cancel button
80 // Cancel button
81 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
81 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
82 option.rect.height());
82 option.rect.height());
83
83
84 auto e = (QMouseEvent *)event;
84 auto e = (QMouseEvent *)event;
85 auto clickX = e->x();
85 auto clickX = e->x();
86 auto clickY = e->y();
86 auto clickY = e->y();
87
87
88 auto x = buttonRect.left(); // the X coordinate
88 auto x = buttonRect.left(); // the X coordinate
89 auto y = buttonRect.top(); // the Y coordinate
89 auto y = buttonRect.top(); // the Y coordinate
90 auto w = buttonRect.width(); // button width
90 auto w = buttonRect.width(); // button width
91 auto h = buttonRect.height(); // button height
91 auto h = buttonRect.height(); // button height
92
92
93 if (clickX > x && clickX < x + w) {
93 if (clickX > x && clickX < x + w) {
94 if (clickY > y && clickY < y + h) {
94 if (clickY > y && clickY < y + h) {
95 auto variableModel = sqpApp->variableController().variableModel();
95 //auto& variableModel = sqpApp->variableModel();
96 variableModel->abortProgress(index);
96 //variableModel->abortProgress(index);
97 }
97 }
98 return true;
98 return true;
99 }
99 }
100 else {
100 else {
101 return QStyledItemDelegate::editorEvent(event, model, option, index);
101 return QStyledItemDelegate::editorEvent(event, model, option, index);
102 }
102 }
103 }
103 }
104 else {
104 else {
105 return QStyledItemDelegate::editorEvent(event, model, option, index);
105 return QStyledItemDelegate::editorEvent(event, model, option, index);
106 }
106 }
107 }
107 }
108 else {
108 else {
109 return QStyledItemDelegate::editorEvent(event, model, option, index);
109 return QStyledItemDelegate::editorEvent(event, model, option, index);
110 }
110 }
111
111
112
112
113 return QStyledItemDelegate::editorEvent(event, model, option, index);
113 return QStyledItemDelegate::editorEvent(event, model, option, index);
114 }
114 }
115 };
115 };
116
116
117 VariableInspectorWidget::VariableInspectorWidget(QWidget *parent)
117 VariableInspectorWidget::VariableInspectorWidget(QWidget *parent)
118 : QWidget{parent},
118 : QWidget{parent},
119 ui{new Ui::VariableInspectorWidget},
119 ui{new Ui::VariableInspectorWidget},
120 m_ProgressBarItemDelegate{new QProgressBarItemDelegate{this}}
120 m_ProgressBarItemDelegate{new QProgressBarItemDelegate{this}}
121 {
121 {
122 ui->setupUi(this);
122 ui->setupUi(this);
123
123
124 // Sets model for table
124 // Sets model for table
125 // auto sortFilterModel = new QSortFilterProxyModel{this};
125 // auto sortFilterModel = new QSortFilterProxyModel{this};
126 // sortFilterModel->setSourceModel(sqpApp->variableController().variableModel());
126 // sortFilterModel->setSourceModel(sqpApp->variableController().variableModel());
127
127
128 auto variableModel = sqpApp->variableController().variableModel();
128 m_model = new VariableModel2(sqpApp->variableControllerOwner());
129 ui->tableView->setModel(variableModel);
129 ui->tableView->setModel(m_model);
130
130
131 // Adds extra signal/slot between view and model, so the view can be updated instantly when
131 // Adds extra signal/slot between view and model, so the view can be updated instantly when
132 // there is a change of data in the model
132 // there is a change of data in the model
133 connect(variableModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this,
133 connect(m_model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this,
134 SLOT(refresh()));
134 SLOT(refresh()));
135
135
136 ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel());
136 //ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel());
137 ui->tableView->setItemDelegateForColumn(0, m_ProgressBarItemDelegate);
137 ui->tableView->setItemDelegateForColumn(0, m_ProgressBarItemDelegate);
138
138
139 // Fixes column sizes
139 // Fixes column sizes
140 auto model = ui->tableView->model();
140 auto model = ui->tableView->model();
141 const auto count = model->columnCount();
141 const auto count = model->columnCount();
142 for (auto i = 0; i < count; ++i) {
142 for (auto i = 0; i < count; ++i) {
143 ui->tableView->setColumnWidth(
143 ui->tableView->setColumnWidth(
144 i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width());
144 i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width());
145 }
145 }
146
146
147 // Sets selection options
147 // Sets selection options
148 ui->tableView->setSelectionBehavior(QTableView::SelectRows);
148 ui->tableView->setSelectionBehavior(QTableView::SelectRows);
149 ui->tableView->setSelectionMode(QTableView::ExtendedSelection);
149 ui->tableView->setSelectionMode(QTableView::ExtendedSelection);
150
150
151 // Connection to show a menu when right clicking on the tree
151 // Connection to show a menu when right clicking on the tree
152 ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
152 ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
153 connect(ui->tableView, &QTableView::customContextMenuRequested, this,
153 connect(ui->tableView, &QTableView::customContextMenuRequested, this,
154 &VariableInspectorWidget::onTableMenuRequested);
154 &VariableInspectorWidget::onTableMenuRequested);
155 }
155 }
156
156
157 VariableInspectorWidget::~VariableInspectorWidget()
157 VariableInspectorWidget::~VariableInspectorWidget()
158 {
158 {
159 delete ui;
159 delete ui;
160 }
160 }
161
161
162 void VariableInspectorWidget::onTableMenuRequested(const QPoint &pos) noexcept
162 void VariableInspectorWidget::onTableMenuRequested(const QPoint &pos) noexcept
163 {
163 {
164 auto selectedRows = ui->tableView->selectionModel()->selectedRows();
164 auto selectedRows = ui->tableView->selectionModel()->selectedRows();
165
165
166 // Gets the model to retrieve the underlying selected variables
166 // Gets the model to retrieve the underlying selected variables
167 auto model = sqpApp->variableController().variableModel();
167 auto& vc = sqpApp->variableController();
168 auto selectedVariables = QVector<std::shared_ptr<Variable> >{};
168 auto selectedVariables = QVector<std::shared_ptr<Variable> >{};
169 for (const auto &selectedRow : qAsConst(selectedRows)) {
169 for (const auto &selectedRow : qAsConst(selectedRows)) {
170 if (auto selectedVariable = model->variable(selectedRow.row())) {
170 if (auto selectedVariable = vc[selectedRow.row()]) {
171 selectedVariables.push_back(selectedVariable);
171 selectedVariables.push_back(selectedVariable);
172 }
172 }
173 }
173 }
174
174
175 QMenu tableMenu{};
175 QMenu tableMenu{};
176
176
177 // Emits a signal so that potential receivers can populate the menu before displaying it
177 // Emits a signal so that potential receivers can populate the menu before displaying it
178 emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables);
178 emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables);
179
179
180 // Adds menu-specific actions
180 // Adds menu-specific actions
181 if (!selectedVariables.isEmpty()) {
181 if (!selectedVariables.isEmpty()) {
182 tableMenu.addSeparator();
182 tableMenu.addSeparator();
183
183
184 // 'Rename' and 'Duplicate' actions (only if one variable selected)
184 // 'Rename' and 'Duplicate' actions (only if one variable selected)
185 if (selectedVariables.size() == 1) {
185 if (selectedVariables.size() == 1) {
186 auto selectedVariable = selectedVariables.front();
186 auto selectedVariable = selectedVariables.front();
187
187
188 auto duplicateFun = [varW = std::weak_ptr<Variable>(selectedVariable)]()
188 auto duplicateFun = [varW = std::weak_ptr<Variable>(selectedVariable)]()
189 {
189 {
190 if (auto var = varW.lock()) {
190 if (auto var = varW.lock()) {
191 sqpApp->variableController().cloneVariable(var);
191 sqpApp->variableController().cloneVariable(var);
192 }
192 }
193 };
193 };
194
194
195 tableMenu.addAction(tr("Duplicate"), duplicateFun);
195 tableMenu.addAction(tr("Duplicate"), duplicateFun);
196
196
197 auto renameFun = [ varW = std::weak_ptr<Variable>(selectedVariable), &model, this ]()
197 auto renameFun = [ varW = std::weak_ptr<Variable>(selectedVariable), this ]()
198 {
198 {
199 if (auto var = varW.lock()) {
199 if (auto var = varW.lock()) {
200 // Generates forbidden names (names associated to existing variables)
200 // Generates forbidden names (names associated to existing variables)
201 auto allVariables = model->variables();
201 auto allVariables = sqpApp->variableController().variables();
202 auto forbiddenNames = QVector<QString>(allVariables.size());
202 auto forbiddenNames = QVector<QString>(allVariables.size());
203 std::transform(allVariables.cbegin(), allVariables.cend(),
203 std::transform(allVariables.cbegin(), allVariables.cend(),
204 forbiddenNames.begin(),
204 forbiddenNames.begin(),
205 [](const auto &variable) { return variable->name(); });
205 [](const auto &variable) { return variable->name(); });
206
206
207 RenameVariableDialog dialog{var->name(), forbiddenNames, this};
207 RenameVariableDialog dialog{var->name(), forbiddenNames, this};
208 if (dialog.exec() == QDialog::Accepted) {
208 if (dialog.exec() == QDialog::Accepted) {
209 var->setName(dialog.name());
209 var->setName(dialog.name());
210 }
210 }
211 }
211 }
212 };
212 };
213
213
214 tableMenu.addAction(tr("Rename..."), renameFun);
214 tableMenu.addAction(tr("Rename..."), renameFun);
215 }
215 }
216
216
217 // 'Delete' action
217 // 'Delete' action
218 auto deleteFun = [&selectedVariables]() {
218 auto deleteFun = [&selectedVariables]() {
219 sqpApp->variableController().deleteVariables(selectedVariables);
219 for(const auto& var:selectedVariables)
220 sqpApp->variableController().deleteVariable(var);
220 };
221 };
221
222
222 tableMenu.addAction(QIcon{":/icones/delete.png"}, tr("Delete"), deleteFun);
223 tableMenu.addAction(QIcon{":/icones/delete.png"}, tr("Delete"), deleteFun);
223 }
224 }
224
225
225 if (!tableMenu.isEmpty()) {
226 if (!tableMenu.isEmpty()) {
226 // Generates menu header (inserted before first action)
227 // Generates menu header (inserted before first action)
227 auto firstAction = tableMenu.actions().first();
228 auto firstAction = tableMenu.actions().first();
228 auto headerAction = new QWidgetAction{&tableMenu};
229 auto headerAction = new QWidgetAction{&tableMenu};
229 headerAction->setDefaultWidget(new VariableMenuHeaderWidget{selectedVariables, &tableMenu});
230 headerAction->setDefaultWidget(new VariableMenuHeaderWidget{selectedVariables, &tableMenu});
230 tableMenu.insertAction(firstAction, headerAction);
231 tableMenu.insertAction(firstAction, headerAction);
231
232
232 // Displays menu
233 // Displays menu
233 tableMenu.exec(QCursor::pos());
234 tableMenu.exec(QCursor::pos());
234 }
235 }
235 }
236 }
236
237
237 void VariableInspectorWidget::refresh() noexcept
238 void VariableInspectorWidget::refresh() noexcept
238 {
239 {
239 ui->tableView->viewport()->update();
240 ui->tableView->viewport()->update();
240 }
241 }
@@ -1,1082 +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/VariableController.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 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
256 //@TODO implement this :)
257 &VariableController::onRequestDataLoading);
257 // connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
258 // &VariableController::onRequestDataLoading);
258
259
259 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
260 // connect(&sqpApp->variableController(), &VariableController2::updateVarDisplaying, this,
260 &VisualizationGraphWidget::onUpdateVarDisplaying);
261 // &VisualizationGraphWidget::onUpdateVarDisplaying);
261
262
262 // Necessary for all platform since Qt::AA_EnableHighDpiScaling is enable.
263 // Necessary for all platform since Qt::AA_EnableHighDpiScaling is enable.
263 plot().setPlottingHint(QCP::phFastPolylines, true);
264 plot().setPlottingHint(QCP::phFastPolylines, true);
264 }
265 }
265
266
266
267
267 VisualizationGraphWidget::~VisualizationGraphWidget()
268 VisualizationGraphWidget::~VisualizationGraphWidget()
268 {
269 {
269 delete ui;
270 delete ui;
270 }
271 }
271
272
272 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
273 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
273 {
274 {
274 auto parent = parentWidget();
275 auto parent = parentWidget();
275 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
276 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
276 parent = parent->parentWidget();
277 parent = parent->parentWidget();
277 }
278 }
278
279
279 return qobject_cast<VisualizationZoneWidget *>(parent);
280 return qobject_cast<VisualizationZoneWidget *>(parent);
280 }
281 }
281
282
282 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
283 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
283 {
284 {
284 auto parent = parentWidget();
285 auto parent = parentWidget();
285 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
286 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
286 parent = parent->parentWidget();
287 parent = parent->parentWidget();
287 }
288 }
288
289
289 return qobject_cast<VisualizationWidget *>(parent);
290 return qobject_cast<VisualizationWidget *>(parent);
290 }
291 }
291
292
292 void VisualizationGraphWidget::setFlags(GraphFlags flags)
293 void VisualizationGraphWidget::setFlags(GraphFlags flags)
293 {
294 {
294 impl->m_Flags = std::move(flags);
295 impl->m_Flags = std::move(flags);
295 }
296 }
296
297
297 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, DateTimeRange range)
298 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, DateTimeRange range)
298 {
299 {
299 /// 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
300 auto loadRange = [this](std::shared_ptr<Variable> variable, const DateTimeRange &range) {
301 auto loadRange = [this](std::shared_ptr<Variable> variable, const DateTimeRange &range) {
301 impl->m_RenderingDelegate->setAxesUnits(*variable);
302 impl->m_RenderingDelegate->setAxesUnits(*variable);
302
303
303 this->setFlags(GraphFlag::DisableAll);
304 this->setFlags(GraphFlag::DisableAll);
304 setGraphRange(range);
305 setGraphRange(range);
305 this->setFlags(GraphFlag::EnableAll);
306 this->setFlags(GraphFlag::EnableAll);
306 emit requestDataLoading({variable}, range, false);
307 emit requestDataLoading({variable}, range, false);
307 };
308 };
308
309
309 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
310 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
310
311
311 // 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.
312 // 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
313 connect(variable.get(), &Variable::dataInitialized, this,
314 connect(variable.get(), &Variable::dataInitialized, this,
314 [ varW = std::weak_ptr<Variable>{variable}, range, loadRange, this ]() {
315 [ varW = std::weak_ptr<Variable>{variable}, range, loadRange, this ]() {
315 if (auto var = varW.lock()) {
316 if (auto var = varW.lock()) {
316 // 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
317 auto firstVariableInGraph = range == INVALID_RANGE;
318 auto firstVariableInGraph = range == INVALID_RANGE;
318 auto loadedRange = graphRange();
319 auto loadedRange = graphRange();
319 if (impl->m_VariableAutoRangeOnInit) {
320 if (impl->m_VariableAutoRangeOnInit) {
320 loadedRange = firstVariableInGraph ? var->range() : range;
321 loadedRange = firstVariableInGraph ? var->range() : range;
321 }
322 }
322 loadRange(var, loadedRange);
323 loadRange(var, loadedRange);
323 setYRange(var);
324 setYRange(var);
324 }
325 }
325 },
326 },
326 Qt::QueuedConnection);
327 Qt::QueuedConnection);
327
328
328 // Uses delegate to create the qcpplot components according to the variable
329 // Uses delegate to create the qcpplot components according to the variable
329 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
330 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
330
331
331 // Sets graph properties
332 // Sets graph properties
332 impl->m_RenderingDelegate->setGraphProperties(*variable, createdPlottables);
333 impl->m_RenderingDelegate->setGraphProperties(*variable, createdPlottables);
333
334
334 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
335 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
335
336
336 // 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
337 if (variable->dataSeries() != nullptr) {
338 if (variable->dataSeries() != nullptr) {
338 loadRange(variable, range);
339 loadRange(variable, range);
339 }
340 }
340
341
341 emit variableAdded(variable);
342 emit variableAdded(variable);
342 }
343 }
343
344
344 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
345 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
345 {
346 {
346 // Each component associated to the variable :
347 // Each component associated to the variable :
347 // - is removed from qcpplot (which deletes it)
348 // - is removed from qcpplot (which deletes it)
348 // - is no longer referenced in the map
349 // - is no longer referenced in the map
349 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
350 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
350 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
351 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
351 emit variableAboutToBeRemoved(variable);
352 emit variableAboutToBeRemoved(variable);
352
353
353 auto &plottablesMap = variableIt->second;
354 auto &plottablesMap = variableIt->second;
354
355
355 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
356 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
356 plottableIt != plottableEnd;) {
357 plottableIt != plottableEnd;) {
357 ui->widget->removePlottable(plottableIt->second);
358 ui->widget->removePlottable(plottableIt->second);
358 plottableIt = plottablesMap.erase(plottableIt);
359 plottableIt = plottablesMap.erase(plottableIt);
359 }
360 }
360
361
361 impl->m_VariableToPlotMultiMap.erase(variableIt);
362 impl->m_VariableToPlotMultiMap.erase(variableIt);
362 }
363 }
363
364
364 // Updates graph
365 // Updates graph
365 ui->widget->replot();
366 ui->widget->replot();
366 }
367 }
367
368
368 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
369 std::vector<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
369 {
370 {
370 auto variables = QList<std::shared_ptr<Variable> >{};
371 auto variables = std::vector<std::shared_ptr<Variable> >{};
371 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
372 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
372 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
373 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
373 variables << it->first;
374 variables.push_back (it->first);
374 }
375 }
375
376
376 return variables;
377 return variables;
377 }
378 }
378
379
379 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
380 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
380 {
381 {
381 if (!variable) {
382 if (!variable) {
382 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";
383 return;
384 return;
384 }
385 }
385
386
386 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
387 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
387 }
388 }
388
389
389 DateTimeRange VisualizationGraphWidget::graphRange() const noexcept
390 DateTimeRange VisualizationGraphWidget::graphRange() const noexcept
390 {
391 {
391 auto graphRange = ui->widget->xAxis->range();
392 auto graphRange = ui->widget->xAxis->range();
392 return DateTimeRange{graphRange.lower, graphRange.upper};
393 return DateTimeRange{graphRange.lower, graphRange.upper};
393 }
394 }
394
395
395 void VisualizationGraphWidget::setGraphRange(const DateTimeRange &range, bool calibration)
396 void VisualizationGraphWidget::setGraphRange(const DateTimeRange &range, bool calibration)
396 {
397 {
397 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
398 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
398
399
399 if (calibration) {
400 if (calibration) {
400 impl->m_IsCalibration = true;
401 impl->m_IsCalibration = true;
401 }
402 }
402
403
403 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
404 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
404 ui->widget->replot();
405 ui->widget->replot();
405
406
406 if (calibration) {
407 if (calibration) {
407 impl->m_IsCalibration = false;
408 impl->m_IsCalibration = false;
408 }
409 }
409
410
410 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
411 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
411 }
412 }
412
413
413 void VisualizationGraphWidget::setAutoRangeOnVariableInitialization(bool value)
414 void VisualizationGraphWidget::setAutoRangeOnVariableInitialization(bool value)
414 {
415 {
415 impl->m_VariableAutoRangeOnInit = value;
416 impl->m_VariableAutoRangeOnInit = value;
416 }
417 }
417
418
418 QVector<DateTimeRange> VisualizationGraphWidget::selectionZoneRanges() const
419 QVector<DateTimeRange> VisualizationGraphWidget::selectionZoneRanges() const
419 {
420 {
420 QVector<DateTimeRange> ranges;
421 QVector<DateTimeRange> ranges;
421 for (auto zone : impl->m_SelectionZones) {
422 for (auto zone : impl->m_SelectionZones) {
422 ranges << zone->range();
423 ranges << zone->range();
423 }
424 }
424
425
425 return ranges;
426 return ranges;
426 }
427 }
427
428
428 void VisualizationGraphWidget::addSelectionZones(const QVector<DateTimeRange> &ranges)
429 void VisualizationGraphWidget::addSelectionZones(const QVector<DateTimeRange> &ranges)
429 {
430 {
430 for (const auto &range : ranges) {
431 for (const auto &range : ranges) {
431 // note: ownership is transfered to QCustomPlot
432 // note: ownership is transfered to QCustomPlot
432 auto zone = new VisualizationSelectionZoneItem(&plot());
433 auto zone = new VisualizationSelectionZoneItem(&plot());
433 zone->setRange(range.m_TStart, range.m_TEnd);
434 zone->setRange(range.m_TStart, range.m_TEnd);
434 impl->addSelectionZone(zone);
435 impl->addSelectionZone(zone);
435 }
436 }
436
437
437 plot().replot(QCustomPlot::rpQueuedReplot);
438 plot().replot(QCustomPlot::rpQueuedReplot);
438 }
439 }
439
440
440 VisualizationSelectionZoneItem *VisualizationGraphWidget::addSelectionZone(const QString &name,
441 VisualizationSelectionZoneItem *VisualizationGraphWidget::addSelectionZone(const QString &name,
441 const DateTimeRange &range)
442 const DateTimeRange &range)
442 {
443 {
443 // note: ownership is transfered to QCustomPlot
444 // note: ownership is transfered to QCustomPlot
444 auto zone = new VisualizationSelectionZoneItem(&plot());
445 auto zone = new VisualizationSelectionZoneItem(&plot());
445 zone->setName(name);
446 zone->setName(name);
446 zone->setRange(range.m_TStart, range.m_TEnd);
447 zone->setRange(range.m_TStart, range.m_TEnd);
447 impl->addSelectionZone(zone);
448 impl->addSelectionZone(zone);
448
449
449 plot().replot(QCustomPlot::rpQueuedReplot);
450 plot().replot(QCustomPlot::rpQueuedReplot);
450
451
451 return zone;
452 return zone;
452 }
453 }
453
454
454 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
455 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
455 {
456 {
456 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
457 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
457
458
458 if (impl->m_HoveredZone == selectionZone) {
459 if (impl->m_HoveredZone == selectionZone) {
459 impl->m_HoveredZone = nullptr;
460 impl->m_HoveredZone = nullptr;
460 setCursor(Qt::ArrowCursor);
461 setCursor(Qt::ArrowCursor);
461 }
462 }
462
463
463 impl->m_SelectionZones.removeAll(selectionZone);
464 impl->m_SelectionZones.removeAll(selectionZone);
464 plot().removeItem(selectionZone);
465 plot().removeItem(selectionZone);
465 plot().replot(QCustomPlot::rpQueuedReplot);
466 plot().replot(QCustomPlot::rpQueuedReplot);
466 }
467 }
467
468
468 void VisualizationGraphWidget::undoZoom()
469 void VisualizationGraphWidget::undoZoom()
469 {
470 {
470 auto zoom = impl->m_ZoomStack.pop();
471 auto zoom = impl->m_ZoomStack.pop();
471 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
472 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
472 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
473 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
473
474
474 axisX->setRange(zoom.first);
475 axisX->setRange(zoom.first);
475 axisY->setRange(zoom.second);
476 axisY->setRange(zoom.second);
476
477
477 plot().replot(QCustomPlot::rpQueuedReplot);
478 plot().replot(QCustomPlot::rpQueuedReplot);
478 }
479 }
479
480
480 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
481 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
481 {
482 {
482 if (visitor) {
483 if (visitor) {
483 visitor->visit(this);
484 visitor->visit(this);
484 }
485 }
485 else {
486 else {
486 qCCritical(LOG_VisualizationGraphWidget())
487 qCCritical(LOG_VisualizationGraphWidget())
487 << tr("Can't visit widget : the visitor is null");
488 << tr("Can't visit widget : the visitor is null");
488 }
489 }
489 }
490 }
490
491
491 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
492 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
492 {
493 {
493 auto isSpectrogram = [](const auto &variable) {
494 auto isSpectrogram = [](const auto &variable) {
494 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
495 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
495 };
496 };
496
497
497 // - 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
498 // - 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
499 return isSpectrogram(variable)
500 return isSpectrogram(variable)
500 ? impl->m_VariableToPlotMultiMap.empty()
501 ? impl->m_VariableToPlotMultiMap.empty()
501 : std::none_of(
502 : std::none_of(
502 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
503 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
503 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
504 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
504 }
505 }
505
506
506 bool VisualizationGraphWidget::contains(const Variable &variable) const
507 bool VisualizationGraphWidget::contains(const Variable &variable) const
507 {
508 {
508 // Finds the variable among the keys of the map
509 // Finds the variable among the keys of the map
509 auto variablePtr = &variable;
510 auto variablePtr = &variable;
510 auto findVariable
511 auto findVariable
511 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
512 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
512
513
513 auto end = impl->m_VariableToPlotMultiMap.cend();
514 auto end = impl->m_VariableToPlotMultiMap.cend();
514 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
515 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
515 return it != end;
516 return it != end;
516 }
517 }
517
518
518 QString VisualizationGraphWidget::name() const
519 QString VisualizationGraphWidget::name() const
519 {
520 {
520 return impl->m_Name;
521 return impl->m_Name;
521 }
522 }
522
523
523 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
524 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
524 {
525 {
525 auto mimeData = new QMimeData;
526 auto mimeData = new QMimeData;
526
527
527 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
528 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
528 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
529 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
529 && selectionZoneItemUnderCursor) {
530 && selectionZoneItemUnderCursor) {
530 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
531 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
531 selectionZoneItemUnderCursor->range()));
532 selectionZoneItemUnderCursor->range()));
532 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
533 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
533 selectionZoneItemUnderCursor->range()));
534 selectionZoneItemUnderCursor->range()));
534 }
535 }
535 else {
536 else {
536 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
537 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
537
538
538 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
539 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
539 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
540 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
540 }
541 }
541
542
542 return mimeData;
543 return mimeData;
543 }
544 }
544
545
545 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
546 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
546 {
547 {
547 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
548 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
548 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
549 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
549 && selectionZoneItemUnderCursor) {
550 && selectionZoneItemUnderCursor) {
550
551
551 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
552 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
552 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
553 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
553
554
554 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
555 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
555 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
556 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
556 .toSize();
557 .toSize();
557
558
558 auto pixmap = QPixmap(zoneSize);
559 auto pixmap = QPixmap(zoneSize);
559 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
560 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
560
561
561 return pixmap;
562 return pixmap;
562 }
563 }
563
564
564 return QPixmap();
565 return QPixmap();
565 }
566 }
566
567
567 bool VisualizationGraphWidget::isDragAllowed() const
568 bool VisualizationGraphWidget::isDragAllowed() const
568 {
569 {
569 return true;
570 return true;
570 }
571 }
571
572
572 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
573 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
573 {
574 {
574 if (highlighted) {
575 if (highlighted) {
575 plot().setBackground(QBrush(QColor("#BBD5EE")));
576 plot().setBackground(QBrush(QColor("#BBD5EE")));
576 }
577 }
577 else {
578 else {
578 plot().setBackground(QBrush(Qt::white));
579 plot().setBackground(QBrush(Qt::white));
579 }
580 }
580
581
581 plot().update();
582 plot().update();
582 }
583 }
583
584
584 void VisualizationGraphWidget::addVerticalCursor(double time)
585 void VisualizationGraphWidget::addVerticalCursor(double time)
585 {
586 {
586 impl->m_VerticalCursor->setPosition(time);
587 impl->m_VerticalCursor->setPosition(time);
587 impl->m_VerticalCursor->setVisible(true);
588 impl->m_VerticalCursor->setVisible(true);
588
589
589 auto text
590 auto text
590 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
591 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
591 impl->m_VerticalCursor->setLabelText(text);
592 impl->m_VerticalCursor->setLabelText(text);
592 }
593 }
593
594
594 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
595 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
595 {
596 {
596 impl->m_VerticalCursor->setAbsolutePosition(position);
597 impl->m_VerticalCursor->setAbsolutePosition(position);
597 impl->m_VerticalCursor->setVisible(true);
598 impl->m_VerticalCursor->setVisible(true);
598
599
599 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
600 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
600 auto text
601 auto text
601 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
602 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
602 impl->m_VerticalCursor->setLabelText(text);
603 impl->m_VerticalCursor->setLabelText(text);
603 }
604 }
604
605
605 void VisualizationGraphWidget::removeVerticalCursor()
606 void VisualizationGraphWidget::removeVerticalCursor()
606 {
607 {
607 impl->m_VerticalCursor->setVisible(false);
608 impl->m_VerticalCursor->setVisible(false);
608 plot().replot(QCustomPlot::rpQueuedReplot);
609 plot().replot(QCustomPlot::rpQueuedReplot);
609 }
610 }
610
611
611 void VisualizationGraphWidget::addHorizontalCursor(double value)
612 void VisualizationGraphWidget::addHorizontalCursor(double value)
612 {
613 {
613 impl->m_HorizontalCursor->setPosition(value);
614 impl->m_HorizontalCursor->setPosition(value);
614 impl->m_HorizontalCursor->setVisible(true);
615 impl->m_HorizontalCursor->setVisible(true);
615 impl->m_HorizontalCursor->setLabelText(QString::number(value));
616 impl->m_HorizontalCursor->setLabelText(QString::number(value));
616 }
617 }
617
618
618 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
619 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
619 {
620 {
620 impl->m_HorizontalCursor->setAbsolutePosition(position);
621 impl->m_HorizontalCursor->setAbsolutePosition(position);
621 impl->m_HorizontalCursor->setVisible(true);
622 impl->m_HorizontalCursor->setVisible(true);
622
623
623 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
624 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
624 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
625 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
625 }
626 }
626
627
627 void VisualizationGraphWidget::removeHorizontalCursor()
628 void VisualizationGraphWidget::removeHorizontalCursor()
628 {
629 {
629 impl->m_HorizontalCursor->setVisible(false);
630 impl->m_HorizontalCursor->setVisible(false);
630 plot().replot(QCustomPlot::rpQueuedReplot);
631 plot().replot(QCustomPlot::rpQueuedReplot);
631 }
632 }
632
633
633 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
634 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
634 {
635 {
635 Q_UNUSED(event);
636 Q_UNUSED(event);
636
637
637 for (auto i : impl->m_SelectionZones) {
638 for (auto i : impl->m_SelectionZones) {
638 parentVisualizationWidget()->selectionZoneManager().setSelected(i, false);
639 parentVisualizationWidget()->selectionZoneManager().setSelected(i, false);
639 }
640 }
640
641
641 // 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
642 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
643 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
643 emit variableAboutToBeRemoved(variableEntry.first);
644 emit variableAboutToBeRemoved(variableEntry.first);
644 }
645 }
645 }
646 }
646
647
647 void VisualizationGraphWidget::enterEvent(QEvent *event)
648 void VisualizationGraphWidget::enterEvent(QEvent *event)
648 {
649 {
649 Q_UNUSED(event);
650 Q_UNUSED(event);
650 impl->m_RenderingDelegate->showGraphOverlay(true);
651 impl->m_RenderingDelegate->showGraphOverlay(true);
651 }
652 }
652
653
653 void VisualizationGraphWidget::leaveEvent(QEvent *event)
654 void VisualizationGraphWidget::leaveEvent(QEvent *event)
654 {
655 {
655 Q_UNUSED(event);
656 Q_UNUSED(event);
656 impl->m_RenderingDelegate->showGraphOverlay(false);
657 impl->m_RenderingDelegate->showGraphOverlay(false);
657
658
658 if (auto parentZone = parentZoneWidget()) {
659 if (auto parentZone = parentZoneWidget()) {
659 parentZone->notifyMouseLeaveGraph(this);
660 parentZone->notifyMouseLeaveGraph(this);
660 }
661 }
661 else {
662 else {
662 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
663 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
663 }
664 }
664
665
665 if (impl->m_HoveredZone) {
666 if (impl->m_HoveredZone) {
666 impl->m_HoveredZone->setHovered(false);
667 impl->m_HoveredZone->setHovered(false);
667 impl->m_HoveredZone = nullptr;
668 impl->m_HoveredZone = nullptr;
668 }
669 }
669 }
670 }
670
671
671 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
672 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
672 {
673 {
673 return *ui->widget;
674 return *ui->widget;
674 }
675 }
675
676
676 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
677 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
677 {
678 {
678 QMenu graphMenu{};
679 QMenu graphMenu{};
679
680
680 // Iterates on variables (unique keys)
681 // Iterates on variables (unique keys)
681 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
682 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
682 end = impl->m_VariableToPlotMultiMap.cend();
683 end = impl->m_VariableToPlotMultiMap.cend();
683 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
684 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
684 // 'Remove variable' action
685 // 'Remove variable' action
685 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
686 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
686 [ this, var = it->first ]() { removeVariable(var); });
687 [ this, var = it->first ]() { removeVariable(var); });
687 }
688 }
688
689
689 if (!impl->m_ZoomStack.isEmpty()) {
690 if (!impl->m_ZoomStack.isEmpty()) {
690 if (!graphMenu.isEmpty()) {
691 if (!graphMenu.isEmpty()) {
691 graphMenu.addSeparator();
692 graphMenu.addSeparator();
692 }
693 }
693
694
694 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
695 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
695 }
696 }
696
697
697 // Selection Zone Actions
698 // Selection Zone Actions
698 auto selectionZoneItem = impl->selectionZoneAt(pos, plot());
699 auto selectionZoneItem = impl->selectionZoneAt(pos, plot());
699 if (selectionZoneItem) {
700 if (selectionZoneItem) {
700 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
701 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
701 selectedItems.removeAll(selectionZoneItem);
702 selectedItems.removeAll(selectionZoneItem);
702 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
703 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
703
704
704 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
705 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
705 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
706 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
706 graphMenu.addSeparator();
707 graphMenu.addSeparator();
707 }
708 }
708
709
709 QHash<QString, QMenu *> subMenus;
710 QHash<QString, QMenu *> subMenus;
710 QHash<QString, bool> subMenusEnabled;
711 QHash<QString, bool> subMenusEnabled;
711 QHash<QString, FilteringAction *> filteredMenu;
712 QHash<QString, FilteringAction *> filteredMenu;
712
713
713 for (auto zoneAction : zoneActions) {
714 for (auto zoneAction : zoneActions) {
714
715
715 auto isEnabled = zoneAction->isEnabled(selectedItems);
716 auto isEnabled = zoneAction->isEnabled(selectedItems);
716
717
717 auto menu = &graphMenu;
718 auto menu = &graphMenu;
718 QString menuPath;
719 QString menuPath;
719 for (auto subMenuName : zoneAction->subMenuList()) {
720 for (auto subMenuName : zoneAction->subMenuList()) {
720 menuPath += '/';
721 menuPath += '/';
721 menuPath += subMenuName;
722 menuPath += subMenuName;
722
723
723 if (!subMenus.contains(menuPath)) {
724 if (!subMenus.contains(menuPath)) {
724 menu = menu->addMenu(subMenuName);
725 menu = menu->addMenu(subMenuName);
725 subMenus[menuPath] = menu;
726 subMenus[menuPath] = menu;
726 subMenusEnabled[menuPath] = isEnabled;
727 subMenusEnabled[menuPath] = isEnabled;
727 }
728 }
728 else {
729 else {
729 menu = subMenus.value(menuPath);
730 menu = subMenus.value(menuPath);
730 if (isEnabled) {
731 if (isEnabled) {
731 // 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
732 subMenusEnabled[menuPath] = true;
733 subMenusEnabled[menuPath] = true;
733 }
734 }
734 }
735 }
735 }
736 }
736
737
737 FilteringAction *filterAction = nullptr;
738 FilteringAction *filterAction = nullptr;
738 if (sqpApp->actionsGuiController().isMenuFiltered(zoneAction->subMenuList())) {
739 if (sqpApp->actionsGuiController().isMenuFiltered(zoneAction->subMenuList())) {
739 filterAction = filteredMenu.value(menuPath);
740 filterAction = filteredMenu.value(menuPath);
740 if (!filterAction) {
741 if (!filterAction) {
741 filterAction = new FilteringAction{this};
742 filterAction = new FilteringAction{this};
742 filteredMenu[menuPath] = filterAction;
743 filteredMenu[menuPath] = filterAction;
743 menu->addAction(filterAction);
744 menu->addAction(filterAction);
744 }
745 }
745 }
746 }
746
747
747 auto action = menu->addAction(zoneAction->name());
748 auto action = menu->addAction(zoneAction->name());
748 action->setEnabled(isEnabled);
749 action->setEnabled(isEnabled);
749 action->setShortcut(zoneAction->displayedShortcut());
750 action->setShortcut(zoneAction->displayedShortcut());
750 QObject::connect(action, &QAction::triggered,
751 QObject::connect(action, &QAction::triggered,
751 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
752 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
752
753
753 if (filterAction && zoneAction->isFilteringAllowed()) {
754 if (filterAction && zoneAction->isFilteringAllowed()) {
754 filterAction->addActionToFilter(action);
755 filterAction->addActionToFilter(action);
755 }
756 }
756 }
757 }
757
758
758 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) {
759 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) {
759 it.value()->setEnabled(subMenusEnabled[it.key()]);
760 it.value()->setEnabled(subMenusEnabled[it.key()]);
760 }
761 }
761 }
762 }
762
763
763 if (!graphMenu.isEmpty()) {
764 if (!graphMenu.isEmpty()) {
764 graphMenu.exec(QCursor::pos());
765 graphMenu.exec(QCursor::pos());
765 }
766 }
766 }
767 }
767
768
768 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
769 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
769 {
770 {
770 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
771 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
771 << QThread::currentThread()->objectName() << "DoAcqui"
772 << QThread::currentThread()->objectName() << "DoAcqui"
772 << impl->m_Flags.testFlag(GraphFlag::EnableAcquisition);
773 << impl->m_Flags.testFlag(GraphFlag::EnableAcquisition);
773
774
774 auto graphRange = DateTimeRange{t1.lower, t1.upper};
775 auto graphRange = DateTimeRange{t1.lower, t1.upper};
775 auto oldGraphRange = DateTimeRange{t2.lower, t2.upper};
776 auto oldGraphRange = DateTimeRange{t2.lower, t2.upper};
776
777
777 if (impl->m_Flags.testFlag(GraphFlag::EnableAcquisition)) {
778 if (impl->m_Flags.testFlag(GraphFlag::EnableAcquisition)) {
778 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
779 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
779
780
780 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
781 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
781 end = impl->m_VariableToPlotMultiMap.end();
782 end = impl->m_VariableToPlotMultiMap.end();
782 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
783 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
783 variableUnderGraphVector.push_back(it->first);
784 variableUnderGraphVector.push_back(it->first);
784 }
785 }
785 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
786 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
786 !impl->m_IsCalibration);
787 !impl->m_IsCalibration);
787 }
788 }
788
789
789 if (impl->m_Flags.testFlag(GraphFlag::EnableSynchronization) && !impl->m_IsCalibration) {
790 if (impl->m_Flags.testFlag(GraphFlag::EnableSynchronization) && !impl->m_IsCalibration) {
790 qCDebug(LOG_VisualizationGraphWidget())
791 qCDebug(LOG_VisualizationGraphWidget())
791 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
792 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
792 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
793 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
793 emit synchronize(graphRange, oldGraphRange);
794 emit synchronize(graphRange, oldGraphRange);
794 }
795 }
795
796
796 auto pos = mapFromGlobal(QCursor::pos());
797 auto pos = mapFromGlobal(QCursor::pos());
797 auto axisPos = impl->posToAxisPos(pos, plot());
798 auto axisPos = impl->posToAxisPos(pos, plot());
798 if (auto parentZone = parentZoneWidget()) {
799 if (auto parentZone = parentZoneWidget()) {
799 if (impl->pointIsInAxisRect(axisPos, plot())) {
800 if (impl->pointIsInAxisRect(axisPos, plot())) {
800 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
801 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
801 }
802 }
802 else {
803 else {
803 parentZone->notifyMouseLeaveGraph(this);
804 parentZone->notifyMouseLeaveGraph(this);
804 }
805 }
805 }
806 }
806 else {
807 else {
807 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
808 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
808 }
809 }
809
810
810 // Quits calibration
811 // Quits calibration
811 impl->m_IsCalibration = false;
812 impl->m_IsCalibration = false;
812 }
813 }
813
814
814 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
815 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
815 {
816 {
816 impl->m_RenderingDelegate->onMouseDoubleClick(event);
817 impl->m_RenderingDelegate->onMouseDoubleClick(event);
817 }
818 }
818
819
819 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
820 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
820 {
821 {
821 // Handles plot rendering when mouse is moving
822 // Handles plot rendering when mouse is moving
822 impl->m_RenderingDelegate->onMouseMove(event);
823 impl->m_RenderingDelegate->onMouseMove(event);
823
824
824 auto axisPos = impl->posToAxisPos(event->pos(), plot());
825 auto axisPos = impl->posToAxisPos(event->pos(), plot());
825
826
826 // Zoom box and zone drawing
827 // Zoom box and zone drawing
827 if (impl->m_DrawingZoomRect) {
828 if (impl->m_DrawingZoomRect) {
828 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
829 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
829 }
830 }
830 else if (impl->m_DrawingZone) {
831 else if (impl->m_DrawingZone) {
831 impl->m_DrawingZone->setEnd(axisPos.x());
832 impl->m_DrawingZone->setEnd(axisPos.x());
832 }
833 }
833
834
834 // Cursor
835 // Cursor
835 if (auto parentZone = parentZoneWidget()) {
836 if (auto parentZone = parentZoneWidget()) {
836 if (impl->pointIsInAxisRect(axisPos, plot())) {
837 if (impl->pointIsInAxisRect(axisPos, plot())) {
837 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
838 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
838 }
839 }
839 else {
840 else {
840 parentZone->notifyMouseLeaveGraph(this);
841 parentZone->notifyMouseLeaveGraph(this);
841 }
842 }
842 }
843 }
843 else {
844 else {
844 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
845 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
845 }
846 }
846
847
847 // Search for the selection zone under the mouse
848 // Search for the selection zone under the mouse
848 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
849 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
849 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
850 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
850 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
851 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
851
852
852 // Sets the appropriate cursor shape
853 // Sets the appropriate cursor shape
853 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
854 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
854 setCursor(cursorShape);
855 setCursor(cursorShape);
855
856
856 // Manages the hovered zone
857 // Manages the hovered zone
857 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
858 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
858 if (impl->m_HoveredZone) {
859 if (impl->m_HoveredZone) {
859 impl->m_HoveredZone->setHovered(false);
860 impl->m_HoveredZone->setHovered(false);
860 }
861 }
861 selectionZoneItemUnderCursor->setHovered(true);
862 selectionZoneItemUnderCursor->setHovered(true);
862 impl->m_HoveredZone = selectionZoneItemUnderCursor;
863 impl->m_HoveredZone = selectionZoneItemUnderCursor;
863 plot().replot(QCustomPlot::rpQueuedReplot);
864 plot().replot(QCustomPlot::rpQueuedReplot);
864 }
865 }
865 }
866 }
866 else {
867 else {
867 // 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"
868 if (impl->m_HoveredZone) {
869 if (impl->m_HoveredZone) {
869 impl->m_HoveredZone->setHovered(false);
870 impl->m_HoveredZone->setHovered(false);
870 impl->m_HoveredZone = nullptr;
871 impl->m_HoveredZone = nullptr;
871 }
872 }
872
873
873 setCursor(Qt::ArrowCursor);
874 setCursor(Qt::ArrowCursor);
874 }
875 }
875
876
876 impl->m_HasMovedMouse = true;
877 impl->m_HasMovedMouse = true;
877 VisualizationDragWidget::mouseMoveEvent(event);
878 VisualizationDragWidget::mouseMoveEvent(event);
878 }
879 }
879
880
880 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
881 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
881 {
882 {
882 // Processes event only if the wheel occurs on axis rect
883 // Processes event only if the wheel occurs on axis rect
883 if (!dynamic_cast<QCPAxisRect *>(ui->widget->layoutElementAt(event->posF()))) {
884 if (!dynamic_cast<QCPAxisRect *>(ui->widget->layoutElementAt(event->posF()))) {
884 return;
885 return;
885 }
886 }
886
887
887 auto value = event->angleDelta().x() + event->angleDelta().y();
888 auto value = event->angleDelta().x() + event->angleDelta().y();
888 if (value != 0) {
889 if (value != 0) {
889
890
890 auto direction = value > 0 ? 1.0 : -1.0;
891 auto direction = value > 0 ? 1.0 : -1.0;
891 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
892 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
892 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
893 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
893 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
894 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
894
895
895 auto zoomOrientations = QFlags<Qt::Orientation>{};
896 auto zoomOrientations = QFlags<Qt::Orientation>{};
896 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
897 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
897 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
898 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
898
899
899 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
900 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
900
901
901 if (!isZoomX && !isZoomY) {
902 if (!isZoomX && !isZoomY) {
902 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
903 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
903 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
904 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
904
905
905 axis->setRange(axis->range() + diff);
906 axis->setRange(axis->range() + diff);
906
907
907 if (plot().noAntialiasingOnDrag()) {
908 if (plot().noAntialiasingOnDrag()) {
908 plot().setNotAntialiasedElements(QCP::aeAll);
909 plot().setNotAntialiasedElements(QCP::aeAll);
909 }
910 }
910
911
911 plot().replot(QCustomPlot::rpQueuedReplot);
912 plot().replot(QCustomPlot::rpQueuedReplot);
912 }
913 }
913 }
914 }
914 }
915 }
915
916
916 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
917 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
917 {
918 {
918 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
919 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
919 auto isSelectionZoneMode
920 auto isSelectionZoneMode
920 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
921 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
921 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
922 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
922
923
923 if (!isDragDropClick && isLeftClick) {
924 if (!isDragDropClick && isLeftClick) {
924 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
925 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
925 // Starts a zoom box
926 // Starts a zoom box
926 impl->startDrawingRect(event->pos(), plot());
927 impl->startDrawingRect(event->pos(), plot());
927 }
928 }
928 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
929 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
929 // Starts a new selection zone
930 // Starts a new selection zone
930 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
931 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
931 if (!zoneAtPos) {
932 if (!zoneAtPos) {
932 impl->startDrawingZone(event->pos(), this);
933 impl->startDrawingZone(event->pos(), this);
933 }
934 }
934 }
935 }
935 }
936 }
936
937
937 // Allows mouse panning only in default mode
938 // Allows mouse panning only in default mode
938 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
939 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
939 == SqpApplication::PlotsInteractionMode::None
940 == SqpApplication::PlotsInteractionMode::None
940 && !isDragDropClick);
941 && !isDragDropClick);
941
942
942 // Allows zone edition only in selection zone mode without drag&drop
943 // Allows zone edition only in selection zone mode without drag&drop
943 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
944 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
944
945
945 // Selection / Deselection
946 // Selection / Deselection
946 if (isSelectionZoneMode) {
947 if (isSelectionZoneMode) {
947 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
948 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
948 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
949 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
949
950
950
951
951 if (selectionZoneItemUnderCursor && !selectionZoneItemUnderCursor->selected()
952 if (selectionZoneItemUnderCursor && !selectionZoneItemUnderCursor->selected()
952 && !isMultiSelectionClick) {
953 && !isMultiSelectionClick) {
953 parentVisualizationWidget()->selectionZoneManager().select(
954 parentVisualizationWidget()->selectionZoneManager().select(
954 {selectionZoneItemUnderCursor});
955 {selectionZoneItemUnderCursor});
955 }
956 }
956 else if (!selectionZoneItemUnderCursor && !isMultiSelectionClick && isLeftClick) {
957 else if (!selectionZoneItemUnderCursor && !isMultiSelectionClick && isLeftClick) {
957 parentVisualizationWidget()->selectionZoneManager().clearSelection();
958 parentVisualizationWidget()->selectionZoneManager().clearSelection();
958 }
959 }
959 else {
960 else {
960 // No selection change
961 // No selection change
961 }
962 }
962
963
963 if (selectionZoneItemUnderCursor && isLeftClick) {
964 if (selectionZoneItemUnderCursor && isLeftClick) {
964 selectionZoneItemUnderCursor->setAssociatedEditedZones(
965 selectionZoneItemUnderCursor->setAssociatedEditedZones(
965 parentVisualizationWidget()->selectionZoneManager().selectedItems());
966 parentVisualizationWidget()->selectionZoneManager().selectedItems());
966 }
967 }
967 }
968 }
968
969
969
970
970 impl->m_HasMovedMouse = false;
971 impl->m_HasMovedMouse = false;
971 VisualizationDragWidget::mousePressEvent(event);
972 VisualizationDragWidget::mousePressEvent(event);
972 }
973 }
973
974
974 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
975 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
975 {
976 {
976 if (impl->m_DrawingZoomRect) {
977 if (impl->m_DrawingZoomRect) {
977
978
978 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
979 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
979 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
980 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
980
981
981 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
982 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
982 impl->m_DrawingZoomRect->bottomRight->coords().x()};
983 impl->m_DrawingZoomRect->bottomRight->coords().x()};
983
984
984 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
985 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
985 impl->m_DrawingZoomRect->bottomRight->coords().y()};
986 impl->m_DrawingZoomRect->bottomRight->coords().y()};
986
987
987 impl->removeDrawingRect(plot());
988 impl->removeDrawingRect(plot());
988
989
989 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)
990 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
991 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
991 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
992 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
992 axisX->setRange(newAxisXRange);
993 axisX->setRange(newAxisXRange);
993 axisY->setRange(newAxisYRange);
994 axisY->setRange(newAxisYRange);
994
995
995 plot().replot(QCustomPlot::rpQueuedReplot);
996 plot().replot(QCustomPlot::rpQueuedReplot);
996 }
997 }
997 }
998 }
998
999
999 impl->endDrawingZone(this);
1000 impl->endDrawingZone(this);
1000
1001
1001 // Selection / Deselection
1002 // Selection / Deselection
1002 auto isSelectionZoneMode
1003 auto isSelectionZoneMode
1003 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
1004 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
1004 if (isSelectionZoneMode) {
1005 if (isSelectionZoneMode) {
1005 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
1006 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
1006 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
1007 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
1007 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton
1008 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton
1008 && !impl->m_HasMovedMouse) {
1009 && !impl->m_HasMovedMouse) {
1009
1010
1010 auto zonesUnderCursor = impl->selectionZonesAt(event->pos(), plot());
1011 auto zonesUnderCursor = impl->selectionZonesAt(event->pos(), plot());
1011 if (zonesUnderCursor.count() > 1) {
1012 if (zonesUnderCursor.count() > 1) {
1012 // There are multiple zones under the mouse.
1013 // There are multiple zones under the mouse.
1013 // Performs the selection with a selection dialog.
1014 // Performs the selection with a selection dialog.
1014 VisualizationMultiZoneSelectionDialog dialog{this};
1015 VisualizationMultiZoneSelectionDialog dialog{this};
1015 dialog.setZones(zonesUnderCursor);
1016 dialog.setZones(zonesUnderCursor);
1016 dialog.move(mapToGlobal(event->pos() - QPoint(dialog.width() / 2, 20)));
1017 dialog.move(mapToGlobal(event->pos() - QPoint(dialog.width() / 2, 20)));
1017 dialog.activateWindow();
1018 dialog.activateWindow();
1018 dialog.raise();
1019 dialog.raise();
1019 if (dialog.exec() == QDialog::Accepted) {
1020 if (dialog.exec() == QDialog::Accepted) {
1020 auto selection = dialog.selectedZones();
1021 auto selection = dialog.selectedZones();
1021
1022
1022 if (!isMultiSelectionClick) {
1023 if (!isMultiSelectionClick) {
1023 parentVisualizationWidget()->selectionZoneManager().clearSelection();
1024 parentVisualizationWidget()->selectionZoneManager().clearSelection();
1024 }
1025 }
1025
1026
1026 for (auto it = selection.cbegin(); it != selection.cend(); ++it) {
1027 for (auto it = selection.cbegin(); it != selection.cend(); ++it) {
1027 auto zone = it.key();
1028 auto zone = it.key();
1028 auto isSelected = it.value();
1029 auto isSelected = it.value();
1029 parentVisualizationWidget()->selectionZoneManager().setSelected(zone,
1030 parentVisualizationWidget()->selectionZoneManager().setSelected(zone,
1030 isSelected);
1031 isSelected);
1031
1032
1032 if (isSelected) {
1033 if (isSelected) {
1033 // 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
1034 impl->moveSelectionZoneOnTop(zone, plot());
1035 impl->moveSelectionZoneOnTop(zone, plot());
1035 }
1036 }
1036 }
1037 }
1037 }
1038 }
1038 }
1039 }
1039 else {
1040 else {
1040 if (!isMultiSelectionClick) {
1041 if (!isMultiSelectionClick) {
1041 parentVisualizationWidget()->selectionZoneManager().select(
1042 parentVisualizationWidget()->selectionZoneManager().select(
1042 {selectionZoneItemUnderCursor});
1043 {selectionZoneItemUnderCursor});
1043 impl->moveSelectionZoneOnTop(selectionZoneItemUnderCursor, plot());
1044 impl->moveSelectionZoneOnTop(selectionZoneItemUnderCursor, plot());
1044 }
1045 }
1045 else {
1046 else {
1046 parentVisualizationWidget()->selectionZoneManager().setSelected(
1047 parentVisualizationWidget()->selectionZoneManager().setSelected(
1047 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
1048 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
1048 || event->button() == Qt::RightButton);
1049 || event->button() == Qt::RightButton);
1049 }
1050 }
1050 }
1051 }
1051 }
1052 }
1052 else {
1053 else {
1053 // No selection change
1054 // No selection change
1054 }
1055 }
1055 }
1056 }
1056 }
1057 }
1057
1058
1058 void VisualizationGraphWidget::onDataCacheVariableUpdated()
1059 void VisualizationGraphWidget::onDataCacheVariableUpdated()
1059 {
1060 {
1060 auto graphRange = ui->widget->xAxis->range();
1061 auto graphRange = ui->widget->xAxis->range();
1061 auto dateTime = DateTimeRange{graphRange.lower, graphRange.upper};
1062 auto dateTime = DateTimeRange{graphRange.lower, graphRange.upper};
1062
1063
1063 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
1064 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
1064 auto variable = variableEntry.first;
1065 auto variable = variableEntry.first;
1065 qCDebug(LOG_VisualizationGraphWidget())
1066 qCDebug(LOG_VisualizationGraphWidget())
1066 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
1067 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
1067 qCDebug(LOG_VisualizationGraphWidget())
1068 qCDebug(LOG_VisualizationGraphWidget())
1068 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
1069 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
1069 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
1070 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
1070 impl->updateData(variableEntry.second, variable, variable->range());
1071 impl->updateData(variableEntry.second, variable, variable->range());
1071 }
1072 }
1072 }
1073 }
1073 }
1074 }
1074
1075
1075 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
1076 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
1076 const DateTimeRange &range)
1077 const DateTimeRange &range)
1077 {
1078 {
1078 auto it = impl->m_VariableToPlotMultiMap.find(variable);
1079 auto it = impl->m_VariableToPlotMultiMap.find(variable);
1079 if (it != impl->m_VariableToPlotMultiMap.end()) {
1080 if (it != impl->m_VariableToPlotMultiMap.end()) {
1080 impl->updateData(it->second, variable, range);
1081 impl->updateData(it->second, variable, range);
1081 }
1082 }
1082 }
1083 }
@@ -1,389 +1,389
1 #include "Visualization/VisualizationTabWidget.h"
1 #include "Visualization/VisualizationTabWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "ui_VisualizationTabWidget.h"
3 #include "ui_VisualizationTabWidget.h"
4
4
5 #include "Visualization/VisualizationGraphWidget.h"
5 #include "Visualization/VisualizationGraphWidget.h"
6 #include "Visualization/VisualizationZoneWidget.h"
6 #include "Visualization/VisualizationZoneWidget.h"
7
7
8 #include "Visualization/MacScrollBarStyle.h"
8 #include "Visualization/MacScrollBarStyle.h"
9
9
10 #include "DataSource/DataSourceController.h"
10 #include "DataSource/DataSourceController.h"
11 #include "Variable/VariableController.h"
11 #include "Variable/VariableController2.h"
12
12
13 #include "Common/MimeTypesDef.h"
13 #include "Common/MimeTypesDef.h"
14
14
15 #include "DragAndDrop/DragDropGuiController.h"
15 #include "DragAndDrop/DragDropGuiController.h"
16 #include "SqpApplication.h"
16 #include "SqpApplication.h"
17
17
18 Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget")
18 Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget")
19
19
20 namespace {
20 namespace {
21
21
22 /**
22 /**
23 * Applies a function to all zones of the tab represented by its layout
23 * Applies a function to all zones of the tab represented by its layout
24 * @param layout the layout that contains zones
24 * @param layout the layout that contains zones
25 * @param fun the function to apply to each zone
25 * @param fun the function to apply to each zone
26 */
26 */
27 template <typename Fun>
27 template <typename Fun>
28 void processZones(QLayout &layout, Fun fun)
28 void processZones(QLayout &layout, Fun fun)
29 {
29 {
30 for (auto i = 0; i < layout.count(); ++i) {
30 for (auto i = 0; i < layout.count(); ++i) {
31 if (auto item = layout.itemAt(i)) {
31 if (auto item = layout.itemAt(i)) {
32 if (auto visualizationZoneWidget
32 if (auto visualizationZoneWidget
33 = qobject_cast<VisualizationZoneWidget *>(item->widget())) {
33 = qobject_cast<VisualizationZoneWidget *>(item->widget())) {
34 fun(*visualizationZoneWidget);
34 fun(*visualizationZoneWidget);
35 }
35 }
36 }
36 }
37 }
37 }
38 }
38 }
39
39
40 /// Generates a default name for a new zone, according to the number of zones already displayed in
40 /// Generates a default name for a new zone, according to the number of zones already displayed in
41 /// the tab
41 /// the tab
42 QString defaultZoneName(QLayout &layout)
42 QString defaultZoneName(QLayout &layout)
43 {
43 {
44 QSet<QString> existingNames;
44 QSet<QString> existingNames;
45 processZones(layout,
45 processZones(layout,
46 [&existingNames](auto &zoneWidget) { existingNames.insert(zoneWidget.name()); });
46 [&existingNames](auto &zoneWidget) { existingNames.insert(zoneWidget.name()); });
47
47
48 int zoneNum = 1;
48 int zoneNum = 1;
49 QString name;
49 QString name;
50 do {
50 do {
51 name = QObject::tr("Zone ").append(QString::number(zoneNum));
51 name = QObject::tr("Zone ").append(QString::number(zoneNum));
52 ++zoneNum;
52 ++zoneNum;
53 } while (existingNames.contains(name));
53 } while (existingNames.contains(name));
54
54
55 return name;
55 return name;
56 }
56 }
57
57
58 } // namespace
58 } // namespace
59
59
60 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
60 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
61 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
61 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
62
62
63 QString m_Name;
63 QString m_Name;
64
64
65 #ifdef Q_OS_MAC
65 #ifdef Q_OS_MAC
66 std::unique_ptr<MacScrollBarStyle> m_MacScrollBarStyle = std::make_unique<MacScrollBarStyle>();
66 std::unique_ptr<MacScrollBarStyle> m_MacScrollBarStyle = std::make_unique<MacScrollBarStyle>();
67 #endif
67 #endif
68
68
69 void dropGraph(int index, VisualizationTabWidget *tabWidget);
69 void dropGraph(int index, VisualizationTabWidget *tabWidget);
70 void dropZone(int index, VisualizationTabWidget *tabWidget);
70 void dropZone(int index, VisualizationTabWidget *tabWidget);
71 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
71 void dropVariables(const std::vector<std::shared_ptr<Variable> > &variables, int index,
72 VisualizationTabWidget *tabWidget);
72 VisualizationTabWidget *tabWidget);
73 void dropProducts(const QVariantList &productsMetaData, int index,
73 void dropProducts(const QVariantList &productsMetaData, int index,
74 VisualizationTabWidget *tabWidget);
74 VisualizationTabWidget *tabWidget);
75 };
75 };
76
76
77 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
77 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
78 : QWidget{parent},
78 : QWidget{parent},
79 ui{new Ui::VisualizationTabWidget},
79 ui{new Ui::VisualizationTabWidget},
80 impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)}
80 impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)}
81 {
81 {
82 ui->setupUi(this);
82 ui->setupUi(this);
83
83
84 #ifdef Q_OS_MAC
84 #ifdef Q_OS_MAC
85 impl->m_MacScrollBarStyle->selfInstallOn(ui->scrollArea, true);
85 impl->m_MacScrollBarStyle->selfInstallOn(ui->scrollArea, true);
86 #endif
86 #endif
87
87
88 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Zone, "Zone");
88 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Zone, "Zone");
89 ui->dragDropContainer->layout()->setContentsMargins(0, 0, 0, 12);
89 ui->dragDropContainer->layout()->setContentsMargins(0, 0, 0, 12);
90 ui->dragDropContainer->layout()->setSpacing(0);
90 ui->dragDropContainer->layout()->setSpacing(0);
91 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
91 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
92 VisualizationDragDropContainer::DropBehavior::Inserted);
92 VisualizationDragDropContainer::DropBehavior::Inserted);
93 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
93 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
94 VisualizationDragDropContainer::DropBehavior::Inserted);
94 VisualizationDragDropContainer::DropBehavior::Inserted);
95 ui->dragDropContainer->setMimeType(MIME_TYPE_VARIABLE_LIST,
95 ui->dragDropContainer->setMimeType(MIME_TYPE_VARIABLE_LIST,
96 VisualizationDragDropContainer::DropBehavior::Inserted);
96 VisualizationDragDropContainer::DropBehavior::Inserted);
97 ui->dragDropContainer->setMimeType(MIME_TYPE_PRODUCT_LIST,
97 ui->dragDropContainer->setMimeType(MIME_TYPE_PRODUCT_LIST,
98 VisualizationDragDropContainer::DropBehavior::Inserted);
98 VisualizationDragDropContainer::DropBehavior::Inserted);
99
99
100 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
100 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
101 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(mimeData,
101 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(mimeData,
102 ui->dragDropContainer);
102 ui->dragDropContainer);
103 });
103 });
104
104
105 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
105 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
106 &VisualizationTabWidget::dropMimeData);
106 &VisualizationTabWidget::dropMimeData);
107
107
108 sqpApp->dragDropGuiController().addDragDropScrollArea(ui->scrollArea);
108 sqpApp->dragDropGuiController().addDragDropScrollArea(ui->scrollArea);
109
109
110 // Widget is deleted when closed
110 // Widget is deleted when closed
111 setAttribute(Qt::WA_DeleteOnClose);
111 setAttribute(Qt::WA_DeleteOnClose);
112 }
112 }
113
113
114 VisualizationTabWidget::~VisualizationTabWidget()
114 VisualizationTabWidget::~VisualizationTabWidget()
115 {
115 {
116 sqpApp->dragDropGuiController().removeDragDropScrollArea(ui->scrollArea);
116 sqpApp->dragDropGuiController().removeDragDropScrollArea(ui->scrollArea);
117 delete ui;
117 delete ui;
118 }
118 }
119
119
120 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
120 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
121 {
121 {
122 ui->dragDropContainer->addDragWidget(zoneWidget);
122 ui->dragDropContainer->addDragWidget(zoneWidget);
123 }
123 }
124
124
125 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget)
125 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget)
126 {
126 {
127 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
127 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
128 }
128 }
129
129
130 QStringList VisualizationTabWidget::availableZoneWidgets() const
130 QStringList VisualizationTabWidget::availableZoneWidgets() const
131 {
131 {
132 QStringList zones;
132 QStringList zones;
133 processZones(tabLayout(),
133 processZones(tabLayout(),
134 [&zones](VisualizationZoneWidget &zoneWidget) { zones << zoneWidget.name(); });
134 [&zones](VisualizationZoneWidget &zoneWidget) { zones << zoneWidget.name(); });
135
135
136 return zones;
136 return zones;
137 }
137 }
138
138
139 VisualizationZoneWidget *VisualizationTabWidget::getZoneWithName(const QString &zoneName)
139 VisualizationZoneWidget *VisualizationTabWidget::getZoneWithName(const QString &zoneName)
140 {
140 {
141 VisualizationZoneWidget *result = nullptr;
141 VisualizationZoneWidget *result = nullptr;
142 processZones(tabLayout(), [&zoneName, &result](VisualizationZoneWidget &zoneWidget) {
142 processZones(tabLayout(), [&zoneName, &result](VisualizationZoneWidget &zoneWidget) {
143 if (!result && zoneWidget.name() == zoneName) {
143 if (!result && zoneWidget.name() == zoneName) {
144 result = &zoneWidget;
144 result = &zoneWidget;
145 }
145 }
146 });
146 });
147
147
148 return result;
148 return result;
149 }
149 }
150
150
151 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
151 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
152 {
152 {
153 return createZone({variable}, -1);
153 return createZone({variable}, -1);
154 }
154 }
155
155
156 VisualizationZoneWidget *
156 VisualizationZoneWidget *
157 VisualizationTabWidget::createZone(const QList<std::shared_ptr<Variable> > &variables, int index)
157 VisualizationTabWidget::createZone(const std::vector<std::shared_ptr<Variable> > &variables, int index)
158 {
158 {
159 auto zoneWidget = createEmptyZone(index);
159 auto zoneWidget = createEmptyZone(index);
160
160
161 // Creates a new graph into the zone
161 // Creates a new graph into the zone
162 zoneWidget->createGraph(variables, index);
162 zoneWidget->createGraph(variables, index);
163
163
164 return zoneWidget;
164 return zoneWidget;
165 }
165 }
166
166
167 VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index)
167 VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index)
168 {
168 {
169 auto zoneWidget
169 auto zoneWidget
170 = new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this};
170 = new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this};
171 this->insertZone(index, zoneWidget);
171 this->insertZone(index, zoneWidget);
172
172
173 return zoneWidget;
173 return zoneWidget;
174 }
174 }
175
175
176 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
176 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
177 {
177 {
178 if (visitor) {
178 if (visitor) {
179 visitor->visitEnter(this);
179 visitor->visitEnter(this);
180
180
181 // Apply visitor to zone children: widgets different from zones are not visited (no action)
181 // Apply visitor to zone children: widgets different from zones are not visited (no action)
182 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
182 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
183 zoneWidget.accept(visitor);
183 zoneWidget.accept(visitor);
184 });
184 });
185
185
186 visitor->visitLeave(this);
186 visitor->visitLeave(this);
187 }
187 }
188 else {
188 else {
189 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
189 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
190 }
190 }
191 }
191 }
192
192
193 bool VisualizationTabWidget::canDrop(const Variable &variable) const
193 bool VisualizationTabWidget::canDrop(const Variable &variable) const
194 {
194 {
195 // A tab can always accomodate a variable
195 // A tab can always accomodate a variable
196 Q_UNUSED(variable);
196 Q_UNUSED(variable);
197 return true;
197 return true;
198 }
198 }
199
199
200 bool VisualizationTabWidget::contains(const Variable &variable) const
200 bool VisualizationTabWidget::contains(const Variable &variable) const
201 {
201 {
202 Q_UNUSED(variable);
202 Q_UNUSED(variable);
203 return false;
203 return false;
204 }
204 }
205
205
206 QString VisualizationTabWidget::name() const
206 QString VisualizationTabWidget::name() const
207 {
207 {
208 return impl->m_Name;
208 return impl->m_Name;
209 }
209 }
210
210
211 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
211 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
212 {
212 {
213 // Closes zones in the tab
213 // Closes zones in the tab
214 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
214 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
215
215
216 QWidget::closeEvent(event);
216 QWidget::closeEvent(event);
217 }
217 }
218
218
219 QLayout &VisualizationTabWidget::tabLayout() const noexcept
219 QLayout &VisualizationTabWidget::tabLayout() const noexcept
220 {
220 {
221 return *ui->dragDropContainer->layout();
221 return *ui->dragDropContainer->layout();
222 }
222 }
223
223
224 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
224 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
225 {
225 {
226 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
226 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
227 impl->dropGraph(index, this);
227 impl->dropGraph(index, this);
228 }
228 }
229 else if (mimeData->hasFormat(MIME_TYPE_ZONE)) {
229 else if (mimeData->hasFormat(MIME_TYPE_ZONE)) {
230 impl->dropZone(index, this);
230 impl->dropZone(index, this);
231 }
231 }
232 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
232 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
233 auto variables = sqpApp->variableController().variablesForMimeData(
233 auto variables = sqpApp->variableController().variables(
234 mimeData->data(MIME_TYPE_VARIABLE_LIST));
234 mimeData->data(MIME_TYPE_VARIABLE_LIST));
235 impl->dropVariables(variables, index, this);
235 impl->dropVariables(variables, index, this);
236 }
236 }
237 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
237 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
238 auto productsData = sqpApp->dataSourceController().productsDataForMimeData(
238 auto productsData = sqpApp->dataSourceController().productsDataForMimeData(
239 mimeData->data(MIME_TYPE_PRODUCT_LIST));
239 mimeData->data(MIME_TYPE_PRODUCT_LIST));
240 impl->dropProducts(productsData, index, this);
240 impl->dropProducts(productsData, index, this);
241 }
241 }
242 else {
242 else {
243 qCWarning(LOG_VisualizationZoneWidget())
243 qCWarning(LOG_VisualizationZoneWidget())
244 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
244 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
245 }
245 }
246 }
246 }
247
247
248 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph(
248 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph(
249 int index, VisualizationTabWidget *tabWidget)
249 int index, VisualizationTabWidget *tabWidget)
250 {
250 {
251 auto &helper = sqpApp->dragDropGuiController();
251 auto &helper = sqpApp->dragDropGuiController();
252
252
253 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
253 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
254 if (!graphWidget) {
254 if (!graphWidget) {
255 qCWarning(LOG_VisualizationZoneWidget())
255 qCWarning(LOG_VisualizationZoneWidget())
256 << tr("VisualizationTabWidget::dropGraph, drop aborted, the dropped graph is not "
256 << tr("VisualizationTabWidget::dropGraph, drop aborted, the dropped graph is not "
257 "found or invalid.");
257 "found or invalid.");
258 Q_ASSERT(false);
258 Q_ASSERT(false);
259 return;
259 return;
260 }
260 }
261
261
262 auto parentDragDropContainer
262 auto parentDragDropContainer
263 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
263 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
264 if (!parentDragDropContainer) {
264 if (!parentDragDropContainer) {
265 qCWarning(LOG_VisualizationZoneWidget())
265 qCWarning(LOG_VisualizationZoneWidget())
266 << tr("VisualizationTabWidget::dropGraph, drop aborted, the parent container of "
266 << tr("VisualizationTabWidget::dropGraph, drop aborted, the parent container of "
267 "the dropped graph is not found.");
267 "the dropped graph is not found.");
268 Q_ASSERT(false);
268 Q_ASSERT(false);
269 return;
269 return;
270 }
270 }
271
271
272 auto nbGraph = parentDragDropContainer->countDragWidget();
272 auto nbGraph = parentDragDropContainer->countDragWidget();
273
273
274 const auto &variables = graphWidget->variables();
274 const auto &variables = graphWidget->variables();
275
275
276 if (!variables.isEmpty()) {
276 if (!variables.empty()) {
277 // Abort the requests for the variables (if any)
277 // Abort the requests for the variables (if any)
278 // Commented, because it's not sure if it's needed or not
278 // Commented, because it's not sure if it's needed or not
279 // for (const auto& var : variables)
279 // for (const auto& var : variables)
280 //{
280 //{
281 // sqpApp->variableController().onAbortProgressRequested(var);
281 // sqpApp->variableController().onAbortProgressRequested(var);
282 //}
282 //}
283
283
284 if (nbGraph == 1) {
284 if (nbGraph == 1) {
285 // This is the only graph in the previous zone, close the zone
285 // This is the only graph in the previous zone, close the zone
286 helper.delayedCloseWidget(graphWidget->parentZoneWidget());
286 helper.delayedCloseWidget(graphWidget->parentZoneWidget());
287 }
287 }
288 else {
288 else {
289 // Close the graph
289 // Close the graph
290 helper.delayedCloseWidget(graphWidget);
290 helper.delayedCloseWidget(graphWidget);
291 }
291 }
292
292
293 auto zoneWidget = tabWidget->createZone(variables, index);
293 auto zoneWidget = tabWidget->createZone(variables, index);
294 auto firstGraph = zoneWidget->firstGraph();
294 auto firstGraph = zoneWidget->firstGraph();
295 if (firstGraph) {
295 if (firstGraph) {
296 firstGraph->addSelectionZones(graphWidget->selectionZoneRanges());
296 firstGraph->addSelectionZones(graphWidget->selectionZoneRanges());
297 }
297 }
298 else {
298 else {
299 qCWarning(LOG_VisualizationZoneWidget())
299 qCWarning(LOG_VisualizationZoneWidget())
300 << tr("VisualizationTabWidget::dropGraph, no graph added in the widget.");
300 << tr("VisualizationTabWidget::dropGraph, no graph added in the widget.");
301 Q_ASSERT(false);
301 Q_ASSERT(false);
302 }
302 }
303 }
303 }
304 else {
304 else {
305 // The graph is empty, create an empty zone and move the graph inside
305 // The graph is empty, create an empty zone and move the graph inside
306
306
307 auto parentZoneWidget = graphWidget->parentZoneWidget();
307 auto parentZoneWidget = graphWidget->parentZoneWidget();
308
308
309 parentDragDropContainer->layout()->removeWidget(graphWidget);
309 parentDragDropContainer->layout()->removeWidget(graphWidget);
310
310
311 auto zoneWidget = tabWidget->createEmptyZone(index);
311 auto zoneWidget = tabWidget->createEmptyZone(index);
312 zoneWidget->addGraph(graphWidget);
312 zoneWidget->addGraph(graphWidget);
313
313
314 // Close the old zone if it was the only graph inside
314 // Close the old zone if it was the only graph inside
315 if (nbGraph == 1) {
315 if (nbGraph == 1) {
316 helper.delayedCloseWidget(parentZoneWidget);
316 helper.delayedCloseWidget(parentZoneWidget);
317 }
317 }
318 }
318 }
319 }
319 }
320
320
321 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropZone(
321 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropZone(
322 int index, VisualizationTabWidget *tabWidget)
322 int index, VisualizationTabWidget *tabWidget)
323 {
323 {
324 auto &helper = sqpApp->dragDropGuiController();
324 auto &helper = sqpApp->dragDropGuiController();
325
325
326 auto zoneWidget = qobject_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget());
326 auto zoneWidget = qobject_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget());
327 if (!zoneWidget) {
327 if (!zoneWidget) {
328 qCWarning(LOG_VisualizationZoneWidget())
328 qCWarning(LOG_VisualizationZoneWidget())
329 << tr("VisualizationTabWidget::dropZone, drop aborted, the dropped zone is not "
329 << tr("VisualizationTabWidget::dropZone, drop aborted, the dropped zone is not "
330 "found or invalid.");
330 "found or invalid.");
331 Q_ASSERT(false);
331 Q_ASSERT(false);
332 return;
332 return;
333 }
333 }
334
334
335 auto parentDragDropContainer
335 auto parentDragDropContainer
336 = qobject_cast<VisualizationDragDropContainer *>(zoneWidget->parentWidget());
336 = qobject_cast<VisualizationDragDropContainer *>(zoneWidget->parentWidget());
337 if (!parentDragDropContainer) {
337 if (!parentDragDropContainer) {
338 qCWarning(LOG_VisualizationZoneWidget())
338 qCWarning(LOG_VisualizationZoneWidget())
339 << tr("VisualizationTabWidget::dropZone, drop aborted, the parent container of "
339 << tr("VisualizationTabWidget::dropZone, drop aborted, the parent container of "
340 "the dropped zone is not found.");
340 "the dropped zone is not found.");
341 Q_ASSERT(false);
341 Q_ASSERT(false);
342 return;
342 return;
343 }
343 }
344
344
345 // Simple move of the zone, no variable operation associated
345 // Simple move of the zone, no variable operation associated
346 parentDragDropContainer->layout()->removeWidget(zoneWidget);
346 parentDragDropContainer->layout()->removeWidget(zoneWidget);
347 tabWidget->ui->dragDropContainer->insertDragWidget(index, zoneWidget);
347 tabWidget->ui->dragDropContainer->insertDragWidget(index, zoneWidget);
348 }
348 }
349
349
350 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables(
350 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables(
351 const QList<std::shared_ptr<Variable> > &variables, int index,
351 const std::vector<std::shared_ptr<Variable> > &variables, int index,
352 VisualizationTabWidget *tabWidget)
352 VisualizationTabWidget *tabWidget)
353 {
353 {
354 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
354 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
355 // compatible variable here
355 // compatible variable here
356 if (variables.count() > 1) {
356 if (variables.size() > 1) {
357 qCWarning(LOG_VisualizationZoneWidget())
357 qCWarning(LOG_VisualizationZoneWidget())
358 << tr("VisualizationTabWidget::dropVariables, dropping multiple variables, operation "
358 << tr("VisualizationTabWidget::dropVariables, dropping multiple variables, operation "
359 "aborted.");
359 "aborted.");
360 return;
360 return;
361 }
361 }
362
362
363 tabWidget->createZone(variables, index);
363 tabWidget->createZone(variables, index);
364 }
364 }
365
365
366 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropProducts(
366 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropProducts(
367 const QVariantList &productsMetaData, int index, VisualizationTabWidget *tabWidget)
367 const QVariantList &productsMetaData, int index, VisualizationTabWidget *tabWidget)
368 {
368 {
369 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
369 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
370 // compatible variable here
370 // compatible variable here
371 if (productsMetaData.count() != 1) {
371 if (productsMetaData.count() != 1) {
372 qCWarning(LOG_VisualizationZoneWidget())
372 qCWarning(LOG_VisualizationZoneWidget())
373 << tr("VisualizationTabWidget::dropProducts, dropping multiple products, operation "
373 << tr("VisualizationTabWidget::dropProducts, dropping multiple products, operation "
374 "aborted.");
374 "aborted.");
375 return;
375 return;
376 }
376 }
377
377
378 auto context = new QObject{tabWidget};
378 auto context = new QObject{tabWidget};
379 connect(&sqpApp->variableController(), &VariableController::variableAdded, context,
379 connect(&sqpApp->variableController(), &VariableController2::variableAdded, context,
380 [this, index, tabWidget, context](auto variable) {
380 [this, index, tabWidget, context](auto variable) {
381 tabWidget->createZone({variable}, index);
381 tabWidget->createZone({variable}, index);
382 delete context; // removes the connection
382 delete context; // removes the connection
383 },
383 },
384 Qt::QueuedConnection);
384 Qt::QueuedConnection);
385
385
386 auto productData = productsMetaData.first().toHash();
386 auto productData = productsMetaData.first().toHash();
387 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
387 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
388 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
388 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
389 }
389 }
@@ -1,659 +1,629
1 #include "Visualization/VisualizationZoneWidget.h"
1 #include "Visualization/VisualizationZoneWidget.h"
2
2
3 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/IVisualizationWidgetVisitor.h"
4 #include "Visualization/QCustomPlotSynchronizer.h"
4 #include "Visualization/QCustomPlotSynchronizer.h"
5 #include "Visualization/VisualizationGraphWidget.h"
5 #include "Visualization/VisualizationGraphWidget.h"
6 #include "Visualization/VisualizationWidget.h"
6 #include "Visualization/VisualizationWidget.h"
7 #include "ui_VisualizationZoneWidget.h"
7 #include "ui_VisualizationZoneWidget.h"
8
8
9 #include "Common/MimeTypesDef.h"
9 #include "Common/MimeTypesDef.h"
10 #include "Common/VisualizationDef.h"
10 #include "Common/VisualizationDef.h"
11
11
12 #include <Data/DateTimeRange.h>
12 #include <Data/DateTimeRange.h>
13 #include <Data/DateTimeRangeHelper.h>
13 #include <DataSource/DataSourceController.h>
14 #include <DataSource/DataSourceController.h>
14 #include <Time/TimeController.h>
15 #include <Time/TimeController.h>
15 #include <Variable/Variable.h>
16 #include <Variable/Variable.h>
16 #include <Variable/VariableController.h>
17 #include <Variable/VariableController2.h>
17
18
18 #include <Visualization/operations/FindVariableOperation.h>
19 #include <Visualization/operations/FindVariableOperation.h>
19
20
20 #include <DragAndDrop/DragDropGuiController.h>
21 #include <DragAndDrop/DragDropGuiController.h>
21 #include <QUuid>
22 #include <QUuid>
22 #include <SqpApplication.h>
23 #include <SqpApplication.h>
23 #include <cmath>
24 #include <cmath>
24
25
25 #include <QLayout>
26 #include <QLayout>
26 #include <QStyle>
27 #include <QStyle>
27
28
28 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
29 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
29
30
30 namespace {
31 namespace {
31
32
32 /**
33 /**
33 * Applies a function to all graphs of the zone represented by its layout
34 * Applies a function to all graphs of the zone represented by its layout
34 * @param layout the layout that contains graphs
35 * @param layout the layout that contains graphs
35 * @param fun the function to apply to each graph
36 * @param fun the function to apply to each graph
36 */
37 */
37 template <typename Fun>
38 template <typename Fun>
38 void processGraphs(QLayout &layout, Fun fun)
39 void processGraphs(QLayout &layout, Fun fun)
39 {
40 {
40 for (auto i = 0; i < layout.count(); ++i) {
41 for (auto i = 0; i < layout.count(); ++i) {
41 if (auto item = layout.itemAt(i)) {
42 if (auto item = layout.itemAt(i)) {
42 if (auto visualizationGraphWidget
43 if (auto visualizationGraphWidget
43 = qobject_cast<VisualizationGraphWidget *>(item->widget())) {
44 = qobject_cast<VisualizationGraphWidget *>(item->widget())) {
44 fun(*visualizationGraphWidget);
45 fun(*visualizationGraphWidget);
45 }
46 }
46 }
47 }
47 }
48 }
48 }
49 }
49
50
50 /// Generates a default name for a new graph, according to the number of graphs already displayed in
51 /// Generates a default name for a new graph, according to the number of graphs already displayed in
51 /// the zone
52 /// the zone
52 QString defaultGraphName(QLayout &layout)
53 QString defaultGraphName(QLayout &layout)
53 {
54 {
54 QSet<QString> existingNames;
55 QSet<QString> existingNames;
55 processGraphs(
56 processGraphs(
56 layout, [&existingNames](auto &graphWidget) { existingNames.insert(graphWidget.name()); });
57 layout, [&existingNames](auto &graphWidget) { existingNames.insert(graphWidget.name()); });
57
58
58 int zoneNum = 1;
59 int zoneNum = 1;
59 QString name;
60 QString name;
60 do {
61 do {
61 name = QObject::tr("Graph ").append(QString::number(zoneNum));
62 name = QObject::tr("Graph ").append(QString::number(zoneNum));
62 ++zoneNum;
63 ++zoneNum;
63 } while (existingNames.contains(name));
64 } while (existingNames.contains(name));
64
65
65 return name;
66 return name;
66 }
67 }
67
68
68 } // namespace
69 } // namespace
69
70
70 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
71 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
71
72
72 explicit VisualizationZoneWidgetPrivate()
73 explicit VisualizationZoneWidgetPrivate()
73 : m_SynchronisationGroupId{QUuid::createUuid()},
74 : m_SynchronisationGroupId{QUuid::createUuid()},
74 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
75 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
75 {
76 {
76 }
77 }
77 QUuid m_SynchronisationGroupId;
78 QUuid m_SynchronisationGroupId;
78 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
79 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
79
80
80 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
81 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
81 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
82 void dropVariables(const std::vector<std::shared_ptr<Variable> > &variables, int index,
82 VisualizationZoneWidget *zoneWidget);
83 VisualizationZoneWidget *zoneWidget);
83 void dropProducts(const QVariantList &productsData, int index,
84 void dropProducts(const QVariantList &productsData, int index,
84 VisualizationZoneWidget *zoneWidget);
85 VisualizationZoneWidget *zoneWidget);
85 };
86 };
86
87
87 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
88 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
88 : VisualizationDragWidget{parent},
89 : VisualizationDragWidget{parent},
89 ui{new Ui::VisualizationZoneWidget},
90 ui{new Ui::VisualizationZoneWidget},
90 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
91 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
91 {
92 {
92 ui->setupUi(this);
93 ui->setupUi(this);
93
94
94 ui->zoneNameLabel->setText(name);
95 ui->zoneNameLabel->setText(name);
95
96
96 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Graph);
97 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Graph);
97 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
98 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
98 VisualizationDragDropContainer::DropBehavior::Inserted);
99 VisualizationDragDropContainer::DropBehavior::Inserted);
99 ui->dragDropContainer->setMimeType(
100 ui->dragDropContainer->setMimeType(
100 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
101 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
101 ui->dragDropContainer->setMimeType(
102 ui->dragDropContainer->setMimeType(
102 MIME_TYPE_PRODUCT_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
103 MIME_TYPE_PRODUCT_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
103 ui->dragDropContainer->setMimeType(MIME_TYPE_TIME_RANGE,
104 ui->dragDropContainer->setMimeType(MIME_TYPE_TIME_RANGE,
104 VisualizationDragDropContainer::DropBehavior::Merged);
105 VisualizationDragDropContainer::DropBehavior::Merged);
105 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
106 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
106 VisualizationDragDropContainer::DropBehavior::Forbidden);
107 VisualizationDragDropContainer::DropBehavior::Forbidden);
107 ui->dragDropContainer->setMimeType(MIME_TYPE_SELECTION_ZONE,
108 ui->dragDropContainer->setMimeType(MIME_TYPE_SELECTION_ZONE,
108 VisualizationDragDropContainer::DropBehavior::Forbidden);
109 VisualizationDragDropContainer::DropBehavior::Forbidden);
109 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
110 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
110 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(mimeData,
111 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(mimeData,
111 ui->dragDropContainer);
112 ui->dragDropContainer);
112 });
113 });
113
114
114 auto acceptDragWidgetFun = [](auto dragWidget, auto mimeData) {
115 auto acceptDragWidgetFun = [](auto dragWidget, auto mimeData) {
115 if (!mimeData) {
116 if (!mimeData) {
116 return false;
117 return false;
117 }
118 }
118
119
119 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
120 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
120 auto variables = sqpApp->variableController().variablesForMimeData(
121 auto variables = sqpApp->variableController().variables(
121 mimeData->data(MIME_TYPE_VARIABLE_LIST));
122 mimeData->data(MIME_TYPE_VARIABLE_LIST));
122
123
123 if (variables.count() != 1) {
124 if (variables.size() != 1) {
124 return false;
125 return false;
125 }
126 }
126 auto variable = variables.first();
127 auto variable = variables.front();
127
128
128 if (auto graphWidget = dynamic_cast<const VisualizationGraphWidget *>(dragWidget)) {
129 if (auto graphWidget = dynamic_cast<const VisualizationGraphWidget *>(dragWidget)) {
129 return graphWidget->canDrop(*variable);
130 return graphWidget->canDrop(*variable);
130 }
131 }
131 }
132 }
132
133
133 return true;
134 return true;
134 };
135 };
135 ui->dragDropContainer->setAcceptDragWidgetFunction(acceptDragWidgetFun);
136 ui->dragDropContainer->setAcceptDragWidgetFunction(acceptDragWidgetFun);
136
137
137 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
138 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
138 &VisualizationZoneWidget::dropMimeData);
139 &VisualizationZoneWidget::dropMimeData);
139 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
140 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
140 &VisualizationZoneWidget::dropMimeDataOnGraph);
141 &VisualizationZoneWidget::dropMimeDataOnGraph);
141
142
142 // 'Close' options : widget is deleted when closed
143 // 'Close' options : widget is deleted when closed
143 setAttribute(Qt::WA_DeleteOnClose);
144 setAttribute(Qt::WA_DeleteOnClose);
144 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
145 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
145 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
146 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
146
147
147 // Synchronisation id
148 // Synchronisation id
148 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
149 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
149 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
150 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
150 }
151 }
151
152
152 VisualizationZoneWidget::~VisualizationZoneWidget()
153 VisualizationZoneWidget::~VisualizationZoneWidget()
153 {
154 {
154 delete ui;
155 delete ui;
155 }
156 }
156
157
157 void VisualizationZoneWidget::setZoneRange(const DateTimeRange &range)
158 void VisualizationZoneWidget::setZoneRange(const DateTimeRange &range)
158 {
159 {
159 if (auto graph = firstGraph()) {
160 if (auto graph = firstGraph()) {
160 graph->setGraphRange(range);
161 graph->setGraphRange(range);
161 }
162 }
162 else {
163 else {
163 qCWarning(LOG_VisualizationZoneWidget())
164 qCWarning(LOG_VisualizationZoneWidget())
164 << tr("setZoneRange:Cannot set the range of an empty zone.");
165 << tr("setZoneRange:Cannot set the range of an empty zone.");
165 }
166 }
166 }
167 }
167
168
168 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
169 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
169 {
170 {
170 // Synchronize new graph with others in the zone
171 // Synchronize new graph with others in the zone
171 impl->m_Synchronizer->addGraph(*graphWidget);
172 impl->m_Synchronizer->addGraph(*graphWidget);
172
173
173 ui->dragDropContainer->addDragWidget(graphWidget);
174 ui->dragDropContainer->addDragWidget(graphWidget);
174 }
175 }
175
176
176 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
177 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
177 {
178 {
178 // Synchronize new graph with others in the zone
179 // Synchronize new graph with others in the zone
179 impl->m_Synchronizer->addGraph(*graphWidget);
180 impl->m_Synchronizer->addGraph(*graphWidget);
180
181
181 ui->dragDropContainer->insertDragWidget(index, graphWidget);
182 ui->dragDropContainer->insertDragWidget(index, graphWidget);
182 }
183 }
183
184
184 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
185 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
185 {
186 {
186 return createGraph(variable, -1);
187 return createGraph(variable, -1);
187 }
188 }
188
189
189 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
190 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
190 int index)
191 int index)
191 {
192 {
192 auto graphWidget
193 auto graphWidget
193 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
194 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
194
195
195
196
196 // Set graph properties
197 // Set graph properties
197 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
198 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
198 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
199 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
199
200
200
201
201 // Lambda to synchronize zone widget
202 // Lambda to synchronize zone widget
202 auto synchronizeZoneWidget = [this, graphWidget](const DateTimeRange &graphRange,
203 auto synchronizeZoneWidget = [this, graphWidget](const DateTimeRange &graphRange,
203 const DateTimeRange &oldGraphRange) {
204 const DateTimeRange &oldGraphRange) {
204
205
205 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
206 auto zoomType = DateTimeRangeHelper::getTransformationType(oldGraphRange, graphRange);
206 auto frameLayout = ui->dragDropContainer->layout();
207 auto frameLayout = ui->dragDropContainer->layout();
207 for (auto i = 0; i < frameLayout->count(); ++i) {
208 for (auto i = 0; i < frameLayout->count(); ++i) {
208 auto graphChild
209 auto graphChild
209 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
210 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
210 if (graphChild && (graphChild != graphWidget)) {
211 if (graphChild && (graphChild != graphWidget)) {
211
212
212 auto graphChildRange = graphChild->graphRange();
213 auto graphChildRange = graphChild->graphRange();
213 switch (zoomType) {
214 switch (zoomType) {
214 case AcquisitionZoomType::ZoomIn: {
215 case TransformationType::ZoomIn: {
215 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
216 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
216 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
217 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
217 graphChildRange.m_TStart += deltaLeft;
218 graphChildRange.m_TStart += deltaLeft;
218 graphChildRange.m_TEnd -= deltaRight;
219 graphChildRange.m_TEnd -= deltaRight;
219 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
220 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
221 << deltaLeft;
222 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
223 << deltaRight;
224 qCDebug(LOG_VisualizationZoneWidget())
225 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
226
227 break;
220 break;
228 }
221 }
229
222
230 case AcquisitionZoomType::ZoomOut: {
223 case TransformationType::ZoomOut: {
231 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
232 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
224 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
233 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
225 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
234 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
235 << deltaLeft;
236 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
237 << deltaRight;
238 qCDebug(LOG_VisualizationZoneWidget())
239 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
240 graphChildRange.m_TStart -= deltaLeft;
226 graphChildRange.m_TStart -= deltaLeft;
241 graphChildRange.m_TEnd += deltaRight;
227 graphChildRange.m_TEnd += deltaRight;
242 break;
228 break;
243 }
229 }
244 case AcquisitionZoomType::PanRight: {
230 case TransformationType::PanRight: {
245 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
246 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
231 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
247 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
232 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
248 graphChildRange.m_TStart += deltaLeft;
233 graphChildRange.m_TStart += deltaLeft;
249 graphChildRange.m_TEnd += deltaRight;
234 graphChildRange.m_TEnd += deltaRight;
250 qCDebug(LOG_VisualizationZoneWidget())
251 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
252 break;
235 break;
253 }
236 }
254 case AcquisitionZoomType::PanLeft: {
237 case TransformationType::PanLeft: {
255 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
256 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
238 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
257 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
239 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
258 graphChildRange.m_TStart -= deltaLeft;
240 graphChildRange.m_TStart -= deltaLeft;
259 graphChildRange.m_TEnd -= deltaRight;
241 graphChildRange.m_TEnd -= deltaRight;
260 break;
242 break;
261 }
243 }
262 case AcquisitionZoomType::Unknown: {
244 case TransformationType::Unknown: {
263 qCDebug(LOG_VisualizationZoneWidget())
264 << tr("Impossible to synchronize: zoom type unknown");
265 break;
245 break;
266 }
246 }
267 default:
247 default:
268 qCCritical(LOG_VisualizationZoneWidget())
248 qCCritical(LOG_VisualizationZoneWidget())
269 << tr("Impossible to synchronize: zoom type not take into account");
249 << tr("Impossible to synchronize: zoom type not take into account");
270 // No action
250 // No action
271 break;
251 break;
272 }
252 }
273 graphChild->setFlags(GraphFlag::DisableAll);
253 graphChild->setFlags(GraphFlag::DisableAll);
274 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
275 << graphChild->graphRange();
276 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
277 << graphChildRange;
278 qCDebug(LOG_VisualizationZoneWidget())
279 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
280 graphChild->setGraphRange(graphChildRange);
254 graphChild->setGraphRange(graphChildRange);
281 graphChild->setFlags(GraphFlag::EnableAll);
255 graphChild->setFlags(GraphFlag::EnableAll);
282 }
256 }
283 }
257 }
284 };
258 };
285
259
286 // connection for synchronization
260 // connection for synchronization
287 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
261 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
288 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
262 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
289 &VisualizationZoneWidget::onVariableAdded);
263 &VisualizationZoneWidget::onVariableAdded);
290 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
264 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
291 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
265 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
292
266
293 auto range = DateTimeRange{};
267 auto range = DateTimeRange{};
294 if (auto firstGraph = this->firstGraph()) {
268 if (auto firstGraph = this->firstGraph()) {
295 // Case of a new graph in a existant zone
269 // Case of a new graph in a existant zone
296 range = firstGraph->graphRange();
270 range = firstGraph->graphRange();
297 }
271 }
298 else {
272 else {
299 // Case of a new graph as the first of the zone
273 // Case of a new graph as the first of the zone
300 range = variable->range();
274 range = variable->range();
301 }
275 }
302
276
303 this->insertGraph(index, graphWidget);
277 this->insertGraph(index, graphWidget);
304
278
305 graphWidget->addVariable(variable, range);
279 graphWidget->addVariable(variable, range);
306 graphWidget->setYRange(variable);
280 graphWidget->setYRange(variable);
307
281
308 return graphWidget;
282 return graphWidget;
309 }
283 }
310
284
311 VisualizationGraphWidget *
285 VisualizationGraphWidget *
312 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
286 VisualizationZoneWidget::createGraph(const std::vector<std::shared_ptr<Variable> > variables, int index)
313 {
287 {
314 if (variables.isEmpty()) {
288 if (variables.empty()) {
315 return nullptr;
289 return nullptr;
316 }
290 }
317
291
318 auto graphWidget = createGraph(variables.first(), index);
292 auto graphWidget = createGraph(variables.front(), index);
319 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
293 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
320 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
294 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
321 }
295 }
322
296
323 return graphWidget;
297 return graphWidget;
324 }
298 }
325
299
326 VisualizationGraphWidget *VisualizationZoneWidget::firstGraph() const
300 VisualizationGraphWidget *VisualizationZoneWidget::firstGraph() const
327 {
301 {
328 VisualizationGraphWidget *firstGraph = nullptr;
302 VisualizationGraphWidget *firstGraph = nullptr;
329 auto layout = ui->dragDropContainer->layout();
303 auto layout = ui->dragDropContainer->layout();
330 if (layout->count() > 0) {
304 if (layout->count() > 0) {
331 if (auto visualizationGraphWidget
305 if (auto visualizationGraphWidget
332 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
306 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
333 firstGraph = visualizationGraphWidget;
307 firstGraph = visualizationGraphWidget;
334 }
308 }
335 }
309 }
336
310
337 return firstGraph;
311 return firstGraph;
338 }
312 }
339
313
340 void VisualizationZoneWidget::closeAllGraphs()
314 void VisualizationZoneWidget::closeAllGraphs()
341 {
315 {
342 processGraphs(*ui->dragDropContainer->layout(),
316 processGraphs(*ui->dragDropContainer->layout(),
343 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
317 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
344 }
318 }
345
319
346 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
320 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
347 {
321 {
348 if (visitor) {
322 if (visitor) {
349 visitor->visitEnter(this);
323 visitor->visitEnter(this);
350
324
351 // Apply visitor to graph children: widgets different from graphs are not visited (no
325 // Apply visitor to graph children: widgets different from graphs are not visited (no
352 // action)
326 // action)
353 processGraphs(
327 processGraphs(
354 *ui->dragDropContainer->layout(),
328 *ui->dragDropContainer->layout(),
355 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
329 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
356
330
357 visitor->visitLeave(this);
331 visitor->visitLeave(this);
358 }
332 }
359 else {
333 else {
360 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
334 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
361 }
335 }
362 }
336 }
363
337
364 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
338 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
365 {
339 {
366 // A tab can always accomodate a variable
340 // A tab can always accomodate a variable
367 Q_UNUSED(variable);
341 Q_UNUSED(variable);
368 return true;
342 return true;
369 }
343 }
370
344
371 bool VisualizationZoneWidget::contains(const Variable &variable) const
345 bool VisualizationZoneWidget::contains(const Variable &variable) const
372 {
346 {
373 Q_UNUSED(variable);
347 Q_UNUSED(variable);
374 return false;
348 return false;
375 }
349 }
376
350
377 QString VisualizationZoneWidget::name() const
351 QString VisualizationZoneWidget::name() const
378 {
352 {
379 return ui->zoneNameLabel->text();
353 return ui->zoneNameLabel->text();
380 }
354 }
381
355
382 QMimeData *VisualizationZoneWidget::mimeData(const QPoint &position) const
356 QMimeData *VisualizationZoneWidget::mimeData(const QPoint &position) const
383 {
357 {
384 Q_UNUSED(position);
358 Q_UNUSED(position);
385
359
386 auto mimeData = new QMimeData;
360 auto mimeData = new QMimeData;
387 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
361 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
388
362
389 if (auto firstGraph = this->firstGraph()) {
363 if (auto firstGraph = this->firstGraph()) {
390 auto timeRangeData = TimeController::mimeDataForTimeRange(firstGraph->graphRange());
364 auto timeRangeData = TimeController::mimeDataForTimeRange(firstGraph->graphRange());
391 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
365 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
392 }
366 }
393
367
394 return mimeData;
368 return mimeData;
395 }
369 }
396
370
397 bool VisualizationZoneWidget::isDragAllowed() const
371 bool VisualizationZoneWidget::isDragAllowed() const
398 {
372 {
399 return true;
373 return true;
400 }
374 }
401
375
402 void VisualizationZoneWidget::notifyMouseMoveInGraph(const QPointF &graphPosition,
376 void VisualizationZoneWidget::notifyMouseMoveInGraph(const QPointF &graphPosition,
403 const QPointF &plotPosition,
377 const QPointF &plotPosition,
404 VisualizationGraphWidget *graphWidget)
378 VisualizationGraphWidget *graphWidget)
405 {
379 {
406 processGraphs(*ui->dragDropContainer->layout(), [&graphPosition, &plotPosition, &graphWidget](
380 processGraphs(*ui->dragDropContainer->layout(), [&graphPosition, &plotPosition, &graphWidget](
407 VisualizationGraphWidget &processedGraph) {
381 VisualizationGraphWidget &processedGraph) {
408
382
409 switch (sqpApp->plotsCursorMode()) {
383 switch (sqpApp->plotsCursorMode()) {
410 case SqpApplication::PlotsCursorMode::Vertical:
384 case SqpApplication::PlotsCursorMode::Vertical:
411 processedGraph.removeHorizontalCursor();
385 processedGraph.removeHorizontalCursor();
412 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
386 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
413 break;
387 break;
414 case SqpApplication::PlotsCursorMode::Temporal:
388 case SqpApplication::PlotsCursorMode::Temporal:
415 processedGraph.addVerticalCursor(plotPosition.x());
389 processedGraph.addVerticalCursor(plotPosition.x());
416 processedGraph.removeHorizontalCursor();
390 processedGraph.removeHorizontalCursor();
417 break;
391 break;
418 case SqpApplication::PlotsCursorMode::Horizontal:
392 case SqpApplication::PlotsCursorMode::Horizontal:
419 processedGraph.removeVerticalCursor();
393 processedGraph.removeVerticalCursor();
420 if (&processedGraph == graphWidget) {
394 if (&processedGraph == graphWidget) {
421 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
395 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
422 }
396 }
423 else {
397 else {
424 processedGraph.removeHorizontalCursor();
398 processedGraph.removeHorizontalCursor();
425 }
399 }
426 break;
400 break;
427 case SqpApplication::PlotsCursorMode::Cross:
401 case SqpApplication::PlotsCursorMode::Cross:
428 if (&processedGraph == graphWidget) {
402 if (&processedGraph == graphWidget) {
429 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
403 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
430 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
404 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
431 }
405 }
432 else {
406 else {
433 processedGraph.removeHorizontalCursor();
407 processedGraph.removeHorizontalCursor();
434 processedGraph.removeVerticalCursor();
408 processedGraph.removeVerticalCursor();
435 }
409 }
436 break;
410 break;
437 case SqpApplication::PlotsCursorMode::NoCursor:
411 case SqpApplication::PlotsCursorMode::NoCursor:
438 processedGraph.removeHorizontalCursor();
412 processedGraph.removeHorizontalCursor();
439 processedGraph.removeVerticalCursor();
413 processedGraph.removeVerticalCursor();
440 break;
414 break;
441 }
415 }
442
416
443
417
444 });
418 });
445 }
419 }
446
420
447 void VisualizationZoneWidget::notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget)
421 void VisualizationZoneWidget::notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget)
448 {
422 {
449 processGraphs(*ui->dragDropContainer->layout(), [](VisualizationGraphWidget &processedGraph) {
423 processGraphs(*ui->dragDropContainer->layout(), [](VisualizationGraphWidget &processedGraph) {
450 processedGraph.removeHorizontalCursor();
424 processedGraph.removeHorizontalCursor();
451 processedGraph.removeVerticalCursor();
425 processedGraph.removeVerticalCursor();
452 });
426 });
453 }
427 }
454
428
455 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
429 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
456 {
430 {
457 // Closes graphs in the zone
431 // Closes graphs in the zone
458 processGraphs(*ui->dragDropContainer->layout(),
432 processGraphs(*ui->dragDropContainer->layout(),
459 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
433 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
460
434
461 // Delete synchronization group from variable controller
435 // Delete synchronization group from variable controller
462 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
436 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
463 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
437 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
464
438
465 QWidget::closeEvent(event);
439 QWidget::closeEvent(event);
466 }
440 }
467
441
468 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
442 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
469 {
443 {
470 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
444 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
471 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
445 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
472 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
446 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
473 }
447 }
474
448
475 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
449 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
476 {
450 {
477 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
451 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
478 Q_ARG(std::shared_ptr<Variable>, variable),
452 Q_ARG(std::shared_ptr<Variable>, variable),
479 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
453 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
480 }
454 }
481
455
482 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
456 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
483 {
457 {
484 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
458 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
485 impl->dropGraph(index, this);
459 impl->dropGraph(index, this);
486 }
460 }
487 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
461 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
488 auto variables = sqpApp->variableController().variablesForMimeData(
462 auto variables = sqpApp->variableController().variables(
489 mimeData->data(MIME_TYPE_VARIABLE_LIST));
463 mimeData->data(MIME_TYPE_VARIABLE_LIST));
490 impl->dropVariables(variables, index, this);
464 impl->dropVariables(variables, index, this);
491 }
465 }
492 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
466 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
493 auto products = sqpApp->dataSourceController().productsDataForMimeData(
467 auto products = sqpApp->dataSourceController().productsDataForMimeData(
494 mimeData->data(MIME_TYPE_PRODUCT_LIST));
468 mimeData->data(MIME_TYPE_PRODUCT_LIST));
495 impl->dropProducts(products, index, this);
469 impl->dropProducts(products, index, this);
496 }
470 }
497 else {
471 else {
498 qCWarning(LOG_VisualizationZoneWidget())
472 qCWarning(LOG_VisualizationZoneWidget())
499 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
473 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
500 }
474 }
501 }
475 }
502
476
503 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
477 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
504 const QMimeData *mimeData)
478 const QMimeData *mimeData)
505 {
479 {
506 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
480 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
507 if (!graphWidget) {
481 if (!graphWidget) {
508 qCWarning(LOG_VisualizationZoneWidget())
482 qCWarning(LOG_VisualizationZoneWidget())
509 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
483 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
510 "drop aborted");
484 "drop aborted");
511 Q_ASSERT(false);
485 Q_ASSERT(false);
512 return;
486 return;
513 }
487 }
514
488
515 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
489 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
516 auto variables = sqpApp->variableController().variablesForMimeData(
490 auto variables = sqpApp->variableController().variables(
517 mimeData->data(MIME_TYPE_VARIABLE_LIST));
491 mimeData->data(MIME_TYPE_VARIABLE_LIST));
518 for (const auto &var : variables) {
492 for (const auto &var : variables) {
519 graphWidget->addVariable(var, graphWidget->graphRange());
493 graphWidget->addVariable(var, graphWidget->graphRange());
520 }
494 }
521 }
495 }
522 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
496 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
523 auto products = sqpApp->dataSourceController().productsDataForMimeData(
497 auto products = sqpApp->dataSourceController().productsDataForMimeData(
524 mimeData->data(MIME_TYPE_PRODUCT_LIST));
498 mimeData->data(MIME_TYPE_PRODUCT_LIST));
525
499
526 auto context = new QObject{this};
500 auto context = new QObject{this};
527 connect(&sqpApp->variableController(), &VariableController::variableAdded, context,
501 connect(&sqpApp->variableController(), &VariableController2::variableAdded, context,
528 [this, graphWidget, context](auto variable) {
502 [this, graphWidget, context](auto variable) {
529 graphWidget->addVariable(variable, graphWidget->graphRange());
503 graphWidget->addVariable(variable, graphWidget->graphRange());
530 delete context; // removes the connection
504 delete context; // removes the connection
531 },
505 },
532 Qt::QueuedConnection);
506 Qt::QueuedConnection);
533
507
534 auto productData = products.first().toHash();
508 auto productData = products.first().toHash();
535 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
509 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
536 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
510 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
537 }
511 }
538 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
512 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
539 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
513 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
540 graphWidget->setGraphRange(range);
514 graphWidget->setGraphRange(range);
541 }
515 }
542 else {
516 else {
543 qCWarning(LOG_VisualizationZoneWidget())
517 qCWarning(LOG_VisualizationZoneWidget())
544 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
518 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
545 }
519 }
546 }
520 }
547
521
548 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
522 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
549 int index, VisualizationZoneWidget *zoneWidget)
523 int index, VisualizationZoneWidget *zoneWidget)
550 {
524 {
551 auto &helper = sqpApp->dragDropGuiController();
525 auto &helper = sqpApp->dragDropGuiController();
552
526
553 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
527 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
554 if (!graphWidget) {
528 if (!graphWidget) {
555 qCWarning(LOG_VisualizationZoneWidget())
529 qCWarning(LOG_VisualizationZoneWidget())
556 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
530 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
557 "found or invalid.");
531 "found or invalid.");
558 Q_ASSERT(false);
532 Q_ASSERT(false);
559 return;
533 return;
560 }
534 }
561
535
562 auto parentDragDropContainer
536 auto parentDragDropContainer
563 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
537 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
564 if (!parentDragDropContainer) {
538 if (!parentDragDropContainer) {
565 qCWarning(LOG_VisualizationZoneWidget())
539 qCWarning(LOG_VisualizationZoneWidget())
566 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
540 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
567 "the dropped graph is not found.");
541 "the dropped graph is not found.");
568 Q_ASSERT(false);
542 Q_ASSERT(false);
569 return;
543 return;
570 }
544 }
571
545
572 const auto &variables = graphWidget->variables();
546 const auto &variables = graphWidget->variables();
573
547
574 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
548 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.empty()) {
575 // The drop didn't occur in the same zone
549 // The drop didn't occur in the same zone
576
550
577 // Abort the requests for the variables (if any)
551 // Abort the requests for the variables (if any)
578 // Commented, because it's not sure if it's needed or not
552 // Commented, because it's not sure if it's needed or not
579 // for (const auto& var : variables)
553 // for (const auto& var : variables)
580 //{
554 //{
581 // sqpApp->variableController().onAbortProgressRequested(var);
555 // sqpApp->variableController().onAbortProgressRequested(var);
582 //}
556 //}
583
557
584 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
558 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
585 auto nbGraph = parentDragDropContainer->countDragWidget();
559 auto nbGraph = parentDragDropContainer->countDragWidget();
586 if (nbGraph == 1) {
560 if (nbGraph == 1) {
587 // This is the only graph in the previous zone, close the zone
561 // This is the only graph in the previous zone, close the zone
588 helper.delayedCloseWidget(previousParentZoneWidget);
562 helper.delayedCloseWidget(previousParentZoneWidget);
589 }
563 }
590 else {
564 else {
591 // Close the graph
565 // Close the graph
592 helper.delayedCloseWidget(graphWidget);
566 helper.delayedCloseWidget(graphWidget);
593 }
567 }
594
568
595 // Creates the new graph in the zone
569 // Creates the new graph in the zone
596 auto newGraphWidget = zoneWidget->createGraph(variables, index);
570 auto newGraphWidget = zoneWidget->createGraph(variables, index);
597 newGraphWidget->addSelectionZones(graphWidget->selectionZoneRanges());
571 newGraphWidget->addSelectionZones(graphWidget->selectionZoneRanges());
598 }
572 }
599 else {
573 else {
600 // The drop occurred in the same zone or the graph is empty
574 // The drop occurred in the same zone or the graph is empty
601 // Simple move of the graph, no variable operation associated
575 // Simple move of the graph, no variable operation associated
602 parentDragDropContainer->layout()->removeWidget(graphWidget);
576 parentDragDropContainer->layout()->removeWidget(graphWidget);
603
577
604 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
578 if (variables.empty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
605 // The graph is empty and dropped in a different zone.
579 // The graph is empty and dropped in a different zone.
606 // Take the range of the first graph in the zone (if existing).
580 // Take the range of the first graph in the zone (if existing).
607 auto layout = zoneWidget->ui->dragDropContainer->layout();
581 auto layout = zoneWidget->ui->dragDropContainer->layout();
608 if (layout->count() > 0) {
582 if (layout->count() > 0) {
609 if (auto visualizationGraphWidget
583 if (auto visualizationGraphWidget
610 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
584 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
611 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
585 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
612 }
586 }
613 }
587 }
614 }
588 }
615
589
616 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
590 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
617 }
591 }
618 }
592 }
619
593
620 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
594 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
621 const QList<std::shared_ptr<Variable> > &variables, int index,
595 const std::vector<std::shared_ptr<Variable> > &variables, int index,
622 VisualizationZoneWidget *zoneWidget)
596 VisualizationZoneWidget *zoneWidget)
623 {
597 {
624 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
598 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
625 // compatible variable here
599 // compatible variable here
626 if (variables.count() > 1) {
600 if (variables.size() > 1) {
627 qCWarning(LOG_VisualizationZoneWidget())
628 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
629 "aborted.");
630 return;
601 return;
631 }
602 }
632
633 zoneWidget->createGraph(variables, index);
603 zoneWidget->createGraph(variables, index);
634 }
604 }
635
605
636 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropProducts(
606 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropProducts(
637 const QVariantList &productsData, int index, VisualizationZoneWidget *zoneWidget)
607 const QVariantList &productsData, int index, VisualizationZoneWidget *zoneWidget)
638 {
608 {
639 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
609 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
640 // compatible variable here
610 // compatible variable here
641 if (productsData.count() != 1) {
611 if (productsData.count() != 1) {
642 qCWarning(LOG_VisualizationZoneWidget())
612 qCWarning(LOG_VisualizationZoneWidget())
643 << tr("VisualizationTabWidget::dropProducts, dropping multiple products, operation "
613 << tr("VisualizationTabWidget::dropProducts, dropping multiple products, operation "
644 "aborted.");
614 "aborted.");
645 return;
615 return;
646 }
616 }
647
617
648 auto context = new QObject{zoneWidget};
618 auto context = new QObject{zoneWidget};
649 connect(&sqpApp->variableController(), &VariableController::variableAdded, context,
619 connect(&sqpApp->variableController(), &VariableController2::variableAdded, context,
650 [this, index, zoneWidget, context](auto variable) {
620 [this, index, zoneWidget, context](auto variable) {
651 zoneWidget->createGraph(variable, index);
621 zoneWidget->createGraph(variable, index);
652 delete context; // removes the connection
622 delete context; // removes the connection
653 },
623 },
654 Qt::QueuedConnection);
624 Qt::QueuedConnection);
655
625
656 auto productData = productsData.first().toHash();
626 auto productData = productsData.first().toHash();
657 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
627 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
658 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
628 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
659 }
629 }
@@ -1,126 +1,126
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) 2018, Plasma Physics Laboratory - CNRS
3 -- Copyright (C) 2018, 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 <string>
22 #include <string>
23 #include <sstream>
23 #include <sstream>
24 #include <memory>
24 #include <memory>
25
25
26 #include <pybind11/pybind11.h>
26 #include <pybind11/pybind11.h>
27 #include <pybind11/operators.h>
27 #include <pybind11/operators.h>
28 #include <pybind11/embed.h>
28 #include <pybind11/embed.h>
29 #include <pybind11/numpy.h>
29 #include <pybind11/numpy.h>
30 #include <pybind11/chrono.h>
30 #include <pybind11/chrono.h>
31
31
32 #include <SqpApplication.h>
32 #include <SqpApplication.h>
33 #include <Variable/VariableController.h>
33 #include <Variable/VariableController2.h>
34 #include <Time/TimeController.h>
34 #include <Time/TimeController.h>
35 #include <Data/DateTimeRange.h>
35 #include <Data/DateTimeRange.h>
36 #include <Data/DataSeriesType.h>
36 #include <Data/DataSeriesType.h>
37 #include <Common/DateUtils.h>
37 #include <Common/DateUtils.h>
38 #include <Variable/Variable.h>
38 #include <Variable/Variable.h>
39 #include <Data/ScalarSeries.h>
39 #include <Data/ScalarSeries.h>
40 #include <Data/VectorSeries.h>
40 #include <Data/VectorSeries.h>
41
41
42 #include <AmdaProvider.h>
42 #include <AmdaProvider.h>
43 #include <AmdaResultParser.h>
43 #include <AmdaResultParser.h>
44
44
45 //#include <QDate>
45 //#include <QDate>
46 //#include <QTime>
46 //#include <QTime>
47 //#include <QUuid>
47 //#include <QUuid>
48 //#include <QString>
48 //#include <QString>
49 #include <QFile>
49 #include <QFile>
50
50
51 #include <pywrappers_common.h>
51 #include <pywrappers_common.h>
52 #include <CoreWrappers.h>
52 #include <CoreWrappers.h>
53
53
54 #include "PyTestAmdaWrapper.h"
54 #include "PyTestAmdaWrapper.h"
55
55
56
56
57 using namespace std::chrono;
57 using namespace std::chrono;
58
58
59
59
60
60
61
61
62 PYBIND11_MODULE(pytestamda, m){
62 PYBIND11_MODULE(pytestamda, m){
63
63
64 int argc = 0;
64 int argc = 0;
65 char ** argv=nullptr;
65 char ** argv=nullptr;
66 SqpApplication::setOrganizationName("LPP");
66 SqpApplication::setOrganizationName("LPP");
67 SqpApplication::setOrganizationDomain("lpp.fr");
67 SqpApplication::setOrganizationDomain("lpp.fr");
68 SqpApplication::setApplicationName("SciQLop");
68 SqpApplication::setApplicationName("SciQLop");
69 static SqpApplication app(argc, argv);
69 static SqpApplication app(argc, argv);
70
70
71 auto qtmod = py::module::import("sciqlopqt");
71 auto qtmod = py::module::import("sciqlopqt");
72 auto sciqlopmod = py::module::import("pysciqlopcore");
72 auto sciqlopmod = py::module::import("pysciqlopcore");
73
73
74 m.doc() = "hello";
74 m.doc() = "hello";
75
75
76 py::class_<VariableController>(m, "VariableController")
76 // py::class_<VariableController>(m, "VariableController")
77 .def_static("createVariable",[](const QString &name,
77 // .def_static("createVariable",[](const QString &name,
78 std::shared_ptr<IDataProvider> provider, const DateTimeRange& range){
78 // std::shared_ptr<IDataProvider> provider, const DateTimeRange& range){
79 return sqpApp->variableController().createVariable(name, {{"dataType", "vector"}, {"xml:id", "c1_b"}}, provider, range);
79 // return sqpApp->variableController().createVariable(name, {{"dataType", "vector"}, {"xml:id", "c1_b"}}, provider, range);
80 })
80 // })
81 .def_static("hasPendingDownloads",
81 // .def_static("hasPendingDownloads",
82 [](){return sqpApp->variableController().hasPendingDownloads();}
82 // [](){return sqpApp->variableController().hasPendingDownloads();}
83 )
83 // )
84 .def_static("addSynchronizationGroup",
84 // .def_static("addSynchronizationGroup",
85 [](QUuid uuid){sqpApp->variableController().onAddSynchronizationGroupId(uuid);}
85 // [](QUuid uuid){sqpApp->variableController().onAddSynchronizationGroupId(uuid);}
86 )
86 // )
87 .def_static("removeSynchronizationGroup",
87 // .def_static("removeSynchronizationGroup",
88 [](QUuid uuid){sqpApp->variableController().onRemoveSynchronizationGroupId(uuid);}
88 // [](QUuid uuid){sqpApp->variableController().onRemoveSynchronizationGroupId(uuid);}
89 )
89 // )
90 .def_static("synchronizeVar",
90 // .def_static("synchronizeVar",
91 [](std::shared_ptr<Variable> variable, QUuid uuid){sqpApp->variableController().onAddSynchronized(variable, uuid);}
91 // [](std::shared_ptr<Variable> variable, QUuid uuid){sqpApp->variableController().onAddSynchronized(variable, uuid);}
92 )
92 // )
93 .def_static("deSynchronizeVar",
93 // .def_static("deSynchronizeVar",
94 [](std::shared_ptr<Variable> variable, QUuid uuid){sqpApp->variableController().desynchronize(variable, uuid);}
94 // [](std::shared_ptr<Variable> variable, QUuid uuid){sqpApp->variableController().desynchronize(variable, uuid);}
95 )
95 // )
96 .def_static("deleteVariable",
96 // .def_static("deleteVariable",
97 [](std::shared_ptr<Variable> variable){
97 // [](std::shared_ptr<Variable> variable){
98 sqpApp->variableController().deleteVariable(variable);}
98 // sqpApp->variableController().deleteVariable(variable);}
99 )
99 // )
100 .def_static("update_range",[](std::shared_ptr<Variable> variable, const DateTimeRange &range, bool synchronise){
100 // .def_static("update_range",[](std::shared_ptr<Variable> variable, const DateTimeRange &range, bool synchronise){
101 sqpApp->variableController().onRequestDataLoading({variable}, range, synchronise);
101 // sqpApp->variableController().onRequestDataLoading({variable}, range, synchronise);
102 })
102 // })
103 .def_static("wait_for_downloads",[](){
103 // .def_static("wait_for_downloads",[](){
104 while (sqpApp->variableController().hasPendingDownloads()) {
104 // while (sqpApp->variableController().hasPendingDownloads()) {
105 usleep(100);
105 // usleep(100);
106 }
106 // }
107 });
107 // });
108
108
109 py::class_<TimeController>(m,"TimeController")
109 py::class_<TimeController>(m,"TimeController")
110 .def_static("setTime", [](DateTimeRange range){sqpApp->timeController().setDateTimeRange(range);});
110 .def_static("setTime", [](DateTimeRange range){sqpApp->timeController().setDateTimeRange(range);});
111
111
112
112
113 auto amda_provider = std::make_shared<AmdaProvider>();
113 auto amda_provider = std::make_shared<AmdaProvider>();
114 m.def("amda_provider",[amda_provider](){return amda_provider;}, py::return_value_policy::copy);
114 m.def("amda_provider",[amda_provider](){return amda_provider;}, py::return_value_policy::copy);
115
115
116 py::class_<AmdaProvider, std::shared_ptr<AmdaProvider>, IDataProvider>(m, "AmdaProvider");
116 py::class_<AmdaProvider, std::shared_ptr<AmdaProvider>, IDataProvider>(m, "AmdaProvider");
117
117
118 py::class_<AmdaResultParser>(m, "AmdaResultParser")
118 py::class_<AmdaResultParser>(m, "AmdaResultParser")
119 .def_static("readTxt", AmdaResultParser::readTxt)
119 .def_static("readTxt", AmdaResultParser::readTxt)
120 .def("readScalarTxt", [](const QString& path){
120 .def("readScalarTxt", [](const QString& path){
121 return std::dynamic_pointer_cast<ScalarSeries>(AmdaResultParser::readTxt(path, DataSeriesType::SCALAR));
121 return std::dynamic_pointer_cast<ScalarSeries>(AmdaResultParser::readTxt(path, DataSeriesType::SCALAR));
122 }, py::return_value_policy::copy);
122 }, py::return_value_policy::copy);
123
123
124
124
125 }
125 }
126
126
@@ -1,164 +1,164
1 #include "AmdaProvider.h"
1 #include "AmdaProvider.h"
2 #include "AmdaResultParser.h"
2 #include "AmdaResultParser.h"
3
3
4 #include "SqpApplication.h"
4 #include "SqpApplication.h"
5 #include <Data/DataSeries.h>
5 #include <Data/DataSeries.h>
6 #include <Data/IDataSeries.h>
6 #include <Data/IDataSeries.h>
7 #include <Data/ScalarSeries.h>
7 #include <Data/ScalarSeries.h>
8 #include <Time/TimeController.h>
8 #include <Time/TimeController.h>
9 #include <Variable/Variable.h>
9 #include <Variable/Variable.h>
10 #include <Variable/VariableController.h>
10 #include <Variable/VariableController2.h>
11
11
12 #include <QObject>
12 #include <QObject>
13 #include <QtTest>
13 #include <QtTest>
14
14
15 #include <memory>
15 #include <memory>
16
16
17 // TEST with REF:
17 // TEST with REF:
18 // AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00
18 // AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00
19 // imf(0) - Type : Local Parameter @ CDPP/AMDA -
19 // imf(0) - Type : Local Parameter @ CDPP/AMDA -
20 // Name : bx_gse - Units : nT - Size : 1 -
20 // Name : bx_gse - Units : nT - Size : 1 -
21 // Frame : GSE - Mission : ACE -
21 // Frame : GSE - Mission : ACE -
22 // Instrument : MFI - Dataset : mfi_final-prelim
22 // Instrument : MFI - Dataset : mfi_final-prelim
23 // REFERENCE DOWNLOAD FILE =
23 // REFERENCE DOWNLOAD FILE =
24 // http://amdatest.irap.omp.eu/php/rest/getParameter.php?startTime=2012-01-01T12:00:00&stopTime=2012-01-03T12:00:00&parameterID=imf(0)&outputFormat=ASCII&timeFormat=ISO8601&gzip=0
24 // http://amdatest.irap.omp.eu/php/rest/getParameter.php?startTime=2012-01-01T12:00:00&stopTime=2012-01-03T12:00:00&parameterID=imf(0)&outputFormat=ASCII&timeFormat=ISO8601&gzip=0
25
25
26 namespace {
26 namespace {
27
27
28 /// Path for the tests
28 /// Path for the tests
29 const auto TESTS_RESOURCES_PATH
29 const auto TESTS_RESOURCES_PATH
30 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaAcquisition"}.absoluteFilePath();
30 = QFileInfo{QString{AMDA_TESTS_RESOURCES_DIR}, "TestAmdaAcquisition"}.absoluteFilePath();
31
31
32 /// Delay after each operation on the variable before validating it (in ms)
32 /// Delay after each operation on the variable before validating it (in ms)
33 const auto OPERATION_DELAY = 10000;
33 const auto OPERATION_DELAY = 10000;
34
34
35 template <typename T>
35 template <typename T>
36 bool compareDataSeries(std::shared_ptr<IDataSeries> candidate, DateTimeRange candidateCacheRange,
36 bool compareDataSeries(std::shared_ptr<IDataSeries> candidate, DateTimeRange candidateCacheRange,
37 std::shared_ptr<IDataSeries> reference)
37 std::shared_ptr<IDataSeries> reference)
38 {
38 {
39 auto compareLambda = [](const auto &it1, const auto &it2) {
39 auto compareLambda = [](const auto &it1, const auto &it2) {
40 return (it1.x() == it2.x()) && (it1.value() == it2.value());
40 return (it1.x() == it2.x()) && (it1.value() == it2.value());
41 };
41 };
42
42
43 auto candidateDS = std::dynamic_pointer_cast<T>(candidate);
43 auto candidateDS = std::dynamic_pointer_cast<T>(candidate);
44 auto referenceDS = std::dynamic_pointer_cast<T>(reference);
44 auto referenceDS = std::dynamic_pointer_cast<T>(reference);
45
45
46 if (candidateDS && referenceDS) {
46 if (candidateDS && referenceDS) {
47
47
48 auto itRefs
48 auto itRefs
49 = referenceDS->xAxisRange(candidateCacheRange.m_TStart, candidateCacheRange.m_TEnd);
49 = referenceDS->xAxisRange(candidateCacheRange.m_TStart, candidateCacheRange.m_TEnd);
50 qDebug() << " DISTANCE" << std::distance(candidateDS->cbegin(), candidateDS->cend())
50 qDebug() << " DISTANCE" << std::distance(candidateDS->cbegin(), candidateDS->cend())
51 << std::distance(itRefs.first, itRefs.second);
51 << std::distance(itRefs.first, itRefs.second);
52
52
53 return std::equal(candidateDS->cbegin(), candidateDS->cend(), itRefs.first, itRefs.second,
53 return std::equal(candidateDS->cbegin(), candidateDS->cend(), itRefs.first, itRefs.second,
54 compareLambda);
54 compareLambda);
55 }
55 }
56 else {
56 else {
57 return false;
57 return false;
58 }
58 }
59 }
59 }
60 }
60 }
61
61
62 class TestAmdaAcquisition : public QObject {
62 class TestAmdaAcquisition : public QObject {
63 Q_OBJECT
63 Q_OBJECT
64
64
65 private slots:
65 private slots:
66 /// Input data for @sa testAcquisition()
66 /// Input data for @sa testAcquisition()
67 void testAcquisition_data();
67 void testAcquisition_data();
68 void testAcquisition();
68 void testAcquisition();
69 };
69 };
70
70
71 void TestAmdaAcquisition::testAcquisition_data()
71 void TestAmdaAcquisition::testAcquisition_data()
72 {
72 {
73 // ////////////// //
73 // ////////////// //
74 // Test structure //
74 // Test structure //
75 // ////////////// //
75 // ////////////// //
76
76
77 QTest::addColumn<QString>("dataFilename"); // File containing expected data of acquisitions
77 QTest::addColumn<QString>("dataFilename"); // File containing expected data of acquisitions
78 QTest::addColumn<DateTimeRange>("initialRange"); // First acquisition
78 QTest::addColumn<DateTimeRange>("initialRange"); // First acquisition
79 QTest::addColumn<std::vector<DateTimeRange> >("operations"); // Acquisitions to make
79 QTest::addColumn<std::vector<DateTimeRange> >("operations"); // Acquisitions to make
80
80
81 // ////////// //
81 // ////////// //
82 // Test cases //
82 // Test cases //
83 // ////////// //
83 // ////////// //
84
84
85 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
85 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
86 return DateUtils::secondsSinceEpoch(
86 return DateUtils::secondsSinceEpoch(
87 QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC});
87 QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC});
88 };
88 };
89
89
90
90
91 QTest::newRow("amda")
91 QTest::newRow("amda")
92 << "AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00.txt"
92 << "AmdaData-2012-01-01-12-00-00_2012-01-03-12-00-00.txt"
93 << DateTimeRange{dateTime(2012, 1, 2, 2, 3, 0), dateTime(2012, 1, 2, 2, 4, 0)}
93 << DateTimeRange{dateTime(2012, 1, 2, 2, 3, 0), dateTime(2012, 1, 2, 2, 4, 0)}
94 << std::vector<DateTimeRange>{
94 << std::vector<DateTimeRange>{
95 // 2 : pan (jump) left for two min
95 // 2 : pan (jump) left for two min
96 DateTimeRange{dateTime(2012, 1, 2, 2, 1, 0), dateTime(2012, 1, 2, 2, 2, 0)},
96 DateTimeRange{dateTime(2012, 1, 2, 2, 1, 0), dateTime(2012, 1, 2, 2, 2, 0)},
97 // 3 : pan (jump) right for four min
97 // 3 : pan (jump) right for four min
98 DateTimeRange{dateTime(2012, 1, 2, 2, 5, 0), dateTime(2012, 1, 2, 2, 6, 0)},
98 DateTimeRange{dateTime(2012, 1, 2, 2, 5, 0), dateTime(2012, 1, 2, 2, 6, 0)},
99 // 4 : pan (overlay) right for 30 sec
99 // 4 : pan (overlay) right for 30 sec
100 /*SqpRange{dateTime(2012, 1, 2, 2, 5, 30), dateTime(2012, 1, 2, 2, 6, 30)},
100 /*SqpRange{dateTime(2012, 1, 2, 2, 5, 30), dateTime(2012, 1, 2, 2, 6, 30)},
101 // 5 : pan (overlay) left for 30 sec
101 // 5 : pan (overlay) left for 30 sec
102 SqpRange{dateTime(2012, 1, 2, 2, 5, 0), dateTime(2012, 1, 2, 2, 6, 0)},
102 SqpRange{dateTime(2012, 1, 2, 2, 5, 0), dateTime(2012, 1, 2, 2, 6, 0)},
103 // 6 : pan (overlay) left for 30 sec - BIS
103 // 6 : pan (overlay) left for 30 sec - BIS
104 SqpRange{dateTime(2012, 1, 2, 2, 4, 30), dateTime(2012, 1, 2, 2, 5, 30)},
104 SqpRange{dateTime(2012, 1, 2, 2, 4, 30), dateTime(2012, 1, 2, 2, 5, 30)},
105 // 7 : Zoom in Inside 20 sec range
105 // 7 : Zoom in Inside 20 sec range
106 SqpRange{dateTime(2012, 1, 2, 2, 4, 50), dateTime(2012, 1, 2, 2, 5, 10)},
106 SqpRange{dateTime(2012, 1, 2, 2, 4, 50), dateTime(2012, 1, 2, 2, 5, 10)},
107 // 8 : Zoom out Inside 20 sec range
107 // 8 : Zoom out Inside 20 sec range
108 SqpRange{dateTime(2012, 1, 2, 2, 4, 30), dateTime(2012, 1, 2, 2, 5, 30)}*/};
108 SqpRange{dateTime(2012, 1, 2, 2, 4, 30), dateTime(2012, 1, 2, 2, 5, 30)}*/};
109 }
109 }
110
110
111 void TestAmdaAcquisition::testAcquisition()
111 void TestAmdaAcquisition::testAcquisition()
112 {
112 {
113 /// @todo: update test to be compatible with AMDA v2
113 /// @todo: update test to be compatible with AMDA v2
114
114
115 // Retrieves data file
115 // Retrieves data file
116 QFETCH(QString, dataFilename);
116 QFETCH(QString, dataFilename);
117 auto filePath = QFileInfo{TESTS_RESOURCES_PATH, dataFilename}.absoluteFilePath();
117 auto filePath = QFileInfo{TESTS_RESOURCES_PATH, dataFilename}.absoluteFilePath();
118 auto results = AmdaResultParser::readTxt(filePath, DataSeriesType::SCALAR);
118 auto results = AmdaResultParser::readTxt(filePath, DataSeriesType::SCALAR);
119
119
120 /// Lambda used to validate a variable at each step
120 /// Lambda used to validate a variable at each step
121 auto validateVariable = [results](std::shared_ptr<Variable> variable, const DateTimeRange &range) {
121 auto validateVariable = [results](std::shared_ptr<Variable> variable, const DateTimeRange &range) {
122 // Checks that the variable's range has changed
122 // Checks that the variable's range has changed
123 qInfo() << tr("Compare var range vs range") << variable->range() << range;
123 qInfo() << tr("Compare var range vs range") << variable->range() << range;
124 QCOMPARE(variable->range(), range);
124 QCOMPARE(variable->range(), range);
125
125
126 // Checks the variable's data series
126 // Checks the variable's data series
127 QVERIFY(compareDataSeries<ScalarSeries>(variable->dataSeries(), variable->cacheRange(),
127 QVERIFY(compareDataSeries<ScalarSeries>(variable->dataSeries(), variable->cacheRange(),
128 results));
128 results));
129 qInfo() << "\n";
129 qInfo() << "\n";
130 };
130 };
131
131
132 // Creates variable
132 // Creates variable
133 QFETCH(DateTimeRange, initialRange);
133 QFETCH(DateTimeRange, initialRange);
134 sqpApp->timeController().setDateTimeRange(initialRange);
134 sqpApp->timeController().setDateTimeRange(initialRange);
135 auto provider = std::make_shared<AmdaProvider>();
135 auto provider = std::make_shared<AmdaProvider>();
136 auto variable = sqpApp->variableController().createVariable(
136 auto variable = sqpApp->variableController().createVariable(
137 "bx_gse", {{"dataType", "scalar"}, {"xml:id", "imf(0)"}}, provider, initialRange);
137 "bx_gse", {{"dataType", "scalar"}, {"xml:id", "imf(0)"}}, provider, initialRange);
138
138
139 QTest::qWait(OPERATION_DELAY);
139 QTest::qWait(OPERATION_DELAY);
140 validateVariable(variable, initialRange);
140 validateVariable(variable, initialRange);
141
141
142 // Makes operations on the variable
142 // Makes operations on the variable
143 QFETCH(std::vector<DateTimeRange>, operations);
143 QFETCH(std::vector<DateTimeRange>, operations);
144 for (const auto &operation : operations) {
144 for (const auto &operation : operations) {
145 // Asks request on the variable and waits during its execution
145 // Asks request on the variable and waits during its execution
146 sqpApp->variableController().onRequestDataLoading({variable}, operation, false);
146 sqpApp->variableController().changeRange({variable}, operation);
147
147
148 QTest::qWait(OPERATION_DELAY);
148 QTest::qWait(OPERATION_DELAY);
149 validateVariable(variable, operation);
149 validateVariable(variable, operation);
150 }
150 }
151 }
151 }
152
152
153 int main(int argc, char *argv[])
153 int main(int argc, char *argv[])
154 {
154 {
155 SqpApplication app(argc, argv);
155 SqpApplication app(argc, argv);
156 app.setAttribute(Qt::AA_Use96Dpi, true);
156 app.setAttribute(Qt::AA_Use96Dpi, true);
157 TestAmdaAcquisition tc;
157 TestAmdaAcquisition tc;
158 QTEST_SET_MAIN_SOURCE_PATH
158 QTEST_SET_MAIN_SOURCE_PATH
159 return QTest::qExec(&tc, argc, argv);
159 return QTest::qExec(&tc, argc, argv);
160 }
160 }
161
161
162 // QTEST_MAIN(TestAmdaAcquisition)
162 // QTEST_MAIN(TestAmdaAcquisition)
163
163
164 #include "TestAmdaAcquisition.moc"
164 #include "TestAmdaAcquisition.moc"
@@ -1,395 +1,395
1 #include "FuzzingDefs.h"
1 #include "FuzzingDefs.h"
2 #include "FuzzingOperations.h"
2 #include "FuzzingOperations.h"
3 #include "FuzzingUtils.h"
3 #include "FuzzingUtils.h"
4 #include "FuzzingValidators.h"
4 #include "FuzzingValidators.h"
5
5
6 #include "AmdaProvider.h"
6 #include "AmdaProvider.h"
7
7
8 #include <Common/SignalWaiter.h>
8 #include <Common/SignalWaiter.h>
9 #include <Network/NetworkController.h>
9 #include <Network/NetworkController.h>
10 #include <Settings/SqpSettingsDefs.h>
10 #include <Settings/SqpSettingsDefs.h>
11 #include <SqpApplication.h>
11 #include <SqpApplication.h>
12 #include <Time/TimeController.h>
12 #include <Time/TimeController.h>
13 #include <Variable/Variable.h>
13 #include <Variable/Variable.h>
14 #include <Variable/VariableController.h>
14 #include <Variable/VariableController2.h>
15
15
16 #include <QLoggingCategory>
16 #include <QLoggingCategory>
17 #include <QObject>
17 #include <QObject>
18 #include <QtTest>
18 #include <QtTest>
19
19
20 #include <memory>
20 #include <memory>
21
21
22 Q_LOGGING_CATEGORY(LOG_TestAmdaFuzzing, "TestAmdaFuzzing")
22 Q_LOGGING_CATEGORY(LOG_TestAmdaFuzzing, "TestAmdaFuzzing")
23
23
24 /**
24 /**
25 * Macro used to generate a getter for a property in @sa FuzzingTest. The macro generates a static
25 * Macro used to generate a getter for a property in @sa FuzzingTest. The macro generates a static
26 * attribute that is initialized by searching in properties the property and use a default value if
26 * attribute that is initialized by searching in properties the property and use a default value if
27 * it's not present. Macro arguments are:
27 * it's not present. Macro arguments are:
28 * - GETTER_NAME : name of the getter
28 * - GETTER_NAME : name of the getter
29 * - PROPERTY_NAME: used to generate constants for property's name ({PROPERTY_NAME}_PROPERTY) and
29 * - PROPERTY_NAME: used to generate constants for property's name ({PROPERTY_NAME}_PROPERTY) and
30 * default value ({PROPERTY_NAME}_DEFAULT_VALUE)
30 * default value ({PROPERTY_NAME}_DEFAULT_VALUE)
31 * - TYPE : return type of the getter
31 * - TYPE : return type of the getter
32 */
32 */
33 // clang-format off
33 // clang-format off
34 #define DECLARE_PROPERTY_GETTER(GETTER_NAME, PROPERTY_NAME, TYPE) \
34 #define DECLARE_PROPERTY_GETTER(GETTER_NAME, PROPERTY_NAME, TYPE) \
35 TYPE GETTER_NAME() const \
35 TYPE GETTER_NAME() const \
36 { \
36 { \
37 static auto result = m_Properties.value(PROPERTY_NAME##_PROPERTY, PROPERTY_NAME##_DEFAULT_VALUE).value<TYPE>(); \
37 static auto result = m_Properties.value(PROPERTY_NAME##_PROPERTY, PROPERTY_NAME##_DEFAULT_VALUE).value<TYPE>(); \
38 return result; \
38 return result; \
39 } \
39 } \
40 // clang-format on
40 // clang-format on
41
41
42 namespace {
42 namespace {
43
43
44 // /////// //
44 // /////// //
45 // Aliases //
45 // Aliases //
46 // /////// //
46 // /////// //
47
47
48 using IntPair = std::pair<int, int>;
48 using IntPair = std::pair<int, int>;
49 using Weight = double;
49 using Weight = double;
50 using Weights = std::vector<Weight>;
50 using Weights = std::vector<Weight>;
51
51
52 struct OperationProperty {
52 struct OperationProperty {
53 Weight m_Weight{1.};
53 Weight m_Weight{1.};
54 bool m_WaitAcquisition{false};
54 bool m_WaitAcquisition{false};
55 };
55 };
56
56
57 using VariableOperation = std::pair<VariableId, std::shared_ptr<IFuzzingOperation> >;
57 using VariableOperation = std::pair<VariableId, std::shared_ptr<IFuzzingOperation> >;
58 using VariablesOperations = std::vector<VariableOperation>;
58 using VariablesOperations = std::vector<VariableOperation>;
59
59
60 using OperationsTypes = std::map<FuzzingOperationType, OperationProperty>;
60 using OperationsTypes = std::map<FuzzingOperationType, OperationProperty>;
61 using OperationsPool = std::map<std::shared_ptr<IFuzzingOperation>, OperationProperty>;
61 using OperationsPool = std::map<std::shared_ptr<IFuzzingOperation>, OperationProperty>;
62
62
63 using Validators = std::vector<std::shared_ptr<IFuzzingValidator> >;
63 using Validators = std::vector<std::shared_ptr<IFuzzingValidator> >;
64
64
65 // ///////// //
65 // ///////// //
66 // Constants //
66 // Constants //
67 // ///////// //
67 // ///////// //
68
68
69 // Defaults values used when the associated properties have not been set for the test
69 // Defaults values used when the associated properties have not been set for the test
70 const auto ACQUISITION_TIMEOUT_DEFAULT_VALUE = 30000;
70 const auto ACQUISITION_TIMEOUT_DEFAULT_VALUE = 30000;
71 const auto NB_MAX_OPERATIONS_DEFAULT_VALUE = 100;
71 const auto NB_MAX_OPERATIONS_DEFAULT_VALUE = 100;
72 const auto NB_MAX_SYNC_GROUPS_DEFAULT_VALUE = 1;
72 const auto NB_MAX_SYNC_GROUPS_DEFAULT_VALUE = 1;
73 const auto NB_MAX_VARIABLES_DEFAULT_VALUE = 1;
73 const auto NB_MAX_VARIABLES_DEFAULT_VALUE = 1;
74 const auto AVAILABLE_OPERATIONS_DEFAULT_VALUE = QVariant::fromValue(
74 const auto AVAILABLE_OPERATIONS_DEFAULT_VALUE = QVariant::fromValue(
75 OperationsTypes{{FuzzingOperationType::CREATE, {1., true}},
75 OperationsTypes{{FuzzingOperationType::CREATE, {1., true}},
76 {FuzzingOperationType::DELETE, {0.1}}, // Delete operation is less frequent
76 {FuzzingOperationType::DELETE, {0.1}}, // Delete operation is less frequent
77 {FuzzingOperationType::PAN_LEFT, {1.}},
77 {FuzzingOperationType::PAN_LEFT, {1.}},
78 {FuzzingOperationType::PAN_RIGHT, {1.}},
78 {FuzzingOperationType::PAN_RIGHT, {1.}},
79 {FuzzingOperationType::ZOOM_IN, {1.}},
79 {FuzzingOperationType::ZOOM_IN, {1.}},
80 {FuzzingOperationType::ZOOM_OUT, {1.}},
80 {FuzzingOperationType::ZOOM_OUT, {1.}},
81 {FuzzingOperationType::SYNCHRONIZE, {0.8}},
81 {FuzzingOperationType::SYNCHRONIZE, {0.8}},
82 {FuzzingOperationType::DESYNCHRONIZE, {0.4}}});
82 {FuzzingOperationType::DESYNCHRONIZE, {0.4}}});
83 const auto CACHE_TOLERANCE_DEFAULT_VALUE = 0.2;
83 const auto CACHE_TOLERANCE_DEFAULT_VALUE = 0.2;
84
84
85 /// Min/max delays between each operation (in ms)
85 /// Min/max delays between each operation (in ms)
86 const auto OPERATION_DELAY_BOUNDS_DEFAULT_VALUE = QVariant::fromValue(std::make_pair(100, 3000));
86 const auto OPERATION_DELAY_BOUNDS_DEFAULT_VALUE = QVariant::fromValue(std::make_pair(100, 3000));
87
87
88 /// Validators for the tests (executed in the order in which they're defined)
88 /// Validators for the tests (executed in the order in which they're defined)
89 const auto VALIDATORS_DEFAULT_VALUE = QVariant::fromValue(
89 const auto VALIDATORS_DEFAULT_VALUE = QVariant::fromValue(
90 ValidatorsTypes{{FuzzingValidatorType::RANGE, FuzzingValidatorType::DATA}});
90 ValidatorsTypes{{FuzzingValidatorType::RANGE, FuzzingValidatorType::DATA}});
91
91
92 /// Min/max number of operations to execute before calling validation
92 /// Min/max number of operations to execute before calling validation
93 const auto VALIDATION_FREQUENCY_BOUNDS_DEFAULT_VALUE = QVariant::fromValue(std::make_pair(1, 10));
93 const auto VALIDATION_FREQUENCY_BOUNDS_DEFAULT_VALUE = QVariant::fromValue(std::make_pair(1, 10));
94
94
95 // /////// //
95 // /////// //
96 // Methods //
96 // Methods //
97 // /////// //
97 // /////// //
98
98
99 /// Goes through the variables pool and operations pool to determine the set of {variable/operation}
99 /// Goes through the variables pool and operations pool to determine the set of {variable/operation}
100 /// pairs that are valid (i.e. operation that can be executed on variable)
100 /// pairs that are valid (i.e. operation that can be executed on variable)
101 std::pair<VariablesOperations, Weights> availableOperations(const FuzzingState &fuzzingState,
101 std::pair<VariablesOperations, Weights> availableOperations(const FuzzingState &fuzzingState,
102 const OperationsPool &operationsPool)
102 const OperationsPool &operationsPool)
103 {
103 {
104 VariablesOperations result{};
104 VariablesOperations result{};
105 Weights weights{};
105 Weights weights{};
106
106
107 for (const auto &variablesPoolEntry : fuzzingState.m_VariablesPool) {
107 for (const auto &variablesPoolEntry : fuzzingState.m_VariablesPool) {
108 auto variableId = variablesPoolEntry.first;
108 auto variableId = variablesPoolEntry.first;
109
109
110 for (const auto &operationsPoolEntry : operationsPool) {
110 for (const auto &operationsPoolEntry : operationsPool) {
111 auto operation = operationsPoolEntry.first;
111 auto operation = operationsPoolEntry.first;
112 auto operationProperty = operationsPoolEntry.second;
112 auto operationProperty = operationsPoolEntry.second;
113
113
114 // A pair is valid if the current operation can be executed on the current variable
114 // A pair is valid if the current operation can be executed on the current variable
115 if (operation->canExecute(variableId, fuzzingState)) {
115 if (operation->canExecute(variableId, fuzzingState)) {
116 result.push_back({variableId, operation});
116 result.push_back({variableId, operation});
117 weights.push_back(operationProperty.m_Weight);
117 weights.push_back(operationProperty.m_Weight);
118 }
118 }
119 }
119 }
120 }
120 }
121
121
122 return {result, weights};
122 return {result, weights};
123 }
123 }
124
124
125 OperationsPool createOperationsPool(const OperationsTypes &types)
125 OperationsPool createOperationsPool(const OperationsTypes &types)
126 {
126 {
127 OperationsPool result{};
127 OperationsPool result{};
128
128
129 std::transform(
129 std::transform(
130 types.cbegin(), types.cend(), std::inserter(result, result.end()), [](const auto &type) {
130 types.cbegin(), types.cend(), std::inserter(result, result.end()), [](const auto &type) {
131 return std::make_pair(FuzzingOperationFactory::create(type.first), type.second);
131 return std::make_pair(FuzzingOperationFactory::create(type.first), type.second);
132 });
132 });
133
133
134 return result;
134 return result;
135 }
135 }
136
136
137 Validators createValidators(const ValidatorsTypes &types)
137 Validators createValidators(const ValidatorsTypes &types)
138 {
138 {
139 Validators result{};
139 Validators result{};
140
140
141 std::transform(types.cbegin(), types.cend(), std::inserter(result, result.end()),
141 std::transform(types.cbegin(), types.cend(), std::inserter(result, result.end()),
142 [](const auto &type) { return FuzzingValidatorFactory::create(type); });
142 [](const auto &type) { return FuzzingValidatorFactory::create(type); });
143
143
144 return result;
144 return result;
145 }
145 }
146
146
147 /**
147 /**
148 * Validates all the variables' states passed in parameter, according to a set of validators
148 * Validates all the variables' states passed in parameter, according to a set of validators
149 * @param variablesPool the variables' states
149 * @param variablesPool the variables' states
150 * @param validators the validators used for validation
150 * @param validators the validators used for validation
151 */
151 */
152 void validate(const VariablesPool &variablesPool, const Validators &validators)
152 void validate(const VariablesPool &variablesPool, const Validators &validators)
153 {
153 {
154 for (const auto &variablesPoolEntry : variablesPool) {
154 for (const auto &variablesPoolEntry : variablesPool) {
155 auto variableId = variablesPoolEntry.first;
155 auto variableId = variablesPoolEntry.first;
156 const auto &variableState = variablesPoolEntry.second;
156 const auto &variableState = variablesPoolEntry.second;
157
157
158 auto variableMessage = variableState.m_Variable ? variableState.m_Variable->name()
158 auto variableMessage = variableState.m_Variable ? variableState.m_Variable->name()
159 : QStringLiteral("null variable");
159 : QStringLiteral("null variable");
160 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validating state of variable at index"
160 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validating state of variable at index"
161 << variableId << "(" << variableMessage << ")...";
161 << variableId << "(" << variableMessage << ")...";
162
162
163 for (const auto &validator : validators) {
163 for (const auto &validator : validators) {
164 validator->validate(VariableState{variableState});
164 validator->validate(VariableState{variableState});
165 }
165 }
166
166
167 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validation completed.";
167 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Validation completed.";
168 }
168 }
169 }
169 }
170
170
171 /**
171 /**
172 * Class to run random tests
172 * Class to run random tests
173 */
173 */
174 class FuzzingTest {
174 class FuzzingTest {
175 public:
175 public:
176 explicit FuzzingTest(VariableController &variableController, Properties properties)
176 explicit FuzzingTest(VariableController2 &variableController, Properties properties)
177 : m_VariableController{variableController},
177 : m_VariableController{variableController},
178 m_Properties{std::move(properties)},
178 m_Properties{std::move(properties)},
179 m_FuzzingState{}
179 m_FuzzingState{}
180 {
180 {
181 // Inits variables pool: at init, all variables are null
181 // Inits variables pool: at init, all variables are null
182 for (auto variableId = 0; variableId < nbMaxVariables(); ++variableId) {
182 for (auto variableId = 0; variableId < nbMaxVariables(); ++variableId) {
183 m_FuzzingState.m_VariablesPool[variableId] = VariableState{};
183 m_FuzzingState.m_VariablesPool[variableId] = VariableState{};
184 }
184 }
185
185
186 // Inits sync groups and registers them into the variable controller
186 // Inits sync groups and registers them into the variable controller
187 for (auto i = 0; i < nbMaxSyncGroups(); ++i) {
187 for (auto i = 0; i < nbMaxSyncGroups(); ++i) {
188 auto syncGroupId = SyncGroupId::createUuid();
188 auto syncGroupId = SyncGroupId::createUuid();
189 variableController.onAddSynchronizationGroupId(syncGroupId);
189 //variableController.onAddSynchronizationGroupId(syncGroupId);
190 m_FuzzingState.m_SyncGroupsPool[syncGroupId] = SyncGroup{};
190 m_FuzzingState.m_SyncGroupsPool[syncGroupId] = SyncGroup{};
191 }
191 }
192 }
192 }
193
193
194 void execute()
194 void execute()
195 {
195 {
196 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Running" << nbMaxOperations() << "operations on"
196 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Running" << nbMaxOperations() << "operations on"
197 << nbMaxVariables() << "variable(s)...";
197 << nbMaxVariables() << "variable(s)...";
198
198
199
199
200 // Inits the count of the number of operations before the next validation
200 // Inits the count of the number of operations before the next validation
201 int nextValidationCounter = 0;
201 int nextValidationCounter = 0;
202 auto updateValidationCounter = [this, &nextValidationCounter]() {
202 auto updateValidationCounter = [this, &nextValidationCounter]() {
203 nextValidationCounter = RandomGenerator::instance().generateInt(
203 nextValidationCounter = RandomGenerator::instance().generateInt(
204 validationFrequencies().first, validationFrequencies().second);
204 validationFrequencies().first, validationFrequencies().second);
205 qCInfo(LOG_TestAmdaFuzzing()).noquote()
205 qCInfo(LOG_TestAmdaFuzzing()).noquote()
206 << "Next validation in " << nextValidationCounter << "operation(s)...";
206 << "Next validation in " << nextValidationCounter << "operation(s)...";
207 };
207 };
208 updateValidationCounter();
208 updateValidationCounter();
209
209
210 auto canExecute = true;
210 auto canExecute = true;
211 for (auto i = 0; i < nbMaxOperations() && canExecute; ++i) {
211 for (auto i = 0; i < nbMaxOperations() && canExecute; ++i) {
212 // Retrieves all operations that can be executed in the current context
212 // Retrieves all operations that can be executed in the current context
213 VariablesOperations variableOperations{};
213 VariablesOperations variableOperations{};
214 Weights weights{};
214 Weights weights{};
215 std::tie(variableOperations, weights)
215 std::tie(variableOperations, weights)
216 = availableOperations(m_FuzzingState, operationsPool());
216 = availableOperations(m_FuzzingState, operationsPool());
217
217
218 canExecute = !variableOperations.empty();
218 canExecute = !variableOperations.empty();
219 if (canExecute) {
219 if (canExecute) {
220 --nextValidationCounter;
220 --nextValidationCounter;
221
221
222 // Of the operations available, chooses a random operation and executes it
222 // Of the operations available, chooses a random operation and executes it
223 auto variableOperation
223 auto variableOperation
224 = RandomGenerator::instance().randomChoice(variableOperations, weights);
224 = RandomGenerator::instance().randomChoice(variableOperations, weights);
225
225
226 auto variableId = variableOperation.first;
226 auto variableId = variableOperation.first;
227 auto fuzzingOperation = variableOperation.second;
227 auto fuzzingOperation = variableOperation.second;
228
228
229 auto waitAcquisition = nextValidationCounter == 0
229 auto waitAcquisition = nextValidationCounter == 0
230 || operationsPool().at(fuzzingOperation).m_WaitAcquisition;
230 || operationsPool().at(fuzzingOperation).m_WaitAcquisition;
231
231
232 fuzzingOperation->execute(variableId, m_FuzzingState, m_VariableController,
232 // fuzzingOperation->execute(variableId, m_FuzzingState, m_VariableController,
233 m_Properties);
233 // m_Properties);
234
234
235 if (waitAcquisition) {
235 if (waitAcquisition) {
236 qCDebug(LOG_TestAmdaFuzzing()) << "Waiting for acquisition to finish...";
236 qCDebug(LOG_TestAmdaFuzzing()) << "Waiting for acquisition to finish...";
237 SignalWaiter{m_VariableController, SIGNAL(acquisitionFinished())}.wait(
237 SignalWaiter{m_VariableController, SIGNAL(acquisitionFinished())}.wait(
238 acquisitionTimeout());
238 acquisitionTimeout());
239
239
240 // Validates variables
240 // Validates variables
241 if (nextValidationCounter == 0) {
241 if (nextValidationCounter == 0) {
242 validate(m_FuzzingState.m_VariablesPool, validators());
242 validate(m_FuzzingState.m_VariablesPool, validators());
243 updateValidationCounter();
243 updateValidationCounter();
244 }
244 }
245 }
245 }
246 else {
246 else {
247 // Delays the next operation with a randomly generated time
247 // Delays the next operation with a randomly generated time
248 auto delay = RandomGenerator::instance().generateInt(operationDelays().first,
248 auto delay = RandomGenerator::instance().generateInt(operationDelays().first,
249 operationDelays().second);
249 operationDelays().second);
250 qCDebug(LOG_TestAmdaFuzzing())
250 qCDebug(LOG_TestAmdaFuzzing())
251 << "Waiting " << delay << "ms before the next operation...";
251 << "Waiting " << delay << "ms before the next operation...";
252 QTest::qWait(delay);
252 QTest::qWait(delay);
253 }
253 }
254 }
254 }
255 else {
255 else {
256 qCInfo(LOG_TestAmdaFuzzing()).noquote()
256 qCInfo(LOG_TestAmdaFuzzing()).noquote()
257 << "No more operations are available, the execution of the test will stop...";
257 << "No more operations are available, the execution of the test will stop...";
258 }
258 }
259 }
259 }
260
260
261 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Execution of the test completed.";
261 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Execution of the test completed.";
262 }
262 }
263
263
264 private:
264 private:
265 OperationsPool operationsPool() const
265 OperationsPool operationsPool() const
266 {
266 {
267 static auto result = createOperationsPool(
267 static auto result = createOperationsPool(
268 m_Properties.value(AVAILABLE_OPERATIONS_PROPERTY, AVAILABLE_OPERATIONS_DEFAULT_VALUE)
268 m_Properties.value(AVAILABLE_OPERATIONS_PROPERTY, AVAILABLE_OPERATIONS_DEFAULT_VALUE)
269 .value<OperationsTypes>());
269 .value<OperationsTypes>());
270 return result;
270 return result;
271 }
271 }
272
272
273 Validators validators() const
273 Validators validators() const
274 {
274 {
275 static auto result
275 static auto result
276 = createValidators(m_Properties.value(VALIDATORS_PROPERTY, VALIDATORS_DEFAULT_VALUE)
276 = createValidators(m_Properties.value(VALIDATORS_PROPERTY, VALIDATORS_DEFAULT_VALUE)
277 .value<ValidatorsTypes>());
277 .value<ValidatorsTypes>());
278 return result;
278 return result;
279 }
279 }
280
280
281 DECLARE_PROPERTY_GETTER(nbMaxOperations, NB_MAX_OPERATIONS, int)
281 DECLARE_PROPERTY_GETTER(nbMaxOperations, NB_MAX_OPERATIONS, int)
282 DECLARE_PROPERTY_GETTER(nbMaxSyncGroups, NB_MAX_SYNC_GROUPS, int)
282 DECLARE_PROPERTY_GETTER(nbMaxSyncGroups, NB_MAX_SYNC_GROUPS, int)
283 DECLARE_PROPERTY_GETTER(nbMaxVariables, NB_MAX_VARIABLES, int)
283 DECLARE_PROPERTY_GETTER(nbMaxVariables, NB_MAX_VARIABLES, int)
284 DECLARE_PROPERTY_GETTER(operationDelays, OPERATION_DELAY_BOUNDS, IntPair)
284 DECLARE_PROPERTY_GETTER(operationDelays, OPERATION_DELAY_BOUNDS, IntPair)
285 DECLARE_PROPERTY_GETTER(validationFrequencies, VALIDATION_FREQUENCY_BOUNDS, IntPair)
285 DECLARE_PROPERTY_GETTER(validationFrequencies, VALIDATION_FREQUENCY_BOUNDS, IntPair)
286 DECLARE_PROPERTY_GETTER(acquisitionTimeout, ACQUISITION_TIMEOUT, int)
286 DECLARE_PROPERTY_GETTER(acquisitionTimeout, ACQUISITION_TIMEOUT, int)
287
287
288 VariableController &m_VariableController;
288 VariableController2 &m_VariableController;
289 Properties m_Properties;
289 Properties m_Properties;
290 FuzzingState m_FuzzingState;
290 FuzzingState m_FuzzingState;
291 };
291 };
292
292
293 } // namespace
293 } // namespace
294
294
295 Q_DECLARE_METATYPE(OperationsTypes)
295 Q_DECLARE_METATYPE(OperationsTypes)
296
296
297 class TestAmdaFuzzing : public QObject {
297 class TestAmdaFuzzing : public QObject {
298 Q_OBJECT
298 Q_OBJECT
299
299
300 private slots:
300 private slots:
301 /// Input data for @sa testFuzzing()
301 /// Input data for @sa testFuzzing()
302 void testFuzzing_data();
302 void testFuzzing_data();
303 void testFuzzing();
303 void testFuzzing();
304 };
304 };
305
305
306 void TestAmdaFuzzing::testFuzzing_data()
306 void TestAmdaFuzzing::testFuzzing_data()
307 {
307 {
308 // Note: Comment this line to run fuzzing tests
308 // Note: Comment this line to run fuzzing tests
309 QSKIP("Fuzzing tests are disabled by default");
309 QSKIP("Fuzzing tests are disabled by default");
310
310
311 // ////////////// //
311 // ////////////// //
312 // Test structure //
312 // Test structure //
313 // ////////////// //
313 // ////////////// //
314
314
315 QTest::addColumn<Properties>("properties"); // Properties for random test
315 QTest::addColumn<Properties>("properties"); // Properties for random test
316
316
317 // ////////// //
317 // ////////// //
318 // Test cases //
318 // Test cases //
319 // ////////// //
319 // ////////// //
320
320
321 auto maxRange = DateTimeRange::fromDateTime({2017, 1, 1}, {0, 0}, {2017, 1, 5}, {0, 0});
321 auto maxRange = DateTimeRange::fromDateTime({2017, 1, 1}, {0, 0}, {2017, 1, 5}, {0, 0});
322 MetadataPool metadataPool{{{"dataType", "vector"}, {"xml:id", "imf"}}};
322 MetadataPool metadataPool{{{"dataType", "vector"}, {"xml:id", "imf"}}};
323
323
324 // Note: we don't use auto here as we want to pass std::shared_ptr<IDataProvider> as is in the
324 // Note: we don't use auto here as we want to pass std::shared_ptr<IDataProvider> as is in the
325 // QVariant
325 // QVariant
326 std::shared_ptr<IDataProvider> provider = std::make_shared<AmdaProvider>();
326 std::shared_ptr<IDataProvider> provider = std::make_shared<AmdaProvider>();
327
327
328 QTest::newRow("fuzzingTest") << Properties{
328 QTest::newRow("fuzzingTest") << Properties{
329 {MAX_RANGE_PROPERTY, QVariant::fromValue(maxRange)},
329 {MAX_RANGE_PROPERTY, QVariant::fromValue(maxRange)},
330 {METADATA_POOL_PROPERTY, QVariant::fromValue(metadataPool)},
330 {METADATA_POOL_PROPERTY, QVariant::fromValue(metadataPool)},
331 {PROVIDER_PROPERTY, QVariant::fromValue(provider)}};
331 {PROVIDER_PROPERTY, QVariant::fromValue(provider)}};
332 }
332 }
333
333
334 void TestAmdaFuzzing::testFuzzing()
334 void TestAmdaFuzzing::testFuzzing()
335 {
335 {
336 QFETCH(Properties, properties);
336 QFETCH(Properties, properties);
337
337
338 // Sets cache property
338 // Sets cache property
339 QSettings settings{};
339 QSettings settings{};
340 auto cacheTolerance = properties.value(CACHE_TOLERANCE_PROPERTY, CACHE_TOLERANCE_DEFAULT_VALUE);
340 auto cacheTolerance = properties.value(CACHE_TOLERANCE_PROPERTY, CACHE_TOLERANCE_DEFAULT_VALUE);
341 settings.setValue(GENERAL_TOLERANCE_AT_INIT_KEY, cacheTolerance);
341 settings.setValue(GENERAL_TOLERANCE_AT_INIT_KEY, cacheTolerance);
342 settings.setValue(GENERAL_TOLERANCE_AT_UPDATE_KEY, cacheTolerance);
342 settings.setValue(GENERAL_TOLERANCE_AT_UPDATE_KEY, cacheTolerance);
343
343
344 auto &variableController = sqpApp->variableController();
344 auto &variableController = sqpApp->variableController();
345 auto &timeController = sqpApp->timeController();
345 auto &timeController = sqpApp->timeController();
346
346
347 // Generates random initial range (bounded to max range)
347 // Generates random initial range (bounded to max range)
348 auto maxRange = properties.value(MAX_RANGE_PROPERTY, QVariant::fromValue(INVALID_RANGE))
348 auto maxRange = properties.value(MAX_RANGE_PROPERTY, QVariant::fromValue(INVALID_RANGE))
349 .value<DateTimeRange>();
349 .value<DateTimeRange>();
350
350
351 QVERIFY(maxRange != INVALID_RANGE);
351 QVERIFY(maxRange != INVALID_RANGE);
352
352
353 auto initialRangeStart
353 auto initialRangeStart
354 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
354 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
355 auto initialRangeEnd
355 auto initialRangeEnd
356 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
356 = RandomGenerator::instance().generateDouble(maxRange.m_TStart, maxRange.m_TEnd);
357 if (initialRangeStart > initialRangeEnd) {
357 if (initialRangeStart > initialRangeEnd) {
358 std::swap(initialRangeStart, initialRangeEnd);
358 std::swap(initialRangeStart, initialRangeEnd);
359 }
359 }
360
360
361 // Sets initial range on time controller
361 // Sets initial range on time controller
362 DateTimeRange initialRange{initialRangeStart, initialRangeEnd};
362 DateTimeRange initialRange{initialRangeStart, initialRangeEnd};
363 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Setting initial range to" << initialRange << "...";
363 qCInfo(LOG_TestAmdaFuzzing()).noquote() << "Setting initial range to" << initialRange << "...";
364 timeController.setDateTimeRange(initialRange);
364 timeController.setDateTimeRange(initialRange);
365 properties.insert(INITIAL_RANGE_PROPERTY, QVariant::fromValue(initialRange));
365 properties.insert(INITIAL_RANGE_PROPERTY, QVariant::fromValue(initialRange));
366
366
367 FuzzingTest test{variableController, properties};
367 FuzzingTest test{variableController, properties};
368 test.execute();
368 test.execute();
369 }
369 }
370
370
371 int main(int argc, char *argv[])
371 int main(int argc, char *argv[])
372 {
372 {
373 // Increases the test function timeout (which is 5 minutes by default) to 12 hours
373 // Increases the test function timeout (which is 5 minutes by default) to 12 hours
374 // https://stackoverflow.com/questions/42655932/setting-timeout-to-qt-test
374 // https://stackoverflow.com/questions/42655932/setting-timeout-to-qt-test
375 qputenv("QTEST_FUNCTION_TIMEOUT", QByteArray::number(12*60*60*1000));
375 qputenv("QTEST_FUNCTION_TIMEOUT", QByteArray::number(12*60*60*1000));
376
376
377 QLoggingCategory::setFilterRules(
377 QLoggingCategory::setFilterRules(
378 "*.warning=false\n"
378 "*.warning=false\n"
379 "*.info=false\n"
379 "*.info=false\n"
380 "*.debug=false\n"
380 "*.debug=false\n"
381 "FuzzingOperations.info=true\n"
381 "FuzzingOperations.info=true\n"
382 "FuzzingValidators.info=true\n"
382 "FuzzingValidators.info=true\n"
383 "TestAmdaFuzzing.info=true\n");
383 "TestAmdaFuzzing.info=true\n");
384
384
385 SqpApplication app{argc, argv};
385 SqpApplication app{argc, argv};
386 SqpApplication::setOrganizationName("LPP");
386 SqpApplication::setOrganizationName("LPP");
387 SqpApplication::setOrganizationDomain("lpp.fr");
387 SqpApplication::setOrganizationDomain("lpp.fr");
388 SqpApplication::setApplicationName("SciQLop-TestFuzzing");
388 SqpApplication::setApplicationName("SciQLop-TestFuzzing");
389 app.setAttribute(Qt::AA_Use96Dpi, true);
389 app.setAttribute(Qt::AA_Use96Dpi, true);
390 TestAmdaFuzzing testObject{};
390 TestAmdaFuzzing testObject{};
391 QTEST_SET_MAIN_SOURCE_PATH
391 QTEST_SET_MAIN_SOURCE_PATH
392 return QTest::qExec(&testObject, argc, argv);
392 return QTest::qExec(&testObject, argc, argv);
393 }
393 }
394
394
395 #include "TestAmdaFuzzing.moc"
395 #include "TestAmdaFuzzing.moc"
@@ -1,195 +1,195
1 #include "CosinusProvider.h"
1 #include "CosinusProvider.h"
2 #include "MockDefs.h"
2 #include "MockDefs.h"
3
3
4 #include <Data/DataProviderParameters.h>
4 #include <Data/DataProviderParameters.h>
5 #include <Data/ScalarSeries.h>
5 #include <Data/ScalarSeries.h>
6 #include <SqpApplication.h>
6 #include <SqpApplication.h>
7 #include <Time/TimeController.h>
7 #include <Time/TimeController.h>
8 #include <Variable/Variable.h>
8 #include <Variable/Variable.h>
9 #include <Variable/VariableController.h>
9 #include <Variable/VariableController2.h>
10
10
11 #include <QObject>
11 #include <QObject>
12 #include <QtTest>
12 #include <QtTest>
13
13
14 #include <cmath>
14 #include <cmath>
15 #include <memory>
15 #include <memory>
16
16
17 namespace {
17 namespace {
18
18
19 /// Path for the tests
19 /// Path for the tests
20 const auto TESTS_RESOURCES_PATH = QFileInfo{
20 const auto TESTS_RESOURCES_PATH = QFileInfo{
21 QString{MOCKPLUGIN_TESTS_RESOURCES_DIR},
21 QString{MOCKPLUGIN_TESTS_RESOURCES_DIR},
22 "TestCosinusAcquisition"}.absoluteFilePath();
22 "TestCosinusAcquisition"}.absoluteFilePath();
23
23
24 /// Format of dates in data files
24 /// Format of dates in data files
25 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
25 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
26
26
27 /**
27 /**
28 * Verifies that the data in the candidate series are identical to the data in the reference series
28 * Verifies that the data in the candidate series are identical to the data in the reference series
29 * in a specific range
29 * in a specific range
30 * @param candidate the candidate data series
30 * @param candidate the candidate data series
31 * @param range the range to check
31 * @param range the range to check
32 * @param reference the reference data series
32 * @param reference the reference data series
33 * @return true if the data of the candidate series and the reference series are identical in the
33 * @return true if the data of the candidate series and the reference series are identical in the
34 * range, false otherwise
34 * range, false otherwise
35 */
35 */
36 bool checkDataSeries(std::shared_ptr<IDataSeries> candidate, const DateTimeRange &range,
36 bool checkDataSeries(std::shared_ptr<IDataSeries> candidate, const DateTimeRange &range,
37 std::shared_ptr<IDataSeries> reference)
37 std::shared_ptr<IDataSeries> reference)
38 {
38 {
39 if (candidate == nullptr || reference == nullptr) {
39 if (candidate == nullptr || reference == nullptr) {
40 return candidate == reference;
40 return candidate == reference;
41 }
41 }
42
42
43 auto referenceIt = reference->xAxisRange(range.m_TStart, range.m_TEnd);
43 auto referenceIt = reference->xAxisRange(range.m_TStart, range.m_TEnd);
44
44
45 qInfo() << "candidateSize" << std::distance(candidate->cbegin(), candidate->cend());
45 qInfo() << "candidateSize" << std::distance(candidate->cbegin(), candidate->cend());
46 qInfo() << "refSize" << std::distance(referenceIt.first, referenceIt.second);
46 qInfo() << "refSize" << std::distance(referenceIt.first, referenceIt.second);
47
47
48 return std::equal(candidate->cbegin(), candidate->cend(), referenceIt.first, referenceIt.second,
48 return std::equal(candidate->cbegin(), candidate->cend(), referenceIt.first, referenceIt.second,
49 [](const auto &it1, const auto &it2) {
49 [](const auto &it1, const auto &it2) {
50 // - milliseconds precision for time
50 // - milliseconds precision for time
51 // - 1e-6 precision for value
51 // - 1e-6 precision for value
52 return std::abs(it1.x() - it2.x()) < 1e-3
52 return std::abs(it1.x() - it2.x()) < 1e-3
53 && std::abs(it1.value() - it2.value()) < 1e-6;
53 && std::abs(it1.value() - it2.value()) < 1e-6;
54 });
54 });
55 }
55 }
56
56
57 } // namespace
57 } // namespace
58
58
59 /**
59 /**
60 * @brief The TestCosinusAcquisition class tests acquisition in SciQlop (operations like zooms in,
60 * @brief The TestCosinusAcquisition class tests acquisition in SciQlop (operations like zooms in,
61 * zooms out, pans) of data from CosinusProvider
61 * zooms out, pans) of data from CosinusProvider
62 * @sa CosinusProvider
62 * @sa CosinusProvider
63 */
63 */
64 class TestCosinusAcquisition : public QObject {
64 class TestCosinusAcquisition : public QObject {
65 Q_OBJECT
65 Q_OBJECT
66
66
67 private slots:
67 private slots:
68 /// Input data for @sa testAcquisition()
68 /// Input data for @sa testAcquisition()
69 void testAcquisition_data();
69 void testAcquisition_data();
70 void testAcquisition();
70 void testAcquisition();
71 };
71 };
72
72
73 void TestCosinusAcquisition::testAcquisition_data()
73 void TestCosinusAcquisition::testAcquisition_data()
74 {
74 {
75 // ////////////// //
75 // ////////////// //
76 // Test structure //
76 // Test structure //
77 // ////////////// //
77 // ////////////// //
78
78
79 QTest::addColumn<DateTimeRange>("referenceRange"); // Range for generating reference series
79 QTest::addColumn<DateTimeRange>("referenceRange"); // Range for generating reference series
80 QTest::addColumn<DateTimeRange>("initialRange"); // First acquisition
80 QTest::addColumn<DateTimeRange>("initialRange"); // First acquisition
81 QTest::addColumn<int>("operationDelay"); // Acquisitions to make
81 QTest::addColumn<int>("operationDelay"); // Acquisitions to make
82 QTest::addColumn<std::vector<DateTimeRange> >("operations"); // Acquisitions to make
82 QTest::addColumn<std::vector<DateTimeRange> >("operations"); // Acquisitions to make
83
83
84 // ////////// //
84 // ////////// //
85 // Test cases //
85 // Test cases //
86 // ////////// //
86 // ////////// //
87
87
88 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
88 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
89 return DateUtils::secondsSinceEpoch(
89 return DateUtils::secondsSinceEpoch(
90 QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC});
90 QDateTime{{year, month, day}, {hours, minutes, seconds}, Qt::UTC});
91 };
91 };
92
92
93 QTest::newRow("cosinus")
93 QTest::newRow("cosinus")
94 << DateTimeRange{dateTime(2017, 1, 1, 12, 0, 0), dateTime(2017, 1, 1, 13, 0, 0)}
94 << DateTimeRange{dateTime(2017, 1, 1, 12, 0, 0), dateTime(2017, 1, 1, 13, 0, 0)}
95 << DateTimeRange{dateTime(2017, 1, 1, 12, 30, 0), dateTime(2017, 1, 1, 12, 35, 1)} << 250
95 << DateTimeRange{dateTime(2017, 1, 1, 12, 30, 0), dateTime(2017, 1, 1, 12, 35, 1)} << 250
96 << std::vector<DateTimeRange>{
96 << std::vector<DateTimeRange>{
97 // Pan (jump) left
97 // Pan (jump) left
98 DateTimeRange{dateTime(2017, 1, 1, 12, 45, 0), dateTime(2017, 1, 1, 12, 50, 0)},
98 DateTimeRange{dateTime(2017, 1, 1, 12, 45, 0), dateTime(2017, 1, 1, 12, 50, 0)},
99 // Pan (jump) right
99 // Pan (jump) right
100 DateTimeRange{dateTime(2017, 1, 1, 12, 15, 0), dateTime(2017, 1, 1, 12, 20, 0)},
100 DateTimeRange{dateTime(2017, 1, 1, 12, 15, 0), dateTime(2017, 1, 1, 12, 20, 0)},
101 // Pan (overlay) right
101 // Pan (overlay) right
102 DateTimeRange{dateTime(2017, 1, 1, 12, 14, 0), dateTime(2017, 1, 1, 12, 19, 0)},
102 DateTimeRange{dateTime(2017, 1, 1, 12, 14, 0), dateTime(2017, 1, 1, 12, 19, 0)},
103 // Pan (overlay) left
103 // Pan (overlay) left
104 DateTimeRange{dateTime(2017, 1, 1, 12, 15, 0), dateTime(2017, 1, 1, 12, 20, 0)},
104 DateTimeRange{dateTime(2017, 1, 1, 12, 15, 0), dateTime(2017, 1, 1, 12, 20, 0)},
105 // Pan (overlay) left
105 // Pan (overlay) left
106 DateTimeRange{dateTime(2017, 1, 1, 12, 16, 0), dateTime(2017, 1, 1, 12, 21, 0)},
106 DateTimeRange{dateTime(2017, 1, 1, 12, 16, 0), dateTime(2017, 1, 1, 12, 21, 0)},
107 // Zoom in
107 // Zoom in
108 DateTimeRange{dateTime(2017, 1, 1, 12, 17, 30), dateTime(2017, 1, 1, 12, 19, 30)},
108 DateTimeRange{dateTime(2017, 1, 1, 12, 17, 30), dateTime(2017, 1, 1, 12, 19, 30)},
109 // Zoom out
109 // Zoom out
110 DateTimeRange{dateTime(2017, 1, 1, 12, 12, 30), dateTime(2017, 1, 1, 12, 24, 30)}};
110 DateTimeRange{dateTime(2017, 1, 1, 12, 12, 30), dateTime(2017, 1, 1, 12, 24, 30)}};
111
111
112 QTest::newRow("cosinus_big")
112 QTest::newRow("cosinus_big")
113 << DateTimeRange{dateTime(2017, 1, 1, 1, 0, 0), dateTime(2017, 1, 5, 13, 0, 0)}
113 << DateTimeRange{dateTime(2017, 1, 1, 1, 0, 0), dateTime(2017, 1, 5, 13, 0, 0)}
114 << DateTimeRange{dateTime(2017, 1, 2, 6, 30, 0), dateTime(2017, 1, 2, 18, 30, 0)} << 5000
114 << DateTimeRange{dateTime(2017, 1, 2, 6, 30, 0), dateTime(2017, 1, 2, 18, 30, 0)} << 5000
115 << std::vector<DateTimeRange>{
115 << std::vector<DateTimeRange>{
116 // Pan (jump) left
116 // Pan (jump) left
117 DateTimeRange{dateTime(2017, 1, 1, 13, 30, 0), dateTime(2017, 1, 1, 18, 30, 0)},
117 DateTimeRange{dateTime(2017, 1, 1, 13, 30, 0), dateTime(2017, 1, 1, 18, 30, 0)},
118 // Pan (jump) right
118 // Pan (jump) right
119 DateTimeRange{dateTime(2017, 1, 3, 4, 30, 0), dateTime(2017, 1, 3, 10, 30, 0)},
119 DateTimeRange{dateTime(2017, 1, 3, 4, 30, 0), dateTime(2017, 1, 3, 10, 30, 0)},
120 // Pan (overlay) right
120 // Pan (overlay) right
121 DateTimeRange{dateTime(2017, 1, 3, 8, 30, 0), dateTime(2017, 1, 3, 12, 30, 0)},
121 DateTimeRange{dateTime(2017, 1, 3, 8, 30, 0), dateTime(2017, 1, 3, 12, 30, 0)},
122 // Pan (overlay) left
122 // Pan (overlay) left
123 DateTimeRange{dateTime(2017, 1, 2, 8, 30, 0), dateTime(2017, 1, 3, 10, 30, 0)},
123 DateTimeRange{dateTime(2017, 1, 2, 8, 30, 0), dateTime(2017, 1, 3, 10, 30, 0)},
124 // Pan (overlay) left
124 // Pan (overlay) left
125 DateTimeRange{dateTime(2017, 1, 1, 12, 30, 0), dateTime(2017, 1, 3, 5, 30, 0)},
125 DateTimeRange{dateTime(2017, 1, 1, 12, 30, 0), dateTime(2017, 1, 3, 5, 30, 0)},
126 // Zoom in
126 // Zoom in
127 DateTimeRange{dateTime(2017, 1, 2, 2, 30, 0), dateTime(2017, 1, 2, 8, 30, 0)},
127 DateTimeRange{dateTime(2017, 1, 2, 2, 30, 0), dateTime(2017, 1, 2, 8, 30, 0)},
128 // Zoom out
128 // Zoom out
129 DateTimeRange{dateTime(2017, 1, 1, 14, 30, 0), dateTime(2017, 1, 3, 12, 30, 0)}};
129 DateTimeRange{dateTime(2017, 1, 1, 14, 30, 0), dateTime(2017, 1, 3, 12, 30, 0)}};
130 }
130 }
131
131
132 void TestCosinusAcquisition::testAcquisition()
132 void TestCosinusAcquisition::testAcquisition()
133 {
133 {
134 // Retrieves reference range
134 // Retrieves reference range
135 QFETCH(DateTimeRange, referenceRange);
135 QFETCH(DateTimeRange, referenceRange);
136 CosinusProvider referenceProvider{};
136 CosinusProvider referenceProvider{};
137 auto dataSeries = referenceProvider.provideDataSeries(
137 auto dataSeries = referenceProvider.provideDataSeries(
138 referenceRange, {{COSINUS_TYPE_KEY, "scalar"}, {COSINUS_FREQUENCY_KEY, 10.}});
138 referenceRange, {{COSINUS_TYPE_KEY, "scalar"}, {COSINUS_FREQUENCY_KEY, 10.}});
139
139
140 auto end = dataSeries->cend() - 1;
140 auto end = dataSeries->cend() - 1;
141 qInfo() << dataSeries->nbPoints() << dataSeries->cbegin()->x() << end->x();
141 qInfo() << dataSeries->nbPoints() << dataSeries->cbegin()->x() << end->x();
142
142
143 /// Lambda used to validate a variable at each step
143 /// Lambda used to validate a variable at each step
144 auto validateVariable
144 auto validateVariable
145 = [dataSeries](std::shared_ptr<Variable> variable, const DateTimeRange &range) {
145 = [dataSeries](std::shared_ptr<Variable> variable, const DateTimeRange &range) {
146 // Checks that the variable's range has changed
146 // Checks that the variable's range has changed
147 qInfo() << "range vs expected range" << variable->range() << range;
147 qInfo() << "range vs expected range" << variable->range() << range;
148 QCOMPARE(variable->range(), range);
148 QCOMPARE(variable->range(), range);
149
149
150 // Checks the variable's data series
150 // Checks the variable's data series
151 QVERIFY(checkDataSeries(variable->dataSeries(), variable->cacheRange(), dataSeries));
151 QVERIFY(checkDataSeries(variable->dataSeries(), variable->cacheRange(), dataSeries));
152 };
152 };
153
153
154 // Creates variable
154 // Creates variable
155 QFETCH(DateTimeRange, initialRange);
155 QFETCH(DateTimeRange, initialRange);
156 sqpApp->timeController().setDateTimeRange(initialRange);
156 sqpApp->timeController().setDateTimeRange(initialRange);
157 auto provider = std::make_shared<CosinusProvider>();
157 auto provider = std::make_shared<CosinusProvider>();
158 auto variable = sqpApp->variableController().createVariable(
158 auto variable = sqpApp->variableController().createVariable(
159 "MMS", {{COSINUS_TYPE_KEY, "scalar"}, {COSINUS_FREQUENCY_KEY, 10.}}, provider, initialRange);
159 "MMS", {{COSINUS_TYPE_KEY, "scalar"}, {COSINUS_FREQUENCY_KEY, 10.}}, provider, initialRange);
160
160
161
161
162 QFETCH(int, operationDelay);
162 QFETCH(int, operationDelay);
163 QTest::qWait(operationDelay);
163 QTest::qWait(operationDelay);
164 validateVariable(variable, initialRange);
164 validateVariable(variable, initialRange);
165
165
166 QTest::qWait(operationDelay);
166 QTest::qWait(operationDelay);
167 // Makes operations on the variable
167 // Makes operations on the variable
168 QFETCH(std::vector<DateTimeRange>, operations);
168 QFETCH(std::vector<DateTimeRange>, operations);
169 for (const auto &operation : operations) {
169 for (const auto &operation : operations) {
170 // Asks request on the variable and waits during its execution
170 // Asks request on the variable and waits during its execution
171 sqpApp->variableController().onRequestDataLoading({variable}, operation, false);
171 sqpApp->variableController().changeRange(variable, operation);
172
172
173 QTest::qWait(operationDelay);
173 QTest::qWait(operationDelay);
174 validateVariable(variable, operation);
174 validateVariable(variable, operation);
175 }
175 }
176
176
177
177
178 for (const auto &operation : operations) {
178 for (const auto &operation : operations) {
179 // Asks request on the variable and waits during its execution
179 // Asks request on the variable and waits during its execution
180 sqpApp->variableController().onRequestDataLoading({variable}, operation, false);
180 sqpApp->variableController().changeRange(variable, operation);
181 }
181 }
182 QTest::qWait(operationDelay);
182 QTest::qWait(operationDelay);
183 validateVariable(variable, operations.back());
183 validateVariable(variable, operations.back());
184 }
184 }
185
185
186 int main(int argc, char *argv[])
186 int main(int argc, char *argv[])
187 {
187 {
188 SqpApplication app{argc, argv};
188 SqpApplication app{argc, argv};
189 app.setAttribute(Qt::AA_Use96Dpi, true);
189 app.setAttribute(Qt::AA_Use96Dpi, true);
190 TestCosinusAcquisition testObject{};
190 TestCosinusAcquisition testObject{};
191 QTEST_SET_MAIN_SOURCE_PATH
191 QTEST_SET_MAIN_SOURCE_PATH
192 return QTest::qExec(&testObject, argc, argv);
192 return QTest::qExec(&testObject, argc, argv);
193 }
193 }
194
194
195 #include "TestCosinusAcquisition.moc"
195 #include "TestCosinusAcquisition.moc"
General Comments 0
You need to be logged in to leave comments. Login now