##// END OF EJS Templates
prevent dropping an variable without data in the visu
trabillard -
r882:da9523540c62
parent child
Show More
@@ -1,336 +1,353
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 #include "Variable/Variable.h"
8 9 #include "Variable/VariableController.h"
9 10
10 11 #include "Common/MimeTypesDef.h"
11 12 #include "Common/VisualizationDef.h"
12 13
13 14 #include <QDir>
14 15 #include <QDragEnterEvent>
15 16 #include <QDragMoveEvent>
16 17 #include <QScrollArea>
17 18 #include <QScrollBar>
18 19 #include <QTimer>
19 20 #include <QVBoxLayout>
20 21
21 22 const int SCROLL_SPEED = 5;
22 23 const int SCROLL_ZONE_SIZE = 50;
23 24
24 25 Q_LOGGING_CATEGORY(LOG_DragDropHelper, "DragDrophelper")
25 26
26 27 struct DragDropScroller::DragDropScrollerPrivate {
27 28
28 29 QList<QScrollArea *> m_ScrollAreas;
29 30 QScrollArea *m_CurrentScrollArea = nullptr;
30 31 std::unique_ptr<QTimer> m_Timer = nullptr;
31 32
32 33 enum class ScrollDirection { up, down, unknown };
33 34 ScrollDirection m_Direction = ScrollDirection::unknown;
34 35
35 36 explicit DragDropScrollerPrivate() : m_Timer{std::make_unique<QTimer>()}
36 37 {
37 38 m_Timer->setInterval(0);
38 39 }
39 40 };
40 41
41 42 DragDropScroller::DragDropScroller(QObject *parent)
42 43 : QObject{parent}, impl{spimpl::make_unique_impl<DragDropScrollerPrivate>()}
43 44 {
44 45 connect(impl->m_Timer.get(), &QTimer::timeout, this, &DragDropScroller::onTimer);
45 46 }
46 47
47 48 void DragDropScroller::addScrollArea(QScrollArea *scrollArea)
48 49 {
49 50 impl->m_ScrollAreas << scrollArea;
50 51 scrollArea->viewport()->setAcceptDrops(true);
51 52 }
52 53
53 54 void DragDropScroller::removeScrollArea(QScrollArea *scrollArea)
54 55 {
55 56 impl->m_ScrollAreas.removeAll(scrollArea);
56 57 scrollArea->viewport()->setAcceptDrops(false);
57 58 }
58 59
59 60 bool DragDropScroller::eventFilter(QObject *obj, QEvent *event)
60 61 {
61 62 if (event->type() == QEvent::DragMove) {
62 63 auto w = static_cast<QWidget *>(obj);
63 64
64 65 if (impl->m_CurrentScrollArea && impl->m_CurrentScrollArea->isAncestorOf(w)) {
65 66 auto moveEvent = static_cast<QDragMoveEvent *>(event);
66 67
67 68 auto pos = moveEvent->pos();
68 69 if (impl->m_CurrentScrollArea->viewport() != w) {
69 70 auto globalPos = w->mapToGlobal(moveEvent->pos());
70 71 pos = impl->m_CurrentScrollArea->viewport()->mapFromGlobal(globalPos);
71 72 }
72 73
73 74 auto isInTopZone = pos.y() > impl->m_CurrentScrollArea->viewport()->size().height()
74 75 - SCROLL_ZONE_SIZE;
75 76 auto isInBottomZone = pos.y() < SCROLL_ZONE_SIZE;
76 77
77 78 if (!isInTopZone && !isInBottomZone) {
78 79 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
79 80 impl->m_Timer->stop();
80 81 }
81 82 else if (!impl->m_Timer->isActive()) {
82 83 impl->m_Direction = isInTopZone ? DragDropScrollerPrivate::ScrollDirection::up
83 84 : DragDropScrollerPrivate::ScrollDirection::down;
84 85 impl->m_Timer->start();
85 86 }
86 87 }
87 88 }
88 89 else if (event->type() == QEvent::DragEnter) {
89 90 auto w = static_cast<QWidget *>(obj);
90 91
91 92 for (auto scrollArea : impl->m_ScrollAreas) {
92 93 if (impl->m_CurrentScrollArea != scrollArea && scrollArea->isAncestorOf(w)) {
93 94 auto enterEvent = static_cast<QDragEnterEvent *>(event);
94 95 enterEvent->acceptProposedAction();
95 96 enterEvent->setDropAction(Qt::IgnoreAction);
96 97 impl->m_CurrentScrollArea = scrollArea;
97 98 break;
98 99 }
99 100 }
100 101 }
101 102 else if (event->type() == QEvent::DragLeave) {
102 103 if (impl->m_CurrentScrollArea) {
103 104 if (!QRect(QPoint(), impl->m_CurrentScrollArea->size())
104 105 .contains(impl->m_CurrentScrollArea->mapFromGlobal(QCursor::pos()))) {
105 106 impl->m_CurrentScrollArea = nullptr;
106 107 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
107 108 impl->m_Timer->stop();
108 109 }
109 110 }
110 111 }
111 112 else if (event->type() == QEvent::Drop) {
112 113 if (impl->m_CurrentScrollArea) {
113 114 impl->m_CurrentScrollArea = nullptr;
114 115 impl->m_Direction = DragDropScrollerPrivate::ScrollDirection::unknown;
115 116 impl->m_Timer->stop();
116 117 }
117 118 }
118 119
119 120 return false;
120 121 }
121 122
122 123 void DragDropScroller::onTimer()
123 124 {
124 125 if (impl->m_CurrentScrollArea) {
125 126 auto mvt = 0;
126 127 switch (impl->m_Direction) {
127 128 case DragDropScrollerPrivate::ScrollDirection::up:
128 129 mvt = SCROLL_SPEED;
129 130 break;
130 131 case DragDropScrollerPrivate::ScrollDirection::down:
131 132 mvt = -SCROLL_SPEED;
132 133 break;
133 134 default:
134 135 break;
135 136 }
136 137
137 138 impl->m_CurrentScrollArea->verticalScrollBar()->setValue(
138 139 impl->m_CurrentScrollArea->verticalScrollBar()->value() + mvt);
139 140 }
140 141 }
141 142
142 143 struct DragDropHelper::DragDropHelperPrivate {
143 144
144 145 VisualizationDragWidget *m_CurrentDragWidget = nullptr;
145 146 std::unique_ptr<QWidget> m_PlaceHolder = nullptr;
146 147 std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr;
147 148 QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using
148 149 // QTemporaryFile to have a name which is not generated.
149 150
150 151 VisualizationDragWidget *m_HighlightedDragWidget = nullptr;
151 152
152 153 QMetaObject::Connection m_DragWidgetDestroyedConnection;
153 154 QMetaObject::Connection m_HighlightedWidgetDestroyedConnection;
154 155
155 156 explicit DragDropHelperPrivate()
156 157 : m_PlaceHolder{std::make_unique<QWidget>()},
157 158 m_DragDropScroller{std::make_unique<DragDropScroller>()}
158 159 {
159 160 m_PlaceHolder->setStyleSheet("background-color: #BBD5EE; border:2px solid #2A7FD4");
160 161 sqpApp->installEventFilter(m_DragDropScroller.get());
161 162
162 163
163 m_ImageTempUrl = QDir::temp().absoluteFilePath("Scqlop_graph.png");
164 m_ImageTempUrl = QDir::temp().absoluteFilePath("Sciqlop_graph.png");
164 165 }
165 166
166 167 void preparePlaceHolder() const
167 168 {
168 169 if (m_CurrentDragWidget) {
169 170 m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size());
170 171 m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy());
171 172 }
172 173 else {
173 174 // Configuration of the placeHolder when there is no dragWidget
174 175 // (for instance with a drag from a variable)
175 176
176 177 m_PlaceHolder->setMinimumSize(0, GRAPH_MINIMUM_HEIGHT);
177 178 m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
178 179 }
179 180 }
180 181 };
181 182
182 183
183 184 DragDropHelper::DragDropHelper() : impl{spimpl::make_unique_impl<DragDropHelperPrivate>()}
184 185 {
185 186 }
186 187
187 188 DragDropHelper::~DragDropHelper()
188 189 {
189 190 QFile::remove(impl->m_ImageTempUrl);
190 191 }
191 192
192 193 void DragDropHelper::resetDragAndDrop()
193 194 {
194 195 setCurrentDragWidget(nullptr);
195 196 impl->m_HighlightedDragWidget = nullptr;
196 197 }
197 198
198 199 void DragDropHelper::setCurrentDragWidget(VisualizationDragWidget *dragWidget)
199 200 {
200 201 if (impl->m_CurrentDragWidget) {
201 202
202 203 QObject::disconnect(impl->m_DragWidgetDestroyedConnection);
203 204 }
204 205
205 206 if (dragWidget) {
206 207 // ensures the impl->m_CurrentDragWidget is reset when the widget is destroyed
207 208 impl->m_DragWidgetDestroyedConnection
208 209 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
209 210 [this]() { impl->m_CurrentDragWidget = nullptr; });
210 211 }
211 212
212 213 impl->m_CurrentDragWidget = dragWidget;
213 214 }
214 215
215 216 VisualizationDragWidget *DragDropHelper::getCurrentDragWidget() const
216 217 {
217 218 return impl->m_CurrentDragWidget;
218 219 }
219 220
220 221
221 222 QWidget &DragDropHelper::placeHolder() const
222 223 {
223 224 return *impl->m_PlaceHolder;
224 225 }
225 226
226 227 void DragDropHelper::insertPlaceHolder(QVBoxLayout *layout, int index)
227 228 {
228 229 removePlaceHolder();
229 230 impl->preparePlaceHolder();
230 231 layout->insertWidget(index, impl->m_PlaceHolder.get());
231 232 impl->m_PlaceHolder->show();
232 233 }
233 234
234 235 void DragDropHelper::removePlaceHolder()
235 236 {
236 237 auto parentWidget = impl->m_PlaceHolder->parentWidget();
237 238 if (parentWidget) {
238 239 parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get());
239 240 impl->m_PlaceHolder->setParent(nullptr);
240 241 impl->m_PlaceHolder->hide();
241 242 }
242 243 }
243 244
244 245 bool DragDropHelper::isPlaceHolderSet() const
245 246 {
246 247 return impl->m_PlaceHolder->parentWidget();
247 248 }
248 249
249 250 void DragDropHelper::addDragDropScrollArea(QScrollArea *scrollArea)
250 251 {
251 252 impl->m_DragDropScroller->addScrollArea(scrollArea);
252 253 }
253 254
254 255 void DragDropHelper::removeDragDropScrollArea(QScrollArea *scrollArea)
255 256 {
256 257 impl->m_DragDropScroller->removeScrollArea(scrollArea);
257 258 }
258 259
259 260 QUrl DragDropHelper::imageTemporaryUrl(const QImage &image) const
260 261 {
261 262 image.save(impl->m_ImageTempUrl);
262 263 return QUrl::fromLocalFile(impl->m_ImageTempUrl);
263 264 }
264 265
265 266 void DragDropHelper::setHightlightedDragWidget(VisualizationDragWidget *dragWidget)
266 267 {
267 268 if (impl->m_HighlightedDragWidget) {
268 269 impl->m_HighlightedDragWidget->highlightForMerge(false);
269 270 QObject::disconnect(impl->m_HighlightedWidgetDestroyedConnection);
270 271 }
271 272
272 273 if (dragWidget) {
273 274 dragWidget->highlightForMerge(true);
274 275
275 276 // ensures the impl->m_HighlightedDragWidget is reset when the widget is destroyed
276 277 impl->m_DragWidgetDestroyedConnection
277 278 = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed,
278 279 [this]() { impl->m_HighlightedDragWidget = nullptr; });
279 280 }
280 281
281 282 impl->m_HighlightedDragWidget = dragWidget;
282 283 }
283 284
284 285 VisualizationDragWidget *DragDropHelper::getHightlightedDragWidget() const
285 286 {
286 287 return impl->m_HighlightedDragWidget;
287 288 }
288 289
289 290 bool DragDropHelper::checkMimeDataForVisualization(const QMimeData *mimeData,
290 291 VisualizationDragDropContainer *dropContainer)
291 292 {
292 293 if (!mimeData || !dropContainer) {
293 294 qCWarning(LOG_DragDropHelper()) << QObject::tr(
294 295 "DragDropHelper::checkMimeDataForVisualization, invalid input parameters.");
295 296 Q_ASSERT(false);
297 return false;
296 298 }
297 299
298 auto result = true;
300 auto result = false;
299 301
300 302 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
301 303 auto variables = sqpApp->variableController().variablesForMimeData(
302 304 mimeData->data(MIME_TYPE_VARIABLE_LIST));
303 305
304 306 if (variables.count() == 1) {
305 // Check that the viariable is not already in a graph
306 307
307 // Search for the top level VisualizationWidget
308 auto variable = variables.first();
309 if (variable->dataSeries() != nullptr) {
310
311 // Check that the variable is not already in a graph
312
308 313 auto parent = dropContainer->parentWidget();
309 314 while (parent && qobject_cast<VisualizationWidget *>(parent) == nullptr) {
310 parent = parent->parentWidget();
315 parent = parent->parentWidget(); // Search for the top level VisualizationWidget
311 316 }
312 317
313 318 if (parent) {
314 319 auto visualizationWidget = static_cast<VisualizationWidget *>(parent);
315 320
316 FindVariableOperation findVariableOperation{variables.first()};
321 FindVariableOperation findVariableOperation{variable};
317 322 visualizationWidget->accept(&findVariableOperation);
318 323 auto variableContainers = findVariableOperation.result();
319 if (!variableContainers.empty()) {
320 result = false;
324 if (variableContainers.empty()) {
325 result = true;
326 }
327 else {
328 // result = false: the variable already exist in the visualisation
321 329 }
322 330 }
323 331 else {
324 332 qCWarning(LOG_DragDropHelper()) << QObject::tr(
325 333 "DragDropHelper::checkMimeDataForVisualization, the parent "
326 "VisualizationWidget cannot be found.");
327 result = false;
334 "VisualizationWidget cannot be found. Cannot check if the variable is "
335 "already used or not.");
328 336 }
329 337 }
330 338 else {
331 result = false;
339 // result = false: the variable is not fully loaded
332 340 }
333 341 }
342 else {
343 // result = false: cannot drop multiple variables in the visualisation
344 }
345 }
346 else {
347 // Other MIME data
348 // no special rules, accepted by default
349 result = true;
350 }
334 351
335 352 return result;
336 353 }
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