##// END OF EJS Templates
Move the GRAPH_MINIMUM_HEIGHT constant in a place accessible everywhere and use it in the drag&drop
trabillard -
r853:1ba93038a6bd
parent child
Show More
@@ -0,0 +1,7
1 #ifndef SCIQLOP_VISUALIZATIONDEF_H
2 #define SCIQLOP_VISUALIZATIONDEF_H
3
4 /// Minimum height for graph added in zones (in pixels)
5 extern const int GRAPH_MINIMUM_HEIGHT;
6
7 #endif // SCIQLOP_VISUALIZATIONDEF_H
@@ -0,0 +1,3
1 #include "Common/VisualizationDef.h"
2
3 const int GRAPH_MINIMUM_HEIGHT = 300;
@@ -1,289 +1,289
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/VariableController.h"
8 #include "Variable/VariableController.h"
9
9
10 #include "Common/MimeTypesDef.h"
10 #include "Common/MimeTypesDef.h"
11 #include "Common/VisualizationDef.h"
11 #include "Common/VisualizationDef.h"
12
12
13 #include <QDir>
13 #include <QDir>
14 #include <QDragEnterEvent>
14 #include <QDragEnterEvent>
15 #include <QDragMoveEvent>
15 #include <QDragMoveEvent>
16 #include <QScrollArea>
16 #include <QScrollArea>
17 #include <QScrollBar>
17 #include <QScrollBar>
18 #include <QTimer>
18 #include <QTimer>
19 #include <QVBoxLayout>
19 #include <QVBoxLayout>
20
20
21 const int SCROLL_SPEED = 5;
21 const int SCROLL_SPEED = 5;
22 const int SCROLL_ZONE_SIZE = 50;
22 const int SCROLL_ZONE_SIZE = 50;
23
23
24 Q_LOGGING_CATEGORY(LOG_DragDropHelper, "DragDrophelper")
24 Q_LOGGING_CATEGORY(LOG_DragDropHelper, "DragDrophelper")
25
25
26 struct DragDropScroller::DragDropScrollerPrivate {
26 struct DragDropScroller::DragDropScrollerPrivate {
27
27
28 QList<QScrollArea *> m_ScrollAreas;
28 QList<QScrollArea *> m_ScrollAreas;
29 QScrollArea *m_CurrentScrollArea = nullptr;
29 QScrollArea *m_CurrentScrollArea = nullptr;
30 std::unique_ptr<QTimer> m_Timer = nullptr;
30 std::unique_ptr<QTimer> m_Timer = nullptr;
31
31
32
32
33 enum class ScrollDirection { up, down, unknown };
33 enum class ScrollDirection { up, down, unknown };
34 ScrollDirection m_Direction = ScrollDirection::unknown;
34 ScrollDirection m_Direction = ScrollDirection::unknown;
35
35
36 explicit DragDropScrollerPrivate() : m_Timer{std::make_unique<QTimer>()}
36 explicit DragDropScrollerPrivate() : m_Timer{std::make_unique<QTimer>()}
37 {
37 {
38 m_Timer->setInterval(0);
38 m_Timer->setInterval(0);
39 }
39 }
40 };
40 };
41
41
42 DragDropScroller::DragDropScroller(QObject *parent)
42 DragDropScroller::DragDropScroller(QObject *parent)
43 : QObject{parent}, impl{spimpl::make_unique_impl<DragDropScrollerPrivate>()}
43 : QObject{parent}, impl{spimpl::make_unique_impl<DragDropScrollerPrivate>()}
44 {
44 {
45 connect(impl->m_Timer.get(), &QTimer::timeout, this, &DragDropScroller::onTimer);
45 connect(impl->m_Timer.get(), &QTimer::timeout, this, &DragDropScroller::onTimer);
46 }
46 }
47
47
48 void DragDropScroller::addScrollArea(QScrollArea *scrollArea)
48 void DragDropScroller::addScrollArea(QScrollArea *scrollArea)
49 {
49 {
50 impl->m_ScrollAreas << scrollArea;
50 impl->m_ScrollAreas << scrollArea;
51 scrollArea->viewport()->setAcceptDrops(true);
51 scrollArea->viewport()->setAcceptDrops(true);
52 }
52 }
53
53
54 void DragDropScroller::removeScrollArea(QScrollArea *scrollArea)
54 void DragDropScroller::removeScrollArea(QScrollArea *scrollArea)
55 {
55 {
56 impl->m_ScrollAreas.removeAll(scrollArea);
56 impl->m_ScrollAreas.removeAll(scrollArea);
57 scrollArea->viewport()->setAcceptDrops(false);
57 scrollArea->viewport()->setAcceptDrops(false);
58 }
58 }
59
59
60 bool DragDropScroller::eventFilter(QObject *obj, QEvent *event)
60 bool DragDropScroller::eventFilter(QObject *obj, QEvent *event)
61 {
61 {
62 if (event->type() == QEvent::DragMove) {
62 if (event->type() == QEvent::DragMove) {
63 auto w = static_cast<QWidget *>(obj);
63 auto w = static_cast<QWidget *>(obj);
64
64
65 if (impl->m_CurrentScrollArea && impl->m_CurrentScrollArea->isAncestorOf(w)) {
65 if (impl->m_CurrentScrollArea && impl->m_CurrentScrollArea->isAncestorOf(w)) {
66 auto moveEvent = static_cast<QDragMoveEvent *>(event);
66 auto moveEvent = static_cast<QDragMoveEvent *>(event);
67
67
68 auto pos = moveEvent->pos();
68 auto pos = moveEvent->pos();
69 if (impl->m_CurrentScrollArea->viewport() != w) {
69 if (impl->m_CurrentScrollArea->viewport() != w) {
70 auto globalPos = w->mapToGlobal(moveEvent->pos());
70 auto globalPos = w->mapToGlobal(moveEvent->pos());
71 pos = impl->m_CurrentScrollArea->viewport()->mapFromGlobal(globalPos);
71 pos = impl->m_CurrentScrollArea->viewport()->mapFromGlobal(globalPos);
72 }
72 }
73
73
74 auto isInTopZone = pos.y() > impl->m_CurrentScrollArea->viewport()->size().height()
74 auto isInTopZone = pos.y() > impl->m_CurrentScrollArea->viewport()->size().height()
75 - SCROLL_ZONE_SIZE;
75 - SCROLL_ZONE_SIZE;
76 auto isInBottomZone = pos.y() < SCROLL_ZONE_SIZE;
76 auto isInBottomZone = pos.y() < SCROLL_ZONE_SIZE;
77
77
78 if (!isInTopZone && !isInBottomZone) {
78 if (!isInTopZone && !isInBottomZone) {
79 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
79 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
80 impl->m_Timer->stop();
80 impl->m_Timer->stop();
81 }
81 }
82 else if (!impl->m_Timer->isActive()) {
82 else if (!impl->m_Timer->isActive()) {
83 impl->m_Direction = isInTopZone ? DragDropScrollerPrivate::ScrollDirection::up
83 impl->m_Direction = isInTopZone ? DragDropScrollerPrivate::ScrollDirection::up
84 : DragDropScrollerPrivate::ScrollDirection::down;
84 : DragDropScrollerPrivate::ScrollDirection::down;
85 impl->m_Timer->start();
85 impl->m_Timer->start();
86 }
86 }
87 }
87 }
88 }
88 }
89 else if (event->type() == QEvent::DragEnter) {
89 else if (event->type() == QEvent::DragEnter) {
90 auto w = static_cast<QWidget *>(obj);
90 auto w = static_cast<QWidget *>(obj);
91
91
92 for (auto scrollArea : impl->m_ScrollAreas) {
92 for (auto scrollArea : impl->m_ScrollAreas) {
93 if (impl->m_CurrentScrollArea != scrollArea && scrollArea->isAncestorOf(w)) {
93 if (impl->m_CurrentScrollArea != scrollArea && scrollArea->isAncestorOf(w)) {
94 auto enterEvent = static_cast<QDragEnterEvent *>(event);
94 auto enterEvent = static_cast<QDragEnterEvent *>(event);
95 enterEvent->acceptProposedAction();
95 enterEvent->acceptProposedAction();
96 enterEvent->setDropAction(Qt::IgnoreAction);
96 enterEvent->setDropAction(Qt::IgnoreAction);
97 impl->m_CurrentScrollArea = scrollArea;
97 impl->m_CurrentScrollArea = scrollArea;
98 break;
98 break;
99 }
99 }
100 }
100 }
101 }
101 }
102 else if (event->type() == QEvent::DragLeave) {
102 else if (event->type() == QEvent::DragLeave) {
103 if (impl->m_CurrentScrollArea) {
103 if (impl->m_CurrentScrollArea) {
104 if (!QRect(QPoint(), impl->m_CurrentScrollArea->size())
104 if (!QRect(QPoint(), impl->m_CurrentScrollArea->size())
105 .contains(impl->m_CurrentScrollArea->mapFromGlobal(QCursor::pos()))) {
105 .contains(impl->m_CurrentScrollArea->mapFromGlobal(QCursor::pos()))) {
106 impl->m_CurrentScrollArea = nullptr;
106 impl->m_CurrentScrollArea = nullptr;
107 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
107 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
108 impl->m_Timer->stop();
108 impl->m_Timer->stop();
109 }
109 }
110 }
110 }
111 }
111 }
112 else if (event->type() == QEvent::Drop) {
112 else if (event->type() == QEvent::Drop) {
113 if (impl->m_CurrentScrollArea) {
113 if (impl->m_CurrentScrollArea) {
114 impl->m_CurrentScrollArea = nullptr;
114 impl->m_CurrentScrollArea = nullptr;
115 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
115 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
116 impl->m_Timer->stop();
116 impl->m_Timer->stop();
117 }
117 }
118 }
118 }
119
119
120 return false;
120 return false;
121 }
121 }
122
122
123 void DragDropScroller::onTimer()
123 void DragDropScroller::onTimer()
124 {
124 {
125 if (impl->m_CurrentScrollArea) {
125 if (impl->m_CurrentScrollArea) {
126 auto mvt = 0;
126 auto mvt = 0;
127 switch (impl->m_Direction) {
127 switch (impl->m_Direction) {
128 case DragDropScrollerPrivate::ScrollDirection::up:
128 case DragDropScrollerPrivate::ScrollDirection::up:
129 mvt = SCROLL_SPEED;
129 mvt = SCROLL_SPEED;
130 break;
130 break;
131 case DragDropScrollerPrivate::ScrollDirection::down:
131 case DragDropScrollerPrivate::ScrollDirection::down:
132 mvt = -SCROLL_SPEED;
132 mvt = -SCROLL_SPEED;
133 break;
133 break;
134 default:
134 default:
135 break;
135 break;
136 }
136 }
137
137
138 impl->m_CurrentScrollArea->verticalScrollBar()->setValue(
138 impl->m_CurrentScrollArea->verticalScrollBar()->setValue(
139 impl->m_CurrentScrollArea->verticalScrollBar()->value() + mvt);
139 impl->m_CurrentScrollArea->verticalScrollBar()->value() + mvt);
140 }
140 }
141 }
141 }
142
142
143 struct DragDropHelper::DragDropHelperPrivate {
143 struct DragDropHelper::DragDropHelperPrivate {
144
144
145 VisualizationDragWidget *m_CurrentDragWidget = nullptr;
145 VisualizationDragWidget *m_CurrentDragWidget = nullptr;
146 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
146 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
147 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
147 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
148 QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using
148 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.
149 // QTemporaryFile to have a name which is not generated.
150
150
151 explicit DragDropHelperPrivate()
151 explicit DragDropHelperPrivate()
152 : m_PlaceHolder{std::make_unique<QWidget>()},
152 : m_PlaceHolder{std::make_unique<QWidget>()},
153 m_DragDropScroller{std::make_unique<DragDropScroller>()}
153 m_DragDropScroller{std::make_unique<DragDropScroller>()}
154 {
154 {
155 m_PlaceHolder->setStyleSheet("background-color: #BBD5EE; border:2px solid #2A7FD4");
155 m_PlaceHolder->setStyleSheet("background-color: #BBD5EE; border:2px solid #2A7FD4");
156 sqpApp->installEventFilter(m_DragDropScroller.get());
156 sqpApp->installEventFilter(m_DragDropScroller.get());
157
157
158
158
159 m_ImageTempUrl = QDir::temp().absoluteFilePath("Scqlop_graph.png");
159 m_ImageTempUrl = QDir::temp().absoluteFilePath("Scqlop_graph.png");
160 }
160 }
161
161
162 void preparePlaceHolder() const
162 void preparePlaceHolder() const
163 {
163 {
164 if (m_CurrentDragWidget) {
164 if (m_CurrentDragWidget) {
165 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
165 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
166 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
166 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
167 }
167 }
168 else {
168 else {
169 // Configuration of the placeHolder when there is no dragWidget
169 // Configuration of the placeHolder when there is no dragWidget
170 // (for instance with a drag from a variable)
170 // (for instance with a drag from a variable)
171
171
172 m_PlaceHolder->setMinimumSize(400, 300);
172 m_PlaceHolder->setMinimumSize(0, GRAPH_MINIMUM_HEIGHT);
173 m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
173 m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
174 }
174 }
175 }
175 }
176 };
176 };
177
177
178
178
179 DragDropHelper::DragDropHelper() : impl{spimpl::make_unique_impl<DragDropHelperPrivate>()}
179 DragDropHelper::DragDropHelper() : impl{spimpl::make_unique_impl<DragDropHelperPrivate>()}
180 {
180 {
181 }
181 }
182
182
183 DragDropHelper::~DragDropHelper()
183 DragDropHelper::~DragDropHelper()
184 {
184 {
185 QFile::remove(impl->m_ImageTempUrl);
185 QFile::remove(impl->m_ImageTempUrl);
186 }
186 }
187
187
188 void DragDropHelper::resetDragAndDrop()
188 void DragDropHelper::resetDragAndDrop()
189 {
189 {
190 setCurrentDragWidget(nullptr);
190 setCurrentDragWidget(nullptr);
191 }
191 }
192
192
193 void DragDropHelper::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
193 void DragDropHelper::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
194 {
194 {
195 impl->m_CurrentDragWidget = dragWidget;
195 impl->m_CurrentDragWidget = dragWidget;
196 }
196 }
197
197
198 VisualizationDragWidget *DragDropHelper::getCurrentDragWidget() const
198 VisualizationDragWidget *DragDropHelper::getCurrentDragWidget() const
199 {
199 {
200 return impl->m_CurrentDragWidget;
200 return impl->m_CurrentDragWidget;
201 }
201 }
202
202
203
203
204 QWidget &DragDropHelper::placeHolder() const
204 QWidget &DragDropHelper::placeHolder() const
205 {
205 {
206 return *impl->m_PlaceHolder;
206 return *impl->m_PlaceHolder;
207 }
207 }
208
208
209 void DragDropHelper::insertPlaceHolder(QVBoxLayout *layout, int index)
209 void DragDropHelper::insertPlaceHolder(QVBoxLayout *layout, int index)
210 {
210 {
211 removePlaceHolder();
211 removePlaceHolder();
212 impl->preparePlaceHolder();
212 impl->preparePlaceHolder();
213 layout->insertWidget(index, impl->m_PlaceHolder.get());
213 layout->insertWidget(index, impl->m_PlaceHolder.get());
214 impl->m_PlaceHolder->show();
214 impl->m_PlaceHolder->show();
215 }
215 }
216
216
217 void DragDropHelper::removePlaceHolder()
217 void DragDropHelper::removePlaceHolder()
218 {
218 {
219 auto parentWidget = impl->m_PlaceHolder->parentWidget();
219 auto parentWidget = impl->m_PlaceHolder->parentWidget();
220 if (parentWidget) {
220 if (parentWidget) {
221 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
221 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
222 impl->m_PlaceHolder->setParent(nullptr);
222 impl->m_PlaceHolder->setParent(nullptr);
223 impl->m_PlaceHolder->hide();
223 impl->m_PlaceHolder->hide();
224 }
224 }
225 }
225 }
226
226
227 bool DragDropHelper::isPlaceHolderSet() const
227 bool DragDropHelper::isPlaceHolderSet() const
228 {
228 {
229 return impl->m_PlaceHolder->parentWidget();
229 return impl->m_PlaceHolder->parentWidget();
230 }
230 }
231
231
232 void DragDropHelper::addDragDropScrollArea(QScrollArea *scrollArea)
232 void DragDropHelper::addDragDropScrollArea(QScrollArea *scrollArea)
233 {
233 {
234 impl->m_DragDropScroller->addScrollArea(scrollArea);
234 impl->m_DragDropScroller->addScrollArea(scrollArea);
235 }
235 }
236
236
237 void DragDropHelper::removeDragDropScrollArea(QScrollArea *scrollArea)
237 void DragDropHelper::removeDragDropScrollArea(QScrollArea *scrollArea)
238 {
238 {
239 impl->m_DragDropScroller->removeScrollArea(scrollArea);
239 impl->m_DragDropScroller->removeScrollArea(scrollArea);
240 }
240 }
241
241
242 QUrl DragDropHelper::imageTemporaryUrl(const QImage &image) const
242 QUrl DragDropHelper::imageTemporaryUrl(const QImage &image) const
243 {
243 {
244 image.save(impl->m_ImageTempUrl);
244 image.save(impl->m_ImageTempUrl);
245 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
245 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
246 }
246 }
247
247
248 bool DragDropHelper::checkMimeDataForVisualization(const QMimeData *mimeData,
248 bool DragDropHelper::checkMimeDataForVisualization(const QMimeData *mimeData,
249 VisualizationDragDropContainer *dropContainer)
249 VisualizationDragDropContainer *dropContainer)
250 {
250 {
251 auto result = true;
251 auto result = true;
252
252
253 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
253 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
254 auto variables = sqpApp->variableController().variablesForMimeData(
254 auto variables = sqpApp->variableController().variablesForMimeData(
255 mimeData->data(MIME_TYPE_VARIABLE_LIST));
255 mimeData->data(MIME_TYPE_VARIABLE_LIST));
256
256
257 if (variables.count() == 1) {
257 if (variables.count() == 1) {
258 // Check that the viariable is not already in a graph
258 // Check that the viariable is not already in a graph
259
259
260 // Search for the top level VisualizationWidget
260 // Search for the top level VisualizationWidget
261 auto parent = dropContainer->parentWidget();
261 auto parent = dropContainer->parentWidget();
262 while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) {
262 while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) {
263 parent = parent->parentWidget();
263 parent = parent->parentWidget();
264 }
264 }
265
265
266 if (parent) {
266 if (parent) {
267 auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
267 auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
268
268
269 FindVariableOperation findVariableOperation{variables.first()};
269 FindVariableOperation findVariableOperation{variables.first()};
270 visualizationWidget->accept(&findVariableOperation);
270 visualizationWidget->accept(&findVariableOperation);
271 auto variableContainers = findVariableOperation.result();
271 auto variableContainers = findVariableOperation.result();
272 if (!variableContainers.empty()) {
272 if (!variableContainers.empty()) {
273 result = false;
273 result = false;
274 }
274 }
275 }
275 }
276 else {
276 else {
277 qCWarning(LOG_DragDropHelper()) << QObject::tr(
277 qCWarning(LOG_DragDropHelper()) << QObject::tr(
278 "DragDropHelper::checkMimeDataForVisualization, the parent "
278 "DragDropHelper::checkMimeDataForVisualization, the parent "
279 "VisualizationWidget cannot be found.");
279 "VisualizationWidget cannot be found.");
280 result = false;
280 result = false;
281 }
281 }
282 }
282 }
283 else {
283 else {
284 result = false;
284 result = false;
285 }
285 }
286 }
286 }
287
287
288 return result;
288 return result;
289 }
289 }
@@ -1,359 +1,362
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"
7
6 #include <QDrag>
8 #include <QDrag>
7 #include <QDragEnterEvent>
9 #include <QDragEnterEvent>
8 #include <QVBoxLayout>
10 #include <QVBoxLayout>
9
11
10 #include <cmath>
12 #include <cmath>
11 #include <memory>
13 #include <memory>
12
14
13 Q_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer, "VisualizationDragDropContainer")
15 Q_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer, "VisualizationDragDropContainer")
14
16
15 struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate {
17 struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate {
16
18
17 QVBoxLayout *m_Layout;
19 QVBoxLayout *m_Layout;
18 QStringList m_AcceptedMimeTypes;
20 QStringList m_AcceptedMimeTypes;
19 QStringList m_MergeAllowedMimeTypes;
21 QStringList m_MergeAllowedMimeTypes;
20 VisualizationDragDropContainer::AcceptMimeDataFunction m_AcceptMimeDataFun
22 VisualizationDragDropContainer::AcceptMimeDataFunction m_AcceptMimeDataFun
21 = [](auto mimeData) { return true; };
23 = [](auto mimeData) { return true; };
22
24
23 explicit VisualizationDragDropContainerPrivate(QWidget *widget)
25 explicit VisualizationDragDropContainerPrivate(QWidget *widget)
24 {
26 {
25 m_Layout = new QVBoxLayout(widget);
27 m_Layout = new QVBoxLayout(widget);
26 m_Layout->setContentsMargins(0, 0, 0, 0);
28 m_Layout->setContentsMargins(0, 0, 0, 0);
27 }
29 }
28
30
29 bool acceptMimeData(const QMimeData *data) const
31 bool acceptMimeData(const QMimeData *data) const
30 {
32 {
31 for (const auto &type : m_AcceptedMimeTypes) {
33 for (const auto &type : m_AcceptedMimeTypes) {
32 if (data->hasFormat(type) && m_AcceptMimeDataFun(data)) {
34 if (data->hasFormat(type) && m_AcceptMimeDataFun(data)) {
33 return true;
35 return true;
34 }
36 }
35 }
37 }
36
38
37 return false;
39 return false;
38 }
40 }
39
41
40 bool allowMergeMimeData(const QMimeData *data) const
42 bool allowMergeMimeData(const QMimeData *data) const
41 {
43 {
42 for (const auto &type : m_MergeAllowedMimeTypes) {
44 for (const auto &type : m_MergeAllowedMimeTypes) {
43 if (data->hasFormat(type)) {
45 if (data->hasFormat(type)) {
44 return true;
46 return true;
45 }
47 }
46 }
48 }
47
49
48 return false;
50 return false;
49 }
51 }
50
52
51 bool hasPlaceHolder() const
53 bool hasPlaceHolder() const
52 {
54 {
53 return sqpApp->dragDropHelper().placeHolder().parentWidget() == m_Layout->parentWidget();
55 return sqpApp->dragDropHelper().placeHolder().parentWidget() == m_Layout->parentWidget();
54 }
56 }
55
57
56 VisualizationDragWidget *getChildDragWidgetAt(QWidget *parent, const QPoint &pos) const
58 VisualizationDragWidget *getChildDragWidgetAt(QWidget *parent, const QPoint &pos) const
57 {
59 {
58 VisualizationDragWidget *dragWidget = nullptr;
60 VisualizationDragWidget *dragWidget = nullptr;
59
61
60 for (auto child : parent->children()) {
62 for (auto child : parent->children()) {
61 auto widget = qobject_cast<VisualizationDragWidget *>(child);
63 auto widget = qobject_cast<VisualizationDragWidget *>(child);
62 if (widget && widget->isVisible()) {
64 if (widget && widget->isVisible()) {
63 if (widget->frameGeometry().contains(pos)) {
65 if (widget->frameGeometry().contains(pos)) {
64 dragWidget = widget;
66 dragWidget = widget;
65 break;
67 break;
66 }
68 }
67 }
69 }
68 }
70 }
69
71
70 return dragWidget;
72 return dragWidget;
71 }
73 }
72
74
73 bool cursorIsInContainer(QWidget *container) const
75 bool cursorIsInContainer(QWidget *container) const
74 {
76 {
75 auto adustNum = 18; // to be safe, in case of scrollbar on the side
77 auto adustNum = 18; // to be safe, in case of scrollbar on the side
76 auto containerRect = QRect(QPoint(), container->contentsRect().size())
78 auto containerRect = QRect(QPoint(), container->contentsRect().size())
77 .adjusted(adustNum, adustNum, -adustNum, -adustNum);
79 .adjusted(adustNum, adustNum, -adustNum, -adustNum);
78 return containerRect.contains(container->mapFromGlobal(QCursor::pos()));
80 return containerRect.contains(container->mapFromGlobal(QCursor::pos()));
79 }
81 }
80 };
82 };
81
83
82 VisualizationDragDropContainer::VisualizationDragDropContainer(QWidget *parent)
84 VisualizationDragDropContainer::VisualizationDragDropContainer(QWidget *parent)
83 : QWidget{parent},
85 : QWidget{parent},
84 impl{spimpl::make_unique_impl<VisualizationDragDropContainerPrivate>(this)}
86 impl{spimpl::make_unique_impl<VisualizationDragDropContainerPrivate>(this)}
85 {
87 {
86 setAcceptDrops(true);
88 setAcceptDrops(true);
87 }
89 }
88
90
89 void VisualizationDragDropContainer::addDragWidget(VisualizationDragWidget *dragWidget)
91 void VisualizationDragDropContainer::addDragWidget(VisualizationDragWidget *dragWidget)
90 {
92 {
91 impl->m_Layout->addWidget(dragWidget);
93 impl->m_Layout->addWidget(dragWidget);
92 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
94 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
93 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
95 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
94 &VisualizationDragDropContainer::startDrag);
96 &VisualizationDragDropContainer::startDrag);
95 }
97 }
96
98
97 void VisualizationDragDropContainer::insertDragWidget(int index,
99 void VisualizationDragDropContainer::insertDragWidget(int index,
98 VisualizationDragWidget *dragWidget)
100 VisualizationDragWidget *dragWidget)
99 {
101 {
100 impl->m_Layout->insertWidget(index, dragWidget);
102 impl->m_Layout->insertWidget(index, dragWidget);
101 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
103 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
102 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
104 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
103 &VisualizationDragDropContainer::startDrag);
105 &VisualizationDragDropContainer::startDrag);
104 }
106 }
105
107
106 void VisualizationDragDropContainer::setAcceptedMimeTypes(const QStringList &mimeTypes)
108 void VisualizationDragDropContainer::setAcceptedMimeTypes(const QStringList &mimeTypes)
107 {
109 {
108 impl->m_AcceptedMimeTypes = mimeTypes;
110 impl->m_AcceptedMimeTypes = mimeTypes;
109 }
111 }
110
112
111 void VisualizationDragDropContainer::setMergeAllowedMimeTypes(const QStringList &mimeTypes)
113 void VisualizationDragDropContainer::setMergeAllowedMimeTypes(const QStringList &mimeTypes)
112 {
114 {
113 impl->m_MergeAllowedMimeTypes = mimeTypes;
115 impl->m_MergeAllowedMimeTypes = mimeTypes;
114 }
116 }
115
117
116 int VisualizationDragDropContainer::countDragWidget() const
118 int VisualizationDragDropContainer::countDragWidget() const
117 {
119 {
118 auto nbGraph = 0;
120 auto nbGraph = 0;
119 for (auto child : children()) {
121 for (auto child : children()) {
120 if (qobject_cast<VisualizationDragWidget *>(child)) {
122 if (qobject_cast<VisualizationDragWidget *>(child)) {
121 nbGraph += 1;
123 nbGraph += 1;
122 }
124 }
123 }
125 }
124
126
125 return nbGraph;
127 return nbGraph;
126 }
128 }
127
129
128 void VisualizationDragDropContainer::setAcceptMimeDataFunction(
130 void VisualizationDragDropContainer::setAcceptMimeDataFunction(
129 VisualizationDragDropContainer::AcceptMimeDataFunction fun)
131 VisualizationDragDropContainer::AcceptMimeDataFunction fun)
130 {
132 {
131 impl->m_AcceptMimeDataFun = fun;
133 impl->m_AcceptMimeDataFun = fun;
132 }
134 }
133
135
134 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidget,
136 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidget,
135 const QPoint &dragPosition)
137 const QPoint &dragPosition)
136 {
138 {
137 auto &helper = sqpApp->dragDropHelper();
139 auto &helper = sqpApp->dragDropHelper();
138 helper.resetDragAndDrop();
140 helper.resetDragAndDrop();
139
141
140 // Note: The management of the drag object is done by Qt
142 // Note: The management of the drag object is done by Qt
141 auto drag = new QDrag{dragWidget};
143 auto drag = new QDrag{dragWidget};
142 drag->setHotSpot(dragPosition);
144 drag->setHotSpot(dragPosition);
143
145
144 auto mimeData = dragWidget->mimeData();
146 auto mimeData = dragWidget->mimeData();
145 drag->setMimeData(mimeData);
147 drag->setMimeData(mimeData);
146
148
147 auto pixmap = QPixmap(dragWidget->size());
149 auto pixmap = QPixmap(dragWidget->size());
148 dragWidget->render(&pixmap);
150 dragWidget->render(&pixmap);
149 drag->setPixmap(pixmap);
151 drag->setPixmap(pixmap);
150
152
151 auto image = pixmap.toImage();
153 auto image = pixmap.toImage();
152 mimeData->setImageData(image);
154 mimeData->setImageData(image);
153 mimeData->setUrls({helper.imageTemporaryUrl(image)});
155 mimeData->setUrls({helper.imageTemporaryUrl(image)});
154
156
155 if (impl->m_Layout->indexOf(dragWidget) >= 0) {
157 if (impl->m_Layout->indexOf(dragWidget) >= 0) {
156 helper.setCurrentDragWidget(dragWidget);
158 helper.setCurrentDragWidget(dragWidget);
157
159
158 if (impl->cursorIsInContainer(this)) {
160 if (impl->cursorIsInContainer(this)) {
159 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
161 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
160 helper.insertPlaceHolder(impl->m_Layout, dragWidgetIndex);
162 helper.insertPlaceHolder(impl->m_Layout, dragWidgetIndex);
161 dragWidget->setVisible(false);
163 dragWidget->setVisible(false);
162 }
164 }
163
165
164 // Note: The exec() is blocking on windows but not on linux and macOS
166 // Note: The exec() is blocking on windows but not on linux and macOS
165 drag->exec(Qt::MoveAction | Qt::CopyAction);
167 drag->exec(Qt::MoveAction | Qt::CopyAction);
166 }
168 }
167 else {
169 else {
168 qCWarning(LOG_VisualizationDragDropContainer())
170 qCWarning(LOG_VisualizationDragDropContainer())
169 << tr("VisualizationDragDropContainer::startDrag, drag aborted, the specified "
171 << tr("VisualizationDragDropContainer::startDrag, drag aborted, the specified "
170 "VisualizationDragWidget is not found in this container.");
172 "VisualizationDragWidget is not found in this container.");
171 }
173 }
172 }
174 }
173
175
174 void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event)
176 void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event)
175 {
177 {
176 if (impl->acceptMimeData(event->mimeData())) {
178 if (impl->acceptMimeData(event->mimeData())) {
177 event->acceptProposedAction();
179 event->acceptProposedAction();
178
180
179 auto &helper = sqpApp->dragDropHelper();
181 auto &helper = sqpApp->dragDropHelper();
180
182
181 if (!impl->hasPlaceHolder()) {
183 if (!impl->hasPlaceHolder()) {
182 auto dragWidget = helper.getCurrentDragWidget();
184 auto dragWidget = helper.getCurrentDragWidget();
183
185
184 if (dragWidget) {
186 if (dragWidget) {
185 // If the drag&drop is internal to the visualization, entering the container hide
187 // If the drag&drop is internal to the visualization, entering the container hide
186 // the dragWidget which was hidden by the dragLeaveEvent
188 // the dragWidget which was hidden by the dragLeaveEvent
187 auto parentWidget
189 auto parentWidget
188 = qobject_cast<VisualizationDragDropContainer *>(dragWidget->parentWidget());
190 = qobject_cast<VisualizationDragDropContainer *>(dragWidget->parentWidget());
189 if (parentWidget) {
191 if (parentWidget) {
190 dragWidget->setVisible(false);
192 dragWidget->setVisible(false);
191 }
193 }
192 }
194 }
193
195
194 auto dragWidgetHovered = impl->getChildDragWidgetAt(this, event->pos());
196 auto dragWidgetHovered = impl->getChildDragWidgetAt(this, event->pos());
195
197
196 if (dragWidgetHovered) {
198 if (dragWidgetHovered) {
197 auto hoveredWidgetIndex = impl->m_Layout->indexOf(dragWidgetHovered);
199 auto hoveredWidgetIndex = impl->m_Layout->indexOf(dragWidgetHovered);
198
200
199 if (dragWidget) {
201 if (dragWidget) {
200 auto dragWidgetIndex = impl->m_Layout->indexOf(helper.getCurrentDragWidget());
202 auto dragWidgetIndex = impl->m_Layout->indexOf(helper.getCurrentDragWidget());
201 if (dragWidgetIndex >= 0 && dragWidgetIndex <= hoveredWidgetIndex) {
203 if (dragWidgetIndex >= 0 && dragWidgetIndex <= hoveredWidgetIndex) {
202 // Correction of the index if the drop occurs in the same container
204 // Correction of the index if the drop occurs in the same container
203 // and if the drag is started from the visualization (in that case, the
205 // and if the drag is started from the visualization (in that case, the
204 // dragWidget is hidden)
206 // dragWidget is hidden)
205 hoveredWidgetIndex += 1;
207 hoveredWidgetIndex += 1;
206 }
208 }
207 }
209 }
208
210
209 helper.insertPlaceHolder(impl->m_Layout, hoveredWidgetIndex);
211 helper.insertPlaceHolder(impl->m_Layout, hoveredWidgetIndex);
210 }
212 }
211 else {
213 else {
212 helper.insertPlaceHolder(impl->m_Layout, 0);
214 helper.insertPlaceHolder(impl->m_Layout, 0);
213 }
215 }
214 }
216 }
215 else {
217 else {
216 // do nothing
218 // do nothing
217 }
219 }
218 }
220 }
219 else {
221 else {
220 event->ignore();
222 event->ignore();
221 }
223 }
222
224
223 QWidget::dragEnterEvent(event);
225 QWidget::dragEnterEvent(event);
224 }
226 }
225
227
226 void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event)
228 void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event)
227 {
229 {
228 Q_UNUSED(event);
230 Q_UNUSED(event);
229
231
230 auto &helper = sqpApp->dragDropHelper();
232 auto &helper = sqpApp->dragDropHelper();
231
233
232 if (!impl->cursorIsInContainer(this)) {
234 if (!impl->cursorIsInContainer(this)) {
233 helper.removePlaceHolder();
235 helper.removePlaceHolder();
234
236
235 auto dragWidget = helper.getCurrentDragWidget();
237 auto dragWidget = helper.getCurrentDragWidget();
236 if (dragWidget) {
238 if (dragWidget) {
237 // dragWidget has a value only if the drag is started from the visualization
239 // dragWidget has a value only if the drag is started from the visualization
238 // In that case, shows the drag widget at its original place
240 // In that case, shows the drag widget at its original place
239 // So the drag widget doesn't stay hidden if the drop occurs outside the visualization
241 // So the drag widget doesn't stay hidden if the drop occurs outside the visualization
240 // drop zone (It is not possible to catch a drop event outside of the application)
242 // drop zone (It is not possible to catch a drop event outside of the application)
241
243
242 if (dragWidget) {
244 if (dragWidget) {
243 dragWidget->setVisible(true);
245 dragWidget->setVisible(true);
244 }
246 }
245 }
247 }
246 }
248 }
247 else {
249 else {
248 // Leave event probably received for a child widget.
250 // Leave event probably received for a child widget.
249 // Do nothing.
251 // Do nothing.
250 // Note: The DragLeave event, doesn't have any mean to determine who sent it.
252 // Note: The DragLeave event, doesn't have any mean to determine who sent it.
251 }
253 }
252
254
253 QWidget::dragLeaveEvent(event);
255 QWidget::dragLeaveEvent(event);
254 }
256 }
255
257
256 void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event)
258 void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event)
257 {
259 {
258 if (impl->acceptMimeData(event->mimeData())) {
260 if (impl->acceptMimeData(event->mimeData())) {
259 auto dragWidgetHovered = impl->getChildDragWidgetAt(this, event->pos());
261 auto dragWidgetHovered = impl->getChildDragWidgetAt(this, event->pos());
260 if (dragWidgetHovered) {
262 if (dragWidgetHovered) {
261 auto canMerge = impl->allowMergeMimeData(event->mimeData());
263 auto canMerge = impl->allowMergeMimeData(event->mimeData());
262
264
263 auto nbDragWidget = countDragWidget();
265 auto nbDragWidget = countDragWidget();
264 if (nbDragWidget > 0) {
266 if (nbDragWidget > 0) {
265 auto graphHeight = size().height() / nbDragWidget;
267 auto graphHeight = qMax(size().height() / nbDragWidget, GRAPH_MINIMUM_HEIGHT);
268
266 auto dropIndex = floor(event->pos().y() / graphHeight);
269 auto dropIndex = floor(event->pos().y() / graphHeight);
267 auto zoneSize = qMin(graphHeight / 3.0, 150.0);
270 auto zoneSize = qMin(graphHeight / 3.0, 150.0);
268
271
269 auto isOnTop = event->pos().y() < dropIndex * graphHeight + zoneSize;
272 auto isOnTop = event->pos().y() < dropIndex * graphHeight + zoneSize;
270 auto isOnBottom = event->pos().y() > (dropIndex + 1) * graphHeight - zoneSize;
273 auto isOnBottom = event->pos().y() > (dropIndex + 1) * graphHeight - zoneSize;
271
274
272 auto &helper = sqpApp->dragDropHelper();
275 auto &helper = sqpApp->dragDropHelper();
273 auto placeHolderIndex = impl->m_Layout->indexOf(&(helper.placeHolder()));
276 auto placeHolderIndex = impl->m_Layout->indexOf(&(helper.placeHolder()));
274
277
275 if (isOnTop || isOnBottom) {
278 if (isOnTop || isOnBottom) {
276 if (isOnBottom) {
279 if (isOnBottom) {
277 dropIndex += 1;
280 dropIndex += 1;
278 }
281 }
279
282
280 if (helper.getCurrentDragWidget()) {
283 if (helper.getCurrentDragWidget()) {
281 auto dragWidgetIndex
284 auto dragWidgetIndex
282 = impl->m_Layout->indexOf(helper.getCurrentDragWidget());
285 = impl->m_Layout->indexOf(helper.getCurrentDragWidget());
283 if (dragWidgetIndex >= 0 && dragWidgetIndex <= dropIndex) {
286 if (dragWidgetIndex >= 0 && dragWidgetIndex <= dropIndex) {
284 // Correction of the index if the drop occurs in the same container
287 // Correction of the index if the drop occurs in the same container
285 // and if the drag is started from the visualization (in that case, the
288 // and if the drag is started from the visualization (in that case, the
286 // dragWidget is hidden)
289 // dragWidget is hidden)
287 dropIndex += 1;
290 dropIndex += 1;
288 }
291 }
289 }
292 }
290
293
291 if (dropIndex != placeHolderIndex) {
294 if (dropIndex != placeHolderIndex) {
292 helper.insertPlaceHolder(impl->m_Layout, dropIndex);
295 helper.insertPlaceHolder(impl->m_Layout, dropIndex);
293 }
296 }
294 }
297 }
295 else if (canMerge) {
298 else if (canMerge) {
296 // drop on the middle -> merge
299 // drop on the middle -> merge
297 if (impl->hasPlaceHolder()) {
300 if (impl->hasPlaceHolder()) {
298 helper.removePlaceHolder();
301 helper.removePlaceHolder();
299 }
302 }
300 }
303 }
301 }
304 }
302 else {
305 else {
303 qCWarning(LOG_VisualizationDragDropContainer())
306 qCWarning(LOG_VisualizationDragDropContainer())
304 << tr("VisualizationDragDropContainer::dragMoveEvent, no widget found in the "
307 << tr("VisualizationDragDropContainer::dragMoveEvent, no widget found in the "
305 "container");
308 "container");
306 }
309 }
307 }
310 }
308 else {
311 else {
309 // No hovered drag widget, the mouse is probably hover the placeHolder
312 // No hovered drag widget, the mouse is probably hover the placeHolder
310 // Do nothing
313 // Do nothing
311 }
314 }
312 }
315 }
313 else {
316 else {
314 event->ignore();
317 event->ignore();
315 }
318 }
316
319
317 QWidget::dragMoveEvent(event);
320 QWidget::dragMoveEvent(event);
318 }
321 }
319
322
320 void VisualizationDragDropContainer::dropEvent(QDropEvent *event)
323 void VisualizationDragDropContainer::dropEvent(QDropEvent *event)
321 {
324 {
322 if (impl->acceptMimeData(event->mimeData())) {
325 if (impl->acceptMimeData(event->mimeData())) {
323 auto dragWidget = sqpApp->dragDropHelper().getCurrentDragWidget();
326 auto dragWidget = sqpApp->dragDropHelper().getCurrentDragWidget();
324 if (impl->hasPlaceHolder()) {
327 if (impl->hasPlaceHolder()) {
325 auto &helper = sqpApp->dragDropHelper();
328 auto &helper = sqpApp->dragDropHelper();
326
329
327 auto droppedIndex = impl->m_Layout->indexOf(&helper.placeHolder());
330 auto droppedIndex = impl->m_Layout->indexOf(&helper.placeHolder());
328
331
329 if (dragWidget) {
332 if (dragWidget) {
330 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
333 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
331 if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex) {
334 if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex) {
332 // Correction of the index if the drop occurs in the same container
335 // Correction of the index if the drop occurs in the same container
333 // and if the drag is started from the visualization (in that case, the
336 // and if the drag is started from the visualization (in that case, the
334 // dragWidget is hidden)
337 // dragWidget is hidden)
335 droppedIndex -= 1;
338 droppedIndex -= 1;
336 }
339 }
337
340
338 dragWidget->setVisible(true);
341 dragWidget->setVisible(true);
339 }
342 }
340
343
341 event->acceptProposedAction();
344 event->acceptProposedAction();
342
345
343 helper.removePlaceHolder();
346 helper.removePlaceHolder();
344
347
345 emit dropOccured(droppedIndex, event->mimeData());
348 emit dropOccured(droppedIndex, event->mimeData());
346 }
349 }
347 else {
350 else {
348 qCWarning(LOG_VisualizationDragDropContainer())
351 qCWarning(LOG_VisualizationDragDropContainer())
349 << tr("VisualizationDragDropContainer::dropEvent, couldn't drop because the "
352 << tr("VisualizationDragDropContainer::dropEvent, couldn't drop because the "
350 "placeHolder is not found.");
353 "placeHolder is not found.");
351 Q_ASSERT(false);
354 Q_ASSERT(false);
352 }
355 }
353 }
356 }
354 else {
357 else {
355 event->ignore();
358 event->ignore();
356 }
359 }
357
360
358 QWidget::dropEvent(event);
361 QWidget::dropEvent(event);
359 }
362 }
@@ -1,484 +1,484
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"
11
10 #include <Data/SqpRange.h>
12 #include <Data/SqpRange.h>
11 #include <Variable/Variable.h>
13 #include <Variable/Variable.h>
12 #include <Variable/VariableController.h>
14 #include <Variable/VariableController.h>
13
15
14 #include <Visualization/operations/FindVariableOperation.h>
16 #include <Visualization/operations/FindVariableOperation.h>
15
17
16 #include <DragDropHelper.h>
18 #include <DragDropHelper.h>
17 #include <QUuid>
19 #include <QUuid>
18 #include <SqpApplication.h>
20 #include <SqpApplication.h>
19 #include <cmath>
21 #include <cmath>
20
22
21 #include <QLayout>
23 #include <QLayout>
22
24
23 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
25 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
24
26
25 namespace {
27 namespace {
26
28
27 /// Minimum height for graph added in zones (in pixels)
28 const auto GRAPH_MINIMUM_HEIGHT = 300;
29
29
30 /// Generates a default name for a new graph, according to the number of graphs already displayed in
30 /// Generates a default name for a new graph, according to the number of graphs already displayed in
31 /// the zone
31 /// the zone
32 QString defaultGraphName(const QLayout &layout)
32 QString defaultGraphName(const QLayout &layout)
33 {
33 {
34 auto count = 0;
34 auto count = 0;
35 for (auto i = 0; i < layout.count(); ++i) {
35 for (auto i = 0; i < layout.count(); ++i) {
36 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
36 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
37 count++;
37 count++;
38 }
38 }
39 }
39 }
40
40
41 return QObject::tr("Graph %1").arg(count + 1);
41 return QObject::tr("Graph %1").arg(count + 1);
42 }
42 }
43
43
44 /**
44 /**
45 * Applies a function to all graphs of the zone represented by its layout
45 * Applies a function to all graphs of the zone represented by its layout
46 * @param layout the layout that contains graphs
46 * @param layout the layout that contains graphs
47 * @param fun the function to apply to each graph
47 * @param fun the function to apply to each graph
48 */
48 */
49 template <typename Fun>
49 template <typename Fun>
50 void processGraphs(QLayout &layout, Fun fun)
50 void processGraphs(QLayout &layout, Fun fun)
51 {
51 {
52 for (auto i = 0; i < layout.count(); ++i) {
52 for (auto i = 0; i < layout.count(); ++i) {
53 if (auto item = layout.itemAt(i)) {
53 if (auto item = layout.itemAt(i)) {
54 if (auto visualizationGraphWidget
54 if (auto visualizationGraphWidget
55 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
55 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
56 fun(*visualizationGraphWidget);
56 fun(*visualizationGraphWidget);
57 }
57 }
58 }
58 }
59 }
59 }
60 }
60 }
61
61
62 } // namespace
62 } // namespace
63
63
64 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
64 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
65
65
66 explicit VisualizationZoneWidgetPrivate()
66 explicit VisualizationZoneWidgetPrivate()
67 : m_SynchronisationGroupId{QUuid::createUuid()},
67 : m_SynchronisationGroupId{QUuid::createUuid()},
68 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
68 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
69 {
69 {
70 }
70 }
71 QUuid m_SynchronisationGroupId;
71 QUuid m_SynchronisationGroupId;
72 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
72 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
73
73
74 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
74 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
75 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
75 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
76 VisualizationZoneWidget *zoneWidget);
76 VisualizationZoneWidget *zoneWidget);
77 };
77 };
78
78
79 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
79 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
80 : VisualizationDragWidget{parent},
80 : VisualizationDragWidget{parent},
81 ui{new Ui::VisualizationZoneWidget},
81 ui{new Ui::VisualizationZoneWidget},
82 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
82 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
83 {
83 {
84 ui->setupUi(this);
84 ui->setupUi(this);
85
85
86 ui->zoneNameLabel->setText(name);
86 ui->zoneNameLabel->setText(name);
87
87
88 ui->dragDropContainer->setAcceptedMimeTypes({MIME_TYPE_GRAPH, MIME_TYPE_VARIABLE_LIST});
88 ui->dragDropContainer->setAcceptedMimeTypes({MIME_TYPE_GRAPH, MIME_TYPE_VARIABLE_LIST});
89 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
89 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
90 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
90 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
91 ui->dragDropContainer);
91 ui->dragDropContainer);
92 });
92 });
93 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccured, this,
93 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccured, this,
94 &VisualizationZoneWidget::dropMimeData);
94 &VisualizationZoneWidget::dropMimeData);
95
95
96 // 'Close' options : widget is deleted when closed
96 // 'Close' options : widget is deleted when closed
97 setAttribute(Qt::WA_DeleteOnClose);
97 setAttribute(Qt::WA_DeleteOnClose);
98 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
98 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
99 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
99 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
100
100
101 // Synchronisation id
101 // Synchronisation id
102 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
102 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
103 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
103 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
104 }
104 }
105
105
106 VisualizationZoneWidget::~VisualizationZoneWidget()
106 VisualizationZoneWidget::~VisualizationZoneWidget()
107 {
107 {
108 delete ui;
108 delete ui;
109 }
109 }
110
110
111 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
111 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
112 {
112 {
113 // Synchronize new graph with others in the zone
113 // Synchronize new graph with others in the zone
114 impl->m_Synchronizer->addGraph(*graphWidget);
114 impl->m_Synchronizer->addGraph(*graphWidget);
115
115
116 ui->dragDropContainer->addDragWidget(graphWidget);
116 ui->dragDropContainer->addDragWidget(graphWidget);
117 }
117 }
118
118
119 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
119 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
120 {
120 {
121 // Synchronize new graph with others in the zone
121 // Synchronize new graph with others in the zone
122 impl->m_Synchronizer->addGraph(*graphWidget);
122 impl->m_Synchronizer->addGraph(*graphWidget);
123
123
124 ui->dragDropContainer->insertDragWidget(index, graphWidget);
124 ui->dragDropContainer->insertDragWidget(index, graphWidget);
125 }
125 }
126
126
127 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
127 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
128 {
128 {
129 return createGraph(variable, -1);
129 return createGraph(variable, -1);
130 }
130 }
131
131
132 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
132 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
133 int index)
133 int index)
134 {
134 {
135 auto graphWidget
135 auto graphWidget
136 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
136 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
137
137
138
138
139 // Set graph properties
139 // Set graph properties
140 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
140 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
141 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
141 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
142
142
143
143
144 // Lambda to synchronize zone widget
144 // Lambda to synchronize zone widget
145 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
145 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
146 const SqpRange &oldGraphRange) {
146 const SqpRange &oldGraphRange) {
147
147
148 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
148 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
149 auto frameLayout = ui->dragDropContainer->layout();
149 auto frameLayout = ui->dragDropContainer->layout();
150 for (auto i = 0; i < frameLayout->count(); ++i) {
150 for (auto i = 0; i < frameLayout->count(); ++i) {
151 auto graphChild
151 auto graphChild
152 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
152 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
153 if (graphChild && (graphChild != graphWidget)) {
153 if (graphChild && (graphChild != graphWidget)) {
154
154
155 auto graphChildRange = graphChild->graphRange();
155 auto graphChildRange = graphChild->graphRange();
156 switch (zoomType) {
156 switch (zoomType) {
157 case AcquisitionZoomType::ZoomIn: {
157 case AcquisitionZoomType::ZoomIn: {
158 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
158 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
159 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
159 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
160 graphChildRange.m_TStart += deltaLeft;
160 graphChildRange.m_TStart += deltaLeft;
161 graphChildRange.m_TEnd -= deltaRight;
161 graphChildRange.m_TEnd -= deltaRight;
162 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
162 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
163 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
163 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
164 << deltaLeft;
164 << deltaLeft;
165 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
165 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
166 << deltaRight;
166 << deltaRight;
167 qCDebug(LOG_VisualizationZoneWidget())
167 qCDebug(LOG_VisualizationZoneWidget())
168 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
168 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
169
169
170 break;
170 break;
171 }
171 }
172
172
173 case AcquisitionZoomType::ZoomOut: {
173 case AcquisitionZoomType::ZoomOut: {
174 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
174 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
175 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
175 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
176 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
176 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
177 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
177 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
178 << deltaLeft;
178 << deltaLeft;
179 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
179 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
180 << deltaRight;
180 << deltaRight;
181 qCDebug(LOG_VisualizationZoneWidget())
181 qCDebug(LOG_VisualizationZoneWidget())
182 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
182 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
183 graphChildRange.m_TStart -= deltaLeft;
183 graphChildRange.m_TStart -= deltaLeft;
184 graphChildRange.m_TEnd += deltaRight;
184 graphChildRange.m_TEnd += deltaRight;
185 break;
185 break;
186 }
186 }
187 case AcquisitionZoomType::PanRight: {
187 case AcquisitionZoomType::PanRight: {
188 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
188 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
189 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
189 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
190 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
190 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
191 graphChildRange.m_TStart += deltaLeft;
191 graphChildRange.m_TStart += deltaLeft;
192 graphChildRange.m_TEnd += deltaRight;
192 graphChildRange.m_TEnd += deltaRight;
193 qCDebug(LOG_VisualizationZoneWidget())
193 qCDebug(LOG_VisualizationZoneWidget())
194 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
194 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
195 break;
195 break;
196 }
196 }
197 case AcquisitionZoomType::PanLeft: {
197 case AcquisitionZoomType::PanLeft: {
198 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
198 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
199 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
199 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
200 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
200 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
201 graphChildRange.m_TStart -= deltaLeft;
201 graphChildRange.m_TStart -= deltaLeft;
202 graphChildRange.m_TEnd -= deltaRight;
202 graphChildRange.m_TEnd -= deltaRight;
203 break;
203 break;
204 }
204 }
205 case AcquisitionZoomType::Unknown: {
205 case AcquisitionZoomType::Unknown: {
206 qCDebug(LOG_VisualizationZoneWidget())
206 qCDebug(LOG_VisualizationZoneWidget())
207 << tr("Impossible to synchronize: zoom type unknown");
207 << tr("Impossible to synchronize: zoom type unknown");
208 break;
208 break;
209 }
209 }
210 default:
210 default:
211 qCCritical(LOG_VisualizationZoneWidget())
211 qCCritical(LOG_VisualizationZoneWidget())
212 << tr("Impossible to synchronize: zoom type not take into account");
212 << tr("Impossible to synchronize: zoom type not take into account");
213 // No action
213 // No action
214 break;
214 break;
215 }
215 }
216 graphChild->enableAcquisition(false);
216 graphChild->enableAcquisition(false);
217 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
217 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
218 << graphChild->graphRange();
218 << graphChild->graphRange();
219 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
219 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
220 << graphChildRange;
220 << graphChildRange;
221 qCDebug(LOG_VisualizationZoneWidget())
221 qCDebug(LOG_VisualizationZoneWidget())
222 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
222 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
223 graphChild->setGraphRange(graphChildRange);
223 graphChild->setGraphRange(graphChildRange);
224 graphChild->enableAcquisition(true);
224 graphChild->enableAcquisition(true);
225 }
225 }
226 }
226 }
227 };
227 };
228
228
229 // connection for synchronization
229 // connection for synchronization
230 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
230 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
231 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
231 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
232 &VisualizationZoneWidget::onVariableAdded);
232 &VisualizationZoneWidget::onVariableAdded);
233 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
233 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
234 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
234 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
235
235
236 auto range = SqpRange{};
236 auto range = SqpRange{};
237
237
238 // Apply visitor to graph children
238 // Apply visitor to graph children
239 auto layout = ui->dragDropContainer->layout();
239 auto layout = ui->dragDropContainer->layout();
240 if (layout->count() > 0) {
240 if (layout->count() > 0) {
241 // Case of a new graph in a existant zone
241 // Case of a new graph in a existant zone
242 if (auto visualizationGraphWidget
242 if (auto visualizationGraphWidget
243 = dynamic_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
243 = dynamic_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
244 range = visualizationGraphWidget->graphRange();
244 range = visualizationGraphWidget->graphRange();
245 }
245 }
246 }
246 }
247 else {
247 else {
248 // Case of a new graph as the first of the zone
248 // Case of a new graph as the first of the zone
249 range = variable->range();
249 range = variable->range();
250 }
250 }
251
251
252 this->insertGraph(index, graphWidget);
252 this->insertGraph(index, graphWidget);
253
253
254 graphWidget->addVariable(variable, range);
254 graphWidget->addVariable(variable, range);
255
255
256 // get y using variable range
256 // get y using variable range
257 if (auto dataSeries = variable->dataSeries()) {
257 if (auto dataSeries = variable->dataSeries()) {
258 dataSeries->lockRead();
258 dataSeries->lockRead();
259 auto valuesBounds
259 auto valuesBounds
260 = dataSeries->valuesBounds(variable->range().m_TStart, variable->range().m_TEnd);
260 = dataSeries->valuesBounds(variable->range().m_TStart, variable->range().m_TEnd);
261 auto end = dataSeries->cend();
261 auto end = dataSeries->cend();
262 if (valuesBounds.first != end && valuesBounds.second != end) {
262 if (valuesBounds.first != end && valuesBounds.second != end) {
263 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
263 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
264
264
265 auto minValue = rangeValue(valuesBounds.first->minValue());
265 auto minValue = rangeValue(valuesBounds.first->minValue());
266 auto maxValue = rangeValue(valuesBounds.second->maxValue());
266 auto maxValue = rangeValue(valuesBounds.second->maxValue());
267
267
268 graphWidget->setYRange(SqpRange{minValue, maxValue});
268 graphWidget->setYRange(SqpRange{minValue, maxValue});
269 }
269 }
270 dataSeries->unlock();
270 dataSeries->unlock();
271 }
271 }
272
272
273 return graphWidget;
273 return graphWidget;
274 }
274 }
275
275
276 VisualizationGraphWidget *
276 VisualizationGraphWidget *
277 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
277 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
278 {
278 {
279 if (variables.isEmpty()) {
279 if (variables.isEmpty()) {
280 return nullptr;
280 return nullptr;
281 }
281 }
282
282
283 auto graphWidget = createGraph(variables.first(), index);
283 auto graphWidget = createGraph(variables.first(), index);
284 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
284 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
285 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
285 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
286 }
286 }
287
287
288 return graphWidget;
288 return graphWidget;
289 }
289 }
290
290
291 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
291 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
292 {
292 {
293 if (visitor) {
293 if (visitor) {
294 visitor->visitEnter(this);
294 visitor->visitEnter(this);
295
295
296 // Apply visitor to graph children: widgets different from graphs are not visited (no
296 // Apply visitor to graph children: widgets different from graphs are not visited (no
297 // action)
297 // action)
298 processGraphs(
298 processGraphs(
299 *ui->dragDropContainer->layout(),
299 *ui->dragDropContainer->layout(),
300 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
300 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
301
301
302 visitor->visitLeave(this);
302 visitor->visitLeave(this);
303 }
303 }
304 else {
304 else {
305 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
305 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
306 }
306 }
307 }
307 }
308
308
309 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
309 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
310 {
310 {
311 // A tab can always accomodate a variable
311 // A tab can always accomodate a variable
312 Q_UNUSED(variable);
312 Q_UNUSED(variable);
313 return true;
313 return true;
314 }
314 }
315
315
316 bool VisualizationZoneWidget::contains(const Variable &variable) const
316 bool VisualizationZoneWidget::contains(const Variable &variable) const
317 {
317 {
318 Q_UNUSED(variable);
318 Q_UNUSED(variable);
319 return false;
319 return false;
320 }
320 }
321
321
322 QString VisualizationZoneWidget::name() const
322 QString VisualizationZoneWidget::name() const
323 {
323 {
324 return ui->zoneNameLabel->text();
324 return ui->zoneNameLabel->text();
325 }
325 }
326
326
327 QMimeData *VisualizationZoneWidget::mimeData() const
327 QMimeData *VisualizationZoneWidget::mimeData() const
328 {
328 {
329 auto mimeData = new QMimeData;
329 auto mimeData = new QMimeData;
330 mimeData->setData(MIME_TYPE_ZONE, QByteArray());
330 mimeData->setData(MIME_TYPE_ZONE, QByteArray());
331
331
332 return mimeData;
332 return mimeData;
333 }
333 }
334
334
335 bool VisualizationZoneWidget::isDragAllowed() const
335 bool VisualizationZoneWidget::isDragAllowed() const
336 {
336 {
337 return true;
337 return true;
338 }
338 }
339
339
340 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
340 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
341 {
341 {
342 // Closes graphs in the zone
342 // Closes graphs in the zone
343 processGraphs(*ui->dragDropContainer->layout(),
343 processGraphs(*ui->dragDropContainer->layout(),
344 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
344 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
345
345
346 // Delete synchronization group from variable controller
346 // Delete synchronization group from variable controller
347 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
347 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
348 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
348 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
349
349
350 QWidget::closeEvent(event);
350 QWidget::closeEvent(event);
351 }
351 }
352
352
353 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
353 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
354 {
354 {
355 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
355 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
356 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
356 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
357 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
357 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
358 }
358 }
359
359
360 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
360 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
361 {
361 {
362 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
362 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
363 Q_ARG(std::shared_ptr<Variable>, variable),
363 Q_ARG(std::shared_ptr<Variable>, variable),
364 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
364 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
365 }
365 }
366
366
367 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
367 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
368 {
368 {
369 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
369 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
370 impl->dropGraph(index, this);
370 impl->dropGraph(index, this);
371 }
371 }
372 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
372 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
373 auto variables = sqpApp->variableController().variablesForMimeData(
373 auto variables = sqpApp->variableController().variablesForMimeData(
374 mimeData->data(MIME_TYPE_VARIABLE_LIST));
374 mimeData->data(MIME_TYPE_VARIABLE_LIST));
375 impl->dropVariables(variables, index, this);
375 impl->dropVariables(variables, index, this);
376 }
376 }
377 else {
377 else {
378 qCWarning(LOG_VisualizationZoneWidget())
378 qCWarning(LOG_VisualizationZoneWidget())
379 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
379 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
380 }
380 }
381 }
381 }
382
382
383 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
383 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
384 int index, VisualizationZoneWidget *zoneWidget)
384 int index, VisualizationZoneWidget *zoneWidget)
385 {
385 {
386 auto &helper = sqpApp->dragDropHelper();
386 auto &helper = sqpApp->dragDropHelper();
387
387
388 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
388 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
389 if (!graphWidget) {
389 if (!graphWidget) {
390 qCWarning(LOG_VisualizationZoneWidget())
390 qCWarning(LOG_VisualizationZoneWidget())
391 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
391 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
392 "found or invalid.");
392 "found or invalid.");
393 Q_ASSERT(false);
393 Q_ASSERT(false);
394 return;
394 return;
395 }
395 }
396
396
397 auto parentDragDropContainer
397 auto parentDragDropContainer
398 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
398 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
399 if (!parentDragDropContainer) {
399 if (!parentDragDropContainer) {
400 qCWarning(LOG_VisualizationZoneWidget())
400 qCWarning(LOG_VisualizationZoneWidget())
401 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
401 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
402 "the dropped graph is not found.");
402 "the dropped graph is not found.");
403 Q_ASSERT(false);
403 Q_ASSERT(false);
404 return;
404 return;
405 }
405 }
406
406
407 const auto &variables = graphWidget->variables();
407 const auto &variables = graphWidget->variables();
408
408
409 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
409 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
410 // The drop didn't occur in the same zone
410 // The drop didn't occur in the same zone
411
411
412 // Abort the requests for the variables (if any)
412 // Abort the requests for the variables (if any)
413 // Commented, because it's not sure if it's needed or not
413 // Commented, because it's not sure if it's needed or not
414 // for (const auto& var : variables)
414 // for (const auto& var : variables)
415 //{
415 //{
416 // sqpApp->variableController().onAbortProgressRequested(var);
416 // sqpApp->variableController().onAbortProgressRequested(var);
417 //}
417 //}
418
418
419 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
419 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
420 auto nbGraph = parentDragDropContainer->countDragWidget();
420 auto nbGraph = parentDragDropContainer->countDragWidget();
421 if (nbGraph == 1) {
421 if (nbGraph == 1) {
422 // This is the only graph in the previous zone, close the zone
422 // This is the only graph in the previous zone, close the zone
423 previousParentZoneWidget->close();
423 previousParentZoneWidget->close();
424 }
424 }
425 else {
425 else {
426 // Close the graph
426 // Close the graph
427 graphWidget->close();
427 graphWidget->close();
428 }
428 }
429
429
430 // Creates the new graph in the zone
430 // Creates the new graph in the zone
431 zoneWidget->createGraph(variables, index);
431 zoneWidget->createGraph(variables, index);
432 }
432 }
433 else {
433 else {
434 // The drop occurred in the same zone or the graph is empty
434 // The drop occurred in the same zone or the graph is empty
435 // Simple move of the graph, no variable operation associated
435 // Simple move of the graph, no variable operation associated
436 parentDragDropContainer->layout()->removeWidget(graphWidget);
436 parentDragDropContainer->layout()->removeWidget(graphWidget);
437
437
438 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
438 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
439 // The graph is empty and dropped in a different zone.
439 // The graph is empty and dropped in a different zone.
440 // Take the range of the first graph in the zone (if existing).
440 // Take the range of the first graph in the zone (if existing).
441 auto layout = zoneWidget->ui->dragDropContainer->layout();
441 auto layout = zoneWidget->ui->dragDropContainer->layout();
442 if (layout->count() > 0) {
442 if (layout->count() > 0) {
443 if (auto visualizationGraphWidget
443 if (auto visualizationGraphWidget
444 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
444 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
445 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
445 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
446 }
446 }
447 }
447 }
448 }
448 }
449
449
450 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
450 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
451 }
451 }
452 }
452 }
453
453
454 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
454 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
455 const QList<std::shared_ptr<Variable> > &variables, int index,
455 const QList<std::shared_ptr<Variable> > &variables, int index,
456 VisualizationZoneWidget *zoneWidget)
456 VisualizationZoneWidget *zoneWidget)
457 {
457 {
458 // Search for the top level VisualizationWidget
458 // Search for the top level VisualizationWidget
459 auto parent = zoneWidget->parentWidget();
459 auto parent = zoneWidget->parentWidget();
460 while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) {
460 while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) {
461 parent = parent->parentWidget();
461 parent = parent->parentWidget();
462 }
462 }
463
463
464 if (!parent) {
464 if (!parent) {
465 qCWarning(LOG_VisualizationZoneWidget())
465 qCWarning(LOG_VisualizationZoneWidget())
466 << tr("VisualizationZoneWidget::dropVariables, drop aborted, the parent "
466 << tr("VisualizationZoneWidget::dropVariables, drop aborted, the parent "
467 "VisualizationWidget cannot be found.");
467 "VisualizationWidget cannot be found.");
468 Q_ASSERT(false);
468 Q_ASSERT(false);
469 return;
469 return;
470 }
470 }
471
471
472 auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
472 auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
473
473
474 // Search for the first variable which can be dropped
474 // Search for the first variable which can be dropped
475 for (auto variable : variables) {
475 for (auto variable : variables) {
476 FindVariableOperation findVariableOperation{variable};
476 FindVariableOperation findVariableOperation{variable};
477 visualizationWidget->accept(&findVariableOperation);
477 visualizationWidget->accept(&findVariableOperation);
478 auto variableContainers = findVariableOperation.result();
478 auto variableContainers = findVariableOperation.result();
479 if (variableContainers.empty()) {
479 if (variableContainers.empty()) {
480 zoneWidget->createGraph(variable, index);
480 zoneWidget->createGraph(variable, index);
481 break;
481 break;
482 }
482 }
483 }
483 }
484 }
484 }
General Comments 1
Under Review
author

Auto status change to "Under Review"

You need to be logged in to leave comments. Login now