1 /****************************************************************************
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the test suite of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include <QtTest/QtTest>
43 #include <QtTest/QSignalSpy>
44 #include <QtDeclarative/qsgitem.h>
45 #include <QtDeclarative/qsgview.h>
46 #include <QtDeclarative/qdeclarativecontext.h>
47 #include <QtDeclarative/qdeclarativeengine.h>
48 #include <QtDeclarative/qdeclarativeexpression.h>
50 template <typename T> static T evaluate(QObject *scope, const QString &expression)
52 QDeclarativeExpression 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 QDeclarativeExpression expr(qmlContext(scope), scope, expression);
64 qWarning() << expr.error().toString();
67 Q_DECLARE_METATYPE(Qt::DropActions)
69 class TestDropTarget : public QSGItem
73 TestDropTarget(QSGItem *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_QSGDrag: public QObject
152 void cleanupTestCase();
158 void supportedActions();
159 void proposedAction();
164 QDeclarativeEngine engine;
167 void tst_QSGDrag::initTestCase()
172 void tst_QSGDrag::cleanupTestCase()
177 void tst_QSGDrag::active()
180 TestDropTarget dropTarget(canvas.rootItem());
181 dropTarget.setSize(QSizeF(100, 100));
182 QDeclarativeComponent component(&engine);
184 "import QtQuick 2.0\n"
186 "property bool dragActive: Drag.active\n"
187 "property Item dragTarget: Drag.target\n"
189 "width: 10; height: 10\n"
191 QScopedPointer<QObject> object(component.create());
192 QSGItem *item = qobject_cast<QSGItem *>(object.data());
194 item->setParentItem(&dropTarget);
196 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
197 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
199 evaluate<void>(item, "Drag.active = true");
200 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
201 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
202 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&dropTarget));
203 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&dropTarget));
204 QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0);
207 evaluate<void>(item, "Drag.active = false");
208 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
209 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
210 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
211 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
212 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 1);
215 evaluate<void>(item, "Drag.cancel()");
216 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
217 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
218 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
219 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
220 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0);
223 evaluate<void>(item, "Drag.start()");
224 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
225 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
226 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&dropTarget));
227 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&dropTarget));
228 QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0);
230 // Start while a drag is active, cancels the previous drag and starts a new one.
232 evaluate<void>(item, "Drag.start()");
233 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
234 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
235 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&dropTarget));
236 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&dropTarget));
237 QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 1);
240 evaluate<void>(item, "Drag.cancel()");
241 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
242 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
243 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
244 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
245 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 1);
247 // Enter events aren't sent to items without the QSGItem::ItemAcceptsDrops flag.
248 dropTarget.setFlags(QSGItem::Flags());
251 evaluate<void>(item, "Drag.active = true");
252 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
253 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
254 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
255 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
256 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0);
259 evaluate<void>(item, "Drag.active = false");
260 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
261 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
262 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
263 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
264 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0);
266 dropTarget.setFlags(QSGItem::ItemAcceptsDrops);
269 evaluate<void>(item, "Drag.active = true");
270 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
271 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
272 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&dropTarget));
273 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&dropTarget));
274 QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0);
276 dropTarget.setFlags(QSGItem::Flags());
279 evaluate<void>(item, "Drag.active = false");
280 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
281 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
282 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
283 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
284 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 1);
286 // Follow up events aren't sent to items if the enter event isn't accepted.
287 dropTarget.setFlags(QSGItem::ItemAcceptsDrops);
288 dropTarget.accept = false;
291 evaluate<void>(item, "Drag.active = true");
292 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
293 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
294 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
295 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
296 QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0);
299 evaluate<void>(item, "Drag.active = false");
300 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
301 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
302 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
303 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
304 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0);
306 dropTarget.accept = true;
309 evaluate<void>(item, "Drag.active = true");
310 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
311 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
312 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&dropTarget));
313 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&dropTarget));
314 QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0);
316 dropTarget.accept = false;
319 evaluate<void>(item, "Drag.active = false");
320 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
321 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
322 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
323 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
324 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 1);
326 // Events are sent to hidden or disabled items.
327 dropTarget.accept = true;
328 dropTarget.setVisible(false);
330 evaluate<void>(item, "Drag.active = true");
331 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
332 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
333 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
334 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
335 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0);
337 evaluate<void>(item, "Drag.active = false");
338 dropTarget.setVisible(true);
340 dropTarget.setOpacity(0.0);
342 evaluate<void>(item, "Drag.active = true");
343 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
344 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
345 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
346 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
347 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0);
349 evaluate<void>(item, "Drag.active = false");
350 dropTarget.setOpacity(1.0);
352 dropTarget.setEnabled(false);
354 evaluate<void>(item, "Drag.active = true");
355 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
356 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
357 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
358 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
359 QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0);
362 void tst_QSGDrag::drop()
365 TestDropTarget outerTarget(canvas.rootItem());
366 outerTarget.setSize(QSizeF(100, 100));
367 outerTarget.acceptAction = Qt::CopyAction;
368 TestDropTarget innerTarget(&outerTarget);
369 innerTarget.setSize(QSizeF(100, 100));
370 innerTarget.acceptAction = Qt::MoveAction;
371 QDeclarativeComponent component(&engine);
373 "import QtQuick 2.0\n"
375 "property bool dragActive: Drag.active\n"
376 "property Item dragTarget: Drag.target\n"
378 "width: 10; height: 10\n"
380 QScopedPointer<QObject> object(component.create());
381 QSGItem *item = qobject_cast<QSGItem *>(object.data());
383 item->setParentItem(&outerTarget);
385 innerTarget.reset(); outerTarget.reset();
386 evaluate<void>(item, "Drag.active = true");
387 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
388 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
389 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&innerTarget));
390 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&innerTarget));
391 QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0);
392 QCOMPARE(innerTarget.enterEvents, 1); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0);
394 innerTarget.reset(); outerTarget.reset();
395 QCOMPARE(evaluate<bool>(item, "Drag.drop() == Qt.MoveAction"), true);
396 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
397 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
398 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&innerTarget));
399 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&innerTarget));
400 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 1); QCOMPARE(outerTarget.dropEvents, 0);
401 QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 1);
403 innerTarget.reset(); outerTarget.reset();
404 evaluate<void>(item, "Drag.active = true");
405 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
406 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
407 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&innerTarget));
408 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&innerTarget));
409 QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0);
410 QCOMPARE(innerTarget.enterEvents, 1); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0);
412 // Inner target declines the drop so it is propagated to the outer target.
413 innerTarget.accept = false;
415 innerTarget.reset(); outerTarget.reset();
416 QCOMPARE(evaluate<bool>(item, "Drag.drop() == Qt.CopyAction"), true);
417 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
418 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
419 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget));
420 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget));
421 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 1);
422 QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 1);
425 // Inner target doesn't accept enter so drop goes directly to outer.
426 innerTarget.accept = true;
427 innerTarget.setFlags(QSGItem::Flags());
429 innerTarget.reset(); outerTarget.reset();
430 evaluate<void>(item, "Drag.active = true");
431 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
432 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
433 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget));
434 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget));
435 QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0);
436 QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0);
438 innerTarget.reset(); outerTarget.reset();
439 QCOMPARE(evaluate<bool>(item, "Drag.drop() == Qt.CopyAction"), true);
440 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
441 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
442 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget));
443 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget));
444 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 1);
445 QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0);
447 // Neither target accepts drop so Qt::IgnoreAction is returned.
448 innerTarget.reset(); outerTarget.reset();
449 evaluate<void>(item, "Drag.active = true");
450 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
451 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
452 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget));
453 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget));
454 QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0);
455 QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0);
457 outerTarget.accept = false;
459 innerTarget.reset(); outerTarget.reset();
460 QCOMPARE(evaluate<bool>(item, "Drag.drop() == Qt.IgnoreAction"), true);
461 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
462 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
463 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
464 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
465 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 1);
466 QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0);
468 // drop doesn't send an event and returns Qt.IgnoreAction if not active.
469 innerTarget.accept = true;
470 outerTarget.accept = true;
471 innerTarget.reset(); outerTarget.reset();
472 QCOMPARE(evaluate<bool>(item, "Drag.drop() == Qt.IgnoreAction"), true);
473 QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
474 QCOMPARE(evaluate<bool>(item, "dragActive"), false);
475 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
476 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
477 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0);
478 QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0);
481 void tst_QSGDrag::move()
484 TestDropTarget outerTarget(canvas.rootItem());
485 outerTarget.setSize(QSizeF(100, 100));
486 TestDropTarget leftTarget(&outerTarget);
487 leftTarget.setPos(QPointF(0, 35));
488 leftTarget.setSize(QSizeF(30, 30));
489 TestDropTarget rightTarget(&outerTarget);
490 rightTarget.setPos(QPointF(70, 35));
491 rightTarget.setSize(QSizeF(30, 30));
492 QDeclarativeComponent component(&engine);
494 "import QtQuick 2.0\n"
496 "property bool dragActive: Drag.active\n"
497 "property Item dragTarget: Drag.target\n"
499 "width: 10; height: 10\n"
501 QScopedPointer<QObject> object(component.create());
502 QSGItem *item = qobject_cast<QSGItem *>(object.data());
504 item->setParentItem(&outerTarget);
506 evaluate<void>(item, "Drag.active = true");
507 QCOMPARE(evaluate<bool>(item, "Drag.active"), true);
508 QCOMPARE(evaluate<bool>(item, "dragActive"), true);
509 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget));
510 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget));
511 QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 0);
512 QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0);
513 QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0);
514 QCOMPARE(outerTarget.position.x(), qreal(50)); QCOMPARE(outerTarget.position.y(), qreal(50));
516 // Move within the outer target.
517 outerTarget.reset(); leftTarget.reset(); rightTarget.reset();
518 item->setPos(QPointF(60, 50));
519 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget));
520 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget));
521 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 1);
522 QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0);
523 QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0);
524 QCOMPARE(outerTarget.position.x(), qreal(60)); QCOMPARE(outerTarget.position.y(), qreal(50));
526 // Move into the right target.
527 outerTarget.reset(); leftTarget.reset(); rightTarget.reset();
528 item->setPos(QPointF(75, 50));
529 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&rightTarget));
530 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&rightTarget));
531 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 1);
532 QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0);
533 QCOMPARE(rightTarget.enterEvents, 1); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0);
534 QCOMPARE(outerTarget.position.x(), qreal(75)); QCOMPARE(outerTarget.position.y(), qreal(50));
535 QCOMPARE(rightTarget.position.x(), qreal(5)); QCOMPARE(rightTarget.position.y(), qreal(15));
537 // Move into the left target.
538 outerTarget.reset(); leftTarget.reset(); rightTarget.reset();
539 item->setPos(QPointF(25, 50));
540 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&leftTarget));
541 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&leftTarget));
542 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 1);
543 QCOMPARE(leftTarget .enterEvents, 1); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0);
544 QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 1); QCOMPARE(rightTarget.moveEvents, 0);
545 QCOMPARE(outerTarget.position.x(), qreal(25)); QCOMPARE(outerTarget.position.y(), qreal(50));
546 QCOMPARE(leftTarget.position.x(), qreal(25)); QCOMPARE(leftTarget.position.y(), qreal(15));
548 // Move within the left target.
549 outerTarget.reset(); leftTarget.reset(); rightTarget.reset();
550 item->setPos(QPointF(25, 40));
551 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&leftTarget));
552 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&leftTarget));
553 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 1);
554 QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 1);
555 QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0);
556 QCOMPARE(outerTarget.position.x(), qreal(25)); QCOMPARE(outerTarget.position.y(), qreal(40));
557 QCOMPARE(leftTarget.position.x(), qreal(25)); QCOMPARE(leftTarget.position.y(), qreal(5));
559 // Move out of all targets.
560 outerTarget.reset(); leftTarget.reset(); rightTarget.reset();
561 item->setPos(QPointF(110, 50));
562 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(0));
563 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(0));
564 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 1); QCOMPARE(outerTarget.moveEvents, 0);
565 QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 1); QCOMPARE(leftTarget .moveEvents, 0);
566 QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0);
568 // Stop the right target accepting drag events and move into it.
569 rightTarget.accept = false;
571 outerTarget.reset(); leftTarget.reset(); rightTarget.reset();
572 item->setPos(QPointF(80, 50));
573 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget));
574 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget));
575 QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 0);
576 QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0);
577 QCOMPARE(rightTarget.enterEvents, 1); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0);
578 QCOMPARE(outerTarget.position.x(), qreal(80)); QCOMPARE(outerTarget.position.y(), qreal(50));
580 // Stop the outer target accepting drag events after it has accepted an enter event.
581 outerTarget.accept = false;
583 outerTarget.reset(); leftTarget.reset(); rightTarget.reset();
584 item->setPos(QPointF(60, 50));
585 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget));
586 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget));
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, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0);
590 QCOMPARE(outerTarget.position.x(), qreal(60)); QCOMPARE(outerTarget.position.y(), qreal(50));
592 // Clear the QSGItem::ItemAcceptsDrops flag from the outer target after it accepted an enter event.
593 outerTarget.setFlags(QSGItem::Flags());
595 outerTarget.reset(); leftTarget.reset(); rightTarget.reset();
596 item->setPos(QPointF(40, 50));
597 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget));
598 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget));
599 QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 1);
600 QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0);
601 QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0);
602 QCOMPARE(outerTarget.position.x(), qreal(40)); QCOMPARE(outerTarget.position.y(), qreal(50));
604 // Clear the QSGItem::ItemAcceptsDrops flag from the left target before it accepts an enter event.
605 leftTarget.setFlags(QSGItem::Flags());
607 outerTarget.reset(); leftTarget.reset(); rightTarget.reset();
608 item->setPos(QPointF(25, 50));
609 QCOMPARE(evaluate<QObject *>(item, "Drag.target"), static_cast<QObject *>(&outerTarget));
610 QCOMPARE(evaluate<QObject *>(item, "dragTarget"), static_cast<QObject *>(&outerTarget));
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, 0);
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(50));
618 void tst_QSGDrag::hotSpot()
621 TestDropTarget dropTarget(canvas.rootItem());
622 dropTarget.setSize(QSizeF(100, 100));
623 QDeclarativeComponent component(&engine);
625 "import QtQuick 2.0\n"
627 "property real hotSpotX: Drag.hotSpot.x\n"
628 "property real hotSpotY: Drag.hotSpot.y\n"
630 "width: 10; height: 10\n"
632 QScopedPointer<QObject> object(component.create());
633 QSGItem *item = qobject_cast<QSGItem *>(object.data());
635 item->setParentItem(&dropTarget);
637 QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.x"), qreal(0));
638 QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.y"), qreal(0));
639 QCOMPARE(evaluate<qreal>(item, "hotSpotX"), qreal(0));
640 QCOMPARE(evaluate<qreal>(item, "hotSpotY"), qreal(0));
642 evaluate<void>(item, "{ Drag.start(); Drag.cancel() }");
643 QCOMPARE(dropTarget.position.x(), qreal(50));
644 QCOMPARE(dropTarget.position.y(), qreal(50));
646 evaluate<void>(item, "{ Drag.hotSpot.x = 5, Drag.hotSpot.y = 5 }");
647 QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.x"), qreal(5));
648 QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.y"), qreal(5));
649 QCOMPARE(evaluate<qreal>(item, "hotSpotX"), qreal(5));
650 QCOMPARE(evaluate<qreal>(item, "hotSpotY"), qreal(5));
652 evaluate<void>(item, "Drag.start()");
653 QCOMPARE(dropTarget.position.x(), qreal(55));
654 QCOMPARE(dropTarget.position.y(), qreal(55));
656 item->setPos(QPointF(30, 20));
657 QCOMPARE(dropTarget.position.x(), qreal(35));
658 QCOMPARE(dropTarget.position.y(), qreal(25));
660 evaluate<void>(item, "{ Drag.hotSpot.x = 10; Drag.hotSpot.y = 10 }");
661 QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.x"), qreal(10));
662 QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.y"), qreal(10));
663 QCOMPARE(evaluate<qreal>(item, "hotSpotX"), qreal(10));
664 QCOMPARE(evaluate<qreal>(item, "hotSpotY"), qreal(10));
665 // Changing the hotSpot won't generate a move event so the position is unchanged. Should it?
666 QCOMPARE(dropTarget.position.x(), qreal(35));
667 QCOMPARE(dropTarget.position.y(), qreal(25));
669 item->setPos(QPointF(10, 20));
670 QCOMPARE(dropTarget.position.x(), qreal(20));
671 QCOMPARE(dropTarget.position.y(), qreal(30));
674 void tst_QSGDrag::supportedActions()
677 TestDropTarget dropTarget(canvas.rootItem());
678 dropTarget.setSize(QSizeF(100, 100));
679 QDeclarativeComponent component(&engine);
681 "import QtQuick 2.0\n"
683 "property int supportedActions: Drag.supportedActions\n"
685 "width: 10; height: 10\n"
687 QScopedPointer<QObject> object(component.create());
688 QSGItem *item = qobject_cast<QSGItem *>(object.data());
690 item->setParentItem(&dropTarget);
692 QCOMPARE(evaluate<bool>(item, "Drag.supportedActions == Qt.CopyAction | Qt.MoveAction | Qt.LinkAction"), true);
693 QCOMPARE(evaluate<bool>(item, "supportedActions == Qt.CopyAction | Qt.MoveAction | Qt.LinkAction"), true);
694 evaluate<void>(item, "{ Drag.start(); Drag.cancel() }");
695 QCOMPARE(dropTarget.supportedActions, Qt::CopyAction | Qt::MoveAction | Qt::LinkAction);
697 evaluate<void>(item, "Drag.supportedActions = Qt.CopyAction | Qt.MoveAction");
698 QCOMPARE(evaluate<bool>(item, "Drag.supportedActions == Qt.CopyAction | Qt.MoveAction"), true);
699 QCOMPARE(evaluate<bool>(item, "supportedActions == Qt.CopyAction | Qt.MoveAction"), true);
700 evaluate<void>(item, "Drag.start()");
701 QCOMPARE(dropTarget.supportedActions, Qt::CopyAction | Qt::MoveAction);
703 // Once a drag is started the proposed actions are locked in for future events.
704 evaluate<void>(item, "Drag.supportedActions = Qt.MoveAction");
705 QCOMPARE(evaluate<bool>(item, "Drag.supportedActions == Qt.MoveAction"), true);
706 QCOMPARE(evaluate<bool>(item, "supportedActions == Qt.MoveAction"), true);
707 item->setPos(QPointF(60, 60));
708 QCOMPARE(dropTarget.supportedActions, Qt::CopyAction | Qt::MoveAction);
710 // Calling start with proposed actions will override the current actions for the next sequence.
711 evaluate<void>(item, "Drag.start(Qt.CopyAction)");
712 QCOMPARE(evaluate<bool>(item, "Drag.supportedActions == Qt.MoveAction"), true);
713 QCOMPARE(evaluate<bool>(item, "supportedActions == Qt.MoveAction"), true);
714 QCOMPARE(dropTarget.supportedActions, Qt::CopyAction);
716 evaluate<void>(item, "Drag.start()");
717 QCOMPARE(evaluate<bool>(item, "Drag.supportedActions == Qt.MoveAction"), true);
718 QCOMPARE(evaluate<bool>(item, "supportedActions == Qt.MoveAction"), true);
719 QCOMPARE(dropTarget.supportedActions, Qt::MoveAction);
722 void tst_QSGDrag::proposedAction()
725 TestDropTarget dropTarget(canvas.rootItem());
726 dropTarget.setSize(QSizeF(100, 100));
727 QDeclarativeComponent component(&engine);
729 "import QtQuick 2.0\n"
731 "property int proposedAction: Drag.proposedAction\n"
733 "width: 10; height: 10\n"
735 QScopedPointer<QObject> object(component.create());
736 QSGItem *item = qobject_cast<QSGItem *>(object.data());
738 item->setParentItem(&dropTarget);
741 QCOMPARE(evaluate<bool>(item, "Drag.proposedAction == Qt.MoveAction"), true);
742 QCOMPARE(evaluate<bool>(item, "proposedAction == Qt.MoveAction"), true);
743 evaluate<void>(item, "{ Drag.start(); Drag.cancel() }");
744 QCOMPARE(dropTarget.defaultAction, Qt::MoveAction);
745 QCOMPARE(dropTarget.proposedAction, Qt::MoveAction);
747 evaluate<void>(item, "Drag.proposedAction = Qt.CopyAction");
748 QCOMPARE(evaluate<bool>(item, "Drag.proposedAction == Qt.CopyAction"), true);
749 QCOMPARE(evaluate<bool>(item, "proposedAction == Qt.CopyAction"), true);
750 evaluate<void>(item, "Drag.start()");
751 QCOMPARE(dropTarget.defaultAction, Qt::CopyAction);
752 QCOMPARE(dropTarget.proposedAction, Qt::CopyAction);
754 // The proposed action can change during a drag.
755 evaluate<void>(item, "Drag.proposedAction = Qt.MoveAction");
756 QCOMPARE(evaluate<bool>(item, "Drag.proposedAction == Qt.MoveAction"), true);
757 QCOMPARE(evaluate<bool>(item, "proposedAction == Qt.MoveAction"), true);
758 item->setPos(QPointF(60, 60));
759 QCOMPARE(dropTarget.defaultAction, Qt::MoveAction);
760 QCOMPARE(dropTarget.proposedAction, Qt::MoveAction);
762 evaluate<void>(item, "Drag.proposedAction = Qt.LinkAction");
763 QCOMPARE(evaluate<bool>(item, "Drag.proposedAction == Qt.LinkAction"), true);
764 QCOMPARE(evaluate<bool>(item, "proposedAction == Qt.LinkAction"), true);
765 evaluate<void>(item, "Drag.drop()");
766 QCOMPARE(dropTarget.defaultAction, Qt::LinkAction);
767 QCOMPARE(dropTarget.proposedAction, Qt::LinkAction);
770 void tst_QSGDrag::keys()
772 QDeclarativeComponent component(&engine);
774 "import QtQuick 2.0\n"
776 "property variant keys: Drag.keys\n"
778 "width: 10; height: 10\n"
780 QScopedPointer<QObject> object(component.create());
781 QSGItem *item = qobject_cast<QSGItem *>(object.data());
784 // QCOMPARE(evaluate<QStringList>(item, "Drag.keys"), QStringList());
785 // QCOMPARE(evaluate<QStringList>(item, "keys"), QStringList());
786 QCOMPARE(item->property("keys").toStringList(), QStringList());
788 evaluate<void>(item, "Drag.keys = [\"red\", \"blue\"]");
789 // QCOMPARE(evaluate<QStringList>(item, "Drag.keys"), QStringList() << "red" << "blue");
790 // QCOMPARE(evaluate<QStringList>(item, "keys"), QStringList() << "red" << "blue");
791 QCOMPARE(item->property("keys").toStringList(), QStringList() << "red" << "blue");
794 void tst_QSGDrag::source()
797 QDeclarativeComponent component(&engine);
799 "import QtQuick 2.0\n"
801 "property Item source: Drag.source\n"
803 "width: 10; height: 10\n"
804 "Item { id: proxySource; objectName: \"proxySource\" }\n"
806 QScopedPointer<QObject> object(component.create());
807 QSGItem *item = qobject_cast<QSGItem *>(object.data());
810 QCOMPARE(evaluate<QObject *>(item, "Drag.source"), static_cast<QObject *>(item));
811 QCOMPARE(evaluate<QObject *>(item, "source"), static_cast<QObject *>(item));
813 QSGItem *proxySource = item->findChild<QSGItem *>("proxySource");
814 QVERIFY(proxySource);
816 evaluate<void>(item, "Drag.source = proxySource");
817 QCOMPARE(evaluate<QObject *>(item, "Drag.source"), static_cast<QObject *>(proxySource));
818 QCOMPARE(evaluate<QObject *>(item, "source"), static_cast<QObject *>(proxySource));
820 evaluate<void>(item, "Drag.source = undefined");
821 QCOMPARE(evaluate<QObject *>(item, "Drag.source"), static_cast<QObject *>(item));
822 QCOMPARE(evaluate<QObject *>(item, "source"), static_cast<QObject *>(item));
825 QTEST_MAIN(tst_QSGDrag)
827 #include "tst_qsgdrag.moc"