##// END OF EJS Templates
Moves the DragDropHelper file
trabillard -
r890:9b45c5936f92
parent child
Show More
1 NO CONTENT: file renamed from gui/include/DragDropHelper.h to gui/include/DragAndDrop/DragDropHelper.h
NO CONTENT: file renamed from gui/include/DragDropHelper.h to gui/include/DragAndDrop/DragDropHelper.h
@@ -1,57 +1,57
1 #ifndef SCIQLOP_VISUALIZATIONDRAGDROPCONTAINER_H
1 #ifndef SCIQLOP_VISUALIZATIONDRAGDROPCONTAINER_H
2 #define SCIQLOP_VISUALIZATIONDRAGDROPCONTAINER_H
2 #define SCIQLOP_VISUALIZATIONDRAGDROPCONTAINER_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5 #include <QFrame>
5 #include <QFrame>
6 #include <QLoggingCategory>
6 #include <QLoggingCategory>
7 #include <QMimeData>
7 #include <QMimeData>
8 #include <QVBoxLayout>
8 #include <QVBoxLayout>
9
9
10 #include <functional>
10 #include <functional>
11
11
12 #include <DragDropHelper.h>
12 #include <DragAndDrop/DragDropHelper.h>
13
13
14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer)
14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer)
15
15
16 class VisualizationDragWidget;
16 class VisualizationDragWidget;
17
17
18 class VisualizationDragDropContainer : public QFrame {
18 class VisualizationDragDropContainer : public QFrame {
19 Q_OBJECT
19 Q_OBJECT
20
20
21 signals:
21 signals:
22 void dropOccuredInContainer(int dropIndex, const QMimeData *mimeData);
22 void dropOccuredInContainer(int dropIndex, const QMimeData *mimeData);
23 void dropOccuredOnWidget(VisualizationDragWidget *dragWidget, const QMimeData *mimeData);
23 void dropOccuredOnWidget(VisualizationDragWidget *dragWidget, const QMimeData *mimeData);
24
24
25 public:
25 public:
26 enum class DropBehavior { Inserted, Merged, InsertedAndMerged };
26 enum class DropBehavior { Inserted, Merged, InsertedAndMerged };
27 using AcceptMimeDataFunction = std::function<bool(const QMimeData *mimeData)>;
27 using AcceptMimeDataFunction = std::function<bool(const QMimeData *mimeData)>;
28
28
29 VisualizationDragDropContainer(QWidget *parent = nullptr);
29 VisualizationDragDropContainer(QWidget *parent = nullptr);
30
30
31 void addDragWidget(VisualizationDragWidget *dragWidget);
31 void addDragWidget(VisualizationDragWidget *dragWidget);
32 void insertDragWidget(int index, VisualizationDragWidget *dragWidget);
32 void insertDragWidget(int index, VisualizationDragWidget *dragWidget);
33
33
34 void addAcceptedMimeType(const QString &mimeType, DropBehavior behavior);
34 void addAcceptedMimeType(const QString &mimeType, DropBehavior behavior);
35
35
36 int countDragWidget() const;
36 int countDragWidget() const;
37
37
38 void setAcceptMimeDataFunction(AcceptMimeDataFunction fun);
38 void setAcceptMimeDataFunction(AcceptMimeDataFunction fun);
39
39
40 void setPlaceHolderType(DragDropHelper::PlaceHolderType type,
40 void setPlaceHolderType(DragDropHelper::PlaceHolderType type,
41 const QString &placeHolderText = QString());
41 const QString &placeHolderText = QString());
42
42
43 protected:
43 protected:
44 void dragEnterEvent(QDragEnterEvent *event);
44 void dragEnterEvent(QDragEnterEvent *event);
45 void dragLeaveEvent(QDragLeaveEvent *event);
45 void dragLeaveEvent(QDragLeaveEvent *event);
46 void dragMoveEvent(QDragMoveEvent *event);
46 void dragMoveEvent(QDragMoveEvent *event);
47 void dropEvent(QDropEvent *event);
47 void dropEvent(QDropEvent *event);
48
48
49 private:
49 private:
50 class VisualizationDragDropContainerPrivate;
50 class VisualizationDragDropContainerPrivate;
51 spimpl::unique_impl_ptr<VisualizationDragDropContainerPrivate> impl;
51 spimpl::unique_impl_ptr<VisualizationDragDropContainerPrivate> impl;
52
52
53 private slots:
53 private slots:
54 void startDrag(VisualizationDragWidget *dragWidget, const QPoint &dragPosition);
54 void startDrag(VisualizationDragWidget *dragWidget, const QPoint &dragPosition);
55 };
55 };
56
56
57 #endif // SCIQLOP_VISUALIZATIONDRAGDROPCONTAINER_H
57 #endif // SCIQLOP_VISUALIZATIONDRAGDROPCONTAINER_H
@@ -1,91 +1,91
1
1
2 gui_moc_headers = [
2 gui_moc_headers = [
3 'include/DataSource/DataSourceWidget.h',
3 'include/DataSource/DataSourceWidget.h',
4 'include/DataSource/DataSourceTreeWidget.h',
4 'include/DataSource/DataSourceTreeWidget.h',
5 'include/Settings/SqpSettingsDialog.h',
5 'include/Settings/SqpSettingsDialog.h',
6 'include/Settings/SqpSettingsGeneralWidget.h',
6 'include/Settings/SqpSettingsGeneralWidget.h',
7 'include/SidePane/SqpSidePane.h',
7 'include/SidePane/SqpSidePane.h',
8 'include/SqpApplication.h',
8 'include/SqpApplication.h',
9 'include/DragDropHelper.h',
9 'include/DragAndDrop/DragDropHelper.h',
10 'include/TimeWidget/TimeWidget.h',
10 'include/TimeWidget/TimeWidget.h',
11 'include/Variable/VariableInspectorWidget.h',
11 'include/Variable/VariableInspectorWidget.h',
12 'include/Variable/VariableInspectorTableView.h',
12 'include/Variable/VariableInspectorTableView.h',
13 'include/Variable/RenameVariableDialog.h',
13 'include/Variable/RenameVariableDialog.h',
14 'include/Visualization/qcustomplot.h',
14 'include/Visualization/qcustomplot.h',
15 'include/Visualization/VisualizationGraphWidget.h',
15 'include/Visualization/VisualizationGraphWidget.h',
16 'include/Visualization/VisualizationTabWidget.h',
16 'include/Visualization/VisualizationTabWidget.h',
17 'include/Visualization/VisualizationWidget.h',
17 'include/Visualization/VisualizationWidget.h',
18 'include/Visualization/VisualizationZoneWidget.h',
18 'include/Visualization/VisualizationZoneWidget.h',
19 'include/Visualization/VisualizationDragDropContainer.h',
19 'include/Visualization/VisualizationDragDropContainer.h',
20 'include/Visualization/VisualizationDragWidget.h'
20 'include/Visualization/VisualizationDragWidget.h'
21 ]
21 ]
22
22
23 gui_ui_files = [
23 gui_ui_files = [
24 'ui/DataSource/DataSourceWidget.ui',
24 'ui/DataSource/DataSourceWidget.ui',
25 'ui/Settings/SqpSettingsDialog.ui',
25 'ui/Settings/SqpSettingsDialog.ui',
26 'ui/Settings/SqpSettingsGeneralWidget.ui',
26 'ui/Settings/SqpSettingsGeneralWidget.ui',
27 'ui/SidePane/SqpSidePane.ui',
27 'ui/SidePane/SqpSidePane.ui',
28 'ui/TimeWidget/TimeWidget.ui',
28 'ui/TimeWidget/TimeWidget.ui',
29 'ui/Variable/VariableInspectorWidget.ui',
29 'ui/Variable/VariableInspectorWidget.ui',
30 'ui/Variable/RenameVariableDialog.ui',
30 'ui/Variable/RenameVariableDialog.ui',
31 'ui/Variable/VariableMenuHeaderWidget.ui',
31 'ui/Variable/VariableMenuHeaderWidget.ui',
32 'ui/Visualization/VisualizationGraphWidget.ui',
32 'ui/Visualization/VisualizationGraphWidget.ui',
33 'ui/Visualization/VisualizationTabWidget.ui',
33 'ui/Visualization/VisualizationTabWidget.ui',
34 'ui/Visualization/VisualizationWidget.ui',
34 'ui/Visualization/VisualizationWidget.ui',
35 'ui/Visualization/VisualizationZoneWidget.ui'
35 'ui/Visualization/VisualizationZoneWidget.ui'
36 ]
36 ]
37
37
38 gui_qresources = ['resources/sqpguiresources.qrc']
38 gui_qresources = ['resources/sqpguiresources.qrc']
39
39
40 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
40 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
41 ui_files : gui_ui_files,
41 ui_files : gui_ui_files,
42 qresources : gui_qresources)
42 qresources : gui_qresources)
43
43
44 gui_sources = [
44 gui_sources = [
45 'src/SqpApplication.cpp',
45 'src/SqpApplication.cpp',
46 'src/DragDropHelper.cpp',
46 'src/DragAndDrop/DragDropHelper.cpp',
47 'src/Common/ColorUtils.cpp',
47 'src/Common/ColorUtils.cpp',
48 'src/Common/VisualizationDef.cpp',
48 'src/Common/VisualizationDef.cpp',
49 'src/DataSource/DataSourceTreeWidgetItem.cpp',
49 'src/DataSource/DataSourceTreeWidgetItem.cpp',
50 'src/DataSource/DataSourceTreeWidgetHelper.cpp',
50 'src/DataSource/DataSourceTreeWidgetHelper.cpp',
51 'src/DataSource/DataSourceWidget.cpp',
51 'src/DataSource/DataSourceWidget.cpp',
52 'src/DataSource/DataSourceTreeWidget.cpp',
52 'src/DataSource/DataSourceTreeWidget.cpp',
53 'src/Settings/SqpSettingsDialog.cpp',
53 'src/Settings/SqpSettingsDialog.cpp',
54 'src/Settings/SqpSettingsGeneralWidget.cpp',
54 'src/Settings/SqpSettingsGeneralWidget.cpp',
55 'src/SidePane/SqpSidePane.cpp',
55 'src/SidePane/SqpSidePane.cpp',
56 'src/TimeWidget/TimeWidget.cpp',
56 'src/TimeWidget/TimeWidget.cpp',
57 'src/Variable/VariableInspectorWidget.cpp',
57 'src/Variable/VariableInspectorWidget.cpp',
58 'src/Variable/VariableInspectorTableView.cpp',
58 'src/Variable/VariableInspectorTableView.cpp',
59 'src/Variable/VariableMenuHeaderWidget.cpp',
59 'src/Variable/VariableMenuHeaderWidget.cpp',
60 'src/Variable/RenameVariableDialog.cpp',
60 'src/Variable/RenameVariableDialog.cpp',
61 'src/Visualization/VisualizationGraphHelper.cpp',
61 'src/Visualization/VisualizationGraphHelper.cpp',
62 'src/Visualization/VisualizationGraphRenderingDelegate.cpp',
62 'src/Visualization/VisualizationGraphRenderingDelegate.cpp',
63 'src/Visualization/VisualizationGraphWidget.cpp',
63 'src/Visualization/VisualizationGraphWidget.cpp',
64 'src/Visualization/VisualizationTabWidget.cpp',
64 'src/Visualization/VisualizationTabWidget.cpp',
65 'src/Visualization/VisualizationWidget.cpp',
65 'src/Visualization/VisualizationWidget.cpp',
66 'src/Visualization/VisualizationZoneWidget.cpp',
66 'src/Visualization/VisualizationZoneWidget.cpp',
67 'src/Visualization/qcustomplot.cpp',
67 'src/Visualization/qcustomplot.cpp',
68 'src/Visualization/QCustomPlotSynchronizer.cpp',
68 'src/Visualization/QCustomPlotSynchronizer.cpp',
69 'src/Visualization/operations/FindVariableOperation.cpp',
69 'src/Visualization/operations/FindVariableOperation.cpp',
70 'src/Visualization/operations/GenerateVariableMenuOperation.cpp',
70 'src/Visualization/operations/GenerateVariableMenuOperation.cpp',
71 'src/Visualization/operations/MenuBuilder.cpp',
71 'src/Visualization/operations/MenuBuilder.cpp',
72 'src/Visualization/operations/RemoveVariableOperation.cpp',
72 'src/Visualization/operations/RemoveVariableOperation.cpp',
73 'src/Visualization/operations/RescaleAxeOperation.cpp',
73 'src/Visualization/operations/RescaleAxeOperation.cpp',
74 'src/Visualization/VisualizationDragDropContainer.cpp',
74 'src/Visualization/VisualizationDragDropContainer.cpp',
75 'src/Visualization/VisualizationDragWidget.cpp'
75 'src/Visualization/VisualizationDragWidget.cpp'
76 ]
76 ]
77
77
78 gui_inc = include_directories(['include'])
78 gui_inc = include_directories(['include'])
79
79
80 sciqlop_gui_lib = library('sciqlopgui',
80 sciqlop_gui_lib = library('sciqlopgui',
81 gui_sources,
81 gui_sources,
82 gui_moc_files,
82 gui_moc_files,
83 include_directories : [gui_inc],
83 include_directories : [gui_inc],
84 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core],
84 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core],
85 install : true
85 install : true
86 )
86 )
87
87
88 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
88 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
89 include_directories : gui_inc,
89 include_directories : gui_inc,
90 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core])
90 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core])
91
91
@@ -1,45 +1,45
1 #include "DataSource/DataSourceTreeWidget.h"
1 #include "DataSource/DataSourceTreeWidget.h"
2 #include "Common/MimeTypesDef.h"
2 #include "Common/MimeTypesDef.h"
3 #include "DataSource/DataSourceController.h"
3 #include "DataSource/DataSourceController.h"
4 #include "DataSource/DataSourceItem.h"
4 #include "DataSource/DataSourceItem.h"
5 #include "DataSource/DataSourceTreeWidgetItem.h"
5 #include "DataSource/DataSourceTreeWidgetItem.h"
6
6
7 #include "DragDropHelper.h"
7 #include "DragAndDrop/DragDropHelper.h"
8 #include "SqpApplication.h"
8 #include "SqpApplication.h"
9
9
10 #include <QMimeData>
10 #include <QMimeData>
11
11
12 DataSourceTreeWidget::DataSourceTreeWidget(QWidget *parent) : QTreeWidget(parent) {}
12 DataSourceTreeWidget::DataSourceTreeWidget(QWidget *parent) : QTreeWidget(parent) {}
13
13
14 QMimeData *DataSourceTreeWidget::mimeData(const QList<QTreeWidgetItem *> items) const
14 QMimeData *DataSourceTreeWidget::mimeData(const QList<QTreeWidgetItem *> items) const
15 {
15 {
16 auto mimeData = new QMimeData;
16 auto mimeData = new QMimeData;
17
17
18 // Basic check to ensure the item are correctly typed
18 // Basic check to ensure the item are correctly typed
19 Q_ASSERT(items.isEmpty() || dynamic_cast<DataSourceTreeWidgetItem *>(items.first()) != nullptr);
19 Q_ASSERT(items.isEmpty() || dynamic_cast<DataSourceTreeWidgetItem *>(items.first()) != nullptr);
20
20
21 QVariantList productData;
21 QVariantList productData;
22
22
23 for (auto item : items) {
23 for (auto item : items) {
24 auto dataSourceTreeItem = static_cast<DataSourceTreeWidgetItem *>(item);
24 auto dataSourceTreeItem = static_cast<DataSourceTreeWidgetItem *>(item);
25 auto dataSource = dataSourceTreeItem->data();
25 auto dataSource = dataSourceTreeItem->data();
26
26
27 if (dataSource->type() == DataSourceItemType::COMPONENT
27 if (dataSource->type() == DataSourceItemType::COMPONENT
28 || dataSource->type() == DataSourceItemType::PRODUCT) {
28 || dataSource->type() == DataSourceItemType::PRODUCT) {
29 auto metaData = dataSource->data();
29 auto metaData = dataSource->data();
30 productData << metaData;
30 productData << metaData;
31 }
31 }
32 }
32 }
33
33
34 auto encodedData = sqpApp->dataSourceController().mimeDataForProductsData(productData);
34 auto encodedData = sqpApp->dataSourceController().mimeDataForProductsData(productData);
35 mimeData->setData(MIME_TYPE_PRODUCT_LIST, encodedData);
35 mimeData->setData(MIME_TYPE_PRODUCT_LIST, encodedData);
36
36
37 return mimeData;
37 return mimeData;
38 }
38 }
39
39
40 void DataSourceTreeWidget::startDrag(Qt::DropActions supportedActions)
40 void DataSourceTreeWidget::startDrag(Qt::DropActions supportedActions)
41 {
41 {
42 // Resets the drag&drop operations before it's starting
42 // Resets the drag&drop operations before it's starting
43 sqpApp->dragDropHelper().resetDragAndDrop();
43 sqpApp->dragDropHelper().resetDragAndDrop();
44 QTreeWidget::startDrag(supportedActions);
44 QTreeWidget::startDrag(supportedActions);
45 }
45 }
@@ -1,383 +1,381
1 #include "DragDropHelper.h"
1 #include "DragAndDrop/DragDropHelper.h"
2 #include "SqpApplication.h"
2 #include "SqpApplication.h"
3 #include "Visualization/VisualizationDragDropContainer.h"
3 #include "Visualization/VisualizationDragDropContainer.h"
4 #include "Visualization/VisualizationDragWidget.h"
4 #include "Visualization/VisualizationDragWidget.h"
5 #include "Visualization/VisualizationWidget.h"
5 #include "Visualization/VisualizationWidget.h"
6 #include "Visualization/operations/FindVariableOperation.h"
6 #include "Visualization/operations/FindVariableOperation.h"
7
7
8 #include "Variable/Variable.h"
8 #include "Variable/Variable.h"
9 #include "Variable/VariableController.h"
9 #include "Variable/VariableController.h"
10
10
11 #include "Common/MimeTypesDef.h"
11 #include "Common/MimeTypesDef.h"
12 #include "Common/VisualizationDef.h"
12 #include "Common/VisualizationDef.h"
13
13
14 #include <QDir>
14 #include <QDir>
15 #include <QDragEnterEvent>
15 #include <QDragEnterEvent>
16 #include <QDragMoveEvent>
16 #include <QDragMoveEvent>
17 #include <QLabel>
17 #include <QLabel>
18 #include <QScrollArea>
18 #include <QScrollArea>
19 #include <QScrollBar>
19 #include <QScrollBar>
20 #include <QTimer>
20 #include <QTimer>
21 #include <QVBoxLayout>
21 #include <QVBoxLayout>
22
22
23 const int SCROLL_SPEED = 5;
23 const int SCROLL_SPEED = 5;
24 const int SCROLL_ZONE_SIZE = 50;
24 const int SCROLL_ZONE_SIZE = 50;
25
25
26 Q_LOGGING_CATEGORY(LOG_DragDropHelper, "DragDrophelper")
26 Q_LOGGING_CATEGORY(LOG_DragDropHelper, "DragDrophelper")
27
27
28 struct DragDropScroller::DragDropScrollerPrivate {
28 struct DragDropScroller::DragDropScrollerPrivate {
29
29
30 QList<QScrollArea *> m_ScrollAreas;
30 QList<QScrollArea *> m_ScrollAreas;
31 QScrollArea *m_CurrentScrollArea = nullptr;
31 QScrollArea *m_CurrentScrollArea = nullptr;
32 std::unique_ptr<QTimer> m_Timer = nullptr;
32 std::unique_ptr<QTimer> m_Timer = nullptr;
33
33
34 enum class ScrollDirection { up, down, unknown };
34 enum class ScrollDirection { up, down, unknown };
35 ScrollDirection m_Direction = ScrollDirection::unknown;
35 ScrollDirection m_Direction = ScrollDirection::unknown;
36
36
37 explicit DragDropScrollerPrivate() : m_Timer{std::make_unique<QTimer>()}
37 explicit DragDropScrollerPrivate() : m_Timer{std::make_unique<QTimer>()}
38 {
38 {
39 m_Timer->setInterval(0);
39 m_Timer->setInterval(0);
40 }
40 }
41 };
41 };
42
42
43 DragDropScroller::DragDropScroller(QObject *parent)
43 DragDropScroller::DragDropScroller(QObject *parent)
44 : QObject{parent}, impl{spimpl::make_unique_impl<DragDropScrollerPrivate>()}
44 : QObject{parent}, impl{spimpl::make_unique_impl<DragDropScrollerPrivate>()}
45 {
45 {
46 connect(impl->m_Timer.get(), &QTimer::timeout, this, &DragDropScroller::onTimer);
46 connect(impl->m_Timer.get(), &QTimer::timeout, this, &DragDropScroller::onTimer);
47 }
47 }
48
48
49 void DragDropScroller::addScrollArea(QScrollArea *scrollArea)
49 void DragDropScroller::addScrollArea(QScrollArea *scrollArea)
50 {
50 {
51 impl->m_ScrollAreas << scrollArea;
51 impl->m_ScrollAreas << scrollArea;
52 scrollArea->viewport()->setAcceptDrops(true);
52 scrollArea->viewport()->setAcceptDrops(true);
53 }
53 }
54
54
55 void DragDropScroller::removeScrollArea(QScrollArea *scrollArea)
55 void DragDropScroller::removeScrollArea(QScrollArea *scrollArea)
56 {
56 {
57 impl->m_ScrollAreas.removeAll(scrollArea);
57 impl->m_ScrollAreas.removeAll(scrollArea);
58 scrollArea->viewport()->setAcceptDrops(false);
58 scrollArea->viewport()->setAcceptDrops(false);
59 }
59 }
60
60
61 bool DragDropScroller::eventFilter(QObject *obj, QEvent *event)
61 bool DragDropScroller::eventFilter(QObject *obj, QEvent *event)
62 {
62 {
63 if (event->type() == QEvent::DragMove) {
63 if (event->type() == QEvent::DragMove) {
64 auto w = static_cast<QWidget *>(obj);
64 auto w = static_cast<QWidget *>(obj);
65
65
66 if (impl->m_CurrentScrollArea && impl->m_CurrentScrollArea->isAncestorOf(w)) {
66 if (impl->m_CurrentScrollArea && impl->m_CurrentScrollArea->isAncestorOf(w)) {
67 auto moveEvent = static_cast<QDragMoveEvent *>(event);
67 auto moveEvent = static_cast<QDragMoveEvent *>(event);
68
68
69 auto pos = moveEvent->pos();
69 auto pos = moveEvent->pos();
70 if (impl->m_CurrentScrollArea->viewport() != w) {
70 if (impl->m_CurrentScrollArea->viewport() != w) {
71 auto globalPos = w->mapToGlobal(moveEvent->pos());
71 auto globalPos = w->mapToGlobal(moveEvent->pos());
72 pos = impl->m_CurrentScrollArea->viewport()->mapFromGlobal(globalPos);
72 pos = impl->m_CurrentScrollArea->viewport()->mapFromGlobal(globalPos);
73 }
73 }
74
74
75 auto isInTopZone = pos.y() > impl->m_CurrentScrollArea->viewport()->size().height()
75 auto isInTopZone = pos.y() > impl->m_CurrentScrollArea->viewport()->size().height()
76 - SCROLL_ZONE_SIZE;
76 - SCROLL_ZONE_SIZE;
77 auto isInBottomZone = pos.y() < SCROLL_ZONE_SIZE;
77 auto isInBottomZone = pos.y() < SCROLL_ZONE_SIZE;
78
78
79 if (!isInTopZone && !isInBottomZone) {
79 if (!isInTopZone && !isInBottomZone) {
80 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
80 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
81 impl->m_Timer->stop();
81 impl->m_Timer->stop();
82 }
82 }
83 else if (!impl->m_Timer->isActive()) {
83 else if (!impl->m_Timer->isActive()) {
84 impl->m_Direction = isInTopZone ? DragDropScrollerPrivate::ScrollDirection::up
84 impl->m_Direction = isInTopZone ? DragDropScrollerPrivate::ScrollDirection::up
85 : DragDropScrollerPrivate::ScrollDirection::down;
85 : DragDropScrollerPrivate::ScrollDirection::down;
86 impl->m_Timer->start();
86 impl->m_Timer->start();
87 }
87 }
88 }
88 }
89 }
89 }
90 else if (event->type() == QEvent::DragEnter) {
90 else if (event->type() == QEvent::DragEnter) {
91 auto w = static_cast<QWidget *>(obj);
91 auto w = static_cast<QWidget *>(obj);
92
92
93 for (auto scrollArea : impl->m_ScrollAreas) {
93 for (auto scrollArea : impl->m_ScrollAreas) {
94 if (impl->m_CurrentScrollArea != scrollArea && scrollArea->isAncestorOf(w)) {
94 if (impl->m_CurrentScrollArea != scrollArea && scrollArea->isAncestorOf(w)) {
95 auto enterEvent = static_cast<QDragEnterEvent *>(event);
95 auto enterEvent = static_cast<QDragEnterEvent *>(event);
96 enterEvent->acceptProposedAction();
96 enterEvent->acceptProposedAction();
97 enterEvent->setDropAction(Qt::IgnoreAction);
97 enterEvent->setDropAction(Qt::IgnoreAction);
98 impl->m_CurrentScrollArea = scrollArea;
98 impl->m_CurrentScrollArea = scrollArea;
99 break;
99 break;
100 }
100 }
101 }
101 }
102 }
102 }
103 else if (event->type() == QEvent::DragLeave) {
103 else if (event->type() == QEvent::DragLeave) {
104 if (impl->m_CurrentScrollArea) {
104 if (impl->m_CurrentScrollArea) {
105 if (!QRect(QPoint(), impl->m_CurrentScrollArea->size())
105 if (!QRect(QPoint(), impl->m_CurrentScrollArea->size())
106 .contains(impl->m_CurrentScrollArea->mapFromGlobal(QCursor::pos()))) {
106 .contains(impl->m_CurrentScrollArea->mapFromGlobal(QCursor::pos()))) {
107 impl->m_CurrentScrollArea = nullptr;
107 impl->m_CurrentScrollArea = nullptr;
108 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
108 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
109 impl->m_Timer->stop();
109 impl->m_Timer->stop();
110 }
110 }
111 }
111 }
112 }
112 }
113 else if (event->type() == QEvent::Drop) {
113 else if (event->type() == QEvent::Drop) {
114 if (impl->m_CurrentScrollArea) {
114 if (impl->m_CurrentScrollArea) {
115 impl->m_CurrentScrollArea = nullptr;
115 impl->m_CurrentScrollArea = nullptr;
116 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
116 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
117 impl->m_Timer->stop();
117 impl->m_Timer->stop();
118 }
118 }
119 }
119 }
120
120
121 return false;
121 return false;
122 }
122 }
123
123
124 void DragDropScroller::onTimer()
124 void DragDropScroller::onTimer()
125 {
125 {
126 if (impl->m_CurrentScrollArea) {
126 if (impl->m_CurrentScrollArea) {
127 auto mvt = 0;
127 auto mvt = 0;
128 switch (impl->m_Direction) {
128 switch (impl->m_Direction) {
129 case DragDropScrollerPrivate::ScrollDirection::up:
129 case DragDropScrollerPrivate::ScrollDirection::up:
130 mvt = SCROLL_SPEED;
130 mvt = SCROLL_SPEED;
131 break;
131 break;
132 case DragDropScrollerPrivate::ScrollDirection::down:
132 case DragDropScrollerPrivate::ScrollDirection::down:
133 mvt = -SCROLL_SPEED;
133 mvt = -SCROLL_SPEED;
134 break;
134 break;
135 default:
135 default:
136 break;
136 break;
137 }
137 }
138
138
139 impl->m_CurrentScrollArea->verticalScrollBar()->setValue(
139 impl->m_CurrentScrollArea->verticalScrollBar()->setValue(
140 impl->m_CurrentScrollArea->verticalScrollBar()->value() + mvt);
140 impl->m_CurrentScrollArea->verticalScrollBar()->value() + mvt);
141 }
141 }
142 }
142 }
143
143
144 struct DragDropHelper::DragDropHelperPrivate {
144 struct DragDropHelper::DragDropHelperPrivate {
145
145
146 VisualizationDragWidget *m_CurrentDragWidget = nullptr;
146 VisualizationDragWidget *m_CurrentDragWidget = nullptr;
147 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
147 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
148 QLabel *m_PlaceHolderLabel;
148 QLabel *m_PlaceHolderLabel;
149 QWidget *m_PlaceBackground;
149 QWidget *m_PlaceBackground;
150 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
150 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
151 QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using
151 QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using
152 // QTemporaryFile to have a name which is not generated.
152 // QTemporaryFile to have a name which is not generated.
153
153
154 VisualizationDragWidget *m_HighlightedDragWidget = nullptr;
154 VisualizationDragWidget *m_HighlightedDragWidget = nullptr;
155
155
156 QMetaObject::Connection m_DragWidgetDestroyedConnection;
156 QMetaObject::Connection m_DragWidgetDestroyedConnection;
157 QMetaObject::Connection m_HighlightedWidgetDestroyedConnection;
157 QMetaObject::Connection m_HighlightedWidgetDestroyedConnection;
158
158
159 explicit DragDropHelperPrivate()
159 explicit DragDropHelperPrivate()
160 : m_PlaceHolder{std::make_unique<QWidget>()},
160 : m_PlaceHolder{std::make_unique<QWidget>()},
161 m_DragDropScroller{std::make_unique<DragDropScroller>()}
161 m_DragDropScroller{std::make_unique<DragDropScroller>()}
162 {
162 {
163
163
164 auto layout = new QVBoxLayout{m_PlaceHolder.get()};
164 auto layout = new QVBoxLayout{m_PlaceHolder.get()};
165 layout->setSpacing(0);
165 layout->setSpacing(0);
166 layout->setContentsMargins(0, 0, 0, 0);
166 layout->setContentsMargins(0, 0, 0, 0);
167
167
168 m_PlaceHolderLabel = new QLabel{"", m_PlaceHolder.get()};
168 m_PlaceHolderLabel = new QLabel{"", m_PlaceHolder.get()};
169 m_PlaceHolderLabel->setMinimumHeight(25);
169 m_PlaceHolderLabel->setMinimumHeight(25);
170 layout->addWidget(m_PlaceHolderLabel);
170 layout->addWidget(m_PlaceHolderLabel);
171
171
172 m_PlaceBackground = new QWidget{m_PlaceHolder.get()};
172 m_PlaceBackground = new QWidget{m_PlaceHolder.get()};
173 m_PlaceBackground->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
173 m_PlaceBackground->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
174 layout->addWidget(m_PlaceBackground);
174 layout->addWidget(m_PlaceBackground);
175
175
176 sqpApp->installEventFilter(m_DragDropScroller.get());
176 sqpApp->installEventFilter(m_DragDropScroller.get());
177
177
178 m_ImageTempUrl = QDir::temp().absoluteFilePath("Sciqlop_graph.png");
178 m_ImageTempUrl = QDir::temp().absoluteFilePath("Sciqlop_graph.png");
179 }
179 }
180
180
181 void preparePlaceHolder(DragDropHelper::PlaceHolderType type, const QString &topLabelText) const
181 void preparePlaceHolder(DragDropHelper::PlaceHolderType type, const QString &topLabelText) const
182 {
182 {
183 if (m_CurrentDragWidget) {
183 if (m_CurrentDragWidget) {
184 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
184 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
185 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
185 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
186 }
186 }
187 else {
187 else {
188 // Configuration of the placeHolder when there is no dragWidget
188 // Configuration of the placeHolder when there is no dragWidget
189 // (for instance with a drag from a variable)
189 // (for instance with a drag from a variable)
190
190
191 m_PlaceHolder->setMinimumSize(0, GRAPH_MINIMUM_HEIGHT);
191 m_PlaceHolder->setMinimumSize(0, GRAPH_MINIMUM_HEIGHT);
192 m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
192 m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
193 }
193 }
194
194
195 switch (type) {
195 switch (type) {
196 case DragDropHelper::PlaceHolderType::Graph:
196 case DragDropHelper::PlaceHolderType::Graph:
197 m_PlaceBackground->setStyleSheet(
197 m_PlaceBackground->setStyleSheet(
198 "background-color: #BBD5EE; border: 1px solid #2A7FD4");
198 "background-color: #BBD5EE; border: 1px solid #2A7FD4");
199 break;
199 break;
200 case DragDropHelper::PlaceHolderType::Zone:
200 case DragDropHelper::PlaceHolderType::Zone:
201 case DragDropHelper::PlaceHolderType::Default:
201 case DragDropHelper::PlaceHolderType::Default:
202 m_PlaceBackground->setStyleSheet(
202 m_PlaceBackground->setStyleSheet(
203 "background-color: #BBD5EE; border: 2px solid #2A7FD4");
203 "background-color: #BBD5EE; border: 2px solid #2A7FD4");
204 m_PlaceHolderLabel->setStyleSheet("color: #2A7FD4");
204 m_PlaceHolderLabel->setStyleSheet("color: #2A7FD4");
205 break;
205 break;
206 }
206 }
207
207
208 m_PlaceHolderLabel->setText(topLabelText);
208 m_PlaceHolderLabel->setText(topLabelText);
209 m_PlaceHolderLabel->setVisible(!topLabelText.isEmpty());
209 m_PlaceHolderLabel->setVisible(!topLabelText.isEmpty());
210 }
210 }
211 };
211 };
212
212
213
213
214 DragDropHelper::DragDropHelper() : impl{spimpl::make_unique_impl<DragDropHelperPrivate>()}
214 DragDropHelper::DragDropHelper() : impl{spimpl::make_unique_impl<DragDropHelperPrivate>()} {}
215 {
216 }
217
215
218 DragDropHelper::~DragDropHelper()
216 DragDropHelper::~DragDropHelper()
219 {
217 {
220 QFile::remove(impl->m_ImageTempUrl);
218 QFile::remove(impl->m_ImageTempUrl);
221 }
219 }
222
220
223 void DragDropHelper::resetDragAndDrop()
221 void DragDropHelper::resetDragAndDrop()
224 {
222 {
225 setCurrentDragWidget(nullptr);
223 setCurrentDragWidget(nullptr);
226 impl->m_HighlightedDragWidget = nullptr;
224 impl->m_HighlightedDragWidget = nullptr;
227 }
225 }
228
226
229 void DragDropHelper::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
227 void DragDropHelper::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
230 {
228 {
231 if (impl->m_CurrentDragWidget) {
229 if (impl->m_CurrentDragWidget) {
232
230
233 QObject::disconnect(impl->m_DragWidgetDestroyedConnection);
231 QObject::disconnect(impl->m_DragWidgetDestroyedConnection);
234 }
232 }
235
233
236 if (dragWidget) {
234 if (dragWidget) {
237 // ensures the impl->m_CurrentDragWidget is reset when the widget is destroyed
235 // ensures the impl->m_CurrentDragWidget is reset when the widget is destroyed
238 impl->m_DragWidgetDestroyedConnection
236 impl->m_DragWidgetDestroyedConnection
239 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
237 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
240 [this]() { impl->m_CurrentDragWidget = nullptr; });
238 [this]() { impl->m_CurrentDragWidget = nullptr; });
241 }
239 }
242
240
243 impl->m_CurrentDragWidget = dragWidget;
241 impl->m_CurrentDragWidget = dragWidget;
244 }
242 }
245
243
246 VisualizationDragWidget *DragDropHelper::getCurrentDragWidget() const
244 VisualizationDragWidget *DragDropHelper::getCurrentDragWidget() const
247 {
245 {
248 return impl->m_CurrentDragWidget;
246 return impl->m_CurrentDragWidget;
249 }
247 }
250
248
251 QWidget &DragDropHelper::placeHolder() const
249 QWidget &DragDropHelper::placeHolder() const
252 {
250 {
253 return *impl->m_PlaceHolder;
251 return *impl->m_PlaceHolder;
254 }
252 }
255
253
256 void DragDropHelper::insertPlaceHolder(QVBoxLayout *layout, int index, PlaceHolderType type,
254 void DragDropHelper::insertPlaceHolder(QVBoxLayout *layout, int index, PlaceHolderType type,
257 const QString &topLabelText)
255 const QString &topLabelText)
258 {
256 {
259 removePlaceHolder();
257 removePlaceHolder();
260 impl->preparePlaceHolder(type, topLabelText);
258 impl->preparePlaceHolder(type, topLabelText);
261 layout->insertWidget(index, impl->m_PlaceHolder.get());
259 layout->insertWidget(index, impl->m_PlaceHolder.get());
262 impl->m_PlaceHolder->show();
260 impl->m_PlaceHolder->show();
263 }
261 }
264
262
265 void DragDropHelper::removePlaceHolder()
263 void DragDropHelper::removePlaceHolder()
266 {
264 {
267 auto parentWidget = impl->m_PlaceHolder->parentWidget();
265 auto parentWidget = impl->m_PlaceHolder->parentWidget();
268 if (parentWidget) {
266 if (parentWidget) {
269 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
267 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
270 impl->m_PlaceHolder->setParent(nullptr);
268 impl->m_PlaceHolder->setParent(nullptr);
271 impl->m_PlaceHolder->hide();
269 impl->m_PlaceHolder->hide();
272 }
270 }
273 }
271 }
274
272
275 bool DragDropHelper::isPlaceHolderSet() const
273 bool DragDropHelper::isPlaceHolderSet() const
276 {
274 {
277 return impl->m_PlaceHolder->parentWidget();
275 return impl->m_PlaceHolder->parentWidget();
278 }
276 }
279
277
280 void DragDropHelper::addDragDropScrollArea(QScrollArea *scrollArea)
278 void DragDropHelper::addDragDropScrollArea(QScrollArea *scrollArea)
281 {
279 {
282 impl->m_DragDropScroller->addScrollArea(scrollArea);
280 impl->m_DragDropScroller->addScrollArea(scrollArea);
283 }
281 }
284
282
285 void DragDropHelper::removeDragDropScrollArea(QScrollArea *scrollArea)
283 void DragDropHelper::removeDragDropScrollArea(QScrollArea *scrollArea)
286 {
284 {
287 impl->m_DragDropScroller->removeScrollArea(scrollArea);
285 impl->m_DragDropScroller->removeScrollArea(scrollArea);
288 }
286 }
289
287
290 QUrl DragDropHelper::imageTemporaryUrl(const QImage &image) const
288 QUrl DragDropHelper::imageTemporaryUrl(const QImage &image) const
291 {
289 {
292 image.save(impl->m_ImageTempUrl);
290 image.save(impl->m_ImageTempUrl);
293 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
291 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
294 }
292 }
295
293
296 void DragDropHelper::setHightlightedDragWidget(VisualizationDragWidget *dragWidget)
294 void DragDropHelper::setHightlightedDragWidget(VisualizationDragWidget *dragWidget)
297 {
295 {
298 if (impl->m_HighlightedDragWidget) {
296 if (impl->m_HighlightedDragWidget) {
299 impl->m_HighlightedDragWidget->highlightForMerge(false);
297 impl->m_HighlightedDragWidget->highlightForMerge(false);
300 QObject::disconnect(impl->m_HighlightedWidgetDestroyedConnection);
298 QObject::disconnect(impl->m_HighlightedWidgetDestroyedConnection);
301 }
299 }
302
300
303 if (dragWidget) {
301 if (dragWidget) {
304 dragWidget->highlightForMerge(true);
302 dragWidget->highlightForMerge(true);
305
303
306 // ensures the impl->m_HighlightedDragWidget is reset when the widget is destroyed
304 // ensures the impl->m_HighlightedDragWidget is reset when the widget is destroyed
307 impl->m_DragWidgetDestroyedConnection
305 impl->m_DragWidgetDestroyedConnection
308 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
306 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
309 [this]() { impl->m_HighlightedDragWidget = nullptr; });
307 [this]() { impl->m_HighlightedDragWidget = nullptr; });
310 }
308 }
311
309
312 impl->m_HighlightedDragWidget = dragWidget;
310 impl->m_HighlightedDragWidget = dragWidget;
313 }
311 }
314
312
315 VisualizationDragWidget *DragDropHelper::getHightlightedDragWidget() const
313 VisualizationDragWidget *DragDropHelper::getHightlightedDragWidget() const
316 {
314 {
317 return impl->m_HighlightedDragWidget;
315 return impl->m_HighlightedDragWidget;
318 }
316 }
319
317
320 bool DragDropHelper::checkMimeDataForVisualization(const QMimeData *mimeData,
318 bool DragDropHelper::checkMimeDataForVisualization(const QMimeData *mimeData,
321 VisualizationDragDropContainer *dropContainer)
319 VisualizationDragDropContainer *dropContainer)
322 {
320 {
323 if (!mimeData || !dropContainer) {
321 if (!mimeData || !dropContainer) {
324 qCWarning(LOG_DragDropHelper()) << QObject::tr(
322 qCWarning(LOG_DragDropHelper()) << QObject::tr(
325 "DragDropHelper::checkMimeDataForVisualization, invalid input parameters.");
323 "DragDropHelper::checkMimeDataForVisualization, invalid input parameters.");
326 Q_ASSERT(false);
324 Q_ASSERT(false);
327 return false;
325 return false;
328 }
326 }
329
327
330 auto result = false;
328 auto result = false;
331
329
332 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
330 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
333 auto variables = sqpApp->variableController().variablesForMimeData(
331 auto variables = sqpApp->variableController().variablesForMimeData(
334 mimeData->data(MIME_TYPE_VARIABLE_LIST));
332 mimeData->data(MIME_TYPE_VARIABLE_LIST));
335
333
336 if (variables.count() == 1) {
334 if (variables.count() == 1) {
337
335
338 auto variable = variables.first();
336 auto variable = variables.first();
339 if (variable->dataSeries() != nullptr) {
337 if (variable->dataSeries() != nullptr) {
340
338
341 // Check that the variable is not already in a graph
339 // Check that the variable is not already in a graph
342
340
343 auto parent = dropContainer->parentWidget();
341 auto parent = dropContainer->parentWidget();
344 while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) {
342 while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) {
345 parent = parent->parentWidget(); // Search for the top level VisualizationWidget
343 parent = parent->parentWidget(); // Search for the top level VisualizationWidget
346 }
344 }
347
345
348 if (parent) {
346 if (parent) {
349 auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
347 auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
350
348
351 FindVariableOperation findVariableOperation{variable};
349 FindVariableOperation findVariableOperation{variable};
352 visualizationWidget->accept(&findVariableOperation);
350 visualizationWidget->accept(&findVariableOperation);
353 auto variableContainers = findVariableOperation.result();
351 auto variableContainers = findVariableOperation.result();
354 if (variableContainers.empty()) {
352 if (variableContainers.empty()) {
355 result = true;
353 result = true;
356 }
354 }
357 else {
355 else {
358 // result = false: the variable already exist in the visualisation
356 // result = false: the variable already exist in the visualisation
359 }
357 }
360 }
358 }
361 else {
359 else {
362 qCWarning(LOG_DragDropHelper()) << QObject::tr(
360 qCWarning(LOG_DragDropHelper()) << QObject::tr(
363 "DragDropHelper::checkMimeDataForVisualization, the parent "
361 "DragDropHelper::checkMimeDataForVisualization, the parent "
364 "VisualizationWidget cannot be found. Cannot check if the variable is "
362 "VisualizationWidget cannot be found. Cannot check if the variable is "
365 "already used or not.");
363 "already used or not.");
366 }
364 }
367 }
365 }
368 else {
366 else {
369 // result = false: the variable is not fully loaded
367 // result = false: the variable is not fully loaded
370 }
368 }
371 }
369 }
372 else {
370 else {
373 // result = false: cannot drop multiple variables in the visualisation
371 // result = false: cannot drop multiple variables in the visualisation
374 }
372 }
375 }
373 }
376 else {
374 else {
377 // Other MIME data
375 // Other MIME data
378 // no special rules, accepted by default
376 // no special rules, accepted by default
379 result = true;
377 result = true;
380 }
378 }
381
379
382 return result;
380 return result;
383 }
381 }
@@ -1,163 +1,163
1 #include "SqpApplication.h"
1 #include "SqpApplication.h"
2
2
3 #include <Data/IDataProvider.h>
3 #include <Data/IDataProvider.h>
4 #include <DataSource/DataSourceController.h>
4 #include <DataSource/DataSourceController.h>
5 #include <DragDropHelper.h>
5 #include <DragAndDrop/DragDropHelper.h>
6 #include <Network/NetworkController.h>
6 #include <Network/NetworkController.h>
7 #include <QThread>
7 #include <QThread>
8 #include <Time/TimeController.h>
8 #include <Time/TimeController.h>
9 #include <Variable/Variable.h>
9 #include <Variable/Variable.h>
10 #include <Variable/VariableController.h>
10 #include <Variable/VariableController.h>
11 #include <Variable/VariableModel.h>
11 #include <Variable/VariableModel.h>
12 #include <Visualization/VisualizationController.h>
12 #include <Visualization/VisualizationController.h>
13
13
14 Q_LOGGING_CATEGORY(LOG_SqpApplication, "SqpApplication")
14 Q_LOGGING_CATEGORY(LOG_SqpApplication, "SqpApplication")
15
15
16 class SqpApplication::SqpApplicationPrivate {
16 class SqpApplication::SqpApplicationPrivate {
17 public:
17 public:
18 SqpApplicationPrivate()
18 SqpApplicationPrivate()
19 : m_DataSourceController{std::make_unique<DataSourceController>()},
19 : m_DataSourceController{std::make_unique<DataSourceController>()},
20 m_NetworkController{std::make_unique<NetworkController>()},
20 m_NetworkController{std::make_unique<NetworkController>()},
21 m_TimeController{std::make_unique<TimeController>()},
21 m_TimeController{std::make_unique<TimeController>()},
22 m_VariableController{std::make_unique<VariableController>()},
22 m_VariableController{std::make_unique<VariableController>()},
23 m_VisualizationController{std::make_unique<VisualizationController>()},
23 m_VisualizationController{std::make_unique<VisualizationController>()},
24 m_DragDropHelper{std::make_unique<DragDropHelper>()}
24 m_DragDropHelper{std::make_unique<DragDropHelper>()}
25 {
25 {
26 // /////////////////////////////// //
26 // /////////////////////////////// //
27 // Connections between controllers //
27 // Connections between controllers //
28 // /////////////////////////////// //
28 // /////////////////////////////// //
29
29
30 // VariableController <-> DataSourceController
30 // VariableController <-> DataSourceController
31 connect(m_DataSourceController.get(),
31 connect(m_DataSourceController.get(),
32 SIGNAL(variableCreationRequested(const QString &, const QVariantHash &,
32 SIGNAL(variableCreationRequested(const QString &, const QVariantHash &,
33 std::shared_ptr<IDataProvider>)),
33 std::shared_ptr<IDataProvider>)),
34 m_VariableController.get(),
34 m_VariableController.get(),
35 SLOT(createVariable(const QString &, const QVariantHash &,
35 SLOT(createVariable(const QString &, const QVariantHash &,
36 std::shared_ptr<IDataProvider>)));
36 std::shared_ptr<IDataProvider>)));
37
37
38 connect(m_VariableController->variableModel(), &VariableModel::requestVariable,
38 connect(m_VariableController->variableModel(), &VariableModel::requestVariable,
39 m_DataSourceController.get(), &DataSourceController::requestVariable);
39 m_DataSourceController.get(), &DataSourceController::requestVariable);
40
40
41 // VariableController <-> VisualizationController
41 // VariableController <-> VisualizationController
42 connect(m_VariableController.get(),
42 connect(m_VariableController.get(),
43 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)),
43 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)),
44 m_VisualizationController.get(),
44 m_VisualizationController.get(),
45 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), Qt::DirectConnection);
45 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), Qt::DirectConnection);
46
46
47 connect(m_VariableController.get(),
47 connect(m_VariableController.get(),
48 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpRange &)),
48 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpRange &)),
49 m_VisualizationController.get(),
49 m_VisualizationController.get(),
50 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpRange &)));
50 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpRange &)));
51
51
52
52
53 m_DataSourceController->moveToThread(&m_DataSourceControllerThread);
53 m_DataSourceController->moveToThread(&m_DataSourceControllerThread);
54 m_DataSourceControllerThread.setObjectName("DataSourceControllerThread");
54 m_DataSourceControllerThread.setObjectName("DataSourceControllerThread");
55 m_NetworkController->moveToThread(&m_NetworkControllerThread);
55 m_NetworkController->moveToThread(&m_NetworkControllerThread);
56 m_NetworkControllerThread.setObjectName("NetworkControllerThread");
56 m_NetworkControllerThread.setObjectName("NetworkControllerThread");
57 m_VariableController->moveToThread(&m_VariableControllerThread);
57 m_VariableController->moveToThread(&m_VariableControllerThread);
58 m_VariableControllerThread.setObjectName("VariableControllerThread");
58 m_VariableControllerThread.setObjectName("VariableControllerThread");
59 m_VisualizationController->moveToThread(&m_VisualizationControllerThread);
59 m_VisualizationController->moveToThread(&m_VisualizationControllerThread);
60 m_VisualizationControllerThread.setObjectName("VsualizationControllerThread");
60 m_VisualizationControllerThread.setObjectName("VsualizationControllerThread");
61
61
62
62
63 // Additionnal init
63 // Additionnal init
64 m_VariableController->setTimeController(m_TimeController.get());
64 m_VariableController->setTimeController(m_TimeController.get());
65 }
65 }
66
66
67 virtual ~SqpApplicationPrivate()
67 virtual ~SqpApplicationPrivate()
68 {
68 {
69 m_DataSourceControllerThread.quit();
69 m_DataSourceControllerThread.quit();
70 m_DataSourceControllerThread.wait();
70 m_DataSourceControllerThread.wait();
71
71
72 m_NetworkControllerThread.quit();
72 m_NetworkControllerThread.quit();
73 m_NetworkControllerThread.wait();
73 m_NetworkControllerThread.wait();
74
74
75 m_VariableControllerThread.quit();
75 m_VariableControllerThread.quit();
76 m_VariableControllerThread.wait();
76 m_VariableControllerThread.wait();
77
77
78 m_VisualizationControllerThread.quit();
78 m_VisualizationControllerThread.quit();
79 m_VisualizationControllerThread.wait();
79 m_VisualizationControllerThread.wait();
80 }
80 }
81
81
82 std::unique_ptr<DataSourceController> m_DataSourceController;
82 std::unique_ptr<DataSourceController> m_DataSourceController;
83 std::unique_ptr<VariableController> m_VariableController;
83 std::unique_ptr<VariableController> m_VariableController;
84 std::unique_ptr<TimeController> m_TimeController;
84 std::unique_ptr<TimeController> m_TimeController;
85 std::unique_ptr<NetworkController> m_NetworkController;
85 std::unique_ptr<NetworkController> m_NetworkController;
86 std::unique_ptr<VisualizationController> m_VisualizationController;
86 std::unique_ptr<VisualizationController> m_VisualizationController;
87 QThread m_DataSourceControllerThread;
87 QThread m_DataSourceControllerThread;
88 QThread m_NetworkControllerThread;
88 QThread m_NetworkControllerThread;
89 QThread m_VariableControllerThread;
89 QThread m_VariableControllerThread;
90 QThread m_VisualizationControllerThread;
90 QThread m_VisualizationControllerThread;
91
91
92 std::unique_ptr<DragDropHelper> m_DragDropHelper;
92 std::unique_ptr<DragDropHelper> m_DragDropHelper;
93 };
93 };
94
94
95
95
96 SqpApplication::SqpApplication(int &argc, char **argv)
96 SqpApplication::SqpApplication(int &argc, char **argv)
97 : QApplication{argc, argv}, impl{spimpl::make_unique_impl<SqpApplicationPrivate>()}
97 : QApplication{argc, argv}, impl{spimpl::make_unique_impl<SqpApplicationPrivate>()}
98 {
98 {
99 qCDebug(LOG_SqpApplication()) << tr("SqpApplication construction") << QThread::currentThread();
99 qCDebug(LOG_SqpApplication()) << tr("SqpApplication construction") << QThread::currentThread();
100
100
101 connect(&impl->m_DataSourceControllerThread, &QThread::started,
101 connect(&impl->m_DataSourceControllerThread, &QThread::started,
102 impl->m_DataSourceController.get(), &DataSourceController::initialize);
102 impl->m_DataSourceController.get(), &DataSourceController::initialize);
103 connect(&impl->m_DataSourceControllerThread, &QThread::finished,
103 connect(&impl->m_DataSourceControllerThread, &QThread::finished,
104 impl->m_DataSourceController.get(), &DataSourceController::finalize);
104 impl->m_DataSourceController.get(), &DataSourceController::finalize);
105
105
106 connect(&impl->m_NetworkControllerThread, &QThread::started, impl->m_NetworkController.get(),
106 connect(&impl->m_NetworkControllerThread, &QThread::started, impl->m_NetworkController.get(),
107 &NetworkController::initialize);
107 &NetworkController::initialize);
108 connect(&impl->m_NetworkControllerThread, &QThread::finished, impl->m_NetworkController.get(),
108 connect(&impl->m_NetworkControllerThread, &QThread::finished, impl->m_NetworkController.get(),
109 &NetworkController::finalize);
109 &NetworkController::finalize);
110
110
111 connect(&impl->m_VariableControllerThread, &QThread::started, impl->m_VariableController.get(),
111 connect(&impl->m_VariableControllerThread, &QThread::started, impl->m_VariableController.get(),
112 &VariableController::initialize);
112 &VariableController::initialize);
113 connect(&impl->m_VariableControllerThread, &QThread::finished, impl->m_VariableController.get(),
113 connect(&impl->m_VariableControllerThread, &QThread::finished, impl->m_VariableController.get(),
114 &VariableController::finalize);
114 &VariableController::finalize);
115
115
116 connect(&impl->m_VisualizationControllerThread, &QThread::started,
116 connect(&impl->m_VisualizationControllerThread, &QThread::started,
117 impl->m_VisualizationController.get(), &VisualizationController::initialize);
117 impl->m_VisualizationController.get(), &VisualizationController::initialize);
118 connect(&impl->m_VisualizationControllerThread, &QThread::finished,
118 connect(&impl->m_VisualizationControllerThread, &QThread::finished,
119 impl->m_VisualizationController.get(), &VisualizationController::finalize);
119 impl->m_VisualizationController.get(), &VisualizationController::finalize);
120
120
121 impl->m_DataSourceControllerThread.start();
121 impl->m_DataSourceControllerThread.start();
122 impl->m_NetworkControllerThread.start();
122 impl->m_NetworkControllerThread.start();
123 impl->m_VariableControllerThread.start();
123 impl->m_VariableControllerThread.start();
124 impl->m_VisualizationControllerThread.start();
124 impl->m_VisualizationControllerThread.start();
125 }
125 }
126
126
127 SqpApplication::~SqpApplication()
127 SqpApplication::~SqpApplication()
128 {
128 {
129 }
129 }
130
130
131 void SqpApplication::initialize()
131 void SqpApplication::initialize()
132 {
132 {
133 }
133 }
134
134
135 DataSourceController &SqpApplication::dataSourceController() noexcept
135 DataSourceController &SqpApplication::dataSourceController() noexcept
136 {
136 {
137 return *impl->m_DataSourceController;
137 return *impl->m_DataSourceController;
138 }
138 }
139
139
140 NetworkController &SqpApplication::networkController() noexcept
140 NetworkController &SqpApplication::networkController() noexcept
141 {
141 {
142 return *impl->m_NetworkController;
142 return *impl->m_NetworkController;
143 }
143 }
144
144
145 TimeController &SqpApplication::timeController() noexcept
145 TimeController &SqpApplication::timeController() noexcept
146 {
146 {
147 return *impl->m_TimeController;
147 return *impl->m_TimeController;
148 }
148 }
149
149
150 VariableController &SqpApplication::variableController() noexcept
150 VariableController &SqpApplication::variableController() noexcept
151 {
151 {
152 return *impl->m_VariableController;
152 return *impl->m_VariableController;
153 }
153 }
154
154
155 VisualizationController &SqpApplication::visualizationController() noexcept
155 VisualizationController &SqpApplication::visualizationController() noexcept
156 {
156 {
157 return *impl->m_VisualizationController;
157 return *impl->m_VisualizationController;
158 }
158 }
159
159
160 DragDropHelper &SqpApplication::dragDropHelper() noexcept
160 DragDropHelper &SqpApplication::dragDropHelper() noexcept
161 {
161 {
162 return *impl->m_DragDropHelper;
162 return *impl->m_DragDropHelper;
163 }
163 }
@@ -1,156 +1,156
1 #include "TimeWidget/TimeWidget.h"
1 #include "TimeWidget/TimeWidget.h"
2 #include "ui_TimeWidget.h"
2 #include "ui_TimeWidget.h"
3
3
4 #include <Common/DateUtils.h>
4 #include <Common/DateUtils.h>
5 #include <Common/MimeTypesDef.h>
5 #include <Common/MimeTypesDef.h>
6
6
7 #include <DragDropHelper.h>
7 #include <DragAndDrop/DragDropHelper.h>
8 #include <SqpApplication.h>
8 #include <SqpApplication.h>
9 #include <Time/TimeController.h>
9 #include <Time/TimeController.h>
10
10
11 #include <QDrag>
11 #include <QDrag>
12 #include <QDragEnterEvent>
12 #include <QDragEnterEvent>
13 #include <QDropEvent>
13 #include <QDropEvent>
14 #include <QMimeData>
14 #include <QMimeData>
15
15
16
16
17 struct TimeWidget::TimeWidgetPrivate {
17 struct TimeWidget::TimeWidgetPrivate {
18
18
19 explicit TimeWidgetPrivate() {}
19 explicit TimeWidgetPrivate() {}
20
20
21 QPoint m_DragStartPosition;
21 QPoint m_DragStartPosition;
22 };
22 };
23
23
24 TimeWidget::TimeWidget(QWidget *parent)
24 TimeWidget::TimeWidget(QWidget *parent)
25 : QWidget{parent},
25 : QWidget{parent},
26 ui{new Ui::TimeWidget},
26 ui{new Ui::TimeWidget},
27 impl{spimpl::make_unique_impl<TimeWidgetPrivate>()}
27 impl{spimpl::make_unique_impl<TimeWidgetPrivate>()}
28 {
28 {
29 ui->setupUi(this);
29 ui->setupUi(this);
30
30
31 ui->applyToolButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_DialogApplyButton));
31 ui->applyToolButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_DialogApplyButton));
32
32
33 // Connection
33 // Connection
34 connect(ui->startDateTimeEdit, &QDateTimeEdit::dateTimeChanged, this,
34 connect(ui->startDateTimeEdit, &QDateTimeEdit::dateTimeChanged, this,
35 &TimeWidget::onTimeUpdateRequested);
35 &TimeWidget::onTimeUpdateRequested);
36
36
37 connect(ui->endDateTimeEdit, &QDateTimeEdit::dateTimeChanged, this,
37 connect(ui->endDateTimeEdit, &QDateTimeEdit::dateTimeChanged, this,
38 &TimeWidget::onTimeUpdateRequested);
38 &TimeWidget::onTimeUpdateRequested);
39
39
40
40
41 connect(ui->applyToolButton, &QToolButton::clicked, &sqpApp->timeController(),
41 connect(ui->applyToolButton, &QToolButton::clicked, &sqpApp->timeController(),
42 &TimeController::onTimeNotify);
42 &TimeController::onTimeNotify);
43
43
44 // Initialisation
44 // Initialisation
45 auto endDateTime = QDateTime::currentDateTimeUtc();
45 auto endDateTime = QDateTime::currentDateTimeUtc();
46 auto startDateTime = endDateTime.addSecs(-3600); // one hour before
46 auto startDateTime = endDateTime.addSecs(-3600); // one hour before
47
47
48 ui->startDateTimeEdit->setDateTime(startDateTime);
48 ui->startDateTimeEdit->setDateTime(startDateTime);
49 ui->endDateTimeEdit->setDateTime(endDateTime);
49 ui->endDateTimeEdit->setDateTime(endDateTime);
50
50
51 auto dateTime = SqpRange{DateUtils::secondsSinceEpoch(startDateTime),
51 auto dateTime = SqpRange{DateUtils::secondsSinceEpoch(startDateTime),
52 DateUtils::secondsSinceEpoch(endDateTime)};
52 DateUtils::secondsSinceEpoch(endDateTime)};
53
53
54 sqpApp->timeController().onTimeToUpdate(dateTime);
54 sqpApp->timeController().onTimeToUpdate(dateTime);
55 }
55 }
56
56
57
57
58 TimeWidget::~TimeWidget()
58 TimeWidget::~TimeWidget()
59 {
59 {
60 delete ui;
60 delete ui;
61 }
61 }
62
62
63 void TimeWidget::setTimeRange(SqpRange time)
63 void TimeWidget::setTimeRange(SqpRange time)
64 {
64 {
65 auto startDateTime = DateUtils::dateTime(time.m_TStart);
65 auto startDateTime = DateUtils::dateTime(time.m_TStart);
66 auto endDateTime = DateUtils::dateTime(time.m_TEnd);
66 auto endDateTime = DateUtils::dateTime(time.m_TEnd);
67
67
68 ui->startDateTimeEdit->setDateTime(startDateTime);
68 ui->startDateTimeEdit->setDateTime(startDateTime);
69 ui->endDateTimeEdit->setDateTime(endDateTime);
69 ui->endDateTimeEdit->setDateTime(endDateTime);
70 }
70 }
71
71
72 SqpRange TimeWidget::timeRange() const
72 SqpRange TimeWidget::timeRange() const
73 {
73 {
74 return SqpRange{DateUtils::secondsSinceEpoch(ui->startDateTimeEdit->dateTime()),
74 return SqpRange{DateUtils::secondsSinceEpoch(ui->startDateTimeEdit->dateTime()),
75 DateUtils::secondsSinceEpoch(ui->endDateTimeEdit->dateTime())};
75 DateUtils::secondsSinceEpoch(ui->endDateTimeEdit->dateTime())};
76 }
76 }
77
77
78 void TimeWidget::onTimeUpdateRequested()
78 void TimeWidget::onTimeUpdateRequested()
79 {
79 {
80 auto dateTime = timeRange();
80 auto dateTime = timeRange();
81 emit timeUpdated(std::move(dateTime));
81 emit timeUpdated(std::move(dateTime));
82 }
82 }
83
83
84 void TimeWidget::dragEnterEvent(QDragEnterEvent *event)
84 void TimeWidget::dragEnterEvent(QDragEnterEvent *event)
85 {
85 {
86 if (event->mimeData()->hasFormat(MIME_TYPE_TIME_RANGE)) {
86 if (event->mimeData()->hasFormat(MIME_TYPE_TIME_RANGE)) {
87 event->acceptProposedAction();
87 event->acceptProposedAction();
88 setStyleSheet("QDateTimeEdit{background-color: #BBD5EE; border:2px solid #2A7FD4}");
88 setStyleSheet("QDateTimeEdit{background-color: #BBD5EE; border:2px solid #2A7FD4}");
89 }
89 }
90 else {
90 else {
91 event->ignore();
91 event->ignore();
92 }
92 }
93 }
93 }
94
94
95 void TimeWidget::dragLeaveEvent(QDragLeaveEvent *event)
95 void TimeWidget::dragLeaveEvent(QDragLeaveEvent *event)
96 {
96 {
97 setStyleSheet(QString());
97 setStyleSheet(QString());
98 }
98 }
99
99
100 void TimeWidget::dropEvent(QDropEvent *event)
100 void TimeWidget::dropEvent(QDropEvent *event)
101 {
101 {
102 if (event->mimeData()->hasFormat(MIME_TYPE_TIME_RANGE)) {
102 if (event->mimeData()->hasFormat(MIME_TYPE_TIME_RANGE)) {
103 auto mimeData = event->mimeData()->data(MIME_TYPE_TIME_RANGE);
103 auto mimeData = event->mimeData()->data(MIME_TYPE_TIME_RANGE);
104 auto timeRange = TimeController::timeRangeForMimeData(mimeData);
104 auto timeRange = TimeController::timeRangeForMimeData(mimeData);
105
105
106 setTimeRange(timeRange);
106 setTimeRange(timeRange);
107 }
107 }
108 else {
108 else {
109 event->ignore();
109 event->ignore();
110 }
110 }
111
111
112 setStyleSheet(QString());
112 setStyleSheet(QString());
113 }
113 }
114
114
115
115
116 void TimeWidget::mousePressEvent(QMouseEvent *event)
116 void TimeWidget::mousePressEvent(QMouseEvent *event)
117 {
117 {
118 if (event->button() == Qt::LeftButton) {
118 if (event->button() == Qt::LeftButton) {
119 impl->m_DragStartPosition = event->pos();
119 impl->m_DragStartPosition = event->pos();
120 }
120 }
121
121
122 QWidget::mousePressEvent(event);
122 QWidget::mousePressEvent(event);
123 }
123 }
124
124
125 void TimeWidget::mouseMoveEvent(QMouseEvent *event)
125 void TimeWidget::mouseMoveEvent(QMouseEvent *event)
126 {
126 {
127 if (!(event->buttons() & Qt::LeftButton)) {
127 if (!(event->buttons() & Qt::LeftButton)) {
128 return;
128 return;
129 }
129 }
130
130
131 if ((event->pos() - impl->m_DragStartPosition).manhattanLength()
131 if ((event->pos() - impl->m_DragStartPosition).manhattanLength()
132 < QApplication::startDragDistance()) {
132 < QApplication::startDragDistance()) {
133 return;
133 return;
134 }
134 }
135
135
136 // Note: The management of the drag object is done by Qt
136 // Note: The management of the drag object is done by Qt
137 auto drag = new QDrag{this};
137 auto drag = new QDrag{this};
138
138
139 auto mimeData = new QMimeData;
139 auto mimeData = new QMimeData;
140 auto timeData = TimeController::mimeDataForTimeRange(timeRange());
140 auto timeData = TimeController::mimeDataForTimeRange(timeRange());
141 mimeData->setData(MIME_TYPE_TIME_RANGE, timeData);
141 mimeData->setData(MIME_TYPE_TIME_RANGE, timeData);
142
142
143 drag->setMimeData(mimeData);
143 drag->setMimeData(mimeData);
144
144
145 auto pixmap = QPixmap(size());
145 auto pixmap = QPixmap(size());
146 render(&pixmap);
146 render(&pixmap);
147 drag->setPixmap(pixmap);
147 drag->setPixmap(pixmap);
148 drag->setHotSpot(impl->m_DragStartPosition);
148 drag->setHotSpot(impl->m_DragStartPosition);
149
149
150 sqpApp->dragDropHelper().resetDragAndDrop();
150 sqpApp->dragDropHelper().resetDragAndDrop();
151
151
152 // Note: The exec() is blocking on windows but not on linux and macOS
152 // Note: The exec() is blocking on windows but not on linux and macOS
153 drag->exec(Qt::MoveAction | Qt::CopyAction);
153 drag->exec(Qt::MoveAction | Qt::CopyAction);
154
154
155 QWidget::mouseMoveEvent(event);
155 QWidget::mouseMoveEvent(event);
156 }
156 }
@@ -1,13 +1,13
1 #include "Variable/VariableInspectorTableView.h"
1 #include "Variable/VariableInspectorTableView.h"
2
2
3 #include "DragDropHelper.h"
3 #include "DragAndDrop/DragDropHelper.h"
4 #include "SqpApplication.h"
4 #include "SqpApplication.h"
5
5
6 VariableInspectorTableView::VariableInspectorTableView(QWidget *parent) : QTableView(parent) {}
6 VariableInspectorTableView::VariableInspectorTableView(QWidget *parent) : QTableView(parent) {}
7
7
8 void VariableInspectorTableView::startDrag(Qt::DropActions supportedActions)
8 void VariableInspectorTableView::startDrag(Qt::DropActions supportedActions)
9 {
9 {
10 // Resets the drag&drop operations before it's starting
10 // Resets the drag&drop operations before it's starting
11 sqpApp->dragDropHelper().resetDragAndDrop();
11 sqpApp->dragDropHelper().resetDragAndDrop();
12 QTableView::startDrag(supportedActions);
12 QTableView::startDrag(supportedActions);
13 }
13 }
@@ -1,240 +1,240
1 #include <Variable/RenameVariableDialog.h>
1 #include <Variable/RenameVariableDialog.h>
2 #include <Variable/Variable.h>
2 #include <Variable/Variable.h>
3 #include <Variable/VariableController.h>
3 #include <Variable/VariableController.h>
4 #include <Variable/VariableInspectorWidget.h>
4 #include <Variable/VariableInspectorWidget.h>
5 #include <Variable/VariableMenuHeaderWidget.h>
5 #include <Variable/VariableMenuHeaderWidget.h>
6 #include <Variable/VariableModel.h>
6 #include <Variable/VariableModel.h>
7
7
8 #include <ui_VariableInspectorWidget.h>
8 #include <ui_VariableInspectorWidget.h>
9
9
10 #include <QMouseEvent>
10 #include <QMouseEvent>
11 #include <QSortFilterProxyModel>
11 #include <QSortFilterProxyModel>
12 #include <QStyledItemDelegate>
12 #include <QStyledItemDelegate>
13 #include <QWidgetAction>
13 #include <QWidgetAction>
14
14
15 #include <DragDropHelper.h>
15 #include <DragAndDrop/DragDropHelper.h>
16 #include <SqpApplication.h>
16 #include <SqpApplication.h>
17
17
18 Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget")
18 Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget")
19
19
20
20
21 class QProgressBarItemDelegate : public QStyledItemDelegate {
21 class QProgressBarItemDelegate : public QStyledItemDelegate {
22
22
23 public:
23 public:
24 QProgressBarItemDelegate(QObject *parent) : QStyledItemDelegate{parent} {}
24 QProgressBarItemDelegate(QObject *parent) : QStyledItemDelegate{parent} {}
25
25
26 void paint(QPainter *painter, const QStyleOptionViewItem &option,
26 void paint(QPainter *painter, const QStyleOptionViewItem &option,
27 const QModelIndex &index) const
27 const QModelIndex &index) const
28 {
28 {
29 auto data = index.data(Qt::DisplayRole);
29 auto data = index.data(Qt::DisplayRole);
30 auto progressData = index.data(VariableRoles::ProgressRole);
30 auto progressData = index.data(VariableRoles::ProgressRole);
31 if (data.isValid() && progressData.isValid()) {
31 if (data.isValid() && progressData.isValid()) {
32 auto name = data.value<QString>();
32 auto name = data.value<QString>();
33 auto progress = progressData.value<double>();
33 auto progress = progressData.value<double>();
34 if (progress > 0) {
34 if (progress > 0) {
35 auto cancelButtonWidth = 20;
35 auto cancelButtonWidth = 20;
36 auto progressBarOption = QStyleOptionProgressBar{};
36 auto progressBarOption = QStyleOptionProgressBar{};
37 auto progressRect = option.rect;
37 auto progressRect = option.rect;
38 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
38 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
39 progressBarOption.rect = progressRect;
39 progressBarOption.rect = progressRect;
40 progressBarOption.minimum = 0;
40 progressBarOption.minimum = 0;
41 progressBarOption.maximum = 100;
41 progressBarOption.maximum = 100;
42 progressBarOption.progress = progress;
42 progressBarOption.progress = progress;
43 progressBarOption.text
43 progressBarOption.text
44 = QString("%1 %2").arg(name).arg(QString::number(progress, 'f', 2) + "%");
44 = QString("%1 %2").arg(name).arg(QString::number(progress, 'f', 2) + "%");
45 progressBarOption.textVisible = true;
45 progressBarOption.textVisible = true;
46 progressBarOption.textAlignment = Qt::AlignCenter;
46 progressBarOption.textAlignment = Qt::AlignCenter;
47
47
48
48
49 QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption,
49 QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption,
50 painter);
50 painter);
51
51
52 // Cancel button
52 // Cancel button
53 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
53 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
54 option.rect.height());
54 option.rect.height());
55 auto buttonOption = QStyleOptionButton{};
55 auto buttonOption = QStyleOptionButton{};
56 buttonOption.rect = buttonRect;
56 buttonOption.rect = buttonRect;
57 buttonOption.text = "X";
57 buttonOption.text = "X";
58
58
59 QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter);
59 QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter);
60 }
60 }
61 else {
61 else {
62 QStyledItemDelegate::paint(painter, option, index);
62 QStyledItemDelegate::paint(painter, option, index);
63 }
63 }
64 }
64 }
65 else {
65 else {
66 QStyledItemDelegate::paint(painter, option, index);
66 QStyledItemDelegate::paint(painter, option, index);
67 }
67 }
68 }
68 }
69
69
70 bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
70 bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
71 const QModelIndex &index)
71 const QModelIndex &index)
72 {
72 {
73 if (event->type() == QEvent::MouseButtonRelease) {
73 if (event->type() == QEvent::MouseButtonRelease) {
74 auto data = index.data(Qt::DisplayRole);
74 auto data = index.data(Qt::DisplayRole);
75 auto progressData = index.data(VariableRoles::ProgressRole);
75 auto progressData = index.data(VariableRoles::ProgressRole);
76 if (data.isValid() && progressData.isValid()) {
76 if (data.isValid() && progressData.isValid()) {
77 auto cancelButtonWidth = 20;
77 auto cancelButtonWidth = 20;
78 auto progressRect = option.rect;
78 auto progressRect = option.rect;
79 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
79 progressRect.setWidth(progressRect.width() - cancelButtonWidth);
80 // Cancel button
80 // Cancel button
81 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
81 auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth,
82 option.rect.height());
82 option.rect.height());
83
83
84 auto e = (QMouseEvent *)event;
84 auto e = (QMouseEvent *)event;
85 auto clickX = e->x();
85 auto clickX = e->x();
86 auto clickY = e->y();
86 auto clickY = e->y();
87
87
88 auto x = buttonRect.left(); // the X coordinate
88 auto x = buttonRect.left(); // the X coordinate
89 auto y = buttonRect.top(); // the Y coordinate
89 auto y = buttonRect.top(); // the Y coordinate
90 auto w = buttonRect.width(); // button width
90 auto w = buttonRect.width(); // button width
91 auto h = buttonRect.height(); // button height
91 auto h = buttonRect.height(); // button height
92
92
93 if (clickX > x && clickX < x + w) {
93 if (clickX > x && clickX < x + w) {
94 if (clickY > y && clickY < y + h) {
94 if (clickY > y && clickY < y + h) {
95 auto variableModel = sqpApp->variableController().variableModel();
95 auto variableModel = sqpApp->variableController().variableModel();
96 variableModel->abortProgress(index);
96 variableModel->abortProgress(index);
97 }
97 }
98 return true;
98 return true;
99 }
99 }
100 else {
100 else {
101 return QStyledItemDelegate::editorEvent(event, model, option, index);
101 return QStyledItemDelegate::editorEvent(event, model, option, index);
102 }
102 }
103 }
103 }
104 else {
104 else {
105 return QStyledItemDelegate::editorEvent(event, model, option, index);
105 return QStyledItemDelegate::editorEvent(event, model, option, index);
106 }
106 }
107 }
107 }
108 else {
108 else {
109 return QStyledItemDelegate::editorEvent(event, model, option, index);
109 return QStyledItemDelegate::editorEvent(event, model, option, index);
110 }
110 }
111
111
112
112
113 return QStyledItemDelegate::editorEvent(event, model, option, index);
113 return QStyledItemDelegate::editorEvent(event, model, option, index);
114 }
114 }
115 };
115 };
116
116
117 VariableInspectorWidget::VariableInspectorWidget(QWidget *parent)
117 VariableInspectorWidget::VariableInspectorWidget(QWidget *parent)
118 : QWidget{parent},
118 : QWidget{parent},
119 ui{new Ui::VariableInspectorWidget},
119 ui{new Ui::VariableInspectorWidget},
120 m_ProgressBarItemDelegate{new QProgressBarItemDelegate{this}}
120 m_ProgressBarItemDelegate{new QProgressBarItemDelegate{this}}
121 {
121 {
122 ui->setupUi(this);
122 ui->setupUi(this);
123
123
124 // Sets model for table
124 // Sets model for table
125 // auto sortFilterModel = new QSortFilterProxyModel{this};
125 // auto sortFilterModel = new QSortFilterProxyModel{this};
126 // sortFilterModel->setSourceModel(sqpApp->variableController().variableModel());
126 // sortFilterModel->setSourceModel(sqpApp->variableController().variableModel());
127
127
128 auto variableModel = sqpApp->variableController().variableModel();
128 auto variableModel = sqpApp->variableController().variableModel();
129 ui->tableView->setModel(variableModel);
129 ui->tableView->setModel(variableModel);
130
130
131 // Adds extra signal/slot between view and model, so the view can be updated instantly when
131 // Adds extra signal/slot between view and model, so the view can be updated instantly when
132 // there is a change of data in the model
132 // there is a change of data in the model
133 connect(variableModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this,
133 connect(variableModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this,
134 SLOT(refresh()));
134 SLOT(refresh()));
135
135
136 ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel());
136 ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel());
137 ui->tableView->setItemDelegateForColumn(0, m_ProgressBarItemDelegate);
137 ui->tableView->setItemDelegateForColumn(0, m_ProgressBarItemDelegate);
138
138
139 // Fixes column sizes
139 // Fixes column sizes
140 auto model = ui->tableView->model();
140 auto model = ui->tableView->model();
141 const auto count = model->columnCount();
141 const auto count = model->columnCount();
142 for (auto i = 0; i < count; ++i) {
142 for (auto i = 0; i < count; ++i) {
143 ui->tableView->setColumnWidth(
143 ui->tableView->setColumnWidth(
144 i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width());
144 i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width());
145 }
145 }
146
146
147 // Sets selection options
147 // Sets selection options
148 ui->tableView->setSelectionBehavior(QTableView::SelectRows);
148 ui->tableView->setSelectionBehavior(QTableView::SelectRows);
149 ui->tableView->setSelectionMode(QTableView::ExtendedSelection);
149 ui->tableView->setSelectionMode(QTableView::ExtendedSelection);
150
150
151 // Connection to show a menu when right clicking on the tree
151 // Connection to show a menu when right clicking on the tree
152 ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
152 ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
153 connect(ui->tableView, &QTableView::customContextMenuRequested, this,
153 connect(ui->tableView, &QTableView::customContextMenuRequested, this,
154 &VariableInspectorWidget::onTableMenuRequested);
154 &VariableInspectorWidget::onTableMenuRequested);
155 }
155 }
156
156
157 VariableInspectorWidget::~VariableInspectorWidget()
157 VariableInspectorWidget::~VariableInspectorWidget()
158 {
158 {
159 delete ui;
159 delete ui;
160 }
160 }
161
161
162 void VariableInspectorWidget::onTableMenuRequested(const QPoint &pos) noexcept
162 void VariableInspectorWidget::onTableMenuRequested(const QPoint &pos) noexcept
163 {
163 {
164 auto selectedRows = ui->tableView->selectionModel()->selectedRows();
164 auto selectedRows = ui->tableView->selectionModel()->selectedRows();
165
165
166 // Gets the model to retrieve the underlying selected variables
166 // Gets the model to retrieve the underlying selected variables
167 auto model = sqpApp->variableController().variableModel();
167 auto model = sqpApp->variableController().variableModel();
168 auto selectedVariables = QVector<std::shared_ptr<Variable> >{};
168 auto selectedVariables = QVector<std::shared_ptr<Variable> >{};
169 for (const auto &selectedRow : qAsConst(selectedRows)) {
169 for (const auto &selectedRow : qAsConst(selectedRows)) {
170 if (auto selectedVariable = model->variable(selectedRow.row())) {
170 if (auto selectedVariable = model->variable(selectedRow.row())) {
171 selectedVariables.push_back(selectedVariable);
171 selectedVariables.push_back(selectedVariable);
172 }
172 }
173 }
173 }
174
174
175 QMenu tableMenu{};
175 QMenu tableMenu{};
176
176
177 // Emits a signal so that potential receivers can populate the menu before displaying it
177 // Emits a signal so that potential receivers can populate the menu before displaying it
178 emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables);
178 emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables);
179
179
180 // Adds menu-specific actions
180 // Adds menu-specific actions
181 if (!selectedVariables.isEmpty()) {
181 if (!selectedVariables.isEmpty()) {
182 tableMenu.addSeparator();
182 tableMenu.addSeparator();
183
183
184 // 'Rename' and 'Duplicate' actions (only if one variable selected)
184 // 'Rename' and 'Duplicate' actions (only if one variable selected)
185 if (selectedVariables.size() == 1) {
185 if (selectedVariables.size() == 1) {
186 auto selectedVariable = selectedVariables.front();
186 auto selectedVariable = selectedVariables.front();
187
187
188 auto duplicateFun = [varW = std::weak_ptr<Variable>(selectedVariable)]()
188 auto duplicateFun = [varW = std::weak_ptr<Variable>(selectedVariable)]()
189 {
189 {
190 if (auto var = varW.lock()) {
190 if (auto var = varW.lock()) {
191 sqpApp->variableController().cloneVariable(var);
191 sqpApp->variableController().cloneVariable(var);
192 }
192 }
193 };
193 };
194
194
195 tableMenu.addAction(tr("Duplicate"), duplicateFun);
195 tableMenu.addAction(tr("Duplicate"), duplicateFun);
196
196
197 auto renameFun = [ varW = std::weak_ptr<Variable>(selectedVariable), &model, this ]()
197 auto renameFun = [ varW = std::weak_ptr<Variable>(selectedVariable), &model, this ]()
198 {
198 {
199 if (auto var = varW.lock()) {
199 if (auto var = varW.lock()) {
200 // Generates forbidden names (names associated to existing variables)
200 // Generates forbidden names (names associated to existing variables)
201 auto allVariables = model->variables();
201 auto allVariables = model->variables();
202 auto forbiddenNames = QVector<QString>(allVariables.size());
202 auto forbiddenNames = QVector<QString>(allVariables.size());
203 std::transform(allVariables.cbegin(), allVariables.cend(),
203 std::transform(allVariables.cbegin(), allVariables.cend(),
204 forbiddenNames.begin(),
204 forbiddenNames.begin(),
205 [](const auto &variable) { return variable->name(); });
205 [](const auto &variable) { return variable->name(); });
206
206
207 RenameVariableDialog dialog{var->name(), forbiddenNames, this};
207 RenameVariableDialog dialog{var->name(), forbiddenNames, this};
208 if (dialog.exec() == QDialog::Accepted) {
208 if (dialog.exec() == QDialog::Accepted) {
209 var->setName(dialog.name());
209 var->setName(dialog.name());
210 }
210 }
211 }
211 }
212 };
212 };
213
213
214 tableMenu.addAction(tr("Rename..."), renameFun);
214 tableMenu.addAction(tr("Rename..."), renameFun);
215 }
215 }
216
216
217 // 'Delete' action
217 // 'Delete' action
218 auto deleteFun = [&selectedVariables]() {
218 auto deleteFun = [&selectedVariables]() {
219 sqpApp->variableController().deleteVariables(selectedVariables);
219 sqpApp->variableController().deleteVariables(selectedVariables);
220 };
220 };
221
221
222 tableMenu.addAction(QIcon{":/icones/delete.png"}, tr("Delete"), deleteFun);
222 tableMenu.addAction(QIcon{":/icones/delete.png"}, tr("Delete"), deleteFun);
223 }
223 }
224
224
225 if (!tableMenu.isEmpty()) {
225 if (!tableMenu.isEmpty()) {
226 // Generates menu header (inserted before first action)
226 // Generates menu header (inserted before first action)
227 auto firstAction = tableMenu.actions().first();
227 auto firstAction = tableMenu.actions().first();
228 auto headerAction = new QWidgetAction{&tableMenu};
228 auto headerAction = new QWidgetAction{&tableMenu};
229 headerAction->setDefaultWidget(new VariableMenuHeaderWidget{selectedVariables, &tableMenu});
229 headerAction->setDefaultWidget(new VariableMenuHeaderWidget{selectedVariables, &tableMenu});
230 tableMenu.insertAction(firstAction, headerAction);
230 tableMenu.insertAction(firstAction, headerAction);
231
231
232 // Displays menu
232 // Displays menu
233 tableMenu.exec(QCursor::pos());
233 tableMenu.exec(QCursor::pos());
234 }
234 }
235 }
235 }
236
236
237 void VariableInspectorWidget::refresh() noexcept
237 void VariableInspectorWidget::refresh() noexcept
238 {
238 {
239 ui->tableView->viewport()->update();
239 ui->tableView->viewport()->update();
240 }
240 }
@@ -1,453 +1,453
1 #include "Visualization/VisualizationDragDropContainer.h"
1 #include "Visualization/VisualizationDragDropContainer.h"
2 #include "DragDropHelper.h"
2 #include "DragAndDrop/DragDropHelper.h"
3 #include "SqpApplication.h"
3 #include "SqpApplication.h"
4 #include "Visualization/VisualizationDragWidget.h"
4 #include "Visualization/VisualizationDragWidget.h"
5
5
6 #include "Common/VisualizationDef.h"
6 #include "Common/VisualizationDef.h"
7
7
8 #include <QDrag>
8 #include <QDrag>
9 #include <QDragEnterEvent>
9 #include <QDragEnterEvent>
10 #include <QVBoxLayout>
10 #include <QVBoxLayout>
11
11
12 #include <cmath>
12 #include <cmath>
13 #include <memory>
13 #include <memory>
14
14
15 Q_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer, "VisualizationDragDropContainer")
15 Q_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer, "VisualizationDragDropContainer")
16
16
17 struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate {
17 struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate {
18
18
19 QVBoxLayout *m_Layout;
19 QVBoxLayout *m_Layout;
20 QHash<QString, VisualizationDragDropContainer::DropBehavior> m_AcceptedMimeTypes;
20 QHash<QString, VisualizationDragDropContainer::DropBehavior> m_AcceptedMimeTypes;
21 QString m_PlaceHolderText;
21 QString m_PlaceHolderText;
22 DragDropHelper::PlaceHolderType m_PlaceHolderType = DragDropHelper::PlaceHolderType::Graph;
22 DragDropHelper::PlaceHolderType m_PlaceHolderType = DragDropHelper::PlaceHolderType::Graph;
23
23
24 VisualizationDragDropContainer::AcceptMimeDataFunction m_AcceptMimeDataFun
24 VisualizationDragDropContainer::AcceptMimeDataFunction m_AcceptMimeDataFun
25 = [](auto mimeData) { return true; };
25 = [](auto mimeData) { return true; };
26
26
27 int m_MinContainerHeight = 0;
27 int m_MinContainerHeight = 0;
28
28
29 explicit VisualizationDragDropContainerPrivate(QWidget *widget)
29 explicit VisualizationDragDropContainerPrivate(QWidget *widget)
30 {
30 {
31 m_Layout = new QVBoxLayout(widget);
31 m_Layout = new QVBoxLayout(widget);
32 m_Layout->setContentsMargins(0, 0, 0, 0);
32 m_Layout->setContentsMargins(0, 0, 0, 0);
33 }
33 }
34
34
35 bool acceptMimeData(const QMimeData *data) const
35 bool acceptMimeData(const QMimeData *data) const
36 {
36 {
37 for (const auto &type : m_AcceptedMimeTypes.keys()) {
37 for (const auto &type : m_AcceptedMimeTypes.keys()) {
38 if (data->hasFormat(type) && m_AcceptMimeDataFun(data)) {
38 if (data->hasFormat(type) && m_AcceptMimeDataFun(data)) {
39 return true;
39 return true;
40 }
40 }
41 }
41 }
42
42
43 return false;
43 return false;
44 }
44 }
45
45
46 bool allowMergeForMimeData(const QMimeData *data) const
46 bool allowMergeForMimeData(const QMimeData *data) const
47 {
47 {
48 bool result = false;
48 bool result = false;
49 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
49 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
50 ++it) {
50 ++it) {
51
51
52 if (data->hasFormat(it.key())
52 if (data->hasFormat(it.key())
53 && (it.value() == VisualizationDragDropContainer::DropBehavior::Merged
53 && (it.value() == VisualizationDragDropContainer::DropBehavior::Merged
54 || it.value()
54 || it.value()
55 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
55 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
56 result = true;
56 result = true;
57 }
57 }
58 else if (data->hasFormat(it.key())
58 else if (data->hasFormat(it.key())
59 && it.value() == VisualizationDragDropContainer::DropBehavior::Inserted) {
59 && it.value() == VisualizationDragDropContainer::DropBehavior::Inserted) {
60 // Merge is forbidden if the mime data contain an acceptable type which cannot be
60 // Merge is forbidden if the mime data contain an acceptable type which cannot be
61 // merged
61 // merged
62 result = false;
62 result = false;
63 break;
63 break;
64 }
64 }
65 }
65 }
66
66
67 return result;
67 return result;
68 }
68 }
69
69
70 bool allowInsertForMimeData(const QMimeData *data) const
70 bool allowInsertForMimeData(const QMimeData *data) const
71 {
71 {
72 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
72 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
73 ++it) {
73 ++it) {
74 if (data->hasFormat(it.key())
74 if (data->hasFormat(it.key())
75 && (it.value() == VisualizationDragDropContainer::DropBehavior::Inserted
75 && (it.value() == VisualizationDragDropContainer::DropBehavior::Inserted
76 || it.value()
76 || it.value()
77 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
77 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
78 return true;
78 return true;
79 }
79 }
80 }
80 }
81
81
82 return false;
82 return false;
83 }
83 }
84
84
85 bool hasPlaceHolder() const
85 bool hasPlaceHolder() const
86 {
86 {
87 return sqpApp->dragDropHelper().placeHolder().parentWidget() == m_Layout->parentWidget();
87 return sqpApp->dragDropHelper().placeHolder().parentWidget() == m_Layout->parentWidget();
88 }
88 }
89
89
90 VisualizationDragWidget *getChildDragWidgetAt(const QWidget *parent, const QPoint &pos) const
90 VisualizationDragWidget *getChildDragWidgetAt(const QWidget *parent, const QPoint &pos) const
91 {
91 {
92 VisualizationDragWidget *dragWidget = nullptr;
92 VisualizationDragWidget *dragWidget = nullptr;
93
93
94 for (auto child : parent->children()) {
94 for (auto child : parent->children()) {
95 auto widget = qobject_cast<VisualizationDragWidget *>(child);
95 auto widget = qobject_cast<VisualizationDragWidget *>(child);
96 if (widget && widget->isVisible()) {
96 if (widget && widget->isVisible()) {
97 if (widget->frameGeometry().contains(pos)) {
97 if (widget->frameGeometry().contains(pos)) {
98 dragWidget = widget;
98 dragWidget = widget;
99 break;
99 break;
100 }
100 }
101 }
101 }
102 }
102 }
103
103
104 return dragWidget;
104 return dragWidget;
105 }
105 }
106
106
107 bool cursorIsInContainer(QWidget *container) const
107 bool cursorIsInContainer(QWidget *container) const
108 {
108 {
109 return container->isAncestorOf(sqpApp->widgetAt(QCursor::pos()));
109 return container->isAncestorOf(sqpApp->widgetAt(QCursor::pos()));
110 }
110 }
111
111
112 int countDragWidget(const QWidget *parent, bool onlyVisible = false) const
112 int countDragWidget(const QWidget *parent, bool onlyVisible = false) const
113 {
113 {
114 auto nbGraph = 0;
114 auto nbGraph = 0;
115 for (auto child : parent->children()) {
115 for (auto child : parent->children()) {
116 if (qobject_cast<VisualizationDragWidget *>(child)) {
116 if (qobject_cast<VisualizationDragWidget *>(child)) {
117 if (!onlyVisible || qobject_cast<VisualizationDragWidget *>(child)->isVisible()) {
117 if (!onlyVisible || qobject_cast<VisualizationDragWidget *>(child)->isVisible()) {
118 nbGraph += 1;
118 nbGraph += 1;
119 }
119 }
120 }
120 }
121 }
121 }
122
122
123 return nbGraph;
123 return nbGraph;
124 }
124 }
125
125
126 void findPlaceHolderPosition(const QPoint &pos, bool canInsert, bool canMerge,
126 void findPlaceHolderPosition(const QPoint &pos, bool canInsert, bool canMerge,
127 const VisualizationDragDropContainer *container);
127 const VisualizationDragDropContainer *container);
128 };
128 };
129
129
130 VisualizationDragDropContainer::VisualizationDragDropContainer(QWidget *parent)
130 VisualizationDragDropContainer::VisualizationDragDropContainer(QWidget *parent)
131 : QFrame{parent},
131 : QFrame{parent},
132 impl{spimpl::make_unique_impl<VisualizationDragDropContainerPrivate>(this)}
132 impl{spimpl::make_unique_impl<VisualizationDragDropContainerPrivate>(this)}
133 {
133 {
134 setAcceptDrops(true);
134 setAcceptDrops(true);
135 }
135 }
136
136
137 void VisualizationDragDropContainer::addDragWidget(VisualizationDragWidget *dragWidget)
137 void VisualizationDragDropContainer::addDragWidget(VisualizationDragWidget *dragWidget)
138 {
138 {
139 impl->m_Layout->addWidget(dragWidget);
139 impl->m_Layout->addWidget(dragWidget);
140 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
140 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
141 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
141 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
142 &VisualizationDragDropContainer::startDrag);
142 &VisualizationDragDropContainer::startDrag);
143 }
143 }
144
144
145 void VisualizationDragDropContainer::insertDragWidget(int index,
145 void VisualizationDragDropContainer::insertDragWidget(int index,
146 VisualizationDragWidget *dragWidget)
146 VisualizationDragWidget *dragWidget)
147 {
147 {
148 impl->m_Layout->insertWidget(index, dragWidget);
148 impl->m_Layout->insertWidget(index, dragWidget);
149 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
149 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
150 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
150 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
151 &VisualizationDragDropContainer::startDrag);
151 &VisualizationDragDropContainer::startDrag);
152 }
152 }
153
153
154 void VisualizationDragDropContainer::addAcceptedMimeType(
154 void VisualizationDragDropContainer::addAcceptedMimeType(
155 const QString &mimeType, VisualizationDragDropContainer::DropBehavior behavior)
155 const QString &mimeType, VisualizationDragDropContainer::DropBehavior behavior)
156 {
156 {
157 impl->m_AcceptedMimeTypes[mimeType] = behavior;
157 impl->m_AcceptedMimeTypes[mimeType] = behavior;
158 }
158 }
159
159
160 int VisualizationDragDropContainer::countDragWidget() const
160 int VisualizationDragDropContainer::countDragWidget() const
161 {
161 {
162 return impl->countDragWidget(this);
162 return impl->countDragWidget(this);
163 }
163 }
164
164
165 void VisualizationDragDropContainer::setAcceptMimeDataFunction(
165 void VisualizationDragDropContainer::setAcceptMimeDataFunction(
166 VisualizationDragDropContainer::AcceptMimeDataFunction fun)
166 VisualizationDragDropContainer::AcceptMimeDataFunction fun)
167 {
167 {
168 impl->m_AcceptMimeDataFun = fun;
168 impl->m_AcceptMimeDataFun = fun;
169 }
169 }
170
170
171 void VisualizationDragDropContainer::setPlaceHolderType(DragDropHelper::PlaceHolderType type,
171 void VisualizationDragDropContainer::setPlaceHolderType(DragDropHelper::PlaceHolderType type,
172 const QString &placeHolderText)
172 const QString &placeHolderText)
173 {
173 {
174 impl->m_PlaceHolderType = type;
174 impl->m_PlaceHolderType = type;
175 impl->m_PlaceHolderText = placeHolderText;
175 impl->m_PlaceHolderText = placeHolderText;
176 }
176 }
177
177
178 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidget,
178 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidget,
179 const QPoint &dragPosition)
179 const QPoint &dragPosition)
180 {
180 {
181 auto &helper = sqpApp->dragDropHelper();
181 auto &helper = sqpApp->dragDropHelper();
182 helper.resetDragAndDrop();
182 helper.resetDragAndDrop();
183
183
184 // Note: The management of the drag object is done by Qt
184 // Note: The management of the drag object is done by Qt
185 auto drag = new QDrag{dragWidget};
185 auto drag = new QDrag{dragWidget};
186 drag->setHotSpot(dragPosition);
186 drag->setHotSpot(dragPosition);
187
187
188 auto mimeData = dragWidget->mimeData();
188 auto mimeData = dragWidget->mimeData();
189 drag->setMimeData(mimeData);
189 drag->setMimeData(mimeData);
190
190
191 auto pixmap = QPixmap(dragWidget->size());
191 auto pixmap = QPixmap(dragWidget->size());
192 dragWidget->render(&pixmap);
192 dragWidget->render(&pixmap);
193 drag->setPixmap(pixmap);
193 drag->setPixmap(pixmap);
194
194
195 auto image = pixmap.toImage();
195 auto image = pixmap.toImage();
196 mimeData->setImageData(image);
196 mimeData->setImageData(image);
197 mimeData->setUrls({helper.imageTemporaryUrl(image)});
197 mimeData->setUrls({helper.imageTemporaryUrl(image)});
198
198
199 if (impl->m_Layout->indexOf(dragWidget) >= 0) {
199 if (impl->m_Layout->indexOf(dragWidget) >= 0) {
200 helper.setCurrentDragWidget(dragWidget);
200 helper.setCurrentDragWidget(dragWidget);
201
201
202 if (impl->cursorIsInContainer(this)) {
202 if (impl->cursorIsInContainer(this)) {
203 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
203 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
204 helper.insertPlaceHolder(impl->m_Layout, dragWidgetIndex, impl->m_PlaceHolderType,
204 helper.insertPlaceHolder(impl->m_Layout, dragWidgetIndex, impl->m_PlaceHolderType,
205 impl->m_PlaceHolderText);
205 impl->m_PlaceHolderText);
206 dragWidget->setVisible(false);
206 dragWidget->setVisible(false);
207 }
207 }
208 else {
208 else {
209 // The drag starts directly outside the drop zone
209 // The drag starts directly outside the drop zone
210 // do not add the placeHolder
210 // do not add the placeHolder
211 }
211 }
212
212
213 // Note: The exec() is blocking on windows but not on linux and macOS
213 // Note: The exec() is blocking on windows but not on linux and macOS
214 drag->exec(Qt::MoveAction | Qt::CopyAction);
214 drag->exec(Qt::MoveAction | Qt::CopyAction);
215 }
215 }
216 else {
216 else {
217 qCWarning(LOG_VisualizationDragDropContainer())
217 qCWarning(LOG_VisualizationDragDropContainer())
218 << tr("VisualizationDragDropContainer::startDrag, drag aborted, the specified "
218 << tr("VisualizationDragDropContainer::startDrag, drag aborted, the specified "
219 "VisualizationDragWidget is not found in this container.");
219 "VisualizationDragWidget is not found in this container.");
220 }
220 }
221 }
221 }
222
222
223 void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event)
223 void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event)
224 {
224 {
225 if (impl->acceptMimeData(event->mimeData())) {
225 if (impl->acceptMimeData(event->mimeData())) {
226 event->acceptProposedAction();
226 event->acceptProposedAction();
227
227
228 auto &helper = sqpApp->dragDropHelper();
228 auto &helper = sqpApp->dragDropHelper();
229
229
230 if (!impl->hasPlaceHolder()) {
230 if (!impl->hasPlaceHolder()) {
231 auto dragWidget = helper.getCurrentDragWidget();
231 auto dragWidget = helper.getCurrentDragWidget();
232
232
233 if (dragWidget) {
233 if (dragWidget) {
234 // If the drag&drop is internal to the visualization, entering the container hide
234 // If the drag&drop is internal to the visualization, entering the container hide
235 // the dragWidget which was made visible by the dragLeaveEvent
235 // the dragWidget which was made visible by the dragLeaveEvent
236 auto parentWidget
236 auto parentWidget
237 = qobject_cast<VisualizationDragDropContainer *>(dragWidget->parentWidget());
237 = qobject_cast<VisualizationDragDropContainer *>(dragWidget->parentWidget());
238 if (parentWidget) {
238 if (parentWidget) {
239 dragWidget->setVisible(false);
239 dragWidget->setVisible(false);
240 }
240 }
241 }
241 }
242
242
243 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
243 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
244 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
244 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
245 impl->findPlaceHolderPosition(event->pos(), canInsert, canMerge, this);
245 impl->findPlaceHolderPosition(event->pos(), canInsert, canMerge, this);
246 }
246 }
247 else {
247 else {
248 // do nothing
248 // do nothing
249 }
249 }
250 }
250 }
251 else {
251 else {
252 event->ignore();
252 event->ignore();
253 }
253 }
254
254
255 QWidget::dragEnterEvent(event);
255 QWidget::dragEnterEvent(event);
256 }
256 }
257
257
258 void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event)
258 void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event)
259 {
259 {
260 Q_UNUSED(event);
260 Q_UNUSED(event);
261
261
262 auto &helper = sqpApp->dragDropHelper();
262 auto &helper = sqpApp->dragDropHelper();
263
263
264 if (!impl->cursorIsInContainer(this)) {
264 if (!impl->cursorIsInContainer(this)) {
265 helper.removePlaceHolder();
265 helper.removePlaceHolder();
266 helper.setHightlightedDragWidget(nullptr);
266 helper.setHightlightedDragWidget(nullptr);
267 impl->m_MinContainerHeight = 0;
267 impl->m_MinContainerHeight = 0;
268
268
269 auto dragWidget = helper.getCurrentDragWidget();
269 auto dragWidget = helper.getCurrentDragWidget();
270 if (dragWidget) {
270 if (dragWidget) {
271 // dragWidget has a value only if the drag is started from the visualization
271 // dragWidget has a value only if the drag is started from the visualization
272 // In that case, shows the drag widget at its original place
272 // In that case, shows the drag widget at its original place
273 // So the drag widget doesn't stay hidden if the drop occurs outside the visualization
273 // So the drag widget doesn't stay hidden if the drop occurs outside the visualization
274 // drop zone (It is not possible to catch a drop event outside of the application)
274 // drop zone (It is not possible to catch a drop event outside of the application)
275
275
276 if (dragWidget) {
276 if (dragWidget) {
277 dragWidget->setVisible(true);
277 dragWidget->setVisible(true);
278 }
278 }
279 }
279 }
280 }
280 }
281 else {
281 else {
282 // Leave event probably received for a child widget.
282 // Leave event probably received for a child widget.
283 // Do nothing.
283 // Do nothing.
284 // Note: The DragLeave event, doesn't have any mean to determine who sent it.
284 // Note: The DragLeave event, doesn't have any mean to determine who sent it.
285 }
285 }
286
286
287 QWidget::dragLeaveEvent(event);
287 QWidget::dragLeaveEvent(event);
288 }
288 }
289
289
290 void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event)
290 void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event)
291 {
291 {
292 if (impl->acceptMimeData(event->mimeData())) {
292 if (impl->acceptMimeData(event->mimeData())) {
293 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
293 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
294 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
294 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
295 impl->findPlaceHolderPosition(event->pos(), canInsert, canMerge, this);
295 impl->findPlaceHolderPosition(event->pos(), canInsert, canMerge, this);
296 }
296 }
297 else {
297 else {
298 event->ignore();
298 event->ignore();
299 }
299 }
300
300
301 QWidget::dragMoveEvent(event);
301 QWidget::dragMoveEvent(event);
302 }
302 }
303
303
304 void VisualizationDragDropContainer::dropEvent(QDropEvent *event)
304 void VisualizationDragDropContainer::dropEvent(QDropEvent *event)
305 {
305 {
306 auto &helper = sqpApp->dragDropHelper();
306 auto &helper = sqpApp->dragDropHelper();
307
307
308 if (impl->acceptMimeData(event->mimeData())) {
308 if (impl->acceptMimeData(event->mimeData())) {
309 auto dragWidget = helper.getCurrentDragWidget();
309 auto dragWidget = helper.getCurrentDragWidget();
310 if (impl->hasPlaceHolder()) {
310 if (impl->hasPlaceHolder()) {
311 // drop where the placeHolder is located
311 // drop where the placeHolder is located
312
312
313 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
313 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
314 if (canInsert) {
314 if (canInsert) {
315 auto droppedIndex = impl->m_Layout->indexOf(&helper.placeHolder());
315 auto droppedIndex = impl->m_Layout->indexOf(&helper.placeHolder());
316
316
317 if (dragWidget) {
317 if (dragWidget) {
318 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
318 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
319 if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex) {
319 if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex) {
320 // Correction of the index if the drop occurs in the same container
320 // Correction of the index if the drop occurs in the same container
321 // and if the drag is started from the visualization (in that case, the
321 // and if the drag is started from the visualization (in that case, the
322 // dragWidget is hidden)
322 // dragWidget is hidden)
323 droppedIndex -= 1;
323 droppedIndex -= 1;
324 }
324 }
325
325
326 dragWidget->setVisible(true);
326 dragWidget->setVisible(true);
327 }
327 }
328
328
329 event->acceptProposedAction();
329 event->acceptProposedAction();
330
330
331 helper.removePlaceHolder();
331 helper.removePlaceHolder();
332
332
333 emit dropOccuredInContainer(droppedIndex, event->mimeData());
333 emit dropOccuredInContainer(droppedIndex, event->mimeData());
334 }
334 }
335 else {
335 else {
336 qCWarning(LOG_VisualizationDragDropContainer()) << tr(
336 qCWarning(LOG_VisualizationDragDropContainer()) << tr(
337 "VisualizationDragDropContainer::dropEvent, dropping on the placeHolder, but "
337 "VisualizationDragDropContainer::dropEvent, dropping on the placeHolder, but "
338 "the insertion is forbidden.");
338 "the insertion is forbidden.");
339 Q_ASSERT(false);
339 Q_ASSERT(false);
340 }
340 }
341 }
341 }
342 else if (helper.getHightlightedDragWidget()) {
342 else if (helper.getHightlightedDragWidget()) {
343 // drop on the highlighted widget
343 // drop on the highlighted widget
344
344
345 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
345 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
346 if (canMerge) {
346 if (canMerge) {
347 event->acceptProposedAction();
347 event->acceptProposedAction();
348 emit dropOccuredOnWidget(helper.getHightlightedDragWidget(), event->mimeData());
348 emit dropOccuredOnWidget(helper.getHightlightedDragWidget(), event->mimeData());
349 }
349 }
350 else {
350 else {
351 qCWarning(LOG_VisualizationDragDropContainer())
351 qCWarning(LOG_VisualizationDragDropContainer())
352 << tr("VisualizationDragDropContainer::dropEvent, dropping on a widget, but "
352 << tr("VisualizationDragDropContainer::dropEvent, dropping on a widget, but "
353 "the merge is forbidden.");
353 "the merge is forbidden.");
354 Q_ASSERT(false);
354 Q_ASSERT(false);
355 }
355 }
356 }
356 }
357 }
357 }
358 else {
358 else {
359 event->ignore();
359 event->ignore();
360 }
360 }
361
361
362 sqpApp->dragDropHelper().setHightlightedDragWidget(nullptr);
362 sqpApp->dragDropHelper().setHightlightedDragWidget(nullptr);
363 impl->m_MinContainerHeight = 0;
363 impl->m_MinContainerHeight = 0;
364
364
365 QWidget::dropEvent(event);
365 QWidget::dropEvent(event);
366 }
366 }
367
367
368
368
369 void VisualizationDragDropContainer::VisualizationDragDropContainerPrivate::findPlaceHolderPosition(
369 void VisualizationDragDropContainer::VisualizationDragDropContainerPrivate::findPlaceHolderPosition(
370 const QPoint &pos, bool canInsert, bool canMerge,
370 const QPoint &pos, bool canInsert, bool canMerge,
371 const VisualizationDragDropContainer *container)
371 const VisualizationDragDropContainer *container)
372 {
372 {
373 auto &helper = sqpApp->dragDropHelper();
373 auto &helper = sqpApp->dragDropHelper();
374
374
375 auto absPos = container->mapToGlobal(pos);
375 auto absPos = container->mapToGlobal(pos);
376 auto isOnPlaceHolder = sqpApp->widgetAt(absPos) == &(helper.placeHolder());
376 auto isOnPlaceHolder = sqpApp->widgetAt(absPos) == &(helper.placeHolder());
377
377
378 if (countDragWidget(container, true) == 0) {
378 if (countDragWidget(container, true) == 0) {
379 // Drop on an empty container, just add the placeHolder at the top
379 // Drop on an empty container, just add the placeHolder at the top
380 helper.insertPlaceHolder(m_Layout, 0, m_PlaceHolderType, m_PlaceHolderText);
380 helper.insertPlaceHolder(m_Layout, 0, m_PlaceHolderType, m_PlaceHolderText);
381 }
381 }
382 else if (!isOnPlaceHolder) {
382 else if (!isOnPlaceHolder) {
383 auto nbDragWidget = countDragWidget(container);
383 auto nbDragWidget = countDragWidget(container);
384 if (nbDragWidget > 0) {
384 if (nbDragWidget > 0) {
385
385
386 if (m_MinContainerHeight == 0) {
386 if (m_MinContainerHeight == 0) {
387 m_MinContainerHeight = container->size().height();
387 m_MinContainerHeight = container->size().height();
388 }
388 }
389
389
390 m_MinContainerHeight = qMin(m_MinContainerHeight, container->size().height());
390 m_MinContainerHeight = qMin(m_MinContainerHeight, container->size().height());
391 auto graphHeight = qMax(m_MinContainerHeight / nbDragWidget, GRAPH_MINIMUM_HEIGHT);
391 auto graphHeight = qMax(m_MinContainerHeight / nbDragWidget, GRAPH_MINIMUM_HEIGHT);
392
392
393 auto posY = pos.y();
393 auto posY = pos.y();
394 auto dropIndex = floor(posY / graphHeight);
394 auto dropIndex = floor(posY / graphHeight);
395 auto zoneSize = qMin(graphHeight / 4.0, 75.0);
395 auto zoneSize = qMin(graphHeight / 4.0, 75.0);
396
396
397
397
398 auto isOnTop = posY < dropIndex * graphHeight + zoneSize;
398 auto isOnTop = posY < dropIndex * graphHeight + zoneSize;
399 auto isOnBottom = posY > (dropIndex + 1) * graphHeight - zoneSize;
399 auto isOnBottom = posY > (dropIndex + 1) * graphHeight - zoneSize;
400
400
401 auto placeHolderIndex = m_Layout->indexOf(&(helper.placeHolder()));
401 auto placeHolderIndex = m_Layout->indexOf(&(helper.placeHolder()));
402
402
403 auto dragWidgetHovered = getChildDragWidgetAt(container, pos);
403 auto dragWidgetHovered = getChildDragWidgetAt(container, pos);
404
404
405 if (canInsert && (isOnTop || isOnBottom || !canMerge)) {
405 if (canInsert && (isOnTop || isOnBottom || !canMerge)) {
406 if (isOnBottom) {
406 if (isOnBottom) {
407 dropIndex += 1;
407 dropIndex += 1;
408 }
408 }
409
409
410 if (helper.getCurrentDragWidget()) {
410 if (helper.getCurrentDragWidget()) {
411 auto dragWidgetIndex = m_Layout->indexOf(helper.getCurrentDragWidget());
411 auto dragWidgetIndex = m_Layout->indexOf(helper.getCurrentDragWidget());
412 if (dragWidgetIndex >= 0 && dragWidgetIndex <= dropIndex) {
412 if (dragWidgetIndex >= 0 && dragWidgetIndex <= dropIndex) {
413 // Correction of the index if the drop occurs in the same container
413 // Correction of the index if the drop occurs in the same container
414 // and if the drag is started from the visualization (in that case, the
414 // and if the drag is started from the visualization (in that case, the
415 // dragWidget is hidden)
415 // dragWidget is hidden)
416 dropIndex += 1;
416 dropIndex += 1;
417 }
417 }
418 }
418 }
419
419
420 if (dropIndex != placeHolderIndex) {
420 if (dropIndex != placeHolderIndex) {
421 helper.insertPlaceHolder(m_Layout, dropIndex, m_PlaceHolderType,
421 helper.insertPlaceHolder(m_Layout, dropIndex, m_PlaceHolderType,
422 m_PlaceHolderText);
422 m_PlaceHolderText);
423 }
423 }
424
424
425 helper.setHightlightedDragWidget(nullptr);
425 helper.setHightlightedDragWidget(nullptr);
426 }
426 }
427 else if (canMerge && dragWidgetHovered) {
427 else if (canMerge && dragWidgetHovered) {
428 // drop on the middle -> merge
428 // drop on the middle -> merge
429 if (hasPlaceHolder()) {
429 if (hasPlaceHolder()) {
430 helper.removePlaceHolder();
430 helper.removePlaceHolder();
431 }
431 }
432
432
433 helper.setHightlightedDragWidget(dragWidgetHovered);
433 helper.setHightlightedDragWidget(dragWidgetHovered);
434 }
434 }
435 else {
435 else {
436 qCWarning(LOG_VisualizationDragDropContainer())
436 qCWarning(LOG_VisualizationDragDropContainer())
437 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no valid drop "
437 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no valid drop "
438 "action.");
438 "action.");
439 Q_ASSERT(false);
439 Q_ASSERT(false);
440 }
440 }
441 }
441 }
442 else {
442 else {
443 qCWarning(LOG_VisualizationDragDropContainer())
443 qCWarning(LOG_VisualizationDragDropContainer())
444 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no widget "
444 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no widget "
445 "found in the "
445 "found in the "
446 "container");
446 "container");
447 }
447 }
448 }
448 }
449 else {
449 else {
450 // the mouse is hover the placeHolder
450 // the mouse is hover the placeHolder
451 // Do nothing
451 // Do nothing
452 }
452 }
453 }
453 }
@@ -1,401 +1,401
1 #include "Visualization/VisualizationGraphWidget.h"
1 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationDefs.h"
3 #include "Visualization/VisualizationDefs.h"
4 #include "Visualization/VisualizationGraphHelper.h"
4 #include "Visualization/VisualizationGraphHelper.h"
5 #include "Visualization/VisualizationGraphRenderingDelegate.h"
5 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 #include "Visualization/VisualizationZoneWidget.h"
6 #include "Visualization/VisualizationZoneWidget.h"
7 #include "ui_VisualizationGraphWidget.h"
7 #include "ui_VisualizationGraphWidget.h"
8
8
9 #include <Common/MimeTypesDef.h>
9 #include <Common/MimeTypesDef.h>
10 #include <Data/ArrayData.h>
10 #include <Data/ArrayData.h>
11 #include <Data/IDataSeries.h>
11 #include <Data/IDataSeries.h>
12 #include <DragDropHelper.h>
12 #include <DragAndDrop/DragDropHelper.h>
13 #include <Settings/SqpSettingsDefs.h>
13 #include <Settings/SqpSettingsDefs.h>
14 #include <SqpApplication.h>
14 #include <SqpApplication.h>
15 #include <Time/TimeController.h>
15 #include <Time/TimeController.h>
16 #include <Variable/Variable.h>
16 #include <Variable/Variable.h>
17 #include <Variable/VariableController.h>
17 #include <Variable/VariableController.h>
18
18
19 #include <unordered_map>
19 #include <unordered_map>
20
20
21 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
21 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
22
22
23 namespace {
23 namespace {
24
24
25 /// Key pressed to enable zoom on horizontal axis
25 /// Key pressed to enable zoom on horizontal axis
26 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
26 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
27
27
28 /// Key pressed to enable zoom on vertical axis
28 /// Key pressed to enable zoom on vertical axis
29 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
29 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
30
30
31 } // namespace
31 } // namespace
32
32
33 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
33 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
34
34
35 explicit VisualizationGraphWidgetPrivate(const QString &name)
35 explicit VisualizationGraphWidgetPrivate(const QString &name)
36 : m_Name{name},
36 : m_Name{name},
37 m_DoAcquisition{true},
37 m_DoAcquisition{true},
38 m_IsCalibration{false},
38 m_IsCalibration{false},
39 m_RenderingDelegate{nullptr}
39 m_RenderingDelegate{nullptr}
40 {
40 {
41 }
41 }
42
42
43 QString m_Name;
43 QString m_Name;
44 // 1 variable -> n qcpplot
44 // 1 variable -> n qcpplot
45 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
45 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
46 bool m_DoAcquisition;
46 bool m_DoAcquisition;
47 bool m_IsCalibration;
47 bool m_IsCalibration;
48 QCPItemTracer *m_TextTracer;
48 QCPItemTracer *m_TextTracer;
49 /// Delegate used to attach rendering features to the plot
49 /// Delegate used to attach rendering features to the plot
50 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
50 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
51 };
51 };
52
52
53 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
53 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
54 : VisualizationDragWidget{parent},
54 : VisualizationDragWidget{parent},
55 ui{new Ui::VisualizationGraphWidget},
55 ui{new Ui::VisualizationGraphWidget},
56 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
56 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
57 {
57 {
58 ui->setupUi(this);
58 ui->setupUi(this);
59
59
60 // 'Close' options : widget is deleted when closed
60 // 'Close' options : widget is deleted when closed
61 setAttribute(Qt::WA_DeleteOnClose);
61 setAttribute(Qt::WA_DeleteOnClose);
62
62
63 // Set qcpplot properties :
63 // Set qcpplot properties :
64 // - Drag (on x-axis) and zoom are enabled
64 // - Drag (on x-axis) and zoom are enabled
65 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
65 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
66 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectItems);
66 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectItems);
67 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
67 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
68
68
69 // The delegate must be initialized after the ui as it uses the plot
69 // The delegate must be initialized after the ui as it uses the plot
70 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
70 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
71
71
72 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
72 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
73 connect(ui->widget, &QCustomPlot::mouseRelease, this,
73 connect(ui->widget, &QCustomPlot::mouseRelease, this,
74 &VisualizationGraphWidget::onMouseRelease);
74 &VisualizationGraphWidget::onMouseRelease);
75 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
75 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
76 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
76 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
77 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
77 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
78 &QCPAxis::rangeChanged),
78 &QCPAxis::rangeChanged),
79 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
79 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
80
80
81 // Activates menu when right clicking on the graph
81 // Activates menu when right clicking on the graph
82 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
82 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
83 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
83 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
84 &VisualizationGraphWidget::onGraphMenuRequested);
84 &VisualizationGraphWidget::onGraphMenuRequested);
85
85
86 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
86 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
87 &VariableController::onRequestDataLoading);
87 &VariableController::onRequestDataLoading);
88
88
89 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
89 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
90 &VisualizationGraphWidget::onUpdateVarDisplaying);
90 &VisualizationGraphWidget::onUpdateVarDisplaying);
91 }
91 }
92
92
93
93
94 VisualizationGraphWidget::~VisualizationGraphWidget()
94 VisualizationGraphWidget::~VisualizationGraphWidget()
95 {
95 {
96 delete ui;
96 delete ui;
97 }
97 }
98
98
99 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
99 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
100 {
100 {
101 auto parent = parentWidget();
101 auto parent = parentWidget();
102 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
102 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
103 parent = parent->parentWidget();
103 parent = parent->parentWidget();
104 }
104 }
105
105
106 return qobject_cast<VisualizationZoneWidget *>(parent);
106 return qobject_cast<VisualizationZoneWidget *>(parent);
107 }
107 }
108
108
109 void VisualizationGraphWidget::enableAcquisition(bool enable)
109 void VisualizationGraphWidget::enableAcquisition(bool enable)
110 {
110 {
111 impl->m_DoAcquisition = enable;
111 impl->m_DoAcquisition = enable;
112 }
112 }
113
113
114 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
114 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
115 {
115 {
116 // Uses delegate to create the qcpplot components according to the variable
116 // Uses delegate to create the qcpplot components according to the variable
117 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
117 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
118 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
118 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
119
119
120 // Set axes properties according to the units of the data series
120 // Set axes properties according to the units of the data series
121 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
121 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
122 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
122 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
123 auto xAxisUnit = Unit{};
123 auto xAxisUnit = Unit{};
124 auto valuesUnit = Unit{};
124 auto valuesUnit = Unit{};
125
125
126 if (auto dataSeries = variable->dataSeries()) {
126 if (auto dataSeries = variable->dataSeries()) {
127 dataSeries->lockRead();
127 dataSeries->lockRead();
128 xAxisUnit = dataSeries->xAxisUnit();
128 xAxisUnit = dataSeries->xAxisUnit();
129 valuesUnit = dataSeries->valuesUnit();
129 valuesUnit = dataSeries->valuesUnit();
130 dataSeries->unlock();
130 dataSeries->unlock();
131 }
131 }
132 impl->m_RenderingDelegate->setAxesProperties(xAxisUnit, valuesUnit);
132 impl->m_RenderingDelegate->setAxesProperties(xAxisUnit, valuesUnit);
133
133
134 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
134 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
135
135
136 this->enableAcquisition(false);
136 this->enableAcquisition(false);
137 this->setGraphRange(range);
137 this->setGraphRange(range);
138 this->enableAcquisition(true);
138 this->enableAcquisition(true);
139
139
140 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
140 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
141
141
142 emit variableAdded(variable);
142 emit variableAdded(variable);
143 }
143 }
144
144
145 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
145 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
146 {
146 {
147 // Each component associated to the variable :
147 // Each component associated to the variable :
148 // - is removed from qcpplot (which deletes it)
148 // - is removed from qcpplot (which deletes it)
149 // - is no longer referenced in the map
149 // - is no longer referenced in the map
150 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
150 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
151 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
151 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
152 emit variableAboutToBeRemoved(variable);
152 emit variableAboutToBeRemoved(variable);
153
153
154 auto &plottablesMap = variableIt->second;
154 auto &plottablesMap = variableIt->second;
155
155
156 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
156 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
157 plottableIt != plottableEnd;) {
157 plottableIt != plottableEnd;) {
158 ui->widget->removePlottable(plottableIt->second);
158 ui->widget->removePlottable(plottableIt->second);
159 plottableIt = plottablesMap.erase(plottableIt);
159 plottableIt = plottablesMap.erase(plottableIt);
160 }
160 }
161
161
162 impl->m_VariableToPlotMultiMap.erase(variableIt);
162 impl->m_VariableToPlotMultiMap.erase(variableIt);
163 }
163 }
164
164
165 // Updates graph
165 // Updates graph
166 ui->widget->replot();
166 ui->widget->replot();
167 }
167 }
168
168
169 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
169 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
170 {
170 {
171 auto variables = QList<std::shared_ptr<Variable> >{};
171 auto variables = QList<std::shared_ptr<Variable> >{};
172 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
172 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
173 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
173 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
174 variables << it->first;
174 variables << it->first;
175 }
175 }
176
176
177 return variables;
177 return variables;
178 }
178 }
179
179
180 void VisualizationGraphWidget::setYRange(const SqpRange &range)
180 void VisualizationGraphWidget::setYRange(const SqpRange &range)
181 {
181 {
182 ui->widget->yAxis->setRange(range.m_TStart, range.m_TEnd);
182 ui->widget->yAxis->setRange(range.m_TStart, range.m_TEnd);
183 }
183 }
184
184
185 SqpRange VisualizationGraphWidget::graphRange() const noexcept
185 SqpRange VisualizationGraphWidget::graphRange() const noexcept
186 {
186 {
187 auto graphRange = ui->widget->xAxis->range();
187 auto graphRange = ui->widget->xAxis->range();
188 return SqpRange{graphRange.lower, graphRange.upper};
188 return SqpRange{graphRange.lower, graphRange.upper};
189 }
189 }
190
190
191 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
191 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
192 {
192 {
193 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
193 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
194 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
194 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
195 ui->widget->replot();
195 ui->widget->replot();
196 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
196 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
197 }
197 }
198
198
199 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
199 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
200 {
200 {
201 if (visitor) {
201 if (visitor) {
202 visitor->visit(this);
202 visitor->visit(this);
203 }
203 }
204 else {
204 else {
205 qCCritical(LOG_VisualizationGraphWidget())
205 qCCritical(LOG_VisualizationGraphWidget())
206 << tr("Can't visit widget : the visitor is null");
206 << tr("Can't visit widget : the visitor is null");
207 }
207 }
208 }
208 }
209
209
210 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
210 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
211 {
211 {
212 /// @todo : for the moment, a graph can always accomodate a variable
212 /// @todo : for the moment, a graph can always accomodate a variable
213 Q_UNUSED(variable);
213 Q_UNUSED(variable);
214 return true;
214 return true;
215 }
215 }
216
216
217 bool VisualizationGraphWidget::contains(const Variable &variable) const
217 bool VisualizationGraphWidget::contains(const Variable &variable) const
218 {
218 {
219 // Finds the variable among the keys of the map
219 // Finds the variable among the keys of the map
220 auto variablePtr = &variable;
220 auto variablePtr = &variable;
221 auto findVariable
221 auto findVariable
222 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
222 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
223
223
224 auto end = impl->m_VariableToPlotMultiMap.cend();
224 auto end = impl->m_VariableToPlotMultiMap.cend();
225 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
225 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
226 return it != end;
226 return it != end;
227 }
227 }
228
228
229 QString VisualizationGraphWidget::name() const
229 QString VisualizationGraphWidget::name() const
230 {
230 {
231 return impl->m_Name;
231 return impl->m_Name;
232 }
232 }
233
233
234 QMimeData *VisualizationGraphWidget::mimeData() const
234 QMimeData *VisualizationGraphWidget::mimeData() const
235 {
235 {
236 auto mimeData = new QMimeData;
236 auto mimeData = new QMimeData;
237 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
237 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
238
238
239 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
239 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
240 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
240 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
241
241
242 return mimeData;
242 return mimeData;
243 }
243 }
244
244
245 bool VisualizationGraphWidget::isDragAllowed() const
245 bool VisualizationGraphWidget::isDragAllowed() const
246 {
246 {
247 return true;
247 return true;
248 }
248 }
249
249
250 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
250 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
251 {
251 {
252 if (highlighted) {
252 if (highlighted) {
253 plot().setBackground(QBrush(QColor("#BBD5EE")));
253 plot().setBackground(QBrush(QColor("#BBD5EE")));
254 }
254 }
255 else {
255 else {
256 plot().setBackground(QBrush(Qt::white));
256 plot().setBackground(QBrush(Qt::white));
257 }
257 }
258
258
259 plot().update();
259 plot().update();
260 }
260 }
261
261
262 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
262 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
263 {
263 {
264 Q_UNUSED(event);
264 Q_UNUSED(event);
265
265
266 // Prevents that all variables will be removed from graph when it will be closed
266 // Prevents that all variables will be removed from graph when it will be closed
267 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
267 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
268 emit variableAboutToBeRemoved(variableEntry.first);
268 emit variableAboutToBeRemoved(variableEntry.first);
269 }
269 }
270 }
270 }
271
271
272 void VisualizationGraphWidget::enterEvent(QEvent *event)
272 void VisualizationGraphWidget::enterEvent(QEvent *event)
273 {
273 {
274 Q_UNUSED(event);
274 Q_UNUSED(event);
275 impl->m_RenderingDelegate->showGraphOverlay(true);
275 impl->m_RenderingDelegate->showGraphOverlay(true);
276 }
276 }
277
277
278 void VisualizationGraphWidget::leaveEvent(QEvent *event)
278 void VisualizationGraphWidget::leaveEvent(QEvent *event)
279 {
279 {
280 Q_UNUSED(event);
280 Q_UNUSED(event);
281 impl->m_RenderingDelegate->showGraphOverlay(false);
281 impl->m_RenderingDelegate->showGraphOverlay(false);
282 }
282 }
283
283
284 QCustomPlot &VisualizationGraphWidget::plot() noexcept
284 QCustomPlot &VisualizationGraphWidget::plot() noexcept
285 {
285 {
286 return *ui->widget;
286 return *ui->widget;
287 }
287 }
288
288
289 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
289 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
290 {
290 {
291 QMenu graphMenu{};
291 QMenu graphMenu{};
292
292
293 // Iterates on variables (unique keys)
293 // Iterates on variables (unique keys)
294 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
294 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
295 end = impl->m_VariableToPlotMultiMap.cend();
295 end = impl->m_VariableToPlotMultiMap.cend();
296 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
296 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
297 // 'Remove variable' action
297 // 'Remove variable' action
298 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
298 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
299 [ this, var = it->first ]() { removeVariable(var); });
299 [ this, var = it->first ]() { removeVariable(var); });
300 }
300 }
301
301
302 if (!graphMenu.isEmpty()) {
302 if (!graphMenu.isEmpty()) {
303 graphMenu.exec(QCursor::pos());
303 graphMenu.exec(QCursor::pos());
304 }
304 }
305 }
305 }
306
306
307 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
307 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
308 {
308 {
309 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
309 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
310 << QThread::currentThread()->objectName() << "DoAcqui"
310 << QThread::currentThread()->objectName() << "DoAcqui"
311 << impl->m_DoAcquisition;
311 << impl->m_DoAcquisition;
312
312
313 auto graphRange = SqpRange{t1.lower, t1.upper};
313 auto graphRange = SqpRange{t1.lower, t1.upper};
314 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
314 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
315
315
316 if (impl->m_DoAcquisition) {
316 if (impl->m_DoAcquisition) {
317 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
317 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
318
318
319 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
319 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
320 end = impl->m_VariableToPlotMultiMap.end();
320 end = impl->m_VariableToPlotMultiMap.end();
321 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
321 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
322 variableUnderGraphVector.push_back(it->first);
322 variableUnderGraphVector.push_back(it->first);
323 }
323 }
324 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
324 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
325 !impl->m_IsCalibration);
325 !impl->m_IsCalibration);
326
326
327 if (!impl->m_IsCalibration) {
327 if (!impl->m_IsCalibration) {
328 qCDebug(LOG_VisualizationGraphWidget())
328 qCDebug(LOG_VisualizationGraphWidget())
329 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
329 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
330 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
330 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
331 emit synchronize(graphRange, oldGraphRange);
331 emit synchronize(graphRange, oldGraphRange);
332 }
332 }
333 }
333 }
334 }
334 }
335
335
336 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
336 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
337 {
337 {
338 // Handles plot rendering when mouse is moving
338 // Handles plot rendering when mouse is moving
339 impl->m_RenderingDelegate->onMouseMove(event);
339 impl->m_RenderingDelegate->onMouseMove(event);
340
340
341 VisualizationDragWidget::mouseMoveEvent(event);
341 VisualizationDragWidget::mouseMoveEvent(event);
342 }
342 }
343
343
344 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
344 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
345 {
345 {
346 auto zoomOrientations = QFlags<Qt::Orientation>{};
346 auto zoomOrientations = QFlags<Qt::Orientation>{};
347
347
348 // Lambda that enables a zoom orientation if the key modifier related to this orientation
348 // Lambda that enables a zoom orientation if the key modifier related to this orientation
349 // has
349 // has
350 // been pressed
350 // been pressed
351 auto enableOrientation
351 auto enableOrientation
352 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
352 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
353 auto orientationEnabled = event->modifiers().testFlag(modifier);
353 auto orientationEnabled = event->modifiers().testFlag(modifier);
354 zoomOrientations.setFlag(orientation, orientationEnabled);
354 zoomOrientations.setFlag(orientation, orientationEnabled);
355 };
355 };
356 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
356 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
357 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
357 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
358
358
359 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
359 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
360 }
360 }
361
361
362 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
362 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
363 {
363 {
364 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
364 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
365
365
366 plot().setInteraction(QCP::iRangeDrag, !event->modifiers().testFlag(Qt::AltModifier));
366 plot().setInteraction(QCP::iRangeDrag, !event->modifiers().testFlag(Qt::AltModifier));
367
367
368 VisualizationDragWidget::mousePressEvent(event);
368 VisualizationDragWidget::mousePressEvent(event);
369 }
369 }
370
370
371 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
371 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
372 {
372 {
373 impl->m_IsCalibration = false;
373 impl->m_IsCalibration = false;
374 }
374 }
375
375
376 void VisualizationGraphWidget::onDataCacheVariableUpdated()
376 void VisualizationGraphWidget::onDataCacheVariableUpdated()
377 {
377 {
378 auto graphRange = ui->widget->xAxis->range();
378 auto graphRange = ui->widget->xAxis->range();
379 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
379 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
380
380
381 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
381 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
382 auto variable = variableEntry.first;
382 auto variable = variableEntry.first;
383 qCDebug(LOG_VisualizationGraphWidget())
383 qCDebug(LOG_VisualizationGraphWidget())
384 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
384 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
385 qCDebug(LOG_VisualizationGraphWidget())
385 qCDebug(LOG_VisualizationGraphWidget())
386 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
386 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
387 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
387 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
388 VisualizationGraphHelper::updateData(variableEntry.second, variable->dataSeries(),
388 VisualizationGraphHelper::updateData(variableEntry.second, variable->dataSeries(),
389 variable->range());
389 variable->range());
390 }
390 }
391 }
391 }
392 }
392 }
393
393
394 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
394 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
395 const SqpRange &range)
395 const SqpRange &range)
396 {
396 {
397 auto it = impl->m_VariableToPlotMultiMap.find(variable);
397 auto it = impl->m_VariableToPlotMultiMap.find(variable);
398 if (it != impl->m_VariableToPlotMultiMap.end()) {
398 if (it != impl->m_VariableToPlotMultiMap.end()) {
399 VisualizationGraphHelper::updateData(it->second, variable->dataSeries(), range);
399 VisualizationGraphHelper::updateData(it->second, variable->dataSeries(), range);
400 }
400 }
401 }
401 }
@@ -1,309 +1,309
1 #include "Visualization/VisualizationTabWidget.h"
1 #include "Visualization/VisualizationTabWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "ui_VisualizationTabWidget.h"
3 #include "ui_VisualizationTabWidget.h"
4
4
5 #include "Visualization/VisualizationGraphWidget.h"
5 #include "Visualization/VisualizationGraphWidget.h"
6 #include "Visualization/VisualizationZoneWidget.h"
6 #include "Visualization/VisualizationZoneWidget.h"
7
7
8 #include "Variable/VariableController.h"
8 #include "Variable/VariableController.h"
9
9
10 #include "Common/MimeTypesDef.h"
10 #include "Common/MimeTypesDef.h"
11
11
12 #include "DragDropHelper.h"
12 #include "DragAndDrop/DragDropHelper.h"
13 #include "SqpApplication.h"
13 #include "SqpApplication.h"
14
14
15 Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget")
15 Q_LOGGING_CATEGORY(LOG_VisualizationTabWidget, "VisualizationTabWidget")
16
16
17 namespace {
17 namespace {
18
18
19 /// Generates a default name for a new zone, according to the number of zones already displayed in
19 /// Generates a default name for a new zone, according to the number of zones already displayed in
20 /// the tab
20 /// the tab
21 QString defaultZoneName(const QLayout &layout)
21 QString defaultZoneName(const QLayout &layout)
22 {
22 {
23 auto count = 0;
23 auto count = 0;
24 for (auto i = 0; i < layout.count(); ++i) {
24 for (auto i = 0; i < layout.count(); ++i) {
25 if (dynamic_cast<VisualizationZoneWidget *>(layout.itemAt(i)->widget())) {
25 if (dynamic_cast<VisualizationZoneWidget *>(layout.itemAt(i)->widget())) {
26 count++;
26 count++;
27 }
27 }
28 }
28 }
29
29
30 return QObject::tr("Zone %1").arg(count + 1);
30 return QObject::tr("Zone %1").arg(count + 1);
31 }
31 }
32
32
33 /**
33 /**
34 * Applies a function to all zones of the tab represented by its layout
34 * Applies a function to all zones of the tab represented by its layout
35 * @param layout the layout that contains zones
35 * @param layout the layout that contains zones
36 * @param fun the function to apply to each zone
36 * @param fun the function to apply to each zone
37 */
37 */
38 template <typename Fun>
38 template <typename Fun>
39 void processZones(QLayout &layout, Fun fun)
39 void processZones(QLayout &layout, Fun fun)
40 {
40 {
41 for (auto i = 0; i < layout.count(); ++i) {
41 for (auto i = 0; i < layout.count(); ++i) {
42 if (auto item = layout.itemAt(i)) {
42 if (auto item = layout.itemAt(i)) {
43 if (auto visualizationZoneWidget
43 if (auto visualizationZoneWidget
44 = dynamic_cast<VisualizationZoneWidget *>(item->widget())) {
44 = dynamic_cast<VisualizationZoneWidget *>(item->widget())) {
45 fun(*visualizationZoneWidget);
45 fun(*visualizationZoneWidget);
46 }
46 }
47 }
47 }
48 }
48 }
49 }
49 }
50
50
51 } // namespace
51 } // namespace
52
52
53 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
53 struct VisualizationTabWidget::VisualizationTabWidgetPrivate {
54 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
54 explicit VisualizationTabWidgetPrivate(const QString &name) : m_Name{name} {}
55
55
56 QString m_Name;
56 QString m_Name;
57
57
58 void dropGraph(int index, VisualizationTabWidget *tabWidget);
58 void dropGraph(int index, VisualizationTabWidget *tabWidget);
59 void dropZone(int index, VisualizationTabWidget *tabWidget);
59 void dropZone(int index, VisualizationTabWidget *tabWidget);
60 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
60 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
61 VisualizationTabWidget *tabWidget);
61 VisualizationTabWidget *tabWidget);
62 };
62 };
63
63
64 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
64 VisualizationTabWidget::VisualizationTabWidget(const QString &name, QWidget *parent)
65 : QWidget{parent},
65 : QWidget{parent},
66 ui{new Ui::VisualizationTabWidget},
66 ui{new Ui::VisualizationTabWidget},
67 impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)}
67 impl{spimpl::make_unique_impl<VisualizationTabWidgetPrivate>(name)}
68 {
68 {
69 ui->setupUi(this);
69 ui->setupUi(this);
70
70
71 ui->dragDropContainer->setPlaceHolderType(DragDropHelper::PlaceHolderType::Zone, "Zone");
71 ui->dragDropContainer->setPlaceHolderType(DragDropHelper::PlaceHolderType::Zone, "Zone");
72 ui->dragDropContainer->layout()->setContentsMargins(0, 0, 0, 5);
72 ui->dragDropContainer->layout()->setContentsMargins(0, 0, 0, 5);
73 ui->dragDropContainer->addAcceptedMimeType(
73 ui->dragDropContainer->addAcceptedMimeType(
74 MIME_TYPE_GRAPH, VisualizationDragDropContainer::DropBehavior::Inserted);
74 MIME_TYPE_GRAPH, VisualizationDragDropContainer::DropBehavior::Inserted);
75 ui->dragDropContainer->addAcceptedMimeType(
75 ui->dragDropContainer->addAcceptedMimeType(
76 MIME_TYPE_ZONE, VisualizationDragDropContainer::DropBehavior::Inserted);
76 MIME_TYPE_ZONE, VisualizationDragDropContainer::DropBehavior::Inserted);
77 ui->dragDropContainer->addAcceptedMimeType(
77 ui->dragDropContainer->addAcceptedMimeType(
78 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::Inserted);
78 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::Inserted);
79
79
80 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
80 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
81 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
81 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
82 ui->dragDropContainer);
82 ui->dragDropContainer);
83 });
83 });
84
84
85 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
85 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
86 &VisualizationTabWidget::dropMimeData);
86 &VisualizationTabWidget::dropMimeData);
87
87
88 sqpApp->dragDropHelper().addDragDropScrollArea(ui->scrollArea);
88 sqpApp->dragDropHelper().addDragDropScrollArea(ui->scrollArea);
89
89
90 // Widget is deleted when closed
90 // Widget is deleted when closed
91 setAttribute(Qt::WA_DeleteOnClose);
91 setAttribute(Qt::WA_DeleteOnClose);
92 }
92 }
93
93
94 VisualizationTabWidget::~VisualizationTabWidget()
94 VisualizationTabWidget::~VisualizationTabWidget()
95 {
95 {
96 sqpApp->dragDropHelper().removeDragDropScrollArea(ui->scrollArea);
96 sqpApp->dragDropHelper().removeDragDropScrollArea(ui->scrollArea);
97 delete ui;
97 delete ui;
98 }
98 }
99
99
100 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
100 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
101 {
101 {
102 ui->dragDropContainer->addDragWidget(zoneWidget);
102 ui->dragDropContainer->addDragWidget(zoneWidget);
103 }
103 }
104
104
105 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget)
105 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget)
106 {
106 {
107 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
107 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
108 }
108 }
109
109
110 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
110 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
111 {
111 {
112 return createZone({variable}, -1);
112 return createZone({variable}, -1);
113 }
113 }
114
114
115 VisualizationZoneWidget *
115 VisualizationZoneWidget *
116 VisualizationTabWidget::createZone(const QList<std::shared_ptr<Variable> > &variables, int index)
116 VisualizationTabWidget::createZone(const QList<std::shared_ptr<Variable> > &variables, int index)
117 {
117 {
118 auto zoneWidget = createEmptyZone(index);
118 auto zoneWidget = createEmptyZone(index);
119
119
120 // Creates a new graph into the zone
120 // Creates a new graph into the zone
121 zoneWidget->createGraph(variables, index);
121 zoneWidget->createGraph(variables, index);
122
122
123 return zoneWidget;
123 return zoneWidget;
124 }
124 }
125
125
126 VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index)
126 VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index)
127 {
127 {
128 auto zoneWidget
128 auto zoneWidget
129 = new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this};
129 = new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this};
130 this->insertZone(index, zoneWidget);
130 this->insertZone(index, zoneWidget);
131
131
132 return zoneWidget;
132 return zoneWidget;
133 }
133 }
134
134
135 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
135 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
136 {
136 {
137 if (visitor) {
137 if (visitor) {
138 visitor->visitEnter(this);
138 visitor->visitEnter(this);
139
139
140 // Apply visitor to zone children: widgets different from zones are not visited (no action)
140 // Apply visitor to zone children: widgets different from zones are not visited (no action)
141 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
141 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
142 zoneWidget.accept(visitor);
142 zoneWidget.accept(visitor);
143 });
143 });
144
144
145 visitor->visitLeave(this);
145 visitor->visitLeave(this);
146 }
146 }
147 else {
147 else {
148 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
148 qCCritical(LOG_VisualizationTabWidget()) << tr("Can't visit widget : the visitor is null");
149 }
149 }
150 }
150 }
151
151
152 bool VisualizationTabWidget::canDrop(const Variable &variable) const
152 bool VisualizationTabWidget::canDrop(const Variable &variable) const
153 {
153 {
154 // A tab can always accomodate a variable
154 // A tab can always accomodate a variable
155 Q_UNUSED(variable);
155 Q_UNUSED(variable);
156 return true;
156 return true;
157 }
157 }
158
158
159 bool VisualizationTabWidget::contains(const Variable &variable) const
159 bool VisualizationTabWidget::contains(const Variable &variable) const
160 {
160 {
161 Q_UNUSED(variable);
161 Q_UNUSED(variable);
162 return false;
162 return false;
163 }
163 }
164
164
165 QString VisualizationTabWidget::name() const
165 QString VisualizationTabWidget::name() const
166 {
166 {
167 return impl->m_Name;
167 return impl->m_Name;
168 }
168 }
169
169
170 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
170 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
171 {
171 {
172 // Closes zones in the tab
172 // Closes zones in the tab
173 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
173 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
174
174
175 QWidget::closeEvent(event);
175 QWidget::closeEvent(event);
176 }
176 }
177
177
178 QLayout &VisualizationTabWidget::tabLayout() const noexcept
178 QLayout &VisualizationTabWidget::tabLayout() const noexcept
179 {
179 {
180 return *ui->dragDropContainer->layout();
180 return *ui->dragDropContainer->layout();
181 }
181 }
182
182
183 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
183 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
184 {
184 {
185 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
185 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
186 impl->dropGraph(index, this);
186 impl->dropGraph(index, this);
187 }
187 }
188 else if (mimeData->hasFormat(MIME_TYPE_ZONE)) {
188 else if (mimeData->hasFormat(MIME_TYPE_ZONE)) {
189 impl->dropZone(index, this);
189 impl->dropZone(index, this);
190 }
190 }
191 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
191 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
192 auto variables = sqpApp->variableController().variablesForMimeData(
192 auto variables = sqpApp->variableController().variablesForMimeData(
193 mimeData->data(MIME_TYPE_VARIABLE_LIST));
193 mimeData->data(MIME_TYPE_VARIABLE_LIST));
194 impl->dropVariables(variables, index, this);
194 impl->dropVariables(variables, index, this);
195 }
195 }
196 else {
196 else {
197 qCWarning(LOG_VisualizationZoneWidget())
197 qCWarning(LOG_VisualizationZoneWidget())
198 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
198 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
199 }
199 }
200 }
200 }
201
201
202 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph(
202 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph(
203 int index, VisualizationTabWidget *tabWidget)
203 int index, VisualizationTabWidget *tabWidget)
204 {
204 {
205 auto &helper = sqpApp->dragDropHelper();
205 auto &helper = sqpApp->dragDropHelper();
206
206
207 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
207 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
208 if (!graphWidget) {
208 if (!graphWidget) {
209 qCWarning(LOG_VisualizationZoneWidget())
209 qCWarning(LOG_VisualizationZoneWidget())
210 << tr("VisualizationTabWidget::dropGraph, drop aborted, the dropped graph is not "
210 << tr("VisualizationTabWidget::dropGraph, drop aborted, the dropped graph is not "
211 "found or invalid.");
211 "found or invalid.");
212 Q_ASSERT(false);
212 Q_ASSERT(false);
213 return;
213 return;
214 }
214 }
215
215
216 auto parentDragDropContainer
216 auto parentDragDropContainer
217 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
217 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
218 if (!parentDragDropContainer) {
218 if (!parentDragDropContainer) {
219 qCWarning(LOG_VisualizationZoneWidget())
219 qCWarning(LOG_VisualizationZoneWidget())
220 << tr("VisualizationTabWidget::dropGraph, drop aborted, the parent container of "
220 << tr("VisualizationTabWidget::dropGraph, drop aborted, the parent container of "
221 "the dropped graph is not found.");
221 "the dropped graph is not found.");
222 Q_ASSERT(false);
222 Q_ASSERT(false);
223 return;
223 return;
224 }
224 }
225
225
226 auto nbGraph = parentDragDropContainer->countDragWidget();
226 auto nbGraph = parentDragDropContainer->countDragWidget();
227
227
228 const auto &variables = graphWidget->variables();
228 const auto &variables = graphWidget->variables();
229
229
230 if (!variables.isEmpty()) {
230 if (!variables.isEmpty()) {
231 // Abort the requests for the variables (if any)
231 // Abort the requests for the variables (if any)
232 // Commented, because it's not sure if it's needed or not
232 // Commented, because it's not sure if it's needed or not
233 // for (const auto& var : variables)
233 // for (const auto& var : variables)
234 //{
234 //{
235 // sqpApp->variableController().onAbortProgressRequested(var);
235 // sqpApp->variableController().onAbortProgressRequested(var);
236 //}
236 //}
237
237
238 if (nbGraph == 1) {
238 if (nbGraph == 1) {
239 // This is the only graph in the previous zone, close the zone
239 // This is the only graph in the previous zone, close the zone
240 graphWidget->parentZoneWidget()->close();
240 graphWidget->parentZoneWidget()->close();
241 }
241 }
242 else {
242 else {
243 // Close the graph
243 // Close the graph
244 graphWidget->close();
244 graphWidget->close();
245 }
245 }
246
246
247 tabWidget->createZone(variables, index);
247 tabWidget->createZone(variables, index);
248 }
248 }
249 else {
249 else {
250 // The graph is empty, create an empty zone and move the graph inside
250 // The graph is empty, create an empty zone and move the graph inside
251
251
252 auto parentZoneWidget = graphWidget->parentZoneWidget();
252 auto parentZoneWidget = graphWidget->parentZoneWidget();
253
253
254 parentDragDropContainer->layout()->removeWidget(graphWidget);
254 parentDragDropContainer->layout()->removeWidget(graphWidget);
255
255
256 auto zoneWidget = tabWidget->createEmptyZone(index);
256 auto zoneWidget = tabWidget->createEmptyZone(index);
257 zoneWidget->addGraph(graphWidget);
257 zoneWidget->addGraph(graphWidget);
258
258
259 // Close the old zone if it was the only graph inside
259 // Close the old zone if it was the only graph inside
260 if (nbGraph == 1) {
260 if (nbGraph == 1) {
261 parentZoneWidget->close();
261 parentZoneWidget->close();
262 }
262 }
263 }
263 }
264 }
264 }
265
265
266 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropZone(
266 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropZone(
267 int index, VisualizationTabWidget *tabWidget)
267 int index, VisualizationTabWidget *tabWidget)
268 {
268 {
269 auto &helper = sqpApp->dragDropHelper();
269 auto &helper = sqpApp->dragDropHelper();
270
270
271 auto zoneWidget = qobject_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget());
271 auto zoneWidget = qobject_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget());
272 if (!zoneWidget) {
272 if (!zoneWidget) {
273 qCWarning(LOG_VisualizationZoneWidget())
273 qCWarning(LOG_VisualizationZoneWidget())
274 << tr("VisualizationTabWidget::dropZone, drop aborted, the dropped zone is not "
274 << tr("VisualizationTabWidget::dropZone, drop aborted, the dropped zone is not "
275 "found or invalid.");
275 "found or invalid.");
276 Q_ASSERT(false);
276 Q_ASSERT(false);
277 return;
277 return;
278 }
278 }
279
279
280 auto parentDragDropContainer
280 auto parentDragDropContainer
281 = qobject_cast<VisualizationDragDropContainer *>(zoneWidget->parentWidget());
281 = qobject_cast<VisualizationDragDropContainer *>(zoneWidget->parentWidget());
282 if (!parentDragDropContainer) {
282 if (!parentDragDropContainer) {
283 qCWarning(LOG_VisualizationZoneWidget())
283 qCWarning(LOG_VisualizationZoneWidget())
284 << tr("VisualizationTabWidget::dropZone, drop aborted, the parent container of "
284 << tr("VisualizationTabWidget::dropZone, drop aborted, the parent container of "
285 "the dropped zone is not found.");
285 "the dropped zone is not found.");
286 Q_ASSERT(false);
286 Q_ASSERT(false);
287 return;
287 return;
288 }
288 }
289
289
290 // Simple move of the zone, no variable operation associated
290 // Simple move of the zone, no variable operation associated
291 parentDragDropContainer->layout()->removeWidget(zoneWidget);
291 parentDragDropContainer->layout()->removeWidget(zoneWidget);
292 tabWidget->ui->dragDropContainer->insertDragWidget(index, zoneWidget);
292 tabWidget->ui->dragDropContainer->insertDragWidget(index, zoneWidget);
293 }
293 }
294
294
295 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables(
295 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables(
296 const QList<std::shared_ptr<Variable> > &variables, int index,
296 const QList<std::shared_ptr<Variable> > &variables, int index,
297 VisualizationTabWidget *tabWidget)
297 VisualizationTabWidget *tabWidget)
298 {
298 {
299 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
299 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
300 // compatible variable here
300 // compatible variable here
301 if (variables.count() > 1) {
301 if (variables.count() > 1) {
302 qCWarning(LOG_VisualizationZoneWidget())
302 qCWarning(LOG_VisualizationZoneWidget())
303 << tr("VisualizationTabWidget::dropVariables, dropping multiple variables, operation "
303 << tr("VisualizationTabWidget::dropVariables, dropping multiple variables, operation "
304 "aborted.");
304 "aborted.");
305 return;
305 return;
306 }
306 }
307
307
308 tabWidget->createZone(variables, index);
308 tabWidget->createZone(variables, index);
309 }
309 }
@@ -1,516 +1,516
1 #include "Visualization/VisualizationZoneWidget.h"
1 #include "Visualization/VisualizationZoneWidget.h"
2
2
3 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/IVisualizationWidgetVisitor.h"
4 #include "Visualization/QCustomPlotSynchronizer.h"
4 #include "Visualization/QCustomPlotSynchronizer.h"
5 #include "Visualization/VisualizationGraphWidget.h"
5 #include "Visualization/VisualizationGraphWidget.h"
6 #include "Visualization/VisualizationWidget.h"
6 #include "Visualization/VisualizationWidget.h"
7 #include "ui_VisualizationZoneWidget.h"
7 #include "ui_VisualizationZoneWidget.h"
8
8
9 #include "Common/MimeTypesDef.h"
9 #include "Common/MimeTypesDef.h"
10 #include "Common/VisualizationDef.h"
10 #include "Common/VisualizationDef.h"
11
11
12 #include <Data/SqpRange.h>
12 #include <Data/SqpRange.h>
13 #include <Time/TimeController.h>
13 #include <Time/TimeController.h>
14 #include <Variable/Variable.h>
14 #include <Variable/Variable.h>
15 #include <Variable/VariableController.h>
15 #include <Variable/VariableController.h>
16
16
17 #include <Visualization/operations/FindVariableOperation.h>
17 #include <Visualization/operations/FindVariableOperation.h>
18
18
19 #include <DragDropHelper.h>
19 #include <DragAndDrop/DragDropHelper.h>
20 #include <QUuid>
20 #include <QUuid>
21 #include <SqpApplication.h>
21 #include <SqpApplication.h>
22 #include <cmath>
22 #include <cmath>
23
23
24 #include <QLayout>
24 #include <QLayout>
25
25
26 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
26 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
27
27
28 namespace {
28 namespace {
29
29
30
30
31 /// Generates a default name for a new graph, according to the number of graphs already displayed in
31 /// Generates a default name for a new graph, according to the number of graphs already displayed in
32 /// the zone
32 /// the zone
33 QString defaultGraphName(const QLayout &layout)
33 QString defaultGraphName(const QLayout &layout)
34 {
34 {
35 auto count = 0;
35 auto count = 0;
36 for (auto i = 0; i < layout.count(); ++i) {
36 for (auto i = 0; i < layout.count(); ++i) {
37 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
37 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
38 count++;
38 count++;
39 }
39 }
40 }
40 }
41
41
42 return QObject::tr("Graph %1").arg(count + 1);
42 return QObject::tr("Graph %1").arg(count + 1);
43 }
43 }
44
44
45 /**
45 /**
46 * Applies a function to all graphs of the zone represented by its layout
46 * Applies a function to all graphs of the zone represented by its layout
47 * @param layout the layout that contains graphs
47 * @param layout the layout that contains graphs
48 * @param fun the function to apply to each graph
48 * @param fun the function to apply to each graph
49 */
49 */
50 template <typename Fun>
50 template <typename Fun>
51 void processGraphs(QLayout &layout, Fun fun)
51 void processGraphs(QLayout &layout, Fun fun)
52 {
52 {
53 for (auto i = 0; i < layout.count(); ++i) {
53 for (auto i = 0; i < layout.count(); ++i) {
54 if (auto item = layout.itemAt(i)) {
54 if (auto item = layout.itemAt(i)) {
55 if (auto visualizationGraphWidget
55 if (auto visualizationGraphWidget
56 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
56 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
57 fun(*visualizationGraphWidget);
57 fun(*visualizationGraphWidget);
58 }
58 }
59 }
59 }
60 }
60 }
61 }
61 }
62
62
63 } // namespace
63 } // namespace
64
64
65 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
65 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
66
66
67 explicit VisualizationZoneWidgetPrivate()
67 explicit VisualizationZoneWidgetPrivate()
68 : m_SynchronisationGroupId{QUuid::createUuid()},
68 : m_SynchronisationGroupId{QUuid::createUuid()},
69 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
69 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
70 {
70 {
71 }
71 }
72 QUuid m_SynchronisationGroupId;
72 QUuid m_SynchronisationGroupId;
73 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
73 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
74
74
75 // Returns the first graph in the zone or nullptr if there is no graph inside
75 // Returns the first graph in the zone or nullptr if there is no graph inside
76 VisualizationGraphWidget *firstGraph(const VisualizationZoneWidget *zoneWidget) const
76 VisualizationGraphWidget *firstGraph(const VisualizationZoneWidget *zoneWidget) const
77 {
77 {
78 VisualizationGraphWidget *firstGraph = nullptr;
78 VisualizationGraphWidget *firstGraph = nullptr;
79 auto layout = zoneWidget->ui->dragDropContainer->layout();
79 auto layout = zoneWidget->ui->dragDropContainer->layout();
80 if (layout->count() > 0) {
80 if (layout->count() > 0) {
81 if (auto visualizationGraphWidget
81 if (auto visualizationGraphWidget
82 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
82 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
83 firstGraph = visualizationGraphWidget;
83 firstGraph = visualizationGraphWidget;
84 }
84 }
85 }
85 }
86
86
87 return firstGraph;
87 return firstGraph;
88 }
88 }
89
89
90 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
90 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
91 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
91 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
92 VisualizationZoneWidget *zoneWidget);
92 VisualizationZoneWidget *zoneWidget);
93 };
93 };
94
94
95 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
95 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
96 : VisualizationDragWidget{parent},
96 : VisualizationDragWidget{parent},
97 ui{new Ui::VisualizationZoneWidget},
97 ui{new Ui::VisualizationZoneWidget},
98 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
98 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
99 {
99 {
100 ui->setupUi(this);
100 ui->setupUi(this);
101
101
102 ui->zoneNameLabel->setText(name);
102 ui->zoneNameLabel->setText(name);
103
103
104 ui->dragDropContainer->setPlaceHolderType(DragDropHelper::PlaceHolderType::Graph);
104 ui->dragDropContainer->setPlaceHolderType(DragDropHelper::PlaceHolderType::Graph);
105 ui->dragDropContainer->addAcceptedMimeType(
105 ui->dragDropContainer->addAcceptedMimeType(
106 MIME_TYPE_GRAPH, VisualizationDragDropContainer::DropBehavior::Inserted);
106 MIME_TYPE_GRAPH, VisualizationDragDropContainer::DropBehavior::Inserted);
107 ui->dragDropContainer->addAcceptedMimeType(
107 ui->dragDropContainer->addAcceptedMimeType(
108 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
108 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
109 ui->dragDropContainer->addAcceptedMimeType(
109 ui->dragDropContainer->addAcceptedMimeType(
110 MIME_TYPE_TIME_RANGE, VisualizationDragDropContainer::DropBehavior::Merged);
110 MIME_TYPE_TIME_RANGE, VisualizationDragDropContainer::DropBehavior::Merged);
111 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
111 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
112 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
112 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
113 ui->dragDropContainer);
113 ui->dragDropContainer);
114 });
114 });
115
115
116 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
116 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
117 &VisualizationZoneWidget::dropMimeData);
117 &VisualizationZoneWidget::dropMimeData);
118 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
118 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
119 &VisualizationZoneWidget::dropMimeDataOnGraph);
119 &VisualizationZoneWidget::dropMimeDataOnGraph);
120
120
121 // 'Close' options : widget is deleted when closed
121 // 'Close' options : widget is deleted when closed
122 setAttribute(Qt::WA_DeleteOnClose);
122 setAttribute(Qt::WA_DeleteOnClose);
123 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
123 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
124 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
124 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
125
125
126 // Synchronisation id
126 // Synchronisation id
127 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
127 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
128 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
128 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
129 }
129 }
130
130
131 VisualizationZoneWidget::~VisualizationZoneWidget()
131 VisualizationZoneWidget::~VisualizationZoneWidget()
132 {
132 {
133 delete ui;
133 delete ui;
134 }
134 }
135
135
136 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
136 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
137 {
137 {
138 // Synchronize new graph with others in the zone
138 // Synchronize new graph with others in the zone
139 impl->m_Synchronizer->addGraph(*graphWidget);
139 impl->m_Synchronizer->addGraph(*graphWidget);
140
140
141 ui->dragDropContainer->addDragWidget(graphWidget);
141 ui->dragDropContainer->addDragWidget(graphWidget);
142 }
142 }
143
143
144 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
144 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
145 {
145 {
146 // Synchronize new graph with others in the zone
146 // Synchronize new graph with others in the zone
147 impl->m_Synchronizer->addGraph(*graphWidget);
147 impl->m_Synchronizer->addGraph(*graphWidget);
148
148
149 ui->dragDropContainer->insertDragWidget(index, graphWidget);
149 ui->dragDropContainer->insertDragWidget(index, graphWidget);
150 }
150 }
151
151
152 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
152 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
153 {
153 {
154 return createGraph(variable, -1);
154 return createGraph(variable, -1);
155 }
155 }
156
156
157 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
157 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
158 int index)
158 int index)
159 {
159 {
160 auto graphWidget
160 auto graphWidget
161 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
161 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
162
162
163
163
164 // Set graph properties
164 // Set graph properties
165 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
165 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
166 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
166 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
167
167
168
168
169 // Lambda to synchronize zone widget
169 // Lambda to synchronize zone widget
170 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
170 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
171 const SqpRange &oldGraphRange) {
171 const SqpRange &oldGraphRange) {
172
172
173 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
173 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
174 auto frameLayout = ui->dragDropContainer->layout();
174 auto frameLayout = ui->dragDropContainer->layout();
175 for (auto i = 0; i < frameLayout->count(); ++i) {
175 for (auto i = 0; i < frameLayout->count(); ++i) {
176 auto graphChild
176 auto graphChild
177 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
177 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
178 if (graphChild && (graphChild != graphWidget)) {
178 if (graphChild && (graphChild != graphWidget)) {
179
179
180 auto graphChildRange = graphChild->graphRange();
180 auto graphChildRange = graphChild->graphRange();
181 switch (zoomType) {
181 switch (zoomType) {
182 case AcquisitionZoomType::ZoomIn: {
182 case AcquisitionZoomType::ZoomIn: {
183 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
183 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
184 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
184 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
185 graphChildRange.m_TStart += deltaLeft;
185 graphChildRange.m_TStart += deltaLeft;
186 graphChildRange.m_TEnd -= deltaRight;
186 graphChildRange.m_TEnd -= deltaRight;
187 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
187 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
188 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
188 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
189 << deltaLeft;
189 << deltaLeft;
190 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
190 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
191 << deltaRight;
191 << deltaRight;
192 qCDebug(LOG_VisualizationZoneWidget())
192 qCDebug(LOG_VisualizationZoneWidget())
193 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
193 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
194
194
195 break;
195 break;
196 }
196 }
197
197
198 case AcquisitionZoomType::ZoomOut: {
198 case AcquisitionZoomType::ZoomOut: {
199 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
199 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
200 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
200 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
201 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
201 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
202 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
202 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
203 << deltaLeft;
203 << deltaLeft;
204 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
204 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
205 << deltaRight;
205 << deltaRight;
206 qCDebug(LOG_VisualizationZoneWidget())
206 qCDebug(LOG_VisualizationZoneWidget())
207 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
207 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
208 graphChildRange.m_TStart -= deltaLeft;
208 graphChildRange.m_TStart -= deltaLeft;
209 graphChildRange.m_TEnd += deltaRight;
209 graphChildRange.m_TEnd += deltaRight;
210 break;
210 break;
211 }
211 }
212 case AcquisitionZoomType::PanRight: {
212 case AcquisitionZoomType::PanRight: {
213 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
213 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
214 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
214 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
215 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
215 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
216 graphChildRange.m_TStart += deltaLeft;
216 graphChildRange.m_TStart += deltaLeft;
217 graphChildRange.m_TEnd += deltaRight;
217 graphChildRange.m_TEnd += deltaRight;
218 qCDebug(LOG_VisualizationZoneWidget())
218 qCDebug(LOG_VisualizationZoneWidget())
219 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
219 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
220 break;
220 break;
221 }
221 }
222 case AcquisitionZoomType::PanLeft: {
222 case AcquisitionZoomType::PanLeft: {
223 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
223 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
224 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
224 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
225 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
225 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
226 graphChildRange.m_TStart -= deltaLeft;
226 graphChildRange.m_TStart -= deltaLeft;
227 graphChildRange.m_TEnd -= deltaRight;
227 graphChildRange.m_TEnd -= deltaRight;
228 break;
228 break;
229 }
229 }
230 case AcquisitionZoomType::Unknown: {
230 case AcquisitionZoomType::Unknown: {
231 qCDebug(LOG_VisualizationZoneWidget())
231 qCDebug(LOG_VisualizationZoneWidget())
232 << tr("Impossible to synchronize: zoom type unknown");
232 << tr("Impossible to synchronize: zoom type unknown");
233 break;
233 break;
234 }
234 }
235 default:
235 default:
236 qCCritical(LOG_VisualizationZoneWidget())
236 qCCritical(LOG_VisualizationZoneWidget())
237 << tr("Impossible to synchronize: zoom type not take into account");
237 << tr("Impossible to synchronize: zoom type not take into account");
238 // No action
238 // No action
239 break;
239 break;
240 }
240 }
241 graphChild->enableAcquisition(false);
241 graphChild->enableAcquisition(false);
242 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
242 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
243 << graphChild->graphRange();
243 << graphChild->graphRange();
244 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
244 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
245 << graphChildRange;
245 << graphChildRange;
246 qCDebug(LOG_VisualizationZoneWidget())
246 qCDebug(LOG_VisualizationZoneWidget())
247 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
247 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
248 graphChild->setGraphRange(graphChildRange);
248 graphChild->setGraphRange(graphChildRange);
249 graphChild->enableAcquisition(true);
249 graphChild->enableAcquisition(true);
250 }
250 }
251 }
251 }
252 };
252 };
253
253
254 // connection for synchronization
254 // connection for synchronization
255 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
255 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
256 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
256 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
257 &VisualizationZoneWidget::onVariableAdded);
257 &VisualizationZoneWidget::onVariableAdded);
258 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
258 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
259 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
259 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
260
260
261 auto range = SqpRange{};
261 auto range = SqpRange{};
262 if (auto firstGraph = impl->firstGraph(this)) {
262 if (auto firstGraph = impl->firstGraph(this)) {
263 // Case of a new graph in a existant zone
263 // Case of a new graph in a existant zone
264 range = firstGraph->graphRange();
264 range = firstGraph->graphRange();
265 }
265 }
266 else {
266 else {
267 // Case of a new graph as the first of the zone
267 // Case of a new graph as the first of the zone
268 range = variable->range();
268 range = variable->range();
269 }
269 }
270
270
271 this->insertGraph(index, graphWidget);
271 this->insertGraph(index, graphWidget);
272
272
273 graphWidget->addVariable(variable, range);
273 graphWidget->addVariable(variable, range);
274
274
275 // get y using variable range
275 // get y using variable range
276 if (auto dataSeries = variable->dataSeries()) {
276 if (auto dataSeries = variable->dataSeries()) {
277 dataSeries->lockRead();
277 dataSeries->lockRead();
278 auto valuesBounds
278 auto valuesBounds
279 = dataSeries->valuesBounds(variable->range().m_TStart, variable->range().m_TEnd);
279 = dataSeries->valuesBounds(variable->range().m_TStart, variable->range().m_TEnd);
280 auto end = dataSeries->cend();
280 auto end = dataSeries->cend();
281 if (valuesBounds.first != end && valuesBounds.second != end) {
281 if (valuesBounds.first != end && valuesBounds.second != end) {
282 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
282 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
283
283
284 auto minValue = rangeValue(valuesBounds.first->minValue());
284 auto minValue = rangeValue(valuesBounds.first->minValue());
285 auto maxValue = rangeValue(valuesBounds.second->maxValue());
285 auto maxValue = rangeValue(valuesBounds.second->maxValue());
286
286
287 graphWidget->setYRange(SqpRange{minValue, maxValue});
287 graphWidget->setYRange(SqpRange{minValue, maxValue});
288 }
288 }
289 dataSeries->unlock();
289 dataSeries->unlock();
290 }
290 }
291
291
292 return graphWidget;
292 return graphWidget;
293 }
293 }
294
294
295 VisualizationGraphWidget *
295 VisualizationGraphWidget *
296 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
296 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
297 {
297 {
298 if (variables.isEmpty()) {
298 if (variables.isEmpty()) {
299 return nullptr;
299 return nullptr;
300 }
300 }
301
301
302 auto graphWidget = createGraph(variables.first(), index);
302 auto graphWidget = createGraph(variables.first(), index);
303 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
303 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
304 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
304 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
305 }
305 }
306
306
307 return graphWidget;
307 return graphWidget;
308 }
308 }
309
309
310 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
310 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
311 {
311 {
312 if (visitor) {
312 if (visitor) {
313 visitor->visitEnter(this);
313 visitor->visitEnter(this);
314
314
315 // Apply visitor to graph children: widgets different from graphs are not visited (no
315 // Apply visitor to graph children: widgets different from graphs are not visited (no
316 // action)
316 // action)
317 processGraphs(
317 processGraphs(
318 *ui->dragDropContainer->layout(),
318 *ui->dragDropContainer->layout(),
319 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
319 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
320
320
321 visitor->visitLeave(this);
321 visitor->visitLeave(this);
322 }
322 }
323 else {
323 else {
324 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
324 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
325 }
325 }
326 }
326 }
327
327
328 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
328 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
329 {
329 {
330 // A tab can always accomodate a variable
330 // A tab can always accomodate a variable
331 Q_UNUSED(variable);
331 Q_UNUSED(variable);
332 return true;
332 return true;
333 }
333 }
334
334
335 bool VisualizationZoneWidget::contains(const Variable &variable) const
335 bool VisualizationZoneWidget::contains(const Variable &variable) const
336 {
336 {
337 Q_UNUSED(variable);
337 Q_UNUSED(variable);
338 return false;
338 return false;
339 }
339 }
340
340
341 QString VisualizationZoneWidget::name() const
341 QString VisualizationZoneWidget::name() const
342 {
342 {
343 return ui->zoneNameLabel->text();
343 return ui->zoneNameLabel->text();
344 }
344 }
345
345
346 QMimeData *VisualizationZoneWidget::mimeData() const
346 QMimeData *VisualizationZoneWidget::mimeData() const
347 {
347 {
348 auto mimeData = new QMimeData;
348 auto mimeData = new QMimeData;
349 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
349 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
350
350
351 return mimeData;
351 return mimeData;
352 }
352 }
353
353
354 bool VisualizationZoneWidget::isDragAllowed() const
354 bool VisualizationZoneWidget::isDragAllowed() const
355 {
355 {
356 return true;
356 return true;
357 }
357 }
358
358
359 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
359 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
360 {
360 {
361 // Closes graphs in the zone
361 // Closes graphs in the zone
362 processGraphs(*ui->dragDropContainer->layout(),
362 processGraphs(*ui->dragDropContainer->layout(),
363 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
363 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
364
364
365 // Delete synchronization group from variable controller
365 // Delete synchronization group from variable controller
366 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
366 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
367 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
367 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
368
368
369 QWidget::closeEvent(event);
369 QWidget::closeEvent(event);
370 }
370 }
371
371
372 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
372 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
373 {
373 {
374 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
374 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
375 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
375 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
376 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
376 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
377 }
377 }
378
378
379 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
379 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
380 {
380 {
381 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
381 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
382 Q_ARG(std::shared_ptr<Variable>, variable),
382 Q_ARG(std::shared_ptr<Variable>, variable),
383 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
383 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
384 }
384 }
385
385
386 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
386 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
387 {
387 {
388 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
388 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
389 impl->dropGraph(index, this);
389 impl->dropGraph(index, this);
390 }
390 }
391 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
391 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
392 auto variables = sqpApp->variableController().variablesForMimeData(
392 auto variables = sqpApp->variableController().variablesForMimeData(
393 mimeData->data(MIME_TYPE_VARIABLE_LIST));
393 mimeData->data(MIME_TYPE_VARIABLE_LIST));
394 impl->dropVariables(variables, index, this);
394 impl->dropVariables(variables, index, this);
395 }
395 }
396 else {
396 else {
397 qCWarning(LOG_VisualizationZoneWidget())
397 qCWarning(LOG_VisualizationZoneWidget())
398 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
398 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
399 }
399 }
400 }
400 }
401
401
402 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
402 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
403 const QMimeData *mimeData)
403 const QMimeData *mimeData)
404 {
404 {
405 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
405 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
406 if (!graphWidget) {
406 if (!graphWidget) {
407 qCWarning(LOG_VisualizationZoneWidget())
407 qCWarning(LOG_VisualizationZoneWidget())
408 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
408 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
409 "drop aborted");
409 "drop aborted");
410 Q_ASSERT(false);
410 Q_ASSERT(false);
411 return;
411 return;
412 }
412 }
413
413
414 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
414 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
415 auto variables = sqpApp->variableController().variablesForMimeData(
415 auto variables = sqpApp->variableController().variablesForMimeData(
416 mimeData->data(MIME_TYPE_VARIABLE_LIST));
416 mimeData->data(MIME_TYPE_VARIABLE_LIST));
417 for (const auto &var : variables) {
417 for (const auto &var : variables) {
418 graphWidget->addVariable(var, graphWidget->graphRange());
418 graphWidget->addVariable(var, graphWidget->graphRange());
419 }
419 }
420 }
420 }
421 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
421 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
422 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
422 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
423 graphWidget->setGraphRange(range);
423 graphWidget->setGraphRange(range);
424 }
424 }
425 else {
425 else {
426 qCWarning(LOG_VisualizationZoneWidget())
426 qCWarning(LOG_VisualizationZoneWidget())
427 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
427 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
428 }
428 }
429 }
429 }
430
430
431 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
431 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
432 int index, VisualizationZoneWidget *zoneWidget)
432 int index, VisualizationZoneWidget *zoneWidget)
433 {
433 {
434 auto &helper = sqpApp->dragDropHelper();
434 auto &helper = sqpApp->dragDropHelper();
435
435
436 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
436 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
437 if (!graphWidget) {
437 if (!graphWidget) {
438 qCWarning(LOG_VisualizationZoneWidget())
438 qCWarning(LOG_VisualizationZoneWidget())
439 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
439 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
440 "found or invalid.");
440 "found or invalid.");
441 Q_ASSERT(false);
441 Q_ASSERT(false);
442 return;
442 return;
443 }
443 }
444
444
445 auto parentDragDropContainer
445 auto parentDragDropContainer
446 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
446 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
447 if (!parentDragDropContainer) {
447 if (!parentDragDropContainer) {
448 qCWarning(LOG_VisualizationZoneWidget())
448 qCWarning(LOG_VisualizationZoneWidget())
449 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
449 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
450 "the dropped graph is not found.");
450 "the dropped graph is not found.");
451 Q_ASSERT(false);
451 Q_ASSERT(false);
452 return;
452 return;
453 }
453 }
454
454
455 const auto &variables = graphWidget->variables();
455 const auto &variables = graphWidget->variables();
456
456
457 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
457 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
458 // The drop didn't occur in the same zone
458 // The drop didn't occur in the same zone
459
459
460 // Abort the requests for the variables (if any)
460 // Abort the requests for the variables (if any)
461 // Commented, because it's not sure if it's needed or not
461 // Commented, because it's not sure if it's needed or not
462 // for (const auto& var : variables)
462 // for (const auto& var : variables)
463 //{
463 //{
464 // sqpApp->variableController().onAbortProgressRequested(var);
464 // sqpApp->variableController().onAbortProgressRequested(var);
465 //}
465 //}
466
466
467 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
467 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
468 auto nbGraph = parentDragDropContainer->countDragWidget();
468 auto nbGraph = parentDragDropContainer->countDragWidget();
469 if (nbGraph == 1) {
469 if (nbGraph == 1) {
470 // This is the only graph in the previous zone, close the zone
470 // This is the only graph in the previous zone, close the zone
471 previousParentZoneWidget->close();
471 previousParentZoneWidget->close();
472 }
472 }
473 else {
473 else {
474 // Close the graph
474 // Close the graph
475 graphWidget->close();
475 graphWidget->close();
476 }
476 }
477
477
478 // Creates the new graph in the zone
478 // Creates the new graph in the zone
479 zoneWidget->createGraph(variables, index);
479 zoneWidget->createGraph(variables, index);
480 }
480 }
481 else {
481 else {
482 // The drop occurred in the same zone or the graph is empty
482 // The drop occurred in the same zone or the graph is empty
483 // Simple move of the graph, no variable operation associated
483 // Simple move of the graph, no variable operation associated
484 parentDragDropContainer->layout()->removeWidget(graphWidget);
484 parentDragDropContainer->layout()->removeWidget(graphWidget);
485
485
486 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
486 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
487 // The graph is empty and dropped in a different zone.
487 // The graph is empty and dropped in a different zone.
488 // Take the range of the first graph in the zone (if existing).
488 // Take the range of the first graph in the zone (if existing).
489 auto layout = zoneWidget->ui->dragDropContainer->layout();
489 auto layout = zoneWidget->ui->dragDropContainer->layout();
490 if (layout->count() > 0) {
490 if (layout->count() > 0) {
491 if (auto visualizationGraphWidget
491 if (auto visualizationGraphWidget
492 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
492 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
493 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
493 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
494 }
494 }
495 }
495 }
496 }
496 }
497
497
498 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
498 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
499 }
499 }
500 }
500 }
501
501
502 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
502 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
503 const QList<std::shared_ptr<Variable> > &variables, int index,
503 const QList<std::shared_ptr<Variable> > &variables, int index,
504 VisualizationZoneWidget *zoneWidget)
504 VisualizationZoneWidget *zoneWidget)
505 {
505 {
506 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
506 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
507 // compatible variable here
507 // compatible variable here
508 if (variables.count() > 1) {
508 if (variables.count() > 1) {
509 qCWarning(LOG_VisualizationZoneWidget())
509 qCWarning(LOG_VisualizationZoneWidget())
510 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
510 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
511 "aborted.");
511 "aborted.");
512 return;
512 return;
513 }
513 }
514
514
515 zoneWidget->createGraph(variables, index);
515 zoneWidget->createGraph(variables, index);
516 }
516 }
General Comments 3
Under Review
author

Pull request updated. Auto status change to "Under Review"

Changed commits:
  * 1 added
  * 0 removed

Changed files:
  * A core/tests/meson.build
You need to be logged in to leave comments. Login now