##// END OF EJS Templates
New data sources system switch complete...
jeandet -
r1495:9c439b3d7daf
parent child
Show More
@@ -1,129 +1,130
1 #pragma once
1 #pragma once
2 #include <Data/DataProviderParameters.h>
2 #include <Data/DataProviderParameters.h>
3 #include <Data/DataSeriesType.h>
3 #include <Data/DataSeriesType.h>
4 #include <Data/IDataProvider.h>
4 #include <Data/IDataProvider.h>
5 #include <DataSource/DataSourceController.h>
6 #include <DataSource/DataSourceItem.h>
5 #include <DataSource/DataSourceItem.h>
7 #include <DataSource/DataSourceItemAction.h>
6 #include <DataSource/DataSourceItemAction.h>
7 #include <DataSource/datasources.h>
8
8 #include <QPair>
9 #include <QPair>
9 #include <SqpApplication.h>
10 #include <SqpApplication.h>
10 // must be included last because of Python/Qt definition of slots
11 // must be included last because of Python/Qt definition of slots
11 #include "numpy_wrappers.h"
12 #include "numpy_wrappers.h"
12
13
13 struct Product
14 struct Product
14 {
15 {
15 QString path;
16 QString path;
16 std::vector<std::string> components;
17 std::vector<std::string> components;
17 QMap<QString, QString> metadata;
18 QMap<QString, QString> metadata;
18 Product() = default;
19 Product() = default;
19 explicit Product(const QString& path, const std::vector<std::string>& components,
20 explicit Product(const QString& path, const std::vector<std::string>& components,
20 const QMap<QString, QString>& metadata)
21 const QMap<QString, QString>& metadata)
21 : path { path }, components { components }, metadata { metadata }
22 : path { path }, components { components }, metadata { metadata }
22 {
23 {
23 }
24 }
24 ~Product() = default;
25 ~Product() = default;
25 };
26 };
26
27
27 template <typename T>
28 template <typename T>
28 ScalarTimeSerie* make_scalar(T& t, T& y)
29 ScalarTimeSerie* make_scalar(T& t, T& y)
29 {
30 {
30 return new ScalarTimeSerie { std::move(t.data), std::move(y.data) };
31 return new ScalarTimeSerie { std::move(t.data), std::move(y.data) };
31 }
32 }
32
33
33 template <typename T>
34 template <typename T>
34 VectorTimeSerie* make_vector(T& t, T& y)
35 VectorTimeSerie* make_vector(T& t, T& y)
35 {
36 {
36 return new VectorTimeSerie { std::move(t.data), y.to_std_vect_vect() };
37 return new VectorTimeSerie { std::move(t.data), y.to_std_vect_vect() };
37 }
38 }
38
39
39 template <typename T>
40 template <typename T>
40 MultiComponentTimeSerie* make_multi_comp(T& t, T& y)
41 MultiComponentTimeSerie* make_multi_comp(T& t, T& y)
41 {
42 {
42 auto y_size = y.flat_size();
43 auto y_size = y.flat_size();
43 auto t_size = t.flat_size();
44 auto t_size = t.flat_size();
44 if (t_size && (y_size % t_size) == 0)
45 if (t_size && (y_size % t_size) == 0)
45 {
46 {
46 return new MultiComponentTimeSerie { std::move(t.data), std::move(y.data),
47 return new MultiComponentTimeSerie { std::move(t.data), std::move(y.data),
47 { t_size, y_size / t_size } };
48 { t_size, y_size / t_size } };
48 }
49 }
49 return nullptr;
50 return nullptr;
50 }
51 }
51
52
52 template <typename T>
53 template <typename T>
53 SpectrogramTimeSerie* make_spectro(T& t, T& y)
54 SpectrogramTimeSerie* make_spectro(T& t, T& y)
54 {
55 {
55 auto y_size = y.flat_size();
56 auto y_size = y.flat_size();
56 auto t_size = t.flat_size();
57 auto t_size = t.flat_size();
57 if (t_size && (y_size % t_size) == 0)
58 if (t_size && (y_size % t_size) == 0)
58 {
59 {
59 return new SpectrogramTimeSerie { std::move(t.data), std::move(y.data),
60 return new SpectrogramTimeSerie { std::move(t.data), std::move(y.data),
60 { t_size, y_size / t_size } };
61 { t_size, y_size / t_size } };
61 }
62 }
62 return nullptr;
63 return nullptr;
63 }
64 }
64
65
65
66
66 class PyDataProvider : public IDataProvider
67 class PyDataProvider : public IDataProvider
67 {
68 {
68 public:
69 public:
69 PyDataProvider()
70 PyDataProvider()
70 {
71 {
71 auto& dataSourceController = sqpApp->dataSourceController();
72 auto& dataSources = sqpApp->dataSources();
72 dataSourceController.registerProvider(this);
73 dataSources.addProvider(this);
73 }
74 }
74
75
75 virtual ~PyDataProvider() {}
76 virtual ~PyDataProvider() {}
76
77
77 virtual QPair<QPair<NpArray, NpArray>, DataSeriesType> get_data(
78 virtual QPair<QPair<NpArray, NpArray>, DataSeriesType> get_data(
78 const QMap<QString, QString>& key, double start_time, double stop_time)
79 const QMap<QString, QString>& key, double start_time, double stop_time)
79 {
80 {
80 (void)key, (void)start_time, (void)stop_time;
81 (void)key, (void)start_time, (void)stop_time;
81 return {};
82 return {};
82 }
83 }
83
84
84 virtual TimeSeries::ITimeSerie* getData(const DataProviderParameters& parameters) override
85 virtual TimeSeries::ITimeSerie* getData(const DataProviderParameters& parameters) override
85 {
86 {
86 TimeSeries::ITimeSerie* ts = nullptr;
87 TimeSeries::ITimeSerie* ts = nullptr;
87 if (parameters.m_Data.contains("name"))
88 if (parameters.m_Data.contains("name"))
88 {
89 {
89 QMap<QString, QString> metadata;
90 QMap<QString, QString> metadata;
90 std::for_each(parameters.m_Data.constKeyValueBegin(),
91 std::for_each(parameters.m_Data.constKeyValueBegin(),
91 parameters.m_Data.constKeyValueEnd(),
92 parameters.m_Data.constKeyValueEnd(),
92 [&metadata](const auto& item) { metadata[item.first] = item.second.toString(); });
93 [&metadata](const auto& item) { metadata[item.first] = item.second.toString(); });
93 auto [data, type]
94 auto [data, type]
94 = get_data(metadata, parameters.m_Range.m_TStart, parameters.m_Range.m_TEnd);
95 = get_data(metadata, parameters.m_Range.m_TStart, parameters.m_Range.m_TEnd);
95
96
96 auto& [t, y] = data;
97 auto& [t, y] = data;
97 switch (type)
98 switch (type)
98 {
99 {
99 case DataSeriesType::SCALAR:
100 case DataSeriesType::SCALAR:
100 ts = make_scalar(t, y);
101 ts = make_scalar(t, y);
101 break;
102 break;
102 case DataSeriesType::VECTOR:
103 case DataSeriesType::VECTOR:
103 ts = make_vector(t, y);
104 ts = make_vector(t, y);
104 break;
105 break;
105 case DataSeriesType::MULTICOMPONENT:
106 case DataSeriesType::MULTICOMPONENT:
106 ts = make_multi_comp(t, y);
107 ts = make_multi_comp(t, y);
107 break;
108 break;
108 case DataSeriesType::SPECTROGRAM:
109 case DataSeriesType::SPECTROGRAM:
109 ts = make_spectro(t, y);
110 ts = make_spectro(t, y);
110 break;
111 break;
111 default:
112 default:
112 break;
113 break;
113 }
114 }
114 }
115 }
115 return ts;
116 return ts;
116 }
117 }
117
118
118
119
119 inline void register_products(const QVector<Product*>& products)
120 inline void register_products(const QVector<Product*>& products)
120 {
121 {
121 auto& dataSourceController = sqpApp->dataSourceController();
122 auto& dataSources = sqpApp->dataSources();
122 auto id = this->id();
123 auto id = this->id();
123 auto data_source_name = this->name();
124 auto data_source_name = this->name();
124 std::for_each(std::cbegin(products), std::cend(products),
125 std::for_each(std::cbegin(products), std::cend(products),
125 [&id, &dataSourceController](const Product* product) {
126 [&id, &dataSources](const Product* product) {
126 dataSourceController.setDataSourceItem(id, product->path, product->metadata);
127 dataSources.addDataSourceItem(id, product->path, product->metadata);
127 });
128 });
128 }
129 }
129 };
130 };
@@ -1,208 +1,203
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 <Catalogue2/browser.h>
26 #include <Catalogue2/browser.h>
27 #include <DataSource/DataSourceController.h>
28 #include <DataSource/DataSourceItem.h>
27 #include <DataSource/DataSourceItem.h>
29 #include <DataSource/DataSourceWidget.h>
28 #include <DataSource/DataSourceWidget.h>
30 #include <Settings/SqpSettingsDialog.h>
29 #include <Settings/SqpSettingsDialog.h>
31 #include <Settings/SqpSettingsGeneralWidget.h>
30 #include <Settings/SqpSettingsGeneralWidget.h>
32 #include <SidePane/SqpSidePane.h>
31 #include <SidePane/SqpSidePane.h>
33 #include <SqpApplication.h>
32 #include <SqpApplication.h>
34 #include <Time/TimeController.h>
33 #include <Time/TimeController.h>
35 #include <TimeWidget/TimeWidget.h>
34 #include <TimeWidget/TimeWidget.h>
36
35
37 #include "toolbar.h"
36 #include "toolbar.h"
38
37
39 #include <QAction>
38 #include <QAction>
40 #include <QCloseEvent>
39 #include <QCloseEvent>
41 #include <QDate>
40 #include <QDate>
42 #include <QDir>
41 #include <QDir>
43 #include <QFileDialog>
42 #include <QFileDialog>
44 #include <QMessageBox>
43 #include <QMessageBox>
45 #include <QToolBar>
44 #include <QToolBar>
46 #include <QToolButton>
45 #include <QToolButton>
47 #include <memory.h>
46 #include <memory.h>
48
47
49
48
50 Q_LOGGING_CATEGORY(LOG_MainWindow, "MainWindow")
49 Q_LOGGING_CATEGORY(LOG_MainWindow, "MainWindow")
51
50
52 class MainWindow::MainWindowPrivate
51 class MainWindow::MainWindowPrivate
53 {
52 {
54 public:
53 public:
55 explicit MainWindowPrivate(MainWindow* mainWindow)
54 explicit MainWindowPrivate(MainWindow* mainWindow)
56 : m_GeneralSettingsWidget { new SqpSettingsGeneralWidget { mainWindow } }
55 : m_GeneralSettingsWidget { new SqpSettingsGeneralWidget { mainWindow } }
57 , m_SettingsDialog { new SqpSettingsDialog { mainWindow } }
56 , m_SettingsDialog { new SqpSettingsDialog { mainWindow } }
58 , m_CatalogExplorer { new CataloguesBrowser { mainWindow } }
57 , m_CatalogExplorer { new CataloguesBrowser { mainWindow } }
59 {
58 {
60 }
59 }
61
60
62 /// General settings widget. MainWindow has the ownership
61 /// General settings widget. MainWindow has the ownership
63 SqpSettingsGeneralWidget* m_GeneralSettingsWidget;
62 SqpSettingsGeneralWidget* m_GeneralSettingsWidget;
64 /// Settings dialog. MainWindow has the ownership
63 /// Settings dialog. MainWindow has the ownership
65 SqpSettingsDialog* m_SettingsDialog;
64 SqpSettingsDialog* m_SettingsDialog;
66 /// Catalogue dialog. MainWindow has the ownership
65 /// Catalogue dialog. MainWindow has the ownership
67 CataloguesBrowser* m_CatalogExplorer;
66 CataloguesBrowser* m_CatalogExplorer;
68
67
69 bool checkDataToSave(QWidget* parentWidget);
68 bool checkDataToSave(QWidget* parentWidget);
70 };
69 };
71
70
72 MainWindow::MainWindow(QWidget* parent)
71 MainWindow::MainWindow(QWidget* parent)
73 : QMainWindow { parent }
72 : QMainWindow { parent }
74 , m_Ui { new Ui::MainWindow }
73 , m_Ui { new Ui::MainWindow }
75 , impl { spimpl::make_unique_impl<MainWindowPrivate>(this) }
74 , impl { spimpl::make_unique_impl<MainWindowPrivate>(this) }
76 {
75 {
77 m_Ui->setupUi(this);
76 m_Ui->setupUi(this);
78 setWindowTitle(QString("SciQLop v%1").arg(SCIQLOP_VERSION));
77 setWindowTitle(QString("SciQLop v%1").arg(SCIQLOP_VERSION));
79
78
80 // //////////////// //
79 // //////////////// //
81 // Menu and Toolbar //
80 // Menu and Toolbar //
82 // //////////////// //
81 // //////////////// //
83 this->menuBar()->addAction(tr("File"));
82 this->menuBar()->addAction(tr("File"));
84 auto toolsMenu = this->menuBar()->addMenu(tr("Tools"));
83 auto toolsMenu = this->menuBar()->addMenu(tr("Tools"));
85 toolsMenu->addAction(tr("Settings..."), [this]() {
84 toolsMenu->addAction(tr("Settings..."), [this]() {
86 // Loads settings
85 // Loads settings
87 impl->m_SettingsDialog->loadSettings();
86 impl->m_SettingsDialog->loadSettings();
88
87
89 // Open settings dialog and save settings if the dialog is accepted
88 // Open settings dialog and save settings if the dialog is accepted
90 if (impl->m_SettingsDialog->exec() == QDialog::Accepted)
89 if (impl->m_SettingsDialog->exec() == QDialog::Accepted)
91 {
90 {
92 impl->m_SettingsDialog->saveSettings();
91 impl->m_SettingsDialog->saveSettings();
93 }
92 }
94 });
93 });
95 auto mainToolBar = new ToolBar(this);
94 auto mainToolBar = new ToolBar(this);
96 this->addToolBar(mainToolBar);
95 this->addToolBar(mainToolBar);
97 connect(mainToolBar, &ToolBar::setPlotsInteractionMode, sqpApp,
96 connect(mainToolBar, &ToolBar::setPlotsInteractionMode, sqpApp,
98 &SqpApplication::setPlotsInteractionMode);
97 &SqpApplication::setPlotsInteractionMode);
99 connect(mainToolBar, &ToolBar::setPlotsCursorMode, sqpApp, &SqpApplication::setPlotsCursorMode);
98 connect(mainToolBar, &ToolBar::setPlotsCursorMode, sqpApp, &SqpApplication::setPlotsCursorMode);
100 connect(mainToolBar, &ToolBar::showCataloguesBrowser,
99 connect(mainToolBar, &ToolBar::showCataloguesBrowser,
101 [this]() { impl->m_CatalogExplorer->show(); });
100 [this]() { impl->m_CatalogExplorer->show(); });
102
101
103 // //////// //
102 // //////// //
104 // Settings //
103 // Settings //
105 // //////// //
104 // //////// //
106
105
107 // Registers "general settings" widget to the settings dialog
106 // Registers "general settings" widget to the settings dialog
108 impl->m_SettingsDialog->registerWidget(
107 impl->m_SettingsDialog->registerWidget(
109 QStringLiteral("General"), impl->m_GeneralSettingsWidget);
108 QStringLiteral("General"), impl->m_GeneralSettingsWidget);
110
109
111 // /////////// //
110 // /////////// //
112 // Connections //
111 // Connections //
113 // /////////// //
112 // /////////// //
114
113
115 // Widgets / controllers connections
114 // Widgets / controllers connections
116
115
117 // DataSource
118 connect(&sqpApp->dataSourceController(), &DataSourceController::dataSourceItemSet,
119 m_Ui->dataSourceWidget, &DataSourceWidget::addDataSource);
120
121 // Time
116 // Time
122 // connect(timeWidget, SIGNAL(timeUpdated(DateTimeRange)), &sqpApp->timeController(),
117 // connect(timeWidget, SIGNAL(timeUpdated(DateTimeRange)), &sqpApp->timeController(),
123 // SLOT(onTimeToUpdate(DateTimeRange)));
118 // SLOT(onTimeToUpdate(DateTimeRange)));
124 connect(mainToolBar, &ToolBar::timeUpdated, &sqpApp->timeController(),
119 connect(mainToolBar, &ToolBar::timeUpdated, &sqpApp->timeController(),
125 &TimeController::setDateTimeRange);
120 &TimeController::setDateTimeRange);
126
121
127 // Widgets / widgets connections
122 // Widgets / widgets connections
128
123
129 // For the following connections, we use DirectConnection to allow each widget that can
124 // For the following connections, we use DirectConnection to allow each widget that can
130 // potentially attach a menu to the variable's menu to do so before this menu is displayed.
125 // potentially attach a menu to the variable's menu to do so before this menu is displayed.
131 // The order of connections is also important, since it determines the order in which each
126 // The order of connections is also important, since it determines the order in which each
132 // widget will attach its menu
127 // widget will attach its menu
133 connect(m_Ui->variableInspectorWidget,
128 connect(m_Ui->variableInspectorWidget,
134 SIGNAL(tableMenuAboutToBeDisplayed(QMenu*, const QVector<std::shared_ptr<Variable>>&)),
129 SIGNAL(tableMenuAboutToBeDisplayed(QMenu*, const QVector<std::shared_ptr<Variable>>&)),
135 m_Ui->view, SLOT(attachVariableMenu(QMenu*, const QVector<std::shared_ptr<Variable>>&)),
130 m_Ui->view, SLOT(attachVariableMenu(QMenu*, const QVector<std::shared_ptr<Variable>>&)),
136 Qt::DirectConnection);
131 Qt::DirectConnection);
137 }
132 }
138
133
139 MainWindow::~MainWindow() {}
134 MainWindow::~MainWindow() {}
140
135
141 void MainWindow::changeEvent(QEvent* e)
136 void MainWindow::changeEvent(QEvent* e)
142 {
137 {
143 QMainWindow::changeEvent(e);
138 QMainWindow::changeEvent(e);
144 switch (e->type())
139 switch (e->type())
145 {
140 {
146 case QEvent::LanguageChange:
141 case QEvent::LanguageChange:
147 m_Ui->retranslateUi(this);
142 m_Ui->retranslateUi(this);
148 break;
143 break;
149 default:
144 default:
150 break;
145 break;
151 }
146 }
152 }
147 }
153
148
154 void MainWindow::closeEvent(QCloseEvent* event)
149 void MainWindow::closeEvent(QCloseEvent* event)
155 {
150 {
156 if (!impl->checkDataToSave(this))
151 if (!impl->checkDataToSave(this))
157 {
152 {
158 event->ignore();
153 event->ignore();
159 }
154 }
160 else
155 else
161 {
156 {
162 event->accept();
157 event->accept();
163 }
158 }
164 }
159 }
165
160
166 void MainWindow::keyPressEvent(QKeyEvent* event)
161 void MainWindow::keyPressEvent(QKeyEvent* event)
167 {
162 {
168 switch (event->key())
163 switch (event->key())
169 {
164 {
170 case Qt::Key_F11:
165 case Qt::Key_F11:
171 if (this->isFullScreen())
166 if (this->isFullScreen())
172 {
167 {
173 this->showNormal();
168 this->showNormal();
174 }
169 }
175 else
170 else
176 {
171 {
177 this->showFullScreen();
172 this->showFullScreen();
178 }
173 }
179 break;
174 break;
180 default:
175 default:
181 break;
176 break;
182 }
177 }
183 }
178 }
184
179
185 bool MainWindow::MainWindowPrivate::checkDataToSave(QWidget* parentWidget)
180 bool MainWindow::MainWindowPrivate::checkDataToSave(QWidget* parentWidget)
186 {
181 {
187 // auto hasChanges = sqpApp->catalogueController().hasChanges();
182 // auto hasChanges = sqpApp->catalogueController().hasChanges();
188 // if (hasChanges)
183 // if (hasChanges)
189 // {
184 // {
190 // // There are some unsaved changes
185 // // There are some unsaved changes
191 // switch (QMessageBox::question(parentWidget, tr("Save changes"),
186 // switch (QMessageBox::question(parentWidget, tr("Save changes"),
192 // tr("The catalogue controller has unsaved changes.\nDo you want to save them ?"),
187 // tr("The catalogue controller has unsaved changes.\nDo you want to save them ?"),
193 // QMessageBox::SaveAll | QMessageBox::Discard | QMessageBox::Cancel,
188 // QMessageBox::SaveAll | QMessageBox::Discard | QMessageBox::Cancel,
194 // QMessageBox::SaveAll))
189 // QMessageBox::SaveAll))
195 // {
190 // {
196 // case QMessageBox::SaveAll:
191 // case QMessageBox::SaveAll:
197 // sqpApp->catalogueController().saveAll();
192 // sqpApp->catalogueController().saveAll();
198 // break;
193 // break;
199 // case QMessageBox::Discard:
194 // case QMessageBox::Discard:
200 // break;
195 // break;
201 // case QMessageBox::Cancel:
196 // case QMessageBox::Cancel:
202 // default:
197 // default:
203 // return false;
198 // return false;
204 // }
199 // }
205 // }
200 // }
206
201
207 return true;
202 return true;
208 }
203 }
@@ -1,1 +1,1
1 Subproject commit b081849458c211dcc59f72b11542959db2301162
1 Subproject commit 46467fb43b8d07fe4f4a45df949ec4ae858ccf9d
@@ -1,47 +1,35
1 #ifndef SCIQLOP_DATASOURCEWIDGET_H
1 #ifndef SCIQLOP_DATASOURCEWIDGET_H
2 #define SCIQLOP_DATASOURCEWIDGET_H
2 #define SCIQLOP_DATASOURCEWIDGET_H
3
3
4 #include <QWidget>
4 #include <QWidget>
5
5
6 #include <memory>
6 #include <QSortFilterProxyModel>
7
7
8 namespace Ui {
8 namespace Ui
9 {
9 class DataSourceWidget;
10 class DataSourceWidget;
10 } // Ui
11 } // Ui
11
12
12 class DataSourceItem;
13 class DataSourceItem;
13
14
14 /**
15 /**
15 * @brief The DataSourceWidget handles the graphical representation (as a tree) of the data sources
16 * @brief The DataSourceWidget handles the graphical representation (as a tree) of the data sources
16 * attached to SciQlop.
17 * attached to SciQlop.
17 */
18 */
18 class DataSourceWidget : public QWidget {
19 class DataSourceWidget : public QWidget
20 {
19 Q_OBJECT
21 Q_OBJECT
20
22
21 public:
23 public:
22 explicit DataSourceWidget(QWidget *parent = 0);
24 explicit DataSourceWidget(QWidget* parent = 0);
23 virtual ~DataSourceWidget() noexcept;
25 virtual ~DataSourceWidget() noexcept;
24
26
25 public slots:
26 /**
27 * Adds a data source. An item associated to the data source is created and then added to the
28 * representation tree
29 * @param dataSource the data source to add. The pointer has to be not null
30 */
31 void addDataSource(DataSourceItem *dataSource) noexcept;
32
33 private:
27 private:
34 void updateTreeWidget() noexcept;
28 void updateTreeWidget() noexcept;
35
29
36 Ui::DataSourceWidget *ui;
30 Ui::DataSourceWidget* ui;
37 std::unique_ptr<DataSourceItem> m_Root;
31 QSortFilterProxyModel m_model_proxy;
38
39 private slots:
40 /// Slot called when the filtering text has changed
41 void filterChanged(const QString &text) noexcept;
42
32
43 /// Slot called when right clicking on an item in the tree (displays a menu)
44 void onTreeMenuRequested(const QPoint &pos) noexcept;
45 };
33 };
46
34
47 #endif // SCIQLOP_DATASOURCEWIDGET_H
35 #endif // SCIQLOP_DATASOURCEWIDGET_H
@@ -1,118 +1,120
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 <QAction>
6 #include <QAction>
7 #include <QApplication>
7 #include <QApplication>
8 #include <QLoggingCategory>
8 #include <QLoggingCategory>
9 #include <QMenuBar>
9 #include <QMenuBar>
10 #include <QProxyStyle>
10 #include <QProxyStyle>
11 #include <QStyleOption>
11 #include <QStyleOption>
12 #include <QWidget>
12 #include <QWidget>
13 #include <QWidgetAction>
13 #include <QWidgetAction>
14
14
15 #include <Common/spimpl.h>
15 #include <Common/spimpl.h>
16
16
17 Q_DECLARE_LOGGING_CATEGORY(LOG_SqpApplication)
17 Q_DECLARE_LOGGING_CATEGORY(LOG_SqpApplication)
18
18
19 #if defined(sqpApp)
19 #if defined(sqpApp)
20 #undef sqpApp
20 #undef sqpApp
21 #endif
21 #endif
22 #define sqpApp (static_cast<SqpApplication*>(QCoreApplication::instance()))
22 #define sqpApp (static_cast<SqpApplication*>(QCoreApplication::instance()))
23
23
24 class DataSourceController;
24 class DataSourceController;
25 class DataSources;
25 class NetworkController;
26 class NetworkController;
26 class TimeController;
27 class TimeController;
27 class VariableController;
28 class VariableController;
28 class VariableController2;
29 class VariableController2;
29 class VariableModel2;
30 class VariableModel2;
30 class DragDropGuiController;
31 class DragDropGuiController;
31 class ActionsGuiController;
32 class ActionsGuiController;
32 class CatalogueController;
33 class CatalogueController;
33
34
34 /* stolen from here https://forum.qt.io/topic/90403/show-tooltip-immediatly/6 */
35 /* stolen from here https://forum.qt.io/topic/90403/show-tooltip-immediatly/6 */
35 class MyProxyStyle : public QProxyStyle
36 class MyProxyStyle : public QProxyStyle
36 {
37 {
37 public:
38 public:
38 using QProxyStyle::QProxyStyle;
39 using QProxyStyle::QProxyStyle;
39
40
40 int styleHint(StyleHint hint, const QStyleOption* option = nullptr,
41 int styleHint(StyleHint hint, const QStyleOption* option = nullptr,
41 const QWidget* widget = nullptr, QStyleHintReturn* returnData = nullptr) const override
42 const QWidget* widget = nullptr, QStyleHintReturn* returnData = nullptr) const override
42 {
43 {
43 if (hint == QStyle::SH_ToolButton_PopupDelay && widget
44 if (hint == QStyle::SH_ToolButton_PopupDelay && widget
44 /*&& widget->inherits(QWidgetAction::staticMetaObject.className())*/)
45 /*&& widget->inherits(QWidgetAction::staticMetaObject.className())*/)
45 {
46 {
46 return 0;
47 return 0;
47 }
48 }
48
49
49 return QProxyStyle::styleHint(hint, option, widget, returnData);
50 return QProxyStyle::styleHint(hint, option, widget, returnData);
50 }
51 }
51 };
52 };
52
53
53 /**
54 /**
54 * @brief The SqpApplication class aims to make the link between SciQlop
55 * @brief The SqpApplication class aims to make the link between SciQlop
55 * and its plugins. This is the intermediate class that SciQlop has to use
56 * and its plugins. This is the intermediate class that SciQlop has to use
56 * in the way to connect a data source. Please first use load method to initialize
57 * in the way to connect a data source. Please first use load method to initialize
57 * a plugin specified by its metadata name (JSON plugin source) then others specifics
58 * a plugin specified by its metadata name (JSON plugin source) then others specifics
58 * method will be able to access it.
59 * method will be able to access it.
59 * You can load a data source driver plugin then create a data source.
60 * You can load a data source driver plugin then create a data source.
60 */
61 */
61
62
62 class SqpApplication : public QApplication
63 class SqpApplication : public QApplication
63 {
64 {
64 Q_OBJECT
65 Q_OBJECT
65 public:
66 public:
66 explicit SqpApplication(int& argc, char** argv);
67 explicit SqpApplication(int& argc, char** argv);
67 ~SqpApplication() override;
68 ~SqpApplication() override;
68 void initialize();
69 void initialize();
69
70
70 /// Accessors for the differents sciqlop controllers
71 /// Accessors for the differents sciqlop controllers
71 DataSourceController& dataSourceController() noexcept;
72 //DataSourceController& dataSourceController() noexcept;
73 DataSources& dataSources() noexcept;
72 NetworkController& networkController() noexcept;
74 NetworkController& networkController() noexcept;
73 TimeController& timeController() noexcept;
75 TimeController& timeController() noexcept;
74 VariableController2& variableController() noexcept;
76 VariableController2& variableController() noexcept;
75 std::shared_ptr<VariableController2> variableControllerOwner() noexcept;
77 std::shared_ptr<VariableController2> variableControllerOwner() noexcept;
76 CatalogueController& catalogueController() noexcept;
78 CatalogueController& catalogueController() noexcept;
77
79
78 /// Accessors for the differents sciqlop helpers, these helpers classes are like controllers but
80 /// Accessors for the differents sciqlop helpers, these helpers classes are like controllers but
79 /// doesn't live in a thread and access gui
81 /// doesn't live in a thread and access gui
80 DragDropGuiController& dragDropGuiController() noexcept;
82 DragDropGuiController& dragDropGuiController() noexcept;
81 ActionsGuiController& actionsGuiController() noexcept;
83 ActionsGuiController& actionsGuiController() noexcept;
82
84
83 enum class PlotsInteractionMode
85 enum class PlotsInteractionMode
84 {
86 {
85 None,
87 None,
86 ZoomBox,
88 ZoomBox,
87 DragAndDrop,
89 DragAndDrop,
88 SelectionZones
90 SelectionZones
89 };
91 };
90
92
91 enum class PlotsCursorMode
93 enum class PlotsCursorMode
92 {
94 {
93 NoCursor,
95 NoCursor,
94 Vertical,
96 Vertical,
95 Temporal,
97 Temporal,
96 Horizontal,
98 Horizontal,
97 Cross
99 Cross
98 };
100 };
99
101
100 PlotsInteractionMode plotsInteractionMode() const;
102 PlotsInteractionMode plotsInteractionMode() const;
101 void setPlotsInteractionMode(PlotsInteractionMode mode);
103 void setPlotsInteractionMode(PlotsInteractionMode mode);
102
104
103 PlotsCursorMode plotsCursorMode() const;
105 PlotsCursorMode plotsCursorMode() const;
104 void setPlotsCursorMode(PlotsCursorMode mode);
106 void setPlotsCursorMode(PlotsCursorMode mode);
105
107
106 private:
108 private:
107 class SqpApplicationPrivate;
109 class SqpApplicationPrivate;
108 spimpl::unique_impl_ptr<SqpApplicationPrivate> impl;
110 spimpl::unique_impl_ptr<SqpApplicationPrivate> impl;
109 };
111 };
110
112
111 inline SqpApplication* SqpApplication_ctor()
113 inline SqpApplication* SqpApplication_ctor()
112 {
114 {
113 static int argc;
115 static int argc;
114 static char** argv;
116 static char** argv;
115 return new SqpApplication(argc, argv);
117 return new SqpApplication(argc, argv);
116 }
118 }
117
119
118 #endif // SCIQLOP_SQPAPPLICATION_H
120 #endif // SCIQLOP_SQPAPPLICATION_H
@@ -1,179 +1,173
1
1
2 gui_moc_headers = [
2 gui_moc_headers = [
3 './include/Common/VisualizationDef.h',
3 './include/Common/VisualizationDef.h',
4 './include/Common/ColorUtils.h',
4 './include/Common/ColorUtils.h',
5 './include/DragAndDrop/DragDropGuiController.h',
5 './include/DragAndDrop/DragDropGuiController.h',
6 './include/DragAndDrop/DragDropTabSwitcher.h',
6 './include/DragAndDrop/DragDropTabSwitcher.h',
7 './include/DragAndDrop/DragDropScroller.h',
7 './include/DragAndDrop/DragDropScroller.h',
8 './include/Settings/SqpSettingsDialog.h',
8 './include/Settings/SqpSettingsDialog.h',
9 './include/Settings/SqpSettingsGeneralWidget.h',
9 './include/Settings/SqpSettingsGeneralWidget.h',
10 './include/DataSource/DataSourceTreeWidgetHelper.h',
11 './include/DataSource/DataSourceTreeWidget.h',
12 './include/DataSource/DataSourceTreeWidgetItem.h',
13 './include/DataSource/DataSourceWidget.h',
10 './include/DataSource/DataSourceWidget.h',
14 './include/Catalogue2/repositoriestreeview.h',
11 './include/Catalogue2/repositoriestreeview.h',
15 './include/Catalogue2/browser.h',
12 './include/Catalogue2/browser.h',
16 './include/Catalogue2/eventeditor.h',
13 './include/Catalogue2/eventeditor.h',
17 './include/Catalogue2/eventsmodel.h',
14 './include/Catalogue2/eventsmodel.h',
18 './include/Catalogue2/eventstreeview.h',
15 './include/Catalogue2/eventstreeview.h',
19 './include/Catalogue2/repositoriesmodel.h',
16 './include/Catalogue2/repositoriesmodel.h',
20 './include/TimeWidget/TimeWidget.h',
17 './include/TimeWidget/TimeWidget.h',
21 './include/SqpApplication.h',
18 './include/SqpApplication.h',
22 './include/SidePane/SqpSidePane.h',
19 './include/SidePane/SqpSidePane.h',
23 './include/Variable/RenameVariableDialog.h',
20 './include/Variable/RenameVariableDialog.h',
24 './include/Variable/VariableInspectorWidget.h',
21 './include/Variable/VariableInspectorWidget.h',
25 './include/Variable/VariableInspectorTableView.h',
22 './include/Variable/VariableInspectorTableView.h',
26 './include/Variable/VariableMenuHeaderWidget.h',
23 './include/Variable/VariableMenuHeaderWidget.h',
27 './include/Visualization/VisualizationDragWidget.h',
24 './include/Visualization/VisualizationDragWidget.h',
28 './include/Visualization/VisualizationZoneWidget.h',
25 './include/Visualization/VisualizationZoneWidget.h',
29 './include/Visualization/operations/GenerateVariableMenuOperation.h',
26 './include/Visualization/operations/GenerateVariableMenuOperation.h',
30 './include/Visualization/operations/RescaleAxeOperation.h',
27 './include/Visualization/operations/RescaleAxeOperation.h',
31 './include/Visualization/operations/RemoveVariableOperation.h',
28 './include/Visualization/operations/RemoveVariableOperation.h',
32 './include/Visualization/operations/MenuBuilder.h',
29 './include/Visualization/operations/MenuBuilder.h',
33 './include/Visualization/operations/FindVariableOperation.h',
30 './include/Visualization/operations/FindVariableOperation.h',
34 './include/Visualization/VisualizationDefs.h',
31 './include/Visualization/VisualizationDefs.h',
35 './include/Visualization/IVisualizationWidgetVisitor.h',
32 './include/Visualization/IVisualizationWidgetVisitor.h',
36 './include/Visualization/SqpColorScale.h',
33 './include/Visualization/SqpColorScale.h',
37 './include/Visualization/VisualizationGraphRenderingDelegate.h',
34 './include/Visualization/VisualizationGraphRenderingDelegate.h',
38 './include/Visualization/VisualizationGraphWidget.h',
35 './include/Visualization/VisualizationGraphWidget.h',
39 './include/Visualization/MacScrollBarStyle.h',
36 './include/Visualization/MacScrollBarStyle.h',
40 './include/Visualization/IVisualizationWidget.h',
37 './include/Visualization/IVisualizationWidget.h',
41 './include/Visualization/qcustomplot.h',
38 './include/Visualization/qcustomplot.h',
42 './include/Visualization/IGraphSynchronizer.h',
39 './include/Visualization/IGraphSynchronizer.h',
43 './include/Visualization/QCPColorMapIterator.h',
40 './include/Visualization/QCPColorMapIterator.h',
44 './include/Visualization/VisualizationActionManager.h',
41 './include/Visualization/VisualizationActionManager.h',
45 './include/Visualization/VisualizationTabWidget.h',
42 './include/Visualization/VisualizationTabWidget.h',
46 './include/Visualization/IVariableContainer.h',
43 './include/Visualization/IVariableContainer.h',
47 './include/Visualization/AxisRenderingUtils.h',
44 './include/Visualization/AxisRenderingUtils.h',
48 './include/Visualization/VisualizationMultiZoneSelectionDialog.h',
45 './include/Visualization/VisualizationMultiZoneSelectionDialog.h',
49 './include/Visualization/VisualizationCursorItem.h',
46 './include/Visualization/VisualizationCursorItem.h',
50 './include/Visualization/VisualizationWidget.h',
47 './include/Visualization/VisualizationWidget.h',
51 './include/Visualization/PlottablesRenderingUtils.h',
48 './include/Visualization/PlottablesRenderingUtils.h',
52 './include/Visualization/VisualizationSelectionZoneManager.h',
49 './include/Visualization/VisualizationSelectionZoneManager.h',
53 './include/Visualization/QCustomPlotSynchronizer.h',
50 './include/Visualization/QCustomPlotSynchronizer.h',
54 './include/Visualization/VisualizationSelectionZoneItem.h',
51 './include/Visualization/VisualizationSelectionZoneItem.h',
55 './include/Visualization/VisualizationDragDropContainer.h',
52 './include/Visualization/VisualizationDragDropContainer.h',
56 './include/Visualization/ColorScaleEditor.h',
53 './include/Visualization/ColorScaleEditor.h',
57 './include/Visualization/VisualizationGraphHelper.h',
54 './include/Visualization/VisualizationGraphHelper.h',
58 './include/Actions/ActionsGuiController.h',
55 './include/Actions/ActionsGuiController.h',
59 './include/Actions/FilteringAction.h',
56 './include/Actions/FilteringAction.h',
60 './include/Actions/SelectionZoneAction.h'
57 './include/Actions/SelectionZoneAction.h'
61 ]
58 ]
62
59
63
60
64 gui_ui_files = [
61 gui_ui_files = [
65 './ui/Settings/SqpSettingsGeneralWidget.ui',
62 './ui/Settings/SqpSettingsGeneralWidget.ui',
66 './ui/Settings/SqpSettingsDialog.ui',
63 './ui/Settings/SqpSettingsDialog.ui',
67 './ui/DataSource/DataSourceWidget.ui',
64 './ui/DataSource/DataSourceWidget.ui',
68 './ui/Catalogue2/browser.ui',
65 './ui/Catalogue2/browser.ui',
69 './ui/Catalogue2/eventeditor.ui',
66 './ui/Catalogue2/eventeditor.ui',
70 './ui/TimeWidget/TimeWidget.ui',
67 './ui/TimeWidget/TimeWidget.ui',
71 './ui/SidePane/SqpSidePane.ui',
68 './ui/SidePane/SqpSidePane.ui',
72 './ui/Variable/RenameVariableDialog.ui',
69 './ui/Variable/RenameVariableDialog.ui',
73 './ui/Variable/VariableInspectorWidget.ui',
70 './ui/Variable/VariableInspectorWidget.ui',
74 './ui/Variable/VariableMenuHeaderWidget.ui',
71 './ui/Variable/VariableMenuHeaderWidget.ui',
75 './ui/Visualization/ColorScaleEditor.ui',
72 './ui/Visualization/ColorScaleEditor.ui',
76 './ui/Visualization/VisualizationZoneWidget.ui',
73 './ui/Visualization/VisualizationZoneWidget.ui',
77 './ui/Visualization/VisualizationMultiZoneSelectionDialog.ui',
74 './ui/Visualization/VisualizationMultiZoneSelectionDialog.ui',
78 './ui/Visualization/VisualizationGraphWidget.ui',
75 './ui/Visualization/VisualizationGraphWidget.ui',
79 './ui/Visualization/VisualizationWidget.ui',
76 './ui/Visualization/VisualizationWidget.ui',
80 './ui/Visualization/VisualizationTabWidget.ui'
77 './ui/Visualization/VisualizationTabWidget.ui'
81 ]
78 ]
82
79
83 gui_qresources = ['resources/sqpguiresources.qrc']
80 gui_qresources = ['resources/sqpguiresources.qrc']
84
81
85 rcc_gen = generator(rcc,
82 rcc_gen = generator(rcc,
86 output : 'qrc_@BASENAME@.cpp',
83 output : 'qrc_@BASENAME@.cpp',
87 arguments : [
84 arguments : [
88 '--output',
85 '--output',
89 '@OUTPUT@',
86 '@OUTPUT@',
90 '@INPUT@',
87 '@INPUT@',
91 '@EXTRA_ARGS@'])
88 '@EXTRA_ARGS@'])
92
89
93 rcc_files = rcc_gen.process(gui_qresources, extra_args : ['-name', 'sqpguiresources'])
90 rcc_files = rcc_gen.process(gui_qresources, extra_args : ['-name', 'sqpguiresources'])
94
91
95 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
92 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
96 ui_files : gui_ui_files)
93 ui_files : gui_ui_files)
97
94
98 gui_sources = [
95 gui_sources = [
99 './src/Common/ColorUtils.cpp',
96 './src/Common/ColorUtils.cpp',
100 './src/Common/VisualizationDef.cpp',
97 './src/Common/VisualizationDef.cpp',
101 './src/SqpApplication.cpp',
98 './src/SqpApplication.cpp',
102 './src/DragAndDrop/DragDropTabSwitcher.cpp',
99 './src/DragAndDrop/DragDropTabSwitcher.cpp',
103 './src/DragAndDrop/DragDropScroller.cpp',
100 './src/DragAndDrop/DragDropScroller.cpp',
104 './src/DragAndDrop/DragDropGuiController.cpp',
101 './src/DragAndDrop/DragDropGuiController.cpp',
105 './src/Settings/SqpSettingsGeneralWidget.cpp',
102 './src/Settings/SqpSettingsGeneralWidget.cpp',
106 './src/Settings/SqpSettingsDialog.cpp',
103 './src/Settings/SqpSettingsDialog.cpp',
107 './src/DataSource/DataSourceTreeWidgetItem.cpp',
108 './src/DataSource/DataSourceTreeWidgetHelper.cpp',
109 './src/DataSource/DataSourceWidget.cpp',
104 './src/DataSource/DataSourceWidget.cpp',
110 './src/DataSource/DataSourceTreeWidget.cpp',
111 './src/Catalogue2/eventstreeview.cpp',
105 './src/Catalogue2/eventstreeview.cpp',
112 './src/Catalogue2/eventeditor.cpp',
106 './src/Catalogue2/eventeditor.cpp',
113 './src/Catalogue2/repositoriestreeview.cpp',
107 './src/Catalogue2/repositoriestreeview.cpp',
114 './src/Catalogue2/browser.cpp',
108 './src/Catalogue2/browser.cpp',
115 './src/Catalogue2/eventsmodel.cpp',
109 './src/Catalogue2/eventsmodel.cpp',
116 './src/Catalogue2/repositoriesmodel.cpp',
110 './src/Catalogue2/repositoriesmodel.cpp',
117 './src/TimeWidget/TimeWidget.cpp',
111 './src/TimeWidget/TimeWidget.cpp',
118 './src/SidePane/SqpSidePane.cpp',
112 './src/SidePane/SqpSidePane.cpp',
119 './src/Variable/VariableInspectorTableView.cpp',
113 './src/Variable/VariableInspectorTableView.cpp',
120 './src/Variable/VariableInspectorWidget.cpp',
114 './src/Variable/VariableInspectorWidget.cpp',
121 './src/Variable/RenameVariableDialog.cpp',
115 './src/Variable/RenameVariableDialog.cpp',
122 './src/Variable/VariableMenuHeaderWidget.cpp',
116 './src/Variable/VariableMenuHeaderWidget.cpp',
123 './src/Visualization/VisualizationGraphWidget.cpp',
117 './src/Visualization/VisualizationGraphWidget.cpp',
124 './src/Visualization/PlottablesRenderingUtils.cpp',
118 './src/Visualization/PlottablesRenderingUtils.cpp',
125 './src/Visualization/AxisRenderingUtils.cpp',
119 './src/Visualization/AxisRenderingUtils.cpp',
126 './src/Visualization/VisualizationWidget.cpp',
120 './src/Visualization/VisualizationWidget.cpp',
127 './src/Visualization/qcustomplot.cpp',
121 './src/Visualization/qcustomplot.cpp',
128 './src/Visualization/VisualizationDragWidget.cpp',
122 './src/Visualization/VisualizationDragWidget.cpp',
129 './src/Visualization/VisualizationActionManager.cpp',
123 './src/Visualization/VisualizationActionManager.cpp',
130 './src/Visualization/MacScrollBarStyle.cpp',
124 './src/Visualization/MacScrollBarStyle.cpp',
131 './src/Visualization/VisualizationSelectionZoneManager.cpp',
125 './src/Visualization/VisualizationSelectionZoneManager.cpp',
132 './src/Visualization/operations/FindVariableOperation.cpp',
126 './src/Visualization/operations/FindVariableOperation.cpp',
133 './src/Visualization/operations/RescaleAxeOperation.cpp',
127 './src/Visualization/operations/RescaleAxeOperation.cpp',
134 './src/Visualization/operations/MenuBuilder.cpp',
128 './src/Visualization/operations/MenuBuilder.cpp',
135 './src/Visualization/operations/GenerateVariableMenuOperation.cpp',
129 './src/Visualization/operations/GenerateVariableMenuOperation.cpp',
136 './src/Visualization/operations/RemoveVariableOperation.cpp',
130 './src/Visualization/operations/RemoveVariableOperation.cpp',
137 './src/Visualization/VisualizationSelectionZoneItem.cpp',
131 './src/Visualization/VisualizationSelectionZoneItem.cpp',
138 './src/Visualization/VisualizationCursorItem.cpp',
132 './src/Visualization/VisualizationCursorItem.cpp',
139 './src/Visualization/QCPColorMapIterator.cpp',
133 './src/Visualization/QCPColorMapIterator.cpp',
140 './src/Visualization/QCustomPlotSynchronizer.cpp',
134 './src/Visualization/QCustomPlotSynchronizer.cpp',
141 './src/Visualization/ColorScaleEditor.cpp',
135 './src/Visualization/ColorScaleEditor.cpp',
142 './src/Visualization/VisualizationMultiZoneSelectionDialog.cpp',
136 './src/Visualization/VisualizationMultiZoneSelectionDialog.cpp',
143 './src/Visualization/VisualizationTabWidget.cpp',
137 './src/Visualization/VisualizationTabWidget.cpp',
144 './src/Visualization/VisualizationGraphHelper.cpp',
138 './src/Visualization/VisualizationGraphHelper.cpp',
145 './src/Visualization/VisualizationGraphRenderingDelegate.cpp',
139 './src/Visualization/VisualizationGraphRenderingDelegate.cpp',
146 './src/Visualization/VisualizationDragDropContainer.cpp',
140 './src/Visualization/VisualizationDragDropContainer.cpp',
147 './src/Visualization/VisualizationZoneWidget.cpp',
141 './src/Visualization/VisualizationZoneWidget.cpp',
148 './src/Visualization/SqpColorScale.cpp',
142 './src/Visualization/SqpColorScale.cpp',
149 './src/Actions/FilteringAction.cpp',
143 './src/Actions/FilteringAction.cpp',
150 './src/Actions/SelectionZoneAction.cpp',
144 './src/Actions/SelectionZoneAction.cpp',
151 './src/Actions/ActionsGuiController.cpp'
145 './src/Actions/ActionsGuiController.cpp'
152 ]
146 ]
153
147
154 gui_inc = include_directories(['include', 'include/Visualization'])
148 gui_inc = include_directories(['include', 'include/Visualization'])
155
149
156 sciqlop_gui_lib = library('sciqlopgui',
150 sciqlop_gui_lib = library('sciqlopgui',
157 gui_sources,
151 gui_sources,
158 gui_moc_files,
152 gui_moc_files,
159 rcc_files,
153 rcc_files,
160 include_directories : [gui_inc],
154 include_directories : [gui_inc],
161 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core],
155 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core],
162 install : true
156 install : true
163 )
157 )
164
158
165 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
159 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
166 include_directories : gui_inc,
160 include_directories : gui_inc,
167 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core])
161 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core])
168
162
169 gui_tests_inc = include_directories(['tests/GUITestUtils'])
163 gui_tests_inc = include_directories(['tests/GUITestUtils'])
170
164
171 catalogue_browser_moc_files = qt5.preprocess(moc_sources : 'tests/catalogue/browser/main.cpp')
165 catalogue_browser_moc_files = qt5.preprocess(moc_sources : 'tests/catalogue/browser/main.cpp')
172 catalogue_browser = executable('catalogue_browser', 'tests/catalogue/browser/main.cpp',catalogue_browser_moc_files,
166 catalogue_browser = executable('catalogue_browser', 'tests/catalogue/browser/main.cpp',catalogue_browser_moc_files,
173 include_directories : gui_tests_inc,
167 include_directories : gui_tests_inc,
174 dependencies :[sciqlop_gui, qt5test])
168 dependencies :[sciqlop_gui, qt5test])
175
169
176
170
177 if get_option('biuld_gui_tests')
171 if get_option('biuld_gui_tests')
178 subdir('tests')
172 subdir('tests')
179 endif
173 endif
@@ -1,124 +1,42
1 #include <DataSource/DataSourceWidget.h>
1 #include <DataSource/DataSourceWidget.h>
2
2
3 #include <ui_DataSourceWidget.h>
3 #include <ui_DataSourceWidget.h>
4
4
5 #include <DataSource/DataSourceItem.h>
5 #include <DataSource/datasources.h>
6 #include <DataSource/DataSourceTreeWidgetHelper.h>
6
7 #include <DataSource/DataSourceTreeWidgetItem.h>
7 #include <SqpApplication.h>
8
8
9 #include <QMenu>
10
9
11 namespace
10 namespace
12 {
11 {
13
12
14 /// Number of columns displayed in the tree
13 /// Number of columns displayed in the tree
15 const auto TREE_NB_COLUMNS = 1;
14 const auto TREE_NB_COLUMNS = 1;
16
15
17 /// Header labels for the tree
16 /// Header labels for the tree
18 const auto TREE_HEADER_LABELS = QStringList { QObject::tr("Name") };
17 const auto TREE_HEADER_LABELS = QStringList { QObject::tr("Name") };
19
18
20 /**
21 * Creates the item associated to a data source
22 * @param dataSource the data source for which to create the item
23 * @return the new item
24 */
25 DataSourceTreeWidgetItem* createTreeWidgetItem(DataSourceItem* dataSource)
26 {
27 // Creates item for the data source
28 auto item = new DataSourceTreeWidgetItem { dataSource };
29 // Generates items for the children of the data source
30 std::for_each(dataSource->cbegin(), dataSource->cend(),
31 [&item](const std::unique_ptr<DataSourceItem>& child) {
32 item->addChild(createTreeWidgetItem(child.get()));
33 });
34 return item;
35 }
36
37 } // namespace
19 } // namespace
38
20
39 DataSourceWidget::DataSourceWidget(QWidget* parent)
21 DataSourceWidget::DataSourceWidget(QWidget* parent)
40 : QWidget { parent }
22 : QWidget { parent }
41 , ui { new Ui::DataSourceWidget }
23 , ui { new Ui::DataSourceWidget }
42 , m_Root { std::make_unique<DataSourceItem>(
43 DataSourceItemType::NODE, QStringLiteral("Sources")) }
44 {
24 {
45 ui->setupUi(this);
25 ui->setupUi(this);
46
26 m_model_proxy.setSourceModel(&(sqpApp->dataSources()));
47 // Set tree properties
27 ui->treeView->setModel(&m_model_proxy);
48 ui->treeWidget->setColumnCount(TREE_NB_COLUMNS);
28 ui->treeView->setDragEnabled(true);
49 ui->treeWidget->setHeaderLabels(TREE_HEADER_LABELS);
29 m_model_proxy.setFilterRole(Qt::ToolTipRole);
50 ui->treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
30 m_model_proxy.setRecursiveFilteringEnabled(true);
51
52 // Connection to show a menu when right clicking on the tree
53 connect(ui->treeWidget, &QTreeWidget::customContextMenuRequested, this,
54 &DataSourceWidget::onTreeMenuRequested);
55
31
56 // Connection to filter tree
32 // Connection to filter tree
57 connect(ui->filterLineEdit, &QLineEdit::textChanged, this, &DataSourceWidget::filterChanged);
33 connect(ui->filterLineEdit, &QLineEdit::textChanged, &m_model_proxy, static_cast<void (QSortFilterProxyModel::*)(const QString&)>(
34 &QSortFilterProxyModel::setFilterRegExp));
58
35
59 // First init
60 updateTreeWidget();
61 }
36 }
62
37
63 DataSourceWidget::~DataSourceWidget() noexcept
38 DataSourceWidget::~DataSourceWidget() noexcept
64 {
39 {
65 delete ui;
40 delete ui;
66 }
41 }
67
42
68 void DataSourceWidget::addDataSource(DataSourceItem* dataSource) noexcept
69 {
70 // Merges the data source (without taking its root)
71 if (dataSource)
72 {
73 std::for_each(std::cbegin(*dataSource), std::cend(*dataSource),
74 [this](const auto& child) { this->m_Root->merge(*child.get()); });
75 updateTreeWidget();
76 }
77 }
78
79 void DataSourceWidget::updateTreeWidget() noexcept
80 {
81 ui->treeWidget->clear();
82
83 auto rootItem = createTreeWidgetItem(m_Root.get());
84 ui->treeWidget->addTopLevelItem(rootItem);
85 rootItem->setExpanded(true);
86
87 // Sorts tree
88 ui->treeWidget->setSortingEnabled(true);
89 ui->treeWidget->sortByColumn(0, Qt::AscendingOrder);
90 }
91
92 void DataSourceWidget::filterChanged(const QString& text) noexcept
93 {
94 auto validateItem = [&text](const DataSourceTreeWidgetItem& item) {
95 auto regExp = QRegExp { text, Qt::CaseInsensitive, QRegExp::Wildcard };
96
97 // An item is valid if any of its metadata validates the text filter
98 auto itemMetadata = item.data()->data();
99 auto itemMetadataEnd = itemMetadata.cend();
100 auto acceptFilter
101 = [&regExp](const auto& variant) { return variant.toString().contains(regExp); };
102
103 return std::find_if(itemMetadata.cbegin(), itemMetadataEnd, acceptFilter)
104 != itemMetadataEnd;
105 };
106
107 // Applies filter on tree widget
108 DataSourceTreeWidgetHelper::filter(*ui->treeWidget, validateItem);
109 }
110
111 void DataSourceWidget::onTreeMenuRequested(const QPoint& pos) noexcept
112 {
113 // Retrieves the selected item in the tree, and build the menu from its actions
114 if (auto selectedItem = dynamic_cast<DataSourceTreeWidgetItem*>(ui->treeWidget->itemAt(pos)))
115 {
116 QMenu treeMenu {};
117 treeMenu.addActions(selectedItem->actions());
118
119 if (!treeMenu.isEmpty())
120 {
121 treeMenu.exec(QCursor::pos());
122 }
123 }
124 }
@@ -1,331 +1,330
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"
11 #include "Variable/VariableController2.h"
10 #include "Variable/VariableController2.h"
12
11
13 #include "Common/MimeTypesDef.h"
12 #include "MimeTypes/MimeTypes.h"
14 #include "Common/VisualizationDef.h"
13 #include "Common/VisualizationDef.h"
15
14
16 #include <QDir>
15 #include <QDir>
17 #include <QLabel>
16 #include <QLabel>
18 #include <QUrl>
17 #include <QUrl>
19 #include <QVBoxLayout>
18 #include <QVBoxLayout>
20
19
21
20
22 Q_LOGGING_CATEGORY(LOG_DragDropGuiController, "DragDropGuiController")
21 Q_LOGGING_CATEGORY(LOG_DragDropGuiController, "DragDropGuiController")
23
22
24
23
25 struct DragDropGuiController::DragDropGuiControllerPrivate
24 struct DragDropGuiController::DragDropGuiControllerPrivate
26 {
25 {
27
26
28 VisualizationDragWidget* m_CurrentDragWidget = nullptr;
27 VisualizationDragWidget* m_CurrentDragWidget = nullptr;
29 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
28 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
30 QLabel* m_PlaceHolderLabel;
29 QLabel* m_PlaceHolderLabel;
31 QWidget* m_PlaceBackground;
30 QWidget* m_PlaceBackground;
32 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
31 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
33 std::unique_ptr<DragDropTabSwitcher> m_DragDropTabSwitcher = nullptr;
32 std::unique_ptr<DragDropTabSwitcher> m_DragDropTabSwitcher = nullptr;
34 QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using
33 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.
34 // QTemporaryFile to have a name which is not generated.
36
35
37 VisualizationDragWidget* m_HighlightedDragWidget = nullptr;
36 VisualizationDragWidget* m_HighlightedDragWidget = nullptr;
38
37
39 QMetaObject::Connection m_DragWidgetDestroyedConnection;
38 QMetaObject::Connection m_DragWidgetDestroyedConnection;
40 QMetaObject::Connection m_HighlightedWidgetDestroyedConnection;
39 QMetaObject::Connection m_HighlightedWidgetDestroyedConnection;
41
40
42 QList<QWidget*> m_WidgetToClose;
41 QList<QWidget*> m_WidgetToClose;
43
42
44 explicit DragDropGuiControllerPrivate()
43 explicit DragDropGuiControllerPrivate()
45 : m_PlaceHolder { std::make_unique<QWidget>() }
44 : m_PlaceHolder { std::make_unique<QWidget>() }
46 , m_DragDropScroller { std::make_unique<DragDropScroller>() }
45 , m_DragDropScroller { std::make_unique<DragDropScroller>() }
47 , m_DragDropTabSwitcher { std::make_unique<DragDropTabSwitcher>() }
46 , m_DragDropTabSwitcher { std::make_unique<DragDropTabSwitcher>() }
48 {
47 {
49
48
50 auto layout = new QVBoxLayout { m_PlaceHolder.get() };
49 auto layout = new QVBoxLayout { m_PlaceHolder.get() };
51 layout->setSpacing(0);
50 layout->setSpacing(0);
52 layout->setContentsMargins(0, 0, 0, 0);
51 layout->setContentsMargins(0, 0, 0, 0);
53
52
54 m_PlaceHolderLabel = new QLabel { "", m_PlaceHolder.get() };
53 m_PlaceHolderLabel = new QLabel { "", m_PlaceHolder.get() };
55 m_PlaceHolderLabel->setMinimumHeight(25);
54 m_PlaceHolderLabel->setMinimumHeight(25);
56 layout->addWidget(m_PlaceHolderLabel);
55 layout->addWidget(m_PlaceHolderLabel);
57
56
58 m_PlaceBackground = new QWidget { m_PlaceHolder.get() };
57 m_PlaceBackground = new QWidget { m_PlaceHolder.get() };
59 m_PlaceBackground->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
58 m_PlaceBackground->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
60 layout->addWidget(m_PlaceBackground);
59 layout->addWidget(m_PlaceBackground);
61
60
62 sqpApp->installEventFilter(m_DragDropScroller.get());
61 sqpApp->installEventFilter(m_DragDropScroller.get());
63 sqpApp->installEventFilter(m_DragDropTabSwitcher.get());
62 sqpApp->installEventFilter(m_DragDropTabSwitcher.get());
64
63
65 m_ImageTempUrl = QDir::temp().absoluteFilePath("Sciqlop_graph.png");
64 m_ImageTempUrl = QDir::temp().absoluteFilePath("Sciqlop_graph.png");
66 }
65 }
67
66
68 void preparePlaceHolder(
67 void preparePlaceHolder(
69 DragDropGuiController::PlaceHolderType type, const QString& topLabelText) const
68 DragDropGuiController::PlaceHolderType type, const QString& topLabelText) const
70 {
69 {
71 if (m_CurrentDragWidget)
70 if (m_CurrentDragWidget)
72 {
71 {
73 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
72 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
74 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
73 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
75 }
74 }
76 else
75 else
77 {
76 {
78 // Configuration of the placeHolder when there is no dragWidget
77 // Configuration of the placeHolder when there is no dragWidget
79 // (for instance with a drag from a variable)
78 // (for instance with a drag from a variable)
80
79
81 m_PlaceHolder->setMinimumSize(0, GRAPH_MINIMUM_HEIGHT);
80 m_PlaceHolder->setMinimumSize(0, GRAPH_MINIMUM_HEIGHT);
82 m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
81 m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
83 }
82 }
84
83
85 switch (type)
84 switch (type)
86 {
85 {
87 case DragDropGuiController::PlaceHolderType::Graph:
86 case DragDropGuiController::PlaceHolderType::Graph:
88 m_PlaceBackground->setStyleSheet(
87 m_PlaceBackground->setStyleSheet(
89 "background-color: #BBD5EE; border: 1px solid #2A7FD4");
88 "background-color: #BBD5EE; border: 1px solid #2A7FD4");
90 break;
89 break;
91 case DragDropGuiController::PlaceHolderType::Zone:
90 case DragDropGuiController::PlaceHolderType::Zone:
92 case DragDropGuiController::PlaceHolderType::Default:
91 case DragDropGuiController::PlaceHolderType::Default:
93 m_PlaceBackground->setStyleSheet(
92 m_PlaceBackground->setStyleSheet(
94 "background-color: #BBD5EE; border: 2px solid #2A7FD4");
93 "background-color: #BBD5EE; border: 2px solid #2A7FD4");
95 m_PlaceHolderLabel->setStyleSheet("color: #2A7FD4");
94 m_PlaceHolderLabel->setStyleSheet("color: #2A7FD4");
96 break;
95 break;
97 }
96 }
98
97
99 m_PlaceHolderLabel->setText(topLabelText);
98 m_PlaceHolderLabel->setText(topLabelText);
100 m_PlaceHolderLabel->setVisible(!topLabelText.isEmpty());
99 m_PlaceHolderLabel->setVisible(!topLabelText.isEmpty());
101 }
100 }
102 };
101 };
103
102
104
103
105 DragDropGuiController::DragDropGuiController()
104 DragDropGuiController::DragDropGuiController()
106 : impl { spimpl::make_unique_impl<DragDropGuiControllerPrivate>() }
105 : impl { spimpl::make_unique_impl<DragDropGuiControllerPrivate>() }
107 {
106 {
108 }
107 }
109
108
110 DragDropGuiController::~DragDropGuiController()
109 DragDropGuiController::~DragDropGuiController()
111 {
110 {
112 QFile::remove(impl->m_ImageTempUrl);
111 QFile::remove(impl->m_ImageTempUrl);
113 }
112 }
114
113
115 void DragDropGuiController::resetDragAndDrop()
114 void DragDropGuiController::resetDragAndDrop()
116 {
115 {
117 setCurrentDragWidget(nullptr);
116 setCurrentDragWidget(nullptr);
118 impl->m_HighlightedDragWidget = nullptr;
117 impl->m_HighlightedDragWidget = nullptr;
119 }
118 }
120
119
121 void DragDropGuiController::setCurrentDragWidget(VisualizationDragWidget* dragWidget)
120 void DragDropGuiController::setCurrentDragWidget(VisualizationDragWidget* dragWidget)
122 {
121 {
123 if (impl->m_CurrentDragWidget)
122 if (impl->m_CurrentDragWidget)
124 {
123 {
125
124
126 QObject::disconnect(impl->m_DragWidgetDestroyedConnection);
125 QObject::disconnect(impl->m_DragWidgetDestroyedConnection);
127 }
126 }
128
127
129 if (dragWidget)
128 if (dragWidget)
130 {
129 {
131 // ensures the impl->m_CurrentDragWidget is reset when the widget is destroyed
130 // ensures the impl->m_CurrentDragWidget is reset when the widget is destroyed
132 impl->m_DragWidgetDestroyedConnection = QObject::connect(dragWidget,
131 impl->m_DragWidgetDestroyedConnection = QObject::connect(dragWidget,
133 &VisualizationDragWidget::destroyed, [this]() { impl->m_CurrentDragWidget = nullptr; });
132 &VisualizationDragWidget::destroyed, [this]() { impl->m_CurrentDragWidget = nullptr; });
134 }
133 }
135
134
136 impl->m_CurrentDragWidget = dragWidget;
135 impl->m_CurrentDragWidget = dragWidget;
137 }
136 }
138
137
139 VisualizationDragWidget* DragDropGuiController::getCurrentDragWidget() const
138 VisualizationDragWidget* DragDropGuiController::getCurrentDragWidget() const
140 {
139 {
141 return impl->m_CurrentDragWidget;
140 return impl->m_CurrentDragWidget;
142 }
141 }
143
142
144 QWidget& DragDropGuiController::placeHolder() const
143 QWidget& DragDropGuiController::placeHolder() const
145 {
144 {
146 return *impl->m_PlaceHolder;
145 return *impl->m_PlaceHolder;
147 }
146 }
148
147
149 void DragDropGuiController::insertPlaceHolder(
148 void DragDropGuiController::insertPlaceHolder(
150 QVBoxLayout* layout, int index, PlaceHolderType type, const QString& topLabelText)
149 QVBoxLayout* layout, int index, PlaceHolderType type, const QString& topLabelText)
151 {
150 {
152 removePlaceHolder();
151 removePlaceHolder();
153 impl->preparePlaceHolder(type, topLabelText);
152 impl->preparePlaceHolder(type, topLabelText);
154 layout->insertWidget(index, impl->m_PlaceHolder.get());
153 layout->insertWidget(index, impl->m_PlaceHolder.get());
155 impl->m_PlaceHolder->show();
154 impl->m_PlaceHolder->show();
156 }
155 }
157
156
158 void DragDropGuiController::removePlaceHolder()
157 void DragDropGuiController::removePlaceHolder()
159 {
158 {
160 auto parentWidget = impl->m_PlaceHolder->parentWidget();
159 auto parentWidget = impl->m_PlaceHolder->parentWidget();
161 if (parentWidget)
160 if (parentWidget)
162 {
161 {
163 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
162 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
164 impl->m_PlaceHolder->setParent(nullptr);
163 impl->m_PlaceHolder->setParent(nullptr);
165 impl->m_PlaceHolder->hide();
164 impl->m_PlaceHolder->hide();
166 }
165 }
167 }
166 }
168
167
169 bool DragDropGuiController::isPlaceHolderSet() const
168 bool DragDropGuiController::isPlaceHolderSet() const
170 {
169 {
171 return impl->m_PlaceHolder->parentWidget();
170 return impl->m_PlaceHolder->parentWidget();
172 }
171 }
173
172
174 void DragDropGuiController::addDragDropScrollArea(QScrollArea* scrollArea)
173 void DragDropGuiController::addDragDropScrollArea(QScrollArea* scrollArea)
175 {
174 {
176 impl->m_DragDropScroller->addScrollArea(scrollArea);
175 impl->m_DragDropScroller->addScrollArea(scrollArea);
177 }
176 }
178
177
179 void DragDropGuiController::removeDragDropScrollArea(QScrollArea* scrollArea)
178 void DragDropGuiController::removeDragDropScrollArea(QScrollArea* scrollArea)
180 {
179 {
181 impl->m_DragDropScroller->removeScrollArea(scrollArea);
180 impl->m_DragDropScroller->removeScrollArea(scrollArea);
182 }
181 }
183
182
184 void DragDropGuiController::addDragDropTabBar(QTabBar* tabBar)
183 void DragDropGuiController::addDragDropTabBar(QTabBar* tabBar)
185 {
184 {
186 impl->m_DragDropTabSwitcher->addTabBar(tabBar);
185 impl->m_DragDropTabSwitcher->addTabBar(tabBar);
187 }
186 }
188
187
189 void DragDropGuiController::removeDragDropTabBar(QTabBar* tabBar)
188 void DragDropGuiController::removeDragDropTabBar(QTabBar* tabBar)
190 {
189 {
191 impl->m_DragDropTabSwitcher->removeTabBar(tabBar);
190 impl->m_DragDropTabSwitcher->removeTabBar(tabBar);
192 }
191 }
193
192
194 QUrl DragDropGuiController::imageTemporaryUrl(const QImage& image) const
193 QUrl DragDropGuiController::imageTemporaryUrl(const QImage& image) const
195 {
194 {
196 image.save(impl->m_ImageTempUrl);
195 image.save(impl->m_ImageTempUrl);
197 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
196 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
198 }
197 }
199
198
200 void DragDropGuiController::setHightlightedDragWidget(VisualizationDragWidget* dragWidget)
199 void DragDropGuiController::setHightlightedDragWidget(VisualizationDragWidget* dragWidget)
201 {
200 {
202 if (impl->m_HighlightedDragWidget)
201 if (impl->m_HighlightedDragWidget)
203 {
202 {
204 impl->m_HighlightedDragWidget->highlightForMerge(false);
203 impl->m_HighlightedDragWidget->highlightForMerge(false);
205 QObject::disconnect(impl->m_HighlightedWidgetDestroyedConnection);
204 QObject::disconnect(impl->m_HighlightedWidgetDestroyedConnection);
206 }
205 }
207
206
208 if (dragWidget)
207 if (dragWidget)
209 {
208 {
210 dragWidget->highlightForMerge(true);
209 dragWidget->highlightForMerge(true);
211
210
212 // ensures the impl->m_HighlightedDragWidget is reset when the widget is destroyed
211 // ensures the impl->m_HighlightedDragWidget is reset when the widget is destroyed
213 impl->m_DragWidgetDestroyedConnection
212 impl->m_DragWidgetDestroyedConnection
214 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
213 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
215 [this]() { impl->m_HighlightedDragWidget = nullptr; });
214 [this]() { impl->m_HighlightedDragWidget = nullptr; });
216 }
215 }
217
216
218 impl->m_HighlightedDragWidget = dragWidget;
217 impl->m_HighlightedDragWidget = dragWidget;
219 }
218 }
220
219
221 VisualizationDragWidget* DragDropGuiController::getHightlightedDragWidget() const
220 VisualizationDragWidget* DragDropGuiController::getHightlightedDragWidget() const
222 {
221 {
223 return impl->m_HighlightedDragWidget;
222 return impl->m_HighlightedDragWidget;
224 }
223 }
225
224
226 void DragDropGuiController::delayedCloseWidget(QWidget* widget)
225 void DragDropGuiController::delayedCloseWidget(QWidget* widget)
227 {
226 {
228 widget->hide();
227 widget->hide();
229 impl->m_WidgetToClose << widget;
228 impl->m_WidgetToClose << widget;
230 }
229 }
231
230
232 void DragDropGuiController::doCloseWidgets()
231 void DragDropGuiController::doCloseWidgets()
233 {
232 {
234 for (auto widget : impl->m_WidgetToClose)
233 for (auto widget : impl->m_WidgetToClose)
235 {
234 {
236 widget->close();
235 widget->close();
237 }
236 }
238
237
239 impl->m_WidgetToClose.clear();
238 impl->m_WidgetToClose.clear();
240 }
239 }
241
240
242 bool DragDropGuiController::checkMimeDataForVisualization(
241 bool DragDropGuiController::checkMimeDataForVisualization(
243 const QMimeData* mimeData, VisualizationDragDropContainer* dropContainer)
242 const QMimeData* mimeData, VisualizationDragDropContainer* dropContainer)
244 {
243 {
245 if (!mimeData || !dropContainer)
244 if (!mimeData || !dropContainer)
246 {
245 {
247 qCWarning(LOG_DragDropGuiController()) << QObject::tr(
246 qCWarning(LOG_DragDropGuiController()) << QObject::tr(
248 "DragDropGuiController::checkMimeDataForVisualization, invalid input parameters.");
247 "DragDropGuiController::checkMimeDataForVisualization, invalid input parameters.");
249 Q_ASSERT(false);
248 Q_ASSERT(false);
250 return false;
249 return false;
251 }
250 }
252
251
253 auto result = false;
252 auto result = false;
254
253
255 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST))
254 if (mimeData->hasFormat(MIME::MIME_TYPE_VARIABLE_LIST))
256 {
255 {
257 auto variables = sqpApp->variableController().variables(
256 auto variables = sqpApp->variableController().variables(
258 Variable2::IDs(mimeData->data(MIME_TYPE_VARIABLE_LIST)));
257 Variable2::IDs(mimeData->data(MIME::MIME_TYPE_VARIABLE_LIST)));
259
258
260 if (variables.size() == 1)
259 if (variables.size() == 1)
261 {
260 {
262
261
263 auto variable = variables[0];
262 auto variable = variables[0];
264 if (variable->data() != nullptr)
263 if (variable->data() != nullptr)
265 {
264 {
266
265
267 // Check that the variable is not already in a graph
266 // Check that the variable is not already in a graph
268
267
269 auto parent = dropContainer->parentWidget();
268 auto parent = dropContainer->parentWidget();
270 while (parent && qobject_cast<VisualizationWidget*>(parent) == nullptr)
269 while (parent && qobject_cast<VisualizationWidget*>(parent) == nullptr)
271 {
270 {
272 parent = parent->parentWidget(); // Search for the top level VisualizationWidget
271 parent = parent->parentWidget(); // Search for the top level VisualizationWidget
273 }
272 }
274
273
275 if (parent)
274 if (parent)
276 {
275 {
277 auto visualizationWidget = static_cast<VisualizationWidget*>(parent);
276 auto visualizationWidget = static_cast<VisualizationWidget*>(parent);
278
277
279 FindVariableOperation findVariableOperation { variable };
278 FindVariableOperation findVariableOperation { variable };
280 visualizationWidget->accept(&findVariableOperation);
279 visualizationWidget->accept(&findVariableOperation);
281 auto variableContainers = findVariableOperation.result();
280 auto variableContainers = findVariableOperation.result();
282 if (variableContainers.empty())
281 if (variableContainers.empty())
283 {
282 {
284 result = true;
283 result = true;
285 }
284 }
286 else
285 else
287 {
286 {
288 // result = false: the variable already exist in the visualisation
287 // result = false: the variable already exist in the visualisation
289 }
288 }
290 }
289 }
291 else
290 else
292 {
291 {
293 qCWarning(LOG_DragDropGuiController()) << QObject::tr(
292 qCWarning(LOG_DragDropGuiController()) << QObject::tr(
294 "DragDropGuiController::checkMimeDataForVisualization, the parent "
293 "DragDropGuiController::checkMimeDataForVisualization, the parent "
295 "VisualizationWidget cannot be found. Cannot check if the variable is "
294 "VisualizationWidget cannot be found. Cannot check if the variable is "
296 "already used or not.");
295 "already used or not.");
297 }
296 }
298 }
297 }
299 else
298 else
300 {
299 {
301 // result = false: the variable is not fully loaded
300 // result = false: the variable is not fully loaded
302 }
301 }
303 }
302 }
304 else
303 else
305 {
304 {
306 // result = false: cannot drop multiple variables in the visualisation
305 // result = false: cannot drop multiple variables in the visualisation
307 }
306 }
308 }
307 }
309 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST))
308 else if (mimeData->hasFormat(MIME::MIME_TYPE_PRODUCT_LIST))
310 {
309 {
311 auto productDataList = sqpApp->dataSourceController().productsDataForMimeData(
310 auto productDataList = MIME::decode(
312 mimeData->data(MIME_TYPE_PRODUCT_LIST));
311 mimeData->data(MIME::MIME_TYPE_PRODUCT_LIST));
313 if (productDataList.count() == 1)
312 if (productDataList.count() == 1)
314 {
313 {
315 result = true;
314 result = true;
316 }
315 }
317 else
316 else
318 {
317 {
319 // result = false: cannot drop multiple products in the visualisation
318 // result = false: cannot drop multiple products in the visualisation
320 }
319 }
321 }
320 }
322 else
321 else
323 {
322 {
324 // Other MIME data
323 // Other MIME data
325 // no special rules, accepted by default
324 // no special rules, accepted by default
326 result = true;
325 result = true;
327 }
326 }
328
327
329
328
330 return result;
329 return result;
331 }
330 }
@@ -1,156 +1,151
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/datasources.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/VariableController2.h>
11 #include <Variable/VariableController2.h>
12 #include <Variable/VariableModel2.h>
12 #include <Variable/VariableModel2.h>
13
13
14 Q_LOGGING_CATEGORY(LOG_SqpApplication, "SqpApplication")
14 Q_LOGGING_CATEGORY(LOG_SqpApplication, "SqpApplication")
15
15
16 class SqpApplication::SqpApplicationPrivate
16 class SqpApplication::SqpApplicationPrivate
17 {
17 {
18 public:
18 public:
19 SqpApplicationPrivate()
19 SqpApplicationPrivate()
20 : m_VariableController { std::make_shared<VariableController2>() }
20 : m_VariableController { std::make_shared<VariableController2>() }
21 , m_PlotInterractionMode(SqpApplication::PlotsInteractionMode::None)
21 , m_PlotInterractionMode(SqpApplication::PlotsInteractionMode::None)
22 , m_PlotCursorMode(SqpApplication::PlotsCursorMode::NoCursor)
22 , m_PlotCursorMode(SqpApplication::PlotsCursorMode::NoCursor)
23 {
23 {
24 // /////////////////////////////// //
24 // /////////////////////////////// //
25 // Connections between controllers //
25 // Connections between controllers //
26 // /////////////////////////////// //
26 // /////////////////////////////// //
27
27
28 // VariableController <-> DataSourceController
28 // VariableController <-> DataSourceController
29 connect(&m_DataSourceController, &DataSourceController::createVariable,
29 connect(&m_DataSources, static_cast<void (DataSources::*)(const QString&, const QVariantHash&,
30 std::shared_ptr<IDataProvider>)>(&DataSources::createVariable),
30 [](const QString& variableName, const QVariantHash& variableMetadata,
31 [](const QString& variableName, const QVariantHash& variableMetadata,
31 std::shared_ptr<IDataProvider> variableProvider) {
32 std::shared_ptr<IDataProvider> variableProvider) {
32 sqpApp->variableController().createVariable(variableName, variableMetadata,
33 sqpApp->variableController().createVariable(variableName, variableMetadata,
33 variableProvider, sqpApp->timeController().dateTime());
34 variableProvider, sqpApp->timeController().dateTime());
34 });
35 });
35
36
36
37
37 m_DataSourceController.moveToThread(&m_DataSourceControllerThread);
38 m_DataSourceControllerThread.setObjectName("DataSourceControllerThread");
39 m_NetworkController.moveToThread(&m_NetworkControllerThread);
38 m_NetworkController.moveToThread(&m_NetworkControllerThread);
40 m_NetworkControllerThread.setObjectName("NetworkControllerThread");
39 m_NetworkControllerThread.setObjectName("NetworkControllerThread");
41
40
42 // Additionnal init
41 // Additionnal init
43 // m_VariableController->setTimeController(m_TimeController.get());
42 // m_VariableController->setTimeController(m_TimeController.get());
44 }
43 }
45
44
46 virtual ~SqpApplicationPrivate()
45 virtual ~SqpApplicationPrivate()
47 {
46 {
48 m_DataSourceControllerThread.quit();
49 m_DataSourceControllerThread.wait();
50
47
51 m_NetworkControllerThread.quit();
48 m_NetworkControllerThread.quit();
52 m_NetworkControllerThread.wait();
49 m_NetworkControllerThread.wait();
53 }
50 }
54
51
55 DataSourceController m_DataSourceController;
52 DataSources m_DataSources;
56 std::shared_ptr<VariableController2> m_VariableController;
53 std::shared_ptr<VariableController2> m_VariableController;
57 TimeController m_TimeController;
54 TimeController m_TimeController;
58 NetworkController m_NetworkController;
55 NetworkController m_NetworkController;
59 CatalogueController m_CatalogueController;
56 CatalogueController m_CatalogueController;
60
57
61 QThread m_DataSourceControllerThread;
62 QThread m_NetworkControllerThread;
58 QThread m_NetworkControllerThread;
63
59
64 DragDropGuiController m_DragDropGuiController;
60 DragDropGuiController m_DragDropGuiController;
65 ActionsGuiController m_ActionsGuiController;
61 ActionsGuiController m_ActionsGuiController;
66
62
67 SqpApplication::PlotsInteractionMode m_PlotInterractionMode;
63 SqpApplication::PlotsInteractionMode m_PlotInterractionMode;
68 SqpApplication::PlotsCursorMode m_PlotCursorMode;
64 SqpApplication::PlotsCursorMode m_PlotCursorMode;
69 };
65 };
70
66
71
67
72 SqpApplication::SqpApplication(int& argc, char** argv)
68 SqpApplication::SqpApplication(int& argc, char** argv)
73 : QApplication { argc, argv }, impl { spimpl::make_unique_impl<SqpApplicationPrivate>() }
69 : QApplication { argc, argv }, impl { spimpl::make_unique_impl<SqpApplicationPrivate>() }
74 {
70 {
75 this->setStyle(new MyProxyStyle(this->style()));
71 this->setStyle(new MyProxyStyle(this->style()));
76 qCDebug(LOG_SqpApplication()) << tr("SqpApplication construction") << QThread::currentThread();
72 qCDebug(LOG_SqpApplication()) << tr("SqpApplication construction") << QThread::currentThread();
77
73
78 QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
74 QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
79
75
80 connect(&impl->m_DataSourceControllerThread, &QThread::started, &impl->m_DataSourceController,
81 &DataSourceController::initialize);
82 connect(&impl->m_DataSourceControllerThread, &QThread::finished, &impl->m_DataSourceController,
83 &DataSourceController::finalize);
84
85 connect(&impl->m_NetworkControllerThread, &QThread::started, &impl->m_NetworkController,
76 connect(&impl->m_NetworkControllerThread, &QThread::started, &impl->m_NetworkController,
86 &NetworkController::initialize);
77 &NetworkController::initialize);
87 connect(&impl->m_NetworkControllerThread, &QThread::finished, &impl->m_NetworkController,
78 connect(&impl->m_NetworkControllerThread, &QThread::finished, &impl->m_NetworkController,
88 &NetworkController::finalize);
79 &NetworkController::finalize);
89
80
90 impl->m_DataSourceControllerThread.start();
91 impl->m_NetworkControllerThread.start();
81 impl->m_NetworkControllerThread.start();
92 }
82 }
93
83
94 SqpApplication::~SqpApplication() {}
84 SqpApplication::~SqpApplication() {}
95
85
96 void SqpApplication::initialize() {}
86 void SqpApplication::initialize() {}
97
87
98 DataSourceController& SqpApplication::dataSourceController() noexcept
88 //DataSourceController& SqpApplication::dataSourceController() noexcept
89 //{
90 // return impl->m_DataSourceController;
91 //}
92
93 DataSources& SqpApplication::dataSources() noexcept
99 {
94 {
100 return impl->m_DataSourceController;
95 return impl->m_DataSources;
101 }
96 }
102
97
103 NetworkController& SqpApplication::networkController() noexcept
98 NetworkController& SqpApplication::networkController() noexcept
104 {
99 {
105 return impl->m_NetworkController;
100 return impl->m_NetworkController;
106 }
101 }
107
102
108 TimeController& SqpApplication::timeController() noexcept
103 TimeController& SqpApplication::timeController() noexcept
109 {
104 {
110 return impl->m_TimeController;
105 return impl->m_TimeController;
111 }
106 }
112
107
113 VariableController2& SqpApplication::variableController() noexcept
108 VariableController2& SqpApplication::variableController() noexcept
114 {
109 {
115 return *impl->m_VariableController;
110 return *impl->m_VariableController;
116 }
111 }
117
112
118 std::shared_ptr<VariableController2> SqpApplication::variableControllerOwner() noexcept
113 std::shared_ptr<VariableController2> SqpApplication::variableControllerOwner() noexcept
119 {
114 {
120 return impl->m_VariableController;
115 return impl->m_VariableController;
121 }
116 }
122
117
123 CatalogueController& SqpApplication::catalogueController() noexcept
118 CatalogueController& SqpApplication::catalogueController() noexcept
124 {
119 {
125 return impl->m_CatalogueController;
120 return impl->m_CatalogueController;
126 }
121 }
127
122
128 DragDropGuiController& SqpApplication::dragDropGuiController() noexcept
123 DragDropGuiController& SqpApplication::dragDropGuiController() noexcept
129 {
124 {
130 return impl->m_DragDropGuiController;
125 return impl->m_DragDropGuiController;
131 }
126 }
132
127
133 ActionsGuiController& SqpApplication::actionsGuiController() noexcept
128 ActionsGuiController& SqpApplication::actionsGuiController() noexcept
134 {
129 {
135 return impl->m_ActionsGuiController;
130 return impl->m_ActionsGuiController;
136 }
131 }
137
132
138 SqpApplication::PlotsInteractionMode SqpApplication::plotsInteractionMode() const
133 SqpApplication::PlotsInteractionMode SqpApplication::plotsInteractionMode() const
139 {
134 {
140 return impl->m_PlotInterractionMode;
135 return impl->m_PlotInterractionMode;
141 }
136 }
142
137
143 void SqpApplication::setPlotsInteractionMode(SqpApplication::PlotsInteractionMode mode)
138 void SqpApplication::setPlotsInteractionMode(SqpApplication::PlotsInteractionMode mode)
144 {
139 {
145 impl->m_PlotInterractionMode = mode;
140 impl->m_PlotInterractionMode = mode;
146 }
141 }
147
142
148 SqpApplication::PlotsCursorMode SqpApplication::plotsCursorMode() const
143 SqpApplication::PlotsCursorMode SqpApplication::plotsCursorMode() const
149 {
144 {
150 return impl->m_PlotCursorMode;
145 return impl->m_PlotCursorMode;
151 }
146 }
152
147
153 void SqpApplication::setPlotsCursorMode(SqpApplication::PlotsCursorMode mode)
148 void SqpApplication::setPlotsCursorMode(SqpApplication::PlotsCursorMode mode)
154 {
149 {
155 impl->m_PlotCursorMode = mode;
150 impl->m_PlotCursorMode = mode;
156 }
151 }
@@ -1,158 +1,158
1 #include "TimeWidget/TimeWidget.h"
1 #include "TimeWidget/TimeWidget.h"
2 #include "ui_TimeWidget.h"
2 #include "ui_TimeWidget.h"
3
3
4 #include <Common/DateUtils.h>
4 #include <Common/DateUtils.h>
5 #include <Common/MimeTypesDef.h>
5 #include <MimeTypes/MimeTypes.h>
6
6
7 #include <DragAndDrop/DragDropGuiController.h>
7 #include <DragAndDrop/DragDropGuiController.h>
8 #include <SqpApplication.h>
8 #include <SqpApplication.h>
9 #include <Time/TimeController.h>
9 #include <Time/TimeController.h>
10
10
11 #include <QDrag>
11 #include <QDrag>
12 #include <QDragEnterEvent>
12 #include <QDragEnterEvent>
13 #include <QDropEvent>
13 #include <QDropEvent>
14 #include <QMimeData>
14 #include <QMimeData>
15 #include <QStyle>
15 #include <QStyle>
16
16
17
17
18 struct TimeWidget::TimeWidgetPrivate
18 struct TimeWidget::TimeWidgetPrivate
19 {
19 {
20
20
21 explicit TimeWidgetPrivate() {}
21 explicit TimeWidgetPrivate() {}
22
22
23 QPoint m_DragStartPosition;
23 QPoint m_DragStartPosition;
24 };
24 };
25
25
26 TimeWidget::TimeWidget(QWidget* parent)
26 TimeWidget::TimeWidget(QWidget* parent)
27 : QWidget { parent }
27 : QWidget { parent }
28 , ui { new Ui::TimeWidget }
28 , ui { new Ui::TimeWidget }
29 , impl { spimpl::make_unique_impl<TimeWidgetPrivate>() }
29 , impl { spimpl::make_unique_impl<TimeWidgetPrivate>() }
30 {
30 {
31 ui->setupUi(this);
31 ui->setupUi(this);
32
32
33 // Connection
33 // Connection
34 connect(ui->startDateTimeEdit, &QDateTimeEdit::dateTimeChanged, this,
34 connect(ui->startDateTimeEdit, &QDateTimeEdit::dateTimeChanged, this,
35 &TimeWidget::onTimeUpdateRequested);
35 &TimeWidget::onTimeUpdateRequested);
36
36
37 connect(ui->endDateTimeEdit, &QDateTimeEdit::dateTimeChanged, this,
37 connect(ui->endDateTimeEdit, &QDateTimeEdit::dateTimeChanged, this,
38 &TimeWidget::onTimeUpdateRequested);
38 &TimeWidget::onTimeUpdateRequested);
39
39
40 // Initialisation
40 // Initialisation
41 auto endDateTime = QDateTime::currentDateTimeUtc();
41 auto endDateTime = QDateTime::currentDateTimeUtc();
42 auto startDateTime = endDateTime.addSecs(-3600); // one hour before
42 auto startDateTime = endDateTime.addSecs(-3600); // one hour before
43
43
44 ui->startDateTimeEdit->setDateTime(startDateTime);
44 ui->startDateTimeEdit->setDateTime(startDateTime);
45 ui->endDateTimeEdit->setDateTime(endDateTime);
45 ui->endDateTimeEdit->setDateTime(endDateTime);
46
46
47 auto dateTime = DateTimeRange { DateUtils::secondsSinceEpoch(startDateTime),
47 auto dateTime = DateTimeRange { DateUtils::secondsSinceEpoch(startDateTime),
48 DateUtils::secondsSinceEpoch(endDateTime) };
48 DateUtils::secondsSinceEpoch(endDateTime) };
49
49
50 sqpApp->timeController().setDateTimeRange(dateTime);
50 sqpApp->timeController().setDateTimeRange(dateTime);
51 }
51 }
52
52
53
53
54 TimeWidget::~TimeWidget()
54 TimeWidget::~TimeWidget()
55 {
55 {
56 delete ui;
56 delete ui;
57 }
57 }
58
58
59 void TimeWidget::setTimeRange(DateTimeRange time)
59 void TimeWidget::setTimeRange(DateTimeRange time)
60 {
60 {
61 auto startDateTime = DateUtils::dateTime(time.m_TStart);
61 auto startDateTime = DateUtils::dateTime(time.m_TStart);
62 auto endDateTime = DateUtils::dateTime(time.m_TEnd);
62 auto endDateTime = DateUtils::dateTime(time.m_TEnd);
63
63
64 ui->startDateTimeEdit->setDateTime(startDateTime);
64 ui->startDateTimeEdit->setDateTime(startDateTime);
65 ui->endDateTimeEdit->setDateTime(endDateTime);
65 ui->endDateTimeEdit->setDateTime(endDateTime);
66 }
66 }
67
67
68 DateTimeRange TimeWidget::timeRange() const
68 DateTimeRange TimeWidget::timeRange() const
69 {
69 {
70 return DateTimeRange { DateUtils::secondsSinceEpoch(ui->startDateTimeEdit->dateTime()),
70 return DateTimeRange { DateUtils::secondsSinceEpoch(ui->startDateTimeEdit->dateTime()),
71 DateUtils::secondsSinceEpoch(ui->endDateTimeEdit->dateTime()) };
71 DateUtils::secondsSinceEpoch(ui->endDateTimeEdit->dateTime()) };
72 }
72 }
73
73
74 void TimeWidget::onTimeUpdateRequested()
74 void TimeWidget::onTimeUpdateRequested()
75 {
75 {
76 auto dateTime = timeRange();
76 auto dateTime = timeRange();
77 emit timeUpdated(dateTime);
77 emit timeUpdated(dateTime);
78 sqpApp->timeController().setDateTimeRange(dateTime);
78 sqpApp->timeController().setDateTimeRange(dateTime);
79 }
79 }
80
80
81 void TimeWidget::dragEnterEvent(QDragEnterEvent* event)
81 void TimeWidget::dragEnterEvent(QDragEnterEvent* event)
82 {
82 {
83 if (event->mimeData()->hasFormat(MIME_TYPE_TIME_RANGE))
83 if (event->mimeData()->hasFormat(MIME::MIME_TYPE_TIME_RANGE))
84 {
84 {
85 event->acceptProposedAction();
85 event->acceptProposedAction();
86 setStyleSheet("QDateTimeEdit{background-color: #BBD5EE; border:2px solid #2A7FD4}");
86 setStyleSheet("QDateTimeEdit{background-color: #BBD5EE; border:2px solid #2A7FD4}");
87 }
87 }
88 else
88 else
89 {
89 {
90 event->ignore();
90 event->ignore();
91 }
91 }
92 }
92 }
93
93
94 void TimeWidget::dragLeaveEvent(QDragLeaveEvent* event)
94 void TimeWidget::dragLeaveEvent(QDragLeaveEvent* event)
95 {
95 {
96 setStyleSheet(QString {});
96 setStyleSheet(QString {});
97 }
97 }
98
98
99 void TimeWidget::dropEvent(QDropEvent* event)
99 void TimeWidget::dropEvent(QDropEvent* event)
100 {
100 {
101 if (event->mimeData()->hasFormat(MIME_TYPE_TIME_RANGE))
101 if (event->mimeData()->hasFormat(MIME::MIME_TYPE_TIME_RANGE))
102 {
102 {
103 auto mimeData = event->mimeData()->data(MIME_TYPE_TIME_RANGE);
103 auto mimeData = event->mimeData()->data(MIME::MIME_TYPE_TIME_RANGE);
104 auto timeRange = TimeController::timeRangeForMimeData(mimeData);
104 auto timeRange = TimeController::timeRangeForMimeData(mimeData);
105
105
106 setTimeRange(timeRange);
106 setTimeRange(timeRange);
107 }
107 }
108 else
108 else
109 {
109 {
110 event->ignore();
110 event->ignore();
111 }
111 }
112
112
113 setStyleSheet(QString {});
113 setStyleSheet(QString {});
114 }
114 }
115
115
116
116
117 void TimeWidget::mousePressEvent(QMouseEvent* event)
117 void TimeWidget::mousePressEvent(QMouseEvent* event)
118 {
118 {
119 if (event->button() == Qt::LeftButton)
119 if (event->button() == Qt::LeftButton)
120 {
120 {
121 impl->m_DragStartPosition = event->pos();
121 impl->m_DragStartPosition = event->pos();
122 }
122 }
123
123
124 QWidget::mousePressEvent(event);
124 QWidget::mousePressEvent(event);
125 }
125 }
126
126
127 void TimeWidget::mouseMoveEvent(QMouseEvent* event)
127 void TimeWidget::mouseMoveEvent(QMouseEvent* event)
128 {
128 {
129 if (!(event->buttons() & Qt::LeftButton))
129 if (!(event->buttons() & Qt::LeftButton))
130 {
130 {
131 return;
131 return;
132 }
132 }
133
133
134 if ((event->pos() - impl->m_DragStartPosition).manhattanLength()
134 if ((event->pos() - impl->m_DragStartPosition).manhattanLength()
135 < QApplication::startDragDistance())
135 < QApplication::startDragDistance())
136 {
136 {
137 return;
137 return;
138 }
138 }
139
139
140 // Note: The management of the drag object is done by Qt
140 // Note: The management of the drag object is done by Qt
141 auto drag = new QDrag { this };
141 auto drag = new QDrag { this };
142
142
143 auto mimeData = new QMimeData;
143 auto mimeData = new QMimeData;
144 auto timeData = TimeController::mimeDataForTimeRange(timeRange());
144 auto timeData = TimeController::mimeDataForTimeRange(timeRange());
145 mimeData->setData(MIME_TYPE_TIME_RANGE, timeData);
145 mimeData->setData(MIME::MIME_TYPE_TIME_RANGE, timeData);
146
146
147 drag->setMimeData(mimeData);
147 drag->setMimeData(mimeData);
148
148
149 auto pixmap = QPixmap { ":/icones/time.png" };
149 auto pixmap = QPixmap { ":/icones/time.png" };
150 drag->setPixmap(pixmap.scaledToWidth(22));
150 drag->setPixmap(pixmap.scaledToWidth(22));
151
151
152 sqpApp->dragDropGuiController().resetDragAndDrop();
152 sqpApp->dragDropGuiController().resetDragAndDrop();
153
153
154 // Note: The exec() is blocking on windows but not on linux and macOS
154 // Note: The exec() is blocking on windows but not on linux and macOS
155 drag->exec(Qt::MoveAction | Qt::CopyAction);
155 drag->exec(Qt::MoveAction | Qt::CopyAction);
156
156
157 QWidget::mouseMoveEvent(event);
157 QWidget::mouseMoveEvent(event);
158 }
158 }
@@ -1,265 +1,265
1 #include <DataSource/DataSourceController.h>
1 #include <DataSource/datasources.h>
2 #include <Variable/RenameVariableDialog.h>
2 #include <Variable/RenameVariableDialog.h>
3 #include <Variable/VariableController2.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/VariableModel2.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
23
24 public:
24 public:
25 QProgressBarItemDelegate(QObject* parent) : QStyledItemDelegate { parent } {}
25 QProgressBarItemDelegate(QObject* parent) : QStyledItemDelegate { parent } {}
26
26
27 void paint(
27 void paint(
28 QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
28 QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
29 {
29 {
30 auto data = index.data(Qt::DisplayRole);
30 auto data = index.data(Qt::DisplayRole);
31 auto progressData = index.data(VariableRoles::ProgressRole);
31 auto progressData = index.data(VariableRoles::ProgressRole);
32 if (data.isValid() && progressData.isValid())
32 if (data.isValid() && progressData.isValid())
33 {
33 {
34 auto name = data.value<QString>();
34 auto name = data.value<QString>();
35 auto progress = progressData.value<double>();
35 auto progress = progressData.value<double>();
36 if (progress > 0)
36 if (progress > 0)
37 {
37 {
38 auto cancelButtonWidth = 20;
38 auto cancelButtonWidth = 20;
39 auto progressBarOption = QStyleOptionProgressBar {};
39 auto progressBarOption = QStyleOptionProgressBar {};
40 auto progressRect = option.rect;
40 auto progressRect = option.rect;
41 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
41 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
42 progressBarOption.rect = progressRect;
42 progressBarOption.rect = progressRect;
43 progressBarOption.minimum = 0;
43 progressBarOption.minimum = 0;
44 progressBarOption.maximum = 100;
44 progressBarOption.maximum = 100;
45 progressBarOption.progress = progress;
45 progressBarOption.progress = progress;
46 progressBarOption.text
46 progressBarOption.text
47 = QString("%1 %2").arg(name).arg(QString::number(progress, 'f', 2) + "%");
47 = QString("%1 %2").arg(name).arg(QString::number(progress, 'f', 2) + "%");
48 progressBarOption.textVisible = true;
48 progressBarOption.textVisible = true;
49 progressBarOption.textAlignment = Qt::AlignCenter;
49 progressBarOption.textAlignment = Qt::AlignCenter;
50
50
51
51
52 QApplication::style()->drawControl(
52 QApplication::style()->drawControl(
53 QStyle::CE_ProgressBar, &progressBarOption, painter);
53 QStyle::CE_ProgressBar, &progressBarOption, painter);
54
54
55 // Cancel button
55 // Cancel button
56 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
56 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
57 option.rect.height());
57 option.rect.height());
58 auto buttonOption = QStyleOptionButton {};
58 auto buttonOption = QStyleOptionButton {};
59 buttonOption.rect = buttonRect;
59 buttonOption.rect = buttonRect;
60 buttonOption.text = "X";
60 buttonOption.text = "X";
61
61
62 QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter);
62 QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter);
63 }
63 }
64 else
64 else
65 {
65 {
66 QStyledItemDelegate::paint(painter, option, index);
66 QStyledItemDelegate::paint(painter, option, index);
67 }
67 }
68 }
68 }
69 else
69 else
70 {
70 {
71 QStyledItemDelegate::paint(painter, option, index);
71 QStyledItemDelegate::paint(painter, option, index);
72 }
72 }
73 }
73 }
74
74
75 bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option,
75 bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option,
76 const QModelIndex& index)
76 const QModelIndex& index)
77 {
77 {
78 if (event->type() == QEvent::MouseButtonRelease)
78 if (event->type() == QEvent::MouseButtonRelease)
79 {
79 {
80 auto data = index.data(Qt::DisplayRole);
80 auto data = index.data(Qt::DisplayRole);
81 auto progressData = index.data(VariableRoles::ProgressRole);
81 auto progressData = index.data(VariableRoles::ProgressRole);
82 if (data.isValid() && progressData.isValid())
82 if (data.isValid() && progressData.isValid())
83 {
83 {
84 auto cancelButtonWidth = 20;
84 auto cancelButtonWidth = 20;
85 auto progressRect = option.rect;
85 auto progressRect = option.rect;
86 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
86 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
87 // Cancel button
87 // Cancel button
88 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
88 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
89 option.rect.height());
89 option.rect.height());
90
90
91 auto e = (QMouseEvent*)event;
91 auto e = (QMouseEvent*)event;
92 auto clickX = e->x();
92 auto clickX = e->x();
93 auto clickY = e->y();
93 auto clickY = e->y();
94
94
95 auto x = buttonRect.left(); // the X coordinate
95 auto x = buttonRect.left(); // the X coordinate
96 auto y = buttonRect.top(); // the Y coordinate
96 auto y = buttonRect.top(); // the Y coordinate
97 auto w = buttonRect.width(); // button width
97 auto w = buttonRect.width(); // button width
98 auto h = buttonRect.height(); // button height
98 auto h = buttonRect.height(); // button height
99
99
100 if (clickX > x && clickX < x + w)
100 if (clickX > x && clickX < x + w)
101 {
101 {
102 if (clickY > y && clickY < y + h)
102 if (clickY > y && clickY < y + h)
103 {
103 {
104 // auto& variableModel = sqpApp->variableModel();
104 // auto& variableModel = sqpApp->variableModel();
105 // variableModel->abortProgress(index);
105 // variableModel->abortProgress(index);
106 }
106 }
107 return true;
107 return true;
108 }
108 }
109 else
109 else
110 {
110 {
111 return QStyledItemDelegate::editorEvent(event, model, option, index);
111 return QStyledItemDelegate::editorEvent(event, model, option, index);
112 }
112 }
113 }
113 }
114 else
114 else
115 {
115 {
116 return QStyledItemDelegate::editorEvent(event, model, option, index);
116 return QStyledItemDelegate::editorEvent(event, model, option, index);
117 }
117 }
118 }
118 }
119 else
119 else
120 {
120 {
121 return QStyledItemDelegate::editorEvent(event, model, option, index);
121 return QStyledItemDelegate::editorEvent(event, model, option, index);
122 }
122 }
123
123
124
124
125 return QStyledItemDelegate::editorEvent(event, model, option, index);
125 return QStyledItemDelegate::editorEvent(event, model, option, index);
126 }
126 }
127 };
127 };
128
128
129 VariableInspectorWidget::VariableInspectorWidget(QWidget* parent)
129 VariableInspectorWidget::VariableInspectorWidget(QWidget* parent)
130 : QWidget { parent }
130 : QWidget { parent }
131 , ui { new Ui::VariableInspectorWidget }
131 , ui { new Ui::VariableInspectorWidget }
132 , m_ProgressBarItemDelegate { new QProgressBarItemDelegate { this } }
132 , m_ProgressBarItemDelegate { new QProgressBarItemDelegate { this } }
133 {
133 {
134 ui->setupUi(this);
134 ui->setupUi(this);
135
135
136 // Sets model for table
136 // Sets model for table
137 // auto sortFilterModel = new QSortFilterProxyModel{this};
137 // auto sortFilterModel = new QSortFilterProxyModel{this};
138 // sortFilterModel->setSourceModel(sqpApp->variableController().variableModel());
138 // sortFilterModel->setSourceModel(sqpApp->variableController().variableModel());
139
139
140 m_model = new VariableModel2();
140 m_model = new VariableModel2();
141 ui->tableView->setModel(m_model);
141 ui->tableView->setModel(m_model);
142 connect(m_model, &VariableModel2::createVariable, [](const QVariantHash& productData) {
142 connect(m_model, &VariableModel2::createVariable, [](const QString& productPath) {
143 sqpApp->dataSourceController().requestVariable(productData);
143 sqpApp->dataSources().createVariable(productPath);
144 });
144 });
145 auto vc = &(sqpApp->variableController());
145 auto vc = &(sqpApp->variableController());
146 connect(vc, &VariableController2::variableAdded, m_model, &VariableModel2::variableAdded);
146 connect(vc, &VariableController2::variableAdded, m_model, &VariableModel2::variableAdded);
147 connect(vc, &VariableController2::variableDeleted, m_model, &VariableModel2::variableDeleted);
147 connect(vc, &VariableController2::variableDeleted, m_model, &VariableModel2::variableDeleted);
148 connect(m_model, &VariableModel2::asyncChangeRange, vc, &VariableController2::asyncChangeRange);
148 connect(m_model, &VariableModel2::asyncChangeRange, vc, &VariableController2::asyncChangeRange);
149
149
150 // Adds extra signal/slot between view and model, so the view can be updated instantly when
150 // Adds extra signal/slot between view and model, so the view can be updated instantly when
151 // there is a change of data in the model
151 // there is a change of data in the model
152 // connect(m_model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this,
152 // connect(m_model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this,
153 // SLOT(refresh()));
153 // SLOT(refresh()));
154
154
155 // ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel());
155 // ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel());
156 ui->tableView->setItemDelegateForColumn(0, m_ProgressBarItemDelegate);
156 ui->tableView->setItemDelegateForColumn(0, m_ProgressBarItemDelegate);
157
157
158 // Fixes column sizes
158 // Fixes column sizes
159 auto model = ui->tableView->model();
159 auto model = ui->tableView->model();
160 const auto count = model->columnCount();
160 const auto count = model->columnCount();
161 for (auto i = 0; i < count; ++i)
161 for (auto i = 0; i < count; ++i)
162 {
162 {
163 ui->tableView->setColumnWidth(
163 ui->tableView->setColumnWidth(
164 i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width());
164 i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width());
165 }
165 }
166
166
167 // Sets selection options
167 // Sets selection options
168 ui->tableView->setSelectionBehavior(QTableView::SelectRows);
168 ui->tableView->setSelectionBehavior(QTableView::SelectRows);
169 ui->tableView->setSelectionMode(QTableView::ExtendedSelection);
169 ui->tableView->setSelectionMode(QTableView::ExtendedSelection);
170
170
171 // Connection to show a menu when right clicking on the tree
171 // Connection to show a menu when right clicking on the tree
172 ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
172 ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
173 connect(ui->tableView, &QTableView::customContextMenuRequested, this,
173 connect(ui->tableView, &QTableView::customContextMenuRequested, this,
174 &VariableInspectorWidget::onTableMenuRequested);
174 &VariableInspectorWidget::onTableMenuRequested);
175 }
175 }
176
176
177 VariableInspectorWidget::~VariableInspectorWidget()
177 VariableInspectorWidget::~VariableInspectorWidget()
178 {
178 {
179 delete ui;
179 delete ui;
180 }
180 }
181
181
182 void VariableInspectorWidget::onTableMenuRequested(const QPoint& pos) noexcept
182 void VariableInspectorWidget::onTableMenuRequested(const QPoint& pos) noexcept
183 {
183 {
184 auto selectedRows = ui->tableView->selectionModel()->selectedRows();
184 auto selectedRows = ui->tableView->selectionModel()->selectedRows();
185 auto selectedVariables = QVector<std::shared_ptr<Variable2>> {};
185 auto selectedVariables = QVector<std::shared_ptr<Variable2>> {};
186 for (const auto& selectedRow : qAsConst(selectedRows))
186 for (const auto& selectedRow : qAsConst(selectedRows))
187 {
187 {
188 if (auto selectedVariable = this->m_model->variables()[selectedRow.row()])
188 if (auto selectedVariable = this->m_model->variables()[selectedRow.row()])
189 {
189 {
190 selectedVariables.push_back(selectedVariable);
190 selectedVariables.push_back(selectedVariable);
191 }
191 }
192 }
192 }
193
193
194 QMenu tableMenu {};
194 QMenu tableMenu {};
195
195
196 // Emits a signal so that potential receivers can populate the menu before displaying it
196 // Emits a signal so that potential receivers can populate the menu before displaying it
197 emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables);
197 emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables);
198
198
199 // Adds menu-specific actions
199 // Adds menu-specific actions
200 if (!selectedVariables.isEmpty())
200 if (!selectedVariables.isEmpty())
201 {
201 {
202 tableMenu.addSeparator();
202 tableMenu.addSeparator();
203
203
204 // 'Rename' and 'Duplicate' actions (only if one variable selected)
204 // 'Rename' and 'Duplicate' actions (only if one variable selected)
205 if (selectedVariables.size() == 1)
205 if (selectedVariables.size() == 1)
206 {
206 {
207 auto selectedVariable = selectedVariables.front();
207 auto selectedVariable = selectedVariables.front();
208
208
209 auto duplicateFun = [varW = std::weak_ptr<Variable2>(selectedVariable)]() {
209 auto duplicateFun = [varW = std::weak_ptr<Variable2>(selectedVariable)]() {
210 if (auto var = varW.lock())
210 if (auto var = varW.lock())
211 {
211 {
212 sqpApp->variableController().cloneVariable(var);
212 sqpApp->variableController().cloneVariable(var);
213 }
213 }
214 };
214 };
215
215
216 tableMenu.addAction(tr("Duplicate"), duplicateFun);
216 tableMenu.addAction(tr("Duplicate"), duplicateFun);
217
217
218 auto renameFun = [varW = std::weak_ptr<Variable2>(selectedVariable), this]() {
218 auto renameFun = [varW = std::weak_ptr<Variable2>(selectedVariable), this]() {
219 if (auto var = varW.lock())
219 if (auto var = varW.lock())
220 {
220 {
221 // Generates forbidden names (names associated to existing variables)
221 // Generates forbidden names (names associated to existing variables)
222 auto allVariables = sqpApp->variableController().variables();
222 auto allVariables = sqpApp->variableController().variables();
223 auto forbiddenNames = QVector<QString>(allVariables.size());
223 auto forbiddenNames = QVector<QString>(allVariables.size());
224 std::transform(allVariables.cbegin(), allVariables.cend(),
224 std::transform(allVariables.cbegin(), allVariables.cend(),
225 forbiddenNames.begin(),
225 forbiddenNames.begin(),
226 [](const auto& variable) { return variable->name(); });
226 [](const auto& variable) { return variable->name(); });
227
227
228 RenameVariableDialog dialog { var->name(), forbiddenNames, this };
228 RenameVariableDialog dialog { var->name(), forbiddenNames, this };
229 if (dialog.exec() == QDialog::Accepted)
229 if (dialog.exec() == QDialog::Accepted)
230 {
230 {
231 var->setName(dialog.name());
231 var->setName(dialog.name());
232 }
232 }
233 }
233 }
234 };
234 };
235
235
236 tableMenu.addAction(tr("Rename..."), renameFun);
236 tableMenu.addAction(tr("Rename..."), renameFun);
237 }
237 }
238
238
239 // 'Delete' action
239 // 'Delete' action
240 auto deleteFun = [&selectedVariables]() {
240 auto deleteFun = [&selectedVariables]() {
241 for (const auto& var : selectedVariables)
241 for (const auto& var : selectedVariables)
242 sqpApp->variableController().deleteVariable(var);
242 sqpApp->variableController().deleteVariable(var);
243 };
243 };
244
244
245 tableMenu.addAction(QIcon { ":/icones/delete.png" }, tr("Delete"), deleteFun);
245 tableMenu.addAction(QIcon { ":/icones/delete.png" }, tr("Delete"), deleteFun);
246 }
246 }
247
247
248 if (!tableMenu.isEmpty())
248 if (!tableMenu.isEmpty())
249 {
249 {
250 // Generates menu header (inserted before first action)
250 // Generates menu header (inserted before first action)
251 auto firstAction = tableMenu.actions().first();
251 auto firstAction = tableMenu.actions().first();
252 auto headerAction = new QWidgetAction { &tableMenu };
252 auto headerAction = new QWidgetAction { &tableMenu };
253 headerAction->setDefaultWidget(
253 headerAction->setDefaultWidget(
254 new VariableMenuHeaderWidget { selectedVariables, &tableMenu });
254 new VariableMenuHeaderWidget { selectedVariables, &tableMenu });
255 tableMenu.insertAction(firstAction, headerAction);
255 tableMenu.insertAction(firstAction, headerAction);
256
256
257 // Displays menu
257 // Displays menu
258 tableMenu.exec(QCursor::pos());
258 tableMenu.exec(QCursor::pos());
259 }
259 }
260 }
260 }
261
261
262 void VariableInspectorWidget::refresh() noexcept
262 void VariableInspectorWidget::refresh() noexcept
263 {
263 {
264 ui->tableView->viewport()->update();
264 ui->tableView->viewport()->update();
265 }
265 }
@@ -1,1578 +1,1578
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 <MimeTypes/MimeTypes.h>
17 #include <cpp_utils_qt/cpp_utils_qt.hpp>
17 #include <cpp_utils_qt/cpp_utils_qt.hpp>
18 #include <containers/algorithms.hpp>
18 #include <containers/algorithms.hpp>
19 #include <Data/DateTimeRangeHelper.h>
19 #include <Data/DateTimeRangeHelper.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/Variable2.h>
24 #include <Variable/Variable2.h>
25 #include <Variable/VariableController2.h>
25 #include <Variable/VariableController2.h>
26
26
27 #include <unordered_map>
27 #include <unordered_map>
28
28
29 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
29 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
30
30
31 namespace
31 namespace
32 {
32 {
33
33
34 /// Key pressed to enable drag&drop in all modes
34 /// Key pressed to enable drag&drop in all modes
35 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
35 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
36
36
37 /// Key pressed to enable zoom on horizontal axis
37 /// Key pressed to enable zoom on horizontal axis
38 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
38 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
39
39
40 /// Key pressed to enable zoom on vertical axis
40 /// Key pressed to enable zoom on vertical axis
41 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
41 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
42
42
43 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
43 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
44 const auto PAN_SPEED = 5;
44 const auto PAN_SPEED = 5;
45
45
46 /// Key pressed to enable a calibration pan
46 /// Key pressed to enable a calibration pan
47 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
47 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
48
48
49 /// Key pressed to enable multi selection of selection zones
49 /// Key pressed to enable multi selection of selection zones
50 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
50 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
51
51
52 /// Minimum size for the zoom box, in percentage of the axis range
52 /// Minimum size for the zoom box, in percentage of the axis range
53 const auto ZOOM_BOX_MIN_SIZE = 0.8;
53 const auto ZOOM_BOX_MIN_SIZE = 0.8;
54
54
55 /// Format of the dates appearing in the label of a cursor
55 /// Format of the dates appearing in the label of a cursor
56 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
56 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
57
57
58 } // namespace
58 } // namespace
59
59
60 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate
60 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate
61 {
61 {
62
62
63 explicit VisualizationGraphWidgetPrivate(const QString& name)
63 explicit VisualizationGraphWidgetPrivate(const QString& name)
64 : m_Name { name }
64 : m_Name { name }
65 , m_Flags { GraphFlag::EnableAll }
65 , m_Flags { GraphFlag::EnableAll }
66 , m_IsCalibration { false }
66 , m_IsCalibration { false }
67 , m_RenderingDelegate { nullptr }
67 , m_RenderingDelegate { nullptr }
68 {
68 {
69 m_plot = new QCustomPlot();
69 m_plot = new QCustomPlot();
70 // Necessary for all platform since Qt::AA_EnableHighDpiScaling is enable.
70 // Necessary for all platform since Qt::AA_EnableHighDpiScaling is enable.
71 m_plot->setPlottingHint(QCP::phFastPolylines, true);
71 m_plot->setPlottingHint(QCP::phFastPolylines, true);
72 }
72 }
73
73
74 void updateData(
74 void updateData(
75 PlottablesMap& plottables, std::shared_ptr<Variable2> variable, const DateTimeRange& range)
75 PlottablesMap& plottables, std::shared_ptr<Variable2> variable, const DateTimeRange& range)
76 {
76 {
77 VisualizationGraphHelper::updateData(plottables, variable, range);
77 VisualizationGraphHelper::updateData(plottables, variable, range);
78
78
79 // Prevents that data has changed to update rendering
79 // Prevents that data has changed to update rendering
80 m_RenderingDelegate->onPlotUpdated();
80 m_RenderingDelegate->onPlotUpdated();
81 }
81 }
82
82
83 QString m_Name;
83 QString m_Name;
84 // 1 variable -> n qcpplot
84 // 1 variable -> n qcpplot
85 std::map<std::shared_ptr<Variable2>, PlottablesMap> m_VariableToPlotMultiMap;
85 std::map<std::shared_ptr<Variable2>, PlottablesMap> m_VariableToPlotMultiMap;
86 GraphFlags m_Flags;
86 GraphFlags m_Flags;
87 bool m_IsCalibration;
87 bool m_IsCalibration;
88 QCustomPlot* m_plot;
88 QCustomPlot* m_plot;
89 QPoint m_lastMousePos;
89 QPoint m_lastMousePos;
90 QCPRange m_lastXRange;
90 QCPRange m_lastXRange;
91 QCPRange m_lastYRange;
91 QCPRange m_lastYRange;
92 /// Delegate used to attach rendering features to the plot
92 /// Delegate used to attach rendering features to the plot
93 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
93 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
94
94
95 QCPItemRect* m_DrawingZoomRect = nullptr;
95 QCPItemRect* m_DrawingZoomRect = nullptr;
96 QStack<QPair<QCPRange, QCPRange>> m_ZoomStack;
96 QStack<QPair<QCPRange, QCPRange>> m_ZoomStack;
97
97
98 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
98 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
99 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
99 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
100
100
101 VisualizationSelectionZoneItem* m_DrawingZone = nullptr;
101 VisualizationSelectionZoneItem* m_DrawingZone = nullptr;
102 VisualizationSelectionZoneItem* m_HoveredZone = nullptr;
102 VisualizationSelectionZoneItem* m_HoveredZone = nullptr;
103 QVector<VisualizationSelectionZoneItem*> m_SelectionZones;
103 QVector<VisualizationSelectionZoneItem*> m_SelectionZones;
104
104
105 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
105 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
106
106
107 bool m_VariableAutoRangeOnInit = true;
107 bool m_VariableAutoRangeOnInit = true;
108
108
109 inline void enterPlotDrag(const QPoint& position)
109 inline void enterPlotDrag(const QPoint& position)
110 {
110 {
111 m_lastMousePos = m_plot->mapFromParent(position);
111 m_lastMousePos = m_plot->mapFromParent(position);
112 m_lastXRange = m_plot->xAxis->range();
112 m_lastXRange = m_plot->xAxis->range();
113 m_lastYRange = m_plot->yAxis->range();
113 m_lastYRange = m_plot->yAxis->range();
114 }
114 }
115
115
116 inline bool isDrawingZoomRect() { return m_DrawingZoomRect != nullptr; }
116 inline bool isDrawingZoomRect() { return m_DrawingZoomRect != nullptr; }
117 void updateZoomRect(const QPoint& newPos)
117 void updateZoomRect(const QPoint& newPos)
118 {
118 {
119 QPointF pos { m_plot->xAxis->pixelToCoord(newPos.x()),
119 QPointF pos { m_plot->xAxis->pixelToCoord(newPos.x()),
120 m_plot->yAxis->pixelToCoord(newPos.y()) };
120 m_plot->yAxis->pixelToCoord(newPos.y()) };
121 m_DrawingZoomRect->bottomRight->setCoords(pos);
121 m_DrawingZoomRect->bottomRight->setCoords(pos);
122 m_plot->replot(QCustomPlot::rpQueuedReplot);
122 m_plot->replot(QCustomPlot::rpQueuedReplot);
123 }
123 }
124
124
125 void applyZoomRect()
125 void applyZoomRect()
126 {
126 {
127 auto axisX = m_plot->axisRect()->axis(QCPAxis::atBottom);
127 auto axisX = m_plot->axisRect()->axis(QCPAxis::atBottom);
128 auto axisY = m_plot->axisRect()->axis(QCPAxis::atLeft);
128 auto axisY = m_plot->axisRect()->axis(QCPAxis::atLeft);
129
129
130 auto newAxisXRange = QCPRange { m_DrawingZoomRect->topLeft->coords().x(),
130 auto newAxisXRange = QCPRange { m_DrawingZoomRect->topLeft->coords().x(),
131 m_DrawingZoomRect->bottomRight->coords().x() };
131 m_DrawingZoomRect->bottomRight->coords().x() };
132
132
133 auto newAxisYRange = QCPRange { m_DrawingZoomRect->topLeft->coords().y(),
133 auto newAxisYRange = QCPRange { m_DrawingZoomRect->topLeft->coords().y(),
134 m_DrawingZoomRect->bottomRight->coords().y() };
134 m_DrawingZoomRect->bottomRight->coords().y() };
135
135
136 removeDrawingRect();
136 removeDrawingRect();
137
137
138 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
138 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
139 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0))
139 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0))
140 {
140 {
141 m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
141 m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
142 axisX->setRange(newAxisXRange);
142 axisX->setRange(newAxisXRange);
143 axisY->setRange(newAxisYRange);
143 axisY->setRange(newAxisYRange);
144
144
145 m_plot->replot(QCustomPlot::rpQueuedReplot);
145 m_plot->replot(QCustomPlot::rpQueuedReplot);
146 }
146 }
147 }
147 }
148
148
149 inline bool isDrawingZoneRect() { return m_DrawingZone != nullptr; }
149 inline bool isDrawingZoneRect() { return m_DrawingZone != nullptr; }
150 void updateZoneRect(const QPoint& newPos)
150 void updateZoneRect(const QPoint& newPos)
151 {
151 {
152 m_DrawingZone->setEnd(m_plot->xAxis->pixelToCoord(newPos.x()));
152 m_DrawingZone->setEnd(m_plot->xAxis->pixelToCoord(newPos.x()));
153 m_plot->replot(QCustomPlot::rpQueuedReplot);
153 m_plot->replot(QCustomPlot::rpQueuedReplot);
154 }
154 }
155
155
156 void startDrawingRect(const QPoint& pos)
156 void startDrawingRect(const QPoint& pos)
157 {
157 {
158 removeDrawingRect();
158 removeDrawingRect();
159
159
160 auto axisPos = posToAxisPos(pos);
160 auto axisPos = posToAxisPos(pos);
161
161
162 m_DrawingZoomRect = new QCPItemRect { m_plot };
162 m_DrawingZoomRect = new QCPItemRect { m_plot };
163 QPen p;
163 QPen p;
164 p.setWidth(2);
164 p.setWidth(2);
165 m_DrawingZoomRect->setPen(p);
165 m_DrawingZoomRect->setPen(p);
166
166
167 m_DrawingZoomRect->topLeft->setCoords(axisPos);
167 m_DrawingZoomRect->topLeft->setCoords(axisPos);
168 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
168 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
169 }
169 }
170
170
171 void removeDrawingRect()
171 void removeDrawingRect()
172 {
172 {
173 if (m_DrawingZoomRect)
173 if (m_DrawingZoomRect)
174 {
174 {
175 m_plot->removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
175 m_plot->removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
176 m_DrawingZoomRect = nullptr;
176 m_DrawingZoomRect = nullptr;
177 m_plot->replot(QCustomPlot::rpQueuedReplot);
177 m_plot->replot(QCustomPlot::rpQueuedReplot);
178 }
178 }
179 }
179 }
180
180
181 void selectZone(const QPoint& pos)
181 void selectZone(const QPoint& pos)
182 {
182 {
183 auto zoneAtPos = selectionZoneAt(pos);
183 auto zoneAtPos = selectionZoneAt(pos);
184 setSelectionZonesEditionEnabled(
184 setSelectionZonesEditionEnabled(
185 sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones);
185 sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones);
186 }
186 }
187
187
188 void startDrawingZone(const QPoint& pos)
188 void startDrawingZone(const QPoint& pos)
189 {
189 {
190 endDrawingZone();
190 endDrawingZone();
191
191
192 auto axisPos = posToAxisPos(pos);
192 auto axisPos = posToAxisPos(pos);
193
193
194 m_DrawingZone = new VisualizationSelectionZoneItem { m_plot };
194 m_DrawingZone = new VisualizationSelectionZoneItem { m_plot };
195 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
195 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
196 m_DrawingZone->setEditionEnabled(false);
196 m_DrawingZone->setEditionEnabled(false);
197 }
197 }
198
198
199 void endDrawingZone()
199 void endDrawingZone()
200 {
200 {
201 if (m_DrawingZone)
201 if (m_DrawingZone)
202 {
202 {
203 auto drawingZoneRange = m_DrawingZone->range();
203 auto drawingZoneRange = m_DrawingZone->range();
204 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0)
204 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0)
205 {
205 {
206 m_DrawingZone->setEditionEnabled(true);
206 m_DrawingZone->setEditionEnabled(true);
207 addSelectionZone(m_DrawingZone);
207 addSelectionZone(m_DrawingZone);
208 }
208 }
209 else
209 else
210 {
210 {
211 m_plot->removeItem(m_DrawingZone);
211 m_plot->removeItem(m_DrawingZone);
212 }
212 }
213
213
214 m_plot->replot(QCustomPlot::rpQueuedReplot);
214 m_plot->replot(QCustomPlot::rpQueuedReplot);
215 m_DrawingZone = nullptr;
215 m_DrawingZone = nullptr;
216 }
216 }
217 }
217 }
218
218
219 void moveSelectionZone(const QPoint& destination)
219 void moveSelectionZone(const QPoint& destination)
220 {
220 {
221 /*
221 /*
222 * I give up on this for now
222 * I give up on this for now
223 * TODO implement this, the difficulty is that selection zones have their own
223 * TODO implement this, the difficulty is that selection zones have their own
224 * event handling code which seems to rely on QCP GUI event handling propagation
224 * event handling code which seems to rely on QCP GUI event handling propagation
225 * which was a realy bad design choice.
225 * which was a realy bad design choice.
226 */
226 */
227 }
227 }
228
228
229 void setSelectionZonesEditionEnabled(bool value)
229 void setSelectionZonesEditionEnabled(bool value)
230 {
230 {
231 for (auto s : m_SelectionZones)
231 for (auto s : m_SelectionZones)
232 {
232 {
233 s->setEditionEnabled(value);
233 s->setEditionEnabled(value);
234 }
234 }
235 }
235 }
236
236
237 void addSelectionZone(VisualizationSelectionZoneItem* zone) { m_SelectionZones << zone; }
237 void addSelectionZone(VisualizationSelectionZoneItem* zone) { m_SelectionZones << zone; }
238
238
239 VisualizationSelectionZoneItem* selectionZoneAt(const QPoint& pos) const
239 VisualizationSelectionZoneItem* selectionZoneAt(const QPoint& pos) const
240 {
240 {
241 VisualizationSelectionZoneItem* selectionZoneItemUnderCursor = nullptr;
241 VisualizationSelectionZoneItem* selectionZoneItemUnderCursor = nullptr;
242 auto minDistanceToZone = -1;
242 auto minDistanceToZone = -1;
243 for (auto zone : m_SelectionZones)
243 for (auto zone : m_SelectionZones)
244 {
244 {
245 auto distanceToZone = zone->selectTest(pos, false);
245 auto distanceToZone = zone->selectTest(pos, false);
246 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
246 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
247 && distanceToZone >= 0 && distanceToZone < m_plot->selectionTolerance())
247 && distanceToZone >= 0 && distanceToZone < m_plot->selectionTolerance())
248 {
248 {
249 selectionZoneItemUnderCursor = zone;
249 selectionZoneItemUnderCursor = zone;
250 }
250 }
251 }
251 }
252
252
253 return selectionZoneItemUnderCursor;
253 return selectionZoneItemUnderCursor;
254 }
254 }
255
255
256 QVector<VisualizationSelectionZoneItem*> selectionZonesAt(
256 QVector<VisualizationSelectionZoneItem*> selectionZonesAt(
257 const QPoint& pos, const QCustomPlot& plot) const
257 const QPoint& pos, const QCustomPlot& plot) const
258 {
258 {
259 QVector<VisualizationSelectionZoneItem*> zones;
259 QVector<VisualizationSelectionZoneItem*> zones;
260 for (auto zone : m_SelectionZones)
260 for (auto zone : m_SelectionZones)
261 {
261 {
262 auto distanceToZone = zone->selectTest(pos, false);
262 auto distanceToZone = zone->selectTest(pos, false);
263 if (distanceToZone >= 0 && distanceToZone < plot.selectionTolerance())
263 if (distanceToZone >= 0 && distanceToZone < plot.selectionTolerance())
264 {
264 {
265 zones << zone;
265 zones << zone;
266 }
266 }
267 }
267 }
268
268
269 return zones;
269 return zones;
270 }
270 }
271
271
272 void moveSelectionZoneOnTop(VisualizationSelectionZoneItem* zone, QCustomPlot& plot)
272 void moveSelectionZoneOnTop(VisualizationSelectionZoneItem* zone, QCustomPlot& plot)
273 {
273 {
274 if (!m_SelectionZones.isEmpty() && m_SelectionZones.last() != zone)
274 if (!m_SelectionZones.isEmpty() && m_SelectionZones.last() != zone)
275 {
275 {
276 zone->moveToTop();
276 zone->moveToTop();
277 m_SelectionZones.removeAll(zone);
277 m_SelectionZones.removeAll(zone);
278 m_SelectionZones.append(zone);
278 m_SelectionZones.append(zone);
279 }
279 }
280 }
280 }
281
281
282 QPointF posToAxisPos(const QPoint& pos) const
282 QPointF posToAxisPos(const QPoint& pos) const
283 {
283 {
284 auto axisX = m_plot->axisRect()->axis(QCPAxis::atBottom);
284 auto axisX = m_plot->axisRect()->axis(QCPAxis::atBottom);
285 auto axisY = m_plot->axisRect()->axis(QCPAxis::atLeft);
285 auto axisY = m_plot->axisRect()->axis(QCPAxis::atLeft);
286 return QPointF { axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y()) };
286 return QPointF { axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y()) };
287 }
287 }
288
288
289 bool pointIsInAxisRect(const QPointF& axisPoint, QCustomPlot& plot) const
289 bool pointIsInAxisRect(const QPointF& axisPoint, QCustomPlot& plot) const
290 {
290 {
291 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
291 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
292 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
292 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
293 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
293 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
294 }
294 }
295
295
296 inline QCPRange _pixDistanceToRange(double pos1, double pos2, QCPAxis* axis)
296 inline QCPRange _pixDistanceToRange(double pos1, double pos2, QCPAxis* axis)
297 {
297 {
298 if (axis->scaleType() == QCPAxis::stLinear)
298 if (axis->scaleType() == QCPAxis::stLinear)
299 {
299 {
300 auto diff = axis->pixelToCoord(pos1) - axis->pixelToCoord(pos2);
300 auto diff = axis->pixelToCoord(pos1) - axis->pixelToCoord(pos2);
301 return QCPRange { axis->range().lower + diff, axis->range().upper + diff };
301 return QCPRange { axis->range().lower + diff, axis->range().upper + diff };
302 }
302 }
303 else
303 else
304 {
304 {
305 auto diff = axis->pixelToCoord(pos1) / axis->pixelToCoord(pos2);
305 auto diff = axis->pixelToCoord(pos1) / axis->pixelToCoord(pos2);
306 return QCPRange { axis->range().lower * diff, axis->range().upper * diff };
306 return QCPRange { axis->range().lower * diff, axis->range().upper * diff };
307 }
307 }
308 }
308 }
309
309
310 void setRange(const DateTimeRange& newRange, bool updateVar = true)
310 void setRange(const DateTimeRange& newRange, bool updateVar = true)
311 {
311 {
312 this->m_plot->xAxis->setRange(newRange.m_TStart, newRange.m_TEnd);
312 this->m_plot->xAxis->setRange(newRange.m_TStart, newRange.m_TEnd);
313 if (updateVar)
313 if (updateVar)
314 {
314 {
315 for (auto it = m_VariableToPlotMultiMap.begin(), end = m_VariableToPlotMultiMap.end();
315 for (auto it = m_VariableToPlotMultiMap.begin(), end = m_VariableToPlotMultiMap.end();
316 it != end; it = m_VariableToPlotMultiMap.upper_bound(it->first))
316 it != end; it = m_VariableToPlotMultiMap.upper_bound(it->first))
317 {
317 {
318 sqpApp->variableController().asyncChangeRange(it->first, newRange);
318 sqpApp->variableController().asyncChangeRange(it->first, newRange);
319 }
319 }
320 }
320 }
321 m_plot->replot(QCustomPlot::rpQueuedReplot);
321 m_plot->replot(QCustomPlot::rpQueuedReplot);
322 }
322 }
323
323
324 void setRange(const QCPRange& newRange)
324 void setRange(const QCPRange& newRange)
325 {
325 {
326 auto graphRange = DateTimeRange { newRange.lower, newRange.upper };
326 auto graphRange = DateTimeRange { newRange.lower, newRange.upper };
327 setRange(graphRange);
327 setRange(graphRange);
328 }
328 }
329
329
330 void rescaleY() { m_plot->yAxis->rescale(true); }
330 void rescaleY() { m_plot->yAxis->rescale(true); }
331
331
332 std::tuple<double, double> moveGraph(const QPoint& destination)
332 std::tuple<double, double> moveGraph(const QPoint& destination)
333 {
333 {
334 auto currentPos = m_plot->mapFromParent(destination);
334 auto currentPos = m_plot->mapFromParent(destination);
335 auto xAxis = m_plot->axisRect()->rangeDragAxis(Qt::Horizontal);
335 auto xAxis = m_plot->axisRect()->rangeDragAxis(Qt::Horizontal);
336 auto yAxis = m_plot->axisRect()->rangeDragAxis(Qt::Vertical);
336 auto yAxis = m_plot->axisRect()->rangeDragAxis(Qt::Vertical);
337 auto oldXRange = xAxis->range();
337 auto oldXRange = xAxis->range();
338 auto oldYRange = yAxis->range();
338 auto oldYRange = yAxis->range();
339 double dx = xAxis->pixelToCoord(m_lastMousePos.x()) - xAxis->pixelToCoord(currentPos.x());
339 double dx = xAxis->pixelToCoord(m_lastMousePos.x()) - xAxis->pixelToCoord(currentPos.x());
340 xAxis->setRange(m_lastXRange.lower + dx, m_lastXRange.upper + dx);
340 xAxis->setRange(m_lastXRange.lower + dx, m_lastXRange.upper + dx);
341 if (yAxis->scaleType() == QCPAxis::stLinear)
341 if (yAxis->scaleType() == QCPAxis::stLinear)
342 {
342 {
343 double dy
343 double dy
344 = yAxis->pixelToCoord(m_lastMousePos.y()) - yAxis->pixelToCoord(currentPos.y());
344 = yAxis->pixelToCoord(m_lastMousePos.y()) - yAxis->pixelToCoord(currentPos.y());
345 yAxis->setRange(m_lastYRange.lower + dy, m_lastYRange.upper + dy);
345 yAxis->setRange(m_lastYRange.lower + dy, m_lastYRange.upper + dy);
346 }
346 }
347 else
347 else
348 {
348 {
349 double dy
349 double dy
350 = yAxis->pixelToCoord(m_lastMousePos.y()) / yAxis->pixelToCoord(currentPos.y());
350 = yAxis->pixelToCoord(m_lastMousePos.y()) / yAxis->pixelToCoord(currentPos.y());
351 yAxis->setRange(m_lastYRange.lower * dy, m_lastYRange.upper * dy);
351 yAxis->setRange(m_lastYRange.lower * dy, m_lastYRange.upper * dy);
352 }
352 }
353 auto newXRange = xAxis->range();
353 auto newXRange = xAxis->range();
354 auto newYRange = yAxis->range();
354 auto newYRange = yAxis->range();
355 setRange(xAxis->range());
355 setRange(xAxis->range());
356 // m_lastMousePos = currentPos;
356 // m_lastMousePos = currentPos;
357 return { newXRange.lower - oldXRange.lower, newYRange.lower - oldYRange.lower };
357 return { newXRange.lower - oldXRange.lower, newYRange.lower - oldYRange.lower };
358 }
358 }
359
359
360 void zoom(double factor, int center, Qt::Orientation orientation)
360 void zoom(double factor, int center, Qt::Orientation orientation)
361 {
361 {
362 QCPAxis* axis = m_plot->axisRect()->rangeZoomAxis(orientation);
362 QCPAxis* axis = m_plot->axisRect()->rangeZoomAxis(orientation);
363 axis->scaleRange(factor, axis->pixelToCoord(center));
363 axis->scaleRange(factor, axis->pixelToCoord(center));
364 if (orientation == Qt::Horizontal)
364 if (orientation == Qt::Horizontal)
365 setRange(axis->range());
365 setRange(axis->range());
366 m_plot->replot(QCustomPlot::rpQueuedReplot);
366 m_plot->replot(QCustomPlot::rpQueuedReplot);
367 }
367 }
368
368
369 void transform(const DateTimeRangeTransformation& tranformation)
369 void transform(const DateTimeRangeTransformation& tranformation)
370 {
370 {
371 auto graphRange = m_plot->xAxis->range();
371 auto graphRange = m_plot->xAxis->range();
372 DateTimeRange range { graphRange.lower, graphRange.upper };
372 DateTimeRange range { graphRange.lower, graphRange.upper };
373 range = range.transform(tranformation);
373 range = range.transform(tranformation);
374 setRange(range);
374 setRange(range);
375 m_plot->replot(QCustomPlot::rpQueuedReplot);
375 m_plot->replot(QCustomPlot::rpQueuedReplot);
376 }
376 }
377
377
378 void move(double dx, double dy)
378 void move(double dx, double dy)
379 {
379 {
380 auto xAxis = m_plot->axisRect()->rangeDragAxis(Qt::Horizontal);
380 auto xAxis = m_plot->axisRect()->rangeDragAxis(Qt::Horizontal);
381 auto yAxis = m_plot->axisRect()->rangeDragAxis(Qt::Vertical);
381 auto yAxis = m_plot->axisRect()->rangeDragAxis(Qt::Vertical);
382 xAxis->setRange(QCPRange(xAxis->range().lower + dx, xAxis->range().upper + dx));
382 xAxis->setRange(QCPRange(xAxis->range().lower + dx, xAxis->range().upper + dx));
383 yAxis->setRange(QCPRange(yAxis->range().lower + dy, yAxis->range().upper + dy));
383 yAxis->setRange(QCPRange(yAxis->range().lower + dy, yAxis->range().upper + dy));
384 setRange(xAxis->range());
384 setRange(xAxis->range());
385 m_plot->replot(QCustomPlot::rpQueuedReplot);
385 m_plot->replot(QCustomPlot::rpQueuedReplot);
386 }
386 }
387
387
388 void move(double factor, Qt::Orientation orientation)
388 void move(double factor, Qt::Orientation orientation)
389 {
389 {
390 auto oldRange = m_plot->xAxis->range();
390 auto oldRange = m_plot->xAxis->range();
391 QCPAxis* axis = m_plot->axisRect()->rangeDragAxis(orientation);
391 QCPAxis* axis = m_plot->axisRect()->rangeDragAxis(orientation);
392 if (m_plot->xAxis->scaleType() == QCPAxis::stLinear)
392 if (m_plot->xAxis->scaleType() == QCPAxis::stLinear)
393 {
393 {
394 double rg = (axis->range().upper - axis->range().lower) * (factor / 10);
394 double rg = (axis->range().upper - axis->range().lower) * (factor / 10);
395 axis->setRange(axis->range().lower + (rg), axis->range().upper + (rg));
395 axis->setRange(axis->range().lower + (rg), axis->range().upper + (rg));
396 }
396 }
397 else if (m_plot->xAxis->scaleType() == QCPAxis::stLogarithmic)
397 else if (m_plot->xAxis->scaleType() == QCPAxis::stLogarithmic)
398 {
398 {
399 int start = 0, stop = 0;
399 int start = 0, stop = 0;
400 double diff = 0.;
400 double diff = 0.;
401 if (factor > 0.0)
401 if (factor > 0.0)
402 {
402 {
403 stop = m_plot->width() * factor / 10;
403 stop = m_plot->width() * factor / 10;
404 start = 2 * m_plot->width() * factor / 10;
404 start = 2 * m_plot->width() * factor / 10;
405 }
405 }
406 if (factor < 0.0)
406 if (factor < 0.0)
407 {
407 {
408 factor *= -1.0;
408 factor *= -1.0;
409 start = m_plot->width() * factor / 10;
409 start = m_plot->width() * factor / 10;
410 stop = 2 * m_plot->width() * factor / 10;
410 stop = 2 * m_plot->width() * factor / 10;
411 }
411 }
412 diff = axis->pixelToCoord(start) / axis->pixelToCoord(stop);
412 diff = axis->pixelToCoord(start) / axis->pixelToCoord(stop);
413 axis->setRange(m_plot->axisRect()->rangeDragAxis(orientation)->range().lower * diff,
413 axis->setRange(m_plot->axisRect()->rangeDragAxis(orientation)->range().lower * diff,
414 m_plot->axisRect()->rangeDragAxis(orientation)->range().upper * diff);
414 m_plot->axisRect()->rangeDragAxis(orientation)->range().upper * diff);
415 }
415 }
416 if (orientation == Qt::Horizontal)
416 if (orientation == Qt::Horizontal)
417 setRange(axis->range());
417 setRange(axis->range());
418 m_plot->replot(QCustomPlot::rpQueuedReplot);
418 m_plot->replot(QCustomPlot::rpQueuedReplot);
419 }
419 }
420 };
420 };
421
421
422 VisualizationGraphWidget::VisualizationGraphWidget(const QString& name, QWidget* parent)
422 VisualizationGraphWidget::VisualizationGraphWidget(const QString& name, QWidget* parent)
423 : VisualizationDragWidget { parent }
423 : VisualizationDragWidget { parent }
424 , ui { new Ui::VisualizationGraphWidget }
424 , ui { new Ui::VisualizationGraphWidget }
425 , impl { spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name) }
425 , impl { spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name) }
426 {
426 {
427 ui->setupUi(this);
427 ui->setupUi(this);
428 this->layout()->addWidget(impl->m_plot);
428 this->layout()->addWidget(impl->m_plot);
429 // 'Close' options : widget is deleted when closed
429 // 'Close' options : widget is deleted when closed
430 setAttribute(Qt::WA_DeleteOnClose);
430 setAttribute(Qt::WA_DeleteOnClose);
431
431
432 // The delegate must be initialized after the ui as it uses the plot
432 // The delegate must be initialized after the ui as it uses the plot
433 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
433 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
434
434
435 // Init the cursors
435 // Init the cursors
436 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
436 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
437 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
437 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
438 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
438 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
439 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
439 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
440
440
441 this->setFocusPolicy(Qt::WheelFocus);
441 this->setFocusPolicy(Qt::WheelFocus);
442 this->setMouseTracking(true);
442 this->setMouseTracking(true);
443 impl->m_plot->setAttribute(Qt::WA_TransparentForMouseEvents);
443 impl->m_plot->setAttribute(Qt::WA_TransparentForMouseEvents);
444 impl->m_plot->setContextMenuPolicy(Qt::CustomContextMenu);
444 impl->m_plot->setContextMenuPolicy(Qt::CustomContextMenu);
445 impl->m_plot->setParent(this);
445 impl->m_plot->setParent(this);
446
446
447 connect(&sqpApp->variableController(), &VariableController2::variableDeleted, this,
447 connect(&sqpApp->variableController(), &VariableController2::variableDeleted, this,
448 &VisualizationGraphWidget::variableDeleted);
448 &VisualizationGraphWidget::variableDeleted);
449 }
449 }
450
450
451
451
452 VisualizationGraphWidget::~VisualizationGraphWidget()
452 VisualizationGraphWidget::~VisualizationGraphWidget()
453 {
453 {
454 delete ui;
454 delete ui;
455 }
455 }
456
456
457 VisualizationZoneWidget* VisualizationGraphWidget::parentZoneWidget() const noexcept
457 VisualizationZoneWidget* VisualizationGraphWidget::parentZoneWidget() const noexcept
458 {
458 {
459 auto parent = parentWidget();
459 auto parent = parentWidget();
460 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget*>(parent))
460 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget*>(parent))
461 {
461 {
462 parent = parent->parentWidget();
462 parent = parent->parentWidget();
463 }
463 }
464
464
465 return qobject_cast<VisualizationZoneWidget*>(parent);
465 return qobject_cast<VisualizationZoneWidget*>(parent);
466 }
466 }
467
467
468 VisualizationWidget* VisualizationGraphWidget::parentVisualizationWidget() const
468 VisualizationWidget* VisualizationGraphWidget::parentVisualizationWidget() const
469 {
469 {
470 auto parent = parentWidget();
470 auto parent = parentWidget();
471 while (parent != nullptr && !qobject_cast<VisualizationWidget*>(parent))
471 while (parent != nullptr && !qobject_cast<VisualizationWidget*>(parent))
472 {
472 {
473 parent = parent->parentWidget();
473 parent = parent->parentWidget();
474 }
474 }
475
475
476 return qobject_cast<VisualizationWidget*>(parent);
476 return qobject_cast<VisualizationWidget*>(parent);
477 }
477 }
478
478
479 void VisualizationGraphWidget::setFlags(GraphFlags flags)
479 void VisualizationGraphWidget::setFlags(GraphFlags flags)
480 {
480 {
481 impl->m_Flags = std::move(flags);
481 impl->m_Flags = std::move(flags);
482 }
482 }
483
483
484 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable2> variable, DateTimeRange range)
484 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable2> variable, DateTimeRange range)
485 {
485 {
486 // Uses delegate to create the qcpplot components according to the variable
486 // Uses delegate to create the qcpplot components according to the variable
487 auto createdPlottables = VisualizationGraphHelper::create(variable, *impl->m_plot);
487 auto createdPlottables = VisualizationGraphHelper::create(variable, *impl->m_plot);
488
488
489 // Sets graph properties
489 // Sets graph properties
490 impl->m_RenderingDelegate->setGraphProperties(*variable, createdPlottables);
490 impl->m_RenderingDelegate->setGraphProperties(*variable, createdPlottables);
491
491
492 impl->m_VariableToPlotMultiMap.insert({ variable, std::move(createdPlottables) });
492 impl->m_VariableToPlotMultiMap.insert({ variable, std::move(createdPlottables) });
493
493
494 setGraphRange(range);
494 setGraphRange(range);
495 // If the variable already has its data loaded, load its units and its range in the graph
495 // If the variable already has its data loaded, load its units and its range in the graph
496 if (variable->data() != nullptr)
496 if (variable->data() != nullptr)
497 {
497 {
498 impl->m_RenderingDelegate->setAxesUnits(*variable);
498 impl->m_RenderingDelegate->setAxesUnits(*variable);
499 }
499 }
500 else
500 else
501 {
501 {
502 auto context = new QObject { this };
502 auto context = new QObject { this };
503 connect(
503 connect(
504 variable.get(), &Variable2::updated, context, [this, variable, context, range](QUuid) {
504 variable.get(), &Variable2::updated, context, [this, variable, context, range](QUuid) {
505 this->impl->m_RenderingDelegate->setAxesUnits(*variable);
505 this->impl->m_RenderingDelegate->setAxesUnits(*variable);
506 this->impl->m_plot->replot(QCustomPlot::rpQueuedReplot);
506 this->impl->m_plot->replot(QCustomPlot::rpQueuedReplot);
507 delete context;
507 delete context;
508 });
508 });
509 }
509 }
510 //TODO this is bad! when variable is moved to another graph it still fires
510 //TODO this is bad! when variable is moved to another graph it still fires
511 // even if this has been deleted
511 // even if this has been deleted
512 connect(variable.get(), &Variable2::updated, this, &VisualizationGraphWidget::variableUpdated);
512 connect(variable.get(), &Variable2::updated, this, &VisualizationGraphWidget::variableUpdated);
513 this->onUpdateVarDisplaying(variable, range); // My bullshit
513 this->onUpdateVarDisplaying(variable, range); // My bullshit
514 emit variableAdded(variable);
514 emit variableAdded(variable);
515 }
515 }
516
516
517 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable2> variable) noexcept
517 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable2> variable) noexcept
518 {
518 {
519 // Each component associated to the variable :
519 // Each component associated to the variable :
520 // - is removed from qcpplot (which deletes it)
520 // - is removed from qcpplot (which deletes it)
521 // - is no longer referenced in the map
521 // - is no longer referenced in the map
522 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
522 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
523 if (variableIt != impl->m_VariableToPlotMultiMap.cend())
523 if (variableIt != impl->m_VariableToPlotMultiMap.cend())
524 {
524 {
525 emit variableAboutToBeRemoved(variable);
525 emit variableAboutToBeRemoved(variable);
526
526
527 auto& plottablesMap = variableIt->second;
527 auto& plottablesMap = variableIt->second;
528
528
529 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
529 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
530 plottableIt != plottableEnd;)
530 plottableIt != plottableEnd;)
531 {
531 {
532 impl->m_plot->removePlottable(plottableIt->second);
532 impl->m_plot->removePlottable(plottableIt->second);
533 plottableIt = plottablesMap.erase(plottableIt);
533 plottableIt = plottablesMap.erase(plottableIt);
534 }
534 }
535
535
536 impl->m_VariableToPlotMultiMap.erase(variableIt);
536 impl->m_VariableToPlotMultiMap.erase(variableIt);
537 }
537 }
538
538
539 // Updates graph
539 // Updates graph
540 impl->m_plot->replot(QCustomPlot::rpQueuedReplot);
540 impl->m_plot->replot(QCustomPlot::rpQueuedReplot);
541 }
541 }
542
542
543 std::vector<std::shared_ptr<Variable2>> VisualizationGraphWidget::variables() const
543 std::vector<std::shared_ptr<Variable2>> VisualizationGraphWidget::variables() const
544 {
544 {
545 auto variables = std::vector<std::shared_ptr<Variable2>> {};
545 auto variables = std::vector<std::shared_ptr<Variable2>> {};
546 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
546 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
547 it != std::cend(impl->m_VariableToPlotMultiMap); ++it)
547 it != std::cend(impl->m_VariableToPlotMultiMap); ++it)
548 {
548 {
549 variables.push_back(it->first);
549 variables.push_back(it->first);
550 }
550 }
551
551
552 return variables;
552 return variables;
553 }
553 }
554
554
555 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable2> variable)
555 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable2> variable)
556 {
556 {
557 if (!variable)
557 if (!variable)
558 {
558 {
559 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
559 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
560 return;
560 return;
561 }
561 }
562
562
563 VisualizationGraphHelper::setYAxisRange(variable, *impl->m_plot);
563 VisualizationGraphHelper::setYAxisRange(variable, *impl->m_plot);
564 }
564 }
565
565
566 DateTimeRange VisualizationGraphWidget::graphRange() const noexcept
566 DateTimeRange VisualizationGraphWidget::graphRange() const noexcept
567 {
567 {
568 auto graphRange = impl->m_plot->xAxis->range();
568 auto graphRange = impl->m_plot->xAxis->range();
569 return DateTimeRange { graphRange.lower, graphRange.upper };
569 return DateTimeRange { graphRange.lower, graphRange.upper };
570 }
570 }
571
571
572 void VisualizationGraphWidget::setGraphRange(
572 void VisualizationGraphWidget::setGraphRange(
573 const DateTimeRange& range, bool updateVar, bool forward)
573 const DateTimeRange& range, bool updateVar, bool forward)
574 {
574 {
575 impl->setRange(range, updateVar);
575 impl->setRange(range, updateVar);
576 if (forward)
576 if (forward)
577 {
577 {
578 emit this->setrange_sig(this->graphRange(), true, false);
578 emit this->setrange_sig(this->graphRange(), true, false);
579 }
579 }
580 }
580 }
581
581
582 void VisualizationGraphWidget::setAutoRangeOnVariableInitialization(bool value)
582 void VisualizationGraphWidget::setAutoRangeOnVariableInitialization(bool value)
583 {
583 {
584 impl->m_VariableAutoRangeOnInit = value;
584 impl->m_VariableAutoRangeOnInit = value;
585 }
585 }
586
586
587 QVector<DateTimeRange> VisualizationGraphWidget::selectionZoneRanges() const
587 QVector<DateTimeRange> VisualizationGraphWidget::selectionZoneRanges() const
588 {
588 {
589 QVector<DateTimeRange> ranges;
589 QVector<DateTimeRange> ranges;
590 for (auto zone : impl->m_SelectionZones)
590 for (auto zone : impl->m_SelectionZones)
591 {
591 {
592 ranges << zone->range();
592 ranges << zone->range();
593 }
593 }
594
594
595 return ranges;
595 return ranges;
596 }
596 }
597
597
598 void VisualizationGraphWidget::addSelectionZones(const QVector<DateTimeRange>& ranges)
598 void VisualizationGraphWidget::addSelectionZones(const QVector<DateTimeRange>& ranges)
599 {
599 {
600 for (const auto& range : ranges)
600 for (const auto& range : ranges)
601 {
601 {
602 // note: ownership is transfered to QCustomPlot
602 // note: ownership is transfered to QCustomPlot
603 auto zone = new VisualizationSelectionZoneItem(&plot());
603 auto zone = new VisualizationSelectionZoneItem(&plot());
604 zone->setRange(range.m_TStart, range.m_TEnd);
604 zone->setRange(range.m_TStart, range.m_TEnd);
605 impl->addSelectionZone(zone);
605 impl->addSelectionZone(zone);
606 }
606 }
607
607
608 plot().replot(QCustomPlot::rpQueuedReplot);
608 plot().replot(QCustomPlot::rpQueuedReplot);
609 }
609 }
610
610
611 VisualizationSelectionZoneItem* VisualizationGraphWidget::addSelectionZone(
611 VisualizationSelectionZoneItem* VisualizationGraphWidget::addSelectionZone(
612 const QString& name, const DateTimeRange& range)
612 const QString& name, const DateTimeRange& range)
613 {
613 {
614 // note: ownership is transfered to QCustomPlot
614 // note: ownership is transfered to QCustomPlot
615 auto zone = new VisualizationSelectionZoneItem(&plot());
615 auto zone = new VisualizationSelectionZoneItem(&plot());
616 zone->setName(name);
616 zone->setName(name);
617 zone->setRange(range.m_TStart, range.m_TEnd);
617 zone->setRange(range.m_TStart, range.m_TEnd);
618 impl->addSelectionZone(zone);
618 impl->addSelectionZone(zone);
619
619
620 plot().replot(QCustomPlot::rpQueuedReplot);
620 plot().replot(QCustomPlot::rpQueuedReplot);
621
621
622 return zone;
622 return zone;
623 }
623 }
624
624
625 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem* selectionZone)
625 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem* selectionZone)
626 {
626 {
627 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
627 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
628
628
629 if (impl->m_HoveredZone == selectionZone)
629 if (impl->m_HoveredZone == selectionZone)
630 {
630 {
631 impl->m_HoveredZone = nullptr;
631 impl->m_HoveredZone = nullptr;
632 setCursor(Qt::ArrowCursor);
632 setCursor(Qt::ArrowCursor);
633 }
633 }
634
634
635 impl->m_SelectionZones.removeAll(selectionZone);
635 impl->m_SelectionZones.removeAll(selectionZone);
636 plot().removeItem(selectionZone);
636 plot().removeItem(selectionZone);
637 plot().replot(QCustomPlot::rpQueuedReplot);
637 plot().replot(QCustomPlot::rpQueuedReplot);
638 }
638 }
639
639
640 void VisualizationGraphWidget::undoZoom()
640 void VisualizationGraphWidget::undoZoom()
641 {
641 {
642 auto zoom = impl->m_ZoomStack.pop();
642 auto zoom = impl->m_ZoomStack.pop();
643 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
643 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
644 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
644 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
645
645
646 axisX->setRange(zoom.first);
646 axisX->setRange(zoom.first);
647 axisY->setRange(zoom.second);
647 axisY->setRange(zoom.second);
648
648
649 plot().replot(QCustomPlot::rpQueuedReplot);
649 plot().replot(QCustomPlot::rpQueuedReplot);
650 }
650 }
651
651
652 void VisualizationGraphWidget::zoom(
652 void VisualizationGraphWidget::zoom(
653 double factor, int center, Qt::Orientation orientation, bool forward)
653 double factor, int center, Qt::Orientation orientation, bool forward)
654 {
654 {
655 impl->zoom(factor, center, orientation);
655 impl->zoom(factor, center, orientation);
656 if (forward && orientation == Qt::Horizontal)
656 if (forward && orientation == Qt::Horizontal)
657 emit this->setrange_sig(this->graphRange(), true, false);
657 emit this->setrange_sig(this->graphRange(), true, false);
658 }
658 }
659
659
660 void VisualizationGraphWidget::move(double factor, Qt::Orientation orientation, bool forward)
660 void VisualizationGraphWidget::move(double factor, Qt::Orientation orientation, bool forward)
661 {
661 {
662 impl->move(factor, orientation);
662 impl->move(factor, orientation);
663 if (forward)
663 if (forward)
664 emit this->setrange_sig(this->graphRange(), true, false);
664 emit this->setrange_sig(this->graphRange(), true, false);
665 }
665 }
666
666
667 void VisualizationGraphWidget::move(double dx, double dy, bool forward)
667 void VisualizationGraphWidget::move(double dx, double dy, bool forward)
668 {
668 {
669 impl->move(dx, dy);
669 impl->move(dx, dy);
670 if (forward)
670 if (forward)
671 emit this->setrange_sig(this->graphRange(), true, false);
671 emit this->setrange_sig(this->graphRange(), true, false);
672 }
672 }
673
673
674 void VisualizationGraphWidget::transform(
674 void VisualizationGraphWidget::transform(
675 const DateTimeRangeTransformation& tranformation, bool forward)
675 const DateTimeRangeTransformation& tranformation, bool forward)
676 {
676 {
677 impl->transform(tranformation);
677 impl->transform(tranformation);
678 if (forward)
678 if (forward)
679 emit this->setrange_sig(this->graphRange(), true, false);
679 emit this->setrange_sig(this->graphRange(), true, false);
680 }
680 }
681
681
682 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor* visitor)
682 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor* visitor)
683 {
683 {
684 if (visitor)
684 if (visitor)
685 {
685 {
686 visitor->visit(this);
686 visitor->visit(this);
687 }
687 }
688 else
688 else
689 {
689 {
690 qCCritical(LOG_VisualizationGraphWidget())
690 qCCritical(LOG_VisualizationGraphWidget())
691 << tr("Can't visit widget : the visitor is null");
691 << tr("Can't visit widget : the visitor is null");
692 }
692 }
693 }
693 }
694
694
695 bool VisualizationGraphWidget::canDrop(Variable2& variable) const
695 bool VisualizationGraphWidget::canDrop(Variable2& variable) const
696 {
696 {
697 auto isSpectrogram
697 auto isSpectrogram
698 = [](auto& variable) { return variable.type() == DataSeriesType::SPECTROGRAM; };
698 = [](auto& variable) { return variable.type() == DataSeriesType::SPECTROGRAM; };
699
699
700 // - A spectrogram series can't be dropped on graph with existing plottables
700 // - A spectrogram series can't be dropped on graph with existing plottables
701 // - No data series can be dropped on graph with existing spectrogram series
701 // - No data series can be dropped on graph with existing spectrogram series
702 return isSpectrogram(variable)
702 return isSpectrogram(variable)
703 ? impl->m_VariableToPlotMultiMap.empty()
703 ? impl->m_VariableToPlotMultiMap.empty()
704 : std::none_of(impl->m_VariableToPlotMultiMap.cbegin(),
704 : std::none_of(impl->m_VariableToPlotMultiMap.cbegin(),
705 impl->m_VariableToPlotMultiMap.cend(),
705 impl->m_VariableToPlotMultiMap.cend(),
706 [isSpectrogram](const auto& entry) { return isSpectrogram(*entry.first); });
706 [isSpectrogram](const auto& entry) { return isSpectrogram(*entry.first); });
707 }
707 }
708
708
709 bool VisualizationGraphWidget::contains(Variable2& variable) const
709 bool VisualizationGraphWidget::contains(Variable2& variable) const
710 {
710 {
711 // Finds the variable among the keys of the map
711 // Finds the variable among the keys of the map
712 auto variablePtr = &variable;
712 auto variablePtr = &variable;
713 auto findVariable
713 auto findVariable
714 = [variablePtr](const auto& entry) { return variablePtr == entry.first.get(); };
714 = [variablePtr](const auto& entry) { return variablePtr == entry.first.get(); };
715
715
716 auto end = impl->m_VariableToPlotMultiMap.cend();
716 auto end = impl->m_VariableToPlotMultiMap.cend();
717 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
717 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
718 return it != end;
718 return it != end;
719 }
719 }
720
720
721 QString VisualizationGraphWidget::name() const
721 QString VisualizationGraphWidget::name() const
722 {
722 {
723 return impl->m_Name;
723 return impl->m_Name;
724 }
724 }
725
725
726 QMimeData* VisualizationGraphWidget::mimeData(const QPoint& position) const
726 QMimeData* VisualizationGraphWidget::mimeData(const QPoint& position) const
727 {
727 {
728 auto mimeData = new QMimeData;
728 auto mimeData = new QMimeData;
729
729
730 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position);
730 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position);
731 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
731 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
732 && selectionZoneItemUnderCursor)
732 && selectionZoneItemUnderCursor)
733 {
733 {
734 mimeData->setData(MIME_TYPE_TIME_RANGE,
734 mimeData->setData(MIME::MIME_TYPE_TIME_RANGE,
735 TimeController::mimeDataForTimeRange(selectionZoneItemUnderCursor->range()));
735 TimeController::mimeDataForTimeRange(selectionZoneItemUnderCursor->range()));
736 mimeData->setData(MIME_TYPE_SELECTION_ZONE,
736 mimeData->setData(MIME::MIME_TYPE_SELECTION_ZONE,
737 TimeController::mimeDataForTimeRange(selectionZoneItemUnderCursor->range()));
737 TimeController::mimeDataForTimeRange(selectionZoneItemUnderCursor->range()));
738 }
738 }
739 else
739 else
740 {
740 {
741 mimeData->setData(MIME_TYPE_GRAPH, QByteArray {});
741 mimeData->setData(MIME::MIME_TYPE_GRAPH, QByteArray {});
742
742
743 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
743 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
744 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
744 mimeData->setData(MIME::MIME_TYPE_TIME_RANGE, timeRangeData);
745 }
745 }
746
746
747 return mimeData;
747 return mimeData;
748 }
748 }
749
749
750 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint& dragPosition)
750 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint& dragPosition)
751 {
751 {
752 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition);
752 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition);
753 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
753 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
754 && selectionZoneItemUnderCursor)
754 && selectionZoneItemUnderCursor)
755 {
755 {
756
756
757 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
757 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
758 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
758 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
759
759
760 auto zoneSize = QSizeF { qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
760 auto zoneSize = QSizeF { qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
761 qAbs(zoneBottomRight.y() - zoneTopLeft.y()) }
761 qAbs(zoneBottomRight.y() - zoneTopLeft.y()) }
762 .toSize();
762 .toSize();
763
763
764 auto pixmap = QPixmap(zoneSize);
764 auto pixmap = QPixmap(zoneSize);
765 render(&pixmap, QPoint(), QRegion { QRect { zoneTopLeft.toPoint(), zoneSize } });
765 render(&pixmap, QPoint(), QRegion { QRect { zoneTopLeft.toPoint(), zoneSize } });
766
766
767 return pixmap;
767 return pixmap;
768 }
768 }
769
769
770 return QPixmap();
770 return QPixmap();
771 }
771 }
772
772
773 bool VisualizationGraphWidget::isDragAllowed() const
773 bool VisualizationGraphWidget::isDragAllowed() const
774 {
774 {
775 return true;
775 return true;
776 }
776 }
777
777
778 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
778 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
779 {
779 {
780 if (highlighted)
780 if (highlighted)
781 {
781 {
782 plot().setBackground(QBrush(QColor("#BBD5EE")));
782 plot().setBackground(QBrush(QColor("#BBD5EE")));
783 }
783 }
784 else
784 else
785 {
785 {
786 plot().setBackground(QBrush(Qt::white));
786 plot().setBackground(QBrush(Qt::white));
787 }
787 }
788
788
789 plot().update();
789 plot().update();
790 }
790 }
791
791
792 void VisualizationGraphWidget::addVerticalCursor(double time)
792 void VisualizationGraphWidget::addVerticalCursor(double time)
793 {
793 {
794 impl->m_VerticalCursor->setPosition(time);
794 impl->m_VerticalCursor->setPosition(time);
795 impl->m_VerticalCursor->setVisible(true);
795 impl->m_VerticalCursor->setVisible(true);
796
796
797 auto text
797 auto text
798 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
798 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
799 impl->m_VerticalCursor->setLabelText(text);
799 impl->m_VerticalCursor->setLabelText(text);
800 }
800 }
801
801
802 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
802 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
803 {
803 {
804 impl->m_VerticalCursor->setAbsolutePosition(position);
804 impl->m_VerticalCursor->setAbsolutePosition(position);
805 impl->m_VerticalCursor->setVisible(true);
805 impl->m_VerticalCursor->setVisible(true);
806
806
807 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
807 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
808 auto text
808 auto text
809 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
809 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
810 impl->m_VerticalCursor->setLabelText(text);
810 impl->m_VerticalCursor->setLabelText(text);
811 }
811 }
812
812
813 void VisualizationGraphWidget::removeVerticalCursor()
813 void VisualizationGraphWidget::removeVerticalCursor()
814 {
814 {
815 impl->m_VerticalCursor->setVisible(false);
815 impl->m_VerticalCursor->setVisible(false);
816 plot().replot(QCustomPlot::rpQueuedReplot);
816 plot().replot(QCustomPlot::rpQueuedReplot);
817 }
817 }
818
818
819 void VisualizationGraphWidget::addHorizontalCursor(double value)
819 void VisualizationGraphWidget::addHorizontalCursor(double value)
820 {
820 {
821 impl->m_HorizontalCursor->setPosition(value);
821 impl->m_HorizontalCursor->setPosition(value);
822 impl->m_HorizontalCursor->setVisible(true);
822 impl->m_HorizontalCursor->setVisible(true);
823 impl->m_HorizontalCursor->setLabelText(QString::number(value));
823 impl->m_HorizontalCursor->setLabelText(QString::number(value));
824 }
824 }
825
825
826 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
826 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
827 {
827 {
828 impl->m_HorizontalCursor->setAbsolutePosition(position);
828 impl->m_HorizontalCursor->setAbsolutePosition(position);
829 impl->m_HorizontalCursor->setVisible(true);
829 impl->m_HorizontalCursor->setVisible(true);
830
830
831 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
831 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
832 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
832 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
833 }
833 }
834
834
835 void VisualizationGraphWidget::removeHorizontalCursor()
835 void VisualizationGraphWidget::removeHorizontalCursor()
836 {
836 {
837 impl->m_HorizontalCursor->setVisible(false);
837 impl->m_HorizontalCursor->setVisible(false);
838 plot().replot(QCustomPlot::rpQueuedReplot);
838 plot().replot(QCustomPlot::rpQueuedReplot);
839 }
839 }
840
840
841 void VisualizationGraphWidget::closeEvent(QCloseEvent* event)
841 void VisualizationGraphWidget::closeEvent(QCloseEvent* event)
842 {
842 {
843 Q_UNUSED(event);
843 Q_UNUSED(event);
844
844
845 for (auto i : impl->m_SelectionZones)
845 for (auto i : impl->m_SelectionZones)
846 {
846 {
847 parentVisualizationWidget()->selectionZoneManager().setSelected(i, false);
847 parentVisualizationWidget()->selectionZoneManager().setSelected(i, false);
848 }
848 }
849
849
850 // Prevents that all variables will be removed from graph when it will be closed
850 // Prevents that all variables will be removed from graph when it will be closed
851 for (auto& variableEntry : impl->m_VariableToPlotMultiMap)
851 for (auto& variableEntry : impl->m_VariableToPlotMultiMap)
852 {
852 {
853 emit variableAboutToBeRemoved(variableEntry.first);
853 emit variableAboutToBeRemoved(variableEntry.first);
854 }
854 }
855 }
855 }
856
856
857 void VisualizationGraphWidget::enterEvent(QEvent* event)
857 void VisualizationGraphWidget::enterEvent(QEvent* event)
858 {
858 {
859 Q_UNUSED(event);
859 Q_UNUSED(event);
860 impl->m_RenderingDelegate->showGraphOverlay(true);
860 impl->m_RenderingDelegate->showGraphOverlay(true);
861 }
861 }
862
862
863 void VisualizationGraphWidget::leaveEvent(QEvent* event)
863 void VisualizationGraphWidget::leaveEvent(QEvent* event)
864 {
864 {
865 Q_UNUSED(event);
865 Q_UNUSED(event);
866 impl->m_RenderingDelegate->showGraphOverlay(false);
866 impl->m_RenderingDelegate->showGraphOverlay(false);
867
867
868 if (auto parentZone = parentZoneWidget())
868 if (auto parentZone = parentZoneWidget())
869 {
869 {
870 parentZone->notifyMouseLeaveGraph(this);
870 parentZone->notifyMouseLeaveGraph(this);
871 }
871 }
872 else
872 else
873 {
873 {
874 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
874 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
875 }
875 }
876
876
877 if (impl->m_HoveredZone)
877 if (impl->m_HoveredZone)
878 {
878 {
879 impl->m_HoveredZone->setHovered(false);
879 impl->m_HoveredZone->setHovered(false);
880 impl->m_HoveredZone = nullptr;
880 impl->m_HoveredZone = nullptr;
881 }
881 }
882 }
882 }
883
883
884 void VisualizationGraphWidget::wheelEvent(QWheelEvent* event)
884 void VisualizationGraphWidget::wheelEvent(QWheelEvent* event)
885 {
885 {
886 double factor;
886 double factor;
887 double wheelSteps = event->delta() / 120.0; // a single step delta is +/-120 usually
887 double wheelSteps = event->delta() / 120.0; // a single step delta is +/-120 usually
888 if (event->modifiers() == Qt::ControlModifier)
888 if (event->modifiers() == Qt::ControlModifier)
889 {
889 {
890 if (event->orientation() == Qt::Vertical) // mRangeZoom.testFlag(Qt::Vertical))
890 if (event->orientation() == Qt::Vertical) // mRangeZoom.testFlag(Qt::Vertical))
891 {
891 {
892 setCursor(Qt::SizeVerCursor);
892 setCursor(Qt::SizeVerCursor);
893 factor = pow(impl->m_plot->axisRect()->rangeZoomFactor(Qt::Vertical), wheelSteps);
893 factor = pow(impl->m_plot->axisRect()->rangeZoomFactor(Qt::Vertical), wheelSteps);
894 zoom(factor, event->pos().y(), Qt::Vertical);
894 zoom(factor, event->pos().y(), Qt::Vertical);
895 }
895 }
896 }
896 }
897 else if (event->modifiers() == Qt::ShiftModifier)
897 else if (event->modifiers() == Qt::ShiftModifier)
898 {
898 {
899 if (event->orientation() == Qt::Vertical) // mRangeZoom.testFlag(Qt::Vertical))
899 if (event->orientation() == Qt::Vertical) // mRangeZoom.testFlag(Qt::Vertical))
900 {
900 {
901 setCursor(Qt::SizeHorCursor);
901 setCursor(Qt::SizeHorCursor);
902 factor = pow(impl->m_plot->axisRect()->rangeZoomFactor(Qt::Horizontal), wheelSteps);
902 factor = pow(impl->m_plot->axisRect()->rangeZoomFactor(Qt::Horizontal), wheelSteps);
903 zoom(factor, event->pos().x(), Qt::Horizontal);
903 zoom(factor, event->pos().x(), Qt::Horizontal);
904 }
904 }
905 }
905 }
906 else
906 else
907 {
907 {
908 move(wheelSteps, Qt::Horizontal);
908 move(wheelSteps, Qt::Horizontal);
909 }
909 }
910 event->accept();
910 event->accept();
911 }
911 }
912
912
913
913
914 void VisualizationGraphWidget::mouseMoveEvent(QMouseEvent* event)
914 void VisualizationGraphWidget::mouseMoveEvent(QMouseEvent* event)
915 {
915 {
916 if (impl->isDrawingZoomRect())
916 if (impl->isDrawingZoomRect())
917 {
917 {
918 impl->updateZoomRect(event->pos());
918 impl->updateZoomRect(event->pos());
919 }
919 }
920 else if (impl->isDrawingZoneRect())
920 else if (impl->isDrawingZoneRect())
921 {
921 {
922 impl->updateZoneRect(event->pos());
922 impl->updateZoneRect(event->pos());
923 }
923 }
924 else if (event->buttons() == Qt::LeftButton)
924 else if (event->buttons() == Qt::LeftButton)
925 {
925 {
926 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::None)
926 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::None)
927 {
927 {
928 auto [dx, dy] = impl->moveGraph(event->pos());
928 auto [dx, dy] = impl->moveGraph(event->pos());
929 emit this->setrange_sig(this->graphRange(), true, false);
929 emit this->setrange_sig(this->graphRange(), true, false);
930 }
930 }
931 else if (sqpApp->plotsInteractionMode()
931 else if (sqpApp->plotsInteractionMode()
932 == SqpApplication::PlotsInteractionMode::SelectionZones)
932 == SqpApplication::PlotsInteractionMode::SelectionZones)
933 {
933 {
934 auto posInPlot = this->impl->m_plot->mapFromParent(event->pos());
934 auto posInPlot = this->impl->m_plot->mapFromParent(event->pos());
935 if (auto item = impl->m_plot->itemAt(posInPlot))
935 if (auto item = impl->m_plot->itemAt(posInPlot))
936 {
936 {
937 if (qobject_cast<VisualizationSelectionZoneItem*>(item))
937 if (qobject_cast<VisualizationSelectionZoneItem*>(item))
938 {
938 {
939 QMouseEvent e { QEvent::MouseMove, posInPlot, event->button(), event->buttons(),
939 QMouseEvent e { QEvent::MouseMove, posInPlot, event->button(), event->buttons(),
940 event->modifiers() };
940 event->modifiers() };
941 sqpApp->sendEvent(this->impl->m_plot, &e);
941 sqpApp->sendEvent(this->impl->m_plot, &e);
942 this->impl->m_plot->replot(QCustomPlot::rpImmediateRefresh);
942 this->impl->m_plot->replot(QCustomPlot::rpImmediateRefresh);
943 }
943 }
944 }
944 }
945 }
945 }
946 }
946 }
947 else
947 else
948 {
948 {
949 impl->m_RenderingDelegate->updateTooltip(event);
949 impl->m_RenderingDelegate->updateTooltip(event);
950 }
950 }
951 // event->accept();
951 // event->accept();
952 QWidget::mouseMoveEvent(event);
952 QWidget::mouseMoveEvent(event);
953 }
953 }
954
954
955 void VisualizationGraphWidget::mouseReleaseEvent(QMouseEvent* event)
955 void VisualizationGraphWidget::mouseReleaseEvent(QMouseEvent* event)
956 {
956 {
957 if (impl->isDrawingZoomRect())
957 if (impl->isDrawingZoomRect())
958 {
958 {
959 auto oldRange = this->graphRange();
959 auto oldRange = this->graphRange();
960 impl->applyZoomRect();
960 impl->applyZoomRect();
961 auto newRange = this->graphRange();
961 auto newRange = this->graphRange();
962 if (auto tf = DateTimeRangeHelper::computeTransformation(oldRange, newRange))
962 if (auto tf = DateTimeRangeHelper::computeTransformation(oldRange, newRange))
963 emit this->transform_sig(tf.value(), false);
963 emit this->transform_sig(tf.value(), false);
964 }
964 }
965 else if (impl->isDrawingZoneRect())
965 else if (impl->isDrawingZoneRect())
966 {
966 {
967 impl->endDrawingZone();
967 impl->endDrawingZone();
968 }
968 }
969 else
969 else
970 {
970 {
971 setCursor(Qt::ArrowCursor);
971 setCursor(Qt::ArrowCursor);
972 }
972 }
973 auto posInPlot = this->impl->m_plot->mapFromParent(event->pos());
973 auto posInPlot = this->impl->m_plot->mapFromParent(event->pos());
974 if (auto item = impl->m_plot->itemAt(posInPlot))
974 if (auto item = impl->m_plot->itemAt(posInPlot))
975 {
975 {
976 if (qobject_cast<VisualizationSelectionZoneItem*>(item))
976 if (qobject_cast<VisualizationSelectionZoneItem*>(item))
977 {
977 {
978 QMouseEvent e { QEvent::MouseButtonRelease, posInPlot, event->button(),
978 QMouseEvent e { QEvent::MouseButtonRelease, posInPlot, event->button(),
979 event->buttons(), event->modifiers() };
979 event->buttons(), event->modifiers() };
980 sqpApp->sendEvent(this->impl->m_plot, &e);
980 sqpApp->sendEvent(this->impl->m_plot, &e);
981 }
981 }
982 }
982 }
983 event->accept();
983 event->accept();
984 }
984 }
985
985
986 void VisualizationGraphWidget::mousePressEvent(QMouseEvent* event)
986 void VisualizationGraphWidget::mousePressEvent(QMouseEvent* event)
987 {
987 {
988 if (event->button() == Qt::RightButton)
988 if (event->button() == Qt::RightButton)
989 {
989 {
990 onGraphMenuRequested(event->pos());
990 onGraphMenuRequested(event->pos());
991 }
991 }
992 else
992 else
993 {
993 {
994 auto selectedZone = impl->selectionZoneAt(event->pos());
994 auto selectedZone = impl->selectionZoneAt(event->pos());
995 switch (sqpApp->plotsInteractionMode())
995 switch (sqpApp->plotsInteractionMode())
996 {
996 {
997 case SqpApplication::PlotsInteractionMode::DragAndDrop:
997 case SqpApplication::PlotsInteractionMode::DragAndDrop:
998 break;
998 break;
999 case SqpApplication::PlotsInteractionMode::SelectionZones:
999 case SqpApplication::PlotsInteractionMode::SelectionZones:
1000 impl->setSelectionZonesEditionEnabled(true);
1000 impl->setSelectionZonesEditionEnabled(true);
1001 if ((event->modifiers() == Qt::ControlModifier) && (selectedZone != nullptr))
1001 if ((event->modifiers() == Qt::ControlModifier) && (selectedZone != nullptr))
1002 {
1002 {
1003 auto alreadySelectedZones
1003 auto alreadySelectedZones
1004 = parentVisualizationWidget()->selectionZoneManager().selectedItems();
1004 = parentVisualizationWidget()->selectionZoneManager().selectedItems();
1005 selectedZone->setAssociatedEditedZones(alreadySelectedZones);
1005 selectedZone->setAssociatedEditedZones(alreadySelectedZones);
1006 if (cpp_utils::containers::contains(alreadySelectedZones, selectedZone))
1006 if (cpp_utils::containers::contains(alreadySelectedZones, selectedZone))
1007 {
1007 {
1008 alreadySelectedZones.removeOne(selectedZone);
1008 alreadySelectedZones.removeOne(selectedZone);
1009 }
1009 }
1010 else
1010 else
1011 {
1011 {
1012 alreadySelectedZones.append(selectedZone);
1012 alreadySelectedZones.append(selectedZone);
1013 }
1013 }
1014 parentVisualizationWidget()->selectionZoneManager().select(
1014 parentVisualizationWidget()->selectionZoneManager().select(
1015 alreadySelectedZones);
1015 alreadySelectedZones);
1016 }
1016 }
1017 else
1017 else
1018 {
1018 {
1019 if (!selectedZone)
1019 if (!selectedZone)
1020 {
1020 {
1021 parentVisualizationWidget()->selectionZoneManager().clearSelection();
1021 parentVisualizationWidget()->selectionZoneManager().clearSelection();
1022 impl->startDrawingZone(event->pos());
1022 impl->startDrawingZone(event->pos());
1023 }
1023 }
1024 else
1024 else
1025 {
1025 {
1026 parentVisualizationWidget()->selectionZoneManager().select(
1026 parentVisualizationWidget()->selectionZoneManager().select(
1027 { selectedZone });
1027 { selectedZone });
1028 }
1028 }
1029 }
1029 }
1030 {
1030 {
1031 auto posInPlot = this->impl->m_plot->mapFromParent(event->pos());
1031 auto posInPlot = this->impl->m_plot->mapFromParent(event->pos());
1032 if (auto item = impl->m_plot->itemAt(posInPlot))
1032 if (auto item = impl->m_plot->itemAt(posInPlot))
1033 {
1033 {
1034 if (qobject_cast<VisualizationSelectionZoneItem*>(item))
1034 if (qobject_cast<VisualizationSelectionZoneItem*>(item))
1035 {
1035 {
1036 QMouseEvent e { QEvent::MouseButtonPress, posInPlot, event->button(),
1036 QMouseEvent e { QEvent::MouseButtonPress, posInPlot, event->button(),
1037 event->buttons(), event->modifiers() };
1037 event->buttons(), event->modifiers() };
1038 sqpApp->sendEvent(this->impl->m_plot, &e);
1038 sqpApp->sendEvent(this->impl->m_plot, &e);
1039 }
1039 }
1040 }
1040 }
1041 }
1041 }
1042 break;
1042 break;
1043 case SqpApplication::PlotsInteractionMode::ZoomBox:
1043 case SqpApplication::PlotsInteractionMode::ZoomBox:
1044 impl->startDrawingRect(event->pos());
1044 impl->startDrawingRect(event->pos());
1045 break;
1045 break;
1046 default:
1046 default:
1047 if (auto item = impl->m_plot->itemAt(event->pos()))
1047 if (auto item = impl->m_plot->itemAt(event->pos()))
1048 {
1048 {
1049 emit impl->m_plot->itemClick(item, event);
1049 emit impl->m_plot->itemClick(item, event);
1050 if (qobject_cast<VisualizationSelectionZoneItem*>(item))
1050 if (qobject_cast<VisualizationSelectionZoneItem*>(item))
1051 {
1051 {
1052 setCursor(Qt::ClosedHandCursor);
1052 setCursor(Qt::ClosedHandCursor);
1053 impl->enterPlotDrag(event->pos());
1053 impl->enterPlotDrag(event->pos());
1054 }
1054 }
1055 }
1055 }
1056 else
1056 else
1057 {
1057 {
1058 setCursor(Qt::ClosedHandCursor);
1058 setCursor(Qt::ClosedHandCursor);
1059 impl->enterPlotDrag(event->pos());
1059 impl->enterPlotDrag(event->pos());
1060 }
1060 }
1061 }
1061 }
1062 }
1062 }
1063 // event->accept();
1063 // event->accept();
1064 QWidget::mousePressEvent(event);
1064 QWidget::mousePressEvent(event);
1065 }
1065 }
1066
1066
1067 void VisualizationGraphWidget::mouseDoubleClickEvent(QMouseEvent* event)
1067 void VisualizationGraphWidget::mouseDoubleClickEvent(QMouseEvent* event)
1068 {
1068 {
1069 impl->m_RenderingDelegate->onMouseDoubleClick(event);
1069 impl->m_RenderingDelegate->onMouseDoubleClick(event);
1070 }
1070 }
1071
1071
1072 void VisualizationGraphWidget::keyReleaseEvent(QKeyEvent* event)
1072 void VisualizationGraphWidget::keyReleaseEvent(QKeyEvent* event)
1073 {
1073 {
1074 switch (event->key())
1074 switch (event->key())
1075 {
1075 {
1076 case Qt::Key_Control:
1076 case Qt::Key_Control:
1077 event->accept();
1077 event->accept();
1078 break;
1078 break;
1079 case Qt::Key_Shift:
1079 case Qt::Key_Shift:
1080 event->accept();
1080 event->accept();
1081 break;
1081 break;
1082 default:
1082 default:
1083 QWidget::keyReleaseEvent(event);
1083 QWidget::keyReleaseEvent(event);
1084 break;
1084 break;
1085 }
1085 }
1086 setCursor(Qt::ArrowCursor);
1086 setCursor(Qt::ArrowCursor);
1087 // event->accept();
1087 // event->accept();
1088 }
1088 }
1089
1089
1090 void VisualizationGraphWidget::keyPressEvent(QKeyEvent* event)
1090 void VisualizationGraphWidget::keyPressEvent(QKeyEvent* event)
1091 {
1091 {
1092 switch (event->key())
1092 switch (event->key())
1093 {
1093 {
1094 case Qt::Key_Control:
1094 case Qt::Key_Control:
1095 setCursor(Qt::CrossCursor);
1095 setCursor(Qt::CrossCursor);
1096 break;
1096 break;
1097 case Qt::Key_Shift:
1097 case Qt::Key_Shift:
1098 break;
1098 break;
1099 case Qt::Key_M:
1099 case Qt::Key_M:
1100 impl->rescaleY();
1100 impl->rescaleY();
1101 impl->m_plot->replot(QCustomPlot::rpQueuedReplot);
1101 impl->m_plot->replot(QCustomPlot::rpQueuedReplot);
1102 break;
1102 break;
1103 case Qt::Key_Left:
1103 case Qt::Key_Left:
1104 if (event->modifiers() != Qt::ControlModifier)
1104 if (event->modifiers() != Qt::ControlModifier)
1105 {
1105 {
1106 move(-0.1, Qt::Horizontal);
1106 move(-0.1, Qt::Horizontal);
1107 }
1107 }
1108 else
1108 else
1109 {
1109 {
1110 zoom(2, this->width() / 2, Qt::Horizontal);
1110 zoom(2, this->width() / 2, Qt::Horizontal);
1111 }
1111 }
1112 break;
1112 break;
1113 case Qt::Key_Right:
1113 case Qt::Key_Right:
1114 if (event->modifiers() != Qt::ControlModifier)
1114 if (event->modifiers() != Qt::ControlModifier)
1115 {
1115 {
1116 move(0.1, Qt::Horizontal);
1116 move(0.1, Qt::Horizontal);
1117 }
1117 }
1118 else
1118 else
1119 {
1119 {
1120 zoom(0.5, this->width() / 2, Qt::Horizontal);
1120 zoom(0.5, this->width() / 2, Qt::Horizontal);
1121 }
1121 }
1122 break;
1122 break;
1123 case Qt::Key_Up:
1123 case Qt::Key_Up:
1124 if (event->modifiers() != Qt::ControlModifier)
1124 if (event->modifiers() != Qt::ControlModifier)
1125 {
1125 {
1126 move(0.1, Qt::Vertical);
1126 move(0.1, Qt::Vertical);
1127 }
1127 }
1128 else
1128 else
1129 {
1129 {
1130 zoom(0.5, this->height() / 2, Qt::Vertical);
1130 zoom(0.5, this->height() / 2, Qt::Vertical);
1131 }
1131 }
1132 break;
1132 break;
1133 case Qt::Key_Down:
1133 case Qt::Key_Down:
1134 if (event->modifiers() != Qt::ControlModifier)
1134 if (event->modifiers() != Qt::ControlModifier)
1135 {
1135 {
1136 move(-0.1, Qt::Vertical);
1136 move(-0.1, Qt::Vertical);
1137 }
1137 }
1138 else
1138 else
1139 {
1139 {
1140 zoom(2, this->height() / 2, Qt::Vertical);
1140 zoom(2, this->height() / 2, Qt::Vertical);
1141 }
1141 }
1142 break;
1142 break;
1143 default:
1143 default:
1144 QWidget::keyPressEvent(event);
1144 QWidget::keyPressEvent(event);
1145 break;
1145 break;
1146 }
1146 }
1147 }
1147 }
1148
1148
1149 QCustomPlot& VisualizationGraphWidget::plot() const noexcept
1149 QCustomPlot& VisualizationGraphWidget::plot() const noexcept
1150 {
1150 {
1151 return *impl->m_plot;
1151 return *impl->m_plot;
1152 }
1152 }
1153
1153
1154 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint& pos) noexcept
1154 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint& pos) noexcept
1155 {
1155 {
1156 QMenu graphMenu {};
1156 QMenu graphMenu {};
1157
1157
1158 // Iterates on variables (unique keys)
1158 // Iterates on variables (unique keys)
1159 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
1159 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
1160 end = impl->m_VariableToPlotMultiMap.cend();
1160 end = impl->m_VariableToPlotMultiMap.cend();
1161 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first))
1161 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first))
1162 {
1162 {
1163 // 'Remove variable' action
1163 // 'Remove variable' action
1164 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
1164 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
1165 [this, var = it->first]() { removeVariable(var); });
1165 [this, var = it->first]() { removeVariable(var); });
1166 }
1166 }
1167
1167
1168 if (!impl->m_ZoomStack.isEmpty())
1168 if (!impl->m_ZoomStack.isEmpty())
1169 {
1169 {
1170 if (!graphMenu.isEmpty())
1170 if (!graphMenu.isEmpty())
1171 {
1171 {
1172 graphMenu.addSeparator();
1172 graphMenu.addSeparator();
1173 }
1173 }
1174
1174
1175 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
1175 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
1176 }
1176 }
1177
1177
1178 // Selection Zone Actions
1178 // Selection Zone Actions
1179 auto selectionZoneItem = impl->selectionZoneAt(pos);
1179 auto selectionZoneItem = impl->selectionZoneAt(pos);
1180 if (selectionZoneItem)
1180 if (selectionZoneItem)
1181 {
1181 {
1182 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
1182 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
1183 selectedItems.removeAll(selectionZoneItem);
1183 selectedItems.removeAll(selectionZoneItem);
1184 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
1184 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
1185
1185
1186 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
1186 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
1187 if (!zoneActions.isEmpty() && !graphMenu.isEmpty())
1187 if (!zoneActions.isEmpty() && !graphMenu.isEmpty())
1188 {
1188 {
1189 graphMenu.addSeparator();
1189 graphMenu.addSeparator();
1190 }
1190 }
1191
1191
1192 QHash<QString, QMenu*> subMenus;
1192 QHash<QString, QMenu*> subMenus;
1193 QHash<QString, bool> subMenusEnabled;
1193 QHash<QString, bool> subMenusEnabled;
1194 QHash<QString, FilteringAction*> filteredMenu;
1194 QHash<QString, FilteringAction*> filteredMenu;
1195
1195
1196 for (auto zoneAction : zoneActions)
1196 for (auto zoneAction : zoneActions)
1197 {
1197 {
1198
1198
1199 auto isEnabled = zoneAction->isEnabled(selectedItems);
1199 auto isEnabled = zoneAction->isEnabled(selectedItems);
1200
1200
1201 auto menu = &graphMenu;
1201 auto menu = &graphMenu;
1202 QString menuPath;
1202 QString menuPath;
1203 for (auto subMenuName : zoneAction->subMenuList())
1203 for (auto subMenuName : zoneAction->subMenuList())
1204 {
1204 {
1205 menuPath += '/';
1205 menuPath += '/';
1206 menuPath += subMenuName;
1206 menuPath += subMenuName;
1207
1207
1208 if (!subMenus.contains(menuPath))
1208 if (!subMenus.contains(menuPath))
1209 {
1209 {
1210 menu = menu->addMenu(subMenuName);
1210 menu = menu->addMenu(subMenuName);
1211 subMenus[menuPath] = menu;
1211 subMenus[menuPath] = menu;
1212 subMenusEnabled[menuPath] = isEnabled;
1212 subMenusEnabled[menuPath] = isEnabled;
1213 }
1213 }
1214 else
1214 else
1215 {
1215 {
1216 menu = subMenus.value(menuPath);
1216 menu = subMenus.value(menuPath);
1217 if (isEnabled)
1217 if (isEnabled)
1218 {
1218 {
1219 // The sub menu is enabled if at least one of its actions is enabled
1219 // The sub menu is enabled if at least one of its actions is enabled
1220 subMenusEnabled[menuPath] = true;
1220 subMenusEnabled[menuPath] = true;
1221 }
1221 }
1222 }
1222 }
1223 }
1223 }
1224
1224
1225 FilteringAction* filterAction = nullptr;
1225 FilteringAction* filterAction = nullptr;
1226 if (sqpApp->actionsGuiController().isMenuFiltered(zoneAction->subMenuList()))
1226 if (sqpApp->actionsGuiController().isMenuFiltered(zoneAction->subMenuList()))
1227 {
1227 {
1228 filterAction = filteredMenu.value(menuPath);
1228 filterAction = filteredMenu.value(menuPath);
1229 if (!filterAction)
1229 if (!filterAction)
1230 {
1230 {
1231 filterAction = new FilteringAction { this };
1231 filterAction = new FilteringAction { this };
1232 filteredMenu[menuPath] = filterAction;
1232 filteredMenu[menuPath] = filterAction;
1233 menu->addAction(filterAction);
1233 menu->addAction(filterAction);
1234 }
1234 }
1235 }
1235 }
1236
1236
1237 auto action = menu->addAction(zoneAction->name());
1237 auto action = menu->addAction(zoneAction->name());
1238 action->setEnabled(isEnabled);
1238 action->setEnabled(isEnabled);
1239 action->setShortcut(zoneAction->displayedShortcut());
1239 action->setShortcut(zoneAction->displayedShortcut());
1240 QObject::connect(action, &QAction::triggered,
1240 QObject::connect(action, &QAction::triggered,
1241 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
1241 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
1242
1242
1243 if (filterAction && zoneAction->isFilteringAllowed())
1243 if (filterAction && zoneAction->isFilteringAllowed())
1244 {
1244 {
1245 filterAction->addActionToFilter(action);
1245 filterAction->addActionToFilter(action);
1246 }
1246 }
1247 }
1247 }
1248
1248
1249 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it)
1249 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it)
1250 {
1250 {
1251 it.value()->setEnabled(subMenusEnabled[it.key()]);
1251 it.value()->setEnabled(subMenusEnabled[it.key()]);
1252 }
1252 }
1253 }
1253 }
1254
1254
1255 if (!graphMenu.isEmpty())
1255 if (!graphMenu.isEmpty())
1256 {
1256 {
1257 graphMenu.exec(QCursor::pos());
1257 graphMenu.exec(QCursor::pos());
1258 }
1258 }
1259 }
1259 }
1260
1260
1261 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent* event) noexcept
1261 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent* event) noexcept
1262 {
1262 {
1263 impl->m_RenderingDelegate->onMouseDoubleClick(event);
1263 impl->m_RenderingDelegate->onMouseDoubleClick(event);
1264 }
1264 }
1265
1265
1266 void VisualizationGraphWidget::onMouseMove(QMouseEvent* event) noexcept
1266 void VisualizationGraphWidget::onMouseMove(QMouseEvent* event) noexcept
1267 {
1267 {
1268 // Handles plot rendering when mouse is moving
1268 // Handles plot rendering when mouse is moving
1269 impl->m_RenderingDelegate->updateTooltip(event);
1269 impl->m_RenderingDelegate->updateTooltip(event);
1270
1270
1271 auto axisPos = impl->posToAxisPos(event->pos());
1271 auto axisPos = impl->posToAxisPos(event->pos());
1272
1272
1273 // Zoom box and zone drawing
1273 // Zoom box and zone drawing
1274 if (impl->m_DrawingZoomRect)
1274 if (impl->m_DrawingZoomRect)
1275 {
1275 {
1276 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
1276 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
1277 }
1277 }
1278 else if (impl->m_DrawingZone)
1278 else if (impl->m_DrawingZone)
1279 {
1279 {
1280 impl->m_DrawingZone->setEnd(axisPos.x());
1280 impl->m_DrawingZone->setEnd(axisPos.x());
1281 }
1281 }
1282
1282
1283 // Cursor
1283 // Cursor
1284 if (auto parentZone = parentZoneWidget())
1284 if (auto parentZone = parentZoneWidget())
1285 {
1285 {
1286 if (impl->pointIsInAxisRect(axisPos, plot()))
1286 if (impl->pointIsInAxisRect(axisPos, plot()))
1287 {
1287 {
1288 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
1288 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
1289 }
1289 }
1290 else
1290 else
1291 {
1291 {
1292 parentZone->notifyMouseLeaveGraph(this);
1292 parentZone->notifyMouseLeaveGraph(this);
1293 }
1293 }
1294 }
1294 }
1295
1295
1296 // Search for the selection zone under the mouse
1296 // Search for the selection zone under the mouse
1297 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos());
1297 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos());
1298 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
1298 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
1299 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones)
1299 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones)
1300 {
1300 {
1301
1301
1302 // Sets the appropriate cursor shape
1302 // Sets the appropriate cursor shape
1303 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
1303 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
1304 setCursor(cursorShape);
1304 setCursor(cursorShape);
1305
1305
1306 // Manages the hovered zone
1306 // Manages the hovered zone
1307 if (selectionZoneItemUnderCursor != impl->m_HoveredZone)
1307 if (selectionZoneItemUnderCursor != impl->m_HoveredZone)
1308 {
1308 {
1309 if (impl->m_HoveredZone)
1309 if (impl->m_HoveredZone)
1310 {
1310 {
1311 impl->m_HoveredZone->setHovered(false);
1311 impl->m_HoveredZone->setHovered(false);
1312 }
1312 }
1313 selectionZoneItemUnderCursor->setHovered(true);
1313 selectionZoneItemUnderCursor->setHovered(true);
1314 impl->m_HoveredZone = selectionZoneItemUnderCursor;
1314 impl->m_HoveredZone = selectionZoneItemUnderCursor;
1315 plot().replot(QCustomPlot::rpQueuedReplot);
1315 plot().replot(QCustomPlot::rpQueuedReplot);
1316 }
1316 }
1317 }
1317 }
1318 else
1318 else
1319 {
1319 {
1320 // There is no zone under the mouse or the interaction mode is not "selection zones"
1320 // There is no zone under the mouse or the interaction mode is not "selection zones"
1321 if (impl->m_HoveredZone)
1321 if (impl->m_HoveredZone)
1322 {
1322 {
1323 impl->m_HoveredZone->setHovered(false);
1323 impl->m_HoveredZone->setHovered(false);
1324 impl->m_HoveredZone = nullptr;
1324 impl->m_HoveredZone = nullptr;
1325 }
1325 }
1326
1326
1327 setCursor(Qt::ArrowCursor);
1327 setCursor(Qt::ArrowCursor);
1328 }
1328 }
1329
1329
1330 impl->m_HasMovedMouse = true;
1330 impl->m_HasMovedMouse = true;
1331 VisualizationDragWidget::mouseMoveEvent(event);
1331 VisualizationDragWidget::mouseMoveEvent(event);
1332 }
1332 }
1333
1333
1334 void VisualizationGraphWidget::onMouseWheel(QWheelEvent* event) noexcept
1334 void VisualizationGraphWidget::onMouseWheel(QWheelEvent* event) noexcept
1335 {
1335 {
1336 // Processes event only if the wheel occurs on axis rect
1336 // Processes event only if the wheel occurs on axis rect
1337 if (!dynamic_cast<QCPAxisRect*>(impl->m_plot->layoutElementAt(event->posF())))
1337 if (!dynamic_cast<QCPAxisRect*>(impl->m_plot->layoutElementAt(event->posF())))
1338 {
1338 {
1339 return;
1339 return;
1340 }
1340 }
1341
1341
1342 auto value = event->angleDelta().x() + event->angleDelta().y();
1342 auto value = event->angleDelta().x() + event->angleDelta().y();
1343 if (value != 0)
1343 if (value != 0)
1344 {
1344 {
1345
1345
1346 auto direction = value > 0 ? 1.0 : -1.0;
1346 auto direction = value > 0 ? 1.0 : -1.0;
1347 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
1347 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
1348 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
1348 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
1349 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
1349 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
1350
1350
1351 auto zoomOrientations = QFlags<Qt::Orientation> {};
1351 auto zoomOrientations = QFlags<Qt::Orientation> {};
1352 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
1352 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
1353 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
1353 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
1354
1354
1355 impl->m_plot->axisRect()->setRangeZoom(zoomOrientations);
1355 impl->m_plot->axisRect()->setRangeZoom(zoomOrientations);
1356
1356
1357 if (!isZoomX && !isZoomY)
1357 if (!isZoomX && !isZoomY)
1358 {
1358 {
1359 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
1359 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
1360 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
1360 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
1361
1361
1362 axis->setRange(axis->range() + diff);
1362 axis->setRange(axis->range() + diff);
1363
1363
1364 if (plot().noAntialiasingOnDrag())
1364 if (plot().noAntialiasingOnDrag())
1365 {
1365 {
1366 plot().setNotAntialiasedElements(QCP::aeAll);
1366 plot().setNotAntialiasedElements(QCP::aeAll);
1367 }
1367 }
1368
1368
1369 // plot().replot(QCustomPlot::rpQueuedReplot);
1369 // plot().replot(QCustomPlot::rpQueuedReplot);
1370 }
1370 }
1371 }
1371 }
1372 }
1372 }
1373
1373
1374 void VisualizationGraphWidget::onMousePress(QMouseEvent* event) noexcept
1374 void VisualizationGraphWidget::onMousePress(QMouseEvent* event) noexcept
1375 {
1375 {
1376 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
1376 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
1377 auto isSelectionZoneMode
1377 auto isSelectionZoneMode
1378 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
1378 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
1379 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
1379 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
1380
1380
1381 if (!isDragDropClick && isLeftClick)
1381 if (!isDragDropClick && isLeftClick)
1382 {
1382 {
1383 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox)
1383 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox)
1384 {
1384 {
1385 // Starts a zoom box
1385 // Starts a zoom box
1386 impl->startDrawingRect(event->pos());
1386 impl->startDrawingRect(event->pos());
1387 }
1387 }
1388 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr)
1388 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr)
1389 {
1389 {
1390 // Starts a new selection zone
1390 // Starts a new selection zone
1391 auto zoneAtPos = impl->selectionZoneAt(event->pos());
1391 auto zoneAtPos = impl->selectionZoneAt(event->pos());
1392 if (!zoneAtPos)
1392 if (!zoneAtPos)
1393 {
1393 {
1394 impl->startDrawingZone(event->pos());
1394 impl->startDrawingZone(event->pos());
1395 }
1395 }
1396 }
1396 }
1397 }
1397 }
1398
1398
1399
1399
1400 // Allows zone edition only in selection zone mode without drag&drop
1400 // Allows zone edition only in selection zone mode without drag&drop
1401 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
1401 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
1402
1402
1403 // Selection / Deselection
1403 // Selection / Deselection
1404 if (isSelectionZoneMode)
1404 if (isSelectionZoneMode)
1405 {
1405 {
1406 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
1406 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
1407 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos());
1407 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos());
1408
1408
1409
1409
1410 if (selectionZoneItemUnderCursor && !selectionZoneItemUnderCursor->selected()
1410 if (selectionZoneItemUnderCursor && !selectionZoneItemUnderCursor->selected()
1411 && !isMultiSelectionClick)
1411 && !isMultiSelectionClick)
1412 {
1412 {
1413 parentVisualizationWidget()->selectionZoneManager().select(
1413 parentVisualizationWidget()->selectionZoneManager().select(
1414 { selectionZoneItemUnderCursor });
1414 { selectionZoneItemUnderCursor });
1415 }
1415 }
1416 else if (!selectionZoneItemUnderCursor && !isMultiSelectionClick && isLeftClick)
1416 else if (!selectionZoneItemUnderCursor && !isMultiSelectionClick && isLeftClick)
1417 {
1417 {
1418 parentVisualizationWidget()->selectionZoneManager().clearSelection();
1418 parentVisualizationWidget()->selectionZoneManager().clearSelection();
1419 }
1419 }
1420 else
1420 else
1421 {
1421 {
1422 // No selection change
1422 // No selection change
1423 }
1423 }
1424
1424
1425 if (selectionZoneItemUnderCursor && isLeftClick)
1425 if (selectionZoneItemUnderCursor && isLeftClick)
1426 {
1426 {
1427 selectionZoneItemUnderCursor->setAssociatedEditedZones(
1427 selectionZoneItemUnderCursor->setAssociatedEditedZones(
1428 parentVisualizationWidget()->selectionZoneManager().selectedItems());
1428 parentVisualizationWidget()->selectionZoneManager().selectedItems());
1429 }
1429 }
1430 }
1430 }
1431
1431
1432
1432
1433 impl->m_HasMovedMouse = false;
1433 impl->m_HasMovedMouse = false;
1434 VisualizationDragWidget::mousePressEvent(event);
1434 VisualizationDragWidget::mousePressEvent(event);
1435 }
1435 }
1436
1436
1437 void VisualizationGraphWidget::onMouseRelease(QMouseEvent* event) noexcept
1437 void VisualizationGraphWidget::onMouseRelease(QMouseEvent* event) noexcept
1438 {
1438 {
1439 if (impl->m_DrawingZoomRect)
1439 if (impl->m_DrawingZoomRect)
1440 {
1440 {
1441
1441
1442 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
1442 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
1443 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
1443 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
1444
1444
1445 auto newAxisXRange = QCPRange { impl->m_DrawingZoomRect->topLeft->coords().x(),
1445 auto newAxisXRange = QCPRange { impl->m_DrawingZoomRect->topLeft->coords().x(),
1446 impl->m_DrawingZoomRect->bottomRight->coords().x() };
1446 impl->m_DrawingZoomRect->bottomRight->coords().x() };
1447
1447
1448 auto newAxisYRange = QCPRange { impl->m_DrawingZoomRect->topLeft->coords().y(),
1448 auto newAxisYRange = QCPRange { impl->m_DrawingZoomRect->topLeft->coords().y(),
1449 impl->m_DrawingZoomRect->bottomRight->coords().y() };
1449 impl->m_DrawingZoomRect->bottomRight->coords().y() };
1450
1450
1451 impl->removeDrawingRect();
1451 impl->removeDrawingRect();
1452
1452
1453 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
1453 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
1454 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0))
1454 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0))
1455 {
1455 {
1456 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
1456 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
1457 axisX->setRange(newAxisXRange);
1457 axisX->setRange(newAxisXRange);
1458 axisY->setRange(newAxisYRange);
1458 axisY->setRange(newAxisYRange);
1459
1459
1460 plot().replot(QCustomPlot::rpQueuedReplot);
1460 plot().replot(QCustomPlot::rpQueuedReplot);
1461 }
1461 }
1462 }
1462 }
1463
1463
1464 impl->endDrawingZone();
1464 impl->endDrawingZone();
1465
1465
1466 // Selection / Deselection
1466 // Selection / Deselection
1467 auto isSelectionZoneMode
1467 auto isSelectionZoneMode
1468 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
1468 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
1469 if (isSelectionZoneMode)
1469 if (isSelectionZoneMode)
1470 {
1470 {
1471 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
1471 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
1472 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos());
1472 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos());
1473 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton
1473 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton
1474 && !impl->m_HasMovedMouse)
1474 && !impl->m_HasMovedMouse)
1475 {
1475 {
1476
1476
1477 auto zonesUnderCursor = impl->selectionZonesAt(event->pos(), plot());
1477 auto zonesUnderCursor = impl->selectionZonesAt(event->pos(), plot());
1478 if (zonesUnderCursor.count() > 1)
1478 if (zonesUnderCursor.count() > 1)
1479 {
1479 {
1480 // There are multiple zones under the mouse.
1480 // There are multiple zones under the mouse.
1481 // Performs the selection with a selection dialog.
1481 // Performs the selection with a selection dialog.
1482 VisualizationMultiZoneSelectionDialog dialog { this };
1482 VisualizationMultiZoneSelectionDialog dialog { this };
1483 dialog.setZones(zonesUnderCursor);
1483 dialog.setZones(zonesUnderCursor);
1484 dialog.move(mapToGlobal(event->pos() - QPoint(dialog.width() / 2, 20)));
1484 dialog.move(mapToGlobal(event->pos() - QPoint(dialog.width() / 2, 20)));
1485 dialog.activateWindow();
1485 dialog.activateWindow();
1486 dialog.raise();
1486 dialog.raise();
1487 if (dialog.exec() == QDialog::Accepted)
1487 if (dialog.exec() == QDialog::Accepted)
1488 {
1488 {
1489 auto selection = dialog.selectedZones();
1489 auto selection = dialog.selectedZones();
1490
1490
1491 if (!isMultiSelectionClick)
1491 if (!isMultiSelectionClick)
1492 {
1492 {
1493 parentVisualizationWidget()->selectionZoneManager().clearSelection();
1493 parentVisualizationWidget()->selectionZoneManager().clearSelection();
1494 }
1494 }
1495
1495
1496 for (auto it = selection.cbegin(); it != selection.cend(); ++it)
1496 for (auto it = selection.cbegin(); it != selection.cend(); ++it)
1497 {
1497 {
1498 auto zone = it.key();
1498 auto zone = it.key();
1499 auto isSelected = it.value();
1499 auto isSelected = it.value();
1500 parentVisualizationWidget()->selectionZoneManager().setSelected(
1500 parentVisualizationWidget()->selectionZoneManager().setSelected(
1501 zone, isSelected);
1501 zone, isSelected);
1502
1502
1503 if (isSelected)
1503 if (isSelected)
1504 {
1504 {
1505 // Puts the zone on top of the stack so it can be moved or resized
1505 // Puts the zone on top of the stack so it can be moved or resized
1506 impl->moveSelectionZoneOnTop(zone, plot());
1506 impl->moveSelectionZoneOnTop(zone, plot());
1507 }
1507 }
1508 }
1508 }
1509 }
1509 }
1510 }
1510 }
1511 else
1511 else
1512 {
1512 {
1513 if (!isMultiSelectionClick)
1513 if (!isMultiSelectionClick)
1514 {
1514 {
1515 parentVisualizationWidget()->selectionZoneManager().select(
1515 parentVisualizationWidget()->selectionZoneManager().select(
1516 { selectionZoneItemUnderCursor });
1516 { selectionZoneItemUnderCursor });
1517 impl->moveSelectionZoneOnTop(selectionZoneItemUnderCursor, plot());
1517 impl->moveSelectionZoneOnTop(selectionZoneItemUnderCursor, plot());
1518 }
1518 }
1519 else
1519 else
1520 {
1520 {
1521 parentVisualizationWidget()->selectionZoneManager().setSelected(
1521 parentVisualizationWidget()->selectionZoneManager().setSelected(
1522 selectionZoneItemUnderCursor,
1522 selectionZoneItemUnderCursor,
1523 !selectionZoneItemUnderCursor->selected()
1523 !selectionZoneItemUnderCursor->selected()
1524 || event->button() == Qt::RightButton);
1524 || event->button() == Qt::RightButton);
1525 }
1525 }
1526 }
1526 }
1527 }
1527 }
1528 else
1528 else
1529 {
1529 {
1530 // No selection change
1530 // No selection change
1531 }
1531 }
1532 }
1532 }
1533 }
1533 }
1534
1534
1535 void VisualizationGraphWidget::onDataCacheVariableUpdated()
1535 void VisualizationGraphWidget::onDataCacheVariableUpdated()
1536 {
1536 {
1537 auto graphRange = impl->m_plot->xAxis->range();
1537 auto graphRange = impl->m_plot->xAxis->range();
1538 auto dateTime = DateTimeRange { graphRange.lower, graphRange.upper };
1538 auto dateTime = DateTimeRange { graphRange.lower, graphRange.upper };
1539
1539
1540 for (auto& variableEntry : impl->m_VariableToPlotMultiMap)
1540 for (auto& variableEntry : impl->m_VariableToPlotMultiMap)
1541 {
1541 {
1542 auto variable = variableEntry.first;
1542 auto variable = variableEntry.first;
1543 qCDebug(LOG_VisualizationGraphWidget())
1543 qCDebug(LOG_VisualizationGraphWidget())
1544 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
1544 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
1545 qCDebug(LOG_VisualizationGraphWidget())
1545 qCDebug(LOG_VisualizationGraphWidget())
1546 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
1546 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
1547 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range()))
1547 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range()))
1548 {
1548 {
1549 impl->updateData(variableEntry.second, variable, variable->range());
1549 impl->updateData(variableEntry.second, variable, variable->range());
1550 }
1550 }
1551 }
1551 }
1552 }
1552 }
1553
1553
1554 void VisualizationGraphWidget::onUpdateVarDisplaying(
1554 void VisualizationGraphWidget::onUpdateVarDisplaying(
1555 std::shared_ptr<Variable2> variable, const DateTimeRange& range)
1555 std::shared_ptr<Variable2> variable, const DateTimeRange& range)
1556 {
1556 {
1557 auto it = impl->m_VariableToPlotMultiMap.find(variable);
1557 auto it = impl->m_VariableToPlotMultiMap.find(variable);
1558 if (it != impl->m_VariableToPlotMultiMap.end())
1558 if (it != impl->m_VariableToPlotMultiMap.end())
1559 {
1559 {
1560 impl->updateData(it->second, variable, range);
1560 impl->updateData(it->second, variable, range);
1561 }
1561 }
1562 }
1562 }
1563
1563
1564 void VisualizationGraphWidget::variableUpdated(QUuid id)
1564 void VisualizationGraphWidget::variableUpdated(QUuid id)
1565 {
1565 {
1566 for (auto& [var, plotables] : impl->m_VariableToPlotMultiMap)
1566 for (auto& [var, plotables] : impl->m_VariableToPlotMultiMap)
1567 {
1567 {
1568 if (var->ID() == id)
1568 if (var->ID() == id)
1569 {
1569 {
1570 impl->updateData(plotables, var, this->graphRange());
1570 impl->updateData(plotables, var, this->graphRange());
1571 }
1571 }
1572 }
1572 }
1573 }
1573 }
1574
1574
1575 void VisualizationGraphWidget::variableDeleted(const std::shared_ptr<Variable2>& variable)
1575 void VisualizationGraphWidget::variableDeleted(const std::shared_ptr<Variable2>& variable)
1576 {
1576 {
1577 this->removeVariable(variable);
1577 this->removeVariable(variable);
1578 }
1578 }
@@ -1,415 +1,415
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/datasources.h"
11 #include "Variable/VariableController2.h"
11 #include "Variable/VariableController2.h"
12
12
13 #include "Common/MimeTypesDef.h"
13 #include "MimeTypes/MimeTypes.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 /**
23 /**
24 * Applies a function to all zones of the tab represented by its layout
24 * Applies a function to all zones of the tab represented by its layout
25 * @param layout the layout that contains zones
25 * @param layout the layout that contains zones
26 * @param fun the function to apply to each zone
26 * @param fun the function to apply to each zone
27 */
27 */
28 template <typename Fun>
28 template <typename Fun>
29 void processZones(QLayout& layout, Fun fun)
29 void processZones(QLayout& layout, Fun fun)
30 {
30 {
31 for (auto i = 0; i < layout.count(); ++i)
31 for (auto i = 0; i < layout.count(); ++i)
32 {
32 {
33 if (auto item = layout.itemAt(i))
33 if (auto item = layout.itemAt(i))
34 {
34 {
35 if (auto visualizationZoneWidget
35 if (auto visualizationZoneWidget
36 = qobject_cast<VisualizationZoneWidget*>(item->widget()))
36 = qobject_cast<VisualizationZoneWidget*>(item->widget()))
37 {
37 {
38 fun(*visualizationZoneWidget);
38 fun(*visualizationZoneWidget);
39 }
39 }
40 }
40 }
41 }
41 }
42 }
42 }
43
43
44 /// Generates a default name for a new zone, according to the number of zones already displayed in
44 /// Generates a default name for a new zone, according to the number of zones already displayed in
45 /// the tab
45 /// the tab
46 QString defaultZoneName(QLayout& layout)
46 QString defaultZoneName(QLayout& layout)
47 {
47 {
48 QSet<QString> existingNames;
48 QSet<QString> existingNames;
49 processZones(
49 processZones(
50 layout, [&existingNames](auto& zoneWidget) { existingNames.insert(zoneWidget.name()); });
50 layout, [&existingNames](auto& zoneWidget) { existingNames.insert(zoneWidget.name()); });
51
51
52 int zoneNum = 1;
52 int zoneNum = 1;
53 QString name;
53 QString name;
54 do
54 do
55 {
55 {
56 name = QObject::tr("Zone ").append(QString::number(zoneNum));
56 name = QObject::tr("Zone ").append(QString::number(zoneNum));
57 ++zoneNum;
57 ++zoneNum;
58 } while (existingNames.contains(name));
58 } while (existingNames.contains(name));
59
59
60 return name;
60 return name;
61 }
61 }
62
62
63 } // namespace
63 } // namespace
64
64
65 struct VisualizationTabWidget::VisualizationTabWidgetPrivate
65 struct VisualizationTabWidget::VisualizationTabWidgetPrivate
66 {
66 {
67 explicit VisualizationTabWidgetPrivate(const QString& name) : m_Name { name } {}
67 explicit VisualizationTabWidgetPrivate(const QString& name) : m_Name { name } {}
68
68
69 QString m_Name;
69 QString m_Name;
70
70
71 #ifdef Q_OS_MAC
71 #ifdef Q_OS_MAC
72 std::unique_ptr<MacScrollBarStyle> m_MacScrollBarStyle = std::make_unique<MacScrollBarStyle>();
72 std::unique_ptr<MacScrollBarStyle> m_MacScrollBarStyle = std::make_unique<MacScrollBarStyle>();
73 #endif
73 #endif
74
74
75 void dropGraph(int index, VisualizationTabWidget* tabWidget);
75 void dropGraph(int index, VisualizationTabWidget* tabWidget);
76 void dropZone(int index, VisualizationTabWidget* tabWidget);
76 void dropZone(int index, VisualizationTabWidget* tabWidget);
77 void dropVariables(const std::vector<std::shared_ptr<Variable2>>& variables, int index,
77 void dropVariables(const std::vector<std::shared_ptr<Variable2>>& variables, int index,
78 VisualizationTabWidget* tabWidget);
78 VisualizationTabWidget* tabWidget);
79 void dropProducts(
79 void dropProducts(
80 const QVariantList& productsMetaData, int index, VisualizationTabWidget* tabWidget);
80 const QVariantList& productsMetaData, int index, VisualizationTabWidget* tabWidget);
81 };
81 };
82
82
83 VisualizationTabWidget::VisualizationTabWidget(const QString& name, QWidget* parent)
83 VisualizationTabWidget::VisualizationTabWidget(const QString& name, QWidget* parent)
84 : QWidget { parent }
84 : QWidget { parent }
85 , ui { new Ui::VisualizationTabWidget }
85 , ui { new Ui::VisualizationTabWidget }
86 , impl { spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name) }
86 , impl { spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name) }
87 {
87 {
88 ui->setupUi(this);
88 ui->setupUi(this);
89
89
90 #ifdef Q_OS_MAC
90 #ifdef Q_OS_MAC
91 impl->m_MacScrollBarStyle->selfInstallOn(ui->scrollArea, true);
91 impl->m_MacScrollBarStyle->selfInstallOn(ui->scrollArea, true);
92 #endif
92 #endif
93
93
94 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Zone, "Zone");
94 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Zone, "Zone");
95 ui->dragDropContainer->layout()->setContentsMargins(0, 0, 0, 12);
95 ui->dragDropContainer->layout()->setContentsMargins(0, 0, 0, 12);
96 ui->dragDropContainer->layout()->setSpacing(0);
96 ui->dragDropContainer->layout()->setSpacing(0);
97 ui->dragDropContainer->setMimeType(
97 ui->dragDropContainer->setMimeType(
98 MIME_TYPE_GRAPH, VisualizationDragDropContainer::DropBehavior::Inserted);
98 MIME::MIME_TYPE_GRAPH, VisualizationDragDropContainer::DropBehavior::Inserted);
99 ui->dragDropContainer->setMimeType(
99 ui->dragDropContainer->setMimeType(
100 MIME_TYPE_ZONE, VisualizationDragDropContainer::DropBehavior::Inserted);
100 MIME::MIME_TYPE_ZONE, VisualizationDragDropContainer::DropBehavior::Inserted);
101 ui->dragDropContainer->setMimeType(
101 ui->dragDropContainer->setMimeType(
102 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::Inserted);
102 MIME::MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::Inserted);
103 ui->dragDropContainer->setMimeType(
103 ui->dragDropContainer->setMimeType(
104 MIME_TYPE_PRODUCT_LIST, VisualizationDragDropContainer::DropBehavior::Inserted);
104 MIME::MIME_TYPE_PRODUCT_LIST, VisualizationDragDropContainer::DropBehavior::Inserted);
105
105
106 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
106 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
107 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(
107 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(
108 mimeData, ui->dragDropContainer);
108 mimeData, ui->dragDropContainer);
109 });
109 });
110
110
111 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
111 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
112 &VisualizationTabWidget::dropMimeData);
112 &VisualizationTabWidget::dropMimeData);
113
113
114 sqpApp->dragDropGuiController().addDragDropScrollArea(ui->scrollArea);
114 sqpApp->dragDropGuiController().addDragDropScrollArea(ui->scrollArea);
115
115
116 // Widget is deleted when closed
116 // Widget is deleted when closed
117 setAttribute(Qt::WA_DeleteOnClose);
117 setAttribute(Qt::WA_DeleteOnClose);
118 }
118 }
119
119
120 VisualizationTabWidget::~VisualizationTabWidget()
120 VisualizationTabWidget::~VisualizationTabWidget()
121 {
121 {
122 sqpApp->dragDropGuiController().removeDragDropScrollArea(ui->scrollArea);
122 sqpApp->dragDropGuiController().removeDragDropScrollArea(ui->scrollArea);
123 delete ui;
123 delete ui;
124 }
124 }
125
125
126 void VisualizationTabWidget::addZone(VisualizationZoneWidget* zoneWidget)
126 void VisualizationTabWidget::addZone(VisualizationZoneWidget* zoneWidget)
127 {
127 {
128 ui->dragDropContainer->addDragWidget(zoneWidget);
128 ui->dragDropContainer->addDragWidget(zoneWidget);
129 }
129 }
130
130
131 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget* zoneWidget)
131 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget* zoneWidget)
132 {
132 {
133 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
133 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
134 }
134 }
135
135
136 QStringList VisualizationTabWidget::availableZoneWidgets() const
136 QStringList VisualizationTabWidget::availableZoneWidgets() const
137 {
137 {
138 QStringList zones;
138 QStringList zones;
139 processZones(
139 processZones(
140 tabLayout(), [&zones](VisualizationZoneWidget& zoneWidget) { zones << zoneWidget.name(); });
140 tabLayout(), [&zones](VisualizationZoneWidget& zoneWidget) { zones << zoneWidget.name(); });
141
141
142 return zones;
142 return zones;
143 }
143 }
144
144
145 VisualizationZoneWidget* VisualizationTabWidget::getZoneWithName(const QString& zoneName)
145 VisualizationZoneWidget* VisualizationTabWidget::getZoneWithName(const QString& zoneName)
146 {
146 {
147 VisualizationZoneWidget* result = nullptr;
147 VisualizationZoneWidget* result = nullptr;
148 processZones(tabLayout(), [&zoneName, &result](VisualizationZoneWidget& zoneWidget) {
148 processZones(tabLayout(), [&zoneName, &result](VisualizationZoneWidget& zoneWidget) {
149 if (!result && zoneWidget.name() == zoneName)
149 if (!result && zoneWidget.name() == zoneName)
150 {
150 {
151 result = &zoneWidget;
151 result = &zoneWidget;
152 }
152 }
153 });
153 });
154
154
155 return result;
155 return result;
156 }
156 }
157
157
158 VisualizationZoneWidget* VisualizationTabWidget::createZone(std::shared_ptr<Variable2> variable)
158 VisualizationZoneWidget* VisualizationTabWidget::createZone(std::shared_ptr<Variable2> variable)
159 {
159 {
160 return createZone({ variable }, -1);
160 return createZone({ variable }, -1);
161 }
161 }
162
162
163 VisualizationZoneWidget* VisualizationTabWidget::createZone(
163 VisualizationZoneWidget* VisualizationTabWidget::createZone(
164 const std::vector<std::shared_ptr<Variable2>>& variables, int index)
164 const std::vector<std::shared_ptr<Variable2>>& variables, int index)
165 {
165 {
166 auto zoneWidget = createEmptyZone(index);
166 auto zoneWidget = createEmptyZone(index);
167
167
168 // Creates a new graph into the zone
168 // Creates a new graph into the zone
169 zoneWidget->createGraph(variables, index);
169 zoneWidget->createGraph(variables, index);
170
170
171 return zoneWidget;
171 return zoneWidget;
172 }
172 }
173
173
174 VisualizationZoneWidget* VisualizationTabWidget::createEmptyZone(int index)
174 VisualizationZoneWidget* VisualizationTabWidget::createEmptyZone(int index)
175 {
175 {
176 auto zoneWidget
176 auto zoneWidget
177 = new VisualizationZoneWidget { defaultZoneName(*ui->dragDropContainer->layout()), this };
177 = new VisualizationZoneWidget { defaultZoneName(*ui->dragDropContainer->layout()), this };
178 this->insertZone(index, zoneWidget);
178 this->insertZone(index, zoneWidget);
179
179
180 return zoneWidget;
180 return zoneWidget;
181 }
181 }
182
182
183 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor* visitor)
183 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor* visitor)
184 {
184 {
185 if (visitor)
185 if (visitor)
186 {
186 {
187 visitor->visitEnter(this);
187 visitor->visitEnter(this);
188
188
189 // Apply visitor to zone children: widgets different from zones are not visited (no action)
189 // Apply visitor to zone children: widgets different from zones are not visited (no action)
190 processZones(tabLayout(),
190 processZones(tabLayout(),
191 [visitor](VisualizationZoneWidget& zoneWidget) { zoneWidget.accept(visitor); });
191 [visitor](VisualizationZoneWidget& zoneWidget) { zoneWidget.accept(visitor); });
192
192
193 visitor->visitLeave(this);
193 visitor->visitLeave(this);
194 }
194 }
195 else
195 else
196 {
196 {
197 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
197 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
198 }
198 }
199 }
199 }
200
200
201 bool VisualizationTabWidget::canDrop(Variable2& variable) const
201 bool VisualizationTabWidget::canDrop(Variable2& variable) const
202 {
202 {
203 // A tab can always accomodate a variable
203 // A tab can always accomodate a variable
204 Q_UNUSED(variable);
204 Q_UNUSED(variable);
205 return true;
205 return true;
206 }
206 }
207
207
208 bool VisualizationTabWidget::contains(Variable2& variable) const
208 bool VisualizationTabWidget::contains(Variable2& variable) const
209 {
209 {
210 Q_UNUSED(variable);
210 Q_UNUSED(variable);
211 return false;
211 return false;
212 }
212 }
213
213
214 QString VisualizationTabWidget::name() const
214 QString VisualizationTabWidget::name() const
215 {
215 {
216 return impl->m_Name;
216 return impl->m_Name;
217 }
217 }
218
218
219 void VisualizationTabWidget::closeEvent(QCloseEvent* event)
219 void VisualizationTabWidget::closeEvent(QCloseEvent* event)
220 {
220 {
221 // Closes zones in the tab
221 // Closes zones in the tab
222 processZones(tabLayout(), [](VisualizationZoneWidget& zoneWidget) { zoneWidget.close(); });
222 processZones(tabLayout(), [](VisualizationZoneWidget& zoneWidget) { zoneWidget.close(); });
223
223
224 QWidget::closeEvent(event);
224 QWidget::closeEvent(event);
225 }
225 }
226
226
227 QLayout& VisualizationTabWidget::tabLayout() const noexcept
227 QLayout& VisualizationTabWidget::tabLayout() const noexcept
228 {
228 {
229 return *ui->dragDropContainer->layout();
229 return *ui->dragDropContainer->layout();
230 }
230 }
231
231
232 void VisualizationTabWidget::dropMimeData(int index, const QMimeData* mimeData)
232 void VisualizationTabWidget::dropMimeData(int index, const QMimeData* mimeData)
233 {
233 {
234 if (mimeData->hasFormat(MIME_TYPE_GRAPH))
234 if (mimeData->hasFormat(MIME::MIME_TYPE_GRAPH))
235 {
235 {
236 impl->dropGraph(index, this);
236 impl->dropGraph(index, this);
237 }
237 }
238 else if (mimeData->hasFormat(MIME_TYPE_ZONE))
238 else if (mimeData->hasFormat(MIME::MIME_TYPE_ZONE))
239 {
239 {
240 impl->dropZone(index, this);
240 impl->dropZone(index, this);
241 }
241 }
242 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST))
242 else if (mimeData->hasFormat(MIME::MIME_TYPE_VARIABLE_LIST))
243 {
243 {
244 auto variables = sqpApp->variableController().variables(
244 auto variables = sqpApp->variableController().variables(
245 Variable2::IDs(mimeData->data(MIME_TYPE_VARIABLE_LIST)));
245 Variable2::IDs(mimeData->data(MIME::MIME_TYPE_VARIABLE_LIST)));
246 impl->dropVariables(variables, index, this);
246 impl->dropVariables(variables, index, this);
247 }
247 }
248 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST))
248 else if (mimeData->hasFormat(MIME::MIME_TYPE_PRODUCT_LIST))
249 {
249 {
250 auto productsData = sqpApp->dataSourceController().productsDataForMimeData(
250 auto productsData = MIME::decode(
251 mimeData->data(MIME_TYPE_PRODUCT_LIST));
251 mimeData->data(MIME::MIME_TYPE_PRODUCT_LIST));
252 impl->dropProducts(productsData, index, this);
252 impl->dropProducts(productsData, index, this);
253 }
253 }
254 else
254 else
255 {
255 {
256 qCWarning(LOG_VisualizationZoneWidget())
256 qCWarning(LOG_VisualizationZoneWidget())
257 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
257 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
258 }
258 }
259 }
259 }
260
260
261 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph(
261 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph(
262 int index, VisualizationTabWidget* tabWidget)
262 int index, VisualizationTabWidget* tabWidget)
263 {
263 {
264 auto& helper = sqpApp->dragDropGuiController();
264 auto& helper = sqpApp->dragDropGuiController();
265
265
266 auto graphWidget = qobject_cast<VisualizationGraphWidget*>(helper.getCurrentDragWidget());
266 auto graphWidget = qobject_cast<VisualizationGraphWidget*>(helper.getCurrentDragWidget());
267 if (!graphWidget)
267 if (!graphWidget)
268 {
268 {
269 qCWarning(LOG_VisualizationZoneWidget())
269 qCWarning(LOG_VisualizationZoneWidget())
270 << tr("VisualizationTabWidget::dropGraph, drop aborted, the dropped graph is not "
270 << tr("VisualizationTabWidget::dropGraph, drop aborted, the dropped graph is not "
271 "found or invalid.");
271 "found or invalid.");
272 Q_ASSERT(false);
272 Q_ASSERT(false);
273 return;
273 return;
274 }
274 }
275
275
276 auto parentDragDropContainer
276 auto parentDragDropContainer
277 = qobject_cast<VisualizationDragDropContainer*>(graphWidget->parentWidget());
277 = qobject_cast<VisualizationDragDropContainer*>(graphWidget->parentWidget());
278 if (!parentDragDropContainer)
278 if (!parentDragDropContainer)
279 {
279 {
280 qCWarning(LOG_VisualizationZoneWidget())
280 qCWarning(LOG_VisualizationZoneWidget())
281 << tr("VisualizationTabWidget::dropGraph, drop aborted, the parent container of "
281 << tr("VisualizationTabWidget::dropGraph, drop aborted, the parent container of "
282 "the dropped graph is not found.");
282 "the dropped graph is not found.");
283 Q_ASSERT(false);
283 Q_ASSERT(false);
284 return;
284 return;
285 }
285 }
286
286
287 auto nbGraph = parentDragDropContainer->countDragWidget();
287 auto nbGraph = parentDragDropContainer->countDragWidget();
288
288
289 const auto& variables = graphWidget->variables();
289 const auto& variables = graphWidget->variables();
290
290
291 if (!variables.empty())
291 if (!variables.empty())
292 {
292 {
293 // Abort the requests for the variables (if any)
293 // Abort the requests for the variables (if any)
294 // Commented, because it's not sure if it's needed or not
294 // Commented, because it's not sure if it's needed or not
295 // for (const auto& var : variables)
295 // for (const auto& var : variables)
296 //{
296 //{
297 // sqpApp->variableController().onAbortProgressRequested(var);
297 // sqpApp->variableController().onAbortProgressRequested(var);
298 //}
298 //}
299
299
300 if (nbGraph == 1)
300 if (nbGraph == 1)
301 {
301 {
302 // This is the only graph in the previous zone, close the zone
302 // This is the only graph in the previous zone, close the zone
303 helper.delayedCloseWidget(graphWidget->parentZoneWidget());
303 helper.delayedCloseWidget(graphWidget->parentZoneWidget());
304 }
304 }
305 else
305 else
306 {
306 {
307 // Close the graph
307 // Close the graph
308 helper.delayedCloseWidget(graphWidget);
308 helper.delayedCloseWidget(graphWidget);
309 }
309 }
310
310
311 auto zoneWidget = tabWidget->createZone(variables, index);
311 auto zoneWidget = tabWidget->createZone(variables, index);
312 auto firstGraph = zoneWidget->firstGraph();
312 auto firstGraph = zoneWidget->firstGraph();
313 if (firstGraph)
313 if (firstGraph)
314 {
314 {
315 firstGraph->addSelectionZones(graphWidget->selectionZoneRanges());
315 firstGraph->addSelectionZones(graphWidget->selectionZoneRanges());
316 }
316 }
317 else
317 else
318 {
318 {
319 qCWarning(LOG_VisualizationZoneWidget())
319 qCWarning(LOG_VisualizationZoneWidget())
320 << tr("VisualizationTabWidget::dropGraph, no graph added in the widget.");
320 << tr("VisualizationTabWidget::dropGraph, no graph added in the widget.");
321 Q_ASSERT(false);
321 Q_ASSERT(false);
322 }
322 }
323 }
323 }
324 else
324 else
325 {
325 {
326 // The graph is empty, create an empty zone and move the graph inside
326 // The graph is empty, create an empty zone and move the graph inside
327
327
328 auto parentZoneWidget = graphWidget->parentZoneWidget();
328 auto parentZoneWidget = graphWidget->parentZoneWidget();
329
329
330 parentDragDropContainer->layout()->removeWidget(graphWidget);
330 parentDragDropContainer->layout()->removeWidget(graphWidget);
331
331
332 auto zoneWidget = tabWidget->createEmptyZone(index);
332 auto zoneWidget = tabWidget->createEmptyZone(index);
333 zoneWidget->addGraph(graphWidget);
333 zoneWidget->addGraph(graphWidget);
334
334
335 // Close the old zone if it was the only graph inside
335 // Close the old zone if it was the only graph inside
336 if (nbGraph == 1)
336 if (nbGraph == 1)
337 {
337 {
338 helper.delayedCloseWidget(parentZoneWidget);
338 helper.delayedCloseWidget(parentZoneWidget);
339 }
339 }
340 }
340 }
341 }
341 }
342
342
343 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropZone(
343 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropZone(
344 int index, VisualizationTabWidget* tabWidget)
344 int index, VisualizationTabWidget* tabWidget)
345 {
345 {
346 auto& helper = sqpApp->dragDropGuiController();
346 auto& helper = sqpApp->dragDropGuiController();
347
347
348 auto zoneWidget = qobject_cast<VisualizationZoneWidget*>(helper.getCurrentDragWidget());
348 auto zoneWidget = qobject_cast<VisualizationZoneWidget*>(helper.getCurrentDragWidget());
349 if (!zoneWidget)
349 if (!zoneWidget)
350 {
350 {
351 qCWarning(LOG_VisualizationZoneWidget())
351 qCWarning(LOG_VisualizationZoneWidget())
352 << tr("VisualizationTabWidget::dropZone, drop aborted, the dropped zone is not "
352 << tr("VisualizationTabWidget::dropZone, drop aborted, the dropped zone is not "
353 "found or invalid.");
353 "found or invalid.");
354 Q_ASSERT(false);
354 Q_ASSERT(false);
355 return;
355 return;
356 }
356 }
357
357
358 auto parentDragDropContainer
358 auto parentDragDropContainer
359 = qobject_cast<VisualizationDragDropContainer*>(zoneWidget->parentWidget());
359 = qobject_cast<VisualizationDragDropContainer*>(zoneWidget->parentWidget());
360 if (!parentDragDropContainer)
360 if (!parentDragDropContainer)
361 {
361 {
362 qCWarning(LOG_VisualizationZoneWidget())
362 qCWarning(LOG_VisualizationZoneWidget())
363 << tr("VisualizationTabWidget::dropZone, drop aborted, the parent container of "
363 << tr("VisualizationTabWidget::dropZone, drop aborted, the parent container of "
364 "the dropped zone is not found.");
364 "the dropped zone is not found.");
365 Q_ASSERT(false);
365 Q_ASSERT(false);
366 return;
366 return;
367 }
367 }
368
368
369 // Simple move of the zone, no variable operation associated
369 // Simple move of the zone, no variable operation associated
370 parentDragDropContainer->layout()->removeWidget(zoneWidget);
370 parentDragDropContainer->layout()->removeWidget(zoneWidget);
371 tabWidget->ui->dragDropContainer->insertDragWidget(index, zoneWidget);
371 tabWidget->ui->dragDropContainer->insertDragWidget(index, zoneWidget);
372 }
372 }
373
373
374 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables(
374 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables(
375 const std::vector<std::shared_ptr<Variable2>>& variables, int index,
375 const std::vector<std::shared_ptr<Variable2>>& variables, int index,
376 VisualizationTabWidget* tabWidget)
376 VisualizationTabWidget* tabWidget)
377 {
377 {
378 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
378 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
379 // compatible variable here
379 // compatible variable here
380 if (variables.size() > 1)
380 if (variables.size() > 1)
381 {
381 {
382 qCWarning(LOG_VisualizationZoneWidget())
382 qCWarning(LOG_VisualizationZoneWidget())
383 << tr("VisualizationTabWidget::dropVariables, dropping multiple variables, operation "
383 << tr("VisualizationTabWidget::dropVariables, dropping multiple variables, operation "
384 "aborted.");
384 "aborted.");
385 return;
385 return;
386 }
386 }
387
387
388 tabWidget->createZone(variables, index);
388 tabWidget->createZone(variables, index);
389 }
389 }
390
390
391 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropProducts(
391 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropProducts(
392 const QVariantList& productsMetaData, int index, VisualizationTabWidget* tabWidget)
392 const QVariantList& productsMetaData, int index, VisualizationTabWidget* tabWidget)
393 {
393 {
394 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
394 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
395 // compatible variable here
395 // compatible variable here
396 if (productsMetaData.count() != 1)
396 if (productsMetaData.count() != 1)
397 {
397 {
398 qCWarning(LOG_VisualizationZoneWidget())
398 qCWarning(LOG_VisualizationZoneWidget())
399 << tr("VisualizationTabWidget::dropProducts, dropping multiple products, operation "
399 << tr("VisualizationTabWidget::dropProducts, dropping multiple products, operation "
400 "aborted.");
400 "aborted.");
401 return;
401 return;
402 }
402 }
403
403
404 auto context = new QObject { tabWidget };
404 auto context = new QObject { tabWidget };
405 connect(&sqpApp->variableController(), &VariableController2::variableAdded, context,
405 connect(&sqpApp->variableController(), &VariableController2::variableAdded, context,
406 [this, index, tabWidget, context](auto variable) {
406 [this, index, tabWidget, context](auto variable) {
407 tabWidget->createZone({ variable }, index);
407 tabWidget->createZone({ variable }, index);
408 delete context; // removes the connection
408 delete context; // removes the connection
409 },
409 },
410 Qt::QueuedConnection);
410 Qt::QueuedConnection);
411
411
412 auto productData = productsMetaData.first().toHash();
412 auto productPath = productsMetaData.first().toString();
413 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
413 QMetaObject::invokeMethod(&sqpApp->dataSources(), "createVariable",
414 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
414 Qt::QueuedConnection, Q_ARG(QString, productPath));
415 }
415 }
@@ -1,695 +1,695
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 "MimeTypes/MimeTypes.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 <Data/DateTimeRangeHelper.h>
14 #include <DataSource/DataSourceController.h>
14 #include <DataSource/datasources.h>
15 #include <Time/TimeController.h>
15 #include <Time/TimeController.h>
16 #include <Variable/Variable2.h>
16 #include <Variable/Variable2.h>
17 #include <Variable/VariableController2.h>
17 #include <Variable/VariableController2.h>
18
18
19 #include <Visualization/operations/FindVariableOperation.h>
19 #include <Visualization/operations/FindVariableOperation.h>
20
20
21 #include <DragAndDrop/DragDropGuiController.h>
21 #include <DragAndDrop/DragDropGuiController.h>
22 #include <QUuid>
22 #include <QUuid>
23 #include <SqpApplication.h>
23 #include <SqpApplication.h>
24 #include <cmath>
24 #include <cmath>
25
25
26 #include <QLayout>
26 #include <QLayout>
27 #include <QStyle>
27 #include <QStyle>
28
28
29 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
29 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
30
30
31 namespace
31 namespace
32 {
32 {
33
33
34 /**
34 /**
35 * Applies a function to all graphs of the zone represented by its layout
35 * Applies a function to all graphs of the zone represented by its layout
36 * @param layout the layout that contains graphs
36 * @param layout the layout that contains graphs
37 * @param fun the function to apply to each graph
37 * @param fun the function to apply to each graph
38 */
38 */
39 template <typename Fun>
39 template <typename Fun>
40 void processGraphs(QLayout& layout, Fun fun)
40 void processGraphs(QLayout& layout, Fun fun)
41 {
41 {
42 for (auto i = 0; i < layout.count(); ++i)
42 for (auto i = 0; i < layout.count(); ++i)
43 {
43 {
44 if (auto item = layout.itemAt(i))
44 if (auto item = layout.itemAt(i))
45 {
45 {
46 if (auto visualizationGraphWidget
46 if (auto visualizationGraphWidget
47 = qobject_cast<VisualizationGraphWidget*>(item->widget()))
47 = qobject_cast<VisualizationGraphWidget*>(item->widget()))
48 {
48 {
49 fun(*visualizationGraphWidget);
49 fun(*visualizationGraphWidget);
50 }
50 }
51 }
51 }
52 }
52 }
53 }
53 }
54
54
55 /// Generates a default name for a new graph, according to the number of graphs already displayed in
55 /// Generates a default name for a new graph, according to the number of graphs already displayed in
56 /// the zone
56 /// the zone
57 QString defaultGraphName(QLayout& layout)
57 QString defaultGraphName(QLayout& layout)
58 {
58 {
59 QSet<QString> existingNames;
59 QSet<QString> existingNames;
60 processGraphs(
60 processGraphs(
61 layout, [&existingNames](auto& graphWidget) { existingNames.insert(graphWidget.name()); });
61 layout, [&existingNames](auto& graphWidget) { existingNames.insert(graphWidget.name()); });
62
62
63 int zoneNum = 1;
63 int zoneNum = 1;
64 QString name;
64 QString name;
65 do
65 do
66 {
66 {
67 name = QObject::tr("Graph ").append(QString::number(zoneNum));
67 name = QObject::tr("Graph ").append(QString::number(zoneNum));
68 ++zoneNum;
68 ++zoneNum;
69 } while (existingNames.contains(name));
69 } while (existingNames.contains(name));
70
70
71 return name;
71 return name;
72 }
72 }
73
73
74 } // namespace
74 } // namespace
75
75
76 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate
76 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate
77 {
77 {
78
78
79 explicit VisualizationZoneWidgetPrivate()
79 explicit VisualizationZoneWidgetPrivate()
80 : m_SynchronisationGroupId { QUuid::createUuid() }
80 : m_SynchronisationGroupId { QUuid::createUuid() }
81 , m_Synchronizer { std::make_unique<QCustomPlotSynchronizer>() }
81 , m_Synchronizer { std::make_unique<QCustomPlotSynchronizer>() }
82 {
82 {
83 }
83 }
84 QUuid m_SynchronisationGroupId;
84 QUuid m_SynchronisationGroupId;
85 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
85 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
86
86
87 void dropGraph(int index, VisualizationZoneWidget* zoneWidget);
87 void dropGraph(int index, VisualizationZoneWidget* zoneWidget);
88 void dropVariables(const std::vector<std::shared_ptr<Variable2>>& variables, int index,
88 void dropVariables(const std::vector<std::shared_ptr<Variable2>>& variables, int index,
89 VisualizationZoneWidget* zoneWidget);
89 VisualizationZoneWidget* zoneWidget);
90 void dropProducts(
90 void dropProducts(
91 const QVariantList& productsData, int index, VisualizationZoneWidget* zoneWidget);
91 const QVariantList& productsData, int index, VisualizationZoneWidget* zoneWidget);
92 };
92 };
93
93
94 VisualizationZoneWidget::VisualizationZoneWidget(const QString& name, QWidget* parent)
94 VisualizationZoneWidget::VisualizationZoneWidget(const QString& name, QWidget* parent)
95 : VisualizationDragWidget { parent }
95 : VisualizationDragWidget { parent }
96 , ui { new Ui::VisualizationZoneWidget }
96 , ui { new Ui::VisualizationZoneWidget }
97 , impl { spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>() }
97 , impl { spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>() }
98 {
98 {
99 ui->setupUi(this);
99 ui->setupUi(this);
100
100
101 ui->zoneNameLabel->setText(name);
101 ui->zoneNameLabel->setText(name);
102
102
103 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Graph);
103 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Graph);
104 ui->dragDropContainer->setMimeType(
104 ui->dragDropContainer->setMimeType(
105 MIME_TYPE_GRAPH, VisualizationDragDropContainer::DropBehavior::Inserted);
105 MIME::MIME_TYPE_GRAPH, VisualizationDragDropContainer::DropBehavior::Inserted);
106 ui->dragDropContainer->setMimeType(
106 ui->dragDropContainer->setMimeType(
107 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
107 MIME::MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
108 ui->dragDropContainer->setMimeType(
108 ui->dragDropContainer->setMimeType(
109 MIME_TYPE_PRODUCT_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
109 MIME::MIME_TYPE_PRODUCT_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
110 ui->dragDropContainer->setMimeType(
110 ui->dragDropContainer->setMimeType(
111 MIME_TYPE_TIME_RANGE, VisualizationDragDropContainer::DropBehavior::Merged);
111 MIME::MIME_TYPE_TIME_RANGE, VisualizationDragDropContainer::DropBehavior::Merged);
112 ui->dragDropContainer->setMimeType(
112 ui->dragDropContainer->setMimeType(
113 MIME_TYPE_ZONE, VisualizationDragDropContainer::DropBehavior::Forbidden);
113 MIME::MIME_TYPE_ZONE, VisualizationDragDropContainer::DropBehavior::Forbidden);
114 ui->dragDropContainer->setMimeType(
114 ui->dragDropContainer->setMimeType(
115 MIME_TYPE_SELECTION_ZONE, VisualizationDragDropContainer::DropBehavior::Forbidden);
115 MIME::MIME_TYPE_SELECTION_ZONE, VisualizationDragDropContainer::DropBehavior::Forbidden);
116 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
116 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
117 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(
117 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(
118 mimeData, ui->dragDropContainer);
118 mimeData, ui->dragDropContainer);
119 });
119 });
120
120
121 auto acceptDragWidgetFun = [](auto dragWidget, auto mimeData) {
121 auto acceptDragWidgetFun = [](auto dragWidget, auto mimeData) {
122 if (!mimeData)
122 if (!mimeData)
123 {
123 {
124 return false;
124 return false;
125 }
125 }
126
126
127 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST))
127 if (mimeData->hasFormat(MIME::MIME_TYPE_VARIABLE_LIST))
128 {
128 {
129 auto variables = sqpApp->variableController().variables(
129 auto variables = sqpApp->variableController().variables(
130 Variable2::IDs(mimeData->data(MIME_TYPE_VARIABLE_LIST)));
130 Variable2::IDs(mimeData->data(MIME::MIME_TYPE_VARIABLE_LIST)));
131
131
132 if (variables.size() != 1)
132 if (variables.size() != 1)
133 {
133 {
134 return false;
134 return false;
135 }
135 }
136 auto variable = variables.front();
136 auto variable = variables.front();
137
137
138 if (auto graphWidget = dynamic_cast<const VisualizationGraphWidget*>(dragWidget))
138 if (auto graphWidget = dynamic_cast<const VisualizationGraphWidget*>(dragWidget))
139 {
139 {
140 return graphWidget->canDrop(*variable);
140 return graphWidget->canDrop(*variable);
141 }
141 }
142 }
142 }
143
143
144 return true;
144 return true;
145 };
145 };
146 ui->dragDropContainer->setAcceptDragWidgetFunction(acceptDragWidgetFun);
146 ui->dragDropContainer->setAcceptDragWidgetFunction(acceptDragWidgetFun);
147
147
148 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
148 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
149 &VisualizationZoneWidget::dropMimeData);
149 &VisualizationZoneWidget::dropMimeData);
150 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
150 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
151 &VisualizationZoneWidget::dropMimeDataOnGraph);
151 &VisualizationZoneWidget::dropMimeDataOnGraph);
152
152
153 // 'Close' options : widget is deleted when closed
153 // 'Close' options : widget is deleted when closed
154 setAttribute(Qt::WA_DeleteOnClose);
154 setAttribute(Qt::WA_DeleteOnClose);
155 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
155 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
156 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
156 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
157
157
158 // Synchronisation id
158 // Synchronisation id
159 // QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
159 // QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
160 // Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
160 // Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
161 }
161 }
162
162
163 VisualizationZoneWidget::~VisualizationZoneWidget()
163 VisualizationZoneWidget::~VisualizationZoneWidget()
164 {
164 {
165 delete ui;
165 delete ui;
166 }
166 }
167
167
168 void VisualizationZoneWidget::setZoneRange(const DateTimeRange& range)
168 void VisualizationZoneWidget::setZoneRange(const DateTimeRange& range)
169 {
169 {
170 if (auto graph = firstGraph())
170 if (auto graph = firstGraph())
171 {
171 {
172 graph->setGraphRange(range);
172 graph->setGraphRange(range);
173 }
173 }
174 else
174 else
175 {
175 {
176 qCWarning(LOG_VisualizationZoneWidget())
176 qCWarning(LOG_VisualizationZoneWidget())
177 << tr("setZoneRange:Cannot set the range of an empty zone.");
177 << tr("setZoneRange:Cannot set the range of an empty zone.");
178 }
178 }
179 }
179 }
180
180
181 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget* graphWidget)
181 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget* graphWidget)
182 {
182 {
183 // Synchronize new graph with others in the zone
183 // Synchronize new graph with others in the zone
184 // impl->m_Synchronizer->addGraph(*graphWidget);
184 // impl->m_Synchronizer->addGraph(*graphWidget);
185
185
186 // ui->dragDropContainer->addDragWidget(graphWidget);
186 // ui->dragDropContainer->addDragWidget(graphWidget);
187 insertGraph(0, graphWidget);
187 insertGraph(0, graphWidget);
188 }
188 }
189
189
190 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget* graphWidget)
190 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget* graphWidget)
191 {
191 {
192 DEPRECATE(
192 DEPRECATE(
193 auto layout = ui->dragDropContainer->layout(); for (int i = 0; i < layout->count(); i++) {
193 auto layout = ui->dragDropContainer->layout(); for (int i = 0; i < layout->count(); i++) {
194 auto graph = qobject_cast<VisualizationGraphWidget*>(layout->itemAt(i)->widget());
194 auto graph = qobject_cast<VisualizationGraphWidget*>(layout->itemAt(i)->widget());
195 connect(graphWidget, &VisualizationGraphWidget::setrange_sig, graph,
195 connect(graphWidget, &VisualizationGraphWidget::setrange_sig, graph,
196 &VisualizationGraphWidget::setGraphRange);
196 &VisualizationGraphWidget::setGraphRange);
197 connect(graph, &VisualizationGraphWidget::setrange_sig, graphWidget,
197 connect(graph, &VisualizationGraphWidget::setrange_sig, graphWidget,
198 &VisualizationGraphWidget::setGraphRange);
198 &VisualizationGraphWidget::setGraphRange);
199 } if (auto graph = firstGraph()) { graphWidget->setGraphRange(graph->graphRange(), true); })
199 } if (auto graph = firstGraph()) { graphWidget->setGraphRange(graph->graphRange(), true); })
200
200
201 // Synchronize new graph with others in the zone
201 // Synchronize new graph with others in the zone
202 impl->m_Synchronizer->addGraph(*graphWidget);
202 impl->m_Synchronizer->addGraph(*graphWidget);
203
203
204 ui->dragDropContainer->insertDragWidget(index, graphWidget);
204 ui->dragDropContainer->insertDragWidget(index, graphWidget);
205 }
205 }
206
206
207 VisualizationGraphWidget* VisualizationZoneWidget::createGraph(std::shared_ptr<Variable2> variable)
207 VisualizationGraphWidget* VisualizationZoneWidget::createGraph(std::shared_ptr<Variable2> variable)
208 {
208 {
209 return createGraph(variable, -1);
209 return createGraph(variable, -1);
210 }
210 }
211
211
212 VisualizationGraphWidget* VisualizationZoneWidget::createGraph(
212 VisualizationGraphWidget* VisualizationZoneWidget::createGraph(
213 std::shared_ptr<Variable2> variable, int index)
213 std::shared_ptr<Variable2> variable, int index)
214 {
214 {
215 auto graphWidget
215 auto graphWidget
216 = new VisualizationGraphWidget { defaultGraphName(*ui->dragDropContainer->layout()), this };
216 = new VisualizationGraphWidget { defaultGraphName(*ui->dragDropContainer->layout()), this };
217
217
218
218
219 // Set graph properties
219 // Set graph properties
220 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
220 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
221 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
221 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
222
222
223
223
224 // Lambda to synchronize zone widget
224 // Lambda to synchronize zone widget
225 // auto synchronizeZoneWidget = [this, graphWidget](const DateTimeRange &graphRange,
225 // auto synchronizeZoneWidget = [this, graphWidget](const DateTimeRange &graphRange,
226 // const DateTimeRange &oldGraphRange) {
226 // const DateTimeRange &oldGraphRange) {
227
227
228 // auto zoomType = DateTimeRangeHelper::getTransformationType(oldGraphRange, graphRange);
228 // auto zoomType = DateTimeRangeHelper::getTransformationType(oldGraphRange, graphRange);
229 // auto frameLayout = ui->dragDropContainer->layout();
229 // auto frameLayout = ui->dragDropContainer->layout();
230 // for (auto i = 0; i < frameLayout->count(); ++i) {
230 // for (auto i = 0; i < frameLayout->count(); ++i) {
231 // auto graphChild
231 // auto graphChild
232 // = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
232 // = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
233 // if (graphChild && (graphChild != graphWidget)) {
233 // if (graphChild && (graphChild != graphWidget)) {
234
234
235 // auto graphChildRange = graphChild->graphRange();
235 // auto graphChildRange = graphChild->graphRange();
236 // switch (zoomType) {
236 // switch (zoomType) {
237 // case TransformationType::ZoomIn: {
237 // case TransformationType::ZoomIn: {
238 // auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
238 // auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
239 // auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
239 // auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
240 // graphChildRange.m_TStart += deltaLeft;
240 // graphChildRange.m_TStart += deltaLeft;
241 // graphChildRange.m_TEnd -= deltaRight;
241 // graphChildRange.m_TEnd -= deltaRight;
242 // break;
242 // break;
243 // }
243 // }
244
244
245 // case TransformationType::ZoomOut: {
245 // case TransformationType::ZoomOut: {
246 // auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
246 // auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
247 // auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
247 // auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
248 // graphChildRange.m_TStart -= deltaLeft;
248 // graphChildRange.m_TStart -= deltaLeft;
249 // graphChildRange.m_TEnd += deltaRight;
249 // graphChildRange.m_TEnd += deltaRight;
250 // break;
250 // break;
251 // }
251 // }
252 // case TransformationType::PanRight: {
252 // case TransformationType::PanRight: {
253 // auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
253 // auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
254 // auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
254 // auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
255 // graphChildRange.m_TStart += deltaLeft;
255 // graphChildRange.m_TStart += deltaLeft;
256 // graphChildRange.m_TEnd += deltaRight;
256 // graphChildRange.m_TEnd += deltaRight;
257 // break;
257 // break;
258 // }
258 // }
259 // case TransformationType::PanLeft: {
259 // case TransformationType::PanLeft: {
260 // auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
260 // auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
261 // auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
261 // auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
262 // graphChildRange.m_TStart -= deltaLeft;
262 // graphChildRange.m_TStart -= deltaLeft;
263 // graphChildRange.m_TEnd -= deltaRight;
263 // graphChildRange.m_TEnd -= deltaRight;
264 // break;
264 // break;
265 // }
265 // }
266 // case TransformationType::Unknown: {
266 // case TransformationType::Unknown: {
267 // break;
267 // break;
268 // }
268 // }
269 // default:
269 // default:
270 // qCCritical(LOG_VisualizationZoneWidget())
270 // qCCritical(LOG_VisualizationZoneWidget())
271 // << tr("Impossible to synchronize: zoom type not take into
271 // << tr("Impossible to synchronize: zoom type not take into
272 // account");
272 // account");
273 // // No action
273 // // No action
274 // break;
274 // break;
275 // }
275 // }
276 // graphChild->setFlags(GraphFlag::DisableAll);
276 // graphChild->setFlags(GraphFlag::DisableAll);
277 // graphChild->setGraphRange(graphChildRange, true);
277 // graphChild->setGraphRange(graphChildRange, true);
278 // graphChild->setFlags(GraphFlag::EnableAll);
278 // graphChild->setFlags(GraphFlag::EnableAll);
279 // }
279 // }
280 // }
280 // }
281 // };
281 // };
282
282
283 // connection for synchronization
283 // connection for synchronization
284 // connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
284 // connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
285 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
285 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
286 &VisualizationZoneWidget::onVariableAdded);
286 &VisualizationZoneWidget::onVariableAdded);
287 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
287 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
288 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
288 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
289
289
290 auto range = DateTimeRange {};
290 auto range = DateTimeRange {};
291 if (auto firstGraph = this->firstGraph())
291 if (auto firstGraph = this->firstGraph())
292 {
292 {
293 // Case of a new graph in a existant zone
293 // Case of a new graph in a existant zone
294 range = firstGraph->graphRange();
294 range = firstGraph->graphRange();
295 }
295 }
296 else
296 else
297 {
297 {
298 // Case of a new graph as the first of the zone
298 // Case of a new graph as the first of the zone
299 range = variable->range();
299 range = variable->range();
300 }
300 }
301
301
302 this->insertGraph(index, graphWidget);
302 this->insertGraph(index, graphWidget);
303
303
304 graphWidget->addVariable(variable, range);
304 graphWidget->addVariable(variable, range);
305 graphWidget->setYRange(variable);
305 graphWidget->setYRange(variable);
306
306
307 return graphWidget;
307 return graphWidget;
308 }
308 }
309
309
310 VisualizationGraphWidget* VisualizationZoneWidget::createGraph(
310 VisualizationGraphWidget* VisualizationZoneWidget::createGraph(
311 const std::vector<std::shared_ptr<Variable2>> variables, int index)
311 const std::vector<std::shared_ptr<Variable2>> variables, int index)
312 {
312 {
313 if (variables.empty())
313 if (variables.empty())
314 {
314 {
315 return nullptr;
315 return nullptr;
316 }
316 }
317
317
318 auto graphWidget = createGraph(variables.front(), index);
318 auto graphWidget = createGraph(variables.front(), index);
319 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt)
319 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt)
320 {
320 {
321 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
321 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
322 }
322 }
323
323
324 return graphWidget;
324 return graphWidget;
325 }
325 }
326
326
327 VisualizationGraphWidget* VisualizationZoneWidget::firstGraph() const
327 VisualizationGraphWidget* VisualizationZoneWidget::firstGraph() const
328 {
328 {
329 VisualizationGraphWidget* firstGraph = nullptr;
329 VisualizationGraphWidget* firstGraph = nullptr;
330 auto layout = ui->dragDropContainer->layout();
330 auto layout = ui->dragDropContainer->layout();
331 if (layout->count() > 0)
331 if (layout->count() > 0)
332 {
332 {
333 if (auto visualizationGraphWidget
333 if (auto visualizationGraphWidget
334 = qobject_cast<VisualizationGraphWidget*>(layout->itemAt(0)->widget()))
334 = qobject_cast<VisualizationGraphWidget*>(layout->itemAt(0)->widget()))
335 {
335 {
336 firstGraph = visualizationGraphWidget;
336 firstGraph = visualizationGraphWidget;
337 }
337 }
338 }
338 }
339
339
340 return firstGraph;
340 return firstGraph;
341 }
341 }
342
342
343 void VisualizationZoneWidget::closeAllGraphs()
343 void VisualizationZoneWidget::closeAllGraphs()
344 {
344 {
345 processGraphs(*ui->dragDropContainer->layout(),
345 processGraphs(*ui->dragDropContainer->layout(),
346 [](VisualizationGraphWidget& graphWidget) { graphWidget.close(); });
346 [](VisualizationGraphWidget& graphWidget) { graphWidget.close(); });
347 }
347 }
348
348
349 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor* visitor)
349 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor* visitor)
350 {
350 {
351 if (visitor)
351 if (visitor)
352 {
352 {
353 visitor->visitEnter(this);
353 visitor->visitEnter(this);
354
354
355 // Apply visitor to graph children: widgets different from graphs are not visited (no
355 // Apply visitor to graph children: widgets different from graphs are not visited (no
356 // action)
356 // action)
357 processGraphs(*ui->dragDropContainer->layout(),
357 processGraphs(*ui->dragDropContainer->layout(),
358 [visitor](VisualizationGraphWidget& graphWidget) { graphWidget.accept(visitor); });
358 [visitor](VisualizationGraphWidget& graphWidget) { graphWidget.accept(visitor); });
359
359
360 visitor->visitLeave(this);
360 visitor->visitLeave(this);
361 }
361 }
362 else
362 else
363 {
363 {
364 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
364 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
365 }
365 }
366 }
366 }
367
367
368 bool VisualizationZoneWidget::canDrop(Variable2& variable) const
368 bool VisualizationZoneWidget::canDrop(Variable2& variable) const
369 {
369 {
370 // A tab can always accomodate a variable
370 // A tab can always accomodate a variable
371 Q_UNUSED(variable);
371 Q_UNUSED(variable);
372 return true;
372 return true;
373 }
373 }
374
374
375 bool VisualizationZoneWidget::contains(Variable2& variable) const
375 bool VisualizationZoneWidget::contains(Variable2& variable) const
376 {
376 {
377 Q_UNUSED(variable);
377 Q_UNUSED(variable);
378 return false;
378 return false;
379 }
379 }
380
380
381 QString VisualizationZoneWidget::name() const
381 QString VisualizationZoneWidget::name() const
382 {
382 {
383 return ui->zoneNameLabel->text();
383 return ui->zoneNameLabel->text();
384 }
384 }
385
385
386 QMimeData* VisualizationZoneWidget::mimeData(const QPoint& position) const
386 QMimeData* VisualizationZoneWidget::mimeData(const QPoint& position) const
387 {
387 {
388 Q_UNUSED(position);
388 Q_UNUSED(position);
389
389
390 auto mimeData = new QMimeData;
390 auto mimeData = new QMimeData;
391 mimeData->setData(MIME_TYPE_ZONE, QByteArray {});
391 mimeData->setData(MIME::MIME_TYPE_ZONE, QByteArray {});
392
392
393 if (auto firstGraph = this->firstGraph())
393 if (auto firstGraph = this->firstGraph())
394 {
394 {
395 auto timeRangeData = TimeController::mimeDataForTimeRange(firstGraph->graphRange());
395 auto timeRangeData = TimeController::mimeDataForTimeRange(firstGraph->graphRange());
396 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
396 mimeData->setData(MIME::MIME_TYPE_TIME_RANGE, timeRangeData);
397 }
397 }
398
398
399 return mimeData;
399 return mimeData;
400 }
400 }
401
401
402 bool VisualizationZoneWidget::isDragAllowed() const
402 bool VisualizationZoneWidget::isDragAllowed() const
403 {
403 {
404 return true;
404 return true;
405 }
405 }
406
406
407 void VisualizationZoneWidget::notifyMouseMoveInGraph(const QPointF& graphPosition,
407 void VisualizationZoneWidget::notifyMouseMoveInGraph(const QPointF& graphPosition,
408 const QPointF& plotPosition, VisualizationGraphWidget* graphWidget)
408 const QPointF& plotPosition, VisualizationGraphWidget* graphWidget)
409 {
409 {
410 processGraphs(*ui->dragDropContainer->layout(),
410 processGraphs(*ui->dragDropContainer->layout(),
411 [&graphPosition, &plotPosition, &graphWidget](VisualizationGraphWidget& processedGraph) {
411 [&graphPosition, &plotPosition, &graphWidget](VisualizationGraphWidget& processedGraph) {
412 switch (sqpApp->plotsCursorMode())
412 switch (sqpApp->plotsCursorMode())
413 {
413 {
414 case SqpApplication::PlotsCursorMode::Vertical:
414 case SqpApplication::PlotsCursorMode::Vertical:
415 processedGraph.removeHorizontalCursor();
415 processedGraph.removeHorizontalCursor();
416 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
416 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
417 break;
417 break;
418 case SqpApplication::PlotsCursorMode::Temporal:
418 case SqpApplication::PlotsCursorMode::Temporal:
419 processedGraph.addVerticalCursor(plotPosition.x());
419 processedGraph.addVerticalCursor(plotPosition.x());
420 processedGraph.removeHorizontalCursor();
420 processedGraph.removeHorizontalCursor();
421 break;
421 break;
422 case SqpApplication::PlotsCursorMode::Horizontal:
422 case SqpApplication::PlotsCursorMode::Horizontal:
423 processedGraph.removeVerticalCursor();
423 processedGraph.removeVerticalCursor();
424 if (&processedGraph == graphWidget)
424 if (&processedGraph == graphWidget)
425 {
425 {
426 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
426 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
427 }
427 }
428 else
428 else
429 {
429 {
430 processedGraph.removeHorizontalCursor();
430 processedGraph.removeHorizontalCursor();
431 }
431 }
432 break;
432 break;
433 case SqpApplication::PlotsCursorMode::Cross:
433 case SqpApplication::PlotsCursorMode::Cross:
434 if (&processedGraph == graphWidget)
434 if (&processedGraph == graphWidget)
435 {
435 {
436 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
436 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
437 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
437 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
438 }
438 }
439 else
439 else
440 {
440 {
441 processedGraph.removeHorizontalCursor();
441 processedGraph.removeHorizontalCursor();
442 processedGraph.removeVerticalCursor();
442 processedGraph.removeVerticalCursor();
443 }
443 }
444 break;
444 break;
445 case SqpApplication::PlotsCursorMode::NoCursor:
445 case SqpApplication::PlotsCursorMode::NoCursor:
446 processedGraph.removeHorizontalCursor();
446 processedGraph.removeHorizontalCursor();
447 processedGraph.removeVerticalCursor();
447 processedGraph.removeVerticalCursor();
448 break;
448 break;
449 }
449 }
450 });
450 });
451 }
451 }
452
452
453 void VisualizationZoneWidget::notifyMouseLeaveGraph(VisualizationGraphWidget* graphWidget)
453 void VisualizationZoneWidget::notifyMouseLeaveGraph(VisualizationGraphWidget* graphWidget)
454 {
454 {
455 processGraphs(*ui->dragDropContainer->layout(), [](VisualizationGraphWidget& processedGraph) {
455 processGraphs(*ui->dragDropContainer->layout(), [](VisualizationGraphWidget& processedGraph) {
456 processedGraph.removeHorizontalCursor();
456 processedGraph.removeHorizontalCursor();
457 processedGraph.removeVerticalCursor();
457 processedGraph.removeVerticalCursor();
458 });
458 });
459 }
459 }
460
460
461 void VisualizationZoneWidget::closeEvent(QCloseEvent* event)
461 void VisualizationZoneWidget::closeEvent(QCloseEvent* event)
462 {
462 {
463 // Closes graphs in the zone
463 // Closes graphs in the zone
464 processGraphs(*ui->dragDropContainer->layout(),
464 processGraphs(*ui->dragDropContainer->layout(),
465 [](VisualizationGraphWidget& graphWidget) { graphWidget.close(); });
465 [](VisualizationGraphWidget& graphWidget) { graphWidget.close(); });
466
466
467 // Delete synchronization group from variable controller
467 // Delete synchronization group from variable controller
468 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
468 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
469 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
469 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
470
470
471 QWidget::closeEvent(event);
471 QWidget::closeEvent(event);
472 }
472 }
473
473
474 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable2> variable)
474 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable2> variable)
475 {
475 {
476 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
476 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
477 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable2>, variable),
477 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable2>, variable),
478 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
478 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
479 }
479 }
480
480
481 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable2> variable)
481 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable2> variable)
482 {
482 {
483 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
483 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
484 Q_ARG(std::shared_ptr<Variable2>, variable), Q_ARG(QUuid, impl->m_SynchronisationGroupId));
484 Q_ARG(std::shared_ptr<Variable2>, variable), Q_ARG(QUuid, impl->m_SynchronisationGroupId));
485 }
485 }
486
486
487 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData* mimeData)
487 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData* mimeData)
488 {
488 {
489 if (mimeData->hasFormat(MIME_TYPE_GRAPH))
489 if (mimeData->hasFormat(MIME::MIME_TYPE_GRAPH))
490 {
490 {
491 impl->dropGraph(index, this);
491 impl->dropGraph(index, this);
492 }
492 }
493 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST))
493 else if (mimeData->hasFormat(MIME::MIME_TYPE_VARIABLE_LIST))
494 {
494 {
495 auto variables = sqpApp->variableController().variables(
495 auto variables = sqpApp->variableController().variables(
496 Variable2::IDs(mimeData->data(MIME_TYPE_VARIABLE_LIST)));
496 Variable2::IDs(mimeData->data(MIME::MIME_TYPE_VARIABLE_LIST)));
497 impl->dropVariables(variables, index, this);
497 impl->dropVariables(variables, index, this);
498 }
498 }
499 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST))
499 else if (mimeData->hasFormat(MIME::MIME_TYPE_PRODUCT_LIST))
500 {
500 {
501 auto products = sqpApp->dataSourceController().productsDataForMimeData(
501 auto products = MIME::decode(
502 mimeData->data(MIME_TYPE_PRODUCT_LIST));
502 mimeData->data(MIME::MIME_TYPE_PRODUCT_LIST));
503 impl->dropProducts(products, index, this);
503 impl->dropProducts(products, index, this);
504 }
504 }
505 else
505 else
506 {
506 {
507 qCWarning(LOG_VisualizationZoneWidget())
507 qCWarning(LOG_VisualizationZoneWidget())
508 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
508 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
509 }
509 }
510 }
510 }
511
511
512 void VisualizationZoneWidget::dropMimeDataOnGraph(
512 void VisualizationZoneWidget::dropMimeDataOnGraph(
513 VisualizationDragWidget* dragWidget, const QMimeData* mimeData)
513 VisualizationDragWidget* dragWidget, const QMimeData* mimeData)
514 {
514 {
515 auto graphWidget = qobject_cast<VisualizationGraphWidget*>(dragWidget);
515 auto graphWidget = qobject_cast<VisualizationGraphWidget*>(dragWidget);
516 if (!graphWidget)
516 if (!graphWidget)
517 {
517 {
518 qCWarning(LOG_VisualizationZoneWidget())
518 qCWarning(LOG_VisualizationZoneWidget())
519 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
519 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
520 "drop aborted");
520 "drop aborted");
521 Q_ASSERT(false);
521 Q_ASSERT(false);
522 return;
522 return;
523 }
523 }
524
524
525 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST))
525 if (mimeData->hasFormat(MIME::MIME_TYPE_VARIABLE_LIST))
526 {
526 {
527 auto variables = sqpApp->variableController().variables(
527 auto variables = sqpApp->variableController().variables(
528 Variable2::IDs(mimeData->data(MIME_TYPE_VARIABLE_LIST)));
528 Variable2::IDs(mimeData->data(MIME::MIME_TYPE_VARIABLE_LIST)));
529 for (const auto& var : variables)
529 for (const auto& var : variables)
530 {
530 {
531 graphWidget->addVariable(var, graphWidget->graphRange());
531 graphWidget->addVariable(var, graphWidget->graphRange());
532 }
532 }
533 }
533 }
534 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST))
534 else if (mimeData->hasFormat(MIME::MIME_TYPE_PRODUCT_LIST))
535 {
535 {
536 auto products = sqpApp->dataSourceController().productsDataForMimeData(
536 auto products = MIME::decode(
537 mimeData->data(MIME_TYPE_PRODUCT_LIST));
537 mimeData->data(MIME::MIME_TYPE_PRODUCT_LIST));
538
538
539 auto context = new QObject { this };
539 auto context = new QObject { this };
540 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
540 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME::MIME_TYPE_TIME_RANGE));
541 // BTW this is really dangerous, this assumes the next created variable will be this one...
541 // BTW this is really dangerous, this assumes the next created variable will be this one...
542 connect(&sqpApp->variableController(), &VariableController2::variableAdded, context,
542 connect(&sqpApp->variableController(), &VariableController2::variableAdded, context,
543 [this, graphWidget, context, range](auto variable) {
543 [this, graphWidget, context, range](auto variable) {
544 if (sqpApp->variableController().isReady(variable))
544 if (sqpApp->variableController().isReady(variable))
545 {
545 {
546 graphWidget->addVariable(variable, range);
546 graphWidget->addVariable(variable, range);
547 delete context;
547 delete context;
548 }
548 }
549 else
549 else
550 {
550 {
551 // -> this is pure insanity! this is a workaround to make a bad design work
551 // -> this is pure insanity! this is a workaround to make a bad design work
552 QObject::connect(variable.get(), &Variable2::updated, context,
552 QObject::connect(variable.get(), &Variable2::updated, context,
553 [graphWidget, context, range, variable]() {
553 [graphWidget, context, range, variable]() {
554 graphWidget->addVariable(variable, range);
554 graphWidget->addVariable(variable, range);
555 delete context;
555 delete context;
556 });
556 });
557 }
557 }
558 },
558 },
559 Qt::QueuedConnection);
559 Qt::QueuedConnection);
560
560
561 auto productData = products.first().toHash();
561 auto productPath = products.first().toString();
562 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
562 QMetaObject::invokeMethod(&sqpApp->dataSources(), "createVariable",
563 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
563 Qt::QueuedConnection, Q_ARG(QString, productPath));
564 }
564 }
565 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE))
565 else if (mimeData->hasFormat(MIME::MIME_TYPE_TIME_RANGE))
566 {
566 {
567 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
567 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME::MIME_TYPE_TIME_RANGE));
568 graphWidget->setGraphRange(range, true, true);
568 graphWidget->setGraphRange(range, true, true);
569 }
569 }
570 else
570 else
571 {
571 {
572 qCWarning(LOG_VisualizationZoneWidget())
572 qCWarning(LOG_VisualizationZoneWidget())
573 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
573 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
574 }
574 }
575 }
575 }
576
576
577 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
577 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
578 int index, VisualizationZoneWidget* zoneWidget)
578 int index, VisualizationZoneWidget* zoneWidget)
579 {
579 {
580 auto& helper = sqpApp->dragDropGuiController();
580 auto& helper = sqpApp->dragDropGuiController();
581
581
582 auto graphWidget = qobject_cast<VisualizationGraphWidget*>(helper.getCurrentDragWidget());
582 auto graphWidget = qobject_cast<VisualizationGraphWidget*>(helper.getCurrentDragWidget());
583 if (!graphWidget)
583 if (!graphWidget)
584 {
584 {
585 qCWarning(LOG_VisualizationZoneWidget())
585 qCWarning(LOG_VisualizationZoneWidget())
586 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
586 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
587 "found or invalid.");
587 "found or invalid.");
588 Q_ASSERT(false);
588 Q_ASSERT(false);
589 return;
589 return;
590 }
590 }
591
591
592 auto parentDragDropContainer
592 auto parentDragDropContainer
593 = qobject_cast<VisualizationDragDropContainer*>(graphWidget->parentWidget());
593 = qobject_cast<VisualizationDragDropContainer*>(graphWidget->parentWidget());
594 if (!parentDragDropContainer)
594 if (!parentDragDropContainer)
595 {
595 {
596 qCWarning(LOG_VisualizationZoneWidget())
596 qCWarning(LOG_VisualizationZoneWidget())
597 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
597 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
598 "the dropped graph is not found.");
598 "the dropped graph is not found.");
599 Q_ASSERT(false);
599 Q_ASSERT(false);
600 return;
600 return;
601 }
601 }
602
602
603 const auto& variables = graphWidget->variables();
603 const auto& variables = graphWidget->variables();
604
604
605 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.empty())
605 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.empty())
606 {
606 {
607 // The drop didn't occur in the same zone
607 // The drop didn't occur in the same zone
608
608
609 // Abort the requests for the variables (if any)
609 // Abort the requests for the variables (if any)
610 // Commented, because it's not sure if it's needed or not
610 // Commented, because it's not sure if it's needed or not
611 // for (const auto& var : variables)
611 // for (const auto& var : variables)
612 //{
612 //{
613 // sqpApp->variableController().onAbortProgressRequested(var);
613 // sqpApp->variableController().onAbortProgressRequested(var);
614 //}
614 //}
615
615
616 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
616 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
617 auto nbGraph = parentDragDropContainer->countDragWidget();
617 auto nbGraph = parentDragDropContainer->countDragWidget();
618 if (nbGraph == 1)
618 if (nbGraph == 1)
619 {
619 {
620 // This is the only graph in the previous zone, close the zone
620 // This is the only graph in the previous zone, close the zone
621 helper.delayedCloseWidget(previousParentZoneWidget);
621 helper.delayedCloseWidget(previousParentZoneWidget);
622 }
622 }
623 else
623 else
624 {
624 {
625 // Close the graph
625 // Close the graph
626 helper.delayedCloseWidget(graphWidget);
626 helper.delayedCloseWidget(graphWidget);
627 }
627 }
628
628
629 // Creates the new graph in the zone
629 // Creates the new graph in the zone
630 auto newGraphWidget = zoneWidget->createGraph(variables, index);
630 auto newGraphWidget = zoneWidget->createGraph(variables, index);
631 newGraphWidget->addSelectionZones(graphWidget->selectionZoneRanges());
631 newGraphWidget->addSelectionZones(graphWidget->selectionZoneRanges());
632 }
632 }
633 else
633 else
634 {
634 {
635 // The drop occurred in the same zone or the graph is empty
635 // The drop occurred in the same zone or the graph is empty
636 // Simple move of the graph, no variable operation associated
636 // Simple move of the graph, no variable operation associated
637 parentDragDropContainer->layout()->removeWidget(graphWidget);
637 parentDragDropContainer->layout()->removeWidget(graphWidget);
638
638
639 if (variables.empty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer)
639 if (variables.empty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer)
640 {
640 {
641 // The graph is empty and dropped in a different zone.
641 // The graph is empty and dropped in a different zone.
642 // Take the range of the first graph in the zone (if existing).
642 // Take the range of the first graph in the zone (if existing).
643 auto layout = zoneWidget->ui->dragDropContainer->layout();
643 auto layout = zoneWidget->ui->dragDropContainer->layout();
644 if (layout->count() > 0)
644 if (layout->count() > 0)
645 {
645 {
646 if (auto visualizationGraphWidget
646 if (auto visualizationGraphWidget
647 = qobject_cast<VisualizationGraphWidget*>(layout->itemAt(0)->widget()))
647 = qobject_cast<VisualizationGraphWidget*>(layout->itemAt(0)->widget()))
648 {
648 {
649 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
649 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
650 }
650 }
651 }
651 }
652 }
652 }
653
653
654 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
654 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
655 }
655 }
656 }
656 }
657
657
658 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
658 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
659 const std::vector<std::shared_ptr<Variable2>>& variables, int index,
659 const std::vector<std::shared_ptr<Variable2>>& variables, int index,
660 VisualizationZoneWidget* zoneWidget)
660 VisualizationZoneWidget* zoneWidget)
661 {
661 {
662 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
662 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
663 // compatible variable here
663 // compatible variable here
664 if (variables.size() > 1)
664 if (variables.size() > 1)
665 {
665 {
666 return;
666 return;
667 }
667 }
668 zoneWidget->createGraph(variables, index);
668 zoneWidget->createGraph(variables, index);
669 }
669 }
670
670
671 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropProducts(
671 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropProducts(
672 const QVariantList& productsData, int index, VisualizationZoneWidget* zoneWidget)
672 const QVariantList& productsData, int index, VisualizationZoneWidget* zoneWidget)
673 {
673 {
674 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
674 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
675 // compatible variable here
675 // compatible variable here
676 if (productsData.count() != 1)
676 if (productsData.count() != 1)
677 {
677 {
678 qCWarning(LOG_VisualizationZoneWidget())
678 qCWarning(LOG_VisualizationZoneWidget())
679 << tr("VisualizationTabWidget::dropProducts, dropping multiple products, operation "
679 << tr("VisualizationTabWidget::dropProducts, dropping multiple products, operation "
680 "aborted.");
680 "aborted.");
681 return;
681 return;
682 }
682 }
683
683
684 auto context = new QObject { zoneWidget };
684 auto context = new QObject { zoneWidget };
685 connect(&sqpApp->variableController(), &VariableController2::variableAdded, context,
685 connect(&sqpApp->variableController(), &VariableController2::variableAdded, context,
686 [this, index, zoneWidget, context](auto variable) {
686 [this, index, zoneWidget, context](auto variable) {
687 zoneWidget->createGraph(variable, index);
687 zoneWidget->createGraph(variable, index);
688 delete context; // removes the connection
688 delete context; // removes the connection
689 },
689 },
690 Qt::QueuedConnection);
690 Qt::QueuedConnection);
691
691
692 auto productData = productsData.first().toHash();
692 auto productPath = productsData.first().toString();
693 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
693 QMetaObject::invokeMethod(&sqpApp->dataSources(), "createVariable",
694 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
694 Qt::QueuedConnection, Q_ARG(QString, productPath));
695 }
695 }
@@ -1,49 +1,37
1 <?xml version="1.0" encoding="UTF-8"?>
1 <?xml version="1.0" encoding="UTF-8"?>
2 <ui version="4.0">
2 <ui version="4.0">
3 <class>DataSourceWidget</class>
3 <class>DataSourceWidget</class>
4 <widget class="QWidget" name="DataSourceWidget">
4 <widget class="QWidget" name="DataSourceWidget">
5 <property name="geometry">
5 <property name="geometry">
6 <rect>
6 <rect>
7 <x>0</x>
7 <x>0</x>
8 <y>0</y>
8 <y>0</y>
9 <width>400</width>
9 <width>400</width>
10 <height>300</height>
10 <height>300</height>
11 </rect>
11 </rect>
12 </property>
12 </property>
13 <property name="windowTitle">
13 <property name="windowTitle">
14 <string>Data sources</string>
14 <string>Data sources</string>
15 </property>
15 </property>
16 <layout class="QGridLayout" name="gridLayout">
16 <layout class="QGridLayout" name="gridLayout">
17 <item row="0" column="0">
17 <item row="0" column="0">
18 <widget class="QLineEdit" name="filterLineEdit"/>
18 <widget class="QLineEdit" name="filterLineEdit"/>
19 </item>
19 </item>
20 <item row="1" column="0">
20 <item row="1" column="0">
21 <widget class="DataSourceTreeWidget" name="treeWidget">
21 <widget class="QTreeView" name="treeView">
22 <property name="dragEnabled">
22 <property name="dragEnabled">
23 <bool>true</bool>
23 <bool>true</bool>
24 </property>
24 </property>
25 <property name="dragDropMode">
25 <property name="dragDropMode">
26 <enum>QAbstractItemView::DragOnly</enum>
26 <enum>QAbstractItemView::DragOnly</enum>
27 </property>
27 </property>
28 <property name="selectionMode">
28 <property name="selectionMode">
29 <enum>QAbstractItemView::ExtendedSelection</enum>
29 <enum>QAbstractItemView::ExtendedSelection</enum>
30 </property>
30 </property>
31 <column>
32 <property name="text">
33 <string notr="true">1</string>
34 </property>
35 </column>
36 </widget>
31 </widget>
37 </item>
32 </item>
38 </layout>
33 </layout>
39 </widget>
34 </widget>
40 <customwidgets>
41 <customwidget>
42 <class>DataSourceTreeWidget</class>
43 <extends>QTreeWidget</extends>
44 <header>DataSource/DataSourceTreeWidget.h</header>
45 </customwidget>
46 </customwidgets>
47 <resources/>
35 <resources/>
48 <connections/>
36 <connections/>
49 </ui>
37 </ui>
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now