1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include <QtTest/QtTest>
43 #include <QtTest/QSignalSpy>
44 #include <QtQuick/qquickitem.h>
45 #include <QtQuick/qquickview.h>
46 #include <QtQml/qqmlcontext.h>
47 #include <QtQml/qqmlengine.h>
48 #include <QtQml/qqmlexpression.h>
50 template <typename T> static T evaluate(QObject *scope, const QString &expression)
52 QQmlExpression expr(qmlContext(scope), scope, expression);
53 QVariant result = expr.evaluate();
55 qWarning() << expr.error().toString();
56 return result.value<T>();
59 template <> void evaluate<void>(QObject *scope, const QString &expression)
61 QQmlExpression expr(qmlContext(scope), scope, expression);
64 qWarning() << expr.error().toString();
67 Q_DECLARE_METATYPE(Qt::DropActions)
69 class TestDropTarget : public QQuickItem
73 TestDropTarget(QQuickItem *parent = 0)
79 , acceptAction(Qt::MoveAction)
80 , defaultAction(Qt::IgnoreAction)
81 , proposedAction(Qt::IgnoreAction)
84 setFlags(ItemAcceptsDrops);
93 defaultAction = Qt::IgnoreAction;
94 proposedAction = Qt::IgnoreAction;
95 supportedActions = Qt::IgnoreAction;
98 void dragEnterEvent(QDragEnterEvent *event)
101 position = event->pos();
102 defaultAction = event->dropAction();
103 proposedAction = event->proposedAction();
104 supportedActions = event->possibleActions();
105 event->setAccepted(accept);
108 void dragMoveEvent(QDragMoveEvent *event)
111 position = event->pos();
112 defaultAction = event->dropAction();
113 proposedAction = event->proposedAction();
114 supportedActions = event->possibleActions();
115 event->setAccepted(accept);
118 void dragLeaveEvent(QDragLeaveEvent *event)
121 event->setAccepted(accept);
124 void dropEvent(QDropEvent *event)
127 position = event->pos();
128 defaultAction = event->dropAction();
129 proposedAction = event->proposedAction();
130 supportedActions = event->possibleActions();
131 event->setDropAction(acceptAction);
132 event->setAccepted(accept);
139 Qt::DropAction acceptAction;
140 Qt::DropAction defaultAction;
141 Qt::DropAction proposedAction;
142 Qt::DropActions supportedActions;
147 class tst_QQuickDrag: public QObject
152 void cleanupTestCase();
159 void supportedActions();
160 void proposedAction();
163 void recursion_data();
170 void tst_QQuickDrag::initTestCase()
175 void tst_QQuickDrag::cleanupTestCase()
180 void tst_QQuickDrag::active()
183 TestDropTarget dropTarget(window.rootItem());
184 dropTarget.setSize(QSizeF(100, 100));
185 QQmlComponent component(&engine);
187 "import QtQuick 2.0\n"
189 "property bool dragActive: Drag.active\n"
190 "property Item dragTarget: Drag.target\n"
192 "width: 10; height: 10\n"
194 QScopedPointer<QObject> object(component.create());
195 QQuickItem *item = qobject_cast<QQuickItem *>(object.data());
197 item->setParentItem(&dropTarget);
199 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
200 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
202 evaluate<void>(item, "Drag.active = true");
203 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
204 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
205 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&dropTarget));
206 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&dropTarget));
207 QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0);
210 evaluate<void>(item, "Drag.active = false");
211 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
212 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
213 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
214 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
215 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 1);
218 evaluate<void>(item, "Drag.cancel()");
219 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
220 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
221 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
222 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
223 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0);
226 evaluate<void>(item, "Drag.start()");
227 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
228 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
229 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&dropTarget));
230 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&dropTarget));
231 QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0);
233 // Start while a drag is active, cancels the previous drag and starts a new one.
235 evaluate<void>(item, "Drag.start()");
236 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
237 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
238 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&dropTarget));
239 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&dropTarget));
240 QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 1);
243 evaluate<void>(item, "Drag.cancel()");
244 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
245 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
246 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
247 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
248 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 1);
250 // Enter events aren't sent to items without the QQuickItem::ItemAcceptsDrops flag.
251 dropTarget.setFlags(QQuickItem::Flags());
254 evaluate<void>(item, "Drag.active = true");
255 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
256 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
257 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
258 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
259 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0);
262 evaluate<void>(item, "Drag.active = false");
263 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
264 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
265 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
266 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
267 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0);
269 dropTarget.setFlags(QQuickItem::ItemAcceptsDrops);
272 evaluate<void>(item, "Drag.active = true");
273 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
274 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
275 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&dropTarget));
276 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&dropTarget));
277 QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0);
279 dropTarget.setFlags(QQuickItem::Flags());
282 evaluate<void>(item, "Drag.active = false");
283 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
284 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
285 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
286 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
287 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 1);
289 // Follow up events aren't sent to items if the enter event isn't accepted.
290 dropTarget.setFlags(QQuickItem::ItemAcceptsDrops);
291 dropTarget.accept = false;
294 evaluate<void>(item, "Drag.active = true");
295 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
296 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
297 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
298 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
299 QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0);
302 evaluate<void>(item, "Drag.active = false");
303 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
304 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
305 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
306 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
307 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0);
309 dropTarget.accept = true;
312 evaluate<void>(item, "Drag.active = true");
313 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
314 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
315 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&dropTarget));
316 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&dropTarget));
317 QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0);
319 dropTarget.accept = false;
322 evaluate<void>(item, "Drag.active = false");
323 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
324 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
325 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
326 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
327 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 1);
329 // Events are sent to hidden or disabled items.
330 dropTarget.accept = true;
331 dropTarget.setVisible(false);
333 evaluate<void>(item, "Drag.active = true");
334 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
335 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
336 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
337 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
338 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0);
340 evaluate<void>(item, "Drag.active = false");
341 dropTarget.setVisible(true);
343 dropTarget.setOpacity(0.0);
345 evaluate<void>(item, "Drag.active = true");
346 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
347 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
348 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&dropTarget));
349 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&dropTarget));
350 QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0);
352 evaluate<void>(item, "Drag.active = false");
353 dropTarget.setOpacity(1.0);
355 dropTarget.setEnabled(false);
357 evaluate<void>(item, "Drag.active = true");
358 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
359 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
360 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
361 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
362 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0);
364 evaluate<void>(item, "Drag.active = false");
365 dropTarget.setEnabled(true);
368 // Queued move events are discarded if the drag is cancelled.
369 evaluate<void>(item, "Drag.active = true");
370 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
371 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
372 QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0); QCOMPARE(dropTarget.moveEvents, 0);
375 item->setPos(QPointF(80, 80));
376 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
377 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
378 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0); QCOMPARE(dropTarget.moveEvents, 0);
380 evaluate<void>(item, "Drag.active = false");
381 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
382 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
383 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 1); QCOMPARE(dropTarget.moveEvents, 0);
386 QCoreApplication::processEvents();
387 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0); QCOMPARE(dropTarget.moveEvents, 0);
390 void tst_QQuickDrag::drop()
393 TestDropTarget outerTarget(window.rootItem());
394 outerTarget.setSize(QSizeF(100, 100));
395 outerTarget.acceptAction = Qt::CopyAction;
396 TestDropTarget innerTarget(&outerTarget);
397 innerTarget.setSize(QSizeF(100, 100));
398 innerTarget.acceptAction = Qt::MoveAction;
399 QQmlComponent component(&engine);
401 "import QtQuick 2.0\n"
403 "property bool dragActive: Drag.active\n"
404 "property Item dragTarget: Drag.target\n"
406 "width: 10; height: 10\n"
408 QScopedPointer<QObject> object(component.create());
409 QQuickItem *item = qobject_cast<QQuickItem *>(object.data());
411 item->setParentItem(&outerTarget);
413 innerTarget.reset(); outerTarget.reset();
414 evaluate<void>(item, "Drag.active = true");
415 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
416 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
417 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&innerTarget));
418 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&innerTarget));
419 QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0);
420 QCOMPARE(innerTarget.enterEvents, 1); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0);
422 innerTarget.reset(); outerTarget.reset();
423 QCOMPARE(evaluate<bool>(item, "Drag.drop() == Qt.MoveAction"), true);
424 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
425 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
426 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&innerTarget));
427 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&innerTarget));
428 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 1); QCOMPARE(outerTarget.dropEvents, 0);
429 QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 1);
431 innerTarget.reset(); outerTarget.reset();
432 evaluate<void>(item, "Drag.active = true");
433 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
434 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
435 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&innerTarget));
436 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&innerTarget));
437 QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0);
438 QCOMPARE(innerTarget.enterEvents, 1); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0);
440 // Inner target declines the drop so it is propagated to the outer target.
441 innerTarget.accept = false;
443 innerTarget.reset(); outerTarget.reset();
444 QCOMPARE(evaluate<bool>(item, "Drag.drop() == Qt.CopyAction"), true);
445 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
446 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
447 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget));
448 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget));
449 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 1);
450 QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 1);
453 // Inner target doesn't accept enter so drop goes directly to outer.
454 innerTarget.accept = true;
455 innerTarget.setFlags(QQuickItem::Flags());
457 innerTarget.reset(); outerTarget.reset();
458 evaluate<void>(item, "Drag.active = true");
459 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
460 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
461 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget));
462 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget));
463 QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0);
464 QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0);
466 innerTarget.reset(); outerTarget.reset();
467 QCOMPARE(evaluate<bool>(item, "Drag.drop() == Qt.CopyAction"), true);
468 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
469 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
470 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget));
471 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget));
472 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 1);
473 QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0);
475 // Neither target accepts drop so Qt::IgnoreAction is returned.
476 innerTarget.reset(); outerTarget.reset();
477 evaluate<void>(item, "Drag.active = true");
478 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
479 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
480 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget));
481 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget));
482 QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0);
483 QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0);
485 outerTarget.accept = false;
487 innerTarget.reset(); outerTarget.reset();
488 QCOMPARE(evaluate<bool>(item, "Drag.drop() == Qt.IgnoreAction"), true);
489 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
490 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
491 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
492 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
493 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 1);
494 QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0);
496 // drop doesn't send an event and returns Qt.IgnoreAction if not active.
497 innerTarget.accept = true;
498 outerTarget.accept = true;
499 innerTarget.reset(); outerTarget.reset();
500 QCOMPARE(evaluate<bool>(item, "Drag.drop() == Qt.IgnoreAction"), true);
501 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
502 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
503 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
504 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
505 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0);
506 QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0);
508 // Queued move event is delivered before a drop event.
509 innerTarget.reset(); outerTarget.reset();
510 evaluate<void>(item, "Drag.active = true");
511 item->setPos(QPointF(80, 80));
512 evaluate<void>(item, "Drag.drop()");
513 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
514 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
515 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget));
516 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget));
517 QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 1); QCOMPARE(outerTarget.moveEvents, 1);
518 QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0); QCOMPARE(innerTarget.moveEvents, 0);
520 innerTarget.reset(); outerTarget.reset();
521 QCoreApplication::processEvents();
522 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0); QCOMPARE(outerTarget.moveEvents, 0);
523 QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0); QCOMPARE(innerTarget.moveEvents, 0);
526 void tst_QQuickDrag::move()
529 TestDropTarget outerTarget(window.rootItem());
530 outerTarget.setSize(QSizeF(100, 100));
531 TestDropTarget leftTarget(&outerTarget);
532 leftTarget.setPos(QPointF(0, 35));
533 leftTarget.setSize(QSizeF(30, 30));
534 TestDropTarget rightTarget(&outerTarget);
535 rightTarget.setPos(QPointF(70, 35));
536 rightTarget.setSize(QSizeF(30, 30));
537 QQmlComponent component(&engine);
539 "import QtQuick 2.0\n"
541 "property bool dragActive: Drag.active\n"
542 "property Item dragTarget: Drag.target\n"
544 "width: 10; height: 10\n"
546 QScopedPointer<QObject> object(component.create());
547 QQuickItem *item = qobject_cast<QQuickItem *>(object.data());
549 item->setParentItem(&outerTarget);
551 evaluate<void>(item, "Drag.active = true");
552 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
553 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
554 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget));
555 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget));
556 QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 0);
557 QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0);
558 QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0);
559 QCOMPARE(outerTarget.position.x(), qreal(50)); QCOMPARE(outerTarget.position.y(), qreal(50));
561 // Move within the outer target.
562 outerTarget.reset(); leftTarget.reset(); rightTarget.reset();
563 item->setPos(QPointF(60, 50));
564 // Move event is delivered in the event loop.
565 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 0);
566 QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0);
567 QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0);
568 QCoreApplication::processEvents();
569 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget));
570 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget));
571 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 1);
572 QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0);
573 QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0);
574 QCOMPARE(outerTarget.position.x(), qreal(60)); QCOMPARE(outerTarget.position.y(), qreal(50));
576 // Move into the right target.
577 outerTarget.reset(); leftTarget.reset(); rightTarget.reset();
578 // Setting X and Y individually should still only generate on move.
581 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 0);
582 QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0);
583 QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0);
584 QCoreApplication::processEvents();
585 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&rightTarget));
586 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&rightTarget));
587 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 1);
588 QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0);
589 QCOMPARE(rightTarget.enterEvents, 1); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0);
590 QCOMPARE(outerTarget.position.x(), qreal(75)); QCOMPARE(outerTarget.position.y(), qreal(50));
591 QCOMPARE(rightTarget.position.x(), qreal(5)); QCOMPARE(rightTarget.position.y(), qreal(15));
593 // Move into the left target.
594 outerTarget.reset(); leftTarget.reset(); rightTarget.reset();
595 item->setPos(QPointF(25, 50));
596 QCoreApplication::processEvents();
597 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&leftTarget));
598 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&leftTarget));
599 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 1);
600 QCOMPARE(leftTarget .enterEvents, 1); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0);
601 QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 1); QCOMPARE(rightTarget.moveEvents, 0);
602 QCOMPARE(outerTarget.position.x(), qreal(25)); QCOMPARE(outerTarget.position.y(), qreal(50));
603 QCOMPARE(leftTarget.position.x(), qreal(25)); QCOMPARE(leftTarget.position.y(), qreal(15));
605 // Move within the left target.
606 outerTarget.reset(); leftTarget.reset(); rightTarget.reset();
607 item->setPos(QPointF(25, 40));
608 QCoreApplication::processEvents();
609 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&leftTarget));
610 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&leftTarget));
611 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 1);
612 QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 1);
613 QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0);
614 QCOMPARE(outerTarget.position.x(), qreal(25)); QCOMPARE(outerTarget.position.y(), qreal(40));
615 QCOMPARE(leftTarget.position.x(), qreal(25)); QCOMPARE(leftTarget.position.y(), qreal(5));
617 // Move out of all targets.
618 outerTarget.reset(); leftTarget.reset(); rightTarget.reset();
619 item->setPos(QPointF(110, 50));
620 QCoreApplication::processEvents();
621 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
622 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
623 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 1); QCOMPARE(outerTarget.moveEvents, 0);
624 QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 1); QCOMPARE(leftTarget .moveEvents, 0);
625 QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0);
627 // Stop the right target accepting drag events and move into it.
628 rightTarget.accept = false;
630 outerTarget.reset(); leftTarget.reset(); rightTarget.reset();
631 item->setPos(QPointF(80, 50));
632 QCoreApplication::processEvents();
633 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget));
634 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget));
635 QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 0);
636 QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0);
637 QCOMPARE(rightTarget.enterEvents, 1); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0);
638 QCOMPARE(outerTarget.position.x(), qreal(80)); QCOMPARE(outerTarget.position.y(), qreal(50));
640 // Stop the outer target accepting drag events after it has accepted an enter event.
641 outerTarget.accept = false;
643 outerTarget.reset(); leftTarget.reset(); rightTarget.reset();
644 item->setPos(QPointF(60, 50));
645 QCoreApplication::processEvents();
646 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget));
647 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget));
648 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 1);
649 QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0);
650 QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0);
651 QCOMPARE(outerTarget.position.x(), qreal(60)); QCOMPARE(outerTarget.position.y(), qreal(50));
653 // Clear the QQuickItem::ItemAcceptsDrops flag from the outer target after it accepted an enter event.
654 outerTarget.setFlags(QQuickItem::Flags());
656 outerTarget.reset(); leftTarget.reset(); rightTarget.reset();
657 item->setPos(QPointF(40, 50));
658 QCoreApplication::processEvents();
659 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget));
660 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget));
661 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 1);
662 QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0);
663 QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0);
664 QCOMPARE(outerTarget.position.x(), qreal(40)); QCOMPARE(outerTarget.position.y(), qreal(50));
666 // Clear the QQuickItem::ItemAcceptsDrops flag from the left target before it accepts an enter event.
667 leftTarget.setFlags(QQuickItem::Flags());
669 outerTarget.reset(); leftTarget.reset(); rightTarget.reset();
670 item->setPos(QPointF(25, 50));
671 QCoreApplication::processEvents();
672 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget));
673 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget));
674 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 1);
675 QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0);
676 QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0);
677 QCOMPARE(outerTarget.position.x(), qreal(25)); QCOMPARE(outerTarget.position.y(), qreal(50));
680 void tst_QQuickDrag::parentChange()
682 QQuickWindow window1;
683 TestDropTarget dropTarget1(window1.rootItem());
684 dropTarget1.setSize(QSizeF(100, 100));
686 QQuickWindow window2;
687 TestDropTarget dropTarget2(window2.rootItem());
688 dropTarget2.setSize(QSizeF(100, 100));
690 QQmlComponent component(&engine);
692 "import QtQuick 2.0\n"
694 "property real hotSpotX: Drag.hotSpot.x\n"
695 "property real hotSpotY: Drag.hotSpot.y\n"
697 "width: 10; height: 10\n"
698 "Drag.active: true\n"
700 QScopedPointer<QObject> object(component.create());
701 QQuickItem *item = qobject_cast<QQuickItem *>(object.data());
704 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
706 // Verify setting a parent item for an item with an active drag sends an enter event.
707 item->setParentItem(window1.rootItem());
708 QCOMPARE(dropTarget1.enterEvents, 0);
709 QCoreApplication::processEvents();
710 QCOMPARE(dropTarget1.enterEvents, 1);
712 // Changing the parent within the same window should send a move event.
713 item->setParentItem(&dropTarget1);
714 QCOMPARE(dropTarget1.enterEvents, 1);
715 QCOMPARE(dropTarget1.moveEvents, 0);
716 QCoreApplication::processEvents();
717 QCOMPARE(dropTarget1.enterEvents, 1);
718 QCOMPARE(dropTarget1.moveEvents, 1);
720 // Changing the parent to an item in another window sends a leave event in the old window
721 // and an enter on the new window.
722 item->setParentItem(window2.rootItem());
723 QCOMPARE(dropTarget1.enterEvents, 1);
724 QCOMPARE(dropTarget1.moveEvents, 1);
725 QCOMPARE(dropTarget1.leaveEvents, 0);
726 QCOMPARE(dropTarget2.enterEvents, 0);
727 QCoreApplication::processEvents();
728 QCOMPARE(dropTarget1.enterEvents, 1);
729 QCOMPARE(dropTarget1.moveEvents, 1);
730 QCOMPARE(dropTarget1.leaveEvents, 1);
731 QCOMPARE(dropTarget2.enterEvents, 1);
733 // Removing then parent item sends a leave event.
734 item->setParentItem(0);
735 QCOMPARE(dropTarget1.enterEvents, 1);
736 QCOMPARE(dropTarget1.moveEvents, 1);
737 QCOMPARE(dropTarget1.leaveEvents, 1);
738 QCOMPARE(dropTarget2.enterEvents, 1);
739 QCOMPARE(dropTarget2.leaveEvents, 0);
740 QCoreApplication::processEvents();
741 QCOMPARE(dropTarget1.enterEvents, 1);
742 QCOMPARE(dropTarget1.moveEvents, 1);
743 QCOMPARE(dropTarget1.leaveEvents, 1);
744 QCOMPARE(dropTarget2.enterEvents, 1);
745 QCOMPARE(dropTarget2.leaveEvents, 1);
747 // Go around again and verify no events if active is false.
748 evaluate<void>(item, "Drag.active = false");
749 item->setParentItem(window1.rootItem());
750 QCoreApplication::processEvents();
752 item->setParentItem(&dropTarget1);
753 QCoreApplication::processEvents();
755 item->setParentItem(window2.rootItem());
756 QCoreApplication::processEvents();
758 item->setParentItem(0);
759 QCoreApplication::processEvents();
760 QCOMPARE(dropTarget1.enterEvents, 1);
761 QCOMPARE(dropTarget1.moveEvents, 1);
762 QCOMPARE(dropTarget1.leaveEvents, 1);
763 QCOMPARE(dropTarget2.enterEvents, 1);
764 QCOMPARE(dropTarget2.leaveEvents, 1);
767 void tst_QQuickDrag::hotSpot()
770 TestDropTarget dropTarget(window.rootItem());
771 dropTarget.setSize(QSizeF(100, 100));
772 QQmlComponent component(&engine);
774 "import QtQuick 2.0\n"
776 "property real hotSpotX: Drag.hotSpot.x\n"
777 "property real hotSpotY: Drag.hotSpot.y\n"
779 "width: 10; height: 10\n"
781 QScopedPointer<QObject> object(component.create());
782 QQuickItem *item = qobject_cast<QQuickItem *>(object.data());
784 item->setParentItem(&dropTarget);
786 QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.x"), qreal(0));
787 QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.y"), qreal(0));
788 QCOMPARE(evaluate<qreal>(item, "hotSpotX"), qreal(0));
789 QCOMPARE(evaluate<qreal>(item, "hotSpotY"), qreal(0));
791 evaluate<void>(item, "{ Drag.start(); Drag.cancel() }");
792 QCOMPARE(dropTarget.position.x(), qreal(50));
793 QCOMPARE(dropTarget.position.y(), qreal(50));
795 evaluate<void>(item, "{ Drag.hotSpot.x = 5, Drag.hotSpot.y = 5 }");
796 QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.x"), qreal(5));
797 QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.y"), qreal(5));
798 QCOMPARE(evaluate<qreal>(item, "hotSpotX"), qreal(5));
799 QCOMPARE(evaluate<qreal>(item, "hotSpotY"), qreal(5));
801 evaluate<void>(item, "Drag.start()");
802 QCOMPARE(dropTarget.position.x(), qreal(55));
803 QCOMPARE(dropTarget.position.y(), qreal(55));
805 item->setPos(QPointF(30, 20));
806 QCoreApplication::processEvents();
807 QCOMPARE(dropTarget.position.x(), qreal(35));
808 QCOMPARE(dropTarget.position.y(), qreal(25));
810 evaluate<void>(item, "{ Drag.hotSpot.x = 10; Drag.hotSpot.y = 10 }");
811 QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.x"), qreal(10));
812 QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.y"), qreal(10));
813 QCOMPARE(evaluate<qreal>(item, "hotSpotX"), qreal(10));
814 QCOMPARE(evaluate<qreal>(item, "hotSpotY"), qreal(10));
816 // Setting the hotSpot will deliver a move event in the event loop.
817 QCOMPARE(dropTarget.position.x(), qreal(35));
818 QCOMPARE(dropTarget.position.y(), qreal(25));
819 QCoreApplication::processEvents();
820 QCOMPARE(dropTarget.position.x(), qreal(40));
821 QCOMPARE(dropTarget.position.y(), qreal(30));
823 item->setPos(QPointF(10, 20));
824 QCoreApplication::processEvents();
825 QCOMPARE(dropTarget.position.x(), qreal(20));
826 QCOMPARE(dropTarget.position.y(), qreal(30));
828 evaluate<void>(item, "{ Drag.hotSpot.x = 10; Drag.hotSpot.y = 10 }");
831 void tst_QQuickDrag::supportedActions()
834 TestDropTarget dropTarget(window.rootItem());
835 dropTarget.setSize(QSizeF(100, 100));
836 QQmlComponent component(&engine);
838 "import QtQuick 2.0\n"
840 "property int supportedActions: Drag.supportedActions\n"
842 "width: 10; height: 10\n"
844 QScopedPointer<QObject> object(component.create());
845 QQuickItem *item = qobject_cast<QQuickItem *>(object.data());
847 item->setParentItem(&dropTarget);
849 QCOMPARE(evaluate<bool>(item, "Drag.supportedActions == Qt.CopyAction | Qt.MoveAction | Qt.LinkAction"), true);
850 QCOMPARE(evaluate<bool>(item, "supportedActions == Qt.CopyAction | Qt.MoveAction | Qt.LinkAction"), true);
851 evaluate<void>(item, "{ Drag.start(); Drag.cancel() }");
852 QCOMPARE(dropTarget.supportedActions, Qt::CopyAction | Qt::MoveAction | Qt::LinkAction);
855 evaluate<void>(item, "Drag.supportedActions = Qt.CopyAction | Qt.MoveAction");
856 QCOMPARE(evaluate<bool>(item, "Drag.supportedActions == Qt.CopyAction | Qt.MoveAction"), true);
857 QCOMPARE(evaluate<bool>(item, "supportedActions == Qt.CopyAction | Qt.MoveAction"), true);
858 evaluate<void>(item, "Drag.start()");
859 QCOMPARE(dropTarget.supportedActions, Qt::CopyAction | Qt::MoveAction);
860 QCOMPARE(dropTarget.leaveEvents, 0);
861 QCOMPARE(dropTarget.enterEvents, 1);
863 // Changing the supported actions will restart the drag, after a delay to avoid any
865 evaluate<void>(item, "Drag.supportedActions = Qt.MoveAction");
866 QCOMPARE(evaluate<bool>(item, "Drag.supportedActions == Qt.MoveAction"), true);
867 QCOMPARE(evaluate<bool>(item, "supportedActions == Qt.MoveAction"), true);
868 item->setPos(QPointF(60, 60));
869 QCOMPARE(dropTarget.supportedActions, Qt::CopyAction | Qt::MoveAction);
870 QCOMPARE(dropTarget.leaveEvents, 0);
871 QCOMPARE(dropTarget.enterEvents, 1);
872 QCoreApplication::processEvents();
873 QCOMPARE(dropTarget.supportedActions, Qt::MoveAction);
874 QCOMPARE(dropTarget.leaveEvents, 1);
875 QCOMPARE(dropTarget.enterEvents, 2);
877 // Calling start with proposed actions will override the current actions for the next sequence.
878 evaluate<void>(item, "Drag.start(Qt.CopyAction)");
879 QCOMPARE(evaluate<bool>(item, "Drag.supportedActions == Qt.MoveAction"), true);
880 QCOMPARE(evaluate<bool>(item, "supportedActions == Qt.MoveAction"), true);
881 QCOMPARE(dropTarget.supportedActions, Qt::CopyAction);
883 evaluate<void>(item, "Drag.start()");
884 QCOMPARE(evaluate<bool>(item, "Drag.supportedActions == Qt.MoveAction"), true);
885 QCOMPARE(evaluate<bool>(item, "supportedActions == Qt.MoveAction"), true);
886 QCOMPARE(dropTarget.supportedActions, Qt::MoveAction);
889 void tst_QQuickDrag::proposedAction()
892 TestDropTarget dropTarget(window.rootItem());
893 dropTarget.setSize(QSizeF(100, 100));
894 QQmlComponent component(&engine);
896 "import QtQuick 2.0\n"
898 "property int proposedAction: Drag.proposedAction\n"
900 "width: 10; height: 10\n"
902 QScopedPointer<QObject> object(component.create());
903 QQuickItem *item = qobject_cast<QQuickItem *>(object.data());
905 item->setParentItem(&dropTarget);
907 QCOMPARE(evaluate<bool>(item, "Drag.proposedAction == Qt.MoveAction"), true);
908 QCOMPARE(evaluate<bool>(item, "proposedAction == Qt.MoveAction"), true);
909 evaluate<void>(item, "{ Drag.start(); Drag.cancel() }");
910 QCOMPARE(dropTarget.defaultAction, Qt::MoveAction);
911 QCOMPARE(dropTarget.proposedAction, Qt::MoveAction);
913 evaluate<void>(item, "Drag.proposedAction = Qt.CopyAction");
914 QCOMPARE(evaluate<bool>(item, "Drag.proposedAction == Qt.CopyAction"), true);
915 QCOMPARE(evaluate<bool>(item, "proposedAction == Qt.CopyAction"), true);
916 evaluate<void>(item, "Drag.start()");
917 QCOMPARE(dropTarget.defaultAction, Qt::CopyAction);
918 QCOMPARE(dropTarget.proposedAction, Qt::CopyAction);
920 // The proposed action can change during a drag.
921 evaluate<void>(item, "Drag.proposedAction = Qt.MoveAction");
922 QCOMPARE(evaluate<bool>(item, "Drag.proposedAction == Qt.MoveAction"), true);
923 QCOMPARE(evaluate<bool>(item, "proposedAction == Qt.MoveAction"), true);
924 QCoreApplication::processEvents();
925 QCOMPARE(dropTarget.defaultAction, Qt::MoveAction);
926 QCOMPARE(dropTarget.proposedAction, Qt::MoveAction);
928 evaluate<void>(item, "Drag.proposedAction = Qt.LinkAction");
929 QCOMPARE(evaluate<bool>(item, "Drag.proposedAction == Qt.LinkAction"), true);
930 QCOMPARE(evaluate<bool>(item, "proposedAction == Qt.LinkAction"), true);
931 evaluate<void>(item, "Drag.drop()");
932 QCOMPARE(dropTarget.defaultAction, Qt::LinkAction);
933 QCOMPARE(dropTarget.proposedAction, Qt::LinkAction);
936 void tst_QQuickDrag::keys()
938 QQmlComponent component(&engine);
940 "import QtQuick 2.0\n"
942 "property variant keys: Drag.keys\n"
944 "width: 10; height: 10\n"
946 QScopedPointer<QObject> object(component.create());
947 QQuickItem *item = qobject_cast<QQuickItem *>(object.data());
950 QCOMPARE(evaluate<QStringList>(item, "Drag.keys"), QStringList());
951 QCOMPARE(evaluate<QStringList>(item, "keys"), QStringList());
952 QCOMPARE(item->property("keys").toStringList(), QStringList());
954 evaluate<void>(item, "Drag.keys = [\"red\", \"blue\"]");
955 QCOMPARE(evaluate<QStringList>(item, "Drag.keys"), QStringList() << "red" << "blue");
956 QCOMPARE(evaluate<QStringList>(item, "keys"), QStringList() << "red" << "blue");
957 QCOMPARE(item->property("keys").toStringList(), QStringList() << "red" << "blue");
959 // Test changing the keys restarts a drag.
961 item->setParentItem(window.rootItem());
962 TestDropTarget dropTarget(window.rootItem());
963 dropTarget.setSize(QSizeF(100, 100));
965 evaluate<void>(item, "Drag.start()");
966 QCOMPARE(dropTarget.leaveEvents, 0);
967 QCOMPARE(dropTarget.enterEvents, 1);
969 evaluate<void>(item, "Drag.keys = [\"green\"]");
970 QCOMPARE(dropTarget.leaveEvents, 0);
971 QCOMPARE(dropTarget.enterEvents, 1);
972 QCoreApplication::processEvents();
973 QCOMPARE(dropTarget.leaveEvents, 1);
974 QCOMPARE(dropTarget.enterEvents, 2);
977 void tst_QQuickDrag::source()
980 QQmlComponent component(&engine);
982 "import QtQuick 2.0\n"
984 "property Item source: Drag.source\n"
986 "width: 10; height: 10\n"
987 "Item { id: proxySource; objectName: \"proxySource\" }\n"
989 QScopedPointer<QObject> object(component.create());
990 QQuickItem *item = qobject_cast<QQuickItem *>(object.data());
993 QCOMPARE(evaluate<QObject *>(item, "Drag.source"), static_cast<QObject *>(item));
994 QCOMPARE(evaluate<QObject *>(item, "source"), static_cast<QObject *>(item));
996 QQuickItem *proxySource = item->findChild<QQuickItem *>("proxySource");
997 QVERIFY(proxySource);
999 evaluate<void>(item, "Drag.source = proxySource");
1000 QCOMPARE(evaluate<QObject *>(item, "Drag.source"), static_cast<QObject *>(proxySource));
1001 QCOMPARE(evaluate<QObject *>(item, "source"), static_cast<QObject *>(proxySource));
1003 evaluate<void>(item, "Drag.source = undefined");
1004 QCOMPARE(evaluate<QObject *>(item, "Drag.source"), static_cast<QObject *>(item));
1005 QCOMPARE(evaluate<QObject *>(item, "source"), static_cast<QObject *>(item));
1007 // Test changing the source restarts a drag.
1008 QQuickWindow window;
1009 item->setParentItem(window.rootItem());
1010 TestDropTarget dropTarget(window.rootItem());
1011 dropTarget.setSize(QSizeF(100, 100));
1013 evaluate<void>(item, "Drag.start()");
1014 QCOMPARE(dropTarget.leaveEvents, 0);
1015 QCOMPARE(dropTarget.enterEvents, 1);
1017 evaluate<void>(item, "Drag.source = proxySource");
1018 QCOMPARE(dropTarget.leaveEvents, 0);
1019 QCOMPARE(dropTarget.enterEvents, 1);
1020 QCoreApplication::processEvents();
1021 QCOMPARE(dropTarget.leaveEvents, 1);
1022 QCOMPARE(dropTarget.enterEvents, 2);
1025 class RecursingDropTarget : public TestDropTarget
1028 RecursingDropTarget(const QString &script, int type, QQuickItem *parent)
1029 : TestDropTarget(parent), script(script), type(type), item(0) {}
1031 void setItem(QQuickItem *i) { item = i; }
1034 void dragEnterEvent(QDragEnterEvent *event)
1036 TestDropTarget::dragEnterEvent(event);
1037 if (type == QEvent::DragEnter && enterEvents < 2)
1038 evaluate<void>(item, script);
1041 void dragMoveEvent(QDragMoveEvent *event)
1043 TestDropTarget::dragMoveEvent(event);
1044 if (type == QEvent::DragMove && moveEvents < 2)
1045 evaluate<void>(item, script);
1048 void dragLeaveEvent(QDragLeaveEvent *event)
1050 TestDropTarget::dragLeaveEvent(event);
1051 if (type == QEvent::DragLeave && leaveEvents < 2)
1052 evaluate<void>(item, script);
1055 void dropEvent(QDropEvent *event)
1057 TestDropTarget::dropEvent(event);
1058 if (type == QEvent::Drop && dropEvents < 2)
1059 evaluate<void>(item, script);
1069 void tst_QQuickDrag::recursion_data()
1071 QTest::addColumn<QString>("script");
1072 QTest::addColumn<int>("type");
1073 QTest::addColumn<QByteArray>("warning");
1075 QTest::newRow("Drag.start() in Enter")
1076 << QString("Drag.start()")
1077 << int(QEvent::DragEnter)
1078 << QByteArray("<Unknown File>: QML QQuickDragAttached: start() cannot be called from within a drag event handler");
1079 QTest::newRow("Drag.cancel() in Enter")
1080 << QString("Drag.cancel()")
1081 << int(QEvent::DragEnter)
1082 << QByteArray("<Unknown File>: QML QQuickDragAttached: cancel() cannot be called from within a drag event handler");
1083 QTest::newRow("Drag.drop() in Enter")
1084 << QString("Drag.drop()")
1085 << int(QEvent::DragEnter)
1086 << QByteArray("<Unknown File>: QML QQuickDragAttached: drop() cannot be called from within a drag event handler");
1087 QTest::newRow("Drag.active = true in Enter")
1088 << QString("Drag.active = true")
1089 << int(QEvent::DragEnter)
1091 QTest::newRow("Drag.active = false in Enter")
1092 << QString("Drag.active = false")
1093 << int(QEvent::DragEnter)
1094 << QByteArray("<Unknown File>: QML QQuickDragAttached: active cannot be changed from within a drag event handler");
1095 QTest::newRow("move in Enter")
1096 << QString("x = 23")
1097 << int(QEvent::DragEnter)
1100 QTest::newRow("Drag.start() in Move")
1101 << QString("Drag.start()")
1102 << int(QEvent::DragMove)
1103 << QByteArray("<Unknown File>: QML QQuickDragAttached: start() cannot be called from within a drag event handler");
1104 QTest::newRow("Drag.cancel() in Move")
1105 << QString("Drag.cancel()")
1106 << int(QEvent::DragMove)
1107 << QByteArray("<Unknown File>: QML QQuickDragAttached: cancel() cannot be called from within a drag event handler");
1108 QTest::newRow("Drag.drop() in Move")
1109 << QString("Drag.drop()")
1110 << int(QEvent::DragMove)
1111 << QByteArray("<Unknown File>: QML QQuickDragAttached: drop() cannot be called from within a drag event handler");
1112 QTest::newRow("Drag.active = true in Move")
1113 << QString("Drag.active = true")
1114 << int(QEvent::DragMove)
1116 QTest::newRow("Drag.active = false in Move")
1117 << QString("Drag.active = false")
1118 << int(QEvent::DragMove)
1119 << QByteArray("<Unknown File>: QML QQuickDragAttached: active cannot be changed from within a drag event handler");
1120 QTest::newRow("move in Move")
1121 << QString("x = 23")
1122 << int(QEvent::DragMove)
1125 QTest::newRow("Drag.start() in Leave")
1126 << QString("Drag.start()")
1127 << int(QEvent::DragLeave)
1128 << QByteArray("<Unknown File>: QML QQuickDragAttached: start() cannot be called from within a drag event handler");
1129 QTest::newRow("Drag.cancel() in Leave")
1130 << QString("Drag.cancel()")
1131 << int(QEvent::DragLeave)
1132 << QByteArray("<Unknown File>: QML QQuickDragAttached: cancel() cannot be called from within a drag event handler");
1133 QTest::newRow("Drag.drop() in Leave")
1134 << QString("Drag.drop()")
1135 << int(QEvent::DragLeave)
1136 << QByteArray("<Unknown File>: QML QQuickDragAttached: drop() cannot be called from within a drag event handler");
1137 QTest::newRow("Drag.active = true in Leave")
1138 << QString("Drag.active = true")
1139 << int(QEvent::DragLeave)
1140 << QByteArray("<Unknown File>: QML QQuickDragAttached: active cannot be changed from within a drag event handler");
1141 QTest::newRow("Drag.active = false in Leave")
1142 << QString("Drag.active = false")
1143 << int(QEvent::DragLeave)
1145 QTest::newRow("move in Leave")
1146 << QString("x = 23")
1147 << int(QEvent::DragLeave)
1150 QTest::newRow("Drag.start() in Drop")
1151 << QString("Drag.start()")
1152 << int(QEvent::Drop)
1153 << QByteArray("<Unknown File>: QML QQuickDragAttached: start() cannot be called from within a drag event handler");
1154 QTest::newRow("Drag.cancel() in Drop")
1155 << QString("Drag.cancel()")
1156 << int(QEvent::Drop)
1157 << QByteArray("<Unknown File>: QML QQuickDragAttached: cancel() cannot be called from within a drag event handler");
1158 QTest::newRow("Drag.drop() in Drop")
1159 << QString("Drag.drop()")
1160 << int(QEvent::Drop)
1161 << QByteArray("<Unknown File>: QML QQuickDragAttached: drop() cannot be called from within a drag event handler");
1162 QTest::newRow("Drag.active = true in Drop")
1163 << QString("Drag.active = true")
1164 << int(QEvent::Drop)
1165 << QByteArray("<Unknown File>: QML QQuickDragAttached: active cannot be changed from within a drag event handler");
1166 QTest::newRow("Drag.active = false in Drop")
1167 << QString("Drag.active = false")
1168 << int(QEvent::Drop)
1170 QTest::newRow("move in Drop")
1171 << QString("x = 23")
1172 << int(QEvent::Drop)
1176 void tst_QQuickDrag::recursion()
1178 QFETCH(QString, script);
1180 QFETCH(QByteArray, warning);
1182 if (!warning.isEmpty())
1183 QTest::ignoreMessage(QtWarningMsg, warning.constData());
1185 QQuickWindow window;
1186 RecursingDropTarget dropTarget(script, type, window.rootItem());
1187 dropTarget.setSize(QSizeF(100, 100));
1188 QQmlComponent component(&engine);
1190 "import QtQuick 2.0\n"
1193 "width: 10; height: 10\n"
1195 QScopedPointer<QObject> object(component.create());
1196 QQuickItem *item = qobject_cast<QQuickItem *>(object.data());
1198 item->setParentItem(window.rootItem());
1200 dropTarget.setItem(item);
1202 evaluate<void>(item, "Drag.start()");
1203 QCOMPARE(dropTarget.enterEvents, 1);
1204 QCOMPARE(dropTarget.moveEvents, 0);
1205 QCOMPARE(dropTarget.dropEvents, 0);
1206 QCOMPARE(dropTarget.leaveEvents, 0);
1208 evaluate<void>(item, "y = 15");
1209 QCoreApplication::processEvents();
1210 QCOMPARE(dropTarget.enterEvents, 1);
1211 QCOMPARE(dropTarget.moveEvents, 1);
1212 QCOMPARE(dropTarget.dropEvents, 0);
1213 QCOMPARE(dropTarget.leaveEvents, 0);
1215 if (type == QEvent::Drop) {
1216 QCOMPARE(evaluate<bool>(item, "Drag.drop() == Qt.MoveAction"), true);
1217 QCOMPARE(dropTarget.enterEvents, 1);
1218 QCOMPARE(dropTarget.moveEvents, 1);
1219 QCOMPARE(dropTarget.dropEvents, 1);
1220 QCOMPARE(dropTarget.leaveEvents, 0);
1222 evaluate<void>(item, "Drag.cancel()");
1223 QCOMPARE(dropTarget.enterEvents, 1);
1224 QCOMPARE(dropTarget.moveEvents, 1);
1225 QCOMPARE(dropTarget.dropEvents, 0);
1226 QCOMPARE(dropTarget.leaveEvents, 1);
1231 QTEST_MAIN(tst_QQuickDrag)
1233 #include "tst_qquickdrag.moc"