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

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

Changed commits:
  * 1 added
  * 0 removed

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