##// END OF EJS Templates
Add an empty area at the bottom of the tab where a new zone can be created from a drop. Differentiate graph and zone placeHolders.
trabillard -
r887:f5851ce3ff09
parent child
Show More
@@ -1,88 +1,91
1 #ifndef SCIQLOP_DRAGDROPHELPER_H
1 #ifndef SCIQLOP_DRAGDROPHELPER_H
2 #define SCIQLOP_DRAGDROPHELPER_H
2 #define SCIQLOP_DRAGDROPHELPER_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5 #include <QLoggingCategory>
5 #include <QLoggingCategory>
6 #include <QWidget>
6 #include <QWidget>
7
7
8 class QVBoxLayout;
8 class QVBoxLayout;
9 class QScrollArea;
9 class QScrollArea;
10 class VisualizationDragWidget;
10 class VisualizationDragWidget;
11 class VisualizationDragDropContainer;
11 class VisualizationDragDropContainer;
12 class QMimeData;
12 class QMimeData;
13
13
14 Q_DECLARE_LOGGING_CATEGORY(LOG_DragDropHelper)
14 Q_DECLARE_LOGGING_CATEGORY(LOG_DragDropHelper)
15
15
16 /**
16 /**
17 * @brief Helper class for drag&drop operations.
17 * @brief Helper class for drag&drop operations.
18 * @note The helper is accessible from the sqpApp singleton and has the same life as the whole
18 * @note The helper is accessible from the sqpApp singleton and has the same life as the whole
19 * application (like a controller). But contrary to a controller, it doesn't live in a thread and
19 * application (like a controller). But contrary to a controller, it doesn't live in a thread and
20 * can interect with the gui.
20 * can interect with the gui.
21 * @see SqpApplication
21 * @see SqpApplication
22 */
22 */
23 class DragDropHelper {
23 class DragDropHelper {
24 public:
24 public:
25 static const QString MIME_TYPE_GRAPH;
25 static const QString MIME_TYPE_GRAPH;
26 static const QString MIME_TYPE_ZONE;
26 static const QString MIME_TYPE_ZONE;
27
27
28 enum class PlaceHolderType { Default, Graph, Zone };
29
28 DragDropHelper();
30 DragDropHelper();
29 virtual ~DragDropHelper();
31 virtual ~DragDropHelper();
30
32
31 /// Resets some internal variables. Must be called before any new drag&drop operation.
33 /// Resets some internal variables. Must be called before any new drag&drop operation.
32 void resetDragAndDrop();
34 void resetDragAndDrop();
33
35
34 /// Sets the visualization widget currently being drag on the visualization.
36 /// Sets the visualization widget currently being drag on the visualization.
35 void setCurrentDragWidget(VisualizationDragWidget *dragWidget);
37 void setCurrentDragWidget(VisualizationDragWidget *dragWidget);
36
38
37 /// Returns the visualization widget currently being drag on the visualization.
39 /// Returns the visualization widget currently being drag on the visualization.
38 /// Can be null if a new visualization widget is intended to be created by the drag&drop
40 /// Can be null if a new visualization widget is intended to be created by the drag&drop
39 /// operation.
41 /// operation.
40 VisualizationDragWidget *getCurrentDragWidget() const;
42 VisualizationDragWidget *getCurrentDragWidget() const;
41
43
42 QWidget &placeHolder() const;
44 QWidget &placeHolder() const;
43 void insertPlaceHolder(QVBoxLayout *layout, int index);
45 void insertPlaceHolder(QVBoxLayout *layout, int index, PlaceHolderType type,
46 const QString &topLabelText);
44 void removePlaceHolder();
47 void removePlaceHolder();
45 bool isPlaceHolderSet() const;
48 bool isPlaceHolderSet() const;
46
49
47 /// Checks if the specified mime data is valid for a drop in the visualization
50 /// Checks if the specified mime data is valid for a drop in the visualization
48 bool checkMimeDataForVisualization(const QMimeData *mimeData,
51 bool checkMimeDataForVisualization(const QMimeData *mimeData,
49 VisualizationDragDropContainer *dropContainer);
52 VisualizationDragDropContainer *dropContainer);
50
53
51 void addDragDropScrollArea(QScrollArea *scrollArea);
54 void addDragDropScrollArea(QScrollArea *scrollArea);
52 void removeDragDropScrollArea(QScrollArea *scrollArea);
55 void removeDragDropScrollArea(QScrollArea *scrollArea);
53
56
54 QUrl imageTemporaryUrl(const QImage &image) const;
57 QUrl imageTemporaryUrl(const QImage &image) const;
55
58
56 void setHightlightedDragWidget(VisualizationDragWidget *dragWidget);
59 void setHightlightedDragWidget(VisualizationDragWidget *dragWidget);
57 VisualizationDragWidget *getHightlightedDragWidget() const;
60 VisualizationDragWidget *getHightlightedDragWidget() const;
58
61
59 private:
62 private:
60 class DragDropHelperPrivate;
63 class DragDropHelperPrivate;
61 spimpl::unique_impl_ptr<DragDropHelperPrivate> impl;
64 spimpl::unique_impl_ptr<DragDropHelperPrivate> impl;
62 };
65 };
63
66
64 /**
67 /**
65 * @brief Event filter class which manage the scroll of QScrollArea during a drag&drop operation.
68 * @brief Event filter class which manage the scroll of QScrollArea during a drag&drop operation.
66 * @note A QScrollArea inside an other QScrollArea is not fully supported.
69 * @note A QScrollArea inside an other QScrollArea is not fully supported.
67 */
70 */
68 class DragDropScroller : public QObject {
71 class DragDropScroller : public QObject {
69 Q_OBJECT
72 Q_OBJECT
70
73
71 public:
74 public:
72 DragDropScroller(QObject *parent = nullptr);
75 DragDropScroller(QObject *parent = nullptr);
73
76
74 void addScrollArea(QScrollArea *scrollArea);
77 void addScrollArea(QScrollArea *scrollArea);
75 void removeScrollArea(QScrollArea *scrollArea);
78 void removeScrollArea(QScrollArea *scrollArea);
76
79
77 protected:
80 protected:
78 bool eventFilter(QObject *obj, QEvent *event);
81 bool eventFilter(QObject *obj, QEvent *event);
79
82
80 private:
83 private:
81 class DragDropScrollerPrivate;
84 class DragDropScrollerPrivate;
82 spimpl::unique_impl_ptr<DragDropScrollerPrivate> impl;
85 spimpl::unique_impl_ptr<DragDropScrollerPrivate> impl;
83
86
84 private slots:
87 private slots:
85 void onTimer();
88 void onTimer();
86 };
89 };
87
90
88 #endif // SCIQLOP_DRAGDROPHELPER_H
91 #endif // SCIQLOP_DRAGDROPHELPER_H
@@ -1,52 +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>
13
12 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer)
14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer)
13
15
14 class VisualizationDragWidget;
16 class VisualizationDragWidget;
15
17
16 class VisualizationDragDropContainer : public QFrame {
18 class VisualizationDragDropContainer : public QFrame {
17 Q_OBJECT
19 Q_OBJECT
18
20
19 signals:
21 signals:
20 void dropOccuredInContainer(int dropIndex, const QMimeData *mimeData);
22 void dropOccuredInContainer(int dropIndex, const QMimeData *mimeData);
21 void dropOccuredOnWidget(VisualizationDragWidget *dragWidget, const QMimeData *mimeData);
23 void dropOccuredOnWidget(VisualizationDragWidget *dragWidget, const QMimeData *mimeData);
22
24
23 public:
25 public:
24 enum class DropBehavior { Inserted, Merged, InsertedAndMerged };
26 enum class DropBehavior { Inserted, Merged, InsertedAndMerged };
25 using AcceptMimeDataFunction = std::function<bool(const QMimeData *mimeData)>;
27 using AcceptMimeDataFunction = std::function<bool(const QMimeData *mimeData)>;
26
28
27 VisualizationDragDropContainer(QWidget *parent = nullptr);
29 VisualizationDragDropContainer(QWidget *parent = nullptr);
28
30
29 void addDragWidget(VisualizationDragWidget *dragWidget);
31 void addDragWidget(VisualizationDragWidget *dragWidget);
30 void insertDragWidget(int index, VisualizationDragWidget *dragWidget);
32 void insertDragWidget(int index, VisualizationDragWidget *dragWidget);
31
33
32 void addAcceptedMimeType(const QString &mimeType, DropBehavior behavior);
34 void addAcceptedMimeType(const QString &mimeType, DropBehavior behavior);
33
35
34 int countDragWidget() const;
36 int countDragWidget() const;
35
37
36 void setAcceptMimeDataFunction(AcceptMimeDataFunction fun);
38 void setAcceptMimeDataFunction(AcceptMimeDataFunction fun);
37
39
40 void setPlaceHolderType(DragDropHelper::PlaceHolderType type,
41 const QString &placeHolderText = QString());
42
38 protected:
43 protected:
39 void dragEnterEvent(QDragEnterEvent *event);
44 void dragEnterEvent(QDragEnterEvent *event);
40 void dragLeaveEvent(QDragLeaveEvent *event);
45 void dragLeaveEvent(QDragLeaveEvent *event);
41 void dragMoveEvent(QDragMoveEvent *event);
46 void dragMoveEvent(QDragMoveEvent *event);
42 void dropEvent(QDropEvent *event);
47 void dropEvent(QDropEvent *event);
43
48
44 private:
49 private:
45 class VisualizationDragDropContainerPrivate;
50 class VisualizationDragDropContainerPrivate;
46 spimpl::unique_impl_ptr<VisualizationDragDropContainerPrivate> impl;
51 spimpl::unique_impl_ptr<VisualizationDragDropContainerPrivate> impl;
47
52
48 private slots:
53 private slots:
49 void startDrag(VisualizationDragWidget *dragWidget, const QPoint &dragPosition);
54 void startDrag(VisualizationDragWidget *dragWidget, const QPoint &dragPosition);
50 };
55 };
51
56
52 #endif // SCIQLOP_VISUALIZATIONDRAGDROPCONTAINER_H
57 #endif // SCIQLOP_VISUALIZATIONDRAGDROPCONTAINER_H
@@ -1,353 +1,383
1 #include "DragDropHelper.h"
1 #include "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 <QScrollArea>
18 #include <QScrollArea>
18 #include <QScrollBar>
19 #include <QScrollBar>
19 #include <QTimer>
20 #include <QTimer>
20 #include <QVBoxLayout>
21 #include <QVBoxLayout>
21
22
22 const int SCROLL_SPEED = 5;
23 const int SCROLL_SPEED = 5;
23 const int SCROLL_ZONE_SIZE = 50;
24 const int SCROLL_ZONE_SIZE = 50;
24
25
25 Q_LOGGING_CATEGORY(LOG_DragDropHelper, "DragDrophelper")
26 Q_LOGGING_CATEGORY(LOG_DragDropHelper, "DragDrophelper")
26
27
27 struct DragDropScroller::DragDropScrollerPrivate {
28 struct DragDropScroller::DragDropScrollerPrivate {
28
29
29 QList<QScrollArea *> m_ScrollAreas;
30 QList<QScrollArea *> m_ScrollAreas;
30 QScrollArea *m_CurrentScrollArea = nullptr;
31 QScrollArea *m_CurrentScrollArea = nullptr;
31 std::unique_ptr<QTimer> m_Timer = nullptr;
32 std::unique_ptr<QTimer> m_Timer = nullptr;
32
33
33 enum class ScrollDirection { up, down, unknown };
34 enum class ScrollDirection { up, down, unknown };
34 ScrollDirection m_Direction = ScrollDirection::unknown;
35 ScrollDirection m_Direction = ScrollDirection::unknown;
35
36
36 explicit DragDropScrollerPrivate() : m_Timer{std::make_unique<QTimer>()}
37 explicit DragDropScrollerPrivate() : m_Timer{std::make_unique<QTimer>()}
37 {
38 {
38 m_Timer->setInterval(0);
39 m_Timer->setInterval(0);
39 }
40 }
40 };
41 };
41
42
42 DragDropScroller::DragDropScroller(QObject *parent)
43 DragDropScroller::DragDropScroller(QObject *parent)
43 : QObject{parent}, impl{spimpl::make_unique_impl<DragDropScrollerPrivate>()}
44 : QObject{parent}, impl{spimpl::make_unique_impl<DragDropScrollerPrivate>()}
44 {
45 {
45 connect(impl->m_Timer.get(), &QTimer::timeout, this, &DragDropScroller::onTimer);
46 connect(impl->m_Timer.get(), &QTimer::timeout, this, &DragDropScroller::onTimer);
46 }
47 }
47
48
48 void DragDropScroller::addScrollArea(QScrollArea *scrollArea)
49 void DragDropScroller::addScrollArea(QScrollArea *scrollArea)
49 {
50 {
50 impl->m_ScrollAreas << scrollArea;
51 impl->m_ScrollAreas << scrollArea;
51 scrollArea->viewport()->setAcceptDrops(true);
52 scrollArea->viewport()->setAcceptDrops(true);
52 }
53 }
53
54
54 void DragDropScroller::removeScrollArea(QScrollArea *scrollArea)
55 void DragDropScroller::removeScrollArea(QScrollArea *scrollArea)
55 {
56 {
56 impl->m_ScrollAreas.removeAll(scrollArea);
57 impl->m_ScrollAreas.removeAll(scrollArea);
57 scrollArea->viewport()->setAcceptDrops(false);
58 scrollArea->viewport()->setAcceptDrops(false);
58 }
59 }
59
60
60 bool DragDropScroller::eventFilter(QObject *obj, QEvent *event)
61 bool DragDropScroller::eventFilter(QObject *obj, QEvent *event)
61 {
62 {
62 if (event->type() == QEvent::DragMove) {
63 if (event->type() == QEvent::DragMove) {
63 auto w = static_cast<QWidget *>(obj);
64 auto w = static_cast<QWidget *>(obj);
64
65
65 if (impl->m_CurrentScrollArea && impl->m_CurrentScrollArea->isAncestorOf(w)) {
66 if (impl->m_CurrentScrollArea && impl->m_CurrentScrollArea->isAncestorOf(w)) {
66 auto moveEvent = static_cast<QDragMoveEvent *>(event);
67 auto moveEvent = static_cast<QDragMoveEvent *>(event);
67
68
68 auto pos = moveEvent->pos();
69 auto pos = moveEvent->pos();
69 if (impl->m_CurrentScrollArea->viewport() != w) {
70 if (impl->m_CurrentScrollArea->viewport() != w) {
70 auto globalPos = w->mapToGlobal(moveEvent->pos());
71 auto globalPos = w->mapToGlobal(moveEvent->pos());
71 pos = impl->m_CurrentScrollArea->viewport()->mapFromGlobal(globalPos);
72 pos = impl->m_CurrentScrollArea->viewport()->mapFromGlobal(globalPos);
72 }
73 }
73
74
74 auto isInTopZone = pos.y() > impl->m_CurrentScrollArea->viewport()->size().height()
75 auto isInTopZone = pos.y() > impl->m_CurrentScrollArea->viewport()->size().height()
75 - SCROLL_ZONE_SIZE;
76 - SCROLL_ZONE_SIZE;
76 auto isInBottomZone = pos.y() < SCROLL_ZONE_SIZE;
77 auto isInBottomZone = pos.y() < SCROLL_ZONE_SIZE;
77
78
78 if (!isInTopZone && !isInBottomZone) {
79 if (!isInTopZone && !isInBottomZone) {
79 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
80 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
80 impl->m_Timer->stop();
81 impl->m_Timer->stop();
81 }
82 }
82 else if (!impl->m_Timer->isActive()) {
83 else if (!impl->m_Timer->isActive()) {
83 impl->m_Direction = isInTopZone ? DragDropScrollerPrivate::ScrollDirection::up
84 impl->m_Direction = isInTopZone ? DragDropScrollerPrivate::ScrollDirection::up
84 : DragDropScrollerPrivate::ScrollDirection::down;
85 : DragDropScrollerPrivate::ScrollDirection::down;
85 impl->m_Timer->start();
86 impl->m_Timer->start();
86 }
87 }
87 }
88 }
88 }
89 }
89 else if (event->type() == QEvent::DragEnter) {
90 else if (event->type() == QEvent::DragEnter) {
90 auto w = static_cast<QWidget *>(obj);
91 auto w = static_cast<QWidget *>(obj);
91
92
92 for (auto scrollArea : impl->m_ScrollAreas) {
93 for (auto scrollArea : impl->m_ScrollAreas) {
93 if (impl->m_CurrentScrollArea != scrollArea && scrollArea->isAncestorOf(w)) {
94 if (impl->m_CurrentScrollArea != scrollArea && scrollArea->isAncestorOf(w)) {
94 auto enterEvent = static_cast<QDragEnterEvent *>(event);
95 auto enterEvent = static_cast<QDragEnterEvent *>(event);
95 enterEvent->acceptProposedAction();
96 enterEvent->acceptProposedAction();
96 enterEvent->setDropAction(Qt::IgnoreAction);
97 enterEvent->setDropAction(Qt::IgnoreAction);
97 impl->m_CurrentScrollArea = scrollArea;
98 impl->m_CurrentScrollArea = scrollArea;
98 break;
99 break;
99 }
100 }
100 }
101 }
101 }
102 }
102 else if (event->type() == QEvent::DragLeave) {
103 else if (event->type() == QEvent::DragLeave) {
103 if (impl->m_CurrentScrollArea) {
104 if (impl->m_CurrentScrollArea) {
104 if (!QRect(QPoint(), impl->m_CurrentScrollArea->size())
105 if (!QRect(QPoint(), impl->m_CurrentScrollArea->size())
105 .contains(impl->m_CurrentScrollArea->mapFromGlobal(QCursor::pos()))) {
106 .contains(impl->m_CurrentScrollArea->mapFromGlobal(QCursor::pos()))) {
106 impl->m_CurrentScrollArea = nullptr;
107 impl->m_CurrentScrollArea = nullptr;
107 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
108 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
108 impl->m_Timer->stop();
109 impl->m_Timer->stop();
109 }
110 }
110 }
111 }
111 }
112 }
112 else if (event->type() == QEvent::Drop) {
113 else if (event->type() == QEvent::Drop) {
113 if (impl->m_CurrentScrollArea) {
114 if (impl->m_CurrentScrollArea) {
114 impl->m_CurrentScrollArea = nullptr;
115 impl->m_CurrentScrollArea = nullptr;
115 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
116 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
116 impl->m_Timer->stop();
117 impl->m_Timer->stop();
117 }
118 }
118 }
119 }
119
120
120 return false;
121 return false;
121 }
122 }
122
123
123 void DragDropScroller::onTimer()
124 void DragDropScroller::onTimer()
124 {
125 {
125 if (impl->m_CurrentScrollArea) {
126 if (impl->m_CurrentScrollArea) {
126 auto mvt = 0;
127 auto mvt = 0;
127 switch (impl->m_Direction) {
128 switch (impl->m_Direction) {
128 case DragDropScrollerPrivate::ScrollDirection::up:
129 case DragDropScrollerPrivate::ScrollDirection::up:
129 mvt = SCROLL_SPEED;
130 mvt = SCROLL_SPEED;
130 break;
131 break;
131 case DragDropScrollerPrivate::ScrollDirection::down:
132 case DragDropScrollerPrivate::ScrollDirection::down:
132 mvt = -SCROLL_SPEED;
133 mvt = -SCROLL_SPEED;
133 break;
134 break;
134 default:
135 default:
135 break;
136 break;
136 }
137 }
137
138
138 impl->m_CurrentScrollArea->verticalScrollBar()->setValue(
139 impl->m_CurrentScrollArea->verticalScrollBar()->setValue(
139 impl->m_CurrentScrollArea->verticalScrollBar()->value() + mvt);
140 impl->m_CurrentScrollArea->verticalScrollBar()->value() + mvt);
140 }
141 }
141 }
142 }
142
143
143 struct DragDropHelper::DragDropHelperPrivate {
144 struct DragDropHelper::DragDropHelperPrivate {
144
145
145 VisualizationDragWidget *m_CurrentDragWidget = nullptr;
146 VisualizationDragWidget *m_CurrentDragWidget = nullptr;
146 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
147 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
148 QLabel *m_PlaceHolderLabel;
149 QWidget *m_PlaceBackground;
147 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
150 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
148 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
149 // QTemporaryFile to have a name which is not generated.
152 // QTemporaryFile to have a name which is not generated.
150
153
151 VisualizationDragWidget *m_HighlightedDragWidget = nullptr;
154 VisualizationDragWidget *m_HighlightedDragWidget = nullptr;
152
155
153 QMetaObject::Connection m_DragWidgetDestroyedConnection;
156 QMetaObject::Connection m_DragWidgetDestroyedConnection;
154 QMetaObject::Connection m_HighlightedWidgetDestroyedConnection;
157 QMetaObject::Connection m_HighlightedWidgetDestroyedConnection;
155
158
156 explicit DragDropHelperPrivate()
159 explicit DragDropHelperPrivate()
157 : m_PlaceHolder{std::make_unique<QWidget>()},
160 : m_PlaceHolder{std::make_unique<QWidget>()},
158 m_DragDropScroller{std::make_unique<DragDropScroller>()}
161 m_DragDropScroller{std::make_unique<DragDropScroller>()}
159 {
162 {
160 m_PlaceHolder->setStyleSheet("background-color: #BBD5EE; border:2px solid #2A7FD4");
161 sqpApp->installEventFilter(m_DragDropScroller.get());
162
163
164 auto layout = new QVBoxLayout{m_PlaceHolder.get()};
165 layout->setSpacing(0);
166 layout->setContentsMargins(0, 0, 0, 0);
167
168 m_PlaceHolderLabel = new QLabel{"", m_PlaceHolder.get()};
169 m_PlaceHolderLabel->setMinimumHeight(25);
170 layout->addWidget(m_PlaceHolderLabel);
171
172 m_PlaceBackground = new QWidget{m_PlaceHolder.get()};
173 m_PlaceBackground->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
174 layout->addWidget(m_PlaceBackground);
175
176 sqpApp->installEventFilter(m_DragDropScroller.get());
163
177
164 m_ImageTempUrl = QDir::temp().absoluteFilePath("Sciqlop_graph.png");
178 m_ImageTempUrl = QDir::temp().absoluteFilePath("Sciqlop_graph.png");
165 }
179 }
166
180
167 void preparePlaceHolder() const
181 void preparePlaceHolder(DragDropHelper::PlaceHolderType type, const QString &topLabelText) const
168 {
182 {
169 if (m_CurrentDragWidget) {
183 if (m_CurrentDragWidget) {
170 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
184 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
171 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
185 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
172 }
186 }
173 else {
187 else {
174 // Configuration of the placeHolder when there is no dragWidget
188 // Configuration of the placeHolder when there is no dragWidget
175 // (for instance with a drag from a variable)
189 // (for instance with a drag from a variable)
176
190
177 m_PlaceHolder->setMinimumSize(0, GRAPH_MINIMUM_HEIGHT);
191 m_PlaceHolder->setMinimumSize(0, GRAPH_MINIMUM_HEIGHT);
178 m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
192 m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
179 }
193 }
194
195 switch (type) {
196 case DragDropHelper::PlaceHolderType::Graph:
197 m_PlaceBackground->setStyleSheet(
198 "background-color: #BBD5EE; border: 1px solid #2A7FD4");
199 break;
200 case DragDropHelper::PlaceHolderType::Zone:
201 case DragDropHelper::PlaceHolderType::Default:
202 m_PlaceBackground->setStyleSheet(
203 "background-color: #BBD5EE; border: 2px solid #2A7FD4");
204 m_PlaceHolderLabel->setStyleSheet("color: #2A7FD4");
205 break;
206 }
207
208 m_PlaceHolderLabel->setText(topLabelText);
209 m_PlaceHolderLabel->setVisible(!topLabelText.isEmpty());
180 }
210 }
181 };
211 };
182
212
183
213
184 DragDropHelper::DragDropHelper() : impl{spimpl::make_unique_impl<DragDropHelperPrivate>()}
214 DragDropHelper::DragDropHelper() : impl{spimpl::make_unique_impl<DragDropHelperPrivate>()}
185 {
215 {
186 }
216 }
187
217
188 DragDropHelper::~DragDropHelper()
218 DragDropHelper::~DragDropHelper()
189 {
219 {
190 QFile::remove(impl->m_ImageTempUrl);
220 QFile::remove(impl->m_ImageTempUrl);
191 }
221 }
192
222
193 void DragDropHelper::resetDragAndDrop()
223 void DragDropHelper::resetDragAndDrop()
194 {
224 {
195 setCurrentDragWidget(nullptr);
225 setCurrentDragWidget(nullptr);
196 impl->m_HighlightedDragWidget = nullptr;
226 impl->m_HighlightedDragWidget = nullptr;
197 }
227 }
198
228
199 void DragDropHelper::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
229 void DragDropHelper::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
200 {
230 {
201 if (impl->m_CurrentDragWidget) {
231 if (impl->m_CurrentDragWidget) {
202
232
203 QObject::disconnect(impl->m_DragWidgetDestroyedConnection);
233 QObject::disconnect(impl->m_DragWidgetDestroyedConnection);
204 }
234 }
205
235
206 if (dragWidget) {
236 if (dragWidget) {
207 // ensures the impl->m_CurrentDragWidget is reset when the widget is destroyed
237 // ensures the impl->m_CurrentDragWidget is reset when the widget is destroyed
208 impl->m_DragWidgetDestroyedConnection
238 impl->m_DragWidgetDestroyedConnection
209 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
239 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
210 [this]() { impl->m_CurrentDragWidget = nullptr; });
240 [this]() { impl->m_CurrentDragWidget = nullptr; });
211 }
241 }
212
242
213 impl->m_CurrentDragWidget = dragWidget;
243 impl->m_CurrentDragWidget = dragWidget;
214 }
244 }
215
245
216 VisualizationDragWidget *DragDropHelper::getCurrentDragWidget() const
246 VisualizationDragWidget *DragDropHelper::getCurrentDragWidget() const
217 {
247 {
218 return impl->m_CurrentDragWidget;
248 return impl->m_CurrentDragWidget;
219 }
249 }
220
250
221
222 QWidget &DragDropHelper::placeHolder() const
251 QWidget &DragDropHelper::placeHolder() const
223 {
252 {
224 return *impl->m_PlaceHolder;
253 return *impl->m_PlaceHolder;
225 }
254 }
226
255
227 void DragDropHelper::insertPlaceHolder(QVBoxLayout *layout, int index)
256 void DragDropHelper::insertPlaceHolder(QVBoxLayout *layout, int index, PlaceHolderType type,
257 const QString &topLabelText)
228 {
258 {
229 removePlaceHolder();
259 removePlaceHolder();
230 impl->preparePlaceHolder();
260 impl->preparePlaceHolder(type, topLabelText);
231 layout->insertWidget(index, impl->m_PlaceHolder.get());
261 layout->insertWidget(index, impl->m_PlaceHolder.get());
232 impl->m_PlaceHolder->show();
262 impl->m_PlaceHolder->show();
233 }
263 }
234
264
235 void DragDropHelper::removePlaceHolder()
265 void DragDropHelper::removePlaceHolder()
236 {
266 {
237 auto parentWidget = impl->m_PlaceHolder->parentWidget();
267 auto parentWidget = impl->m_PlaceHolder->parentWidget();
238 if (parentWidget) {
268 if (parentWidget) {
239 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
269 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
240 impl->m_PlaceHolder->setParent(nullptr);
270 impl->m_PlaceHolder->setParent(nullptr);
241 impl->m_PlaceHolder->hide();
271 impl->m_PlaceHolder->hide();
242 }
272 }
243 }
273 }
244
274
245 bool DragDropHelper::isPlaceHolderSet() const
275 bool DragDropHelper::isPlaceHolderSet() const
246 {
276 {
247 return impl->m_PlaceHolder->parentWidget();
277 return impl->m_PlaceHolder->parentWidget();
248 }
278 }
249
279
250 void DragDropHelper::addDragDropScrollArea(QScrollArea *scrollArea)
280 void DragDropHelper::addDragDropScrollArea(QScrollArea *scrollArea)
251 {
281 {
252 impl->m_DragDropScroller->addScrollArea(scrollArea);
282 impl->m_DragDropScroller->addScrollArea(scrollArea);
253 }
283 }
254
284
255 void DragDropHelper::removeDragDropScrollArea(QScrollArea *scrollArea)
285 void DragDropHelper::removeDragDropScrollArea(QScrollArea *scrollArea)
256 {
286 {
257 impl->m_DragDropScroller->removeScrollArea(scrollArea);
287 impl->m_DragDropScroller->removeScrollArea(scrollArea);
258 }
288 }
259
289
260 QUrl DragDropHelper::imageTemporaryUrl(const QImage &image) const
290 QUrl DragDropHelper::imageTemporaryUrl(const QImage &image) const
261 {
291 {
262 image.save(impl->m_ImageTempUrl);
292 image.save(impl->m_ImageTempUrl);
263 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
293 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
264 }
294 }
265
295
266 void DragDropHelper::setHightlightedDragWidget(VisualizationDragWidget *dragWidget)
296 void DragDropHelper::setHightlightedDragWidget(VisualizationDragWidget *dragWidget)
267 {
297 {
268 if (impl->m_HighlightedDragWidget) {
298 if (impl->m_HighlightedDragWidget) {
269 impl->m_HighlightedDragWidget->highlightForMerge(false);
299 impl->m_HighlightedDragWidget->highlightForMerge(false);
270 QObject::disconnect(impl->m_HighlightedWidgetDestroyedConnection);
300 QObject::disconnect(impl->m_HighlightedWidgetDestroyedConnection);
271 }
301 }
272
302
273 if (dragWidget) {
303 if (dragWidget) {
274 dragWidget->highlightForMerge(true);
304 dragWidget->highlightForMerge(true);
275
305
276 // ensures the impl->m_HighlightedDragWidget is reset when the widget is destroyed
306 // ensures the impl->m_HighlightedDragWidget is reset when the widget is destroyed
277 impl->m_DragWidgetDestroyedConnection
307 impl->m_DragWidgetDestroyedConnection
278 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
308 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
279 [this]() { impl->m_HighlightedDragWidget = nullptr; });
309 [this]() { impl->m_HighlightedDragWidget = nullptr; });
280 }
310 }
281
311
282 impl->m_HighlightedDragWidget = dragWidget;
312 impl->m_HighlightedDragWidget = dragWidget;
283 }
313 }
284
314
285 VisualizationDragWidget *DragDropHelper::getHightlightedDragWidget() const
315 VisualizationDragWidget *DragDropHelper::getHightlightedDragWidget() const
286 {
316 {
287 return impl->m_HighlightedDragWidget;
317 return impl->m_HighlightedDragWidget;
288 }
318 }
289
319
290 bool DragDropHelper::checkMimeDataForVisualization(const QMimeData *mimeData,
320 bool DragDropHelper::checkMimeDataForVisualization(const QMimeData *mimeData,
291 VisualizationDragDropContainer *dropContainer)
321 VisualizationDragDropContainer *dropContainer)
292 {
322 {
293 if (!mimeData || !dropContainer) {
323 if (!mimeData || !dropContainer) {
294 qCWarning(LOG_DragDropHelper()) << QObject::tr(
324 qCWarning(LOG_DragDropHelper()) << QObject::tr(
295 "DragDropHelper::checkMimeDataForVisualization, invalid input parameters.");
325 "DragDropHelper::checkMimeDataForVisualization, invalid input parameters.");
296 Q_ASSERT(false);
326 Q_ASSERT(false);
297 return false;
327 return false;
298 }
328 }
299
329
300 auto result = false;
330 auto result = false;
301
331
302 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
332 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
303 auto variables = sqpApp->variableController().variablesForMimeData(
333 auto variables = sqpApp->variableController().variablesForMimeData(
304 mimeData->data(MIME_TYPE_VARIABLE_LIST));
334 mimeData->data(MIME_TYPE_VARIABLE_LIST));
305
335
306 if (variables.count() == 1) {
336 if (variables.count() == 1) {
307
337
308 auto variable = variables.first();
338 auto variable = variables.first();
309 if (variable->dataSeries() != nullptr) {
339 if (variable->dataSeries() != nullptr) {
310
340
311 // Check that the variable is not already in a graph
341 // Check that the variable is not already in a graph
312
342
313 auto parent = dropContainer->parentWidget();
343 auto parent = dropContainer->parentWidget();
314 while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) {
344 while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) {
315 parent = parent->parentWidget(); // Search for the top level VisualizationWidget
345 parent = parent->parentWidget(); // Search for the top level VisualizationWidget
316 }
346 }
317
347
318 if (parent) {
348 if (parent) {
319 auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
349 auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
320
350
321 FindVariableOperation findVariableOperation{variable};
351 FindVariableOperation findVariableOperation{variable};
322 visualizationWidget->accept(&findVariableOperation);
352 visualizationWidget->accept(&findVariableOperation);
323 auto variableContainers = findVariableOperation.result();
353 auto variableContainers = findVariableOperation.result();
324 if (variableContainers.empty()) {
354 if (variableContainers.empty()) {
325 result = true;
355 result = true;
326 }
356 }
327 else {
357 else {
328 // result = false: the variable already exist in the visualisation
358 // result = false: the variable already exist in the visualisation
329 }
359 }
330 }
360 }
331 else {
361 else {
332 qCWarning(LOG_DragDropHelper()) << QObject::tr(
362 qCWarning(LOG_DragDropHelper()) << QObject::tr(
333 "DragDropHelper::checkMimeDataForVisualization, the parent "
363 "DragDropHelper::checkMimeDataForVisualization, the parent "
334 "VisualizationWidget cannot be found. Cannot check if the variable is "
364 "VisualizationWidget cannot be found. Cannot check if the variable is "
335 "already used or not.");
365 "already used or not.");
336 }
366 }
337 }
367 }
338 else {
368 else {
339 // result = false: the variable is not fully loaded
369 // result = false: the variable is not fully loaded
340 }
370 }
341 }
371 }
342 else {
372 else {
343 // result = false: cannot drop multiple variables in the visualisation
373 // result = false: cannot drop multiple variables in the visualisation
344 }
374 }
345 }
375 }
346 else {
376 else {
347 // Other MIME data
377 // Other MIME data
348 // no special rules, accepted by default
378 // no special rules, accepted by default
349 result = true;
379 result = true;
350 }
380 }
351
381
352 return result;
382 return result;
353 }
383 }
@@ -1,442 +1,453
1 #include "Visualization/VisualizationDragDropContainer.h"
1 #include "Visualization/VisualizationDragDropContainer.h"
2 #include "DragDropHelper.h"
2 #include "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;
22 DragDropHelper::PlaceHolderType m_PlaceHolderType = DragDropHelper::PlaceHolderType::Graph;
21
23
22 VisualizationDragDropContainer::AcceptMimeDataFunction m_AcceptMimeDataFun
24 VisualizationDragDropContainer::AcceptMimeDataFunction m_AcceptMimeDataFun
23 = [](auto mimeData) { return true; };
25 = [](auto mimeData) { return true; };
24
26
25 int m_MinContainerHeight = 0;
27 int m_MinContainerHeight = 0;
26
28
27 explicit VisualizationDragDropContainerPrivate(QWidget *widget)
29 explicit VisualizationDragDropContainerPrivate(QWidget *widget)
28 {
30 {
29 m_Layout = new QVBoxLayout(widget);
31 m_Layout = new QVBoxLayout(widget);
30 m_Layout->setContentsMargins(0, 0, 0, 0);
32 m_Layout->setContentsMargins(0, 0, 0, 0);
31 }
33 }
32
34
33 bool acceptMimeData(const QMimeData *data) const
35 bool acceptMimeData(const QMimeData *data) const
34 {
36 {
35 for (const auto &type : m_AcceptedMimeTypes.keys()) {
37 for (const auto &type : m_AcceptedMimeTypes.keys()) {
36 if (data->hasFormat(type) && m_AcceptMimeDataFun(data)) {
38 if (data->hasFormat(type) && m_AcceptMimeDataFun(data)) {
37 return true;
39 return true;
38 }
40 }
39 }
41 }
40
42
41 return false;
43 return false;
42 }
44 }
43
45
44 bool allowMergeForMimeData(const QMimeData *data) const
46 bool allowMergeForMimeData(const QMimeData *data) const
45 {
47 {
46 bool result = false;
48 bool result = false;
47 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
49 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
48 ++it) {
50 ++it) {
49
51
50 if (data->hasFormat(it.key())
52 if (data->hasFormat(it.key())
51 && (it.value() == VisualizationDragDropContainer::DropBehavior::Merged
53 && (it.value() == VisualizationDragDropContainer::DropBehavior::Merged
52 || it.value()
54 || it.value()
53 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
55 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
54 result = true;
56 result = true;
55 }
57 }
56 else if (data->hasFormat(it.key())
58 else if (data->hasFormat(it.key())
57 && it.value() == VisualizationDragDropContainer::DropBehavior::Inserted) {
59 && it.value() == VisualizationDragDropContainer::DropBehavior::Inserted) {
58 // 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
59 // merged
61 // merged
60 result = false;
62 result = false;
61 break;
63 break;
62 }
64 }
63 }
65 }
64
66
65 return result;
67 return result;
66 }
68 }
67
69
68 bool allowInsertForMimeData(const QMimeData *data) const
70 bool allowInsertForMimeData(const QMimeData *data) const
69 {
71 {
70 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
72 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
71 ++it) {
73 ++it) {
72 if (data->hasFormat(it.key())
74 if (data->hasFormat(it.key())
73 && (it.value() == VisualizationDragDropContainer::DropBehavior::Inserted
75 && (it.value() == VisualizationDragDropContainer::DropBehavior::Inserted
74 || it.value()
76 || it.value()
75 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
77 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
76 return true;
78 return true;
77 }
79 }
78 }
80 }
79
81
80 return false;
82 return false;
81 }
83 }
82
84
83 bool hasPlaceHolder() const
85 bool hasPlaceHolder() const
84 {
86 {
85 return sqpApp->dragDropHelper().placeHolder().parentWidget() == m_Layout->parentWidget();
87 return sqpApp->dragDropHelper().placeHolder().parentWidget() == m_Layout->parentWidget();
86 }
88 }
87
89
88 VisualizationDragWidget *getChildDragWidgetAt(const QWidget *parent, const QPoint &pos) const
90 VisualizationDragWidget *getChildDragWidgetAt(const QWidget *parent, const QPoint &pos) const
89 {
91 {
90 VisualizationDragWidget *dragWidget = nullptr;
92 VisualizationDragWidget *dragWidget = nullptr;
91
93
92 for (auto child : parent->children()) {
94 for (auto child : parent->children()) {
93 auto widget = qobject_cast<VisualizationDragWidget *>(child);
95 auto widget = qobject_cast<VisualizationDragWidget *>(child);
94 if (widget && widget->isVisible()) {
96 if (widget && widget->isVisible()) {
95 if (widget->frameGeometry().contains(pos)) {
97 if (widget->frameGeometry().contains(pos)) {
96 dragWidget = widget;
98 dragWidget = widget;
97 break;
99 break;
98 }
100 }
99 }
101 }
100 }
102 }
101
103
102 return dragWidget;
104 return dragWidget;
103 }
105 }
104
106
105 bool cursorIsInContainer(QWidget *container) const
107 bool cursorIsInContainer(QWidget *container) const
106 {
108 {
107 return container->isAncestorOf(sqpApp->widgetAt(QCursor::pos()));
109 return container->isAncestorOf(sqpApp->widgetAt(QCursor::pos()));
108 }
110 }
109
111
110 int countDragWidget(const QWidget *parent, bool onlyVisible = false) const
112 int countDragWidget(const QWidget *parent, bool onlyVisible = false) const
111 {
113 {
112 auto nbGraph = 0;
114 auto nbGraph = 0;
113 for (auto child : parent->children()) {
115 for (auto child : parent->children()) {
114 if (qobject_cast<VisualizationDragWidget *>(child)) {
116 if (qobject_cast<VisualizationDragWidget *>(child)) {
115 if (!onlyVisible || qobject_cast<VisualizationDragWidget *>(child)->isVisible()) {
117 if (!onlyVisible || qobject_cast<VisualizationDragWidget *>(child)->isVisible()) {
116 nbGraph += 1;
118 nbGraph += 1;
117 }
119 }
118 }
120 }
119 }
121 }
120
122
121 return nbGraph;
123 return nbGraph;
122 }
124 }
123
125
124 void findPlaceHolderPosition(const QPoint &pos, bool canInsert, bool canMerge,
126 void findPlaceHolderPosition(const QPoint &pos, bool canInsert, bool canMerge,
125 const VisualizationDragDropContainer *container);
127 const VisualizationDragDropContainer *container);
126 };
128 };
127
129
128 VisualizationDragDropContainer::VisualizationDragDropContainer(QWidget *parent)
130 VisualizationDragDropContainer::VisualizationDragDropContainer(QWidget *parent)
129 : QFrame{parent},
131 : QFrame{parent},
130 impl{spimpl::make_unique_impl<VisualizationDragDropContainerPrivate>(this)}
132 impl{spimpl::make_unique_impl<VisualizationDragDropContainerPrivate>(this)}
131 {
133 {
132 setAcceptDrops(true);
134 setAcceptDrops(true);
133 }
135 }
134
136
135 void VisualizationDragDropContainer::addDragWidget(VisualizationDragWidget *dragWidget)
137 void VisualizationDragDropContainer::addDragWidget(VisualizationDragWidget *dragWidget)
136 {
138 {
137 impl->m_Layout->addWidget(dragWidget);
139 impl->m_Layout->addWidget(dragWidget);
138 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
140 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
139 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
141 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
140 &VisualizationDragDropContainer::startDrag);
142 &VisualizationDragDropContainer::startDrag);
141 }
143 }
142
144
143 void VisualizationDragDropContainer::insertDragWidget(int index,
145 void VisualizationDragDropContainer::insertDragWidget(int index,
144 VisualizationDragWidget *dragWidget)
146 VisualizationDragWidget *dragWidget)
145 {
147 {
146 impl->m_Layout->insertWidget(index, dragWidget);
148 impl->m_Layout->insertWidget(index, dragWidget);
147 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
149 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
148 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
150 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
149 &VisualizationDragDropContainer::startDrag);
151 &VisualizationDragDropContainer::startDrag);
150 }
152 }
151
153
152 void VisualizationDragDropContainer::addAcceptedMimeType(
154 void VisualizationDragDropContainer::addAcceptedMimeType(
153 const QString &mimeType, VisualizationDragDropContainer::DropBehavior behavior)
155 const QString &mimeType, VisualizationDragDropContainer::DropBehavior behavior)
154 {
156 {
155 impl->m_AcceptedMimeTypes[mimeType] = behavior;
157 impl->m_AcceptedMimeTypes[mimeType] = behavior;
156 }
158 }
157
159
158 int VisualizationDragDropContainer::countDragWidget() const
160 int VisualizationDragDropContainer::countDragWidget() const
159 {
161 {
160 return impl->countDragWidget(this);
162 return impl->countDragWidget(this);
161 }
163 }
162
164
163 void VisualizationDragDropContainer::setAcceptMimeDataFunction(
165 void VisualizationDragDropContainer::setAcceptMimeDataFunction(
164 VisualizationDragDropContainer::AcceptMimeDataFunction fun)
166 VisualizationDragDropContainer::AcceptMimeDataFunction fun)
165 {
167 {
166 impl->m_AcceptMimeDataFun = fun;
168 impl->m_AcceptMimeDataFun = fun;
167 }
169 }
168
170
171 void VisualizationDragDropContainer::setPlaceHolderType(DragDropHelper::PlaceHolderType type,
172 const QString &placeHolderText)
173 {
174 impl->m_PlaceHolderType = type;
175 impl->m_PlaceHolderText = placeHolderText;
176 }
177
169 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidget,
178 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidget,
170 const QPoint &dragPosition)
179 const QPoint &dragPosition)
171 {
180 {
172 auto &helper = sqpApp->dragDropHelper();
181 auto &helper = sqpApp->dragDropHelper();
173 helper.resetDragAndDrop();
182 helper.resetDragAndDrop();
174
183
175 // Note: The management of the drag object is done by Qt
184 // Note: The management of the drag object is done by Qt
176 auto drag = new QDrag{dragWidget};
185 auto drag = new QDrag{dragWidget};
177 drag->setHotSpot(dragPosition);
186 drag->setHotSpot(dragPosition);
178
187
179 auto mimeData = dragWidget->mimeData();
188 auto mimeData = dragWidget->mimeData();
180 drag->setMimeData(mimeData);
189 drag->setMimeData(mimeData);
181
190
182 auto pixmap = QPixmap(dragWidget->size());
191 auto pixmap = QPixmap(dragWidget->size());
183 dragWidget->render(&pixmap);
192 dragWidget->render(&pixmap);
184 drag->setPixmap(pixmap);
193 drag->setPixmap(pixmap);
185
194
186 auto image = pixmap.toImage();
195 auto image = pixmap.toImage();
187 mimeData->setImageData(image);
196 mimeData->setImageData(image);
188 mimeData->setUrls({helper.imageTemporaryUrl(image)});
197 mimeData->setUrls({helper.imageTemporaryUrl(image)});
189
198
190 if (impl->m_Layout->indexOf(dragWidget) >= 0) {
199 if (impl->m_Layout->indexOf(dragWidget) >= 0) {
191 helper.setCurrentDragWidget(dragWidget);
200 helper.setCurrentDragWidget(dragWidget);
192
201
193 if (impl->cursorIsInContainer(this)) {
202 if (impl->cursorIsInContainer(this)) {
194 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
203 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
195 helper.insertPlaceHolder(impl->m_Layout, dragWidgetIndex);
204 helper.insertPlaceHolder(impl->m_Layout, dragWidgetIndex, impl->m_PlaceHolderType,
205 impl->m_PlaceHolderText);
196 dragWidget->setVisible(false);
206 dragWidget->setVisible(false);
197 }
207 }
198 else {
208 else {
199 // The drag starts directly outside the drop zone
209 // The drag starts directly outside the drop zone
200 // do not add the placeHolder
210 // do not add the placeHolder
201 }
211 }
202
212
203 // 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
204 drag->exec(Qt::MoveAction | Qt::CopyAction);
214 drag->exec(Qt::MoveAction | Qt::CopyAction);
205 }
215 }
206 else {
216 else {
207 qCWarning(LOG_VisualizationDragDropContainer())
217 qCWarning(LOG_VisualizationDragDropContainer())
208 << tr("VisualizationDragDropContainer::startDrag, drag aborted, the specified "
218 << tr("VisualizationDragDropContainer::startDrag, drag aborted, the specified "
209 "VisualizationDragWidget is not found in this container.");
219 "VisualizationDragWidget is not found in this container.");
210 }
220 }
211 }
221 }
212
222
213 void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event)
223 void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event)
214 {
224 {
215 if (impl->acceptMimeData(event->mimeData())) {
225 if (impl->acceptMimeData(event->mimeData())) {
216 event->acceptProposedAction();
226 event->acceptProposedAction();
217
227
218 auto &helper = sqpApp->dragDropHelper();
228 auto &helper = sqpApp->dragDropHelper();
219
229
220 if (!impl->hasPlaceHolder()) {
230 if (!impl->hasPlaceHolder()) {
221 auto dragWidget = helper.getCurrentDragWidget();
231 auto dragWidget = helper.getCurrentDragWidget();
222
232
223 if (dragWidget) {
233 if (dragWidget) {
224 // 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
225 // the dragWidget which was made visible by the dragLeaveEvent
235 // the dragWidget which was made visible by the dragLeaveEvent
226 auto parentWidget
236 auto parentWidget
227 = qobject_cast<VisualizationDragDropContainer *>(dragWidget->parentWidget());
237 = qobject_cast<VisualizationDragDropContainer *>(dragWidget->parentWidget());
228 if (parentWidget) {
238 if (parentWidget) {
229 dragWidget->setVisible(false);
239 dragWidget->setVisible(false);
230 }
240 }
231 }
241 }
232
242
233 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
243 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
234 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
244 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
235 impl->findPlaceHolderPosition(event->pos(), canInsert, canMerge, this);
245 impl->findPlaceHolderPosition(event->pos(), canInsert, canMerge, this);
236 }
246 }
237 else {
247 else {
238 // do nothing
248 // do nothing
239 }
249 }
240 }
250 }
241 else {
251 else {
242 event->ignore();
252 event->ignore();
243 }
253 }
244
254
245 QWidget::dragEnterEvent(event);
255 QWidget::dragEnterEvent(event);
246 }
256 }
247
257
248 void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event)
258 void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event)
249 {
259 {
250 Q_UNUSED(event);
260 Q_UNUSED(event);
251
261
252 auto &helper = sqpApp->dragDropHelper();
262 auto &helper = sqpApp->dragDropHelper();
253
263
254 if (!impl->cursorIsInContainer(this)) {
264 if (!impl->cursorIsInContainer(this)) {
255 helper.removePlaceHolder();
265 helper.removePlaceHolder();
256 helper.setHightlightedDragWidget(nullptr);
266 helper.setHightlightedDragWidget(nullptr);
257 impl->m_MinContainerHeight = 0;
267 impl->m_MinContainerHeight = 0;
258
268
259 auto dragWidget = helper.getCurrentDragWidget();
269 auto dragWidget = helper.getCurrentDragWidget();
260 if (dragWidget) {
270 if (dragWidget) {
261 // 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
262 // In that case, shows the drag widget at its original place
272 // In that case, shows the drag widget at its original place
263 // 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
264 // 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)
265
275
266 if (dragWidget) {
276 if (dragWidget) {
267 dragWidget->setVisible(true);
277 dragWidget->setVisible(true);
268 }
278 }
269 }
279 }
270 }
280 }
271 else {
281 else {
272 // Leave event probably received for a child widget.
282 // Leave event probably received for a child widget.
273 // Do nothing.
283 // Do nothing.
274 // 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.
275 }
285 }
276
286
277 QWidget::dragLeaveEvent(event);
287 QWidget::dragLeaveEvent(event);
278 }
288 }
279
289
280 void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event)
290 void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event)
281 {
291 {
282 if (impl->acceptMimeData(event->mimeData())) {
292 if (impl->acceptMimeData(event->mimeData())) {
283 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
293 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
284 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
294 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
285 impl->findPlaceHolderPosition(event->pos(), canInsert, canMerge, this);
295 impl->findPlaceHolderPosition(event->pos(), canInsert, canMerge, this);
286 }
296 }
287 else {
297 else {
288 event->ignore();
298 event->ignore();
289 }
299 }
290
300
291 QWidget::dragMoveEvent(event);
301 QWidget::dragMoveEvent(event);
292 }
302 }
293
303
294 void VisualizationDragDropContainer::dropEvent(QDropEvent *event)
304 void VisualizationDragDropContainer::dropEvent(QDropEvent *event)
295 {
305 {
296 auto &helper = sqpApp->dragDropHelper();
306 auto &helper = sqpApp->dragDropHelper();
297
307
298 if (impl->acceptMimeData(event->mimeData())) {
308 if (impl->acceptMimeData(event->mimeData())) {
299 auto dragWidget = helper.getCurrentDragWidget();
309 auto dragWidget = helper.getCurrentDragWidget();
300 if (impl->hasPlaceHolder()) {
310 if (impl->hasPlaceHolder()) {
301 // drop where the placeHolder is located
311 // drop where the placeHolder is located
302
312
303 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
313 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
304 if (canInsert) {
314 if (canInsert) {
305 auto droppedIndex = impl->m_Layout->indexOf(&helper.placeHolder());
315 auto droppedIndex = impl->m_Layout->indexOf(&helper.placeHolder());
306
316
307 if (dragWidget) {
317 if (dragWidget) {
308 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
318 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
309 if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex) {
319 if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex) {
310 // 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
311 // 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
312 // dragWidget is hidden)
322 // dragWidget is hidden)
313 droppedIndex -= 1;
323 droppedIndex -= 1;
314 }
324 }
315
325
316 dragWidget->setVisible(true);
326 dragWidget->setVisible(true);
317 }
327 }
318
328
319 event->acceptProposedAction();
329 event->acceptProposedAction();
320
330
321 helper.removePlaceHolder();
331 helper.removePlaceHolder();
322
332
323 emit dropOccuredInContainer(droppedIndex, event->mimeData());
333 emit dropOccuredInContainer(droppedIndex, event->mimeData());
324 }
334 }
325 else {
335 else {
326 qCWarning(LOG_VisualizationDragDropContainer()) << tr(
336 qCWarning(LOG_VisualizationDragDropContainer()) << tr(
327 "VisualizationDragDropContainer::dropEvent, dropping on the placeHolder, but "
337 "VisualizationDragDropContainer::dropEvent, dropping on the placeHolder, but "
328 "the insertion is forbidden.");
338 "the insertion is forbidden.");
329 Q_ASSERT(false);
339 Q_ASSERT(false);
330 }
340 }
331 }
341 }
332 else if (helper.getHightlightedDragWidget()) {
342 else if (helper.getHightlightedDragWidget()) {
333 // drop on the highlighted widget
343 // drop on the highlighted widget
334
344
335 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
345 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
336 if (canMerge) {
346 if (canMerge) {
337 event->acceptProposedAction();
347 event->acceptProposedAction();
338 emit dropOccuredOnWidget(helper.getHightlightedDragWidget(), event->mimeData());
348 emit dropOccuredOnWidget(helper.getHightlightedDragWidget(), event->mimeData());
339 }
349 }
340 else {
350 else {
341 qCWarning(LOG_VisualizationDragDropContainer())
351 qCWarning(LOG_VisualizationDragDropContainer())
342 << tr("VisualizationDragDropContainer::dropEvent, dropping on a widget, but "
352 << tr("VisualizationDragDropContainer::dropEvent, dropping on a widget, but "
343 "the merge is forbidden.");
353 "the merge is forbidden.");
344 Q_ASSERT(false);
354 Q_ASSERT(false);
345 }
355 }
346 }
356 }
347 }
357 }
348 else {
358 else {
349 event->ignore();
359 event->ignore();
350 }
360 }
351
361
352 sqpApp->dragDropHelper().setHightlightedDragWidget(nullptr);
362 sqpApp->dragDropHelper().setHightlightedDragWidget(nullptr);
353 impl->m_MinContainerHeight = 0;
363 impl->m_MinContainerHeight = 0;
354
364
355 QWidget::dropEvent(event);
365 QWidget::dropEvent(event);
356 }
366 }
357
367
358
368
359 void VisualizationDragDropContainer::VisualizationDragDropContainerPrivate::findPlaceHolderPosition(
369 void VisualizationDragDropContainer::VisualizationDragDropContainerPrivate::findPlaceHolderPosition(
360 const QPoint &pos, bool canInsert, bool canMerge,
370 const QPoint &pos, bool canInsert, bool canMerge,
361 const VisualizationDragDropContainer *container)
371 const VisualizationDragDropContainer *container)
362 {
372 {
363 auto &helper = sqpApp->dragDropHelper();
373 auto &helper = sqpApp->dragDropHelper();
364
374
365 auto absPos = container->mapToGlobal(pos);
375 auto absPos = container->mapToGlobal(pos);
366 auto isOnPlaceHolder = sqpApp->widgetAt(absPos) == &(helper.placeHolder());
376 auto isOnPlaceHolder = sqpApp->widgetAt(absPos) == &(helper.placeHolder());
367
377
368 if (countDragWidget(container, true) == 0) {
378 if (countDragWidget(container, true) == 0) {
369 // 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
370 helper.insertPlaceHolder(m_Layout, 0);
380 helper.insertPlaceHolder(m_Layout, 0, m_PlaceHolderType, m_PlaceHolderText);
371 }
381 }
372 else if (!isOnPlaceHolder) {
382 else if (!isOnPlaceHolder) {
373 auto nbDragWidget = countDragWidget(container);
383 auto nbDragWidget = countDragWidget(container);
374 if (nbDragWidget > 0) {
384 if (nbDragWidget > 0) {
375
385
376 if (m_MinContainerHeight == 0) {
386 if (m_MinContainerHeight == 0) {
377 m_MinContainerHeight = container->size().height();
387 m_MinContainerHeight = container->size().height();
378 }
388 }
379
389
380 m_MinContainerHeight = qMin(m_MinContainerHeight, container->size().height());
390 m_MinContainerHeight = qMin(m_MinContainerHeight, container->size().height());
381 auto graphHeight = qMax(m_MinContainerHeight / nbDragWidget, GRAPH_MINIMUM_HEIGHT);
391 auto graphHeight = qMax(m_MinContainerHeight / nbDragWidget, GRAPH_MINIMUM_HEIGHT);
382
392
383 auto posY = pos.y();
393 auto posY = pos.y();
384 auto dropIndex = floor(posY / graphHeight);
394 auto dropIndex = floor(posY / graphHeight);
385 auto zoneSize = qMin(graphHeight / 4.0, 75.0);
395 auto zoneSize = qMin(graphHeight / 4.0, 75.0);
386
396
387
397
388 auto isOnTop = posY < dropIndex * graphHeight + zoneSize;
398 auto isOnTop = posY < dropIndex * graphHeight + zoneSize;
389 auto isOnBottom = posY > (dropIndex + 1) * graphHeight - zoneSize;
399 auto isOnBottom = posY > (dropIndex + 1) * graphHeight - zoneSize;
390
400
391 auto placeHolderIndex = m_Layout->indexOf(&(helper.placeHolder()));
401 auto placeHolderIndex = m_Layout->indexOf(&(helper.placeHolder()));
392
402
393 auto dragWidgetHovered = getChildDragWidgetAt(container, pos);
403 auto dragWidgetHovered = getChildDragWidgetAt(container, pos);
394
404
395 if (canInsert && (isOnTop || isOnBottom || !canMerge)) {
405 if (canInsert && (isOnTop || isOnBottom || !canMerge)) {
396 if (isOnBottom) {
406 if (isOnBottom) {
397 dropIndex += 1;
407 dropIndex += 1;
398 }
408 }
399
409
400 if (helper.getCurrentDragWidget()) {
410 if (helper.getCurrentDragWidget()) {
401 auto dragWidgetIndex = m_Layout->indexOf(helper.getCurrentDragWidget());
411 auto dragWidgetIndex = m_Layout->indexOf(helper.getCurrentDragWidget());
402 if (dragWidgetIndex >= 0 && dragWidgetIndex <= dropIndex) {
412 if (dragWidgetIndex >= 0 && dragWidgetIndex <= dropIndex) {
403 // 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
404 // 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
405 // dragWidget is hidden)
415 // dragWidget is hidden)
406 dropIndex += 1;
416 dropIndex += 1;
407 }
417 }
408 }
418 }
409
419
410 if (dropIndex != placeHolderIndex) {
420 if (dropIndex != placeHolderIndex) {
411 helper.insertPlaceHolder(m_Layout, dropIndex);
421 helper.insertPlaceHolder(m_Layout, dropIndex, m_PlaceHolderType,
422 m_PlaceHolderText);
412 }
423 }
413
424
414 helper.setHightlightedDragWidget(nullptr);
425 helper.setHightlightedDragWidget(nullptr);
415 }
426 }
416 else if (canMerge && dragWidgetHovered) {
427 else if (canMerge && dragWidgetHovered) {
417 // drop on the middle -> merge
428 // drop on the middle -> merge
418 if (hasPlaceHolder()) {
429 if (hasPlaceHolder()) {
419 helper.removePlaceHolder();
430 helper.removePlaceHolder();
420 }
431 }
421
432
422 helper.setHightlightedDragWidget(dragWidgetHovered);
433 helper.setHightlightedDragWidget(dragWidgetHovered);
423 }
434 }
424 else {
435 else {
425 qCWarning(LOG_VisualizationDragDropContainer()) << tr(
436 qCWarning(LOG_VisualizationDragDropContainer())
426 "VisualizationDragDropContainer::findPlaceHolderPosition, no valid drop "
437 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no valid drop "
427 "action.");
438 "action.");
428 Q_ASSERT(false);
439 Q_ASSERT(false);
429 }
440 }
430 }
441 }
431 else {
442 else {
432 qCWarning(LOG_VisualizationDragDropContainer())
443 qCWarning(LOG_VisualizationDragDropContainer())
433 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no widget "
444 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no widget "
434 "found in the "
445 "found in the "
435 "container");
446 "container");
436 }
447 }
437 }
448 }
438 else {
449 else {
439 // the mouse is hover the placeHolder
450 // the mouse is hover the placeHolder
440 // Do nothing
451 // Do nothing
441 }
452 }
442 }
453 }
@@ -1,307 +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 "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");
72 ui->dragDropContainer->layout()->setContentsMargins(0, 0, 0, 5);
71 ui->dragDropContainer->addAcceptedMimeType(
73 ui->dragDropContainer->addAcceptedMimeType(
72 MIME_TYPE_GRAPH, VisualizationDragDropContainer::DropBehavior::Inserted);
74 MIME_TYPE_GRAPH, VisualizationDragDropContainer::DropBehavior::Inserted);
73 ui->dragDropContainer->addAcceptedMimeType(
75 ui->dragDropContainer->addAcceptedMimeType(
74 MIME_TYPE_ZONE, VisualizationDragDropContainer::DropBehavior::Inserted);
76 MIME_TYPE_ZONE, VisualizationDragDropContainer::DropBehavior::Inserted);
75 ui->dragDropContainer->addAcceptedMimeType(
77 ui->dragDropContainer->addAcceptedMimeType(
76 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::Inserted);
78 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::Inserted);
77
79
78 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
80 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
79 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
81 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
80 ui->dragDropContainer);
82 ui->dragDropContainer);
81 });
83 });
82
84
83 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
85 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
84 &VisualizationTabWidget::dropMimeData);
86 &VisualizationTabWidget::dropMimeData);
85
87
86 sqpApp->dragDropHelper().addDragDropScrollArea(ui->scrollArea);
88 sqpApp->dragDropHelper().addDragDropScrollArea(ui->scrollArea);
87
89
88 // Widget is deleted when closed
90 // Widget is deleted when closed
89 setAttribute(Qt::WA_DeleteOnClose);
91 setAttribute(Qt::WA_DeleteOnClose);
90 }
92 }
91
93
92 VisualizationTabWidget::~VisualizationTabWidget()
94 VisualizationTabWidget::~VisualizationTabWidget()
93 {
95 {
94 sqpApp->dragDropHelper().removeDragDropScrollArea(ui->scrollArea);
96 sqpApp->dragDropHelper().removeDragDropScrollArea(ui->scrollArea);
95 delete ui;
97 delete ui;
96 }
98 }
97
99
98 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
100 void VisualizationTabWidget::addZone(VisualizationZoneWidget *zoneWidget)
99 {
101 {
100 ui->dragDropContainer->addDragWidget(zoneWidget);
102 ui->dragDropContainer->addDragWidget(zoneWidget);
101 }
103 }
102
104
103 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget)
105 void VisualizationTabWidget::insertZone(int index, VisualizationZoneWidget *zoneWidget)
104 {
106 {
105 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
107 ui->dragDropContainer->insertDragWidget(index, zoneWidget);
106 }
108 }
107
109
108 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
110 VisualizationZoneWidget *VisualizationTabWidget::createZone(std::shared_ptr<Variable> variable)
109 {
111 {
110 return createZone({variable}, -1);
112 return createZone({variable}, -1);
111 }
113 }
112
114
113 VisualizationZoneWidget *
115 VisualizationZoneWidget *
114 VisualizationTabWidget::createZone(const QList<std::shared_ptr<Variable> > &variables, int index)
116 VisualizationTabWidget::createZone(const QList<std::shared_ptr<Variable> > &variables, int index)
115 {
117 {
116 auto zoneWidget = createEmptyZone(index);
118 auto zoneWidget = createEmptyZone(index);
117
119
118 // Creates a new graph into the zone
120 // Creates a new graph into the zone
119 zoneWidget->createGraph(variables, index);
121 zoneWidget->createGraph(variables, index);
120
122
121 return zoneWidget;
123 return zoneWidget;
122 }
124 }
123
125
124 VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index)
126 VisualizationZoneWidget *VisualizationTabWidget::createEmptyZone(int index)
125 {
127 {
126 auto zoneWidget
128 auto zoneWidget
127 = new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this};
129 = new VisualizationZoneWidget{defaultZoneName(*ui->dragDropContainer->layout()), this};
128 this->insertZone(index, zoneWidget);
130 this->insertZone(index, zoneWidget);
129
131
130 return zoneWidget;
132 return zoneWidget;
131 }
133 }
132
134
133 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
135 void VisualizationTabWidget::accept(IVisualizationWidgetVisitor *visitor)
134 {
136 {
135 if (visitor) {
137 if (visitor) {
136 visitor->visitEnter(this);
138 visitor->visitEnter(this);
137
139
138 // 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)
139 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
141 processZones(tabLayout(), [visitor](VisualizationZoneWidget &zoneWidget) {
140 zoneWidget.accept(visitor);
142 zoneWidget.accept(visitor);
141 });
143 });
142
144
143 visitor->visitLeave(this);
145 visitor->visitLeave(this);
144 }
146 }
145 else {
147 else {
146 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");
147 }
149 }
148 }
150 }
149
151
150 bool VisualizationTabWidget::canDrop(const Variable &variable) const
152 bool VisualizationTabWidget::canDrop(const Variable &variable) const
151 {
153 {
152 // A tab can always accomodate a variable
154 // A tab can always accomodate a variable
153 Q_UNUSED(variable);
155 Q_UNUSED(variable);
154 return true;
156 return true;
155 }
157 }
156
158
157 bool VisualizationTabWidget::contains(const Variable &variable) const
159 bool VisualizationTabWidget::contains(const Variable &variable) const
158 {
160 {
159 Q_UNUSED(variable);
161 Q_UNUSED(variable);
160 return false;
162 return false;
161 }
163 }
162
164
163 QString VisualizationTabWidget::name() const
165 QString VisualizationTabWidget::name() const
164 {
166 {
165 return impl->m_Name;
167 return impl->m_Name;
166 }
168 }
167
169
168 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
170 void VisualizationTabWidget::closeEvent(QCloseEvent *event)
169 {
171 {
170 // Closes zones in the tab
172 // Closes zones in the tab
171 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
173 processZones(tabLayout(), [](VisualizationZoneWidget &zoneWidget) { zoneWidget.close(); });
172
174
173 QWidget::closeEvent(event);
175 QWidget::closeEvent(event);
174 }
176 }
175
177
176 QLayout &VisualizationTabWidget::tabLayout() const noexcept
178 QLayout &VisualizationTabWidget::tabLayout() const noexcept
177 {
179 {
178 return *ui->dragDropContainer->layout();
180 return *ui->dragDropContainer->layout();
179 }
181 }
180
182
181 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
183 void VisualizationTabWidget::dropMimeData(int index, const QMimeData *mimeData)
182 {
184 {
183 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
185 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
184 impl->dropGraph(index, this);
186 impl->dropGraph(index, this);
185 }
187 }
186 else if (mimeData->hasFormat(MIME_TYPE_ZONE)) {
188 else if (mimeData->hasFormat(MIME_TYPE_ZONE)) {
187 impl->dropZone(index, this);
189 impl->dropZone(index, this);
188 }
190 }
189 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
191 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
190 auto variables = sqpApp->variableController().variablesForMimeData(
192 auto variables = sqpApp->variableController().variablesForMimeData(
191 mimeData->data(MIME_TYPE_VARIABLE_LIST));
193 mimeData->data(MIME_TYPE_VARIABLE_LIST));
192 impl->dropVariables(variables, index, this);
194 impl->dropVariables(variables, index, this);
193 }
195 }
194 else {
196 else {
195 qCWarning(LOG_VisualizationZoneWidget())
197 qCWarning(LOG_VisualizationZoneWidget())
196 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
198 << tr("VisualizationTabWidget::dropMimeData, unknown MIME data received.");
197 }
199 }
198 }
200 }
199
201
200 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph(
202 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropGraph(
201 int index, VisualizationTabWidget *tabWidget)
203 int index, VisualizationTabWidget *tabWidget)
202 {
204 {
203 auto &helper = sqpApp->dragDropHelper();
205 auto &helper = sqpApp->dragDropHelper();
204
206
205 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
207 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
206 if (!graphWidget) {
208 if (!graphWidget) {
207 qCWarning(LOG_VisualizationZoneWidget())
209 qCWarning(LOG_VisualizationZoneWidget())
208 << tr("VisualizationTabWidget::dropGraph, drop aborted, the dropped graph is not "
210 << tr("VisualizationTabWidget::dropGraph, drop aborted, the dropped graph is not "
209 "found or invalid.");
211 "found or invalid.");
210 Q_ASSERT(false);
212 Q_ASSERT(false);
211 return;
213 return;
212 }
214 }
213
215
214 auto parentDragDropContainer
216 auto parentDragDropContainer
215 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
217 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
216 if (!parentDragDropContainer) {
218 if (!parentDragDropContainer) {
217 qCWarning(LOG_VisualizationZoneWidget())
219 qCWarning(LOG_VisualizationZoneWidget())
218 << tr("VisualizationTabWidget::dropGraph, drop aborted, the parent container of "
220 << tr("VisualizationTabWidget::dropGraph, drop aborted, the parent container of "
219 "the dropped graph is not found.");
221 "the dropped graph is not found.");
220 Q_ASSERT(false);
222 Q_ASSERT(false);
221 return;
223 return;
222 }
224 }
223
225
224 auto nbGraph = parentDragDropContainer->countDragWidget();
226 auto nbGraph = parentDragDropContainer->countDragWidget();
225
227
226 const auto &variables = graphWidget->variables();
228 const auto &variables = graphWidget->variables();
227
229
228 if (!variables.isEmpty()) {
230 if (!variables.isEmpty()) {
229 // Abort the requests for the variables (if any)
231 // Abort the requests for the variables (if any)
230 // 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
231 // for (const auto& var : variables)
233 // for (const auto& var : variables)
232 //{
234 //{
233 // sqpApp->variableController().onAbortProgressRequested(var);
235 // sqpApp->variableController().onAbortProgressRequested(var);
234 //}
236 //}
235
237
236 if (nbGraph == 1) {
238 if (nbGraph == 1) {
237 // 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
238 graphWidget->parentZoneWidget()->close();
240 graphWidget->parentZoneWidget()->close();
239 }
241 }
240 else {
242 else {
241 // Close the graph
243 // Close the graph
242 graphWidget->close();
244 graphWidget->close();
243 }
245 }
244
246
245 tabWidget->createZone(variables, index);
247 tabWidget->createZone(variables, index);
246 }
248 }
247 else {
249 else {
248 // 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
249
251
250 auto parentZoneWidget = graphWidget->parentZoneWidget();
252 auto parentZoneWidget = graphWidget->parentZoneWidget();
251
253
252 parentDragDropContainer->layout()->removeWidget(graphWidget);
254 parentDragDropContainer->layout()->removeWidget(graphWidget);
253
255
254 auto zoneWidget = tabWidget->createEmptyZone(index);
256 auto zoneWidget = tabWidget->createEmptyZone(index);
255 zoneWidget->addGraph(graphWidget);
257 zoneWidget->addGraph(graphWidget);
256
258
257 // Close the old zone if it was the only graph inside
259 // Close the old zone if it was the only graph inside
258 if (nbGraph == 1) {
260 if (nbGraph == 1) {
259 parentZoneWidget->close();
261 parentZoneWidget->close();
260 }
262 }
261 }
263 }
262 }
264 }
263
265
264 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropZone(
266 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropZone(
265 int index, VisualizationTabWidget *tabWidget)
267 int index, VisualizationTabWidget *tabWidget)
266 {
268 {
267 auto &helper = sqpApp->dragDropHelper();
269 auto &helper = sqpApp->dragDropHelper();
268
270
269 auto zoneWidget = qobject_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget());
271 auto zoneWidget = qobject_cast<VisualizationZoneWidget *>(helper.getCurrentDragWidget());
270 if (!zoneWidget) {
272 if (!zoneWidget) {
271 qCWarning(LOG_VisualizationZoneWidget())
273 qCWarning(LOG_VisualizationZoneWidget())
272 << tr("VisualizationTabWidget::dropZone, drop aborted, the dropped zone is not "
274 << tr("VisualizationTabWidget::dropZone, drop aborted, the dropped zone is not "
273 "found or invalid.");
275 "found or invalid.");
274 Q_ASSERT(false);
276 Q_ASSERT(false);
275 return;
277 return;
276 }
278 }
277
279
278 auto parentDragDropContainer
280 auto parentDragDropContainer
279 = qobject_cast<VisualizationDragDropContainer *>(zoneWidget->parentWidget());
281 = qobject_cast<VisualizationDragDropContainer *>(zoneWidget->parentWidget());
280 if (!parentDragDropContainer) {
282 if (!parentDragDropContainer) {
281 qCWarning(LOG_VisualizationZoneWidget())
283 qCWarning(LOG_VisualizationZoneWidget())
282 << tr("VisualizationTabWidget::dropZone, drop aborted, the parent container of "
284 << tr("VisualizationTabWidget::dropZone, drop aborted, the parent container of "
283 "the dropped zone is not found.");
285 "the dropped zone is not found.");
284 Q_ASSERT(false);
286 Q_ASSERT(false);
285 return;
287 return;
286 }
288 }
287
289
288 // Simple move of the zone, no variable operation associated
290 // Simple move of the zone, no variable operation associated
289 parentDragDropContainer->layout()->removeWidget(zoneWidget);
291 parentDragDropContainer->layout()->removeWidget(zoneWidget);
290 tabWidget->ui->dragDropContainer->insertDragWidget(index, zoneWidget);
292 tabWidget->ui->dragDropContainer->insertDragWidget(index, zoneWidget);
291 }
293 }
292
294
293 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables(
295 void VisualizationTabWidget::VisualizationTabWidgetPrivate::dropVariables(
294 const QList<std::shared_ptr<Variable> > &variables, int index,
296 const QList<std::shared_ptr<Variable> > &variables, int index,
295 VisualizationTabWidget *tabWidget)
297 VisualizationTabWidget *tabWidget)
296 {
298 {
297 // 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
298 // compatible variable here
300 // compatible variable here
299 if (variables.count() > 1) {
301 if (variables.count() > 1) {
300 qCWarning(LOG_VisualizationZoneWidget())
302 qCWarning(LOG_VisualizationZoneWidget())
301 << tr("VisualizationTabWidget::dropVariables, dropping multiple variables, operation "
303 << tr("VisualizationTabWidget::dropVariables, dropping multiple variables, operation "
302 "aborted.");
304 "aborted.");
303 return;
305 return;
304 }
306 }
305
307
306 tabWidget->createZone(variables, index);
308 tabWidget->createZone(variables, index);
307 }
309 }
@@ -1,515 +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 <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->addAcceptedMimeType(
105 ui->dragDropContainer->addAcceptedMimeType(
105 MIME_TYPE_GRAPH, VisualizationDragDropContainer::DropBehavior::Inserted);
106 MIME_TYPE_GRAPH, VisualizationDragDropContainer::DropBehavior::Inserted);
106 ui->dragDropContainer->addAcceptedMimeType(
107 ui->dragDropContainer->addAcceptedMimeType(
107 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
108 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
108 ui->dragDropContainer->addAcceptedMimeType(
109 ui->dragDropContainer->addAcceptedMimeType(
109 MIME_TYPE_TIME_RANGE, VisualizationDragDropContainer::DropBehavior::Merged);
110 MIME_TYPE_TIME_RANGE, VisualizationDragDropContainer::DropBehavior::Merged);
110 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
111 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
111 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
112 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
112 ui->dragDropContainer);
113 ui->dragDropContainer);
113 });
114 });
114
115
115 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
116 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
116 &VisualizationZoneWidget::dropMimeData);
117 &VisualizationZoneWidget::dropMimeData);
117 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
118 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
118 &VisualizationZoneWidget::dropMimeDataOnGraph);
119 &VisualizationZoneWidget::dropMimeDataOnGraph);
119
120
120 // 'Close' options : widget is deleted when closed
121 // 'Close' options : widget is deleted when closed
121 setAttribute(Qt::WA_DeleteOnClose);
122 setAttribute(Qt::WA_DeleteOnClose);
122 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
123 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
123 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
124 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
124
125
125 // Synchronisation id
126 // Synchronisation id
126 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
127 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
127 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
128 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
128 }
129 }
129
130
130 VisualizationZoneWidget::~VisualizationZoneWidget()
131 VisualizationZoneWidget::~VisualizationZoneWidget()
131 {
132 {
132 delete ui;
133 delete ui;
133 }
134 }
134
135
135 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
136 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
136 {
137 {
137 // Synchronize new graph with others in the zone
138 // Synchronize new graph with others in the zone
138 impl->m_Synchronizer->addGraph(*graphWidget);
139 impl->m_Synchronizer->addGraph(*graphWidget);
139
140
140 ui->dragDropContainer->addDragWidget(graphWidget);
141 ui->dragDropContainer->addDragWidget(graphWidget);
141 }
142 }
142
143
143 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
144 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
144 {
145 {
145 // Synchronize new graph with others in the zone
146 // Synchronize new graph with others in the zone
146 impl->m_Synchronizer->addGraph(*graphWidget);
147 impl->m_Synchronizer->addGraph(*graphWidget);
147
148
148 ui->dragDropContainer->insertDragWidget(index, graphWidget);
149 ui->dragDropContainer->insertDragWidget(index, graphWidget);
149 }
150 }
150
151
151 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
152 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
152 {
153 {
153 return createGraph(variable, -1);
154 return createGraph(variable, -1);
154 }
155 }
155
156
156 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
157 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
157 int index)
158 int index)
158 {
159 {
159 auto graphWidget
160 auto graphWidget
160 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
161 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
161
162
162
163
163 // Set graph properties
164 // Set graph properties
164 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
165 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
165 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
166 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
166
167
167
168
168 // Lambda to synchronize zone widget
169 // Lambda to synchronize zone widget
169 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
170 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
170 const SqpRange &oldGraphRange) {
171 const SqpRange &oldGraphRange) {
171
172
172 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
173 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
173 auto frameLayout = ui->dragDropContainer->layout();
174 auto frameLayout = ui->dragDropContainer->layout();
174 for (auto i = 0; i < frameLayout->count(); ++i) {
175 for (auto i = 0; i < frameLayout->count(); ++i) {
175 auto graphChild
176 auto graphChild
176 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
177 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
177 if (graphChild && (graphChild != graphWidget)) {
178 if (graphChild && (graphChild != graphWidget)) {
178
179
179 auto graphChildRange = graphChild->graphRange();
180 auto graphChildRange = graphChild->graphRange();
180 switch (zoomType) {
181 switch (zoomType) {
181 case AcquisitionZoomType::ZoomIn: {
182 case AcquisitionZoomType::ZoomIn: {
182 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
183 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
183 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
184 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
184 graphChildRange.m_TStart += deltaLeft;
185 graphChildRange.m_TStart += deltaLeft;
185 graphChildRange.m_TEnd -= deltaRight;
186 graphChildRange.m_TEnd -= deltaRight;
186 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
187 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
187 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
188 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
188 << deltaLeft;
189 << deltaLeft;
189 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
190 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
190 << deltaRight;
191 << deltaRight;
191 qCDebug(LOG_VisualizationZoneWidget())
192 qCDebug(LOG_VisualizationZoneWidget())
192 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
193 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
193
194
194 break;
195 break;
195 }
196 }
196
197
197 case AcquisitionZoomType::ZoomOut: {
198 case AcquisitionZoomType::ZoomOut: {
198 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
199 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
199 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
200 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
200 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
201 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
201 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
202 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
202 << deltaLeft;
203 << deltaLeft;
203 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
204 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
204 << deltaRight;
205 << deltaRight;
205 qCDebug(LOG_VisualizationZoneWidget())
206 qCDebug(LOG_VisualizationZoneWidget())
206 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
207 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
207 graphChildRange.m_TStart -= deltaLeft;
208 graphChildRange.m_TStart -= deltaLeft;
208 graphChildRange.m_TEnd += deltaRight;
209 graphChildRange.m_TEnd += deltaRight;
209 break;
210 break;
210 }
211 }
211 case AcquisitionZoomType::PanRight: {
212 case AcquisitionZoomType::PanRight: {
212 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
213 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
213 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
214 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
214 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
215 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
215 graphChildRange.m_TStart += deltaLeft;
216 graphChildRange.m_TStart += deltaLeft;
216 graphChildRange.m_TEnd += deltaRight;
217 graphChildRange.m_TEnd += deltaRight;
217 qCDebug(LOG_VisualizationZoneWidget())
218 qCDebug(LOG_VisualizationZoneWidget())
218 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
219 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
219 break;
220 break;
220 }
221 }
221 case AcquisitionZoomType::PanLeft: {
222 case AcquisitionZoomType::PanLeft: {
222 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
223 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
223 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
224 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
224 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
225 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
225 graphChildRange.m_TStart -= deltaLeft;
226 graphChildRange.m_TStart -= deltaLeft;
226 graphChildRange.m_TEnd -= deltaRight;
227 graphChildRange.m_TEnd -= deltaRight;
227 break;
228 break;
228 }
229 }
229 case AcquisitionZoomType::Unknown: {
230 case AcquisitionZoomType::Unknown: {
230 qCDebug(LOG_VisualizationZoneWidget())
231 qCDebug(LOG_VisualizationZoneWidget())
231 << tr("Impossible to synchronize: zoom type unknown");
232 << tr("Impossible to synchronize: zoom type unknown");
232 break;
233 break;
233 }
234 }
234 default:
235 default:
235 qCCritical(LOG_VisualizationZoneWidget())
236 qCCritical(LOG_VisualizationZoneWidget())
236 << tr("Impossible to synchronize: zoom type not take into account");
237 << tr("Impossible to synchronize: zoom type not take into account");
237 // No action
238 // No action
238 break;
239 break;
239 }
240 }
240 graphChild->enableAcquisition(false);
241 graphChild->enableAcquisition(false);
241 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
242 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
242 << graphChild->graphRange();
243 << graphChild->graphRange();
243 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
244 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
244 << graphChildRange;
245 << graphChildRange;
245 qCDebug(LOG_VisualizationZoneWidget())
246 qCDebug(LOG_VisualizationZoneWidget())
246 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
247 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
247 graphChild->setGraphRange(graphChildRange);
248 graphChild->setGraphRange(graphChildRange);
248 graphChild->enableAcquisition(true);
249 graphChild->enableAcquisition(true);
249 }
250 }
250 }
251 }
251 };
252 };
252
253
253 // connection for synchronization
254 // connection for synchronization
254 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
255 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
255 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
256 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
256 &VisualizationZoneWidget::onVariableAdded);
257 &VisualizationZoneWidget::onVariableAdded);
257 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
258 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
258 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
259 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
259
260
260 auto range = SqpRange{};
261 auto range = SqpRange{};
261 if (auto firstGraph = impl->firstGraph(this)) {
262 if (auto firstGraph = impl->firstGraph(this)) {
262 // Case of a new graph in a existant zone
263 // Case of a new graph in a existant zone
263 range = firstGraph->graphRange();
264 range = firstGraph->graphRange();
264 }
265 }
265 else {
266 else {
266 // Case of a new graph as the first of the zone
267 // Case of a new graph as the first of the zone
267 range = variable->range();
268 range = variable->range();
268 }
269 }
269
270
270 this->insertGraph(index, graphWidget);
271 this->insertGraph(index, graphWidget);
271
272
272 graphWidget->addVariable(variable, range);
273 graphWidget->addVariable(variable, range);
273
274
274 // get y using variable range
275 // get y using variable range
275 if (auto dataSeries = variable->dataSeries()) {
276 if (auto dataSeries = variable->dataSeries()) {
276 dataSeries->lockRead();
277 dataSeries->lockRead();
277 auto valuesBounds
278 auto valuesBounds
278 = dataSeries->valuesBounds(variable->range().m_TStart, variable->range().m_TEnd);
279 = dataSeries->valuesBounds(variable->range().m_TStart, variable->range().m_TEnd);
279 auto end = dataSeries->cend();
280 auto end = dataSeries->cend();
280 if (valuesBounds.first != end && valuesBounds.second != end) {
281 if (valuesBounds.first != end && valuesBounds.second != end) {
281 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
282 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
282
283
283 auto minValue = rangeValue(valuesBounds.first->minValue());
284 auto minValue = rangeValue(valuesBounds.first->minValue());
284 auto maxValue = rangeValue(valuesBounds.second->maxValue());
285 auto maxValue = rangeValue(valuesBounds.second->maxValue());
285
286
286 graphWidget->setYRange(SqpRange{minValue, maxValue});
287 graphWidget->setYRange(SqpRange{minValue, maxValue});
287 }
288 }
288 dataSeries->unlock();
289 dataSeries->unlock();
289 }
290 }
290
291
291 return graphWidget;
292 return graphWidget;
292 }
293 }
293
294
294 VisualizationGraphWidget *
295 VisualizationGraphWidget *
295 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
296 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
296 {
297 {
297 if (variables.isEmpty()) {
298 if (variables.isEmpty()) {
298 return nullptr;
299 return nullptr;
299 }
300 }
300
301
301 auto graphWidget = createGraph(variables.first(), index);
302 auto graphWidget = createGraph(variables.first(), index);
302 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
303 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
303 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
304 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
304 }
305 }
305
306
306 return graphWidget;
307 return graphWidget;
307 }
308 }
308
309
309 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
310 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
310 {
311 {
311 if (visitor) {
312 if (visitor) {
312 visitor->visitEnter(this);
313 visitor->visitEnter(this);
313
314
314 // 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
315 // action)
316 // action)
316 processGraphs(
317 processGraphs(
317 *ui->dragDropContainer->layout(),
318 *ui->dragDropContainer->layout(),
318 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
319 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
319
320
320 visitor->visitLeave(this);
321 visitor->visitLeave(this);
321 }
322 }
322 else {
323 else {
323 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");
324 }
325 }
325 }
326 }
326
327
327 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
328 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
328 {
329 {
329 // A tab can always accomodate a variable
330 // A tab can always accomodate a variable
330 Q_UNUSED(variable);
331 Q_UNUSED(variable);
331 return true;
332 return true;
332 }
333 }
333
334
334 bool VisualizationZoneWidget::contains(const Variable &variable) const
335 bool VisualizationZoneWidget::contains(const Variable &variable) const
335 {
336 {
336 Q_UNUSED(variable);
337 Q_UNUSED(variable);
337 return false;
338 return false;
338 }
339 }
339
340
340 QString VisualizationZoneWidget::name() const
341 QString VisualizationZoneWidget::name() const
341 {
342 {
342 return ui->zoneNameLabel->text();
343 return ui->zoneNameLabel->text();
343 }
344 }
344
345
345 QMimeData *VisualizationZoneWidget::mimeData() const
346 QMimeData *VisualizationZoneWidget::mimeData() const
346 {
347 {
347 auto mimeData = new QMimeData;
348 auto mimeData = new QMimeData;
348 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
349 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
349
350
350 return mimeData;
351 return mimeData;
351 }
352 }
352
353
353 bool VisualizationZoneWidget::isDragAllowed() const
354 bool VisualizationZoneWidget::isDragAllowed() const
354 {
355 {
355 return true;
356 return true;
356 }
357 }
357
358
358 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
359 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
359 {
360 {
360 // Closes graphs in the zone
361 // Closes graphs in the zone
361 processGraphs(*ui->dragDropContainer->layout(),
362 processGraphs(*ui->dragDropContainer->layout(),
362 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
363 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
363
364
364 // Delete synchronization group from variable controller
365 // Delete synchronization group from variable controller
365 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
366 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
366 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
367 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
367
368
368 QWidget::closeEvent(event);
369 QWidget::closeEvent(event);
369 }
370 }
370
371
371 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
372 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
372 {
373 {
373 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
374 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
374 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
375 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
375 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
376 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
376 }
377 }
377
378
378 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
379 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
379 {
380 {
380 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
381 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
381 Q_ARG(std::shared_ptr<Variable>, variable),
382 Q_ARG(std::shared_ptr<Variable>, variable),
382 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
383 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
383 }
384 }
384
385
385 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
386 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
386 {
387 {
387 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
388 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
388 impl->dropGraph(index, this);
389 impl->dropGraph(index, this);
389 }
390 }
390 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
391 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
391 auto variables = sqpApp->variableController().variablesForMimeData(
392 auto variables = sqpApp->variableController().variablesForMimeData(
392 mimeData->data(MIME_TYPE_VARIABLE_LIST));
393 mimeData->data(MIME_TYPE_VARIABLE_LIST));
393 impl->dropVariables(variables, index, this);
394 impl->dropVariables(variables, index, this);
394 }
395 }
395 else {
396 else {
396 qCWarning(LOG_VisualizationZoneWidget())
397 qCWarning(LOG_VisualizationZoneWidget())
397 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
398 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
398 }
399 }
399 }
400 }
400
401
401 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
402 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
402 const QMimeData *mimeData)
403 const QMimeData *mimeData)
403 {
404 {
404 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
405 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
405 if (!graphWidget) {
406 if (!graphWidget) {
406 qCWarning(LOG_VisualizationZoneWidget())
407 qCWarning(LOG_VisualizationZoneWidget())
407 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
408 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
408 "drop aborted");
409 "drop aborted");
409 Q_ASSERT(false);
410 Q_ASSERT(false);
410 return;
411 return;
411 }
412 }
412
413
413 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
414 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
414 auto variables = sqpApp->variableController().variablesForMimeData(
415 auto variables = sqpApp->variableController().variablesForMimeData(
415 mimeData->data(MIME_TYPE_VARIABLE_LIST));
416 mimeData->data(MIME_TYPE_VARIABLE_LIST));
416 for (const auto &var : variables) {
417 for (const auto &var : variables) {
417 graphWidget->addVariable(var, graphWidget->graphRange());
418 graphWidget->addVariable(var, graphWidget->graphRange());
418 }
419 }
419 }
420 }
420 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
421 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
421 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
422 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
422 graphWidget->setGraphRange(range);
423 graphWidget->setGraphRange(range);
423 }
424 }
424 else {
425 else {
425 qCWarning(LOG_VisualizationZoneWidget())
426 qCWarning(LOG_VisualizationZoneWidget())
426 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
427 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
427 }
428 }
428 }
429 }
429
430
430 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
431 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
431 int index, VisualizationZoneWidget *zoneWidget)
432 int index, VisualizationZoneWidget *zoneWidget)
432 {
433 {
433 auto &helper = sqpApp->dragDropHelper();
434 auto &helper = sqpApp->dragDropHelper();
434
435
435 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
436 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
436 if (!graphWidget) {
437 if (!graphWidget) {
437 qCWarning(LOG_VisualizationZoneWidget())
438 qCWarning(LOG_VisualizationZoneWidget())
438 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
439 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
439 "found or invalid.");
440 "found or invalid.");
440 Q_ASSERT(false);
441 Q_ASSERT(false);
441 return;
442 return;
442 }
443 }
443
444
444 auto parentDragDropContainer
445 auto parentDragDropContainer
445 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
446 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
446 if (!parentDragDropContainer) {
447 if (!parentDragDropContainer) {
447 qCWarning(LOG_VisualizationZoneWidget())
448 qCWarning(LOG_VisualizationZoneWidget())
448 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
449 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
449 "the dropped graph is not found.");
450 "the dropped graph is not found.");
450 Q_ASSERT(false);
451 Q_ASSERT(false);
451 return;
452 return;
452 }
453 }
453
454
454 const auto &variables = graphWidget->variables();
455 const auto &variables = graphWidget->variables();
455
456
456 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
457 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
457 // The drop didn't occur in the same zone
458 // The drop didn't occur in the same zone
458
459
459 // Abort the requests for the variables (if any)
460 // Abort the requests for the variables (if any)
460 // 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
461 // for (const auto& var : variables)
462 // for (const auto& var : variables)
462 //{
463 //{
463 // sqpApp->variableController().onAbortProgressRequested(var);
464 // sqpApp->variableController().onAbortProgressRequested(var);
464 //}
465 //}
465
466
466 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
467 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
467 auto nbGraph = parentDragDropContainer->countDragWidget();
468 auto nbGraph = parentDragDropContainer->countDragWidget();
468 if (nbGraph == 1) {
469 if (nbGraph == 1) {
469 // 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
470 previousParentZoneWidget->close();
471 previousParentZoneWidget->close();
471 }
472 }
472 else {
473 else {
473 // Close the graph
474 // Close the graph
474 graphWidget->close();
475 graphWidget->close();
475 }
476 }
476
477
477 // Creates the new graph in the zone
478 // Creates the new graph in the zone
478 zoneWidget->createGraph(variables, index);
479 zoneWidget->createGraph(variables, index);
479 }
480 }
480 else {
481 else {
481 // 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
482 // Simple move of the graph, no variable operation associated
483 // Simple move of the graph, no variable operation associated
483 parentDragDropContainer->layout()->removeWidget(graphWidget);
484 parentDragDropContainer->layout()->removeWidget(graphWidget);
484
485
485 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
486 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
486 // The graph is empty and dropped in a different zone.
487 // The graph is empty and dropped in a different zone.
487 // 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).
488 auto layout = zoneWidget->ui->dragDropContainer->layout();
489 auto layout = zoneWidget->ui->dragDropContainer->layout();
489 if (layout->count() > 0) {
490 if (layout->count() > 0) {
490 if (auto visualizationGraphWidget
491 if (auto visualizationGraphWidget
491 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
492 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
492 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
493 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
493 }
494 }
494 }
495 }
495 }
496 }
496
497
497 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
498 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
498 }
499 }
499 }
500 }
500
501
501 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
502 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
502 const QList<std::shared_ptr<Variable> > &variables, int index,
503 const QList<std::shared_ptr<Variable> > &variables, int index,
503 VisualizationZoneWidget *zoneWidget)
504 VisualizationZoneWidget *zoneWidget)
504 {
505 {
505 // 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
506 // compatible variable here
507 // compatible variable here
507 if (variables.count() > 1) {
508 if (variables.count() > 1) {
508 qCWarning(LOG_VisualizationZoneWidget())
509 qCWarning(LOG_VisualizationZoneWidget())
509 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
510 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
510 "aborted.");
511 "aborted.");
511 return;
512 return;
512 }
513 }
513
514
514 zoneWidget->createGraph(variables, index);
515 zoneWidget->createGraph(variables, index);
515 }
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