##// END OF EJS Templates
[WIP] new generic WS plugin and few other fixes...
jeandet -
r1352:fb8f470a1906
parent child
Show More
@@ -0,0 +1,25
1 include_directories(include)
2 FILE (GLOB_RECURSE genericWS_SRCS
3 include/*.h
4 src/*.cpp
5 resources/*.qrc
6 )
7
8 add_definitions(-DQT_PLUGIN)
9 add_definitions(-DSCIQLOP_PLUGIN_JSON_FILE_PATH="${CMAKE_CURRENT_SOURCE_DIR}/resources/genericWS.json")
10 if(NOT BUILD_SHARED_LIBS)
11 add_definitions(-DQT_STATICPLUGIN)
12 endif()
13
14 add_library(generic_ws ${genericWS_SRCS})
15 SET_TARGET_PROPERTIES(generic_ws PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
16
17 target_link_libraries(generic_ws PUBLIC sciqlopgui)
18
19 install(TARGETS generic_ws
20 ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/SciQlop
21 LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/SciQlop
22 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
23
24 include(sciqlop_tests)
25
@@ -0,0 +1,26
1 #ifndef GENERICWSENGINE_H
2 #define GENERICWSENGINE_H
3 #include <Data/IDataProvider.h>
4 #include <Data/DataProviderParameters.h>
5
6 class GenericWSEngine: public IDataProvider
7 {
8 public:
9 virtual std::shared_ptr<IDataProvider> clone() const override
10 {
11 return std::make_shared<GenericWSEngine>();
12 }
13
14 virtual IDataSeries* getData(const DataProviderParameters &parameters) override
15 {
16 auto range = parameters.m_Range;
17 auto metadata = parameters.m_Data;
18 auto WS = metadata["WS"].toString();
19 auto parameter = metadata["WS"].toString();
20 return nullptr;
21 }
22
23
24 };
25
26 #endif
@@ -0,0 +1,24
1 #ifndef GENERICWSPLUGIN_H
2 #define GENERICWSPLUGIN_H
3
4 #include <Plugin/IPlugin.h>
5
6
7 #include <memory>
8
9 #ifndef SCIQLOP_PLUGIN_JSON_FILE_PATH
10 #define SCIQLOP_PLUGIN_JSON_FILE_PATH "genericWS.json"
11 #endif
12
13 class DataSourceItem;
14
15 class GenericWS : public QObject, public IPlugin {
16 Q_OBJECT
17 Q_INTERFACES(IPlugin)
18 Q_PLUGIN_METADATA(IID "sciqlop.plugin.IPlugin" FILE SCIQLOP_PLUGIN_JSON_FILE_PATH)
19 public:
20 /// @sa IPlugin::initialize()
21 void initialize() override;
22 };
23
24 #endif // GENERICWSPLUGIN_H
@@ -0,0 +1,3
1 {
2 "name" : "GenericWS"
3 }
@@ -0,0 +1,1
1 #include "GenericWSEngine.h"
@@ -0,0 +1,1
1 #include "GenericWSEngine.h"
@@ -0,0 +1,1
1 Subproject commit f2fa281306099e7136a288dd70fd97d0e33afa15
@@ -1,11 +1,12
1 build/
1 build/
2 CMakeLists.txt.user
2 CMakeLists.txt.user
3 /.project
3 /.project
4 core/src/Version.cpp
4 core/src/Version.cpp
5 core/include/Version.h
5 core/include/Version.h
6 3rdparty/
6 3rdparty/
7 subprojects/CatalogueAPI/
7 subprojects/CatalogueAPI/
8 subprojects/QxOrm/
8 subprojects/QxOrm/
9 documentation/*
9 documentation/*
10 .idea/*
10 **/.idea/*
11 **/__pycache__/*
11 **/__pycache__/*
12 *.srctrl*
@@ -1,60 +1,63
1 cmake_minimum_required(VERSION 3.6)
1 cmake_minimum_required(VERSION 3.6)
2 project(SciQLOP CXX)
2 project(SciQLOP CXX)
3
3
4 include(GNUInstallDirs)
4 include(GNUInstallDirs)
5
5
6 SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/cmake")
6 SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/cmake")
7
7
8 OPTION (CPPCHECK "Analyzes the source code with cppcheck" OFF)
8 OPTION (CPPCHECK "Analyzes the source code with cppcheck" OFF)
9 OPTION (CLANG_TIDY "Analyzes the source code with Clang Tidy" OFF)
9 OPTION (CLANG_TIDY "Analyzes the source code with Clang Tidy" OFF)
10 OPTION (IWYU "Analyzes the source code with Include What You Use" OFF)
10 OPTION (IWYU "Analyzes the source code with Include What You Use" OFF)
11
11
12 set(CMAKE_CXX_STANDARD 17)
12 set(CMAKE_CXX_STANDARD 17)
13
13
14 set(CMAKE_AUTOMOC ON)
14 set(CMAKE_AUTOMOC ON)
15 #https://gitlab.kitware.com/cmake/cmake/issues/15227
15 #https://gitlab.kitware.com/cmake/cmake/issues/15227
16 #set(CMAKE_AUTOUIC ON)
16 #set(CMAKE_AUTOUIC ON)
17 if(POLICY CMP0071)
17 if(POLICY CMP0071)
18 cmake_policy(SET CMP0071 OLD)
18 cmake_policy(SET CMP0071 OLD)
19 endif()
19 endif()
20 set(CMAKE_AUTORCC ON)
20 set(CMAKE_AUTORCC ON)
21 set(CMAKE_INCLUDE_CURRENT_DIR ON)
21 set(CMAKE_INCLUDE_CURRENT_DIR ON)
22
22
23 if(NOT DEFINED CMAKE_INSTALL_RPATH_USE_LINK_PATH)
23 if(NOT DEFINED CMAKE_INSTALL_RPATH_USE_LINK_PATH)
24 set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
24 set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
25 endif()
25 endif()
26 if(NOT DEFINED CMAKE_MACOSX_RPATH)
26 if(NOT DEFINED CMAKE_MACOSX_RPATH)
27 set(CMAKE_MACOSX_RPATH TRUE)
27 set(CMAKE_MACOSX_RPATH TRUE)
28 endif()
28 endif()
29
29
30 if(NOT CMAKE_BUILD_TYPE)
30 if(NOT CMAKE_BUILD_TYPE)
31 set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE)
31 set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE)
32 endif()
32 endif()
33
33
34 find_package(Qt5 COMPONENTS Core Widgets Network PrintSupport Svg Test REQUIRED)
34 find_package(Qt5 COMPONENTS Core Widgets Network PrintSupport Svg Test REQUIRED)
35
35
36 IF(CPPCHECK)
36 IF(CPPCHECK)
37 set(CMAKE_CXX_CPPCHECK "cppcheck;--enable=warning,style")
37 set(CMAKE_CXX_CPPCHECK "cppcheck;--enable=warning,style")
38 ENDIF(CPPCHECK)
38 ENDIF(CPPCHECK)
39
39
40 IF(CLANG_TIDY)
40 IF(CLANG_TIDY)
41 set(CMAKE_CXX_CLANG_TIDY "clang-tidy;-style=file;-checks=*")
41 set(CMAKE_CXX_CLANG_TIDY "clang-tidy;-style=file;-checks=*")
42 ENDIF(CLANG_TIDY)
42 ENDIF(CLANG_TIDY)
43
43
44 IF(IWYU)
44 IF(IWYU)
45 set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "include-what-you-use")
45 set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "include-what-you-use")
46 ENDIF(IWYU)
46 ENDIF(IWYU)
47
47
48 enable_testing()
48 enable_testing()
49
49
50 find_package(core CONFIG QUIET)
50 find_package(SciQLOPCore CONFIG QUIET)
51 if (NOT sciqlopcore_FOUND)
51 if (NOT SciQLOPCore_FOUND)
52 execute_process(COMMAND git submodule init core WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
52 if(NOT IS_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/core)
53 execute_process(COMMAND git submodule update core WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
53 message("Init submodule Core")
54 execute_process(COMMAND git submodule init core WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
55 execute_process(COMMAND git submodule update core WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
56 endif()
54 add_subdirectory(core)
57 add_subdirectory(core)
55 endif()
58 endif()
56
59
57 add_subdirectory(gui)
60 add_subdirectory(gui)
58 add_subdirectory(app)
61 add_subdirectory(app)
59 add_subdirectory(plugins)
62 add_subdirectory(plugins)
60 add_subdirectory(docs)
63 add_subdirectory(docs)
@@ -1,1 +1,1
1 Subproject commit a05b0ab234936e28b6ba79535ccaee297d83a1e8
1 Subproject commit 6b6270b07547ddc94a57ecd2cdb54784412c1081
@@ -1,157 +1,160
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
3
3
4 #include "Visualization/IVisualizationWidget.h"
4 #include "Visualization/IVisualizationWidget.h"
5 #include "Visualization/VisualizationDragWidget.h"
5 #include "Visualization/VisualizationDragWidget.h"
6
6
7 #include <QLoggingCategory>
7 #include <QLoggingCategory>
8 #include <QWidget>
8 #include <QWidget>
9 #include <QUuid>
9
10
10 #include <memory>
11 #include <memory>
11
12
12 #include <Common/spimpl.h>
13 #include <Common/spimpl.h>
13
14
14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
15 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
15
16
16 class QCPRange;
17 class QCPRange;
17 class QCustomPlot;
18 class QCustomPlot;
18 class DateTimeRange;
19 class DateTimeRange;
19 class Variable;
20 class Variable;
20 class VisualizationWidget;
21 class VisualizationWidget;
21 class VisualizationZoneWidget;
22 class VisualizationZoneWidget;
22 class VisualizationSelectionZoneItem;
23 class VisualizationSelectionZoneItem;
23
24
24 namespace Ui {
25 namespace Ui {
25 class VisualizationGraphWidget;
26 class VisualizationGraphWidget;
26 } // namespace Ui
27 } // namespace Ui
27
28
28 /// Defines options that can be associated with the graph
29 /// Defines options that can be associated with the graph
29 enum GraphFlag {
30 enum GraphFlag {
30 DisableAll = 0x0, ///< Disables acquisition and synchronization
31 DisableAll = 0x0, ///< Disables acquisition and synchronization
31 EnableAcquisition = 0x1, ///< When this flag is set, the change of the graph's range leads to
32 EnableAcquisition = 0x1, ///< When this flag is set, the change of the graph's range leads to
32 /// the acquisition of data
33 /// the acquisition of data
33 EnableSynchronization = 0x2, ///< When this flag is set, the change of the graph's range causes
34 EnableSynchronization = 0x2, ///< When this flag is set, the change of the graph's range causes
34 /// the call to the synchronization of the graphs contained in the
35 /// the call to the synchronization of the graphs contained in the
35 /// same zone of this graph
36 /// same zone of this graph
36 EnableAll = ~DisableAll ///< Enables acquisition and synchronization
37 EnableAll = ~DisableAll ///< Enables acquisition and synchronization
37 };
38 };
38
39
39 Q_DECLARE_FLAGS(GraphFlags, GraphFlag)
40 Q_DECLARE_FLAGS(GraphFlags, GraphFlag)
40 Q_DECLARE_OPERATORS_FOR_FLAGS(GraphFlags)
41 Q_DECLARE_OPERATORS_FOR_FLAGS(GraphFlags)
41
42
42 class VisualizationGraphWidget : public VisualizationDragWidget, public IVisualizationWidget {
43 class VisualizationGraphWidget : public VisualizationDragWidget, public IVisualizationWidget {
43 Q_OBJECT
44 Q_OBJECT
44
45
45 friend class QCustomPlotSynchronizer;
46 friend class QCustomPlotSynchronizer;
46 friend class VisualizationGraphRenderingDelegate;
47 friend class VisualizationGraphRenderingDelegate;
47
48
48 public:
49 public:
49 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
50 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
50 virtual ~VisualizationGraphWidget();
51 virtual ~VisualizationGraphWidget();
51
52
52 /// Returns the VisualizationZoneWidget which contains the graph or nullptr
53 /// Returns the VisualizationZoneWidget which contains the graph or nullptr
53 VisualizationZoneWidget *parentZoneWidget() const noexcept;
54 VisualizationZoneWidget *parentZoneWidget() const noexcept;
54
55
55 /// Returns the main VisualizationWidget which contains the graph or nullptr
56 /// Returns the main VisualizationWidget which contains the graph or nullptr
56 VisualizationWidget *parentVisualizationWidget() const;
57 VisualizationWidget *parentVisualizationWidget() const;
57
58
58 /// Sets graph options
59 /// Sets graph options
59 void setFlags(GraphFlags flags);
60 void setFlags(GraphFlags flags);
60
61
61 void addVariable(std::shared_ptr<Variable> variable, DateTimeRange range);
62 void addVariable(std::shared_ptr<Variable> variable, DateTimeRange range);
62
63
63 /// Removes a variable from the graph
64 /// Removes a variable from the graph
64 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
65 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
65
66
66 /// Returns the list of all variables used in the graph
67 /// Returns the list of all variables used in the graph
67 std::vector<std::shared_ptr<Variable> > variables() const;
68 std::vector<std::shared_ptr<Variable> > variables() const;
68
69
69 /// Sets the y-axis range based on the data of a variable
70 /// Sets the y-axis range based on the data of a variable
70 void setYRange(std::shared_ptr<Variable> variable);
71 void setYRange(std::shared_ptr<Variable> variable);
71 DateTimeRange graphRange() const noexcept;
72 DateTimeRange graphRange() const noexcept;
72 void setGraphRange(const DateTimeRange &range, bool calibration = false);
73 void setGraphRange(const DateTimeRange &range, bool calibration = false);
73 void setAutoRangeOnVariableInitialization(bool value);
74 void setAutoRangeOnVariableInitialization(bool value);
74
75
75 // Zones
76 // Zones
76 /// Returns the ranges of all the selection zones on the graph
77 /// Returns the ranges of all the selection zones on the graph
77 QVector<DateTimeRange> selectionZoneRanges() const;
78 QVector<DateTimeRange> selectionZoneRanges() const;
78 /// Adds new selection zones in the graph
79 /// Adds new selection zones in the graph
79 void addSelectionZones(const QVector<DateTimeRange> &ranges);
80 void addSelectionZones(const QVector<DateTimeRange> &ranges);
80 /// Adds a new selection zone in the graph
81 /// Adds a new selection zone in the graph
81 VisualizationSelectionZoneItem *addSelectionZone(const QString &name, const DateTimeRange &range);
82 VisualizationSelectionZoneItem *addSelectionZone(const QString &name, const DateTimeRange &range);
82 /// Removes the specified selection zone
83 /// Removes the specified selection zone
83 void removeSelectionZone(VisualizationSelectionZoneItem *selectionZone);
84 void removeSelectionZone(VisualizationSelectionZoneItem *selectionZone);
84
85
85 /// Undo the last zoom done with a zoom box
86 /// Undo the last zoom done with a zoom box
86 void undoZoom();
87 void undoZoom();
87
88
88 // IVisualizationWidget interface
89 // IVisualizationWidget interface
89 void accept(IVisualizationWidgetVisitor *visitor) override;
90 void accept(IVisualizationWidgetVisitor *visitor) override;
90 bool canDrop(const Variable &variable) const override;
91 bool canDrop(const Variable &variable) const override;
91 bool contains(const Variable &variable) const override;
92 bool contains(const Variable &variable) const override;
92 QString name() const override;
93 QString name() const override;
93
94
94 // VisualisationDragWidget
95 // VisualisationDragWidget
95 QMimeData *mimeData(const QPoint &position) const override;
96 QMimeData *mimeData(const QPoint &position) const override;
96 QPixmap customDragPixmap(const QPoint &dragPosition) override;
97 QPixmap customDragPixmap(const QPoint &dragPosition) override;
97 bool isDragAllowed() const override;
98 bool isDragAllowed() const override;
98 void highlightForMerge(bool highlighted) override;
99 void highlightForMerge(bool highlighted) override;
99
100
100 // Cursors
101 // Cursors
101 /// Adds or moves the vertical cursor at the specified value on the x-axis
102 /// Adds or moves the vertical cursor at the specified value on the x-axis
102 void addVerticalCursor(double time);
103 void addVerticalCursor(double time);
103 /// Adds or moves the vertical cursor at the specified value on the x-axis
104 /// Adds or moves the vertical cursor at the specified value on the x-axis
104 void addVerticalCursorAtViewportPosition(double position);
105 void addVerticalCursorAtViewportPosition(double position);
105 void removeVerticalCursor();
106 void removeVerticalCursor();
106 /// Adds or moves the vertical cursor at the specified value on the y-axis
107 /// Adds or moves the vertical cursor at the specified value on the y-axis
107 void addHorizontalCursor(double value);
108 void addHorizontalCursor(double value);
108 /// Adds or moves the vertical cursor at the specified value on the y-axis
109 /// Adds or moves the vertical cursor at the specified value on the y-axis
109 void addHorizontalCursorAtViewportPosition(double position);
110 void addHorizontalCursorAtViewportPosition(double position);
110 void removeHorizontalCursor();
111 void removeHorizontalCursor();
111
112
112 signals:
113 signals:
113 void synchronize(const DateTimeRange &range, const DateTimeRange &oldRange);
114 void synchronize(const DateTimeRange &range, const DateTimeRange &oldRange);
114 void changeRange(const std::shared_ptr<Variable>& variable, const DateTimeRange &range);
115 void changeRange(const std::shared_ptr<Variable>& variable, const DateTimeRange &range);
115
116
116 /// Signal emitted when the variable is about to be removed from the graph
117 /// Signal emitted when the variable is about to be removed from the graph
117 void variableAboutToBeRemoved(std::shared_ptr<Variable> var);
118 void variableAboutToBeRemoved(std::shared_ptr<Variable> var);
118 /// Signal emitted when the variable has been added to the graph
119 /// Signal emitted when the variable has been added to the graph
119 void variableAdded(std::shared_ptr<Variable> var);
120 void variableAdded(std::shared_ptr<Variable> var);
120
121
121 protected:
122 protected:
122 void closeEvent(QCloseEvent *event) override;
123 void closeEvent(QCloseEvent *event) override;
123 void enterEvent(QEvent *event) override;
124 void enterEvent(QEvent *event) override;
124 void leaveEvent(QEvent *event) override;
125 void leaveEvent(QEvent *event) override;
125
126
126 QCustomPlot &plot() const noexcept;
127 QCustomPlot &plot() const noexcept;
127
128
128 private:
129 private:
129 Ui::VisualizationGraphWidget *ui;
130 Ui::VisualizationGraphWidget *ui;
130
131
131 class VisualizationGraphWidgetPrivate;
132 class VisualizationGraphWidgetPrivate;
132 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
133 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
133
134
134 private slots:
135 private slots:
135 /// Slot called when right clicking on the graph (displays a menu)
136 /// Slot called when right clicking on the graph (displays a menu)
136 void onGraphMenuRequested(const QPoint &pos) noexcept;
137 void onGraphMenuRequested(const QPoint &pos) noexcept;
137
138
138 /// Rescale the X axe to range parameter
139 /// Rescale the X axe to range parameter
139 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
140 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
140
141
141 /// Slot called when a mouse double click was made
142 /// Slot called when a mouse double click was made
142 void onMouseDoubleClick(QMouseEvent *event) noexcept;
143 void onMouseDoubleClick(QMouseEvent *event) noexcept;
143 /// Slot called when a mouse move was made
144 /// Slot called when a mouse move was made
144 void onMouseMove(QMouseEvent *event) noexcept;
145 void onMouseMove(QMouseEvent *event) noexcept;
145 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
146 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
146 void onMouseWheel(QWheelEvent *event) noexcept;
147 void onMouseWheel(QWheelEvent *event) noexcept;
147 /// Slot called when a mouse press was made, to activate the calibration of a graph
148 /// Slot called when a mouse press was made, to activate the calibration of a graph
148 void onMousePress(QMouseEvent *event) noexcept;
149 void onMousePress(QMouseEvent *event) noexcept;
149 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
150 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
150 void onMouseRelease(QMouseEvent *event) noexcept;
151 void onMouseRelease(QMouseEvent *event) noexcept;
151
152
152 void onDataCacheVariableUpdated();
153 void onDataCacheVariableUpdated();
153
154
154 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const DateTimeRange &range);
155 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const DateTimeRange &range);
156
157 void variableUpdated(QUuid id);
155 };
158 };
156
159
157 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
160 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
@@ -1,251 +1,248
1 #include <Variable/RenameVariableDialog.h>
1 #include <Variable/RenameVariableDialog.h>
2 #include <Variable/Variable.h>
2 #include <Variable/Variable.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 #include <DataSource/DataSourceController.h>
7 #include <DataSource/DataSourceController.h>
8
8
9 #include <ui_VariableInspectorWidget.h>
9 #include <ui_VariableInspectorWidget.h>
10
10
11 #include <QMouseEvent>
11 #include <QMouseEvent>
12 #include <QSortFilterProxyModel>
12 #include <QSortFilterProxyModel>
13 #include <QStyledItemDelegate>
13 #include <QStyledItemDelegate>
14 #include <QWidgetAction>
14 #include <QWidgetAction>
15
15
16 #include <DragAndDrop/DragDropGuiController.h>
16 #include <DragAndDrop/DragDropGuiController.h>
17 #include <SqpApplication.h>
17 #include <SqpApplication.h>
18
18
19 Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget")
19 Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget")
20
20
21
21
22 class QProgressBarItemDelegate : public QStyledItemDelegate {
22 class QProgressBarItemDelegate : public QStyledItemDelegate {
23
23
24 public:
24 public:
25 QProgressBarItemDelegate(QObject *parent) : QStyledItemDelegate{parent} {}
25 QProgressBarItemDelegate(QObject *parent) : QStyledItemDelegate{parent} {}
26
26
27 void paint(QPainter *painter, const QStyleOptionViewItem &option,
27 void paint(QPainter *painter, const QStyleOptionViewItem &option,
28 const QModelIndex &index) const
28 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 auto name = data.value<QString>();
33 auto name = data.value<QString>();
34 auto progress = progressData.value<double>();
34 auto progress = progressData.value<double>();
35 if (progress > 0) {
35 if (progress > 0) {
36 auto cancelButtonWidth = 20;
36 auto cancelButtonWidth = 20;
37 auto progressBarOption = QStyleOptionProgressBar{};
37 auto progressBarOption = QStyleOptionProgressBar{};
38 auto progressRect = option.rect;
38 auto progressRect = option.rect;
39 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
39 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
40 progressBarOption.rect = progressRect;
40 progressBarOption.rect = progressRect;
41 progressBarOption.minimum = 0;
41 progressBarOption.minimum = 0;
42 progressBarOption.maximum = 100;
42 progressBarOption.maximum = 100;
43 progressBarOption.progress = progress;
43 progressBarOption.progress = progress;
44 progressBarOption.text
44 progressBarOption.text
45 = QString("%1 %2").arg(name).arg(QString::number(progress, 'f', 2) + "%");
45 = QString("%1 %2").arg(name).arg(QString::number(progress, 'f', 2) + "%");
46 progressBarOption.textVisible = true;
46 progressBarOption.textVisible = true;
47 progressBarOption.textAlignment = Qt::AlignCenter;
47 progressBarOption.textAlignment = Qt::AlignCenter;
48
48
49
49
50 QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption,
50 QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption,
51 painter);
51 painter);
52
52
53 // Cancel button
53 // Cancel button
54 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
54 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
55 option.rect.height());
55 option.rect.height());
56 auto buttonOption = QStyleOptionButton{};
56 auto buttonOption = QStyleOptionButton{};
57 buttonOption.rect = buttonRect;
57 buttonOption.rect = buttonRect;
58 buttonOption.text = "X";
58 buttonOption.text = "X";
59
59
60 QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter);
60 QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter);
61 }
61 }
62 else {
62 else {
63 QStyledItemDelegate::paint(painter, option, index);
63 QStyledItemDelegate::paint(painter, option, index);
64 }
64 }
65 }
65 }
66 else {
66 else {
67 QStyledItemDelegate::paint(painter, option, index);
67 QStyledItemDelegate::paint(painter, option, index);
68 }
68 }
69 }
69 }
70
70
71 bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
71 bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
72 const QModelIndex &index)
72 const QModelIndex &index)
73 {
73 {
74 if (event->type() == QEvent::MouseButtonRelease) {
74 if (event->type() == QEvent::MouseButtonRelease) {
75 auto data = index.data(Qt::DisplayRole);
75 auto data = index.data(Qt::DisplayRole);
76 auto progressData = index.data(VariableRoles::ProgressRole);
76 auto progressData = index.data(VariableRoles::ProgressRole);
77 if (data.isValid() && progressData.isValid()) {
77 if (data.isValid() && progressData.isValid()) {
78 auto cancelButtonWidth = 20;
78 auto cancelButtonWidth = 20;
79 auto progressRect = option.rect;
79 auto progressRect = option.rect;
80 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
80 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
81 // Cancel button
81 // Cancel button
82 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
82 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
83 option.rect.height());
83 option.rect.height());
84
84
85 auto e = (QMouseEvent *)event;
85 auto e = (QMouseEvent *)event;
86 auto clickX = e->x();
86 auto clickX = e->x();
87 auto clickY = e->y();
87 auto clickY = e->y();
88
88
89 auto x = buttonRect.left(); // the X coordinate
89 auto x = buttonRect.left(); // the X coordinate
90 auto y = buttonRect.top(); // the Y coordinate
90 auto y = buttonRect.top(); // the Y coordinate
91 auto w = buttonRect.width(); // button width
91 auto w = buttonRect.width(); // button width
92 auto h = buttonRect.height(); // button height
92 auto h = buttonRect.height(); // button height
93
93
94 if (clickX > x && clickX < x + w) {
94 if (clickX > x && clickX < x + w) {
95 if (clickY > y && clickY < y + h) {
95 if (clickY > y && clickY < y + h) {
96 //auto& variableModel = sqpApp->variableModel();
96 //auto& variableModel = sqpApp->variableModel();
97 //variableModel->abortProgress(index);
97 //variableModel->abortProgress(index);
98 }
98 }
99 return true;
99 return true;
100 }
100 }
101 else {
101 else {
102 return QStyledItemDelegate::editorEvent(event, model, option, index);
102 return QStyledItemDelegate::editorEvent(event, model, option, index);
103 }
103 }
104 }
104 }
105 else {
105 else {
106 return QStyledItemDelegate::editorEvent(event, model, option, index);
106 return QStyledItemDelegate::editorEvent(event, model, option, index);
107 }
107 }
108 }
108 }
109 else {
109 else {
110 return QStyledItemDelegate::editorEvent(event, model, option, index);
110 return QStyledItemDelegate::editorEvent(event, model, option, index);
111 }
111 }
112
112
113
113
114 return QStyledItemDelegate::editorEvent(event, model, option, index);
114 return QStyledItemDelegate::editorEvent(event, model, option, index);
115 }
115 }
116 };
116 };
117
117
118 VariableInspectorWidget::VariableInspectorWidget(QWidget *parent)
118 VariableInspectorWidget::VariableInspectorWidget(QWidget *parent)
119 : QWidget{parent},
119 : QWidget{parent},
120 ui{new Ui::VariableInspectorWidget},
120 ui{new Ui::VariableInspectorWidget},
121 m_ProgressBarItemDelegate{new QProgressBarItemDelegate{this}}
121 m_ProgressBarItemDelegate{new QProgressBarItemDelegate{this}}
122 {
122 {
123 ui->setupUi(this);
123 ui->setupUi(this);
124
124
125 // Sets model for table
125 // Sets model for table
126 // auto sortFilterModel = new QSortFilterProxyModel{this};
126 // auto sortFilterModel = new QSortFilterProxyModel{this};
127 // sortFilterModel->setSourceModel(sqpApp->variableController().variableModel());
127 // sortFilterModel->setSourceModel(sqpApp->variableController().variableModel());
128
128
129 m_model = new VariableModel2();
129 m_model = new VariableModel2();
130 ui->tableView->setModel(m_model);
130 ui->tableView->setModel(m_model);
131 connect(m_model, &VariableModel2::createVariable,
131 connect(m_model, &VariableModel2::createVariable,
132 [](const QVariantHash &productData)
132 [](const QVariantHash &productData)
133 {
133 {
134 sqpApp->dataSourceController().requestVariable(productData);
134 sqpApp->dataSourceController().requestVariable(productData);
135 });
135 });
136 auto vc = &(sqpApp->variableController());
136 auto vc = &(sqpApp->variableController());
137 connect(vc, &VariableController2::variableAdded, m_model, &VariableModel2::variableAdded);
137 connect(vc, &VariableController2::variableAdded, m_model, &VariableModel2::variableAdded);
138 connect(vc, &VariableController2::variableDeleted, m_model, &VariableModel2::variableDeleted);
138 connect(vc, &VariableController2::variableDeleted, m_model, &VariableModel2::variableDeleted);
139 connect(m_model, &VariableModel2::asyncChangeRange, vc, &VariableController2::asyncChangeRange);
139 connect(m_model, &VariableModel2::asyncChangeRange, vc, &VariableController2::asyncChangeRange);
140
140
141 // Adds extra signal/slot between view and model, so the view can be updated instantly when
141 // Adds extra signal/slot between view and model, so the view can be updated instantly when
142 // there is a change of data in the model
142 // there is a change of data in the model
143 //connect(m_model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this,
143 //connect(m_model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this,
144 // SLOT(refresh()));
144 // SLOT(refresh()));
145
145
146 //ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel());
146 //ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel());
147 ui->tableView->setItemDelegateForColumn(0, m_ProgressBarItemDelegate);
147 ui->tableView->setItemDelegateForColumn(0, m_ProgressBarItemDelegate);
148
148
149 // Fixes column sizes
149 // Fixes column sizes
150 auto model = ui->tableView->model();
150 auto model = ui->tableView->model();
151 const auto count = model->columnCount();
151 const auto count = model->columnCount();
152 for (auto i = 0; i < count; ++i) {
152 for (auto i = 0; i < count; ++i) {
153 ui->tableView->setColumnWidth(
153 ui->tableView->setColumnWidth(
154 i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width());
154 i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width());
155 }
155 }
156
156
157 // Sets selection options
157 // Sets selection options
158 ui->tableView->setSelectionBehavior(QTableView::SelectRows);
158 ui->tableView->setSelectionBehavior(QTableView::SelectRows);
159 ui->tableView->setSelectionMode(QTableView::ExtendedSelection);
159 ui->tableView->setSelectionMode(QTableView::ExtendedSelection);
160
160
161 // Connection to show a menu when right clicking on the tree
161 // Connection to show a menu when right clicking on the tree
162 ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
162 ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
163 connect(ui->tableView, &QTableView::customContextMenuRequested, this,
163 connect(ui->tableView, &QTableView::customContextMenuRequested, this,
164 &VariableInspectorWidget::onTableMenuRequested);
164 &VariableInspectorWidget::onTableMenuRequested);
165 }
165 }
166
166
167 VariableInspectorWidget::~VariableInspectorWidget()
167 VariableInspectorWidget::~VariableInspectorWidget()
168 {
168 {
169 delete ui;
169 delete ui;
170 }
170 }
171
171
172 void VariableInspectorWidget::onTableMenuRequested(const QPoint &pos) noexcept
172 void VariableInspectorWidget::onTableMenuRequested(const QPoint &pos) noexcept
173 {
173 {
174 auto selectedRows = ui->tableView->selectionModel()->selectedRows();
174 auto selectedRows = ui->tableView->selectionModel()->selectedRows();
175
176 // Gets the model to retrieve the underlying selected variables
177 auto& vc = sqpApp->variableController();
178 auto selectedVariables = QVector<std::shared_ptr<Variable> >{};
175 auto selectedVariables = QVector<std::shared_ptr<Variable> >{};
179 for (const auto &selectedRow : qAsConst(selectedRows)) {
176 for (const auto &selectedRow : qAsConst(selectedRows)) {
180 if (auto selectedVariable = vc[selectedRow.row()]) {
177 if (auto selectedVariable = this->m_model->variables()[selectedRow.row()]) {
181 selectedVariables.push_back(selectedVariable);
178 selectedVariables.push_back(selectedVariable);
182 }
179 }
183 }
180 }
184
181
185 QMenu tableMenu{};
182 QMenu tableMenu{};
186
183
187 // Emits a signal so that potential receivers can populate the menu before displaying it
184 // Emits a signal so that potential receivers can populate the menu before displaying it
188 emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables);
185 emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables);
189
186
190 // Adds menu-specific actions
187 // Adds menu-specific actions
191 if (!selectedVariables.isEmpty()) {
188 if (!selectedVariables.isEmpty()) {
192 tableMenu.addSeparator();
189 tableMenu.addSeparator();
193
190
194 // 'Rename' and 'Duplicate' actions (only if one variable selected)
191 // 'Rename' and 'Duplicate' actions (only if one variable selected)
195 if (selectedVariables.size() == 1) {
192 if (selectedVariables.size() == 1) {
196 auto selectedVariable = selectedVariables.front();
193 auto selectedVariable = selectedVariables.front();
197
194
198 auto duplicateFun = [varW = std::weak_ptr<Variable>(selectedVariable)]()
195 auto duplicateFun = [varW = std::weak_ptr<Variable>(selectedVariable)]()
199 {
196 {
200 if (auto var = varW.lock()) {
197 if (auto var = varW.lock()) {
201 sqpApp->variableController().cloneVariable(var);
198 sqpApp->variableController().cloneVariable(var);
202 }
199 }
203 };
200 };
204
201
205 tableMenu.addAction(tr("Duplicate"), duplicateFun);
202 tableMenu.addAction(tr("Duplicate"), duplicateFun);
206
203
207 auto renameFun = [ varW = std::weak_ptr<Variable>(selectedVariable), this ]()
204 auto renameFun = [ varW = std::weak_ptr<Variable>(selectedVariable), this ]()
208 {
205 {
209 if (auto var = varW.lock()) {
206 if (auto var = varW.lock()) {
210 // Generates forbidden names (names associated to existing variables)
207 // Generates forbidden names (names associated to existing variables)
211 auto allVariables = sqpApp->variableController().variables();
208 auto allVariables = sqpApp->variableController().variables();
212 auto forbiddenNames = QVector<QString>(allVariables.size());
209 auto forbiddenNames = QVector<QString>(allVariables.size());
213 std::transform(allVariables.cbegin(), allVariables.cend(),
210 std::transform(allVariables.cbegin(), allVariables.cend(),
214 forbiddenNames.begin(),
211 forbiddenNames.begin(),
215 [](const auto &variable) { return variable->name(); });
212 [](const auto &variable) { return variable->name(); });
216
213
217 RenameVariableDialog dialog{var->name(), forbiddenNames, this};
214 RenameVariableDialog dialog{var->name(), forbiddenNames, this};
218 if (dialog.exec() == QDialog::Accepted) {
215 if (dialog.exec() == QDialog::Accepted) {
219 var->setName(dialog.name());
216 var->setName(dialog.name());
220 }
217 }
221 }
218 }
222 };
219 };
223
220
224 tableMenu.addAction(tr("Rename..."), renameFun);
221 tableMenu.addAction(tr("Rename..."), renameFun);
225 }
222 }
226
223
227 // 'Delete' action
224 // 'Delete' action
228 auto deleteFun = [&selectedVariables]() {
225 auto deleteFun = [&selectedVariables]() {
229 for(const auto& var:selectedVariables)
226 for(const auto& var:selectedVariables)
230 sqpApp->variableController().deleteVariable(var);
227 sqpApp->variableController().deleteVariable(var);
231 };
228 };
232
229
233 tableMenu.addAction(QIcon{":/icones/delete.png"}, tr("Delete"), deleteFun);
230 tableMenu.addAction(QIcon{":/icones/delete.png"}, tr("Delete"), deleteFun);
234 }
231 }
235
232
236 if (!tableMenu.isEmpty()) {
233 if (!tableMenu.isEmpty()) {
237 // Generates menu header (inserted before first action)
234 // Generates menu header (inserted before first action)
238 auto firstAction = tableMenu.actions().first();
235 auto firstAction = tableMenu.actions().first();
239 auto headerAction = new QWidgetAction{&tableMenu};
236 auto headerAction = new QWidgetAction{&tableMenu};
240 headerAction->setDefaultWidget(new VariableMenuHeaderWidget{selectedVariables, &tableMenu});
237 headerAction->setDefaultWidget(new VariableMenuHeaderWidget{selectedVariables, &tableMenu});
241 tableMenu.insertAction(firstAction, headerAction);
238 tableMenu.insertAction(firstAction, headerAction);
242
239
243 // Displays menu
240 // Displays menu
244 tableMenu.exec(QCursor::pos());
241 tableMenu.exec(QCursor::pos());
245 }
242 }
246 }
243 }
247
244
248 void VariableInspectorWidget::refresh() noexcept
245 void VariableInspectorWidget::refresh() noexcept
249 {
246 {
250 ui->tableView->viewport()->update();
247 ui->tableView->viewport()->update();
251 }
248 }
@@ -1,1042 +1,1051
1 #include "Visualization/VisualizationGraphWidget.h"
1 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationCursorItem.h"
3 #include "Visualization/VisualizationCursorItem.h"
4 #include "Visualization/VisualizationDefs.h"
4 #include "Visualization/VisualizationDefs.h"
5 #include "Visualization/VisualizationGraphHelper.h"
5 #include "Visualization/VisualizationGraphHelper.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
7 #include "Visualization/VisualizationMultiZoneSelectionDialog.h"
7 #include "Visualization/VisualizationMultiZoneSelectionDialog.h"
8 #include "Visualization/VisualizationSelectionZoneItem.h"
8 #include "Visualization/VisualizationSelectionZoneItem.h"
9 #include "Visualization/VisualizationSelectionZoneManager.h"
9 #include "Visualization/VisualizationSelectionZoneManager.h"
10 #include "Visualization/VisualizationWidget.h"
10 #include "Visualization/VisualizationWidget.h"
11 #include "Visualization/VisualizationZoneWidget.h"
11 #include "Visualization/VisualizationZoneWidget.h"
12 #include "ui_VisualizationGraphWidget.h"
12 #include "ui_VisualizationGraphWidget.h"
13
13
14 #include <Actions/ActionsGuiController.h>
14 #include <Actions/ActionsGuiController.h>
15 #include <Actions/FilteringAction.h>
15 #include <Actions/FilteringAction.h>
16 #include <Common/MimeTypesDef.h>
16 #include <Common/MimeTypesDef.h>
17 #include <Data/ArrayData.h>
17 #include <Data/ArrayData.h>
18 #include <Data/IDataSeries.h>
18 #include <Data/IDataSeries.h>
19 #include <Data/SpectrogramSeries.h>
19 #include <Data/SpectrogramSeries.h>
20 #include <DragAndDrop/DragDropGuiController.h>
20 #include <DragAndDrop/DragDropGuiController.h>
21 #include <Settings/SqpSettingsDefs.h>
21 #include <Settings/SqpSettingsDefs.h>
22 #include <SqpApplication.h>
22 #include <SqpApplication.h>
23 #include <Time/TimeController.h>
23 #include <Time/TimeController.h>
24 #include <Variable/Variable.h>
24 #include <Variable/Variable.h>
25 #include <Variable/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 /// Key pressed to enable drag&drop in all modes
33 /// Key pressed to enable drag&drop in all modes
34 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
34 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
35
35
36 /// Key pressed to enable zoom on horizontal axis
36 /// Key pressed to enable zoom on horizontal axis
37 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
37 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
38
38
39 /// Key pressed to enable zoom on vertical axis
39 /// Key pressed to enable zoom on vertical axis
40 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
40 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
41
41
42 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
42 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
43 const auto PAN_SPEED = 5;
43 const auto PAN_SPEED = 5;
44
44
45 /// Key pressed to enable a calibration pan
45 /// Key pressed to enable a calibration pan
46 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
46 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
47
47
48 /// Key pressed to enable multi selection of selection zones
48 /// Key pressed to enable multi selection of selection zones
49 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
49 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
50
50
51 /// Minimum size for the zoom box, in percentage of the axis range
51 /// Minimum size for the zoom box, in percentage of the axis range
52 const auto ZOOM_BOX_MIN_SIZE = 0.8;
52 const auto ZOOM_BOX_MIN_SIZE = 0.8;
53
53
54 /// Format of the dates appearing in the label of a cursor
54 /// Format of the dates appearing in the label of a cursor
55 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
55 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
56
56
57 } // namespace
57 } // namespace
58
58
59 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
59 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
60
60
61 explicit VisualizationGraphWidgetPrivate(const QString &name)
61 explicit VisualizationGraphWidgetPrivate(const QString &name)
62 : m_Name{name},
62 : m_Name{name},
63 m_Flags{GraphFlag::EnableAll},
63 m_Flags{GraphFlag::EnableAll},
64 m_IsCalibration{false},
64 m_IsCalibration{false},
65 m_RenderingDelegate{nullptr}
65 m_RenderingDelegate{nullptr}
66 {
66 {
67 }
67 }
68
68
69 void updateData(PlottablesMap &plottables, std::shared_ptr<Variable> variable,
69 void updateData(PlottablesMap &plottables, std::shared_ptr<Variable> variable,
70 const DateTimeRange &range)
70 const DateTimeRange &range)
71 {
71 {
72 VisualizationGraphHelper::updateData(plottables, variable, range);
72 VisualizationGraphHelper::updateData(plottables, variable, range);
73
73
74 // Prevents that data has changed to update rendering
74 // Prevents that data has changed to update rendering
75 m_RenderingDelegate->onPlotUpdated();
75 m_RenderingDelegate->onPlotUpdated();
76 }
76 }
77
77
78 QString m_Name;
78 QString m_Name;
79 // 1 variable -> n qcpplot
79 // 1 variable -> n qcpplot
80 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
80 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
81 GraphFlags m_Flags;
81 GraphFlags m_Flags;
82 bool m_IsCalibration;
82 bool m_IsCalibration;
83 /// Delegate used to attach rendering features to the plot
83 /// Delegate used to attach rendering features to the plot
84 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
84 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
85
85
86 QCPItemRect *m_DrawingZoomRect = nullptr;
86 QCPItemRect *m_DrawingZoomRect = nullptr;
87 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
87 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
88
88
89 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
89 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
90 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
90 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
91
91
92 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
92 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
93 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
93 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
94 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
94 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
95
95
96 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
96 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
97
97
98 bool m_VariableAutoRangeOnInit = true;
98 bool m_VariableAutoRangeOnInit = true;
99
99
100 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
100 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
101 {
101 {
102 removeDrawingRect(plot);
102 removeDrawingRect(plot);
103
103
104 auto axisPos = posToAxisPos(pos, plot);
104 auto axisPos = posToAxisPos(pos, plot);
105
105
106 m_DrawingZoomRect = new QCPItemRect{&plot};
106 m_DrawingZoomRect = new QCPItemRect{&plot};
107 QPen p;
107 QPen p;
108 p.setWidth(2);
108 p.setWidth(2);
109 m_DrawingZoomRect->setPen(p);
109 m_DrawingZoomRect->setPen(p);
110
110
111 m_DrawingZoomRect->topLeft->setCoords(axisPos);
111 m_DrawingZoomRect->topLeft->setCoords(axisPos);
112 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
112 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
113 }
113 }
114
114
115 void removeDrawingRect(QCustomPlot &plot)
115 void removeDrawingRect(QCustomPlot &plot)
116 {
116 {
117 if (m_DrawingZoomRect) {
117 if (m_DrawingZoomRect) {
118 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
118 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
119 m_DrawingZoomRect = nullptr;
119 m_DrawingZoomRect = nullptr;
120 plot.replot(QCustomPlot::rpQueuedReplot);
120 plot.replot(QCustomPlot::rpQueuedReplot);
121 }
121 }
122 }
122 }
123
123
124 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
124 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
125 {
125 {
126 endDrawingZone(graph);
126 endDrawingZone(graph);
127
127
128 auto axisPos = posToAxisPos(pos, graph->plot());
128 auto axisPos = posToAxisPos(pos, graph->plot());
129
129
130 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
130 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
131 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
131 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
132 m_DrawingZone->setEditionEnabled(false);
132 m_DrawingZone->setEditionEnabled(false);
133 }
133 }
134
134
135 void endDrawingZone(VisualizationGraphWidget *graph)
135 void endDrawingZone(VisualizationGraphWidget *graph)
136 {
136 {
137 if (m_DrawingZone) {
137 if (m_DrawingZone) {
138 auto drawingZoneRange = m_DrawingZone->range();
138 auto drawingZoneRange = m_DrawingZone->range();
139 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
139 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
140 m_DrawingZone->setEditionEnabled(true);
140 m_DrawingZone->setEditionEnabled(true);
141 addSelectionZone(m_DrawingZone);
141 addSelectionZone(m_DrawingZone);
142 }
142 }
143 else {
143 else {
144 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
144 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
145 }
145 }
146
146
147 graph->plot().replot(QCustomPlot::rpQueuedReplot);
147 graph->plot().replot(QCustomPlot::rpQueuedReplot);
148 m_DrawingZone = nullptr;
148 m_DrawingZone = nullptr;
149 }
149 }
150 }
150 }
151
151
152 void setSelectionZonesEditionEnabled(bool value)
152 void setSelectionZonesEditionEnabled(bool value)
153 {
153 {
154 for (auto s : m_SelectionZones) {
154 for (auto s : m_SelectionZones) {
155 s->setEditionEnabled(value);
155 s->setEditionEnabled(value);
156 }
156 }
157 }
157 }
158
158
159 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
159 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
160
160
161 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
161 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
162 const QCustomPlot &plot) const
162 const QCustomPlot &plot) const
163 {
163 {
164 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
164 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
165 auto minDistanceToZone = -1;
165 auto minDistanceToZone = -1;
166 for (auto zone : m_SelectionZones) {
166 for (auto zone : m_SelectionZones) {
167 auto distanceToZone = zone->selectTest(pos, false);
167 auto distanceToZone = zone->selectTest(pos, false);
168 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
168 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
169 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
169 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
170 selectionZoneItemUnderCursor = zone;
170 selectionZoneItemUnderCursor = zone;
171 }
171 }
172 }
172 }
173
173
174 return selectionZoneItemUnderCursor;
174 return selectionZoneItemUnderCursor;
175 }
175 }
176
176
177 QVector<VisualizationSelectionZoneItem *> selectionZonesAt(const QPoint &pos,
177 QVector<VisualizationSelectionZoneItem *> selectionZonesAt(const QPoint &pos,
178 const QCustomPlot &plot) const
178 const QCustomPlot &plot) const
179 {
179 {
180 QVector<VisualizationSelectionZoneItem *> zones;
180 QVector<VisualizationSelectionZoneItem *> zones;
181 for (auto zone : m_SelectionZones) {
181 for (auto zone : m_SelectionZones) {
182 auto distanceToZone = zone->selectTest(pos, false);
182 auto distanceToZone = zone->selectTest(pos, false);
183 if (distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
183 if (distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
184 zones << zone;
184 zones << zone;
185 }
185 }
186 }
186 }
187
187
188 return zones;
188 return zones;
189 }
189 }
190
190
191 void moveSelectionZoneOnTop(VisualizationSelectionZoneItem *zone, QCustomPlot &plot)
191 void moveSelectionZoneOnTop(VisualizationSelectionZoneItem *zone, QCustomPlot &plot)
192 {
192 {
193 if (!m_SelectionZones.isEmpty() && m_SelectionZones.last() != zone) {
193 if (!m_SelectionZones.isEmpty() && m_SelectionZones.last() != zone) {
194 zone->moveToTop();
194 zone->moveToTop();
195 m_SelectionZones.removeAll(zone);
195 m_SelectionZones.removeAll(zone);
196 m_SelectionZones.append(zone);
196 m_SelectionZones.append(zone);
197 }
197 }
198 }
198 }
199
199
200 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
200 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
201 {
201 {
202 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
202 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
203 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
203 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
204 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
204 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
205 }
205 }
206
206
207 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
207 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
208 {
208 {
209 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
209 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
210 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
210 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
211 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
211 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
212 }
212 }
213 };
213 };
214
214
215 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
215 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
216 : VisualizationDragWidget{parent},
216 : VisualizationDragWidget{parent},
217 ui{new Ui::VisualizationGraphWidget},
217 ui{new Ui::VisualizationGraphWidget},
218 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
218 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
219 {
219 {
220 ui->setupUi(this);
220 ui->setupUi(this);
221
221
222 // 'Close' options : widget is deleted when closed
222 // 'Close' options : widget is deleted when closed
223 setAttribute(Qt::WA_DeleteOnClose);
223 setAttribute(Qt::WA_DeleteOnClose);
224
224
225 // Set qcpplot properties :
225 // Set qcpplot properties :
226 // - zoom is enabled
226 // - zoom is enabled
227 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
227 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
228 ui->widget->setInteractions(QCP::iRangeZoom);
228 ui->widget->setInteractions(QCP::iRangeZoom);
229 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
229 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
230
230
231 // The delegate must be initialized after the ui as it uses the plot
231 // The delegate must be initialized after the ui as it uses the plot
232 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
232 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
233
233
234 // Init the cursors
234 // Init the cursors
235 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
235 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
236 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
236 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
237 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
237 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
238 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
238 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
239
239
240 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
240 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
241 connect(ui->widget, &QCustomPlot::mouseRelease, this,
241 connect(ui->widget, &QCustomPlot::mouseRelease, this,
242 &VisualizationGraphWidget::onMouseRelease);
242 &VisualizationGraphWidget::onMouseRelease);
243 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
243 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
244 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
244 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
245 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
245 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
246 &VisualizationGraphWidget::onMouseDoubleClick);
246 &VisualizationGraphWidget::onMouseDoubleClick);
247 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
247 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
248 &QCPAxis::rangeChanged),
248 &QCPAxis::rangeChanged),
249 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
249 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
250
250
251 // Activates menu when right clicking on the graph
251 // Activates menu when right clicking on the graph
252 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
252 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
253 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
253 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
254 &VisualizationGraphWidget::onGraphMenuRequested);
254 &VisualizationGraphWidget::onGraphMenuRequested);
255
255
256 //@TODO implement this :)
256 //@TODO implement this :)
257 // connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
257 // connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
258 // &VariableController::onRequestDataLoading);
258 // &VariableController::onRequestDataLoading);
259
259
260 // connect(&sqpApp->variableController(), &VariableController2::updateVarDisplaying, this,
260 // connect(&sqpApp->variableController(), &VariableController2::updateVarDisplaying, this,
261 // &VisualizationGraphWidget::onUpdateVarDisplaying);
261 // &VisualizationGraphWidget::onUpdateVarDisplaying);
262
262
263 // Necessary for all platform since Qt::AA_EnableHighDpiScaling is enable.
263 // Necessary for all platform since Qt::AA_EnableHighDpiScaling is enable.
264 plot().setPlottingHint(QCP::phFastPolylines, true);
264 plot().setPlottingHint(QCP::phFastPolylines, true);
265 }
265 }
266
266
267
267
268 VisualizationGraphWidget::~VisualizationGraphWidget()
268 VisualizationGraphWidget::~VisualizationGraphWidget()
269 {
269 {
270 delete ui;
270 delete ui;
271 }
271 }
272
272
273 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
273 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
274 {
274 {
275 auto parent = parentWidget();
275 auto parent = parentWidget();
276 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
276 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
277 parent = parent->parentWidget();
277 parent = parent->parentWidget();
278 }
278 }
279
279
280 return qobject_cast<VisualizationZoneWidget *>(parent);
280 return qobject_cast<VisualizationZoneWidget *>(parent);
281 }
281 }
282
282
283 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
283 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
284 {
284 {
285 auto parent = parentWidget();
285 auto parent = parentWidget();
286 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
286 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
287 parent = parent->parentWidget();
287 parent = parent->parentWidget();
288 }
288 }
289
289
290 return qobject_cast<VisualizationWidget *>(parent);
290 return qobject_cast<VisualizationWidget *>(parent);
291 }
291 }
292
292
293 void VisualizationGraphWidget::setFlags(GraphFlags flags)
293 void VisualizationGraphWidget::setFlags(GraphFlags flags)
294 {
294 {
295 impl->m_Flags = std::move(flags);
295 impl->m_Flags = std::move(flags);
296 }
296 }
297
297
298 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, DateTimeRange range)
298 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, DateTimeRange range)
299 {
299 {
300 // Uses delegate to create the qcpplot components according to the variable
300 // Uses delegate to create the qcpplot components according to the variable
301 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
301 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
302
302
303 // Sets graph properties
303 // Sets graph properties
304 impl->m_RenderingDelegate->setGraphProperties(*variable, createdPlottables);
304 impl->m_RenderingDelegate->setGraphProperties(*variable, createdPlottables);
305
305
306 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
306 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
307
307
308 // If the variable already has its data loaded, load its units and its range in the graph
308 // If the variable already has its data loaded, load its units and its range in the graph
309 if (variable->dataSeries() != nullptr) {
309 if (variable->dataSeries() != nullptr) {
310 impl->m_RenderingDelegate->setAxesUnits(*variable);
310 impl->m_RenderingDelegate->setAxesUnits(*variable);
311 this->setFlags(GraphFlag::DisableAll);
311 this->setFlags(GraphFlag::DisableAll);
312 setGraphRange(range);
312 setGraphRange(range);
313 this->setFlags(GraphFlag::EnableAll);
313 this->setFlags(GraphFlag::EnableAll);
314 }
314 }
315 connect(variable.get(),&Variable::updated,
315 //@TODO this is bad! when variable is moved to another graph it still fires
316 [variable=variable,this]()
316 // even if this has been deleted
317 {
317 connect(variable.get(),&Variable::updated,this, &VisualizationGraphWidget::variableUpdated);
318 QMetaObject::invokeMethod(this,[variable=variable,this](){this->onUpdateVarDisplaying(variable,this->graphRange());});
319 });
320 this->onUpdateVarDisplaying(variable,range);//My bullshit
318 this->onUpdateVarDisplaying(variable,range);//My bullshit
321 emit variableAdded(variable);
319 emit variableAdded(variable);
322 }
320 }
323
321
324 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
322 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
325 {
323 {
326 // Each component associated to the variable :
324 // Each component associated to the variable :
327 // - is removed from qcpplot (which deletes it)
325 // - is removed from qcpplot (which deletes it)
328 // - is no longer referenced in the map
326 // - is no longer referenced in the map
329 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
327 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
330 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
328 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
331 emit variableAboutToBeRemoved(variable);
329 emit variableAboutToBeRemoved(variable);
332
330
333 auto &plottablesMap = variableIt->second;
331 auto &plottablesMap = variableIt->second;
334
332
335 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
333 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
336 plottableIt != plottableEnd;) {
334 plottableIt != plottableEnd;) {
337 ui->widget->removePlottable(plottableIt->second);
335 ui->widget->removePlottable(plottableIt->second);
338 plottableIt = plottablesMap.erase(plottableIt);
336 plottableIt = plottablesMap.erase(plottableIt);
339 }
337 }
340
338
341 impl->m_VariableToPlotMultiMap.erase(variableIt);
339 impl->m_VariableToPlotMultiMap.erase(variableIt);
342 }
340 }
343
341
344 // Updates graph
342 // Updates graph
345 ui->widget->replot();
343 ui->widget->replot();
346 }
344 }
347
345
348 std::vector<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
346 std::vector<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
349 {
347 {
350 auto variables = std::vector<std::shared_ptr<Variable> >{};
348 auto variables = std::vector<std::shared_ptr<Variable> >{};
351 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
349 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
352 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
350 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
353 variables.push_back (it->first);
351 variables.push_back (it->first);
354 }
352 }
355
353
356 return variables;
354 return variables;
357 }
355 }
358
356
359 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
357 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
360 {
358 {
361 if (!variable) {
359 if (!variable) {
362 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
360 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
363 return;
361 return;
364 }
362 }
365
363
366 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
364 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
367 }
365 }
368
366
369 DateTimeRange VisualizationGraphWidget::graphRange() const noexcept
367 DateTimeRange VisualizationGraphWidget::graphRange() const noexcept
370 {
368 {
371 auto graphRange = ui->widget->xAxis->range();
369 auto graphRange = ui->widget->xAxis->range();
372 return DateTimeRange{graphRange.lower, graphRange.upper};
370 return DateTimeRange{graphRange.lower, graphRange.upper};
373 }
371 }
374
372
375 void VisualizationGraphWidget::setGraphRange(const DateTimeRange &range, bool calibration)
373 void VisualizationGraphWidget::setGraphRange(const DateTimeRange &range, bool calibration)
376 {
374 {
377 if (calibration) {
375 if (calibration) {
378 impl->m_IsCalibration = true;
376 impl->m_IsCalibration = true;
379 }
377 }
380
378
381 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
379 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
382 ui->widget->replot();
380 ui->widget->replot();
383
381
384 if (calibration) {
382 if (calibration) {
385 impl->m_IsCalibration = false;
383 impl->m_IsCalibration = false;
386 }
384 }
387 }
385 }
388
386
389 void VisualizationGraphWidget::setAutoRangeOnVariableInitialization(bool value)
387 void VisualizationGraphWidget::setAutoRangeOnVariableInitialization(bool value)
390 {
388 {
391 impl->m_VariableAutoRangeOnInit = value;
389 impl->m_VariableAutoRangeOnInit = value;
392 }
390 }
393
391
394 QVector<DateTimeRange> VisualizationGraphWidget::selectionZoneRanges() const
392 QVector<DateTimeRange> VisualizationGraphWidget::selectionZoneRanges() const
395 {
393 {
396 QVector<DateTimeRange> ranges;
394 QVector<DateTimeRange> ranges;
397 for (auto zone : impl->m_SelectionZones) {
395 for (auto zone : impl->m_SelectionZones) {
398 ranges << zone->range();
396 ranges << zone->range();
399 }
397 }
400
398
401 return ranges;
399 return ranges;
402 }
400 }
403
401
404 void VisualizationGraphWidget::addSelectionZones(const QVector<DateTimeRange> &ranges)
402 void VisualizationGraphWidget::addSelectionZones(const QVector<DateTimeRange> &ranges)
405 {
403 {
406 for (const auto &range : ranges) {
404 for (const auto &range : ranges) {
407 // note: ownership is transfered to QCustomPlot
405 // note: ownership is transfered to QCustomPlot
408 auto zone = new VisualizationSelectionZoneItem(&plot());
406 auto zone = new VisualizationSelectionZoneItem(&plot());
409 zone->setRange(range.m_TStart, range.m_TEnd);
407 zone->setRange(range.m_TStart, range.m_TEnd);
410 impl->addSelectionZone(zone);
408 impl->addSelectionZone(zone);
411 }
409 }
412
410
413 plot().replot(QCustomPlot::rpQueuedReplot);
411 plot().replot(QCustomPlot::rpQueuedReplot);
414 }
412 }
415
413
416 VisualizationSelectionZoneItem *VisualizationGraphWidget::addSelectionZone(const QString &name,
414 VisualizationSelectionZoneItem *VisualizationGraphWidget::addSelectionZone(const QString &name,
417 const DateTimeRange &range)
415 const DateTimeRange &range)
418 {
416 {
419 // note: ownership is transfered to QCustomPlot
417 // note: ownership is transfered to QCustomPlot
420 auto zone = new VisualizationSelectionZoneItem(&plot());
418 auto zone = new VisualizationSelectionZoneItem(&plot());
421 zone->setName(name);
419 zone->setName(name);
422 zone->setRange(range.m_TStart, range.m_TEnd);
420 zone->setRange(range.m_TStart, range.m_TEnd);
423 impl->addSelectionZone(zone);
421 impl->addSelectionZone(zone);
424
422
425 plot().replot(QCustomPlot::rpQueuedReplot);
423 plot().replot(QCustomPlot::rpQueuedReplot);
426
424
427 return zone;
425 return zone;
428 }
426 }
429
427
430 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
428 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
431 {
429 {
432 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
430 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
433
431
434 if (impl->m_HoveredZone == selectionZone) {
432 if (impl->m_HoveredZone == selectionZone) {
435 impl->m_HoveredZone = nullptr;
433 impl->m_HoveredZone = nullptr;
436 setCursor(Qt::ArrowCursor);
434 setCursor(Qt::ArrowCursor);
437 }
435 }
438
436
439 impl->m_SelectionZones.removeAll(selectionZone);
437 impl->m_SelectionZones.removeAll(selectionZone);
440 plot().removeItem(selectionZone);
438 plot().removeItem(selectionZone);
441 plot().replot(QCustomPlot::rpQueuedReplot);
439 plot().replot(QCustomPlot::rpQueuedReplot);
442 }
440 }
443
441
444 void VisualizationGraphWidget::undoZoom()
442 void VisualizationGraphWidget::undoZoom()
445 {
443 {
446 auto zoom = impl->m_ZoomStack.pop();
444 auto zoom = impl->m_ZoomStack.pop();
447 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
445 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
448 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
446 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
449
447
450 axisX->setRange(zoom.first);
448 axisX->setRange(zoom.first);
451 axisY->setRange(zoom.second);
449 axisY->setRange(zoom.second);
452
450
453 plot().replot(QCustomPlot::rpQueuedReplot);
451 plot().replot(QCustomPlot::rpQueuedReplot);
454 }
452 }
455
453
456 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
454 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
457 {
455 {
458 if (visitor) {
456 if (visitor) {
459 visitor->visit(this);
457 visitor->visit(this);
460 }
458 }
461 else {
459 else {
462 qCCritical(LOG_VisualizationGraphWidget())
460 qCCritical(LOG_VisualizationGraphWidget())
463 << tr("Can't visit widget : the visitor is null");
461 << tr("Can't visit widget : the visitor is null");
464 }
462 }
465 }
463 }
466
464
467 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
465 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
468 {
466 {
469 auto isSpectrogram = [](const auto &variable) {
467 auto isSpectrogram = [](const auto &variable) {
470 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
468 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
471 };
469 };
472
470
473 // - A spectrogram series can't be dropped on graph with existing plottables
471 // - A spectrogram series can't be dropped on graph with existing plottables
474 // - No data series can be dropped on graph with existing spectrogram series
472 // - No data series can be dropped on graph with existing spectrogram series
475 return isSpectrogram(variable)
473 return isSpectrogram(variable)
476 ? impl->m_VariableToPlotMultiMap.empty()
474 ? impl->m_VariableToPlotMultiMap.empty()
477 : std::none_of(
475 : std::none_of(
478 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
476 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
479 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
477 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
480 }
478 }
481
479
482 bool VisualizationGraphWidget::contains(const Variable &variable) const
480 bool VisualizationGraphWidget::contains(const Variable &variable) const
483 {
481 {
484 // Finds the variable among the keys of the map
482 // Finds the variable among the keys of the map
485 auto variablePtr = &variable;
483 auto variablePtr = &variable;
486 auto findVariable
484 auto findVariable
487 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
485 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
488
486
489 auto end = impl->m_VariableToPlotMultiMap.cend();
487 auto end = impl->m_VariableToPlotMultiMap.cend();
490 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
488 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
491 return it != end;
489 return it != end;
492 }
490 }
493
491
494 QString VisualizationGraphWidget::name() const
492 QString VisualizationGraphWidget::name() const
495 {
493 {
496 return impl->m_Name;
494 return impl->m_Name;
497 }
495 }
498
496
499 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
497 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
500 {
498 {
501 auto mimeData = new QMimeData;
499 auto mimeData = new QMimeData;
502
500
503 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
501 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
504 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
502 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
505 && selectionZoneItemUnderCursor) {
503 && selectionZoneItemUnderCursor) {
506 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
504 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
507 selectionZoneItemUnderCursor->range()));
505 selectionZoneItemUnderCursor->range()));
508 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
506 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
509 selectionZoneItemUnderCursor->range()));
507 selectionZoneItemUnderCursor->range()));
510 }
508 }
511 else {
509 else {
512 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
510 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
513
511
514 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
512 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
515 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
513 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
516 }
514 }
517
515
518 return mimeData;
516 return mimeData;
519 }
517 }
520
518
521 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
519 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
522 {
520 {
523 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
521 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
524 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
522 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
525 && selectionZoneItemUnderCursor) {
523 && selectionZoneItemUnderCursor) {
526
524
527 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
525 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
528 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
526 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
529
527
530 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
528 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
531 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
529 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
532 .toSize();
530 .toSize();
533
531
534 auto pixmap = QPixmap(zoneSize);
532 auto pixmap = QPixmap(zoneSize);
535 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
533 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
536
534
537 return pixmap;
535 return pixmap;
538 }
536 }
539
537
540 return QPixmap();
538 return QPixmap();
541 }
539 }
542
540
543 bool VisualizationGraphWidget::isDragAllowed() const
541 bool VisualizationGraphWidget::isDragAllowed() const
544 {
542 {
545 return true;
543 return true;
546 }
544 }
547
545
548 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
546 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
549 {
547 {
550 if (highlighted) {
548 if (highlighted) {
551 plot().setBackground(QBrush(QColor("#BBD5EE")));
549 plot().setBackground(QBrush(QColor("#BBD5EE")));
552 }
550 }
553 else {
551 else {
554 plot().setBackground(QBrush(Qt::white));
552 plot().setBackground(QBrush(Qt::white));
555 }
553 }
556
554
557 plot().update();
555 plot().update();
558 }
556 }
559
557
560 void VisualizationGraphWidget::addVerticalCursor(double time)
558 void VisualizationGraphWidget::addVerticalCursor(double time)
561 {
559 {
562 impl->m_VerticalCursor->setPosition(time);
560 impl->m_VerticalCursor->setPosition(time);
563 impl->m_VerticalCursor->setVisible(true);
561 impl->m_VerticalCursor->setVisible(true);
564
562
565 auto text
563 auto text
566 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
564 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
567 impl->m_VerticalCursor->setLabelText(text);
565 impl->m_VerticalCursor->setLabelText(text);
568 }
566 }
569
567
570 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
568 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
571 {
569 {
572 impl->m_VerticalCursor->setAbsolutePosition(position);
570 impl->m_VerticalCursor->setAbsolutePosition(position);
573 impl->m_VerticalCursor->setVisible(true);
571 impl->m_VerticalCursor->setVisible(true);
574
572
575 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
573 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
576 auto text
574 auto text
577 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
575 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
578 impl->m_VerticalCursor->setLabelText(text);
576 impl->m_VerticalCursor->setLabelText(text);
579 }
577 }
580
578
581 void VisualizationGraphWidget::removeVerticalCursor()
579 void VisualizationGraphWidget::removeVerticalCursor()
582 {
580 {
583 impl->m_VerticalCursor->setVisible(false);
581 impl->m_VerticalCursor->setVisible(false);
584 plot().replot(QCustomPlot::rpQueuedReplot);
582 plot().replot(QCustomPlot::rpQueuedReplot);
585 }
583 }
586
584
587 void VisualizationGraphWidget::addHorizontalCursor(double value)
585 void VisualizationGraphWidget::addHorizontalCursor(double value)
588 {
586 {
589 impl->m_HorizontalCursor->setPosition(value);
587 impl->m_HorizontalCursor->setPosition(value);
590 impl->m_HorizontalCursor->setVisible(true);
588 impl->m_HorizontalCursor->setVisible(true);
591 impl->m_HorizontalCursor->setLabelText(QString::number(value));
589 impl->m_HorizontalCursor->setLabelText(QString::number(value));
592 }
590 }
593
591
594 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
592 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
595 {
593 {
596 impl->m_HorizontalCursor->setAbsolutePosition(position);
594 impl->m_HorizontalCursor->setAbsolutePosition(position);
597 impl->m_HorizontalCursor->setVisible(true);
595 impl->m_HorizontalCursor->setVisible(true);
598
596
599 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
597 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
600 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
598 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
601 }
599 }
602
600
603 void VisualizationGraphWidget::removeHorizontalCursor()
601 void VisualizationGraphWidget::removeHorizontalCursor()
604 {
602 {
605 impl->m_HorizontalCursor->setVisible(false);
603 impl->m_HorizontalCursor->setVisible(false);
606 plot().replot(QCustomPlot::rpQueuedReplot);
604 plot().replot(QCustomPlot::rpQueuedReplot);
607 }
605 }
608
606
609 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
607 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
610 {
608 {
611 Q_UNUSED(event);
609 Q_UNUSED(event);
612
610
613 for (auto i : impl->m_SelectionZones) {
611 for (auto i : impl->m_SelectionZones) {
614 parentVisualizationWidget()->selectionZoneManager().setSelected(i, false);
612 parentVisualizationWidget()->selectionZoneManager().setSelected(i, false);
615 }
613 }
616
614
617 // Prevents that all variables will be removed from graph when it will be closed
615 // Prevents that all variables will be removed from graph when it will be closed
618 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
616 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
619 emit variableAboutToBeRemoved(variableEntry.first);
617 emit variableAboutToBeRemoved(variableEntry.first);
620 }
618 }
621 }
619 }
622
620
623 void VisualizationGraphWidget::enterEvent(QEvent *event)
621 void VisualizationGraphWidget::enterEvent(QEvent *event)
624 {
622 {
625 Q_UNUSED(event);
623 Q_UNUSED(event);
626 impl->m_RenderingDelegate->showGraphOverlay(true);
624 impl->m_RenderingDelegate->showGraphOverlay(true);
627 }
625 }
628
626
629 void VisualizationGraphWidget::leaveEvent(QEvent *event)
627 void VisualizationGraphWidget::leaveEvent(QEvent *event)
630 {
628 {
631 Q_UNUSED(event);
629 Q_UNUSED(event);
632 impl->m_RenderingDelegate->showGraphOverlay(false);
630 impl->m_RenderingDelegate->showGraphOverlay(false);
633
631
634 if (auto parentZone = parentZoneWidget()) {
632 if (auto parentZone = parentZoneWidget()) {
635 parentZone->notifyMouseLeaveGraph(this);
633 parentZone->notifyMouseLeaveGraph(this);
636 }
634 }
637 else {
635 else {
638 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
636 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
639 }
637 }
640
638
641 if (impl->m_HoveredZone) {
639 if (impl->m_HoveredZone) {
642 impl->m_HoveredZone->setHovered(false);
640 impl->m_HoveredZone->setHovered(false);
643 impl->m_HoveredZone = nullptr;
641 impl->m_HoveredZone = nullptr;
644 }
642 }
645 }
643 }
646
644
647 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
645 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
648 {
646 {
649 return *ui->widget;
647 return *ui->widget;
650 }
648 }
651
649
652 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
650 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
653 {
651 {
654 QMenu graphMenu{};
652 QMenu graphMenu{};
655
653
656 // Iterates on variables (unique keys)
654 // Iterates on variables (unique keys)
657 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
655 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
658 end = impl->m_VariableToPlotMultiMap.cend();
656 end = impl->m_VariableToPlotMultiMap.cend();
659 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
657 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
660 // 'Remove variable' action
658 // 'Remove variable' action
661 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
659 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
662 [ this, var = it->first ]() { removeVariable(var); });
660 [ this, var = it->first ]() { removeVariable(var); });
663 }
661 }
664
662
665 if (!impl->m_ZoomStack.isEmpty()) {
663 if (!impl->m_ZoomStack.isEmpty()) {
666 if (!graphMenu.isEmpty()) {
664 if (!graphMenu.isEmpty()) {
667 graphMenu.addSeparator();
665 graphMenu.addSeparator();
668 }
666 }
669
667
670 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
668 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
671 }
669 }
672
670
673 // Selection Zone Actions
671 // Selection Zone Actions
674 auto selectionZoneItem = impl->selectionZoneAt(pos, plot());
672 auto selectionZoneItem = impl->selectionZoneAt(pos, plot());
675 if (selectionZoneItem) {
673 if (selectionZoneItem) {
676 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
674 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
677 selectedItems.removeAll(selectionZoneItem);
675 selectedItems.removeAll(selectionZoneItem);
678 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
676 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
679
677
680 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
678 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
681 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
679 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
682 graphMenu.addSeparator();
680 graphMenu.addSeparator();
683 }
681 }
684
682
685 QHash<QString, QMenu *> subMenus;
683 QHash<QString, QMenu *> subMenus;
686 QHash<QString, bool> subMenusEnabled;
684 QHash<QString, bool> subMenusEnabled;
687 QHash<QString, FilteringAction *> filteredMenu;
685 QHash<QString, FilteringAction *> filteredMenu;
688
686
689 for (auto zoneAction : zoneActions) {
687 for (auto zoneAction : zoneActions) {
690
688
691 auto isEnabled = zoneAction->isEnabled(selectedItems);
689 auto isEnabled = zoneAction->isEnabled(selectedItems);
692
690
693 auto menu = &graphMenu;
691 auto menu = &graphMenu;
694 QString menuPath;
692 QString menuPath;
695 for (auto subMenuName : zoneAction->subMenuList()) {
693 for (auto subMenuName : zoneAction->subMenuList()) {
696 menuPath += '/';
694 menuPath += '/';
697 menuPath += subMenuName;
695 menuPath += subMenuName;
698
696
699 if (!subMenus.contains(menuPath)) {
697 if (!subMenus.contains(menuPath)) {
700 menu = menu->addMenu(subMenuName);
698 menu = menu->addMenu(subMenuName);
701 subMenus[menuPath] = menu;
699 subMenus[menuPath] = menu;
702 subMenusEnabled[menuPath] = isEnabled;
700 subMenusEnabled[menuPath] = isEnabled;
703 }
701 }
704 else {
702 else {
705 menu = subMenus.value(menuPath);
703 menu = subMenus.value(menuPath);
706 if (isEnabled) {
704 if (isEnabled) {
707 // The sub menu is enabled if at least one of its actions is enabled
705 // The sub menu is enabled if at least one of its actions is enabled
708 subMenusEnabled[menuPath] = true;
706 subMenusEnabled[menuPath] = true;
709 }
707 }
710 }
708 }
711 }
709 }
712
710
713 FilteringAction *filterAction = nullptr;
711 FilteringAction *filterAction = nullptr;
714 if (sqpApp->actionsGuiController().isMenuFiltered(zoneAction->subMenuList())) {
712 if (sqpApp->actionsGuiController().isMenuFiltered(zoneAction->subMenuList())) {
715 filterAction = filteredMenu.value(menuPath);
713 filterAction = filteredMenu.value(menuPath);
716 if (!filterAction) {
714 if (!filterAction) {
717 filterAction = new FilteringAction{this};
715 filterAction = new FilteringAction{this};
718 filteredMenu[menuPath] = filterAction;
716 filteredMenu[menuPath] = filterAction;
719 menu->addAction(filterAction);
717 menu->addAction(filterAction);
720 }
718 }
721 }
719 }
722
720
723 auto action = menu->addAction(zoneAction->name());
721 auto action = menu->addAction(zoneAction->name());
724 action->setEnabled(isEnabled);
722 action->setEnabled(isEnabled);
725 action->setShortcut(zoneAction->displayedShortcut());
723 action->setShortcut(zoneAction->displayedShortcut());
726 QObject::connect(action, &QAction::triggered,
724 QObject::connect(action, &QAction::triggered,
727 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
725 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
728
726
729 if (filterAction && zoneAction->isFilteringAllowed()) {
727 if (filterAction && zoneAction->isFilteringAllowed()) {
730 filterAction->addActionToFilter(action);
728 filterAction->addActionToFilter(action);
731 }
729 }
732 }
730 }
733
731
734 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) {
732 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) {
735 it.value()->setEnabled(subMenusEnabled[it.key()]);
733 it.value()->setEnabled(subMenusEnabled[it.key()]);
736 }
734 }
737 }
735 }
738
736
739 if (!graphMenu.isEmpty()) {
737 if (!graphMenu.isEmpty()) {
740 graphMenu.exec(QCursor::pos());
738 graphMenu.exec(QCursor::pos());
741 }
739 }
742 }
740 }
743
741
744 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
742 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
745 {
743 {
746 auto graphRange = DateTimeRange{t1.lower, t1.upper};
744 auto graphRange = DateTimeRange{t1.lower, t1.upper};
747 auto oldGraphRange = DateTimeRange{t2.lower, t2.upper};
745 auto oldGraphRange = DateTimeRange{t2.lower, t2.upper};
748
746
749 if (impl->m_Flags.testFlag(GraphFlag::EnableAcquisition)) {
747 if (impl->m_Flags.testFlag(GraphFlag::EnableAcquisition)) {
750 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
748 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
751 end = impl->m_VariableToPlotMultiMap.end();
749 end = impl->m_VariableToPlotMultiMap.end();
752 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
750 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
753 sqpApp->variableController().asyncChangeRange(it->first, graphRange);
751 sqpApp->variableController().asyncChangeRange(it->first, graphRange);
754 }
752 }
755 }
753 }
756
754
757 if (impl->m_Flags.testFlag(GraphFlag::EnableSynchronization) && !impl->m_IsCalibration)
755 if (impl->m_Flags.testFlag(GraphFlag::EnableSynchronization) && !impl->m_IsCalibration)
758 {
756 {
759 emit synchronize(graphRange, oldGraphRange);
757 emit synchronize(graphRange, oldGraphRange);
760 }
758 }
761
759
762 auto pos = mapFromGlobal(QCursor::pos());
760 auto pos = mapFromGlobal(QCursor::pos());
763 auto axisPos = impl->posToAxisPos(pos, plot());
761 auto axisPos = impl->posToAxisPos(pos, plot());
764 if (auto parentZone = parentZoneWidget()) {
762 if (auto parentZone = parentZoneWidget()) {
765 if (impl->pointIsInAxisRect(axisPos, plot())) {
763 if (impl->pointIsInAxisRect(axisPos, plot())) {
766 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
764 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
767 }
765 }
768 else {
766 else {
769 parentZone->notifyMouseLeaveGraph(this);
767 parentZone->notifyMouseLeaveGraph(this);
770 }
768 }
771 }
769 }
772
770
773 // Quits calibration
771 // Quits calibration
774 impl->m_IsCalibration = false;
772 impl->m_IsCalibration = false;
775 }
773 }
776
774
777 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
775 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
778 {
776 {
779 impl->m_RenderingDelegate->onMouseDoubleClick(event);
777 impl->m_RenderingDelegate->onMouseDoubleClick(event);
780 }
778 }
781
779
782 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
780 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
783 {
781 {
784 // Handles plot rendering when mouse is moving
782 // Handles plot rendering when mouse is moving
785 impl->m_RenderingDelegate->onMouseMove(event);
783 impl->m_RenderingDelegate->onMouseMove(event);
786
784
787 auto axisPos = impl->posToAxisPos(event->pos(), plot());
785 auto axisPos = impl->posToAxisPos(event->pos(), plot());
788
786
789 // Zoom box and zone drawing
787 // Zoom box and zone drawing
790 if (impl->m_DrawingZoomRect) {
788 if (impl->m_DrawingZoomRect) {
791 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
789 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
792 }
790 }
793 else if (impl->m_DrawingZone) {
791 else if (impl->m_DrawingZone) {
794 impl->m_DrawingZone->setEnd(axisPos.x());
792 impl->m_DrawingZone->setEnd(axisPos.x());
795 }
793 }
796
794
797 // Cursor
795 // Cursor
798 if (auto parentZone = parentZoneWidget()) {
796 if (auto parentZone = parentZoneWidget()) {
799 if (impl->pointIsInAxisRect(axisPos, plot())) {
797 if (impl->pointIsInAxisRect(axisPos, plot())) {
800 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
798 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
801 }
799 }
802 else {
800 else {
803 parentZone->notifyMouseLeaveGraph(this);
801 parentZone->notifyMouseLeaveGraph(this);
804 }
802 }
805 }
803 }
806
804
807 // Search for the selection zone under the mouse
805 // Search for the selection zone under the mouse
808 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
806 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
809 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
807 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
810 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
808 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
811
809
812 // Sets the appropriate cursor shape
810 // Sets the appropriate cursor shape
813 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
811 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
814 setCursor(cursorShape);
812 setCursor(cursorShape);
815
813
816 // Manages the hovered zone
814 // Manages the hovered zone
817 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
815 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
818 if (impl->m_HoveredZone) {
816 if (impl->m_HoveredZone) {
819 impl->m_HoveredZone->setHovered(false);
817 impl->m_HoveredZone->setHovered(false);
820 }
818 }
821 selectionZoneItemUnderCursor->setHovered(true);
819 selectionZoneItemUnderCursor->setHovered(true);
822 impl->m_HoveredZone = selectionZoneItemUnderCursor;
820 impl->m_HoveredZone = selectionZoneItemUnderCursor;
823 plot().replot(QCustomPlot::rpQueuedReplot);
821 plot().replot(QCustomPlot::rpQueuedReplot);
824 }
822 }
825 }
823 }
826 else {
824 else {
827 // There is no zone under the mouse or the interaction mode is not "selection zones"
825 // There is no zone under the mouse or the interaction mode is not "selection zones"
828 if (impl->m_HoveredZone) {
826 if (impl->m_HoveredZone) {
829 impl->m_HoveredZone->setHovered(false);
827 impl->m_HoveredZone->setHovered(false);
830 impl->m_HoveredZone = nullptr;
828 impl->m_HoveredZone = nullptr;
831 }
829 }
832
830
833 setCursor(Qt::ArrowCursor);
831 setCursor(Qt::ArrowCursor);
834 }
832 }
835
833
836 impl->m_HasMovedMouse = true;
834 impl->m_HasMovedMouse = true;
837 VisualizationDragWidget::mouseMoveEvent(event);
835 VisualizationDragWidget::mouseMoveEvent(event);
838 }
836 }
839
837
840 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
838 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
841 {
839 {
842 // Processes event only if the wheel occurs on axis rect
840 // Processes event only if the wheel occurs on axis rect
843 if (!dynamic_cast<QCPAxisRect *>(ui->widget->layoutElementAt(event->posF()))) {
841 if (!dynamic_cast<QCPAxisRect *>(ui->widget->layoutElementAt(event->posF()))) {
844 return;
842 return;
845 }
843 }
846
844
847 auto value = event->angleDelta().x() + event->angleDelta().y();
845 auto value = event->angleDelta().x() + event->angleDelta().y();
848 if (value != 0) {
846 if (value != 0) {
849
847
850 auto direction = value > 0 ? 1.0 : -1.0;
848 auto direction = value > 0 ? 1.0 : -1.0;
851 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
849 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
852 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
850 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
853 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
851 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
854
852
855 auto zoomOrientations = QFlags<Qt::Orientation>{};
853 auto zoomOrientations = QFlags<Qt::Orientation>{};
856 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
854 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
857 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
855 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
858
856
859 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
857 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
860
858
861 if (!isZoomX && !isZoomY) {
859 if (!isZoomX && !isZoomY) {
862 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
860 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
863 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
861 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
864
862
865 axis->setRange(axis->range() + diff);
863 axis->setRange(axis->range() + diff);
866
864
867 if (plot().noAntialiasingOnDrag()) {
865 if (plot().noAntialiasingOnDrag()) {
868 plot().setNotAntialiasedElements(QCP::aeAll);
866 plot().setNotAntialiasedElements(QCP::aeAll);
869 }
867 }
870
868
871 //plot().replot(QCustomPlot::rpQueuedReplot);
869 //plot().replot(QCustomPlot::rpQueuedReplot);
872 }
870 }
873 }
871 }
874 }
872 }
875
873
876 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
874 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
877 {
875 {
878 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
876 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
879 auto isSelectionZoneMode
877 auto isSelectionZoneMode
880 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
878 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
881 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
879 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
882
880
883 if (!isDragDropClick && isLeftClick) {
881 if (!isDragDropClick && isLeftClick) {
884 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
882 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
885 // Starts a zoom box
883 // Starts a zoom box
886 impl->startDrawingRect(event->pos(), plot());
884 impl->startDrawingRect(event->pos(), plot());
887 }
885 }
888 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
886 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
889 // Starts a new selection zone
887 // Starts a new selection zone
890 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
888 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
891 if (!zoneAtPos) {
889 if (!zoneAtPos) {
892 impl->startDrawingZone(event->pos(), this);
890 impl->startDrawingZone(event->pos(), this);
893 }
891 }
894 }
892 }
895 }
893 }
896
894
897 // Allows mouse panning only in default mode
895 // Allows mouse panning only in default mode
898 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
896 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
899 == SqpApplication::PlotsInteractionMode::None
897 == SqpApplication::PlotsInteractionMode::None
900 && !isDragDropClick);
898 && !isDragDropClick);
901
899
902 // Allows zone edition only in selection zone mode without drag&drop
900 // Allows zone edition only in selection zone mode without drag&drop
903 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
901 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
904
902
905 // Selection / Deselection
903 // Selection / Deselection
906 if (isSelectionZoneMode) {
904 if (isSelectionZoneMode) {
907 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
905 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
908 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
906 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
909
907
910
908
911 if (selectionZoneItemUnderCursor && !selectionZoneItemUnderCursor->selected()
909 if (selectionZoneItemUnderCursor && !selectionZoneItemUnderCursor->selected()
912 && !isMultiSelectionClick) {
910 && !isMultiSelectionClick) {
913 parentVisualizationWidget()->selectionZoneManager().select(
911 parentVisualizationWidget()->selectionZoneManager().select(
914 {selectionZoneItemUnderCursor});
912 {selectionZoneItemUnderCursor});
915 }
913 }
916 else if (!selectionZoneItemUnderCursor && !isMultiSelectionClick && isLeftClick) {
914 else if (!selectionZoneItemUnderCursor && !isMultiSelectionClick && isLeftClick) {
917 parentVisualizationWidget()->selectionZoneManager().clearSelection();
915 parentVisualizationWidget()->selectionZoneManager().clearSelection();
918 }
916 }
919 else {
917 else {
920 // No selection change
918 // No selection change
921 }
919 }
922
920
923 if (selectionZoneItemUnderCursor && isLeftClick) {
921 if (selectionZoneItemUnderCursor && isLeftClick) {
924 selectionZoneItemUnderCursor->setAssociatedEditedZones(
922 selectionZoneItemUnderCursor->setAssociatedEditedZones(
925 parentVisualizationWidget()->selectionZoneManager().selectedItems());
923 parentVisualizationWidget()->selectionZoneManager().selectedItems());
926 }
924 }
927 }
925 }
928
926
929
927
930 impl->m_HasMovedMouse = false;
928 impl->m_HasMovedMouse = false;
931 VisualizationDragWidget::mousePressEvent(event);
929 VisualizationDragWidget::mousePressEvent(event);
932 }
930 }
933
931
934 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
932 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
935 {
933 {
936 if (impl->m_DrawingZoomRect) {
934 if (impl->m_DrawingZoomRect) {
937
935
938 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
936 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
939 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
937 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
940
938
941 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
939 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
942 impl->m_DrawingZoomRect->bottomRight->coords().x()};
940 impl->m_DrawingZoomRect->bottomRight->coords().x()};
943
941
944 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
942 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
945 impl->m_DrawingZoomRect->bottomRight->coords().y()};
943 impl->m_DrawingZoomRect->bottomRight->coords().y()};
946
944
947 impl->removeDrawingRect(plot());
945 impl->removeDrawingRect(plot());
948
946
949 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
947 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
950 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
948 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
951 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
949 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
952 axisX->setRange(newAxisXRange);
950 axisX->setRange(newAxisXRange);
953 axisY->setRange(newAxisYRange);
951 axisY->setRange(newAxisYRange);
954
952
955 plot().replot(QCustomPlot::rpQueuedReplot);
953 plot().replot(QCustomPlot::rpQueuedReplot);
956 }
954 }
957 }
955 }
958
956
959 impl->endDrawingZone(this);
957 impl->endDrawingZone(this);
960
958
961 // Selection / Deselection
959 // Selection / Deselection
962 auto isSelectionZoneMode
960 auto isSelectionZoneMode
963 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
961 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
964 if (isSelectionZoneMode) {
962 if (isSelectionZoneMode) {
965 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
963 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
966 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
964 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
967 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton
965 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton
968 && !impl->m_HasMovedMouse) {
966 && !impl->m_HasMovedMouse) {
969
967
970 auto zonesUnderCursor = impl->selectionZonesAt(event->pos(), plot());
968 auto zonesUnderCursor = impl->selectionZonesAt(event->pos(), plot());
971 if (zonesUnderCursor.count() > 1) {
969 if (zonesUnderCursor.count() > 1) {
972 // There are multiple zones under the mouse.
970 // There are multiple zones under the mouse.
973 // Performs the selection with a selection dialog.
971 // Performs the selection with a selection dialog.
974 VisualizationMultiZoneSelectionDialog dialog{this};
972 VisualizationMultiZoneSelectionDialog dialog{this};
975 dialog.setZones(zonesUnderCursor);
973 dialog.setZones(zonesUnderCursor);
976 dialog.move(mapToGlobal(event->pos() - QPoint(dialog.width() / 2, 20)));
974 dialog.move(mapToGlobal(event->pos() - QPoint(dialog.width() / 2, 20)));
977 dialog.activateWindow();
975 dialog.activateWindow();
978 dialog.raise();
976 dialog.raise();
979 if (dialog.exec() == QDialog::Accepted) {
977 if (dialog.exec() == QDialog::Accepted) {
980 auto selection = dialog.selectedZones();
978 auto selection = dialog.selectedZones();
981
979
982 if (!isMultiSelectionClick) {
980 if (!isMultiSelectionClick) {
983 parentVisualizationWidget()->selectionZoneManager().clearSelection();
981 parentVisualizationWidget()->selectionZoneManager().clearSelection();
984 }
982 }
985
983
986 for (auto it = selection.cbegin(); it != selection.cend(); ++it) {
984 for (auto it = selection.cbegin(); it != selection.cend(); ++it) {
987 auto zone = it.key();
985 auto zone = it.key();
988 auto isSelected = it.value();
986 auto isSelected = it.value();
989 parentVisualizationWidget()->selectionZoneManager().setSelected(zone,
987 parentVisualizationWidget()->selectionZoneManager().setSelected(zone,
990 isSelected);
988 isSelected);
991
989
992 if (isSelected) {
990 if (isSelected) {
993 // Puts the zone on top of the stack so it can be moved or resized
991 // Puts the zone on top of the stack so it can be moved or resized
994 impl->moveSelectionZoneOnTop(zone, plot());
992 impl->moveSelectionZoneOnTop(zone, plot());
995 }
993 }
996 }
994 }
997 }
995 }
998 }
996 }
999 else {
997 else {
1000 if (!isMultiSelectionClick) {
998 if (!isMultiSelectionClick) {
1001 parentVisualizationWidget()->selectionZoneManager().select(
999 parentVisualizationWidget()->selectionZoneManager().select(
1002 {selectionZoneItemUnderCursor});
1000 {selectionZoneItemUnderCursor});
1003 impl->moveSelectionZoneOnTop(selectionZoneItemUnderCursor, plot());
1001 impl->moveSelectionZoneOnTop(selectionZoneItemUnderCursor, plot());
1004 }
1002 }
1005 else {
1003 else {
1006 parentVisualizationWidget()->selectionZoneManager().setSelected(
1004 parentVisualizationWidget()->selectionZoneManager().setSelected(
1007 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
1005 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
1008 || event->button() == Qt::RightButton);
1006 || event->button() == Qt::RightButton);
1009 }
1007 }
1010 }
1008 }
1011 }
1009 }
1012 else {
1010 else {
1013 // No selection change
1011 // No selection change
1014 }
1012 }
1015 }
1013 }
1016 }
1014 }
1017
1015
1018 void VisualizationGraphWidget::onDataCacheVariableUpdated()
1016 void VisualizationGraphWidget::onDataCacheVariableUpdated()
1019 {
1017 {
1020 auto graphRange = ui->widget->xAxis->range();
1018 auto graphRange = ui->widget->xAxis->range();
1021 auto dateTime = DateTimeRange{graphRange.lower, graphRange.upper};
1019 auto dateTime = DateTimeRange{graphRange.lower, graphRange.upper};
1022
1020
1023 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
1021 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
1024 auto variable = variableEntry.first;
1022 auto variable = variableEntry.first;
1025 qCDebug(LOG_VisualizationGraphWidget())
1023 qCDebug(LOG_VisualizationGraphWidget())
1026 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
1024 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
1027 qCDebug(LOG_VisualizationGraphWidget())
1025 qCDebug(LOG_VisualizationGraphWidget())
1028 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
1026 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
1029 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
1027 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
1030 impl->updateData(variableEntry.second, variable, variable->range());
1028 impl->updateData(variableEntry.second, variable, variable->range());
1031 }
1029 }
1032 }
1030 }
1033 }
1031 }
1034
1032
1035 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
1033 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
1036 const DateTimeRange &range)
1034 const DateTimeRange &range)
1037 {
1035 {
1038 auto it = impl->m_VariableToPlotMultiMap.find(variable);
1036 auto it = impl->m_VariableToPlotMultiMap.find(variable);
1039 if (it != impl->m_VariableToPlotMultiMap.end()) {
1037 if (it != impl->m_VariableToPlotMultiMap.end()) {
1040 impl->updateData(it->second, variable, range);
1038 impl->updateData(it->second, variable, range);
1041 }
1039 }
1042 }
1040 }
1041
1042 void VisualizationGraphWidget::variableUpdated(QUuid id)
1043 {
1044 for(auto& [var,plotables]:impl->m_VariableToPlotMultiMap)
1045 {
1046 if(var->ID()==id)
1047 {
1048 impl->updateData(plotables,var,this->graphRange());
1049 }
1050 }
1051 }
@@ -1,2 +1,3
1 add_subdirectory(mockplugin)
1 add_subdirectory(mockplugin)
2 add_subdirectory(amda)
2 add_subdirectory(amda)
3 add_subdirectory(generic_ws)
@@ -1,88 +1,88
1 #include "AmdaProvider.h"
1 #include "AmdaProvider.h"
2 #include "AmdaDefs.h"
2 #include "AmdaDefs.h"
3 #include "AmdaResultParser.h"
3 #include "AmdaResultParser.h"
4 #include "AmdaServer.h"
4 #include "AmdaServer.h"
5
5
6 #include <Common/DateUtils.h>
6 #include <Common/DateUtils.h>
7 #include <Data/DataProviderParameters.h>
7 #include <Data/DataProviderParameters.h>
8 #include <Network/NetworkController.h>
8 #include <Network/NetworkController.h>
9 #include <SqpApplication.h>
9 #include <SqpApplication.h>
10 #include <Variable/Variable.h>
10 #include <Variable/Variable.h>
11
11
12 #include <QNetworkAccessManager>
12 #include <QNetworkAccessManager>
13 #include <QNetworkReply>
13 #include <QNetworkReply>
14 #include <QTemporaryFile>
14 #include <QTemporaryFile>
15 #include <QThread>
15 #include <QThread>
16 #include <QJsonDocument>
16 #include <QJsonDocument>
17 #include <Network/Downloader.h>
17 #include <Network/Downloader.h>
18
18
19 Q_LOGGING_CATEGORY(LOG_AmdaProvider, "AmdaProvider")
19 Q_LOGGING_CATEGORY(LOG_AmdaProvider, "AmdaProvider")
20
20
21 namespace {
21 namespace {
22
22
23 /// URL format for a request on AMDA server. The parameters are as follows:
23 /// URL format for a request on AMDA server. The parameters are as follows:
24 /// - %1: server URL
24 /// - %1: server URL
25 /// - %2: start date
25 /// - %2: start date
26 /// - %3: end date
26 /// - %3: end date
27 /// - %4: parameter id
27 /// - %4: parameter id
28 /// AMDA V2: http://amdatest.irap.omp.eu/php/rest/
28 /// AMDA V2: http://amdatest.irap.omp.eu/php/rest/
29 const auto AMDA_URL_FORMAT = QStringLiteral(
29 const auto AMDA_URL_FORMAT = QStringLiteral(
30 "http://%1/php/rest/"
30 "http://%1/php/rest/"
31 "getParameter.php?startTime=%2&stopTime=%3&parameterID=%4&outputFormat=ASCII&"
31 "getParameter.php?startTime=%2&stopTime=%3&parameterID=%4&outputFormat=ASCII&"
32 "timeFormat=ISO8601&gzip=0");
32 "timeFormat=ISO8601&gzip=0");
33
33
34 const auto AMDA_URL_FORMAT_WITH_TOKEN = QStringLiteral(
34 const auto AMDA_URL_FORMAT_WITH_TOKEN = QStringLiteral(
35 "http://%1/php/rest/"
35 "http://%1/php/rest/"
36 "getParameter.php?startTime=%2&stopTime=%3&parameterID=%4&outputFormat=ASCII&"
36 "getParameter.php?startTime=%2&stopTime=%3&parameterID=%4&outputFormat=ASCII&"
37 "timeFormat=ISO8601&gzip=0&"
37 "timeFormat=ISO8601&gzip=0&"
38 "token=%5");
38 "token=%5");
39
39
40 const auto AMDA_TOKEN_URL_FORMAT = QStringLiteral(
40 const auto AMDA_TOKEN_URL_FORMAT = QStringLiteral(
41 "http://%1/php/rest/"
41 "http://%1/php/rest/"
42 "auth.php");
42 "auth.php");
43
43
44 /// Dates format passed in the URL (e.g 2013-09-23T09:00)
44 /// Dates format passed in the URL (e.g 2013-09-23T09:00)
45 const auto AMDA_TIME_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss");
45 const auto AMDA_TIME_FORMAT = QStringLiteral("yyyy-MM-ddThh:mm:ss");
46
46
47 /// Formats a time to a date that can be passed in URL
47 /// Formats a time to a date that can be passed in URL
48 QString dateFormat(double sqpRange) noexcept
48 QString dateFormat(double sqpRange) noexcept
49 {
49 {
50 auto dateTime = DateUtils::dateTime(sqpRange);
50 auto dateTime = DateUtils::dateTime(sqpRange);
51 return dateTime.toString(AMDA_TIME_FORMAT);
51 return dateTime.toString(AMDA_TIME_FORMAT);
52 }
52 }
53
53
54
54
55 } // namespace
55 } // namespace
56
56
57 AmdaProvider::AmdaProvider()
57 AmdaProvider::AmdaProvider()
58 {
58 {
59
59
60 }
60 }
61
61
62 std::shared_ptr<IDataProvider> AmdaProvider::clone() const
62 std::shared_ptr<IDataProvider> AmdaProvider::clone() const
63 {
63 {
64 // No copy is made in the clone
64 // No copy is made in the clone
65 return std::make_shared<AmdaProvider>();
65 return std::make_shared<AmdaProvider>();
66 }
66 }
67
67
68 IDataSeries* AmdaProvider::getData(const DataProviderParameters &parameters)
68 IDataSeries* AmdaProvider::getData(const DataProviderParameters &parameters)
69 {
69 {
70 auto range = parameters.m_Times.front();
70 auto range = parameters.m_Range;
71 auto metaData = parameters.m_Data;
71 auto metaData = parameters.m_Data;
72 auto productId = metaData.value(AMDA_XML_ID_KEY).toString();
72 auto productId = metaData.value(AMDA_XML_ID_KEY).toString();
73 auto productValueType
73 auto productValueType
74 = DataSeriesTypeUtils::fromString(metaData.value(AMDA_DATA_TYPE_KEY).toString());
74 = DataSeriesTypeUtils::fromString(metaData.value(AMDA_DATA_TYPE_KEY).toString());
75 auto startDate = dateFormat(range.m_TStart);
75 auto startDate = dateFormat(range.m_TStart);
76 auto endDate = dateFormat(range.m_TEnd);
76 auto endDate = dateFormat(range.m_TEnd);
77 QVariantHash urlProperties{{AMDA_SERVER_KEY, metaData.value(AMDA_SERVER_KEY)}};
77 QVariantHash urlProperties{{AMDA_SERVER_KEY, metaData.value(AMDA_SERVER_KEY)}};
78 auto token_url = QString{AMDA_TOKEN_URL_FORMAT}.arg(AmdaServer::instance().url(urlProperties));
78 auto token_url = QString{AMDA_TOKEN_URL_FORMAT}.arg(AmdaServer::instance().url(urlProperties));
79 auto response = Downloader::get(token_url);
79 auto response = Downloader::get(token_url);
80 auto url = QString{AMDA_URL_FORMAT_WITH_TOKEN}.arg(AmdaServer::instance().url(urlProperties),
80 auto url = QString{AMDA_URL_FORMAT_WITH_TOKEN}.arg(AmdaServer::instance().url(urlProperties),
81 startDate, endDate, productId, QString(response.data()));
81 startDate, endDate, productId, QString(response.data()));
82 response = Downloader::get(url);
82 response = Downloader::get(url);
83 auto test = QJsonDocument::fromJson(response.data());
83 auto test = QJsonDocument::fromJson(response.data());
84 url = test["dataFileURLs"].toString();
84 url = test["dataFileURLs"].toString();
85 response = Downloader::get(url);
85 response = Downloader::get(url);
86 return AmdaResultParser::readTxt(QTextStream{response.data()},productValueType);
86 return AmdaResultParser::readTxt(QTextStream{response.data()},productValueType);
87 }
87 }
88
88
@@ -1,99 +1,99
1 #include "AmdaServer.h"
1 #include "AmdaServer.h"
2
2
3 #include "AmdaDefs.h"
3 #include "AmdaDefs.h"
4
4
5 Q_LOGGING_CATEGORY(LOG_AmdaServer, "AmdaServer")
5 Q_LOGGING_CATEGORY(LOG_AmdaServer, "AmdaServer")
6
6
7 namespace {
7 namespace {
8
8
9 /// URL of the default AMDA server
9 /// URL of the default AMDA server
10 const auto AMDA_DEFAULT_SERVER_URL = QStringLiteral("amda.irap.omp.eu");
10 const auto AMDA_DEFAULT_SERVER_URL = QStringLiteral("amda.irap.omp.eu");
11
11
12 /// URL of the AMDA test server
12 /// URL of the AMDA test server
13 const auto AMDA_TEST_SERVER_URL = QStringLiteral("amdatest.irap.omp.eu");
13 const auto AMDA_TEST_SERVER_URL = QStringLiteral("amdadev.irap.omp.eu/");
14
14
15 /// Port used for local server
15 /// Port used for local server
16 const auto AMDA_LOCAL_SERVER_PORT = 6543;
16 const auto AMDA_LOCAL_SERVER_PORT = 6543;
17
17
18 /// URL of the local server
18 /// URL of the local server
19 const auto AMDA_LOCAL_SERVER_URL
19 const auto AMDA_LOCAL_SERVER_URL
20 = QString{"localhost:%1"}.arg(QString::number(AMDA_LOCAL_SERVER_PORT));
20 = QString{"localhost:%1"}.arg(QString::number(AMDA_LOCAL_SERVER_PORT));
21
21
22 /// Default AMDA server
22 /// Default AMDA server
23 struct AmdaDefaultServer : public AmdaServer {
23 struct AmdaDefaultServer : public AmdaServer {
24 public:
24 public:
25 QString name() const override { return QStringLiteral("AMDA (default)"); }
25 QString name() const override { return QStringLiteral("AMDA (default)"); }
26 QString url(const QVariantHash &properties) const override
26 QString url(const QVariantHash &properties) const override
27 {
27 {
28 Q_UNUSED(properties);
28 Q_UNUSED(properties);
29 return AMDA_DEFAULT_SERVER_URL;
29 return AMDA_DEFAULT_SERVER_URL;
30 }
30 }
31 };
31 };
32
32
33 /// Alternative AMDA server (tests)
33 /// Alternative AMDA server (tests)
34 struct AmdaTestServer : public AmdaServer {
34 struct AmdaTestServer : public AmdaServer {
35 public:
35 public:
36 QString name() const override { return QStringLiteral("AMDA (test)"); }
36 QString name() const override { return QStringLiteral("AMDA (test)"); }
37 QString url(const QVariantHash &properties) const override
37 QString url(const QVariantHash &properties) const override
38 {
38 {
39 Q_UNUSED(properties);
39 Q_UNUSED(properties);
40 return AMDA_TEST_SERVER_URL;
40 return AMDA_TEST_SERVER_URL;
41 }
41 }
42 };
42 };
43
43
44 /// Hybrid AMDA server: use both of default and test server.
44 /// Hybrid AMDA server: use both of default and test server.
45 /// The server used is relative to each product for which to retrieve url, according to its "server"
45 /// The server used is relative to each product for which to retrieve url, according to its "server"
46 /// property
46 /// property
47 struct AmdaHybridServer : public AmdaServer {
47 struct AmdaHybridServer : public AmdaServer {
48 public:
48 public:
49 QString name() const override { return QStringLiteral("AMDA (hybrid)"); }
49 QString name() const override { return QStringLiteral("AMDA (hybrid)"); }
50 QString url(const QVariantHash &properties) const override
50 QString url(const QVariantHash &properties) const override
51 {
51 {
52 // Reads "server" property to determine which server url to use
52 // Reads "server" property to determine which server url to use
53 auto server = properties.value(AMDA_SERVER_KEY).toString();
53 auto server = properties.value(AMDA_SERVER_KEY).toString();
54 return server == QString{"amdatest"} ? AMDA_TEST_SERVER_URL : AMDA_DEFAULT_SERVER_URL;
54 return server == QString{"amdatest"} ? AMDA_TEST_SERVER_URL : AMDA_DEFAULT_SERVER_URL;
55 }
55 }
56 };
56 };
57
57
58 /// Local AMDA server: use local python server to simulate AMDA requests
58 /// Local AMDA server: use local python server to simulate AMDA requests
59 struct AmdaLocalServer : public AmdaServer {
59 struct AmdaLocalServer : public AmdaServer {
60 public:
60 public:
61 QString name() const override { return AMDA_LOCAL_SERVER_URL; }
61 QString name() const override { return AMDA_LOCAL_SERVER_URL; }
62 QString url(const QVariantHash &properties) const override
62 QString url(const QVariantHash &properties) const override
63 {
63 {
64 Q_UNUSED(properties);
64 Q_UNUSED(properties);
65 return AMDA_LOCAL_SERVER_URL;
65 return AMDA_LOCAL_SERVER_URL;
66 }
66 }
67 };
67 };
68
68
69 /// @return an AMDA server instance created from the name of the server passed in parameter. If the
69 /// @return an AMDA server instance created from the name of the server passed in parameter. If the
70 /// name does not match any known server, a default server instance is created
70 /// name does not match any known server, a default server instance is created
71 std::unique_ptr<AmdaServer> createInstance(const QString &server)
71 std::unique_ptr<AmdaServer> createInstance(const QString &server)
72 {
72 {
73 if (server == QString{"amdatest"}) {
73 if (server == QString{"amdatest"}) {
74 return std::make_unique<AmdaTestServer>();
74 return std::make_unique<AmdaTestServer>();
75 }
75 }
76 else if (server == QString{"hybrid"}) {
76 else if (server == QString{"hybrid"}) {
77 return std::make_unique<AmdaHybridServer>();
77 return std::make_unique<AmdaHybridServer>();
78 }
78 }
79 else if (server == QString{"localhost"}) {
79 else if (server == QString{"localhost"}) {
80 return std::make_unique<AmdaLocalServer>();
80 return std::make_unique<AmdaLocalServer>();
81 }
81 }
82 else {
82 else {
83 if (server != QString{"default"}) {
83 if (server != QString{"default"}) {
84 qCWarning(LOG_AmdaServer())
84 qCWarning(LOG_AmdaServer())
85 << QObject::tr("Unknown server '%1': default AMDA server will be used").arg(server);
85 << QObject::tr("Unknown server '%1': default AMDA server will be used").arg(server);
86 }
86 }
87
87
88 return std::make_unique<AmdaDefaultServer>();
88 return std::make_unique<AmdaDefaultServer>();
89 }
89 }
90 }
90 }
91
91
92 } // namespace
92 } // namespace
93
93
94 AmdaServer &AmdaServer::instance()
94 AmdaServer &AmdaServer::instance()
95 {
95 {
96 // Creates instance depending on the SCIQLOP_AMDA_SERVER value at compile time
96 // Creates instance depending on the SCIQLOP_AMDA_SERVER value at compile time
97 static auto instance = createInstance(SCIQLOP_AMDA_SERVER);
97 static auto instance = createInstance(SCIQLOP_AMDA_SERVER);
98 return *instance;
98 return *instance;
99 }
99 }
@@ -1,199 +1,199
1 #include "CosinusProvider.h"
1 #include "CosinusProvider.h"
2 #include "MockDefs.h"
2 #include "MockDefs.h"
3
3
4 #include <Data/DataProviderParameters.h>
4 #include <Data/DataProviderParameters.h>
5 #include <Data/ScalarSeries.h>
5 #include <Data/ScalarSeries.h>
6 #include <Data/SpectrogramSeries.h>
6 #include <Data/SpectrogramSeries.h>
7 #include <Data/VectorSeries.h>
7 #include <Data/VectorSeries.h>
8
8
9 #include <cmath>
9 #include <cmath>
10 #include <set>
10 #include <set>
11
11
12 #include <QFuture>
12 #include <QFuture>
13 #include <QThread>
13 #include <QThread>
14 #include <QtConcurrent/QtConcurrent>
14 #include <QtConcurrent/QtConcurrent>
15
15
16
16
17 namespace {
17 namespace {
18
18
19 /// Number of bands generated for a spectrogram
19 /// Number of bands generated for a spectrogram
20 const auto SPECTROGRAM_NUMBER_BANDS = 30;
20 const auto SPECTROGRAM_NUMBER_BANDS = 30;
21
21
22 /// Bands for which to generate NaN values for a spectrogram
22 /// Bands for which to generate NaN values for a spectrogram
23 const auto SPECTROGRAM_NAN_BANDS = std::set<int>{1, 3, 10, 20};
23 const auto SPECTROGRAM_NAN_BANDS = std::set<int>{1, 3, 10, 20};
24
24
25 /// Bands for which to generate zeros for a spectrogram
25 /// Bands for which to generate zeros for a spectrogram
26 const auto SPECTROGRAM_ZERO_BANDS = std::set<int>{2, 15, 19, 29};
26 const auto SPECTROGRAM_ZERO_BANDS = std::set<int>{2, 15, 19, 29};
27
27
28 /// Abstract cosinus type
28 /// Abstract cosinus type
29 struct ICosinusType {
29 struct ICosinusType {
30 virtual ~ICosinusType() = default;
30 virtual ~ICosinusType() = default;
31 /// @return the number of components generated for the type
31 /// @return the number of components generated for the type
32 virtual std::size_t componentCount() const = 0;
32 virtual std::size_t componentCount() const = 0;
33 /// @return the data series created for the type
33 /// @return the data series created for the type
34 virtual IDataSeries* createDataSeries(std::vector<double> xAxisData,
34 virtual IDataSeries* createDataSeries(std::vector<double> xAxisData,
35 std::vector<double> valuesData) const = 0;
35 std::vector<double> valuesData) const = 0;
36 /// Generates values (one value per component)
36 /// Generates values (one value per component)
37 /// @param x the x-axis data used to generate values
37 /// @param x the x-axis data used to generate values
38 /// @param values the vector in which to insert the generated values
38 /// @param values the vector in which to insert the generated values
39 /// @param dataIndex the index of insertion of the generated values
39 /// @param dataIndex the index of insertion of the generated values
40 ///
40 ///
41 virtual void generateValues(double x, std::vector<double> &values, int dataIndex) const = 0;
41 virtual void generateValues(double x, std::vector<double> &values, int dataIndex) const = 0;
42 };
42 };
43
43
44 struct ScalarCosinus : public ICosinusType {
44 struct ScalarCosinus : public ICosinusType {
45 std::size_t componentCount() const override { return 1; }
45 std::size_t componentCount() const override { return 1; }
46
46
47 IDataSeries* createDataSeries(std::vector<double> xAxisData,
47 IDataSeries* createDataSeries(std::vector<double> xAxisData,
48 std::vector<double> valuesData) const override
48 std::vector<double> valuesData) const override
49 {
49 {
50 return new ScalarSeries(std::move(xAxisData), std::move(valuesData),
50 return new ScalarSeries(std::move(xAxisData), std::move(valuesData),
51 Unit{QStringLiteral("t"), true}, Unit{});
51 Unit{QStringLiteral("t"), true}, Unit{});
52 }
52 }
53
53
54 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
54 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
55 {
55 {
56 values[dataIndex] = std::cos(x);
56 values[dataIndex] = std::cos(x);
57 }
57 }
58 };
58 };
59
59
60 struct SpectrogramCosinus : public ICosinusType {
60 struct SpectrogramCosinus : public ICosinusType {
61 /// Ctor with y-axis
61 /// Ctor with y-axis
62 explicit SpectrogramCosinus(std::vector<double> yAxisData, Unit yAxisUnit, Unit valuesUnit)
62 explicit SpectrogramCosinus(std::vector<double> yAxisData, Unit yAxisUnit, Unit valuesUnit)
63 : m_YAxisData{std::move(yAxisData)},
63 : m_YAxisData{std::move(yAxisData)},
64 m_YAxisUnit{std::move(yAxisUnit)},
64 m_YAxisUnit{std::move(yAxisUnit)},
65 m_ValuesUnit{std::move(valuesUnit)}
65 m_ValuesUnit{std::move(valuesUnit)}
66 {
66 {
67 }
67 }
68
68
69 std::size_t componentCount() const override { return m_YAxisData.size(); }
69 std::size_t componentCount() const override { return m_YAxisData.size(); }
70
70
71 IDataSeries* createDataSeries(std::vector<double> xAxisData,
71 IDataSeries* createDataSeries(std::vector<double> xAxisData,
72 std::vector<double> valuesData) const override
72 std::vector<double> valuesData) const override
73 {
73 {
74 return new SpectrogramSeries(
74 return new SpectrogramSeries(
75 std::move(xAxisData), m_YAxisData, std::move(valuesData),
75 std::move(xAxisData), m_YAxisData, std::move(valuesData),
76 Unit{QStringLiteral("t"), true}, m_YAxisUnit, m_ValuesUnit);
76 Unit{QStringLiteral("t"), true}, m_YAxisUnit, m_ValuesUnit);
77 }
77 }
78
78
79 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
79 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
80 {
80 {
81 auto componentCount = this->componentCount();
81 auto componentCount = this->componentCount();
82 for (int i = 0; i < componentCount; ++i) {
82 for (int i = 0; i < componentCount; ++i) {
83 auto y = m_YAxisData[i];
83 auto y = m_YAxisData[i];
84
84
85 double value;
85 double value;
86
86
87 if (SPECTROGRAM_ZERO_BANDS.find(y) != SPECTROGRAM_ZERO_BANDS.end()) {
87 if (SPECTROGRAM_ZERO_BANDS.find(y) != SPECTROGRAM_ZERO_BANDS.end()) {
88 value = 0.;
88 value = 0.;
89 }
89 }
90 else if (SPECTROGRAM_NAN_BANDS.find(y) != SPECTROGRAM_NAN_BANDS.end()) {
90 else if (SPECTROGRAM_NAN_BANDS.find(y) != SPECTROGRAM_NAN_BANDS.end()) {
91 value = std::numeric_limits<double>::quiet_NaN();
91 value = std::numeric_limits<double>::quiet_NaN();
92 }
92 }
93 else {
93 else {
94 // Generates value for non NaN/zero bands
94 // Generates value for non NaN/zero bands
95 auto r = 3 * std::sqrt(x * x + y * y) + 1e-2;
95 auto r = 3 * std::sqrt(x * x + y * y) + 1e-2;
96 value = 2 * x * (std::cos(r + 2) / r - std::sin(r + 2) / r);
96 value = 2 * x * (std::cos(r + 2) / r - std::sin(r + 2) / r);
97 }
97 }
98
98
99 values[componentCount * dataIndex + i] = value;
99 values[componentCount * dataIndex + i] = value;
100 }
100 }
101 }
101 }
102
102
103 std::vector<double> m_YAxisData;
103 std::vector<double> m_YAxisData;
104 Unit m_YAxisUnit;
104 Unit m_YAxisUnit;
105 Unit m_ValuesUnit;
105 Unit m_ValuesUnit;
106 };
106 };
107
107
108 struct VectorCosinus : public ICosinusType {
108 struct VectorCosinus : public ICosinusType {
109 std::size_t componentCount() const override { return 3; }
109 std::size_t componentCount() const override { return 3; }
110
110
111 IDataSeries* createDataSeries(std::vector<double> xAxisData,
111 IDataSeries* createDataSeries(std::vector<double> xAxisData,
112 std::vector<double> valuesData) const override
112 std::vector<double> valuesData) const override
113 {
113 {
114 return new VectorSeries(std::move(xAxisData), std::move(valuesData),
114 return new VectorSeries(std::move(xAxisData), std::move(valuesData),
115 Unit{QStringLiteral("t"), true}, Unit{});
115 Unit{QStringLiteral("t"), true}, Unit{});
116 }
116 }
117
117
118 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
118 void generateValues(double x, std::vector<double> &values, int dataIndex) const override
119 {
119 {
120 // Generates value for each component: cos(x), cos(x)/2, cos(x)/3
120 // Generates value for each component: cos(x), cos(x)/2, cos(x)/3
121 auto xValue = std::cos(x);
121 auto xValue = std::cos(x);
122 auto componentCount = this->componentCount();
122 auto componentCount = this->componentCount();
123 for (auto i = 0; i < componentCount; ++i) {
123 for (auto i = 0; i < componentCount; ++i) {
124 values[componentCount * dataIndex + i] = xValue / (i + 1);
124 values[componentCount * dataIndex + i] = xValue / (i + 1);
125 }
125 }
126 }
126 }
127 };
127 };
128
128
129 /// Converts string to cosinus type
129 /// Converts string to cosinus type
130 /// @return the cosinus type if the string could be converted, nullptr otherwise
130 /// @return the cosinus type if the string could be converted, nullptr otherwise
131 std::unique_ptr<ICosinusType> cosinusType(const QString &type) noexcept
131 std::unique_ptr<ICosinusType> cosinusType(const QString &type) noexcept
132 {
132 {
133 if (type.compare(QStringLiteral("scalar"), Qt::CaseInsensitive) == 0) {
133 if (type.compare(QStringLiteral("scalar"), Qt::CaseInsensitive) == 0) {
134 return std::make_unique<ScalarCosinus>();
134 return std::make_unique<ScalarCosinus>();
135 }
135 }
136 else if (type.compare(QStringLiteral("spectrogram"), Qt::CaseInsensitive) == 0) {
136 else if (type.compare(QStringLiteral("spectrogram"), Qt::CaseInsensitive) == 0) {
137 // Generates default y-axis data for spectrogram [0., 1., 2., ...]
137 // Generates default y-axis data for spectrogram [0., 1., 2., ...]
138 std::vector<double> yAxisData(SPECTROGRAM_NUMBER_BANDS);
138 std::vector<double> yAxisData(SPECTROGRAM_NUMBER_BANDS);
139 std::iota(yAxisData.begin(), yAxisData.end(), 0.);
139 std::iota(yAxisData.begin(), yAxisData.end(), 0.);
140
140
141 return std::make_unique<SpectrogramCosinus>(std::move(yAxisData), Unit{"eV"},
141 return std::make_unique<SpectrogramCosinus>(std::move(yAxisData), Unit{"eV"},
142 Unit{"eV/(cm^2-s-sr-eV)"});
142 Unit{"eV/(cm^2-s-sr-eV)"});
143 }
143 }
144 else if (type.compare(QStringLiteral("vector"), Qt::CaseInsensitive) == 0) {
144 else if (type.compare(QStringLiteral("vector"), Qt::CaseInsensitive) == 0) {
145 return std::make_unique<VectorCosinus>();
145 return std::make_unique<VectorCosinus>();
146 }
146 }
147 else {
147 else {
148 return nullptr;
148 return nullptr;
149 }
149 }
150 }
150 }
151
151
152 } // namespace
152 } // namespace
153
153
154 std::shared_ptr<IDataProvider> CosinusProvider::clone() const
154 std::shared_ptr<IDataProvider> CosinusProvider::clone() const
155 {
155 {
156 // No copy is made in clone
156 // No copy is made in clone
157 return std::make_shared<CosinusProvider>();
157 return std::make_shared<CosinusProvider>();
158 }
158 }
159
159
160 IDataSeries *CosinusProvider::_generate(const DateTimeRange &range, const QVariantHash &metaData)
160 IDataSeries *CosinusProvider::_generate(const DateTimeRange &range, const QVariantHash &metaData)
161 {
161 {
162 auto dataIndex = 0;
162 auto dataIndex = 0;
163
163
164 // Retrieves cosinus type
164 // Retrieves cosinus type
165 auto typeVariant = metaData.value(COSINUS_TYPE_KEY, COSINUS_TYPE_DEFAULT_VALUE);
165 auto typeVariant = metaData.value(COSINUS_TYPE_KEY, COSINUS_TYPE_DEFAULT_VALUE);
166 auto type = cosinusType(typeVariant.toString());
166 auto type = cosinusType(typeVariant.toString());
167 auto freqVariant = metaData.value(COSINUS_FREQUENCY_KEY, COSINUS_FREQUENCY_DEFAULT_VALUE);
167 auto freqVariant = metaData.value(COSINUS_FREQUENCY_KEY, COSINUS_FREQUENCY_DEFAULT_VALUE);
168 double freq = freqVariant.toDouble();
168 double freq = freqVariant.toDouble();
169 double start = std::ceil(range.m_TStart * freq);
169 double start = std::ceil(range.m_TStart * freq);
170 double end = std::floor(range.m_TEnd * freq);
170 double end = std::floor(range.m_TEnd * freq);
171 if (end < start) {
171 if (end < start) {
172 std::swap(start, end);
172 std::swap(start, end);
173 }
173 }
174 std::size_t dataCount = static_cast<std::size_t>(end - start + 1);
174 std::size_t dataCount = static_cast<std::size_t>(end - start + 1);
175 std::size_t componentCount = type->componentCount();
175 std::size_t componentCount = type->componentCount();
176
176
177 auto xAxisData = std::vector<double>{};
177 auto xAxisData = std::vector<double>{};
178 xAxisData.resize(dataCount);
178 xAxisData.resize(dataCount);
179
179
180 auto valuesData = std::vector<double>{};
180 auto valuesData = std::vector<double>{};
181 valuesData.resize(dataCount * componentCount);
181 valuesData.resize(dataCount * componentCount);
182
182
183 int progress = 0;
183 int progress = 0;
184 auto progressEnd = dataCount;
184 auto progressEnd = dataCount;
185 for (auto time = start; time <= end; ++time, ++dataIndex)
185 for (auto time = start; time <= end; ++time, ++dataIndex)
186 {
186 {
187 const auto x = time / freq;
187 const auto x = time / freq;
188 xAxisData[dataIndex] = x;
188 xAxisData[dataIndex] = x;
189 // Generates values (depending on the type)
189 // Generates values (depending on the type)
190 type->generateValues(x, valuesData, dataIndex);
190 type->generateValues(x, valuesData, dataIndex);
191 }
191 }
192 return type->createDataSeries(std::move(xAxisData), std::move(valuesData));
192 return type->createDataSeries(std::move(xAxisData), std::move(valuesData));
193 }
193 }
194
194
195 IDataSeries* CosinusProvider::getData(const DataProviderParameters &parameters)
195 IDataSeries* CosinusProvider::getData(const DataProviderParameters &parameters)
196 {
196 {
197 return _generate(parameters.m_Times.front(),parameters.m_Data);
197 return _generate(parameters.m_Range, parameters.m_Data);
198 }
198 }
199
199
General Comments 0
You need to be logged in to leave comments. Login now