##// END OF EJS Templates
Handle the previous prohibition for drag and drop
Alexandre Leroux -
r1023:1b1ede101ec5
parent child
Show More
@@ -1,57 +1,61
1 1 #ifndef SCIQLOP_VISUALIZATIONDRAGDROPCONTAINER_H
2 2 #define SCIQLOP_VISUALIZATIONDRAGDROPCONTAINER_H
3 3
4 4 #include <Common/spimpl.h>
5 5 #include <QFrame>
6 6 #include <QLoggingCategory>
7 7 #include <QMimeData>
8 8 #include <QVBoxLayout>
9 9
10 10 #include <functional>
11 11
12 12 #include <DragAndDrop/DragDropHelper.h>
13 13
14 14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer)
15 15
16 16 class VisualizationDragWidget;
17 17
18 18 class VisualizationDragDropContainer : public QFrame {
19 19 Q_OBJECT
20 20
21 21 signals:
22 22 void dropOccuredInContainer(int dropIndex, const QMimeData *mimeData);
23 23 void dropOccuredOnWidget(VisualizationDragWidget *dragWidget, const QMimeData *mimeData);
24 24
25 25 public:
26 26 enum class DropBehavior { Inserted, Merged, InsertedAndMerged, Forbidden };
27 27 using AcceptMimeDataFunction = std::function<bool(const QMimeData *mimeData)>;
28 using AcceptDragWidgetFunction
29 = std::function<bool(const VisualizationDragWidget *dragWidget, const QMimeData *mimeData)>;
28 30
29 31 VisualizationDragDropContainer(QWidget *parent = nullptr);
30 32
31 33 void addDragWidget(VisualizationDragWidget *dragWidget);
32 34 void insertDragWidget(int index, VisualizationDragWidget *dragWidget);
33 35
34 36 void setMimeType(const QString &mimeType, DropBehavior behavior);
35 37
36 38 int countDragWidget() const;
37 39
38 40 void setAcceptMimeDataFunction(AcceptMimeDataFunction fun);
39 41
42 void setAcceptDragWidgetFunction(AcceptDragWidgetFunction fun);
43
40 44 void setPlaceHolderType(DragDropHelper::PlaceHolderType type,
41 45 const QString &placeHolderText = QString());
42 46
43 47 protected:
44 48 void dragEnterEvent(QDragEnterEvent *event);
45 49 void dragLeaveEvent(QDragLeaveEvent *event);
46 50 void dragMoveEvent(QDragMoveEvent *event);
47 51 void dropEvent(QDropEvent *event);
48 52
49 53 private:
50 54 class VisualizationDragDropContainerPrivate;
51 55 spimpl::unique_impl_ptr<VisualizationDragDropContainerPrivate> impl;
52 56
53 57 private slots:
54 58 void startDrag(VisualizationDragWidget *dragWidget, const QPoint &dragPosition);
55 59 };
56 60
57 61 #endif // SCIQLOP_VISUALIZATIONDRAGDROPCONTAINER_H
@@ -1,473 +1,492
1 1 #include "Visualization/VisualizationDragDropContainer.h"
2 2 #include "DragAndDrop/DragDropHelper.h"
3 3 #include "SqpApplication.h"
4 4 #include "Visualization/VisualizationDragWidget.h"
5 5
6 6 #include "Common/VisualizationDef.h"
7 7
8 8 #include <QDrag>
9 9 #include <QDragEnterEvent>
10 10 #include <QVBoxLayout>
11 11
12 12 #include <cmath>
13 13 #include <memory>
14 14
15 15 Q_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer, "VisualizationDragDropContainer")
16 16
17 17 auto DRAGGED_MINIATURE_WIDTH = 200; // in pixels
18 18
19 19 struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate {
20 20
21 21 QVBoxLayout *m_Layout;
22 22 QHash<QString, VisualizationDragDropContainer::DropBehavior> m_AcceptedMimeTypes;
23 23 QString m_PlaceHolderText;
24 24 DragDropHelper::PlaceHolderType m_PlaceHolderType;
25 25
26 26 VisualizationDragDropContainer::AcceptMimeDataFunction m_AcceptMimeDataFun
27 27 = [](auto mimeData) { return true; };
28 VisualizationDragDropContainer::AcceptDragWidgetFunction m_AcceptDragWidgetFun
29 = [](auto dragWidget, auto mimeData) { return true; };
28 30
29 31 int m_MinContainerHeight = 0;
30 32
31 33 explicit VisualizationDragDropContainerPrivate(QWidget *widget)
32 34 : m_PlaceHolderType(DragDropHelper::PlaceHolderType::Graph)
33 35 {
34 36 m_Layout = new QVBoxLayout(widget);
35 37 m_Layout->setContentsMargins(0, 0, 0, 0);
36 38 }
37 39
38 40 bool acceptMimeData(const QMimeData *data) const
39 41 {
40 42 auto accepted = false;
41 43 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
42 44 ++it) {
43 45 const auto &type = it.key();
44 46 const auto &behavior = it.value();
45 47
46 48 if (data->hasFormat(type)) {
47 49 if (behavior != DropBehavior::Forbidden) {
48 50 accepted = true;
49 51 }
50 52 else {
51 53 accepted = false;
52 54 break;
53 55 }
54 56 }
55 57 }
56 58
57 59 if (accepted) {
58 60 accepted = m_AcceptMimeDataFun(data);
59 61 }
60 62
61 63 return accepted;
62 64 }
63 65
64 66 bool allowMergeForMimeData(const QMimeData *data) const
65 67 {
66 68 auto result = false;
67 69 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
68 70 ++it) {
69 71
70 72 if (data->hasFormat(it.key())
71 73 && (it.value() == VisualizationDragDropContainer::DropBehavior::Merged
72 74 || it.value()
73 75 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
74 76 result = true;
75 77 }
76 78 else if (data->hasFormat(it.key())
77 79 && it.value() == VisualizationDragDropContainer::DropBehavior::Inserted) {
78 80 // Merge is forbidden if the mime data contain an acceptable type which cannot be
79 81 // merged
80 82 result = false;
81 83 break;
82 84 }
83 85 }
84 86
85 87 return result;
86 88 }
87 89
88 90 bool allowInsertForMimeData(const QMimeData *data) const
89 91 {
90 92 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
91 93 ++it) {
92 94 if (data->hasFormat(it.key())
93 95 && (it.value() == VisualizationDragDropContainer::DropBehavior::Inserted
94 96 || it.value()
95 97 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
96 98 return true;
97 99 }
98 100 }
99 101
100 102 return false;
101 103 }
102 104
103 105 bool hasPlaceHolder() const
104 106 {
105 107 return sqpApp->dragDropHelper().placeHolder().parentWidget() == m_Layout->parentWidget();
106 108 }
107 109
108 110 VisualizationDragWidget *getChildDragWidgetAt(const QWidget *parent, const QPoint &pos) const
109 111 {
110 112 VisualizationDragWidget *dragWidget = nullptr;
111 113
112 114 for (auto child : parent->children()) {
113 115 auto widget = qobject_cast<VisualizationDragWidget *>(child);
114 116 if (widget && widget->isVisible()) {
115 117 if (widget->frameGeometry().contains(pos)) {
116 118 dragWidget = widget;
117 119 break;
118 120 }
119 121 }
120 122 }
121 123
122 124 return dragWidget;
123 125 }
124 126
125 127 bool cursorIsInContainer(QWidget *container) const
126 128 {
127 129 auto widgetUnderMouse = sqpApp->widgetAt(QCursor::pos());
128 130 return container->isAncestorOf(widgetUnderMouse) && widgetUnderMouse != container
129 131 && sqpApp->dragDropHelper().placeHolder().isAncestorOf(widgetUnderMouse);
130 132 }
131 133
132 134 int countDragWidget(const QWidget *parent, bool onlyVisible = false) const
133 135 {
134 136 auto nbGraph = 0;
135 137 for (auto child : parent->children()) {
136 138 if (qobject_cast<VisualizationDragWidget *>(child)) {
137 139 if (!onlyVisible || qobject_cast<VisualizationDragWidget *>(child)->isVisible()) {
138 140 nbGraph += 1;
139 141 }
140 142 }
141 143 }
142 144
143 145 return nbGraph;
144 146 }
145 147
146 void findPlaceHolderPosition(const QPoint &pos, bool canInsert, bool canMerge,
147 const VisualizationDragDropContainer *container);
148 bool findPlaceHolderPosition(const QPoint &pos, const QMimeData *mimeData, bool canInsert,
149 bool canMerge, const VisualizationDragDropContainer *container);
148 150 };
149 151
150 152 VisualizationDragDropContainer::VisualizationDragDropContainer(QWidget *parent)
151 153 : QFrame{parent},
152 154 impl{spimpl::make_unique_impl<VisualizationDragDropContainerPrivate>(this)}
153 155 {
154 156 setAcceptDrops(true);
155 157 }
156 158
157 159 void VisualizationDragDropContainer::addDragWidget(VisualizationDragWidget *dragWidget)
158 160 {
159 161 impl->m_Layout->addWidget(dragWidget);
160 162 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
161 163 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
162 164 &VisualizationDragDropContainer::startDrag);
163 165 }
164 166
165 167 void VisualizationDragDropContainer::insertDragWidget(int index,
166 168 VisualizationDragWidget *dragWidget)
167 169 {
168 170 impl->m_Layout->insertWidget(index, dragWidget);
169 171 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
170 172 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
171 173 &VisualizationDragDropContainer::startDrag);
172 174 }
173 175
174 176 void VisualizationDragDropContainer::setMimeType(
175 177 const QString &mimeType, VisualizationDragDropContainer::DropBehavior behavior)
176 178 {
177 179 impl->m_AcceptedMimeTypes[mimeType] = behavior;
178 180 }
179 181
180 182 int VisualizationDragDropContainer::countDragWidget() const
181 183 {
182 184 return impl->countDragWidget(this);
183 185 }
184 186
185 187 void VisualizationDragDropContainer::setAcceptMimeDataFunction(
186 188 VisualizationDragDropContainer::AcceptMimeDataFunction fun)
187 189 {
188 190 impl->m_AcceptMimeDataFun = fun;
189 191 }
190 192
193 void VisualizationDragDropContainer::setAcceptDragWidgetFunction(
194 VisualizationDragDropContainer::AcceptDragWidgetFunction fun)
195 {
196 impl->m_AcceptDragWidgetFun = fun;
197 }
198
191 199 void VisualizationDragDropContainer::setPlaceHolderType(DragDropHelper::PlaceHolderType type,
192 200 const QString &placeHolderText)
193 201 {
194 202 impl->m_PlaceHolderType = type;
195 203 impl->m_PlaceHolderText = placeHolderText;
196 204 }
197 205
198 206 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidget,
199 207 const QPoint &dragPosition)
200 208 {
201 209 auto &helper = sqpApp->dragDropHelper();
202 210 helper.resetDragAndDrop();
203 211
204 212 // Note: The management of the drag object is done by Qt
205 213 auto drag = new QDrag{dragWidget};
206 214
207 215 auto mimeData = dragWidget->mimeData();
208 216 drag->setMimeData(mimeData);
209 217
210 218 auto pixmap = QPixmap(dragWidget->size());
211 219 dragWidget->render(&pixmap);
212 220 drag->setPixmap(pixmap.scaled(DRAGGED_MINIATURE_WIDTH, DRAGGED_MINIATURE_WIDTH,
213 221 Qt::KeepAspectRatio, Qt::SmoothTransformation));
214 222
215 223 auto image = pixmap.toImage();
216 224 mimeData->setImageData(image);
217 225 mimeData->setUrls({helper.imageTemporaryUrl(image)});
218 226
219 227 if (impl->m_Layout->indexOf(dragWidget) >= 0) {
220 228 helper.setCurrentDragWidget(dragWidget);
221 229
222 230 if (impl->cursorIsInContainer(this)) {
223 231 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
224 232 helper.insertPlaceHolder(impl->m_Layout, dragWidgetIndex, impl->m_PlaceHolderType,
225 233 impl->m_PlaceHolderText);
226 234 dragWidget->setVisible(false);
227 235 }
228 236 else {
229 237 // The drag starts directly outside the drop zone
230 238 // do not add the placeHolder
231 239 }
232 240
233 241 drag->exec(Qt::MoveAction | Qt::CopyAction, Qt::MoveAction);
234 242
235 243 helper.doCloseWidgets();
236 244 }
237 245 else {
238 246 qCWarning(LOG_VisualizationDragDropContainer())
239 247 << tr("VisualizationDragDropContainer::startDrag, drag aborted, the specified "
240 248 "VisualizationDragWidget is not found in this container.");
241 249 }
242 250 }
243 251
244 252 void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event)
245 253 {
246 254 if (impl->acceptMimeData(event->mimeData())) {
247 255 event->acceptProposedAction();
248 256
249 257 auto &helper = sqpApp->dragDropHelper();
250 258
251 259 if (!impl->hasPlaceHolder()) {
252 260 auto dragWidget = helper.getCurrentDragWidget();
253 261
254 262 if (dragWidget) {
255 263 // If the drag&drop is internal to the visualization, entering the container hide
256 264 // the dragWidget which was made visible by the dragLeaveEvent
257 265 auto parentWidget
258 266 = qobject_cast<VisualizationDragDropContainer *>(dragWidget->parentWidget());
259 267 if (parentWidget) {
260 268 dragWidget->setVisible(false);
261 269 }
262 270 }
263 271
264 272 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
265 273 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
266 impl->findPlaceHolderPosition(event->pos(), canInsert, canMerge, this);
274 if (!impl->findPlaceHolderPosition(event->pos(), event->mimeData(), canInsert, canMerge,
275 this)) {
276 event->ignore();
277 }
267 278 }
268 279 else {
269 280 // do nothing
270 281 }
271 282 }
272 283 else {
273 284 event->ignore();
274 285 }
275 286
276 287 QWidget::dragEnterEvent(event);
277 288 }
278 289
279 290 void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event)
280 291 {
281 292 Q_UNUSED(event);
282 293
283 294 auto &helper = sqpApp->dragDropHelper();
284 295
285 296 if (!impl->cursorIsInContainer(this)) {
286 297 helper.removePlaceHolder();
287 298 helper.setHightlightedDragWidget(nullptr);
288 299 impl->m_MinContainerHeight = 0;
289 300
290 301 auto dragWidget = helper.getCurrentDragWidget();
291 302 if (dragWidget) {
292 303 // dragWidget has a value only if the drag is started from the visualization
293 304 // In that case, shows the drag widget at its original place
294 305 // So the drag widget doesn't stay hidden if the drop occurs outside the visualization
295 306 // drop zone (It is not possible to catch a drop event outside of the application)
296 307
297 308 if (dragWidget) {
298 309 dragWidget->setVisible(true);
299 310 }
300 311 }
301 312 }
302 313 else {
303 314 // Leave event probably received for a child widget.
304 315 // Do nothing.
305 316 // Note: The DragLeave event, doesn't have any mean to determine who sent it.
306 317 }
307 318
308 319 QWidget::dragLeaveEvent(event);
309 320 }
310 321
311 322 void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event)
312 323 {
313 324 if (impl->acceptMimeData(event->mimeData())) {
314 325 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
315 326 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
316 impl->findPlaceHolderPosition(event->pos(), canInsert, canMerge, this);
327 impl->findPlaceHolderPosition(event->pos(), event->mimeData(), canInsert, canMerge, this);
317 328 }
318 329 else {
319 330 event->ignore();
320 331 }
321 332
322 333 QWidget::dragMoveEvent(event);
323 334 }
324 335
325 336 void VisualizationDragDropContainer::dropEvent(QDropEvent *event)
326 337 {
327 338 auto &helper = sqpApp->dragDropHelper();
328 339
329 340 if (impl->acceptMimeData(event->mimeData())) {
330 341 auto dragWidget = helper.getCurrentDragWidget();
331 342 if (impl->hasPlaceHolder()) {
332 343 // drop where the placeHolder is located
333 344
334 345 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
335 346 if (canInsert) {
336 347 auto droppedIndex = impl->m_Layout->indexOf(&helper.placeHolder());
337 348
338 349 if (dragWidget) {
339 350 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
340 351 if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex) {
341 352 // Correction of the index if the drop occurs in the same container
342 353 // and if the drag is started from the visualization (in that case, the
343 354 // dragWidget is hidden)
344 355 droppedIndex -= 1;
345 356 }
346 357
347 358 dragWidget->setVisible(true);
348 359 }
349 360
350 361 event->acceptProposedAction();
351 362
352 363 helper.removePlaceHolder();
353 364
354 365 emit dropOccuredInContainer(droppedIndex, event->mimeData());
355 366 }
356 367 else {
357 368 qCWarning(LOG_VisualizationDragDropContainer()) << tr(
358 369 "VisualizationDragDropContainer::dropEvent, dropping on the placeHolder, but "
359 370 "the insertion is forbidden.");
360 371 Q_ASSERT(false);
361 372 }
362 373 }
363 374 else if (helper.getHightlightedDragWidget()) {
364 375 // drop on the highlighted widget
365 376
366 377 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
367 378 if (canMerge) {
368 379 event->acceptProposedAction();
369 380 emit dropOccuredOnWidget(helper.getHightlightedDragWidget(), event->mimeData());
370 381 }
371 382 else {
372 383 qCWarning(LOG_VisualizationDragDropContainer())
373 384 << tr("VisualizationDragDropContainer::dropEvent, dropping on a widget, but "
374 385 "the merge is forbidden.");
375 386 Q_ASSERT(false);
376 387 }
377 388 }
378 389 }
379 390 else {
380 391 event->ignore();
381 392 }
382 393
383 394 sqpApp->dragDropHelper().setHightlightedDragWidget(nullptr);
384 395 impl->m_MinContainerHeight = 0;
385 396
386 397 QWidget::dropEvent(event);
387 398 }
388 399
389 400
390 void VisualizationDragDropContainer::VisualizationDragDropContainerPrivate::findPlaceHolderPosition(
391 const QPoint &pos, bool canInsert, bool canMerge,
401 bool VisualizationDragDropContainer::VisualizationDragDropContainerPrivate::findPlaceHolderPosition(
402 const QPoint &pos, const QMimeData *mimeData, bool canInsert, bool canMerge,
392 403 const VisualizationDragDropContainer *container)
393 404 {
394 405 auto &helper = sqpApp->dragDropHelper();
395 406
396 407 auto absPos = container->mapToGlobal(pos);
397 408 auto isOnPlaceHolder = helper.placeHolder().isAncestorOf(sqpApp->widgetAt(absPos));
398 409
399 410 if (countDragWidget(container, true) == 0) {
400 411 // Drop on an empty container, just add the placeHolder at the top
401 412 helper.insertPlaceHolder(m_Layout, 0, m_PlaceHolderType, m_PlaceHolderText);
402 413 }
403 414 else if (!isOnPlaceHolder) {
404 415 auto nbDragWidget = countDragWidget(container);
405 416 if (nbDragWidget > 0) {
406 417
407 418 if (m_MinContainerHeight == 0) {
408 419 m_MinContainerHeight = container->size().height();
409 420 }
410 421
411 422 m_MinContainerHeight = qMin(m_MinContainerHeight, container->size().height());
412 423 auto graphHeight = qMax(m_MinContainerHeight / nbDragWidget, GRAPH_MINIMUM_HEIGHT);
413 424
414 425 auto posY = pos.y();
415 426 auto dropIndex = floor(posY / graphHeight);
416 427 auto zoneSize = qMin(graphHeight / 4.0, 75.0);
417 428
418 429
419 430 auto isOnTop = posY < dropIndex * graphHeight + zoneSize;
420 431 auto isOnBottom = posY > (dropIndex + 1) * graphHeight - zoneSize;
421 432
422 433 auto placeHolderIndex = m_Layout->indexOf(&(helper.placeHolder()));
423 434
424 435 auto dragWidgetHovered = getChildDragWidgetAt(container, pos);
425 436
426 437 if (canInsert && (isOnTop || isOnBottom || !canMerge)) {
427 438 if (isOnBottom) {
428 439 dropIndex += 1;
429 440 }
430 441
431 442 if (helper.getCurrentDragWidget()) {
432 443 auto dragWidgetIndex = m_Layout->indexOf(helper.getCurrentDragWidget());
433 444 if (dragWidgetIndex >= 0 && dragWidgetIndex <= dropIndex) {
434 445 // Correction of the index if the drop occurs in the same container
435 446 // and if the drag is started from the visualization (in that case, the
436 447 // dragWidget is hidden)
437 448 dropIndex += 1;
438 449 }
439 450 }
440 451
441 452 if (dropIndex != placeHolderIndex) {
442 453 helper.insertPlaceHolder(m_Layout, dropIndex, m_PlaceHolderType,
443 454 m_PlaceHolderText);
444 455 }
445 456
446 457 helper.setHightlightedDragWidget(nullptr);
447 458 }
448 459 else if (canMerge && dragWidgetHovered) {
449 460 // drop on the middle -> merge
450 461 if (hasPlaceHolder()) {
451 462 helper.removePlaceHolder();
452 463 }
453 464
465 if (m_AcceptDragWidgetFun(dragWidgetHovered, mimeData)) {
454 466 helper.setHightlightedDragWidget(dragWidgetHovered);
467 return true;
468 }
469 else {
470 return false;
471 }
455 472 }
456 473 else {
457 474 qCWarning(LOG_VisualizationDragDropContainer())
458 475 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no valid drop "
459 476 "action.");
460 477 }
461 478 }
462 479 else {
463 480 qCWarning(LOG_VisualizationDragDropContainer())
464 481 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no widget "
465 482 "found in the "
466 483 "container");
467 484 }
468 485 }
469 486 else {
470 487 // the mouse is hover the placeHolder
471 488 // Do nothing
472 489 }
490
491 return true;
473 492 }
@@ -1,560 +1,583
1 1 #include "Visualization/VisualizationZoneWidget.h"
2 2
3 3 #include "Visualization/IVisualizationWidgetVisitor.h"
4 4 #include "Visualization/QCustomPlotSynchronizer.h"
5 5 #include "Visualization/VisualizationGraphWidget.h"
6 6 #include "Visualization/VisualizationWidget.h"
7 7 #include "ui_VisualizationZoneWidget.h"
8 8
9 9 #include "Common/MimeTypesDef.h"
10 10 #include "Common/VisualizationDef.h"
11 11
12 12 #include <Data/SqpRange.h>
13 13 #include <Time/TimeController.h>
14 14 #include <Variable/Variable.h>
15 15 #include <Variable/VariableController.h>
16 16
17 17 #include <Visualization/operations/FindVariableOperation.h>
18 18
19 19 #include <DragAndDrop/DragDropHelper.h>
20 20 #include <QUuid>
21 21 #include <SqpApplication.h>
22 22 #include <cmath>
23 23
24 24 #include <QLayout>
25 25
26 26 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
27 27
28 28 namespace {
29 29
30 30
31 31 /// Generates a default name for a new graph, according to the number of graphs already displayed in
32 32 /// the zone
33 33 QString defaultGraphName(const QLayout &layout)
34 34 {
35 35 auto count = 0;
36 36 for (auto i = 0; i < layout.count(); ++i) {
37 37 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
38 38 count++;
39 39 }
40 40 }
41 41
42 42 return QObject::tr("Graph %1").arg(count + 1);
43 43 }
44 44
45 45 /**
46 46 * Applies a function to all graphs of the zone represented by its layout
47 47 * @param layout the layout that contains graphs
48 48 * @param fun the function to apply to each graph
49 49 */
50 50 template <typename Fun>
51 51 void processGraphs(QLayout &layout, Fun fun)
52 52 {
53 53 for (auto i = 0; i < layout.count(); ++i) {
54 54 if (auto item = layout.itemAt(i)) {
55 55 if (auto visualizationGraphWidget
56 56 = qobject_cast<VisualizationGraphWidget *>(item->widget())) {
57 57 fun(*visualizationGraphWidget);
58 58 }
59 59 }
60 60 }
61 61 }
62 62
63 63 } // namespace
64 64
65 65 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
66 66
67 67 explicit VisualizationZoneWidgetPrivate()
68 68 : m_SynchronisationGroupId{QUuid::createUuid()},
69 69 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
70 70 {
71 71 }
72 72 QUuid m_SynchronisationGroupId;
73 73 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
74 74
75 75 // Returns the first graph in the zone or nullptr if there is no graph inside
76 76 VisualizationGraphWidget *firstGraph(const VisualizationZoneWidget *zoneWidget) const
77 77 {
78 78 VisualizationGraphWidget *firstGraph = nullptr;
79 79 auto layout = zoneWidget->ui->dragDropContainer->layout();
80 80 if (layout->count() > 0) {
81 81 if (auto visualizationGraphWidget
82 82 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
83 83 firstGraph = visualizationGraphWidget;
84 84 }
85 85 }
86 86
87 87 return firstGraph;
88 88 }
89 89
90 90 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
91 91 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
92 92 VisualizationZoneWidget *zoneWidget);
93 93 };
94 94
95 95 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
96 96 : VisualizationDragWidget{parent},
97 97 ui{new Ui::VisualizationZoneWidget},
98 98 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
99 99 {
100 100 ui->setupUi(this);
101 101
102 102 ui->zoneNameLabel->setText(name);
103 103
104 104 ui->dragDropContainer->setPlaceHolderType(DragDropHelper::PlaceHolderType::Graph);
105 105 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
106 106 VisualizationDragDropContainer::DropBehavior::Inserted);
107 107 ui->dragDropContainer->setMimeType(
108 108 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
109 109 ui->dragDropContainer->setMimeType(MIME_TYPE_TIME_RANGE,
110 110 VisualizationDragDropContainer::DropBehavior::Merged);
111 111 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
112 112 VisualizationDragDropContainer::DropBehavior::Forbidden);
113 113 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
114 114 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
115 115 ui->dragDropContainer);
116 116 });
117 117
118 auto acceptDragWidgetFun = [](auto dragWidget, auto mimeData) {
119 if (!mimeData) {
120 return false;
121 }
122
123 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
124 auto variables = sqpApp->variableController().variablesForMimeData(
125 mimeData->data(MIME_TYPE_VARIABLE_LIST));
126
127 if (variables.count() != 1) {
128 return false;
129 }
130 auto variable = variables.first();
131
132 if (auto graphWidget = dynamic_cast<const VisualizationGraphWidget *>(dragWidget)) {
133 return graphWidget->canDrop(*variable);
134 }
135 }
136
137 return true;
138 };
139 ui->dragDropContainer->setAcceptDragWidgetFunction(acceptDragWidgetFun);
140
118 141 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
119 142 &VisualizationZoneWidget::dropMimeData);
120 143 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
121 144 &VisualizationZoneWidget::dropMimeDataOnGraph);
122 145
123 146 // 'Close' options : widget is deleted when closed
124 147 setAttribute(Qt::WA_DeleteOnClose);
125 148 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
126 149 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
127 150
128 151 // Synchronisation id
129 152 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
130 153 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
131 154 }
132 155
133 156 VisualizationZoneWidget::~VisualizationZoneWidget()
134 157 {
135 158 delete ui;
136 159 }
137 160
138 161 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
139 162 {
140 163 // Synchronize new graph with others in the zone
141 164 impl->m_Synchronizer->addGraph(*graphWidget);
142 165
143 166 ui->dragDropContainer->addDragWidget(graphWidget);
144 167 }
145 168
146 169 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
147 170 {
148 171 // Synchronize new graph with others in the zone
149 172 impl->m_Synchronizer->addGraph(*graphWidget);
150 173
151 174 ui->dragDropContainer->insertDragWidget(index, graphWidget);
152 175 }
153 176
154 177 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
155 178 {
156 179 return createGraph(variable, -1);
157 180 }
158 181
159 182 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
160 183 int index)
161 184 {
162 185 auto graphWidget
163 186 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
164 187
165 188
166 189 // Set graph properties
167 190 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
168 191 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
169 192
170 193
171 194 // Lambda to synchronize zone widget
172 195 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
173 196 const SqpRange &oldGraphRange) {
174 197
175 198 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
176 199 auto frameLayout = ui->dragDropContainer->layout();
177 200 for (auto i = 0; i < frameLayout->count(); ++i) {
178 201 auto graphChild
179 202 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
180 203 if (graphChild && (graphChild != graphWidget)) {
181 204
182 205 auto graphChildRange = graphChild->graphRange();
183 206 switch (zoomType) {
184 207 case AcquisitionZoomType::ZoomIn: {
185 208 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
186 209 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
187 210 graphChildRange.m_TStart += deltaLeft;
188 211 graphChildRange.m_TEnd -= deltaRight;
189 212 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
190 213 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
191 214 << deltaLeft;
192 215 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
193 216 << deltaRight;
194 217 qCDebug(LOG_VisualizationZoneWidget())
195 218 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
196 219
197 220 break;
198 221 }
199 222
200 223 case AcquisitionZoomType::ZoomOut: {
201 224 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
202 225 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
203 226 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
204 227 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
205 228 << deltaLeft;
206 229 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
207 230 << deltaRight;
208 231 qCDebug(LOG_VisualizationZoneWidget())
209 232 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
210 233 graphChildRange.m_TStart -= deltaLeft;
211 234 graphChildRange.m_TEnd += deltaRight;
212 235 break;
213 236 }
214 237 case AcquisitionZoomType::PanRight: {
215 238 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
216 239 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
217 240 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
218 241 graphChildRange.m_TStart += deltaLeft;
219 242 graphChildRange.m_TEnd += deltaRight;
220 243 qCDebug(LOG_VisualizationZoneWidget())
221 244 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
222 245 break;
223 246 }
224 247 case AcquisitionZoomType::PanLeft: {
225 248 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
226 249 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
227 250 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
228 251 graphChildRange.m_TStart -= deltaLeft;
229 252 graphChildRange.m_TEnd -= deltaRight;
230 253 break;
231 254 }
232 255 case AcquisitionZoomType::Unknown: {
233 256 qCDebug(LOG_VisualizationZoneWidget())
234 257 << tr("Impossible to synchronize: zoom type unknown");
235 258 break;
236 259 }
237 260 default:
238 261 qCCritical(LOG_VisualizationZoneWidget())
239 262 << tr("Impossible to synchronize: zoom type not take into account");
240 263 // No action
241 264 break;
242 265 }
243 266 graphChild->enableAcquisition(false);
244 267 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
245 268 << graphChild->graphRange();
246 269 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
247 270 << graphChildRange;
248 271 qCDebug(LOG_VisualizationZoneWidget())
249 272 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
250 273 graphChild->setGraphRange(graphChildRange);
251 274 graphChild->enableAcquisition(true);
252 275 }
253 276 }
254 277 };
255 278
256 279 // connection for synchronization
257 280 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
258 281 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
259 282 &VisualizationZoneWidget::onVariableAdded);
260 283 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
261 284 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
262 285
263 286 auto range = SqpRange{};
264 287 if (auto firstGraph = impl->firstGraph(this)) {
265 288 // Case of a new graph in a existant zone
266 289 range = firstGraph->graphRange();
267 290 }
268 291 else {
269 292 // Case of a new graph as the first of the zone
270 293 range = variable->range();
271 294 }
272 295
273 296 this->insertGraph(index, graphWidget);
274 297
275 298 graphWidget->addVariable(variable, range);
276 299 graphWidget->setYRange(variable);
277 300
278 301 return graphWidget;
279 302 }
280 303
281 304 VisualizationGraphWidget *
282 305 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
283 306 {
284 307 if (variables.isEmpty()) {
285 308 return nullptr;
286 309 }
287 310
288 311 auto graphWidget = createGraph(variables.first(), index);
289 312 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
290 313 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
291 314 }
292 315
293 316 return graphWidget;
294 317 }
295 318
296 319 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
297 320 {
298 321 if (visitor) {
299 322 visitor->visitEnter(this);
300 323
301 324 // Apply visitor to graph children: widgets different from graphs are not visited (no
302 325 // action)
303 326 processGraphs(
304 327 *ui->dragDropContainer->layout(),
305 328 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
306 329
307 330 visitor->visitLeave(this);
308 331 }
309 332 else {
310 333 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
311 334 }
312 335 }
313 336
314 337 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
315 338 {
316 339 // A tab can always accomodate a variable
317 340 Q_UNUSED(variable);
318 341 return true;
319 342 }
320 343
321 344 bool VisualizationZoneWidget::contains(const Variable &variable) const
322 345 {
323 346 Q_UNUSED(variable);
324 347 return false;
325 348 }
326 349
327 350 QString VisualizationZoneWidget::name() const
328 351 {
329 352 return ui->zoneNameLabel->text();
330 353 }
331 354
332 355 QMimeData *VisualizationZoneWidget::mimeData() const
333 356 {
334 357 auto mimeData = new QMimeData;
335 358 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
336 359
337 360 if (auto firstGraph = impl->firstGraph(this)) {
338 361 auto timeRangeData = TimeController::mimeDataForTimeRange(firstGraph->graphRange());
339 362 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
340 363 }
341 364
342 365 return mimeData;
343 366 }
344 367
345 368 bool VisualizationZoneWidget::isDragAllowed() const
346 369 {
347 370 return true;
348 371 }
349 372
350 373 void VisualizationZoneWidget::notifyMouseMoveInGraph(const QPointF &graphPosition,
351 374 const QPointF &plotPosition,
352 375 VisualizationGraphWidget *graphWidget)
353 376 {
354 377 processGraphs(*ui->dragDropContainer->layout(), [&graphPosition, &plotPosition, &graphWidget](
355 378 VisualizationGraphWidget &processedGraph) {
356 379
357 380 switch (sqpApp->plotsCursorMode()) {
358 381 case SqpApplication::PlotsCursorMode::Vertical:
359 382 processedGraph.removeHorizontalCursor();
360 383 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
361 384 break;
362 385 case SqpApplication::PlotsCursorMode::Temporal:
363 386 processedGraph.addVerticalCursor(plotPosition.x());
364 387 processedGraph.removeHorizontalCursor();
365 388 break;
366 389 case SqpApplication::PlotsCursorMode::Horizontal:
367 390 processedGraph.removeVerticalCursor();
368 391 if (&processedGraph == graphWidget) {
369 392 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
370 393 }
371 394 else {
372 395 processedGraph.removeHorizontalCursor();
373 396 }
374 397 break;
375 398 case SqpApplication::PlotsCursorMode::Cross:
376 399 if (&processedGraph == graphWidget) {
377 400 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
378 401 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
379 402 }
380 403 else {
381 404 processedGraph.removeHorizontalCursor();
382 405 processedGraph.removeVerticalCursor();
383 406 }
384 407 break;
385 408 case SqpApplication::PlotsCursorMode::NoCursor:
386 409 processedGraph.removeHorizontalCursor();
387 410 processedGraph.removeVerticalCursor();
388 411 break;
389 412 }
390 413
391 414
392 415 });
393 416 }
394 417
395 418 void VisualizationZoneWidget::notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget)
396 419 {
397 420 processGraphs(*ui->dragDropContainer->layout(), [](VisualizationGraphWidget &processedGraph) {
398 421 processedGraph.removeHorizontalCursor();
399 422 processedGraph.removeVerticalCursor();
400 423 });
401 424 }
402 425
403 426 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
404 427 {
405 428 // Closes graphs in the zone
406 429 processGraphs(*ui->dragDropContainer->layout(),
407 430 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
408 431
409 432 // Delete synchronization group from variable controller
410 433 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
411 434 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
412 435
413 436 QWidget::closeEvent(event);
414 437 }
415 438
416 439 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
417 440 {
418 441 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
419 442 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
420 443 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
421 444 }
422 445
423 446 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
424 447 {
425 448 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
426 449 Q_ARG(std::shared_ptr<Variable>, variable),
427 450 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
428 451 }
429 452
430 453 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
431 454 {
432 455 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
433 456 impl->dropGraph(index, this);
434 457 }
435 458 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
436 459 auto variables = sqpApp->variableController().variablesForMimeData(
437 460 mimeData->data(MIME_TYPE_VARIABLE_LIST));
438 461 impl->dropVariables(variables, index, this);
439 462 }
440 463 else {
441 464 qCWarning(LOG_VisualizationZoneWidget())
442 465 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
443 466 }
444 467 }
445 468
446 469 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
447 470 const QMimeData *mimeData)
448 471 {
449 472 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
450 473 if (!graphWidget) {
451 474 qCWarning(LOG_VisualizationZoneWidget())
452 475 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
453 476 "drop aborted");
454 477 Q_ASSERT(false);
455 478 return;
456 479 }
457 480
458 481 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
459 482 auto variables = sqpApp->variableController().variablesForMimeData(
460 483 mimeData->data(MIME_TYPE_VARIABLE_LIST));
461 484 for (const auto &var : variables) {
462 485 graphWidget->addVariable(var, graphWidget->graphRange());
463 486 }
464 487 }
465 488 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
466 489 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
467 490 graphWidget->setGraphRange(range);
468 491 }
469 492 else {
470 493 qCWarning(LOG_VisualizationZoneWidget())
471 494 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
472 495 }
473 496 }
474 497
475 498 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
476 499 int index, VisualizationZoneWidget *zoneWidget)
477 500 {
478 501 auto &helper = sqpApp->dragDropHelper();
479 502
480 503 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
481 504 if (!graphWidget) {
482 505 qCWarning(LOG_VisualizationZoneWidget())
483 506 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
484 507 "found or invalid.");
485 508 Q_ASSERT(false);
486 509 return;
487 510 }
488 511
489 512 auto parentDragDropContainer
490 513 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
491 514 if (!parentDragDropContainer) {
492 515 qCWarning(LOG_VisualizationZoneWidget())
493 516 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
494 517 "the dropped graph is not found.");
495 518 Q_ASSERT(false);
496 519 return;
497 520 }
498 521
499 522 const auto &variables = graphWidget->variables();
500 523
501 524 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
502 525 // The drop didn't occur in the same zone
503 526
504 527 // Abort the requests for the variables (if any)
505 528 // Commented, because it's not sure if it's needed or not
506 529 // for (const auto& var : variables)
507 530 //{
508 531 // sqpApp->variableController().onAbortProgressRequested(var);
509 532 //}
510 533
511 534 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
512 535 auto nbGraph = parentDragDropContainer->countDragWidget();
513 536 if (nbGraph == 1) {
514 537 // This is the only graph in the previous zone, close the zone
515 538 helper.delayedCloseWidget(previousParentZoneWidget);
516 539 }
517 540 else {
518 541 // Close the graph
519 542 helper.delayedCloseWidget(graphWidget);
520 543 }
521 544
522 545 // Creates the new graph in the zone
523 546 zoneWidget->createGraph(variables, index);
524 547 }
525 548 else {
526 549 // The drop occurred in the same zone or the graph is empty
527 550 // Simple move of the graph, no variable operation associated
528 551 parentDragDropContainer->layout()->removeWidget(graphWidget);
529 552
530 553 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
531 554 // The graph is empty and dropped in a different zone.
532 555 // Take the range of the first graph in the zone (if existing).
533 556 auto layout = zoneWidget->ui->dragDropContainer->layout();
534 557 if (layout->count() > 0) {
535 558 if (auto visualizationGraphWidget
536 559 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
537 560 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
538 561 }
539 562 }
540 563 }
541 564
542 565 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
543 566 }
544 567 }
545 568
546 569 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
547 570 const QList<std::shared_ptr<Variable> > &variables, int index,
548 571 VisualizationZoneWidget *zoneWidget)
549 572 {
550 573 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
551 574 // compatible variable here
552 575 if (variables.count() > 1) {
553 576 qCWarning(LOG_VisualizationZoneWidget())
554 577 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
555 578 "aborted.");
556 579 return;
557 580 }
558 581
559 582 zoneWidget->createGraph(variables, index);
560 583 }
General Comments 0
You need to be logged in to leave comments. Login now