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