##// END OF EJS Templates
Made core module a git submodule, ready to start switching to new...
jeandet -
r1347:17e0dafec10c
parent child
Show More
@@ -0,0 +1,1
1 Subproject commit 5a50815a763fb421298a06a6d0380b8f5364e7cd
@@ -1,9 +1,6
1 [submodule "external/CatalogueAPI"]
2 path = external/CatalogueAPI
3 url = https://hephaistos.lpp.polytechnique.fr/rhodecode/HG_REPOSITORIES/LPP/INSTRUMENTATION/USERS/JEANDET/CatalogueAPI
4 [submodule "external/libcatalogs"]
5 path = external/libcatalogs
6 url = https://hephaistos.lpp.polytechnique.fr/rhodecode/HG_REPOSITORIES/LPP/SciQLOP_Repos/libcatalogs
7 1 [submodule "external/pybind11"]
8 2 path = external/pybind11
9 3 url = https://github.com/pybind/pybind11
4 [submodule "core"]
5 path = core
6 url = https://hephaistos.lpp.polytechnique.fr/rhodecode/HG_REPOSITORIES/LPP/INSTRUMENTATION/USERS/JEANDET/SciQLOPCore
@@ -1,69 +1,54
1 1 cmake_minimum_required(VERSION 3.6)
2 2 project(SciQLOP CXX)
3 3
4 4 include(GNUInstallDirs)
5 5
6 6 SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/cmake")
7 7
8 8 OPTION (CPPCHECK "Analyzes the source code with cppcheck" OFF)
9 9 OPTION (CLANG_TIDY "Analyzes the source code with Clang Tidy" OFF)
10 10 OPTION (IWYU "Analyzes the source code with Include What You Use" OFF)
11 11
12 set(CMAKE_CXX_STANDARD 14)
12 set(CMAKE_CXX_STANDARD 17)
13 13
14 14 set(CMAKE_AUTOMOC ON)
15 15 #https://gitlab.kitware.com/cmake/cmake/issues/15227
16 16 #set(CMAKE_AUTOUIC ON)
17 17 if(POLICY CMP0071)
18 18 cmake_policy(SET CMP0071 OLD)
19 19 endif()
20 20 set(CMAKE_AUTORCC ON)
21 21 set(CMAKE_INCLUDE_CURRENT_DIR ON)
22 22
23 23 if(NOT DEFINED CMAKE_INSTALL_RPATH_USE_LINK_PATH)
24 24 set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
25 25 endif()
26 26 if(NOT DEFINED CMAKE_MACOSX_RPATH)
27 27 set(CMAKE_MACOSX_RPATH TRUE)
28 28 endif()
29 29
30 30 if(NOT CMAKE_BUILD_TYPE)
31 31 set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE)
32 32 endif()
33 33
34 34 find_package(Qt5 COMPONENTS Core Widgets Network PrintSupport Svg Test REQUIRED)
35 35
36 36 IF(CPPCHECK)
37 37 set(CMAKE_CXX_CPPCHECK "cppcheck;--enable=warning,style")
38 38 ENDIF(CPPCHECK)
39 39
40 40 IF(CLANG_TIDY)
41 41 set(CMAKE_CXX_CLANG_TIDY "clang-tidy;-style=file;-checks=*")
42 42 ENDIF(CLANG_TIDY)
43 43
44 44 IF(IWYU)
45 45 set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "include-what-you-use")
46 46 ENDIF(IWYU)
47 47
48 48 enable_testing()
49 49
50
51 find_package(catalogs CONFIG QUIET)
52 if (NOT CatalogueAPI_FOUND)
53 execute_process(COMMAND git submodule init external/libcatalogs WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
54 execute_process(COMMAND git submodule update external/libcatalogs WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
55 add_subdirectory(external/libcatalogs)
56 endif()
57
58 find_package(pybind11 CONFIG QUIET)
59 if (NOT pybind11_FOUND)
60 execute_process(COMMAND git submodule init external/pybind11 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
61 execute_process(COMMAND git submodule update external/pybind11 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
62 add_subdirectory(external/pybind11)
63 endif()
64
65 50 add_subdirectory(core)
66 51 add_subdirectory(gui)
67 52 add_subdirectory(app)
68 53 add_subdirectory(plugins)
69 54 add_subdirectory(docs)
@@ -1,47 +1,47
1 1 #ifndef SCIQLOP_TIMEWIDGET_H
2 2 #define SCIQLOP_TIMEWIDGET_H
3 3
4 4 #include <QWidget>
5 5
6 #include <Data/SqpRange.h>
6 #include <Data/DateTimeRange.h>
7 7
8 8 #include <Common/spimpl.h>
9 9
10 10 namespace Ui {
11 11 class TimeWidget;
12 12 } // Ui
13 13
14 14 class TimeWidget : public QWidget {
15 15 Q_OBJECT
16 16
17 17 public:
18 18 explicit TimeWidget(QWidget *parent = 0);
19 19 virtual ~TimeWidget();
20 20
21 21 void setTimeRange(DateTimeRange time);
22 22 DateTimeRange timeRange() const;
23 23
24 24 signals:
25 25 /// Signal emitted when the time parameters has beed updated
26 26 void timeUpdated(DateTimeRange time);
27 27
28 28 public slots:
29 29 /// slot called when time parameters update has ben requested
30 30 void onTimeUpdateRequested();
31 31
32 32 protected:
33 33 void dragEnterEvent(QDragEnterEvent *event) override;
34 34 void dragLeaveEvent(QDragLeaveEvent *event) override;
35 35 void dropEvent(QDropEvent *event) override;
36 36
37 37 void mousePressEvent(QMouseEvent *event) override;
38 38 void mouseMoveEvent(QMouseEvent *event) override;
39 39
40 40 private:
41 41 Ui::TimeWidget *ui;
42 42
43 43 class TimeWidgetPrivate;
44 44 spimpl::unique_impl_ptr<TimeWidgetPrivate> impl;
45 45 };
46 46
47 47 #endif // SCIQLOP_ SQPSIDEPANE_H
@@ -1,41 +1,41
1 1 #ifndef SCIQLOP_VISUALIZATIONGRAPHHELPER_H
2 2 #define SCIQLOP_VISUALIZATIONGRAPHHELPER_H
3 3
4 4 #include "Visualization/VisualizationDefs.h"
5 5
6 #include <Data/SqpRange.h>
6 #include <Data/DateTimeRange.h>
7 7
8 8 #include <QLoggingCategory>
9 9 #include <QVector>
10 10
11 11 #include <memory>
12 12
13 13 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphHelper)
14 14
15 15 class IDataSeries;
16 16 class QCPAbstractPlottable;
17 17 class QCustomPlot;
18 18 class Variable;
19 19
20 20 /**
21 21 * @brief The VisualizationGraphHelper class aims to create the QCustomPlot components relative to a
22 22 * variable, depending on the data series of this variable
23 23 */
24 24 struct VisualizationGraphHelper {
25 25 /**
26 26 * Creates (if possible) the QCustomPlot components relative to the variable passed in
27 27 * parameter, and adds these to the plot passed in parameter.
28 28 * @param variable the variable for which to create the components
29 29 * @param plot the plot in which to add the created components. It takes ownership of these
30 30 * components.
31 31 * @return the list of the components created
32 32 */
33 33 static PlottablesMap create(std::shared_ptr<Variable> variable, QCustomPlot &plot) noexcept;
34 34
35 35 static void updateData(PlottablesMap &plottables, std::shared_ptr<Variable> variable,
36 36 const DateTimeRange &dateTime);
37 37
38 38 static void setYAxisRange(std::shared_ptr<Variable> variable, QCustomPlot &plot) noexcept;
39 39 };
40 40
41 41 #endif // SCIQLOP_VISUALIZATIONGRAPHHELPER_H
@@ -1,73 +1,73
1 1 #ifndef SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
2 2 #define SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
3 3
4 4 #include <Common/spimpl.h>
5 #include <Data/SqpRange.h>
5 #include <Data/DateTimeRange.h>
6 6 #include <Visualization/qcustomplot.h>
7 7
8 8 class VisualizationGraphWidget;
9 9
10 10 class VisualizationSelectionZoneItem : public QCPItemRect {
11 11 Q_OBJECT
12 12
13 13 signals:
14 14 /// Signal emitted when the zone range is edited manually
15 15 void rangeEdited(const DateTimeRange &range);
16 16
17 17 public:
18 18 VisualizationSelectionZoneItem(QCustomPlot *plot);
19 19 virtual ~VisualizationSelectionZoneItem();
20 20
21 21 VisualizationGraphWidget *parentGraphWidget() const noexcept;
22 22
23 23 void setName(const QString &name);
24 24 QString name() const;
25 25
26 26 DateTimeRange range() const;
27 27 void setRange(double tstart, double tend);
28 28 void setStart(double tstart);
29 29 void setEnd(double tend);
30 30
31 31 void setColor(const QColor &color);
32 32
33 33 void setEditionEnabled(bool value);
34 34 bool isEditionEnabled() const;
35 35
36 36 /// Moves the item at the top of its QCPLayer. It will then receive the mouse events if multiple
37 37 /// items are stacked on top of each others.
38 38 void moveToTop();
39 39
40 40 Qt::CursorShape curshorShapeForPosition(const QPoint &position) const;
41 41 void setHovered(bool value);
42 42
43 43 /// Sets the zones which should be moved or reisized together with this zone
44 44 void setAssociatedEditedZones(const QVector<VisualizationSelectionZoneItem *> &associatedZones);
45 45
46 46 /// Align the specified zones with this one, vertically with the left border
47 47 bool alignZonesVerticallyOnLeft(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
48 48 bool allowResize);
49 49 /// Align the specified zones with this one, vertically with the right border
50 50 bool alignZonesVerticallyOnRight(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
51 51 bool allowResize);
52 52 /// Align the specified zones with this one, temporally with the left border
53 53 bool alignZonesTemporallyOnLeft(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
54 54 bool allowResize);
55 55 /// Align the specified zones with this one, temporally with the right border
56 56 bool alignZonesTemporallyOnRight(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
57 57 bool allowResize);
58 58
59 59 protected:
60 60 void mousePressEvent(QMouseEvent *event, const QVariant &details) override;
61 61 void mouseMoveEvent(QMouseEvent *event, const QPointF &startPos) override;
62 62 void mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos) override;
63 63
64 64 void resizeLeft(double pixelDiff);
65 65 void resizeRight(double pixelDiff);
66 66 void move(double pixelDiff);
67 67
68 68 private:
69 69 class VisualizationSelectionZoneItemPrivate;
70 70 spimpl::unique_impl_ptr<VisualizationSelectionZoneItemPrivate> impl;
71 71 };
72 72
73 73 #endif // SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
@@ -1,65 +1,65
1 1 #ifndef SCIQLOP_VISUALIZATIONWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONWIDGET_H
3 3
4 4 #include "Visualization/IVisualizationWidget.h"
5 #include <Data/SqpRange.h>
5 #include <Data/DateTimeRange.h>
6 6
7 7 #include <QLoggingCategory>
8 8 #include <QWidget>
9 9
10 10 #include <Common/spimpl.h>
11 11
12 12 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationWidget)
13 13
14 14 class QMenu;
15 15 class Variable;
16 16 class VisualizationTabWidget;
17 17 class VisualizationSelectionZoneManager;
18 18
19 19 namespace Ui {
20 20 class VisualizationWidget;
21 21 } // namespace Ui
22 22
23 23 class VisualizationWidget : public QWidget, public IVisualizationWidget {
24 24 Q_OBJECT
25 25
26 26 public:
27 27 explicit VisualizationWidget(QWidget *parent = 0);
28 28 virtual ~VisualizationWidget();
29 29
30 30 /// Returns the class which manage the selection of selection zone across the visualization
31 31 VisualizationSelectionZoneManager &selectionZoneManager() const;
32 32
33 33 VisualizationTabWidget *currentTabWidget() const;
34 34
35 35 // IVisualizationWidget interface
36 36 void accept(IVisualizationWidgetVisitor *visitor) override;
37 37 bool canDrop(const Variable &variable) const override;
38 38 bool contains(const Variable &variable) const override;
39 39 QString name() const override;
40 40
41 41 public slots:
42 42 /**
43 43 * Attaches to a menu the menu relative to the visualization of variables
44 44 * @param menu the parent menu of the generated menu
45 45 * @param variables the variables for which to generate the menu
46 46 */
47 47 void attachVariableMenu(QMenu *menu,
48 48 const QVector<std::shared_ptr<Variable> > &variables) noexcept;
49 49
50 50 /// Slot called when a variable is about to be deleted from SciQlop
51 51 void onVariableAboutToBeDeleted(std::shared_ptr<Variable> variable) noexcept;
52 52
53 53 void onRangeChanged(std::shared_ptr<Variable> variable, const DateTimeRange &range) noexcept;
54 54
55 55 protected:
56 56 void closeEvent(QCloseEvent *event) override;
57 57
58 58 private:
59 59 Ui::VisualizationWidget *ui;
60 60
61 61 class VisualizationWidgetPrivate;
62 62 spimpl::unique_impl_ptr<VisualizationWidgetPrivate> impl;
63 63 };
64 64
65 65 #endif // VISUALIZATIONWIDGET_H
@@ -1,106 +1,106
1 1 #ifndef SCIQLOP_VISUALIZATIONZONEWIDGET_H
2 2 #define SCIQLOP_VISUALIZATIONZONEWIDGET_H
3 3
4 #include "Data/SqpRange.h"
4 #include "Data/DateTimeRange.h"
5 5 #include "Visualization/IVisualizationWidget.h"
6 6 #include "Visualization/VisualizationDragWidget.h"
7 7
8 8 #include <QLoggingCategory>
9 9 #include <QWidget>
10 10
11 11 #include <memory>
12 12
13 13 #include <Common/spimpl.h>
14 14
15 15 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationZoneWidget)
16 16
17 17 namespace Ui {
18 18 class VisualizationZoneWidget;
19 19 } // namespace Ui
20 20
21 21 class Variable;
22 22 class VisualizationGraphWidget;
23 23
24 24 class VisualizationZoneWidget : public VisualizationDragWidget, public IVisualizationWidget {
25 25 Q_OBJECT
26 26
27 27 public:
28 28 explicit VisualizationZoneWidget(const QString &name = {}, QWidget *parent = 0);
29 29 virtual ~VisualizationZoneWidget();
30 30
31 31 /// Sets the range of the zone, only works if there is at least one graph in the zone
32 32 /// Note: calibrations between graphs are lost.
33 33 void setZoneRange(const DateTimeRange &range);
34 34
35 35 /// Adds a graph widget
36 36 void addGraph(VisualizationGraphWidget *graphWidget);
37 37
38 38 /// Inserts a graph widget
39 39 void insertGraph(int index, VisualizationGraphWidget *graphWidget);
40 40
41 41 /**
42 42 * Creates a graph using a variable. The variable will be displayed in the new graph.
43 43 * The graph is added at the end.
44 44 * @param variable the variable for which to create the graph
45 45 * @return the pointer to the created graph
46 46 */
47 47 VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable);
48 48
49 49 /**
50 50 * Creates a graph using a variable. The variable will be displayed in the new graph.
51 51 * The graph is inserted at the specified index.
52 52 * @param variable the variable for which to create the graph
53 53 * @param index The index where the graph should be inserted in the layout
54 54 * @return the pointer to the created graph
55 55 */
56 56 VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable, int index);
57 57
58 58 /**
59 59 * Creates a graph using a list of variables. The variables will be displayed in the new graph.
60 60 * The graph is inserted at the specified index.
61 61 * @param variables List of variables to be added to the graph
62 62 * @param index The index where the graph should be inserted in the layout
63 63 * @return the pointer to the created graph
64 64 */
65 65 VisualizationGraphWidget *createGraph(const QList<std::shared_ptr<Variable> > variables,
66 66 int index);
67 67
68 68 /// Returns the first graph in the zone or nullptr if there is no graph inside
69 69 VisualizationGraphWidget *firstGraph() const;
70 70
71 71 /// Closes all graphes inside the zone
72 72 void closeAllGraphs();
73 73
74 74 // IVisualizationWidget interface
75 75 void accept(IVisualizationWidgetVisitor *visitor) override;
76 76 bool canDrop(const Variable &variable) const override;
77 77 bool contains(const Variable &variable) const override;
78 78 QString name() const override;
79 79
80 80 // VisualisationDragWidget
81 81 QMimeData *mimeData(const QPoint &position) const override;
82 82 bool isDragAllowed() const override;
83 83
84 84 void notifyMouseMoveInGraph(const QPointF &graphPosition, const QPointF &plotPosition,
85 85 VisualizationGraphWidget *graphWidget);
86 86 void notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget);
87 87
88 88 protected:
89 89 void closeEvent(QCloseEvent *event) override;
90 90
91 91 private:
92 92 Ui::VisualizationZoneWidget *ui;
93 93
94 94 class VisualizationZoneWidgetPrivate;
95 95 spimpl::unique_impl_ptr<VisualizationZoneWidgetPrivate> impl;
96 96
97 97 private slots:
98 98 void onVariableAdded(std::shared_ptr<Variable> variable);
99 99 /// Slot called when a variable is about to be removed from a graph contained in the zone
100 100 void onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable);
101 101
102 102 void dropMimeData(int index, const QMimeData *mimeData);
103 103 void dropMimeDataOnGraph(VisualizationDragWidget *dragWidget, const QMimeData *mimeData);
104 104 };
105 105
106 106 #endif // SCIQLOP_VISUALIZATIONZONEWIDGET_H
@@ -1,42 +1,42
1 1 #ifndef SCIQLOP_RESCALEAXEOPERATION_H
2 2 #define SCIQLOP_RESCALEAXEOPERATION_H
3 3
4 4 #include "Visualization/IVisualizationWidgetVisitor.h"
5 #include <Data/SqpRange.h>
5 #include <Data/DateTimeRange.h>
6 6
7 7 #include <Common/spimpl.h>
8 8
9 9 #include <QLoggingCategory>
10 10
11 11 #include <memory>
12 12
13 13 class Variable;
14 14
15 15 Q_DECLARE_LOGGING_CATEGORY(LOG_RescaleAxeOperation)
16 16
17 17 /**
18 18 * @brief The RescaleAxeOperation class defines an operation that traverses all of visualization
19 19 * widgets to remove a variable if they contain it
20 20 */
21 21 class RescaleAxeOperation : public IVisualizationWidgetVisitor {
22 22 public:
23 23 /**
24 24 * Ctor
25 25 * @param variable the variable to remove from widgets
26 26 */
27 27 explicit RescaleAxeOperation(std::shared_ptr<Variable> variable, const DateTimeRange &range);
28 28
29 29 void visitEnter(VisualizationWidget *widget) override final;
30 30 void visitLeave(VisualizationWidget *widget) override final;
31 31 void visitEnter(VisualizationTabWidget *tabWidget) override final;
32 32 void visitLeave(VisualizationTabWidget *tabWidget) override final;
33 33 void visitEnter(VisualizationZoneWidget *zoneWidget) override final;
34 34 void visitLeave(VisualizationZoneWidget *zoneWidget) override final;
35 35 void visit(VisualizationGraphWidget *graphWidget) override final;
36 36
37 37 private:
38 38 class RescaleAxeOperationPrivate;
39 39 spimpl::unique_impl_ptr<RescaleAxeOperationPrivate> impl;
40 40 };
41 41
42 42 #endif // SCIQLOP_RESCALEAXEOPERATION_H
@@ -1,484 +1,484
1 1 #include "Catalogue/CatalogueEventsModel.h"
2 2
3 3 #include <Catalogue/CatalogueController.h>
4 4 #include <Common/DateUtils.h>
5 5 #include <Common/MimeTypesDef.h>
6 6 #include <DBEvent.h>
7 7 #include <DBEventProduct.h>
8 8 #include <DBTag.h>
9 #include <Data/SqpRange.h>
9 #include <Data/DateTimeRange.h>
10 10 #include <SqpApplication.h>
11 11 #include <Time/TimeController.h>
12 12
13 13 #include <list>
14 14 #include <unordered_map>
15 15
16 16 #include <QHash>
17 17 #include <QMimeData>
18 18
19 19 Q_LOGGING_CATEGORY(LOG_CatalogueEventsModel, "CatalogueEventsModel")
20 20
21 21 const auto EVENT_ITEM_TYPE = 1;
22 22 const auto EVENT_PRODUCT_ITEM_TYPE = 2;
23 23
24 24 struct CatalogueEventsModel::CatalogueEventsModelPrivate {
25 25 QVector<std::shared_ptr<DBEvent> > m_Events;
26 26 std::unordered_map<DBEvent *, QVector<std::shared_ptr<DBEventProduct> > > m_EventProducts;
27 27 QVector<std::shared_ptr<DBCatalogue> > m_SourceCatalogue;
28 28
29 29 QStringList columnNames()
30 30 {
31 31 return QStringList{tr("Event"), tr("TStart"), tr("TEnd"),
32 32 tr("Tags"), tr("Product"), tr("")};
33 33 }
34 34
35 35 QVariant sortData(int col, const std::shared_ptr<DBEvent> &event) const
36 36 {
37 37 if (col == (int)CatalogueEventsModel::Column::Validation) {
38 38 auto hasChanges = sqpApp->catalogueController().eventHasChanges(event);
39 39 return hasChanges ? true : QVariant();
40 40 }
41 41
42 42 return eventData(col, event);
43 43 }
44 44
45 45 QVariant eventData(int col, const std::shared_ptr<DBEvent> &event) const
46 46 {
47 47 switch (static_cast<Column>(col)) {
48 48 case CatalogueEventsModel::Column::Name:
49 49 return event->getName();
50 50 case CatalogueEventsModel::Column::TStart:
51 51 return nbEventProducts(event) > 0
52 52 ? DateUtils::dateTime(event->getTStart())
53 53 .toString(DATETIME_FORMAT_ONE_LINE)
54 54 : QVariant{};
55 55 case CatalogueEventsModel::Column::TEnd:
56 56 return nbEventProducts(event) > 0
57 57 ? DateUtils::dateTime(event->getTEnd())
58 58 .toString(DATETIME_FORMAT_ONE_LINE)
59 59 : QVariant{};
60 60 case CatalogueEventsModel::Column::Product: {
61 61 auto eventProducts = event->getEventProducts();
62 62 QStringList eventProductList;
63 63 for (auto evtProduct : eventProducts) {
64 64 eventProductList << evtProduct.getProductId();
65 65 }
66 66 return eventProductList.join(";");
67 67 }
68 68 case CatalogueEventsModel::Column::Tags: {
69 69 QString tagList;
70 70 auto tags = event->getTags();
71 71 for (auto tag : tags) {
72 72 tagList += tag.getName();
73 73 tagList += ' ';
74 74 }
75 75
76 76 return tagList;
77 77 }
78 78 case CatalogueEventsModel::Column::Validation:
79 79 return QVariant();
80 80 default:
81 81 break;
82 82 }
83 83
84 84 Q_ASSERT(false);
85 85 return QStringLiteral("Unknown Data");
86 86 }
87 87
88 88 void parseEventProduct(const std::shared_ptr<DBEvent> &event)
89 89 {
90 90 for (auto product : event->getEventProducts()) {
91 91 m_EventProducts[event.get()].append(std::make_shared<DBEventProduct>(product));
92 92 }
93 93 }
94 94
95 95 int nbEventProducts(const std::shared_ptr<DBEvent> &event) const
96 96 {
97 97 auto eventProductsIt = m_EventProducts.find(event.get());
98 98 if (eventProductsIt != m_EventProducts.cend()) {
99 99 return m_EventProducts.at(event.get()).count();
100 100 }
101 101 else {
102 102 return 0;
103 103 }
104 104 }
105 105
106 106 QVariant eventProductData(int col, const std::shared_ptr<DBEventProduct> &eventProduct) const
107 107 {
108 108 switch (static_cast<Column>(col)) {
109 109 case CatalogueEventsModel::Column::Name:
110 110 return eventProduct->getProductId();
111 111 case CatalogueEventsModel::Column::TStart:
112 112 return DateUtils::dateTime(eventProduct->getTStart())
113 113 .toString(DATETIME_FORMAT_ONE_LINE);
114 114 case CatalogueEventsModel::Column::TEnd:
115 115 return DateUtils::dateTime(eventProduct->getTEnd())
116 116 .toString(DATETIME_FORMAT_ONE_LINE);
117 117 case CatalogueEventsModel::Column::Product:
118 118 return eventProduct->getProductId();
119 119 case CatalogueEventsModel::Column::Tags:
120 120 return QString();
121 121 case CatalogueEventsModel::Column::Validation:
122 122 return QVariant();
123 123 default:
124 124 break;
125 125 }
126 126
127 127 Q_ASSERT(false);
128 128 return QStringLiteral("Unknown Data");
129 129 }
130 130
131 131 void refreshChildrenOfIndex(CatalogueEventsModel *model, const QModelIndex &index) const
132 132 {
133 133 auto childCount = model->rowCount(index);
134 134 auto colCount = model->columnCount();
135 135 emit model->dataChanged(model->index(0, 0, index),
136 136 model->index(childCount, colCount, index));
137 137 }
138 138 };
139 139
140 140 CatalogueEventsModel::CatalogueEventsModel(QObject *parent)
141 141 : QAbstractItemModel(parent), impl{spimpl::make_unique_impl<CatalogueEventsModelPrivate>()}
142 142 {
143 143 }
144 144
145 145 void CatalogueEventsModel::setSourceCatalogues(
146 146 const QVector<std::shared_ptr<DBCatalogue> > &catalogues)
147 147 {
148 148 impl->m_SourceCatalogue = catalogues;
149 149 }
150 150
151 151 void CatalogueEventsModel::setEvents(const QVector<std::shared_ptr<DBEvent> > &events)
152 152 {
153 153 beginResetModel();
154 154
155 155 impl->m_Events = events;
156 156 impl->m_EventProducts.clear();
157 157 for (auto event : events) {
158 158 impl->parseEventProduct(event);
159 159 }
160 160
161 161 endResetModel();
162 162 }
163 163
164 164 std::shared_ptr<DBEvent> CatalogueEventsModel::getEvent(const QModelIndex &index) const
165 165 {
166 166 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::Event) {
167 167 return impl->m_Events.value(index.row());
168 168 }
169 169 else {
170 170 return nullptr;
171 171 }
172 172 }
173 173
174 174 std::shared_ptr<DBEvent> CatalogueEventsModel::getParentEvent(const QModelIndex &index) const
175 175 {
176 176 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::EventProduct) {
177 177 return getEvent(index.parent());
178 178 }
179 179 else {
180 180 return nullptr;
181 181 }
182 182 }
183 183
184 184 std::shared_ptr<DBEventProduct>
185 185 CatalogueEventsModel::getEventProduct(const QModelIndex &index) const
186 186 {
187 187 if (itemTypeOf(index) == CatalogueEventsModel::ItemType::EventProduct) {
188 188 auto event = static_cast<DBEvent *>(index.internalPointer());
189 189 return impl->m_EventProducts.at(event).value(index.row());
190 190 }
191 191 else {
192 192 return nullptr;
193 193 }
194 194 }
195 195
196 196 void CatalogueEventsModel::addEvent(const std::shared_ptr<DBEvent> &event)
197 197 {
198 198 beginInsertRows(QModelIndex(), impl->m_Events.count(), impl->m_Events.count());
199 199 impl->m_Events.append(event);
200 200 impl->parseEventProduct(event);
201 201 endInsertRows();
202 202
203 203 // Also refreshes its children event products
204 204 auto eventIndex = index(impl->m_Events.count(), 0);
205 205 impl->refreshChildrenOfIndex(this, eventIndex);
206 206 }
207 207
208 208 void CatalogueEventsModel::removeEvent(const std::shared_ptr<DBEvent> &event)
209 209 {
210 210 auto index = impl->m_Events.indexOf(event);
211 211 if (index >= 0) {
212 212 beginRemoveRows(QModelIndex(), index, index);
213 213 impl->m_Events.removeAt(index);
214 214 impl->m_EventProducts.erase(event.get());
215 215 endRemoveRows();
216 216 }
217 217 }
218 218
219 219 QVector<std::shared_ptr<DBEvent> > CatalogueEventsModel::events() const
220 220 {
221 221 return impl->m_Events;
222 222 }
223 223
224 224 void CatalogueEventsModel::refreshEvent(const std::shared_ptr<DBEvent> &event,
225 225 bool refreshEventProducts)
226 226 {
227 227 auto eventIndex = indexOf(event);
228 228 if (eventIndex.isValid()) {
229 229
230 230 if (refreshEventProducts) {
231 231 // Reparse the associated event products
232 232
233 233 auto nbEventProducts = impl->nbEventProducts(event);
234 234 auto newNbOfEventProducts = event->getEventProducts().size();
235 235 if (newNbOfEventProducts < nbEventProducts) {
236 236 beginRemoveRows(eventIndex, newNbOfEventProducts, nbEventProducts - 1);
237 237 impl->m_EventProducts.erase(event.get());
238 238 impl->parseEventProduct(event);
239 239 endRemoveRows();
240 240 }
241 241 else if (newNbOfEventProducts > nbEventProducts) {
242 242 beginInsertRows(eventIndex, nbEventProducts, newNbOfEventProducts - 1);
243 243 impl->m_EventProducts.erase(event.get());
244 244 impl->parseEventProduct(event);
245 245 endInsertRows();
246 246 }
247 247 else { // newNbOfEventProducts == nbEventProducts
248 248 impl->m_EventProducts.erase(event.get());
249 249 impl->parseEventProduct(event);
250 250 }
251 251 }
252 252
253 253 // Refreshes the event line
254 254 auto colCount = columnCount();
255 255 emit dataChanged(eventIndex, index(eventIndex.row(), colCount));
256 256
257 257 // Also refreshes its children event products
258 258 impl->refreshChildrenOfIndex(this, eventIndex);
259 259 }
260 260 else {
261 261 qCWarning(LOG_CatalogueEventsModel()) << "refreshEvent: event not found.";
262 262 }
263 263 }
264 264
265 265 QModelIndex CatalogueEventsModel::indexOf(const std::shared_ptr<DBEvent> &event) const
266 266 {
267 267 auto row = impl->m_Events.indexOf(event);
268 268 if (row >= 0) {
269 269 return index(row, 0);
270 270 }
271 271
272 272 return QModelIndex();
273 273 }
274 274
275 275 QModelIndex CatalogueEventsModel::index(int row, int column, const QModelIndex &parent) const
276 276 {
277 277 if (!hasIndex(row, column, parent)) {
278 278 return QModelIndex();
279 279 }
280 280
281 281 switch (itemTypeOf(parent)) {
282 282 case CatalogueEventsModel::ItemType::Root:
283 283 return createIndex(row, column);
284 284 case CatalogueEventsModel::ItemType::Event: {
285 285 auto event = getEvent(parent);
286 286 return createIndex(row, column, event.get());
287 287 }
288 288 case CatalogueEventsModel::ItemType::EventProduct:
289 289 break;
290 290 default:
291 291 break;
292 292 }
293 293
294 294 return QModelIndex();
295 295 }
296 296
297 297 QModelIndex CatalogueEventsModel::parent(const QModelIndex &index) const
298 298 {
299 299 switch (itemTypeOf(index)) {
300 300 case CatalogueEventsModel::ItemType::EventProduct: {
301 301 auto parentEvent = static_cast<DBEvent *>(index.internalPointer());
302 302 auto it
303 303 = std::find_if(impl->m_Events.cbegin(), impl->m_Events.cend(),
304 304 [parentEvent](auto event) { return event.get() == parentEvent; });
305 305
306 306 if (it != impl->m_Events.cend()) {
307 307 return createIndex(it - impl->m_Events.cbegin(), 0);
308 308 }
309 309 else {
310 310 return QModelIndex();
311 311 }
312 312 }
313 313 case CatalogueEventsModel::ItemType::Root:
314 314 break;
315 315 case CatalogueEventsModel::ItemType::Event:
316 316 break;
317 317 default:
318 318 break;
319 319 }
320 320
321 321 return QModelIndex();
322 322 }
323 323
324 324 int CatalogueEventsModel::rowCount(const QModelIndex &parent) const
325 325 {
326 326 if (parent.column() > 0) {
327 327 return 0;
328 328 }
329 329
330 330 switch (itemTypeOf(parent)) {
331 331 case CatalogueEventsModel::ItemType::Root:
332 332 return impl->m_Events.count();
333 333 case CatalogueEventsModel::ItemType::Event: {
334 334 auto event = getEvent(parent);
335 335 return impl->m_EventProducts[event.get()].count();
336 336 }
337 337 case CatalogueEventsModel::ItemType::EventProduct:
338 338 break;
339 339 default:
340 340 break;
341 341 }
342 342
343 343 return 0;
344 344 }
345 345
346 346 int CatalogueEventsModel::columnCount(const QModelIndex &parent) const
347 347 {
348 348 return static_cast<int>(CatalogueEventsModel::Column::NbColumn);
349 349 }
350 350
351 351 Qt::ItemFlags CatalogueEventsModel::flags(const QModelIndex &index) const
352 352 {
353 353 return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
354 354 }
355 355
356 356 QVariant CatalogueEventsModel::data(const QModelIndex &index, int role) const
357 357 {
358 358 if (index.isValid()) {
359 359
360 360 auto type = itemTypeOf(index);
361 361 if (type == CatalogueEventsModel::ItemType::Event) {
362 362 auto event = getEvent(index);
363 363 switch (role) {
364 364 case Qt::DisplayRole:
365 365 return impl->eventData(index.column(), event);
366 366 break;
367 367 }
368 368 }
369 369 else if (type == CatalogueEventsModel::ItemType::EventProduct) {
370 370 auto product = getEventProduct(index);
371 371 switch (role) {
372 372 case Qt::DisplayRole:
373 373 return impl->eventProductData(index.column(), product);
374 374 break;
375 375 }
376 376 }
377 377 }
378 378
379 379 return QVariant{};
380 380 }
381 381
382 382 QVariant CatalogueEventsModel::headerData(int section, Qt::Orientation orientation, int role) const
383 383 {
384 384 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
385 385 return impl->columnNames().value(section);
386 386 }
387 387
388 388 return QVariant();
389 389 }
390 390
391 391 void CatalogueEventsModel::sort(int column, Qt::SortOrder order)
392 392 {
393 393 beginResetModel();
394 394 std::sort(impl->m_Events.begin(), impl->m_Events.end(),
395 395 [this, column, order](auto e1, auto e2) {
396 396 auto data1 = impl->sortData(column, e1);
397 397 auto data2 = impl->sortData(column, e2);
398 398
399 399 auto result = data1.toString() < data2.toString();
400 400
401 401 return order == Qt::AscendingOrder ? result : !result;
402 402 });
403 403
404 404 endResetModel();
405 405 emit modelSorted();
406 406 }
407 407
408 408 Qt::DropActions CatalogueEventsModel::supportedDragActions() const
409 409 {
410 410 return Qt::CopyAction | Qt::MoveAction;
411 411 }
412 412
413 413 QStringList CatalogueEventsModel::mimeTypes() const
414 414 {
415 415 return {MIME_TYPE_EVENT_LIST, MIME_TYPE_SOURCE_CATALOGUE_LIST, MIME_TYPE_TIME_RANGE};
416 416 }
417 417
418 418 QMimeData *CatalogueEventsModel::mimeData(const QModelIndexList &indexes) const
419 419 {
420 420 auto mimeData = new QMimeData;
421 421
422 422 bool isFirst = true;
423 423
424 424 QVector<std::shared_ptr<DBEvent> > eventList;
425 425 QVector<std::shared_ptr<DBEventProduct> > eventProductList;
426 426
427 427 DateTimeRange firstTimeRange;
428 428 for (const auto &index : indexes) {
429 429 if (index.column() == 0) { // only the first column
430 430
431 431 auto type = itemTypeOf(index);
432 432 if (type == ItemType::Event) {
433 433 auto event = getEvent(index);
434 434 eventList << event;
435 435
436 436 if (isFirst) {
437 437 isFirst = false;
438 438 firstTimeRange.m_TStart = event->getTStart();
439 439 firstTimeRange.m_TEnd = event->getTEnd();
440 440 }
441 441 }
442 442 else if (type == ItemType::EventProduct) {
443 443 auto product = getEventProduct(index);
444 444 eventProductList << product;
445 445
446 446 if (isFirst) {
447 447 isFirst = false;
448 448 firstTimeRange.m_TStart = product->getTStart();
449 449 firstTimeRange.m_TEnd = product->getTEnd();
450 450 }
451 451 }
452 452 }
453 453 }
454 454
455 455 if (!eventList.isEmpty() && eventProductList.isEmpty()) {
456 456 auto eventsEncodedData = sqpApp->catalogueController().mimeDataForEvents(eventList);
457 457 mimeData->setData(MIME_TYPE_EVENT_LIST, eventsEncodedData);
458 458
459 459 auto sourceCataloguesEncodedData
460 460 = sqpApp->catalogueController().mimeDataForCatalogues(impl->m_SourceCatalogue);
461 461 mimeData->setData(MIME_TYPE_SOURCE_CATALOGUE_LIST, sourceCataloguesEncodedData);
462 462 }
463 463
464 464 if (eventList.count() + eventProductList.count() == 1) {
465 465 // No time range MIME data if multiple events are dragged
466 466 auto timeEncodedData = TimeController::mimeDataForTimeRange(firstTimeRange);
467 467 mimeData->setData(MIME_TYPE_TIME_RANGE, timeEncodedData);
468 468 }
469 469
470 470 return mimeData;
471 471 }
472 472
473 473 CatalogueEventsModel::ItemType CatalogueEventsModel::itemTypeOf(const QModelIndex &index) const
474 474 {
475 475 if (!index.isValid()) {
476 476 return ItemType::Root;
477 477 }
478 478 else if (index.internalPointer() == nullptr) {
479 479 return ItemType::Event;
480 480 }
481 481 else {
482 482 return ItemType::EventProduct;
483 483 }
484 484 }
@@ -1,154 +1,155
1 1 #include "TimeWidget/TimeWidget.h"
2 2 #include "ui_TimeWidget.h"
3 3
4 4 #include <Common/DateUtils.h>
5 5 #include <Common/MimeTypesDef.h>
6 6
7 7 #include <DragAndDrop/DragDropGuiController.h>
8 8 #include <SqpApplication.h>
9 9 #include <Time/TimeController.h>
10 10
11 11 #include <QDrag>
12 12 #include <QDragEnterEvent>
13 13 #include <QDropEvent>
14 14 #include <QMimeData>
15 #include <QStyle>
15 16
16 17
17 18 struct TimeWidget::TimeWidgetPrivate {
18 19
19 20 explicit TimeWidgetPrivate() {}
20 21
21 22 QPoint m_DragStartPosition;
22 23 };
23 24
24 25 TimeWidget::TimeWidget(QWidget *parent)
25 26 : QWidget{parent},
26 27 ui{new Ui::TimeWidget},
27 28 impl{spimpl::make_unique_impl<TimeWidgetPrivate>()}
28 29 {
29 30 ui->setupUi(this);
30 31
31 32 ui->applyToolButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_DialogApplyButton));
32 33
33 34 // Connection
34 35 connect(ui->startDateTimeEdit, &QDateTimeEdit::dateTimeChanged, this,
35 36 &TimeWidget::onTimeUpdateRequested);
36 37
37 38 connect(ui->endDateTimeEdit, &QDateTimeEdit::dateTimeChanged, this,
38 39 &TimeWidget::onTimeUpdateRequested);
39 40
40 41
41 42 connect(ui->applyToolButton, &QToolButton::clicked, &sqpApp->timeController(),
42 43 &TimeController::onTimeNotify);
43 44
44 45 // Initialisation
45 46 auto endDateTime = QDateTime::currentDateTimeUtc();
46 47 auto startDateTime = endDateTime.addSecs(-3600); // one hour before
47 48
48 49 ui->startDateTimeEdit->setDateTime(startDateTime);
49 50 ui->endDateTimeEdit->setDateTime(endDateTime);
50 51
51 52 auto dateTime = DateTimeRange{DateUtils::secondsSinceEpoch(startDateTime),
52 53 DateUtils::secondsSinceEpoch(endDateTime)};
53 54
54 55 sqpApp->timeController().setDateTimeRange(dateTime);
55 56 }
56 57
57 58
58 59 TimeWidget::~TimeWidget()
59 60 {
60 61 delete ui;
61 62 }
62 63
63 64 void TimeWidget::setTimeRange(DateTimeRange time)
64 65 {
65 66 auto startDateTime = DateUtils::dateTime(time.m_TStart);
66 67 auto endDateTime = DateUtils::dateTime(time.m_TEnd);
67 68
68 69 ui->startDateTimeEdit->setDateTime(startDateTime);
69 70 ui->endDateTimeEdit->setDateTime(endDateTime);
70 71 }
71 72
72 73 DateTimeRange TimeWidget::timeRange() const
73 74 {
74 75 return DateTimeRange{DateUtils::secondsSinceEpoch(ui->startDateTimeEdit->dateTime()),
75 76 DateUtils::secondsSinceEpoch(ui->endDateTimeEdit->dateTime())};
76 77 }
77 78
78 79 void TimeWidget::onTimeUpdateRequested()
79 80 {
80 81 auto dateTime = timeRange();
81 82 emit timeUpdated(std::move(dateTime));
82 83 }
83 84
84 85 void TimeWidget::dragEnterEvent(QDragEnterEvent *event)
85 86 {
86 87 if (event->mimeData()->hasFormat(MIME_TYPE_TIME_RANGE)) {
87 88 event->acceptProposedAction();
88 89 setStyleSheet("QDateTimeEdit{background-color: #BBD5EE; border:2px solid #2A7FD4}");
89 90 }
90 91 else {
91 92 event->ignore();
92 93 }
93 94 }
94 95
95 96 void TimeWidget::dragLeaveEvent(QDragLeaveEvent *event)
96 97 {
97 98 setStyleSheet(QString{});
98 99 }
99 100
100 101 void TimeWidget::dropEvent(QDropEvent *event)
101 102 {
102 103 if (event->mimeData()->hasFormat(MIME_TYPE_TIME_RANGE)) {
103 104 auto mimeData = event->mimeData()->data(MIME_TYPE_TIME_RANGE);
104 105 auto timeRange = TimeController::timeRangeForMimeData(mimeData);
105 106
106 107 setTimeRange(timeRange);
107 108 }
108 109 else {
109 110 event->ignore();
110 111 }
111 112
112 113 setStyleSheet(QString{});
113 114 }
114 115
115 116
116 117 void TimeWidget::mousePressEvent(QMouseEvent *event)
117 118 {
118 119 if (event->button() == Qt::LeftButton) {
119 120 impl->m_DragStartPosition = event->pos();
120 121 }
121 122
122 123 QWidget::mousePressEvent(event);
123 124 }
124 125
125 126 void TimeWidget::mouseMoveEvent(QMouseEvent *event)
126 127 {
127 128 if (!(event->buttons() & Qt::LeftButton)) {
128 129 return;
129 130 }
130 131
131 132 if ((event->pos() - impl->m_DragStartPosition).manhattanLength()
132 133 < QApplication::startDragDistance()) {
133 134 return;
134 135 }
135 136
136 137 // Note: The management of the drag object is done by Qt
137 138 auto drag = new QDrag{this};
138 139
139 140 auto mimeData = new QMimeData;
140 141 auto timeData = TimeController::mimeDataForTimeRange(timeRange());
141 142 mimeData->setData(MIME_TYPE_TIME_RANGE, timeData);
142 143
143 144 drag->setMimeData(mimeData);
144 145
145 146 auto pixmap = QPixmap{":/icones/time.png"};
146 147 drag->setPixmap(pixmap.scaledToWidth(22));
147 148
148 149 sqpApp->dragDropGuiController().resetDragAndDrop();
149 150
150 151 // Note: The exec() is blocking on windows but not on linux and macOS
151 152 drag->exec(Qt::MoveAction | Qt::CopyAction);
152 153
153 154 QWidget::mouseMoveEvent(event);
154 155 }
@@ -1,658 +1,659
1 1 #include "Visualization/VisualizationZoneWidget.h"
2 2
3 3 #include "Visualization/IVisualizationWidgetVisitor.h"
4 4 #include "Visualization/QCustomPlotSynchronizer.h"
5 5 #include "Visualization/VisualizationGraphWidget.h"
6 6 #include "Visualization/VisualizationWidget.h"
7 7 #include "ui_VisualizationZoneWidget.h"
8 8
9 9 #include "Common/MimeTypesDef.h"
10 10 #include "Common/VisualizationDef.h"
11 11
12 #include <Data/SqpRange.h>
12 #include <Data/DateTimeRange.h>
13 13 #include <DataSource/DataSourceController.h>
14 14 #include <Time/TimeController.h>
15 15 #include <Variable/Variable.h>
16 16 #include <Variable/VariableController.h>
17 17
18 18 #include <Visualization/operations/FindVariableOperation.h>
19 19
20 20 #include <DragAndDrop/DragDropGuiController.h>
21 21 #include <QUuid>
22 22 #include <SqpApplication.h>
23 23 #include <cmath>
24 24
25 25 #include <QLayout>
26 #include <QStyle>
26 27
27 28 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
28 29
29 30 namespace {
30 31
31 32 /**
32 33 * Applies a function to all graphs of the zone represented by its layout
33 34 * @param layout the layout that contains graphs
34 35 * @param fun the function to apply to each graph
35 36 */
36 37 template <typename Fun>
37 38 void processGraphs(QLayout &layout, Fun fun)
38 39 {
39 40 for (auto i = 0; i < layout.count(); ++i) {
40 41 if (auto item = layout.itemAt(i)) {
41 42 if (auto visualizationGraphWidget
42 43 = qobject_cast<VisualizationGraphWidget *>(item->widget())) {
43 44 fun(*visualizationGraphWidget);
44 45 }
45 46 }
46 47 }
47 48 }
48 49
49 50 /// Generates a default name for a new graph, according to the number of graphs already displayed in
50 51 /// the zone
51 52 QString defaultGraphName(QLayout &layout)
52 53 {
53 54 QSet<QString> existingNames;
54 55 processGraphs(
55 56 layout, [&existingNames](auto &graphWidget) { existingNames.insert(graphWidget.name()); });
56 57
57 58 int zoneNum = 1;
58 59 QString name;
59 60 do {
60 61 name = QObject::tr("Graph ").append(QString::number(zoneNum));
61 62 ++zoneNum;
62 63 } while (existingNames.contains(name));
63 64
64 65 return name;
65 66 }
66 67
67 68 } // namespace
68 69
69 70 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
70 71
71 72 explicit VisualizationZoneWidgetPrivate()
72 73 : m_SynchronisationGroupId{QUuid::createUuid()},
73 74 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
74 75 {
75 76 }
76 77 QUuid m_SynchronisationGroupId;
77 78 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
78 79
79 80 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
80 81 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
81 82 VisualizationZoneWidget *zoneWidget);
82 83 void dropProducts(const QVariantList &productsData, int index,
83 84 VisualizationZoneWidget *zoneWidget);
84 85 };
85 86
86 87 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
87 88 : VisualizationDragWidget{parent},
88 89 ui{new Ui::VisualizationZoneWidget},
89 90 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
90 91 {
91 92 ui->setupUi(this);
92 93
93 94 ui->zoneNameLabel->setText(name);
94 95
95 96 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Graph);
96 97 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
97 98 VisualizationDragDropContainer::DropBehavior::Inserted);
98 99 ui->dragDropContainer->setMimeType(
99 100 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
100 101 ui->dragDropContainer->setMimeType(
101 102 MIME_TYPE_PRODUCT_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
102 103 ui->dragDropContainer->setMimeType(MIME_TYPE_TIME_RANGE,
103 104 VisualizationDragDropContainer::DropBehavior::Merged);
104 105 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
105 106 VisualizationDragDropContainer::DropBehavior::Forbidden);
106 107 ui->dragDropContainer->setMimeType(MIME_TYPE_SELECTION_ZONE,
107 108 VisualizationDragDropContainer::DropBehavior::Forbidden);
108 109 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
109 110 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(mimeData,
110 111 ui->dragDropContainer);
111 112 });
112 113
113 114 auto acceptDragWidgetFun = [](auto dragWidget, auto mimeData) {
114 115 if (!mimeData) {
115 116 return false;
116 117 }
117 118
118 119 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
119 120 auto variables = sqpApp->variableController().variablesForMimeData(
120 121 mimeData->data(MIME_TYPE_VARIABLE_LIST));
121 122
122 123 if (variables.count() != 1) {
123 124 return false;
124 125 }
125 126 auto variable = variables.first();
126 127
127 128 if (auto graphWidget = dynamic_cast<const VisualizationGraphWidget *>(dragWidget)) {
128 129 return graphWidget->canDrop(*variable);
129 130 }
130 131 }
131 132
132 133 return true;
133 134 };
134 135 ui->dragDropContainer->setAcceptDragWidgetFunction(acceptDragWidgetFun);
135 136
136 137 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
137 138 &VisualizationZoneWidget::dropMimeData);
138 139 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
139 140 &VisualizationZoneWidget::dropMimeDataOnGraph);
140 141
141 142 // 'Close' options : widget is deleted when closed
142 143 setAttribute(Qt::WA_DeleteOnClose);
143 144 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
144 145 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
145 146
146 147 // Synchronisation id
147 148 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
148 149 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
149 150 }
150 151
151 152 VisualizationZoneWidget::~VisualizationZoneWidget()
152 153 {
153 154 delete ui;
154 155 }
155 156
156 157 void VisualizationZoneWidget::setZoneRange(const DateTimeRange &range)
157 158 {
158 159 if (auto graph = firstGraph()) {
159 160 graph->setGraphRange(range);
160 161 }
161 162 else {
162 163 qCWarning(LOG_VisualizationZoneWidget())
163 164 << tr("setZoneRange:Cannot set the range of an empty zone.");
164 165 }
165 166 }
166 167
167 168 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
168 169 {
169 170 // Synchronize new graph with others in the zone
170 171 impl->m_Synchronizer->addGraph(*graphWidget);
171 172
172 173 ui->dragDropContainer->addDragWidget(graphWidget);
173 174 }
174 175
175 176 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
176 177 {
177 178 // Synchronize new graph with others in the zone
178 179 impl->m_Synchronizer->addGraph(*graphWidget);
179 180
180 181 ui->dragDropContainer->insertDragWidget(index, graphWidget);
181 182 }
182 183
183 184 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
184 185 {
185 186 return createGraph(variable, -1);
186 187 }
187 188
188 189 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
189 190 int index)
190 191 {
191 192 auto graphWidget
192 193 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
193 194
194 195
195 196 // Set graph properties
196 197 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
197 198 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
198 199
199 200
200 201 // Lambda to synchronize zone widget
201 202 auto synchronizeZoneWidget = [this, graphWidget](const DateTimeRange &graphRange,
202 203 const DateTimeRange &oldGraphRange) {
203 204
204 205 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
205 206 auto frameLayout = ui->dragDropContainer->layout();
206 207 for (auto i = 0; i < frameLayout->count(); ++i) {
207 208 auto graphChild
208 209 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
209 210 if (graphChild && (graphChild != graphWidget)) {
210 211
211 212 auto graphChildRange = graphChild->graphRange();
212 213 switch (zoomType) {
213 214 case AcquisitionZoomType::ZoomIn: {
214 215 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
215 216 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
216 217 graphChildRange.m_TStart += deltaLeft;
217 218 graphChildRange.m_TEnd -= deltaRight;
218 219 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
219 220 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
220 221 << deltaLeft;
221 222 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
222 223 << deltaRight;
223 224 qCDebug(LOG_VisualizationZoneWidget())
224 225 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
225 226
226 227 break;
227 228 }
228 229
229 230 case AcquisitionZoomType::ZoomOut: {
230 231 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
231 232 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
232 233 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
233 234 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
234 235 << deltaLeft;
235 236 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
236 237 << deltaRight;
237 238 qCDebug(LOG_VisualizationZoneWidget())
238 239 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
239 240 graphChildRange.m_TStart -= deltaLeft;
240 241 graphChildRange.m_TEnd += deltaRight;
241 242 break;
242 243 }
243 244 case AcquisitionZoomType::PanRight: {
244 245 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
245 246 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
246 247 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
247 248 graphChildRange.m_TStart += deltaLeft;
248 249 graphChildRange.m_TEnd += deltaRight;
249 250 qCDebug(LOG_VisualizationZoneWidget())
250 251 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
251 252 break;
252 253 }
253 254 case AcquisitionZoomType::PanLeft: {
254 255 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
255 256 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
256 257 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
257 258 graphChildRange.m_TStart -= deltaLeft;
258 259 graphChildRange.m_TEnd -= deltaRight;
259 260 break;
260 261 }
261 262 case AcquisitionZoomType::Unknown: {
262 263 qCDebug(LOG_VisualizationZoneWidget())
263 264 << tr("Impossible to synchronize: zoom type unknown");
264 265 break;
265 266 }
266 267 default:
267 268 qCCritical(LOG_VisualizationZoneWidget())
268 269 << tr("Impossible to synchronize: zoom type not take into account");
269 270 // No action
270 271 break;
271 272 }
272 273 graphChild->setFlags(GraphFlag::DisableAll);
273 274 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
274 275 << graphChild->graphRange();
275 276 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
276 277 << graphChildRange;
277 278 qCDebug(LOG_VisualizationZoneWidget())
278 279 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
279 280 graphChild->setGraphRange(graphChildRange);
280 281 graphChild->setFlags(GraphFlag::EnableAll);
281 282 }
282 283 }
283 284 };
284 285
285 286 // connection for synchronization
286 287 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
287 288 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
288 289 &VisualizationZoneWidget::onVariableAdded);
289 290 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
290 291 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
291 292
292 293 auto range = DateTimeRange{};
293 294 if (auto firstGraph = this->firstGraph()) {
294 295 // Case of a new graph in a existant zone
295 296 range = firstGraph->graphRange();
296 297 }
297 298 else {
298 299 // Case of a new graph as the first of the zone
299 300 range = variable->range();
300 301 }
301 302
302 303 this->insertGraph(index, graphWidget);
303 304
304 305 graphWidget->addVariable(variable, range);
305 306 graphWidget->setYRange(variable);
306 307
307 308 return graphWidget;
308 309 }
309 310
310 311 VisualizationGraphWidget *
311 312 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
312 313 {
313 314 if (variables.isEmpty()) {
314 315 return nullptr;
315 316 }
316 317
317 318 auto graphWidget = createGraph(variables.first(), index);
318 319 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
319 320 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
320 321 }
321 322
322 323 return graphWidget;
323 324 }
324 325
325 326 VisualizationGraphWidget *VisualizationZoneWidget::firstGraph() const
326 327 {
327 328 VisualizationGraphWidget *firstGraph = nullptr;
328 329 auto layout = ui->dragDropContainer->layout();
329 330 if (layout->count() > 0) {
330 331 if (auto visualizationGraphWidget
331 332 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
332 333 firstGraph = visualizationGraphWidget;
333 334 }
334 335 }
335 336
336 337 return firstGraph;
337 338 }
338 339
339 340 void VisualizationZoneWidget::closeAllGraphs()
340 341 {
341 342 processGraphs(*ui->dragDropContainer->layout(),
342 343 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
343 344 }
344 345
345 346 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
346 347 {
347 348 if (visitor) {
348 349 visitor->visitEnter(this);
349 350
350 351 // Apply visitor to graph children: widgets different from graphs are not visited (no
351 352 // action)
352 353 processGraphs(
353 354 *ui->dragDropContainer->layout(),
354 355 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
355 356
356 357 visitor->visitLeave(this);
357 358 }
358 359 else {
359 360 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
360 361 }
361 362 }
362 363
363 364 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
364 365 {
365 366 // A tab can always accomodate a variable
366 367 Q_UNUSED(variable);
367 368 return true;
368 369 }
369 370
370 371 bool VisualizationZoneWidget::contains(const Variable &variable) const
371 372 {
372 373 Q_UNUSED(variable);
373 374 return false;
374 375 }
375 376
376 377 QString VisualizationZoneWidget::name() const
377 378 {
378 379 return ui->zoneNameLabel->text();
379 380 }
380 381
381 382 QMimeData *VisualizationZoneWidget::mimeData(const QPoint &position) const
382 383 {
383 384 Q_UNUSED(position);
384 385
385 386 auto mimeData = new QMimeData;
386 387 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
387 388
388 389 if (auto firstGraph = this->firstGraph()) {
389 390 auto timeRangeData = TimeController::mimeDataForTimeRange(firstGraph->graphRange());
390 391 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
391 392 }
392 393
393 394 return mimeData;
394 395 }
395 396
396 397 bool VisualizationZoneWidget::isDragAllowed() const
397 398 {
398 399 return true;
399 400 }
400 401
401 402 void VisualizationZoneWidget::notifyMouseMoveInGraph(const QPointF &graphPosition,
402 403 const QPointF &plotPosition,
403 404 VisualizationGraphWidget *graphWidget)
404 405 {
405 406 processGraphs(*ui->dragDropContainer->layout(), [&graphPosition, &plotPosition, &graphWidget](
406 407 VisualizationGraphWidget &processedGraph) {
407 408
408 409 switch (sqpApp->plotsCursorMode()) {
409 410 case SqpApplication::PlotsCursorMode::Vertical:
410 411 processedGraph.removeHorizontalCursor();
411 412 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
412 413 break;
413 414 case SqpApplication::PlotsCursorMode::Temporal:
414 415 processedGraph.addVerticalCursor(plotPosition.x());
415 416 processedGraph.removeHorizontalCursor();
416 417 break;
417 418 case SqpApplication::PlotsCursorMode::Horizontal:
418 419 processedGraph.removeVerticalCursor();
419 420 if (&processedGraph == graphWidget) {
420 421 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
421 422 }
422 423 else {
423 424 processedGraph.removeHorizontalCursor();
424 425 }
425 426 break;
426 427 case SqpApplication::PlotsCursorMode::Cross:
427 428 if (&processedGraph == graphWidget) {
428 429 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
429 430 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
430 431 }
431 432 else {
432 433 processedGraph.removeHorizontalCursor();
433 434 processedGraph.removeVerticalCursor();
434 435 }
435 436 break;
436 437 case SqpApplication::PlotsCursorMode::NoCursor:
437 438 processedGraph.removeHorizontalCursor();
438 439 processedGraph.removeVerticalCursor();
439 440 break;
440 441 }
441 442
442 443
443 444 });
444 445 }
445 446
446 447 void VisualizationZoneWidget::notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget)
447 448 {
448 449 processGraphs(*ui->dragDropContainer->layout(), [](VisualizationGraphWidget &processedGraph) {
449 450 processedGraph.removeHorizontalCursor();
450 451 processedGraph.removeVerticalCursor();
451 452 });
452 453 }
453 454
454 455 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
455 456 {
456 457 // Closes graphs in the zone
457 458 processGraphs(*ui->dragDropContainer->layout(),
458 459 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
459 460
460 461 // Delete synchronization group from variable controller
461 462 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
462 463 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
463 464
464 465 QWidget::closeEvent(event);
465 466 }
466 467
467 468 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
468 469 {
469 470 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
470 471 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
471 472 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
472 473 }
473 474
474 475 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
475 476 {
476 477 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
477 478 Q_ARG(std::shared_ptr<Variable>, variable),
478 479 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
479 480 }
480 481
481 482 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
482 483 {
483 484 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
484 485 impl->dropGraph(index, this);
485 486 }
486 487 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
487 488 auto variables = sqpApp->variableController().variablesForMimeData(
488 489 mimeData->data(MIME_TYPE_VARIABLE_LIST));
489 490 impl->dropVariables(variables, index, this);
490 491 }
491 492 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
492 493 auto products = sqpApp->dataSourceController().productsDataForMimeData(
493 494 mimeData->data(MIME_TYPE_PRODUCT_LIST));
494 495 impl->dropProducts(products, index, this);
495 496 }
496 497 else {
497 498 qCWarning(LOG_VisualizationZoneWidget())
498 499 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
499 500 }
500 501 }
501 502
502 503 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
503 504 const QMimeData *mimeData)
504 505 {
505 506 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
506 507 if (!graphWidget) {
507 508 qCWarning(LOG_VisualizationZoneWidget())
508 509 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
509 510 "drop aborted");
510 511 Q_ASSERT(false);
511 512 return;
512 513 }
513 514
514 515 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
515 516 auto variables = sqpApp->variableController().variablesForMimeData(
516 517 mimeData->data(MIME_TYPE_VARIABLE_LIST));
517 518 for (const auto &var : variables) {
518 519 graphWidget->addVariable(var, graphWidget->graphRange());
519 520 }
520 521 }
521 522 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
522 523 auto products = sqpApp->dataSourceController().productsDataForMimeData(
523 524 mimeData->data(MIME_TYPE_PRODUCT_LIST));
524 525
525 526 auto context = new QObject{this};
526 527 connect(&sqpApp->variableController(), &VariableController::variableAdded, context,
527 528 [this, graphWidget, context](auto variable) {
528 529 graphWidget->addVariable(variable, graphWidget->graphRange());
529 530 delete context; // removes the connection
530 531 },
531 532 Qt::QueuedConnection);
532 533
533 534 auto productData = products.first().toHash();
534 535 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
535 536 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
536 537 }
537 538 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
538 539 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
539 540 graphWidget->setGraphRange(range);
540 541 }
541 542 else {
542 543 qCWarning(LOG_VisualizationZoneWidget())
543 544 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
544 545 }
545 546 }
546 547
547 548 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
548 549 int index, VisualizationZoneWidget *zoneWidget)
549 550 {
550 551 auto &helper = sqpApp->dragDropGuiController();
551 552
552 553 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
553 554 if (!graphWidget) {
554 555 qCWarning(LOG_VisualizationZoneWidget())
555 556 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
556 557 "found or invalid.");
557 558 Q_ASSERT(false);
558 559 return;
559 560 }
560 561
561 562 auto parentDragDropContainer
562 563 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
563 564 if (!parentDragDropContainer) {
564 565 qCWarning(LOG_VisualizationZoneWidget())
565 566 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
566 567 "the dropped graph is not found.");
567 568 Q_ASSERT(false);
568 569 return;
569 570 }
570 571
571 572 const auto &variables = graphWidget->variables();
572 573
573 574 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
574 575 // The drop didn't occur in the same zone
575 576
576 577 // Abort the requests for the variables (if any)
577 578 // Commented, because it's not sure if it's needed or not
578 579 // for (const auto& var : variables)
579 580 //{
580 581 // sqpApp->variableController().onAbortProgressRequested(var);
581 582 //}
582 583
583 584 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
584 585 auto nbGraph = parentDragDropContainer->countDragWidget();
585 586 if (nbGraph == 1) {
586 587 // This is the only graph in the previous zone, close the zone
587 588 helper.delayedCloseWidget(previousParentZoneWidget);
588 589 }
589 590 else {
590 591 // Close the graph
591 592 helper.delayedCloseWidget(graphWidget);
592 593 }
593 594
594 595 // Creates the new graph in the zone
595 596 auto newGraphWidget = zoneWidget->createGraph(variables, index);
596 597 newGraphWidget->addSelectionZones(graphWidget->selectionZoneRanges());
597 598 }
598 599 else {
599 600 // The drop occurred in the same zone or the graph is empty
600 601 // Simple move of the graph, no variable operation associated
601 602 parentDragDropContainer->layout()->removeWidget(graphWidget);
602 603
603 604 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
604 605 // The graph is empty and dropped in a different zone.
605 606 // Take the range of the first graph in the zone (if existing).
606 607 auto layout = zoneWidget->ui->dragDropContainer->layout();
607 608 if (layout->count() > 0) {
608 609 if (auto visualizationGraphWidget
609 610 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
610 611 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
611 612 }
612 613 }
613 614 }
614 615
615 616 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
616 617 }
617 618 }
618 619
619 620 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
620 621 const QList<std::shared_ptr<Variable> > &variables, int index,
621 622 VisualizationZoneWidget *zoneWidget)
622 623 {
623 624 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
624 625 // compatible variable here
625 626 if (variables.count() > 1) {
626 627 qCWarning(LOG_VisualizationZoneWidget())
627 628 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
628 629 "aborted.");
629 630 return;
630 631 }
631 632
632 633 zoneWidget->createGraph(variables, index);
633 634 }
634 635
635 636 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropProducts(
636 637 const QVariantList &productsData, int index, VisualizationZoneWidget *zoneWidget)
637 638 {
638 639 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
639 640 // compatible variable here
640 641 if (productsData.count() != 1) {
641 642 qCWarning(LOG_VisualizationZoneWidget())
642 643 << tr("VisualizationTabWidget::dropProducts, dropping multiple products, operation "
643 644 "aborted.");
644 645 return;
645 646 }
646 647
647 648 auto context = new QObject{zoneWidget};
648 649 connect(&sqpApp->variableController(), &VariableController::variableAdded, context,
649 650 [this, index, zoneWidget, context](auto variable) {
650 651 zoneWidget->createGraph(variable, index);
651 652 delete context; // removes the connection
652 653 },
653 654 Qt::QueuedConnection);
654 655
655 656 auto productData = productsData.first().toHash();
656 657 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
657 658 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
658 659 }
@@ -1,128 +1,128
1 1 #ifndef SCIQLOP_FUZZINGDEFS_H
2 2 #define SCIQLOP_FUZZINGDEFS_H
3 3
4 #include <Data/SqpRange.h>
4 #include <Data/DateTimeRange.h>
5 5
6 6 #include <QString>
7 7 #include <QUuid>
8 8 #include <QVariantHash>
9 9
10 10 #include <memory>
11 11 #include <set>
12 12
13 13 // /////// //
14 14 // Aliases //
15 15 // /////// //
16 16
17 17 using MetadataPool = std::vector<QVariantHash>;
18 18 Q_DECLARE_METATYPE(MetadataPool)
19 19
20 20 using Properties = QVariantHash;
21 21
22 22 // ///////// //
23 23 // Constants //
24 24 // ///////// //
25 25
26 26 /// Timeout set for data acquisition for an operation (in ms)
27 27 extern const QString ACQUISITION_TIMEOUT_PROPERTY;
28 28
29 29 /// Max number of operations to generate
30 30 extern const QString NB_MAX_OPERATIONS_PROPERTY;
31 31
32 32 /// Max number of sync groups to create through operations
33 33 extern const QString NB_MAX_SYNC_GROUPS_PROPERTY;
34 34
35 35 /// Max number of variables to manipulate through operations
36 36 extern const QString NB_MAX_VARIABLES_PROPERTY;
37 37
38 38 /// Set of operations available for the test
39 39 extern const QString AVAILABLE_OPERATIONS_PROPERTY;
40 40
41 41 /// Tolerance used for variable's cache (in ratio)
42 42 extern const QString CACHE_TOLERANCE_PROPERTY;
43 43
44 44 /// Range with which the timecontroller is initialized
45 45 extern const QString INITIAL_RANGE_PROPERTY;
46 46
47 47 /// Max range that an operation can reach
48 48 extern const QString MAX_RANGE_PROPERTY;
49 49
50 50 /// Set of metadata that can be associated to a variable
51 51 extern const QString METADATA_POOL_PROPERTY;
52 52
53 53 /// Provider used to retrieve data
54 54 extern const QString PROVIDER_PROPERTY;
55 55
56 56 /// Min/max times left for an operation to execute
57 57 extern const QString OPERATION_DELAY_BOUNDS_PROPERTY;
58 58
59 59 /// Validators used to validate an operation
60 60 extern const QString VALIDATORS_PROPERTY;
61 61
62 62 /// Min/max number of operations to execute before calling validation of the current test's state
63 63 extern const QString VALIDATION_FREQUENCY_BOUNDS_PROPERTY;
64 64
65 65 // /////// //
66 66 // Structs //
67 67 // /////// //
68 68
69 69 class Variable;
70 70 struct VariableState {
71 71 std::shared_ptr<Variable> m_Variable{nullptr};
72 72 DateTimeRange m_Range{INVALID_RANGE};
73 73 };
74 74
75 75 using VariableId = int;
76 76 using VariablesPool = std::map<VariableId, VariableState>;
77 77
78 78 /**
79 79 * Defines a synchronization group for a fuzzing state. A group reports the variables synchronized
80 80 * with each other, and the current range of the group (i.e. range of the last synchronized variable
81 81 * that has been moved)
82 82 */
83 83 struct SyncGroup {
84 84 std::set<VariableId> m_Variables{};
85 85 DateTimeRange m_Range{INVALID_RANGE};
86 86 };
87 87
88 88 using SyncGroupId = QUuid;
89 89 using SyncGroupsPool = std::map<SyncGroupId, SyncGroup>;
90 90
91 91 /**
92 92 * Defines a current state during a fuzzing state. It contains all the variables manipulated during
93 93 * the test, as well as the synchronization status of these variables.
94 94 */
95 95 struct FuzzingState {
96 96 const SyncGroup &syncGroup(SyncGroupId id) const;
97 97 SyncGroup &syncGroup(SyncGroupId id);
98 98
99 99 const VariableState &variableState(VariableId id) const;
100 100 VariableState &variableState(VariableId id);
101 101
102 102 /// @return the identifier of the synchronization group in which the variable passed in
103 103 /// parameter is located. If the variable is not in any group, returns an invalid identifier
104 104 SyncGroupId syncGroupId(VariableId variableId) const;
105 105
106 106 /// @return the set of synchronization group identifiers
107 107 std::vector<SyncGroupId> syncGroupsIds() const;
108 108
109 109 /// Updates fuzzing state according to a variable synchronization
110 110 /// @param variableId the variable that is synchronized
111 111 /// @param syncGroupId the synchronization group
112 112 void synchronizeVariable(VariableId variableId, SyncGroupId syncGroupId);
113 113
114 114 /// Updates fuzzing state according to a variable desynchronization
115 115 /// @param variableId the variable that is desynchronized
116 116 /// @param syncGroupId the synchronization group from which to remove the variable
117 117 void desynchronizeVariable(VariableId variableId, SyncGroupId syncGroupId);
118 118
119 119 /// Updates the range of a variable and all variables to which it is synchronized
120 120 /// @param the variable for which to affect the range
121 121 /// @param the range to affect
122 122 void updateRanges(VariableId variableId, const DateTimeRange &newRange);
123 123
124 124 VariablesPool m_VariablesPool;
125 125 SyncGroupsPool m_SyncGroupsPool;
126 126 };
127 127
128 128 #endif // SCIQLOP_FUZZINGDEFS_H
@@ -1,126 +1,126
1 1 /*------------------------------------------------------------------------------
2 2 -- This file is a part of the SciQLOP Software
3 3 -- Copyright (C) 2018, Plasma Physics Laboratory - CNRS
4 4 --
5 5 -- This program is free software; you can redistribute it and/or modify
6 6 -- it under the terms of the GNU General Public License as published by
7 7 -- the Free Software Foundation; either version 2 of the License, or
8 8 -- (at your option) any later version.
9 9 --
10 10 -- This program is distributed in the hope that it will be useful,
11 11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
12 12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 13 -- GNU General Public License for more details.
14 14 --
15 15 -- You should have received a copy of the GNU General Public License
16 16 -- along with this program; if not, write to the Free Software
17 17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 18 -------------------------------------------------------------------------------*/
19 19 /*-- Author : Alexis Jeandet
20 20 -- Mail : alexis.jeandet@member.fsf.org
21 21 ----------------------------------------------------------------------------*/
22 22 #include <string>
23 23 #include <sstream>
24 24 #include <memory>
25 25
26 26 #include <pybind11/pybind11.h>
27 27 #include <pybind11/operators.h>
28 28 #include <pybind11/embed.h>
29 29 #include <pybind11/numpy.h>
30 30 #include <pybind11/chrono.h>
31 31
32 32 #include <SqpApplication.h>
33 33 #include <Variable/VariableController.h>
34 34 #include <Time/TimeController.h>
35 #include <Data/SqpRange.h>
35 #include <Data/DateTimeRange.h>
36 36 #include <Data/DataSeriesType.h>
37 37 #include <Common/DateUtils.h>
38 38 #include <Variable/Variable.h>
39 39 #include <Data/ScalarSeries.h>
40 40 #include <Data/VectorSeries.h>
41 41
42 42 #include <AmdaProvider.h>
43 43 #include <AmdaResultParser.h>
44 44
45 45 //#include <QDate>
46 46 //#include <QTime>
47 47 //#include <QUuid>
48 48 //#include <QString>
49 49 #include <QFile>
50 50
51 51 #include <pywrappers_common.h>
52 52 #include <CoreWrappers.h>
53 53
54 54 #include "PyTestAmdaWrapper.h"
55 55
56 56
57 57 using namespace std::chrono;
58 58
59 59
60 60
61 61
62 62 PYBIND11_MODULE(pytestamda, m){
63 63
64 64 int argc = 0;
65 65 char ** argv=nullptr;
66 66 SqpApplication::setOrganizationName("LPP");
67 67 SqpApplication::setOrganizationDomain("lpp.fr");
68 68 SqpApplication::setApplicationName("SciQLop");
69 69 static SqpApplication app(argc, argv);
70 70
71 71 auto qtmod = py::module::import("sciqlopqt");
72 72 auto sciqlopmod = py::module::import("pysciqlopcore");
73 73
74 74 m.doc() = "hello";
75 75
76 76 py::class_<VariableController>(m, "VariableController")
77 77 .def_static("createVariable",[](const QString &name,
78 78 std::shared_ptr<IDataProvider> provider, const DateTimeRange& range){
79 79 return sqpApp->variableController().createVariable(name, {{"dataType", "vector"}, {"xml:id", "c1_b"}}, provider, range);
80 80 })
81 81 .def_static("hasPendingDownloads",
82 82 [](){return sqpApp->variableController().hasPendingDownloads();}
83 83 )
84 84 .def_static("addSynchronizationGroup",
85 85 [](QUuid uuid){sqpApp->variableController().onAddSynchronizationGroupId(uuid);}
86 86 )
87 87 .def_static("removeSynchronizationGroup",
88 88 [](QUuid uuid){sqpApp->variableController().onRemoveSynchronizationGroupId(uuid);}
89 89 )
90 90 .def_static("synchronizeVar",
91 91 [](std::shared_ptr<Variable> variable, QUuid uuid){sqpApp->variableController().onAddSynchronized(variable, uuid);}
92 92 )
93 93 .def_static("deSynchronizeVar",
94 94 [](std::shared_ptr<Variable> variable, QUuid uuid){sqpApp->variableController().desynchronize(variable, uuid);}
95 95 )
96 96 .def_static("deleteVariable",
97 97 [](std::shared_ptr<Variable> variable){
98 98 sqpApp->variableController().deleteVariable(variable);}
99 99 )
100 100 .def_static("update_range",[](std::shared_ptr<Variable> variable, const DateTimeRange &range, bool synchronise){
101 101 sqpApp->variableController().onRequestDataLoading({variable}, range, synchronise);
102 102 })
103 103 .def_static("wait_for_downloads",[](){
104 104 while (sqpApp->variableController().hasPendingDownloads()) {
105 105 usleep(100);
106 106 }
107 107 });
108 108
109 109 py::class_<TimeController>(m,"TimeController")
110 110 .def_static("setTime", [](DateTimeRange range){sqpApp->timeController().setDateTimeRange(range);});
111 111
112 112
113 113 auto amda_provider = std::make_shared<AmdaProvider>();
114 114 m.def("amda_provider",[amda_provider](){return amda_provider;}, py::return_value_policy::copy);
115 115
116 116 py::class_<AmdaProvider, std::shared_ptr<AmdaProvider>, IDataProvider>(m, "AmdaProvider");
117 117
118 118 py::class_<AmdaResultParser>(m, "AmdaResultParser")
119 119 .def_static("readTxt", AmdaResultParser::readTxt)
120 120 .def("readScalarTxt", [](const QString& path){
121 121 return std::dynamic_pointer_cast<ScalarSeries>(AmdaResultParser::readTxt(path, DataSeriesType::SCALAR));
122 122 }, py::return_value_policy::copy);
123 123
124 124
125 125 }
126 126
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
This diff has been collapsed as it changes many lines, (507 lines changed) Show them Hide them
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
This diff has been collapsed as it changes many lines, (574 lines changed) Show them Hide them
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
This diff has been collapsed as it changes many lines, (1103 lines changed) Show them Hide them
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
This diff has been collapsed as it changes many lines, (600 lines changed) Show them Hide them
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
This diff has been collapsed as it changes many lines, (508 lines changed) Show them Hide them
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now