Remove "All rights reserved" line from license headers.
[profile/ivi/qtdeclarative.git] / tests / auto / qtquick2 / qquickdrag / tst_qquickdrag.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QtTest/QtTest>
43 #include <QtTest/QSignalSpy>
44 #include <QtQuick/qquickitem.h>
45 #include <QtQuick/qquickview.h>
46 #include <QtDeclarative/qdeclarativecontext.h>
47 #include <QtDeclarative/qdeclarativeengine.h>
48 #include <QtDeclarative/qdeclarativeexpression.h>
49
50 template <typename T> static T evaluate(QObject *scope, const QString &expression)
51 {
52     QDeclarativeExpression expr(qmlContext(scope), scope, expression);
53     QVariant result = expr.evaluate();
54     if (expr.hasError())
55         qWarning() << expr.error().toString();
56     return result.value<T>();
57 }
58
59 template <> void evaluate<void>(QObject *scope, const QString &expression)
60 {
61     QDeclarativeExpression expr(qmlContext(scope), scope, expression);
62     expr.evaluate();
63     if (expr.hasError())
64         qWarning() << expr.error().toString();
65 }
66
67 Q_DECLARE_METATYPE(Qt::DropActions)
68
69 class TestDropTarget : public QQuickItem
70 {
71     Q_OBJECT
72 public:
73     TestDropTarget(QQuickItem *parent = 0)
74         : QQuickItem(parent)
75         , enterEvents(0)
76         , moveEvents(0)
77         , leaveEvents(0)
78         , dropEvents(0)
79         , acceptAction(Qt::MoveAction)
80         , defaultAction(Qt::IgnoreAction)
81         , proposedAction(Qt::IgnoreAction)
82         , accept(true)
83     {
84         setFlags(ItemAcceptsDrops);
85     }
86
87     void reset()
88     {
89         enterEvents = 0;
90         moveEvents = 0;
91         leaveEvents = 0;
92         dropEvents = 0;
93         defaultAction = Qt::IgnoreAction;
94         proposedAction = Qt::IgnoreAction;
95         supportedActions = Qt::IgnoreAction;
96     }
97
98     void dragEnterEvent(QDragEnterEvent *event)
99     {
100         ++enterEvents;
101         position = event->pos();
102         defaultAction = event->dropAction();
103         proposedAction = event->proposedAction();
104         supportedActions = event->possibleActions();
105         event->setAccepted(accept);
106     }
107
108     void dragMoveEvent(QDragMoveEvent *event)
109     {
110         ++moveEvents;
111         position = event->pos();
112         defaultAction = event->dropAction();
113         proposedAction = event->proposedAction();
114         supportedActions = event->possibleActions();
115         event->setAccepted(accept);
116     }
117
118     void dragLeaveEvent(QDragLeaveEvent *event)
119     {
120         ++leaveEvents;
121         event->setAccepted(accept);
122     }
123
124     void dropEvent(QDropEvent *event)
125     {
126         ++dropEvents;
127         position = event->pos();
128         defaultAction = event->dropAction();
129         proposedAction = event->proposedAction();
130         supportedActions = event->possibleActions();
131         event->setDropAction(acceptAction);
132         event->setAccepted(accept);
133     }
134
135     int enterEvents;
136     int moveEvents;
137     int leaveEvents;
138     int dropEvents;
139     Qt::DropAction acceptAction;
140     Qt::DropAction defaultAction;
141     Qt::DropAction proposedAction;
142     Qt::DropActions supportedActions;
143     QPointF position;
144     bool accept;
145 };
146
147 class tst_QQuickDrag: public QObject
148 {
149     Q_OBJECT
150 private slots:
151     void initTestCase();
152     void cleanupTestCase();
153
154     void active();
155     void drop();
156     void move();
157     void hotSpot();
158     void supportedActions();
159     void proposedAction();
160     void keys();
161     void source();
162
163 private:
164     QDeclarativeEngine engine;
165 };
166
167 void tst_QQuickDrag::initTestCase()
168 {
169
170 }
171
172 void tst_QQuickDrag::cleanupTestCase()
173 {
174
175 }
176
177 void tst_QQuickDrag::active()
178 {
179     QQuickCanvas canvas;
180     TestDropTarget dropTarget(canvas.rootItem());
181     dropTarget.setSize(QSizeF(100, 100));
182     QDeclarativeComponent component(&engine);
183     component.setData(
184             "import QtQuick 2.0\n"
185             "Item {\n"
186                 "property bool dragActive: Drag.active\n"
187                 "property Item dragTarget: Drag.target\n"
188                 "x: 50; y: 50\n"
189                 "width: 10; height: 10\n"
190             "}", QUrl());
191     QScopedPointer<QObject> object(component.create());
192     QQuickItem *item = qobject_cast<QQuickItem *>(object.data());
193     QVERIFY(item);
194     item->setParentItem(&dropTarget);
195
196     QCOMPARE(evaluate<bool>(item, "Drag.active"), false);
197     QCOMPARE(evaluate<bool>(item, "dragActive"), false);
198
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);
205
206     dropTarget.reset();
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);
213
214     dropTarget.reset();
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);
221
222     dropTarget.reset();
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);
229
230     // Start while a drag is active, cancels the previous drag and starts a new one.
231     dropTarget.reset();
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);
238
239     dropTarget.reset();
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);
246
247     // Enter events aren't sent to items without the QQuickItem::ItemAcceptsDrops flag.
248     dropTarget.setFlags(QQuickItem::Flags());
249
250     dropTarget.reset();
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);
257
258     dropTarget.reset();
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);
265
266     dropTarget.setFlags(QQuickItem::ItemAcceptsDrops);
267
268     dropTarget.reset();
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);
275
276     dropTarget.setFlags(QQuickItem::Flags());
277
278     dropTarget.reset();
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);
285
286     // Follow up events aren't sent to items if the enter event isn't accepted.
287     dropTarget.setFlags(QQuickItem::ItemAcceptsDrops);
288     dropTarget.accept = false;
289
290     dropTarget.reset();
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);
297
298     dropTarget.reset();
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);
305
306     dropTarget.accept = true;
307
308     dropTarget.reset();
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);
315
316     dropTarget.accept = false;
317
318     dropTarget.reset();
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);
325
326     // Events are sent to hidden or disabled items.
327     dropTarget.accept = true;
328     dropTarget.setVisible(false);
329     dropTarget.reset();
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);
336
337     evaluate<void>(item, "Drag.active = false");
338     dropTarget.setVisible(true);
339
340     dropTarget.setOpacity(0.0);
341     dropTarget.reset();
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);
348
349     evaluate<void>(item, "Drag.active = false");
350     dropTarget.setOpacity(1.0);
351
352     dropTarget.setEnabled(false);
353     dropTarget.reset();
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);
360 }
361
362 void tst_QQuickDrag::drop()
363 {
364     QQuickCanvas canvas;
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);
372     component.setData(
373             "import QtQuick 2.0\n"
374             "Item {\n"
375                 "property bool dragActive: Drag.active\n"
376                 "property Item dragTarget: Drag.target\n"
377                 "x: 50; y: 50\n"
378                 "width: 10; height: 10\n"
379             "}", QUrl());
380     QScopedPointer<QObject> object(component.create());
381     QQuickItem *item = qobject_cast<QQuickItem *>(object.data());
382     QVERIFY(item);
383     item->setParentItem(&outerTarget);
384
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);
393
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);
402
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);
411
412     // Inner target declines the drop so it is propagated to the outer target.
413     innerTarget.accept = false;
414
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);
423
424
425     // Inner target doesn't accept enter so drop goes directly to outer.
426     innerTarget.accept = true;
427     innerTarget.setFlags(QQuickItem::Flags());
428
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);
437
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);
446
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);
456
457     outerTarget.accept = false;
458
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);
467
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);
479 }
480
481 void tst_QQuickDrag::move()
482 {
483     QQuickCanvas canvas;
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);
493     component.setData(
494             "import QtQuick 2.0\n"
495             "Item {\n"
496                 "property bool dragActive: Drag.active\n"
497                 "property Item dragTarget: Drag.target\n"
498                 "x: 50; y: 50\n"
499                 "width: 10; height: 10\n"
500             "}", QUrl());
501     QScopedPointer<QObject> object(component.create());
502     QQuickItem *item = qobject_cast<QQuickItem *>(object.data());
503     QVERIFY(item);
504     item->setParentItem(&outerTarget);
505
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));
515
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));
525
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));
536
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));
547
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));
558
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);
567
568     // Stop the right target accepting drag events and move into it.
569     rightTarget.accept = false;
570
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));
579
580     // Stop the outer target accepting drag events after it has accepted an enter event.
581     outerTarget.accept = false;
582
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));
591
592     // Clear the QQuickItem::ItemAcceptsDrops flag from the outer target after it accepted an enter event.
593     outerTarget.setFlags(QQuickItem::Flags());
594
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));
603
604     // Clear the QQuickItem::ItemAcceptsDrops flag from the left target before it accepts an enter event.
605     leftTarget.setFlags(QQuickItem::Flags());
606
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));
615 }
616
617
618 void tst_QQuickDrag::hotSpot()
619 {
620     QQuickCanvas canvas;
621     TestDropTarget dropTarget(canvas.rootItem());
622     dropTarget.setSize(QSizeF(100, 100));
623     QDeclarativeComponent component(&engine);
624     component.setData(
625             "import QtQuick 2.0\n"
626             "Item {\n"
627                 "property real hotSpotX: Drag.hotSpot.x\n"
628                 "property real hotSpotY: Drag.hotSpot.y\n"
629                 "x: 50; y: 50\n"
630                 "width: 10; height: 10\n"
631             "}", QUrl());
632     QScopedPointer<QObject> object(component.create());
633     QQuickItem *item = qobject_cast<QQuickItem *>(object.data());
634     QVERIFY(item);
635     item->setParentItem(&dropTarget);
636
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));
641
642     evaluate<void>(item, "{ Drag.start(); Drag.cancel() }");
643     QCOMPARE(dropTarget.position.x(), qreal(50));
644     QCOMPARE(dropTarget.position.y(), qreal(50));
645
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));
651
652     evaluate<void>(item, "Drag.start()");
653     QCOMPARE(dropTarget.position.x(), qreal(55));
654     QCOMPARE(dropTarget.position.y(), qreal(55));
655
656     item->setPos(QPointF(30, 20));
657     QCOMPARE(dropTarget.position.x(), qreal(35));
658     QCOMPARE(dropTarget.position.y(), qreal(25));
659
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));
668
669     item->setPos(QPointF(10, 20));
670     QCOMPARE(dropTarget.position.x(), qreal(20));
671     QCOMPARE(dropTarget.position.y(), qreal(30));
672 }
673
674 void tst_QQuickDrag::supportedActions()
675 {
676     QQuickCanvas canvas;
677     TestDropTarget dropTarget(canvas.rootItem());
678     dropTarget.setSize(QSizeF(100, 100));
679     QDeclarativeComponent component(&engine);
680     component.setData(
681             "import QtQuick 2.0\n"
682             "Item {\n"
683                 "property int supportedActions: Drag.supportedActions\n"
684                 "x: 50; y: 50\n"
685                 "width: 10; height: 10\n"
686             "}", QUrl());
687     QScopedPointer<QObject> object(component.create());
688     QQuickItem *item = qobject_cast<QQuickItem *>(object.data());
689     QVERIFY(item);
690     item->setParentItem(&dropTarget);
691
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);
696
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);
702
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);
709
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);
715
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);
720 }
721
722 void tst_QQuickDrag::proposedAction()
723 {
724     QQuickCanvas canvas;
725     TestDropTarget dropTarget(canvas.rootItem());
726     dropTarget.setSize(QSizeF(100, 100));
727     QDeclarativeComponent component(&engine);
728     component.setData(
729             "import QtQuick 2.0\n"
730             "Item {\n"
731                 "property int proposedAction: Drag.proposedAction\n"
732                 "x: 50; y: 50\n"
733                 "width: 10; height: 10\n"
734             "}", QUrl());
735     QScopedPointer<QObject> object(component.create());
736     QQuickItem *item = qobject_cast<QQuickItem *>(object.data());
737     QVERIFY(item);
738     item->setParentItem(&dropTarget);
739
740
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);
746
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);
753
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);
761
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);
768 }
769
770 void tst_QQuickDrag::keys()
771 {
772     QDeclarativeComponent component(&engine);
773     component.setData(
774             "import QtQuick 2.0\n"
775             "Item {\n"
776                 "property variant keys: Drag.keys\n"
777                 "x: 50; y: 50\n"
778                 "width: 10; height: 10\n"
779             "}", QUrl());
780     QScopedPointer<QObject> object(component.create());
781     QQuickItem *item = qobject_cast<QQuickItem *>(object.data());
782     QVERIFY(item);
783
784 //    QCOMPARE(evaluate<QStringList>(item, "Drag.keys"), QStringList());
785 //    QCOMPARE(evaluate<QStringList>(item, "keys"), QStringList());
786     QCOMPARE(item->property("keys").toStringList(), QStringList());
787
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");
792 }
793
794 void tst_QQuickDrag::source()
795 {
796
797     QDeclarativeComponent component(&engine);
798     component.setData(
799             "import QtQuick 2.0\n"
800             "Item {\n"
801                 "property Item source: Drag.source\n"
802                 "x: 50; y: 50\n"
803                 "width: 10; height: 10\n"
804                 "Item { id: proxySource; objectName: \"proxySource\" }\n"
805             "}", QUrl());
806     QScopedPointer<QObject> object(component.create());
807     QQuickItem *item = qobject_cast<QQuickItem *>(object.data());
808     QVERIFY(item);
809
810     QCOMPARE(evaluate<QObject *>(item, "Drag.source"), static_cast<QObject *>(item));
811     QCOMPARE(evaluate<QObject *>(item, "source"), static_cast<QObject *>(item));
812
813     QQuickItem *proxySource = item->findChild<QQuickItem *>("proxySource");
814     QVERIFY(proxySource);
815
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));
819
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));
823 }
824
825 QTEST_MAIN(tst_QQuickDrag)
826
827 #include "tst_qquickdrag.moc"