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

Auto status change to "Under Review"

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