| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the test suite of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU | 
| 19 | ** General Public License version 3 as published by the Free Software | 
| 20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT | 
| 21 | ** included in the packaging of this file. Please review the following | 
| 22 | ** information to ensure the GNU General Public License requirements will | 
| 23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. | 
| 24 | ** | 
| 25 | ** $QT_END_LICENSE$ | 
| 26 | ** | 
| 27 | ****************************************************************************/ | 
| 28 |  | 
| 29 | #include <QtTest/QtTest> | 
| 30 | #include <QtTest/QSignalSpy> | 
| 31 | #include <QtQuick/qquickitem.h> | 
| 32 | #include <QtQuick/qquickview.h> | 
| 33 | #include <QtQml/qqmlcontext.h> | 
| 34 | #include <QtQml/qqmlengine.h> | 
| 35 | #include <QtQml/qqmlexpression.h> | 
| 36 |  | 
| 37 | template <typename T> static T evaluate(QObject *scope, const QString &expression) | 
| 38 | { | 
| 39 |     QQmlExpression expr(qmlContext(scope), scope, expression); | 
| 40 |     QVariant result = expr.evaluate(); | 
| 41 |     if (expr.hasError()) | 
| 42 |         qWarning() << expr.error().toString(); | 
| 43 |     return result.value<T>(); | 
| 44 | } | 
| 45 |  | 
| 46 | template <> void evaluate<void>(QObject *scope, const QString &expression) | 
| 47 | { | 
| 48 |     QQmlExpression expr(qmlContext(scope), scope, expression); | 
| 49 |     expr.evaluate(); | 
| 50 |     if (expr.hasError()) | 
| 51 |         qWarning() << expr.error().toString(); | 
| 52 | } | 
| 53 |  | 
| 54 | Q_DECLARE_METATYPE(Qt::DropActions) | 
| 55 |  | 
| 56 | class TestDropTarget : public QQuickItem | 
| 57 | { | 
| 58 |     Q_OBJECT | 
| 59 | public: | 
| 60 |     TestDropTarget(QQuickItem *parent = nullptr) | 
| 61 |         : QQuickItem(parent) | 
| 62 |     { | 
| 63 |         setFlags(ItemAcceptsDrops); | 
| 64 |     } | 
| 65 |  | 
| 66 |     void reset() | 
| 67 |     { | 
| 68 |         enterEvents = 0; | 
| 69 |         moveEvents = 0; | 
| 70 |         leaveEvents = 0; | 
| 71 |         dropEvents = 0; | 
| 72 |         defaultAction = Qt::IgnoreAction; | 
| 73 |         proposedAction = Qt::IgnoreAction; | 
| 74 |         supportedActions = Qt::IgnoreAction; | 
| 75 |     } | 
| 76 |  | 
| 77 |     void dragEnterEvent(QDragEnterEvent *event) | 
| 78 |     { | 
| 79 |         ++enterEvents; | 
| 80 |         position = event->pos(); | 
| 81 |         defaultAction = event->dropAction(); | 
| 82 |         proposedAction = event->proposedAction(); | 
| 83 |         supportedActions = event->possibleActions(); | 
| 84 |         event->setAccepted(accept); | 
| 85 |     } | 
| 86 |  | 
| 87 |     void dragMoveEvent(QDragMoveEvent *event) | 
| 88 |     { | 
| 89 |         ++moveEvents; | 
| 90 |         position = event->pos(); | 
| 91 |         defaultAction = event->dropAction(); | 
| 92 |         proposedAction = event->proposedAction(); | 
| 93 |         supportedActions = event->possibleActions(); | 
| 94 |         event->setAccepted(accept); | 
| 95 |     } | 
| 96 |  | 
| 97 |     void dragLeaveEvent(QDragLeaveEvent *event) | 
| 98 |     { | 
| 99 |         ++leaveEvents; | 
| 100 |         event->setAccepted(accept); | 
| 101 |     } | 
| 102 |  | 
| 103 |     void dropEvent(QDropEvent *event) | 
| 104 |     { | 
| 105 |         ++dropEvents; | 
| 106 |         position = event->pos(); | 
| 107 |         defaultAction = event->dropAction(); | 
| 108 |         proposedAction = event->proposedAction(); | 
| 109 |         supportedActions = event->possibleActions(); | 
| 110 |         event->setDropAction(acceptAction); | 
| 111 |         event->setAccepted(accept); | 
| 112 |     } | 
| 113 |  | 
| 114 |     int enterEvents = 0; | 
| 115 |     int moveEvents = 0; | 
| 116 |     int leaveEvents = 0; | 
| 117 |     int dropEvents = 0; | 
| 118 |     Qt::DropAction acceptAction = Qt::MoveAction; | 
| 119 |     Qt::DropAction defaultAction = Qt::IgnoreAction; | 
| 120 |     Qt::DropAction proposedAction = Qt::IgnoreAction; | 
| 121 |     Qt::DropActions supportedActions; | 
| 122 |     QPointF position; | 
| 123 |     bool accept = true; | 
| 124 | }; | 
| 125 |  | 
| 126 | class tst_QQuickDrag: public QObject | 
| 127 | { | 
| 128 |     Q_OBJECT | 
| 129 | private slots: | 
| 130 |     void initTestCase(); | 
| 131 |     void cleanupTestCase(); | 
| 132 |  | 
| 133 |     void active(); | 
| 134 |     void setActive_data(); | 
| 135 |     void setActive(); | 
| 136 |     void drop(); | 
| 137 |     void move(); | 
| 138 |     void parentChange(); | 
| 139 |     void hotSpot(); | 
| 140 |     void supportedActions(); | 
| 141 |     void proposedAction(); | 
| 142 |     void keys(); | 
| 143 |     void source(); | 
| 144 |     void recursion_data(); | 
| 145 |     void recursion(); | 
| 146 |     void noCrashWithImageProvider(); | 
| 147 |  | 
| 148 | private: | 
| 149 |     QQmlEngine engine; | 
| 150 | }; | 
| 151 |  | 
| 152 | void tst_QQuickDrag::initTestCase() | 
| 153 | { | 
| 154 |  | 
| 155 | } | 
| 156 |  | 
| 157 | void tst_QQuickDrag::cleanupTestCase() | 
| 158 | { | 
| 159 |  | 
| 160 | } | 
| 161 |  | 
| 162 | void tst_QQuickDrag::active() | 
| 163 | { | 
| 164 |     QQuickWindow window; | 
| 165 |     TestDropTarget dropTarget(window.contentItem()); | 
| 166 |     dropTarget.setSize(QSizeF(100, 100)); | 
| 167 |     QQmlComponent component(&engine); | 
| 168 |     component.setData( | 
| 169 |             "import QtQuick 2.0\n"  | 
| 170 |             "Item {\n"  | 
| 171 |                 "property bool dragActive: Drag.active\n"  | 
| 172 |                 "property Item dragTarget: Drag.target\n"  | 
| 173 |                 "x: 50; y: 50\n"  | 
| 174 |                 "width: 10; height: 10\n"  | 
| 175 |             "}" , baseUrl: QUrl()); | 
| 176 |     QScopedPointer<QObject> object(component.create()); | 
| 177 |     QQuickItem *item = qobject_cast<QQuickItem *>(object: object.data()); | 
| 178 |     QVERIFY(item); | 
| 179 |     item->setParentItem(&dropTarget); | 
| 180 |  | 
| 181 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), false); | 
| 182 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), false); | 
| 183 |  | 
| 184 |     evaluate<void>(scope: item, expression: "Drag.active = true" ); | 
| 185 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), true); | 
| 186 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), true); | 
| 187 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(&dropTarget)); | 
| 188 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(&dropTarget)); | 
| 189 |     QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0); | 
| 190 |  | 
| 191 |     dropTarget.reset(); | 
| 192 |     evaluate<void>(scope: item, expression: "Drag.active = false" ); | 
| 193 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), false); | 
| 194 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), false); | 
| 195 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(nullptr)); | 
| 196 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(nullptr)); | 
| 197 |     QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 1); | 
| 198 |  | 
| 199 |     dropTarget.reset(); | 
| 200 |     evaluate<void>(scope: item, expression: "Drag.cancel()" ); | 
| 201 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), false); | 
| 202 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), false); | 
| 203 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(nullptr)); | 
| 204 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(nullptr)); | 
| 205 |     QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0); | 
| 206 |  | 
| 207 |     dropTarget.reset(); | 
| 208 |     evaluate<void>(scope: item, expression: "Drag.start()" ); | 
| 209 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), true); | 
| 210 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), true); | 
| 211 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(&dropTarget)); | 
| 212 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(&dropTarget)); | 
| 213 |     QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0); | 
| 214 |  | 
| 215 |     // Start while a drag is active, cancels the previous drag and starts a new one. | 
| 216 |     dropTarget.reset(); | 
| 217 |     evaluate<void>(scope: item, expression: "Drag.start()" ); | 
| 218 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), true); | 
| 219 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), true); | 
| 220 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(&dropTarget)); | 
| 221 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(&dropTarget)); | 
| 222 |     QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 1); | 
| 223 |  | 
| 224 |     dropTarget.reset(); | 
| 225 |     evaluate<void>(scope: item, expression: "Drag.cancel()" ); | 
| 226 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), false); | 
| 227 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), false); | 
| 228 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(nullptr)); | 
| 229 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(nullptr)); | 
| 230 |     QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 1); | 
| 231 |  | 
| 232 |     // Enter events aren't sent to items without the QQuickItem::ItemAcceptsDrops flag. | 
| 233 |     dropTarget.setFlags(QQuickItem::Flags()); | 
| 234 |  | 
| 235 |     dropTarget.reset(); | 
| 236 |     evaluate<void>(scope: item, expression: "Drag.active = true" ); | 
| 237 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), true); | 
| 238 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), true); | 
| 239 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(nullptr)); | 
| 240 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(nullptr)); | 
| 241 |     QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0); | 
| 242 |  | 
| 243 |     dropTarget.reset(); | 
| 244 |     evaluate<void>(scope: item, expression: "Drag.active = false" ); | 
| 245 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), false); | 
| 246 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), false); | 
| 247 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(nullptr)); | 
| 248 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(nullptr)); | 
| 249 |     QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0); | 
| 250 |  | 
| 251 |     dropTarget.setFlags(QQuickItem::ItemAcceptsDrops); | 
| 252 |  | 
| 253 |     dropTarget.reset(); | 
| 254 |     evaluate<void>(scope: item, expression: "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 *>(&dropTarget)); | 
| 258 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(&dropTarget)); | 
| 259 |     QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0); | 
| 260 |  | 
| 261 |     dropTarget.setFlags(QQuickItem::Flags()); | 
| 262 |  | 
| 263 |     dropTarget.reset(); | 
| 264 |     evaluate<void>(scope: item, expression: "Drag.active = false" ); | 
| 265 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), false); | 
| 266 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), false); | 
| 267 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(nullptr)); | 
| 268 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(nullptr)); | 
| 269 |     QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 1); | 
| 270 |  | 
| 271 |     // Follow up events aren't sent to items if the enter event isn't accepted. | 
| 272 |     dropTarget.setFlags(QQuickItem::ItemAcceptsDrops); | 
| 273 |     dropTarget.accept = false; | 
| 274 |  | 
| 275 |     dropTarget.reset(); | 
| 276 |     evaluate<void>(scope: item, expression: "Drag.active = true" ); | 
| 277 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), true); | 
| 278 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), true); | 
| 279 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(nullptr)); | 
| 280 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(nullptr)); | 
| 281 |     QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0); | 
| 282 |  | 
| 283 |     dropTarget.reset(); | 
| 284 |     evaluate<void>(scope: item, expression: "Drag.active = false" ); | 
| 285 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), false); | 
| 286 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), false); | 
| 287 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(nullptr)); | 
| 288 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(nullptr)); | 
| 289 |     QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0); | 
| 290 |  | 
| 291 |     dropTarget.accept = true; | 
| 292 |  | 
| 293 |     dropTarget.reset(); | 
| 294 |     evaluate<void>(scope: item, expression: "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 *>(&dropTarget)); | 
| 298 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(&dropTarget)); | 
| 299 |     QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0); | 
| 300 |  | 
| 301 |     dropTarget.accept = false; | 
| 302 |  | 
| 303 |     dropTarget.reset(); | 
| 304 |     evaluate<void>(scope: item, expression: "Drag.active = false" ); | 
| 305 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), false); | 
| 306 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), false); | 
| 307 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(nullptr)); | 
| 308 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(nullptr)); | 
| 309 |     QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 1); | 
| 310 |  | 
| 311 |     // Events are sent to hidden or disabled items. | 
| 312 |     dropTarget.accept = true; | 
| 313 |     dropTarget.setVisible(false); | 
| 314 |     dropTarget.reset(); | 
| 315 |     evaluate<void>(scope: item, expression: "Drag.active = true" ); | 
| 316 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), true); | 
| 317 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), true); | 
| 318 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(nullptr)); | 
| 319 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(nullptr)); | 
| 320 |     QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0); | 
| 321 |  | 
| 322 |     evaluate<void>(scope: item, expression: "Drag.active = false" ); | 
| 323 |     dropTarget.setVisible(true); | 
| 324 |  | 
| 325 |     dropTarget.setOpacity(0.0); | 
| 326 |     dropTarget.reset(); | 
| 327 |     evaluate<void>(scope: item, expression: "Drag.active = true" ); | 
| 328 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), true); | 
| 329 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), true); | 
| 330 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(&dropTarget)); | 
| 331 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(&dropTarget)); | 
| 332 |     QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0); | 
| 333 |  | 
| 334 |     evaluate<void>(scope: item, expression: "Drag.active = false" ); | 
| 335 |     dropTarget.setOpacity(1.0); | 
| 336 |  | 
| 337 |     dropTarget.setEnabled(false); | 
| 338 |     dropTarget.reset(); | 
| 339 |     evaluate<void>(scope: item, expression: "Drag.active = true" ); | 
| 340 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), true); | 
| 341 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), true); | 
| 342 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(nullptr)); | 
| 343 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(nullptr)); | 
| 344 |     QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0); | 
| 345 |  | 
| 346 |     evaluate<void>(scope: item, expression: "Drag.active = false" ); | 
| 347 |     dropTarget.setEnabled(true); | 
| 348 |     dropTarget.reset(); | 
| 349 |  | 
| 350 |     // Queued move events are discarded if the drag is cancelled. | 
| 351 |     evaluate<void>(scope: item, expression: "Drag.active = true" ); | 
| 352 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), true); | 
| 353 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), true); | 
| 354 |     QCOMPARE(dropTarget.enterEvents, 1); QCOMPARE(dropTarget.leaveEvents, 0); QCOMPARE(dropTarget.moveEvents, 0); | 
| 355 |  | 
| 356 |     dropTarget.reset(); | 
| 357 |     item->setPosition(QPointF(80, 80)); | 
| 358 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), true); | 
| 359 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), true); | 
| 360 |     QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0); QCOMPARE(dropTarget.moveEvents, 0); | 
| 361 |  | 
| 362 |     evaluate<void>(scope: item, expression: "Drag.active = false" ); | 
| 363 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), false); | 
| 364 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), false); | 
| 365 |     QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 1); QCOMPARE(dropTarget.moveEvents, 0); | 
| 366 |  | 
| 367 |     dropTarget.reset(); | 
| 368 |     QCoreApplication::processEvents(); | 
| 369 |     QCOMPARE(dropTarget.enterEvents, 0); QCOMPARE(dropTarget.leaveEvents, 0); QCOMPARE(dropTarget.moveEvents, 0); | 
| 370 | } | 
| 371 |  | 
| 372 | void tst_QQuickDrag::setActive_data() | 
| 373 | { | 
| 374 |     QTest::addColumn<QString>(name: "dragType" ); | 
| 375 |  | 
| 376 |     QTest::newRow(dataTag: "default" ) << "" ; | 
| 377 |     QTest::newRow(dataTag: "internal" ) << "Drag.dragType: Drag.Internal" ; | 
| 378 |     QTest::newRow(dataTag: "none" ) << "Drag.dragType: Drag.None" ; | 
| 379 |     /* We don't test Drag.Automatic, because that causes QDrag::exec() to be | 
| 380 |      * invoked, and on some platforms tha's implemented by running a main loop | 
| 381 |      * until the drag has finished -- and at that point, the Drag.active will | 
| 382 |      * be false again. */ | 
| 383 | } | 
| 384 |  | 
| 385 | // QTBUG-52540 | 
| 386 | void tst_QQuickDrag::setActive() | 
| 387 | { | 
| 388 |     QFETCH(QString, dragType); | 
| 389 |  | 
| 390 |     QQuickWindow window; | 
| 391 |     TestDropTarget dropTarget(window.contentItem()); | 
| 392 |     dropTarget.setSize(QSizeF(100, 100)); | 
| 393 |     QQmlComponent component(&engine); | 
| 394 |     component.setData( | 
| 395 |             "import QtQuick 2.0\n"  | 
| 396 |             "Item {\n"  | 
| 397 |                 "property bool dragActive: Drag.active\n"  | 
| 398 |                 "property Item dragTarget: Drag.target\n"  + | 
| 399 |                 dragType.toUtf8() + "\n"  | 
| 400 |                 "x: 50; y: 50\n"  | 
| 401 |                 "width: 10; height: 10\n"  | 
| 402 |             "}" , baseUrl: QUrl()); | 
| 403 |     QScopedPointer<QObject> object(component.create()); | 
| 404 |     QQuickItem *item = qobject_cast<QQuickItem *>(object: object.data()); | 
| 405 |     QVERIFY(item); | 
| 406 |     item->setParentItem(&dropTarget); | 
| 407 |  | 
| 408 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), false); | 
| 409 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), false); | 
| 410 |  | 
| 411 |     evaluate<void>(scope: item, expression: "Drag.active = true" ); | 
| 412 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), true); | 
| 413 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), true); | 
| 414 | } | 
| 415 |  | 
| 416 | void tst_QQuickDrag::drop() | 
| 417 | { | 
| 418 |     QQuickWindow window; | 
| 419 |     TestDropTarget outerTarget(window.contentItem()); | 
| 420 |     outerTarget.setSize(QSizeF(100, 100)); | 
| 421 |     outerTarget.acceptAction = Qt::CopyAction; | 
| 422 |     TestDropTarget innerTarget(&outerTarget); | 
| 423 |     innerTarget.setSize(QSizeF(100, 100)); | 
| 424 |     innerTarget.acceptAction = Qt::MoveAction; | 
| 425 |     QQmlComponent component(&engine); | 
| 426 |     component.setData( | 
| 427 |             "import QtQuick 2.0\n"  | 
| 428 |             "Item {\n"  | 
| 429 |                 "property bool dragActive: Drag.active\n"  | 
| 430 |                 "property Item dragTarget: Drag.target\n"  | 
| 431 |                 "x: 50; y: 50\n"  | 
| 432 |                 "width: 10; height: 10\n"  | 
| 433 |             "}" , baseUrl: QUrl()); | 
| 434 |     QScopedPointer<QObject> object(component.create()); | 
| 435 |     QQuickItem *item = qobject_cast<QQuickItem *>(object: object.data()); | 
| 436 |     QVERIFY(item); | 
| 437 |     item->setParentItem(&outerTarget); | 
| 438 |  | 
| 439 |     innerTarget.reset(); outerTarget.reset(); | 
| 440 |     evaluate<void>(scope: item, expression: "Drag.active = true" ); | 
| 441 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), true); | 
| 442 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), true); | 
| 443 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(&innerTarget)); | 
| 444 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(&innerTarget)); | 
| 445 |     QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0); | 
| 446 |     QCOMPARE(innerTarget.enterEvents, 1); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0); | 
| 447 |  | 
| 448 |     innerTarget.reset(); outerTarget.reset(); | 
| 449 |     QCOMPARE(evaluate<bool>(item, "Drag.drop() == Qt.MoveAction" ), true); | 
| 450 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), false); | 
| 451 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), false); | 
| 452 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(&innerTarget)); | 
| 453 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(&innerTarget)); | 
| 454 |     QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0); | 
| 455 |     QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 1); | 
| 456 |  | 
| 457 |     innerTarget.reset(); outerTarget.reset(); | 
| 458 |     evaluate<void>(scope: item, expression: "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 *>(&innerTarget)); | 
| 462 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(&innerTarget)); | 
| 463 |     QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0); | 
| 464 |     QCOMPARE(innerTarget.enterEvents, 1); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0); | 
| 465 |  | 
| 466 |     evaluate<void>(scope: item, expression: "Drag.active = false" ); | 
| 467 |  | 
| 468 |     // Inner target doesn't accept enter so drop goes directly to outer. | 
| 469 |     innerTarget.accept = false; | 
| 470 |     innerTarget.setFlags(QQuickItem::Flags()); | 
| 471 |  | 
| 472 |     innerTarget.reset(); outerTarget.reset(); | 
| 473 |     evaluate<void>(scope: item, expression: "Drag.active = true" ); | 
| 474 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), true); | 
| 475 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), true); | 
| 476 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(&outerTarget)); | 
| 477 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(&outerTarget)); | 
| 478 |     QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0); | 
| 479 |     QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0); | 
| 480 |  | 
| 481 |     innerTarget.reset(); outerTarget.reset(); | 
| 482 |     QCOMPARE(evaluate<bool>(item, "Drag.drop() == Qt.CopyAction" ), true); | 
| 483 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), false); | 
| 484 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), false); | 
| 485 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(&outerTarget)); | 
| 486 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(&outerTarget)); | 
| 487 |     QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 1); | 
| 488 |     QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0); | 
| 489 |  | 
| 490 |     // Neither target accepts drop so Qt::IgnoreAction is returned. | 
| 491 |     innerTarget.reset(); outerTarget.reset(); | 
| 492 |     evaluate<void>(scope: item, expression: "Drag.active = true" ); | 
| 493 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), true); | 
| 494 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), true); | 
| 495 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(&outerTarget)); | 
| 496 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(&outerTarget)); | 
| 497 |     QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0); | 
| 498 |     QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0); | 
| 499 |  | 
| 500 |     outerTarget.accept = false; | 
| 501 |  | 
| 502 |     innerTarget.reset(); outerTarget.reset(); | 
| 503 |     QCOMPARE(evaluate<bool>(item, "Drag.drop() == Qt.IgnoreAction" ), true); | 
| 504 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), false); | 
| 505 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), false); | 
| 506 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(nullptr)); | 
| 507 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(nullptr)); | 
| 508 |     QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 1); | 
| 509 |     QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0); | 
| 510 |  | 
| 511 |     // drop doesn't send an event and returns Qt.IgnoreAction if not active. | 
| 512 |     innerTarget.accept = true; | 
| 513 |     outerTarget.accept = true; | 
| 514 |     innerTarget.reset(); outerTarget.reset(); | 
| 515 |     QCOMPARE(evaluate<bool>(item, "Drag.drop() == Qt.IgnoreAction" ), true); | 
| 516 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), false); | 
| 517 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), false); | 
| 518 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(nullptr)); | 
| 519 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(nullptr)); | 
| 520 |     QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0); | 
| 521 |     QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0); | 
| 522 |  | 
| 523 |     // Queued move event is delivered before a drop event. | 
| 524 |     innerTarget.reset(); outerTarget.reset(); | 
| 525 |     evaluate<void>(scope: item, expression: "Drag.active = true" ); | 
| 526 |     item->setPosition(QPointF(80, 80)); | 
| 527 |     evaluate<void>(scope: item, expression: "Drag.drop()" ); | 
| 528 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), false); | 
| 529 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), false); | 
| 530 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(&outerTarget)); | 
| 531 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(&outerTarget)); | 
| 532 |     QCOMPARE(outerTarget.enterEvents, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 1); QCOMPARE(outerTarget.moveEvents, 1); | 
| 533 |     QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0); QCOMPARE(innerTarget.moveEvents, 0); | 
| 534 |  | 
| 535 |     innerTarget.reset(); outerTarget.reset(); | 
| 536 |     QCoreApplication::processEvents(); | 
| 537 |     QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.dropEvents, 0); QCOMPARE(outerTarget.moveEvents, 0); | 
| 538 |     QCOMPARE(innerTarget.enterEvents, 0); QCOMPARE(innerTarget.leaveEvents, 0); QCOMPARE(innerTarget.dropEvents, 0); QCOMPARE(innerTarget.moveEvents, 0); | 
| 539 | } | 
| 540 |  | 
| 541 | void tst_QQuickDrag::move() | 
| 542 | { | 
| 543 |     QQuickWindow window; | 
| 544 |     TestDropTarget outerTarget(window.contentItem()); | 
| 545 |     outerTarget.setSize(QSizeF(100, 100)); | 
| 546 |     TestDropTarget leftTarget(&outerTarget); | 
| 547 |     leftTarget.setPosition(QPointF(0, 35)); | 
| 548 |     leftTarget.setSize(QSizeF(30, 30)); | 
| 549 |     TestDropTarget rightTarget(&outerTarget); | 
| 550 |     rightTarget.setPosition(QPointF(70, 35)); | 
| 551 |     rightTarget.setSize(QSizeF(30, 30)); | 
| 552 |     QQmlComponent component(&engine); | 
| 553 |     component.setData( | 
| 554 |             "import QtQuick 2.0\n"  | 
| 555 |             "Item {\n"  | 
| 556 |                 "property bool dragActive: Drag.active\n"  | 
| 557 |                 "property Item dragTarget: Drag.target\n"  | 
| 558 |                 "x: 50; y: 50\n"  | 
| 559 |                 "width: 10; height: 10\n"  | 
| 560 |             "}" , baseUrl: QUrl()); | 
| 561 |     QScopedPointer<QObject> object(component.create()); | 
| 562 |     QQuickItem *item = qobject_cast<QQuickItem *>(object: object.data()); | 
| 563 |     QVERIFY(item); | 
| 564 |     item->setParentItem(&outerTarget); | 
| 565 |  | 
| 566 |     evaluate<void>(scope: item, expression: "Drag.active = true" ); | 
| 567 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), true); | 
| 568 |     QCOMPARE(evaluate<bool>(item, "dragActive" ), true); | 
| 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, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 0); | 
| 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(50)); QCOMPARE(outerTarget.position.y(), qreal(50)); | 
| 575 |  | 
| 576 |     // Move within the outer target. | 
| 577 |     outerTarget.reset(); leftTarget.reset(); rightTarget.reset(); | 
| 578 |     item->setPosition(QPointF(60, 50)); | 
| 579 |     // Move event is delivered in the event loop. | 
| 580 |     QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 0); | 
| 581 |     QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0); | 
| 582 |     QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0); | 
| 583 |     QCoreApplication::processEvents(); | 
| 584 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(&outerTarget)); | 
| 585 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(&outerTarget)); | 
| 586 |     QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 1); | 
| 587 |     QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0); | 
| 588 |     QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0); | 
| 589 |     QCOMPARE(outerTarget.position.x(), qreal(60)); QCOMPARE(outerTarget.position.y(), qreal(50)); | 
| 590 |  | 
| 591 |     // Move into the right target. | 
| 592 |     outerTarget.reset(); leftTarget.reset(); rightTarget.reset(); | 
| 593 |     // Setting X and Y individually should still only generate on move. | 
| 594 |     item->setX(75); | 
| 595 |     item->setY(50); | 
| 596 |     QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 0); | 
| 597 |     QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0); | 
| 598 |     QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0); | 
| 599 |     QCoreApplication::processEvents(); | 
| 600 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(&rightTarget)); | 
| 601 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(&rightTarget)); | 
| 602 |     QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 1); QCOMPARE(outerTarget.moveEvents, 0); | 
| 603 |     QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0); | 
| 604 |     QCOMPARE(rightTarget.enterEvents, 1); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0); | 
| 605 |     QCOMPARE(rightTarget.position.x(), qreal(5)); QCOMPARE(rightTarget.position.y(), qreal(15)); | 
| 606 |  | 
| 607 |     // Move into the left target. | 
| 608 |     outerTarget.reset(); leftTarget.reset(); rightTarget.reset(); | 
| 609 |     item->setPosition(QPointF(25, 50)); | 
| 610 |     QCoreApplication::processEvents(); | 
| 611 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(&leftTarget)); | 
| 612 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(&leftTarget)); | 
| 613 |     QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 0); | 
| 614 |     QCOMPARE(leftTarget .enterEvents, 1); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0); | 
| 615 |     QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 1); QCOMPARE(rightTarget.moveEvents, 0); | 
| 616 |     QCOMPARE(leftTarget.position.x(), qreal(25)); QCOMPARE(leftTarget.position.y(), qreal(15)); | 
| 617 |  | 
| 618 |     // Move within the left target. | 
| 619 |     outerTarget.reset(); leftTarget.reset(); rightTarget.reset(); | 
| 620 |     item->setPosition(QPointF(25, 40)); | 
| 621 |     QCoreApplication::processEvents(); | 
| 622 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(&leftTarget)); | 
| 623 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(&leftTarget)); | 
| 624 |     QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 0); | 
| 625 |     QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 1); | 
| 626 |     QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0); | 
| 627 |     QCOMPARE(outerTarget.position.x(), qreal(60)); QCOMPARE(outerTarget.position.y(), qreal(50)); | 
| 628 |     QCOMPARE(leftTarget.position.x(), qreal(25)); QCOMPARE(leftTarget.position.y(), qreal(5)); | 
| 629 |  | 
| 630 |     // Move out of all targets. | 
| 631 |     outerTarget.reset(); leftTarget.reset(); rightTarget.reset(); | 
| 632 |     item->setPosition(QPointF(110, 50)); | 
| 633 |     QCoreApplication::processEvents(); | 
| 634 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(nullptr)); | 
| 635 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(nullptr)); | 
| 636 |     QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 0); | 
| 637 |     QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 1); QCOMPARE(leftTarget .moveEvents, 0); | 
| 638 |     QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0); | 
| 639 |  | 
| 640 |     // Stop the right target accepting drag events and move into it. | 
| 641 |     rightTarget.accept = false; | 
| 642 |  | 
| 643 |     outerTarget.reset(); leftTarget.reset(); rightTarget.reset(); | 
| 644 |     item->setPosition(QPointF(80, 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, 1); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 0); | 
| 649 |     QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0); | 
| 650 |     QCOMPARE(rightTarget.enterEvents, 1); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0); | 
| 651 |     QCOMPARE(outerTarget.position.x(), qreal(80)); QCOMPARE(outerTarget.position.y(), qreal(50)); | 
| 652 |  | 
| 653 |     // Stop the outer target accepting drag events after it has accepted an enter event. | 
| 654 |     outerTarget.accept = false; | 
| 655 |  | 
| 656 |     outerTarget.reset(); leftTarget.reset(); rightTarget.reset(); | 
| 657 |     item->setPosition(QPointF(60, 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(60)); QCOMPARE(outerTarget.position.y(), qreal(50)); | 
| 665 |  | 
| 666 |     // Clear the QQuickItem::ItemAcceptsDrops flag from the outer target after it accepted an enter event. | 
| 667 |     outerTarget.setFlags(QQuickItem::Flags()); | 
| 668 |  | 
| 669 |     outerTarget.reset(); leftTarget.reset(); rightTarget.reset(); | 
| 670 |     item->setPosition(QPointF(40, 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(40)); QCOMPARE(outerTarget.position.y(), qreal(50)); | 
| 678 |  | 
| 679 |     // Clear the QQuickItem::ItemAcceptsDrops flag from the left target before it accepts an enter event. | 
| 680 |     leftTarget.setFlags(QQuickItem::Flags()); | 
| 681 |  | 
| 682 |     outerTarget.reset(); leftTarget.reset(); rightTarget.reset(); | 
| 683 |     item->setPosition(QPointF(25, 50)); | 
| 684 |     QCoreApplication::processEvents(); | 
| 685 |     QCOMPARE(evaluate<QObject *>(item, "Drag.target" ), static_cast<QObject *>(&outerTarget)); | 
| 686 |     QCOMPARE(evaluate<QObject *>(item, "dragTarget" ), static_cast<QObject *>(&outerTarget)); | 
| 687 |     QCOMPARE(outerTarget.enterEvents, 0); QCOMPARE(outerTarget.leaveEvents, 0); QCOMPARE(outerTarget.moveEvents, 1); | 
| 688 |     QCOMPARE(leftTarget .enterEvents, 0); QCOMPARE(leftTarget .leaveEvents, 0); QCOMPARE(leftTarget .moveEvents, 0); | 
| 689 |     QCOMPARE(rightTarget.enterEvents, 0); QCOMPARE(rightTarget.leaveEvents, 0); QCOMPARE(rightTarget.moveEvents, 0); | 
| 690 |     QCOMPARE(outerTarget.position.x(), qreal(25)); QCOMPARE(outerTarget.position.y(), qreal(50)); | 
| 691 | } | 
| 692 |  | 
| 693 | void tst_QQuickDrag::parentChange() | 
| 694 | { | 
| 695 |     QQuickWindow window1; | 
| 696 |     TestDropTarget dropTarget1(window1.contentItem()); | 
| 697 |     dropTarget1.setSize(QSizeF(100, 100)); | 
| 698 |  | 
| 699 |     QQuickWindow window2; | 
| 700 |     TestDropTarget dropTarget2(window2.contentItem()); | 
| 701 |     dropTarget2.setSize(QSizeF(100, 100)); | 
| 702 |  | 
| 703 |     QQmlComponent component(&engine); | 
| 704 |     component.setData( | 
| 705 |             "import QtQuick 2.0\n"  | 
| 706 |             "Item {\n"  | 
| 707 |                 "property real hotSpotX: Drag.hotSpot.x\n"  | 
| 708 |                 "property real hotSpotY: Drag.hotSpot.y\n"  | 
| 709 |                 "x: 50; y: 50\n"  | 
| 710 |                 "width: 10; height: 10\n"  | 
| 711 |                 "Drag.active: true\n"  | 
| 712 |             "}" , baseUrl: QUrl()); | 
| 713 |     QScopedPointer<QObject> object(component.create()); | 
| 714 |     QQuickItem *item = qobject_cast<QQuickItem *>(object: object.data()); | 
| 715 |     QVERIFY(item); | 
| 716 |  | 
| 717 |     QCOMPARE(evaluate<bool>(item, "Drag.active" ), true); | 
| 718 |  | 
| 719 |     // Verify setting a parent item for an item with an active drag sends an enter event. | 
| 720 |     item->setParentItem(window1.contentItem()); | 
| 721 |     QCOMPARE(dropTarget1.enterEvents, 0); | 
| 722 |     QCoreApplication::processEvents(); | 
| 723 |     QCOMPARE(dropTarget1.enterEvents, 1); | 
| 724 |  | 
| 725 |     // Changing the parent within the same window should send a move event. | 
| 726 |     item->setParentItem(&dropTarget1); | 
| 727 |     QCOMPARE(dropTarget1.enterEvents, 1); | 
| 728 |     QCOMPARE(dropTarget1.moveEvents, 0); | 
| 729 |     QCoreApplication::processEvents(); | 
| 730 |     QCOMPARE(dropTarget1.enterEvents, 1); | 
| 731 |     QCOMPARE(dropTarget1.moveEvents, 1); | 
| 732 |  | 
| 733 |     // Changing the parent to an item in another window sends a leave event in the old window | 
| 734 |     // and an enter on the new window. | 
| 735 |     item->setParentItem(window2.contentItem()); | 
| 736 |     QCOMPARE(dropTarget1.enterEvents, 1); | 
| 737 |     QCOMPARE(dropTarget1.moveEvents, 1); | 
| 738 |     QCOMPARE(dropTarget1.leaveEvents, 0); | 
| 739 |     QCOMPARE(dropTarget2.enterEvents, 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 |  | 
| 746 |     // Removing then parent item sends a leave event. | 
| 747 |     item->setParentItem(nullptr); | 
| 748 |     QCOMPARE(dropTarget1.enterEvents, 1); | 
| 749 |     QCOMPARE(dropTarget1.moveEvents, 1); | 
| 750 |     QCOMPARE(dropTarget1.leaveEvents, 1); | 
| 751 |     QCOMPARE(dropTarget2.enterEvents, 1); | 
| 752 |     QCOMPARE(dropTarget2.leaveEvents, 0); | 
| 753 |     QCoreApplication::processEvents(); | 
| 754 |     QCOMPARE(dropTarget1.enterEvents, 1); | 
| 755 |     QCOMPARE(dropTarget1.moveEvents, 1); | 
| 756 |     QCOMPARE(dropTarget1.leaveEvents, 1); | 
| 757 |     QCOMPARE(dropTarget2.enterEvents, 1); | 
| 758 |     QCOMPARE(dropTarget2.leaveEvents, 1); | 
| 759 |  | 
| 760 |     // Go around again and verify no events if active is false. | 
| 761 |     evaluate<void>(scope: item, expression: "Drag.active = false" ); | 
| 762 |     item->setParentItem(window1.contentItem()); | 
| 763 |     QCoreApplication::processEvents(); | 
| 764 |  | 
| 765 |     item->setParentItem(&dropTarget1); | 
| 766 |     QCoreApplication::processEvents(); | 
| 767 |  | 
| 768 |     item->setParentItem(window2.contentItem()); | 
| 769 |     QCoreApplication::processEvents(); | 
| 770 |  | 
| 771 |     item->setParentItem(nullptr); | 
| 772 |     QCoreApplication::processEvents(); | 
| 773 |     QCOMPARE(dropTarget1.enterEvents, 1); | 
| 774 |     QCOMPARE(dropTarget1.moveEvents, 1); | 
| 775 |     QCOMPARE(dropTarget1.leaveEvents, 1); | 
| 776 |     QCOMPARE(dropTarget2.enterEvents, 1); | 
| 777 |     QCOMPARE(dropTarget2.leaveEvents, 1); | 
| 778 | } | 
| 779 |  | 
| 780 | void tst_QQuickDrag::hotSpot() | 
| 781 | { | 
| 782 |     QQuickWindow window; | 
| 783 |     TestDropTarget dropTarget(window.contentItem()); | 
| 784 |     dropTarget.setSize(QSizeF(100, 100)); | 
| 785 |     QQmlComponent component(&engine); | 
| 786 |     component.setData( | 
| 787 |             "import QtQuick 2.0\n"  | 
| 788 |             "Item {\n"  | 
| 789 |                 "property real hotSpotX: Drag.hotSpot.x\n"  | 
| 790 |                 "property real hotSpotY: Drag.hotSpot.y\n"  | 
| 791 |                 "x: 50; y: 50\n"  | 
| 792 |                 "width: 10; height: 10\n"  | 
| 793 |             "}" , baseUrl: QUrl()); | 
| 794 |     QScopedPointer<QObject> object(component.create()); | 
| 795 |     QQuickItem *item = qobject_cast<QQuickItem *>(object: object.data()); | 
| 796 |     QVERIFY(item); | 
| 797 |     item->setParentItem(&dropTarget); | 
| 798 |  | 
| 799 |     QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.x" ), qreal(0)); | 
| 800 |     QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.y" ), qreal(0)); | 
| 801 |     QCOMPARE(evaluate<qreal>(item, "hotSpotX" ), qreal(0)); | 
| 802 |     QCOMPARE(evaluate<qreal>(item, "hotSpotY" ), qreal(0)); | 
| 803 |  | 
| 804 |     evaluate<void>(scope: item, expression: "{ Drag.start(); Drag.cancel() }" ); | 
| 805 |     QCOMPARE(dropTarget.position.x(), qreal(50)); | 
| 806 |     QCOMPARE(dropTarget.position.y(), qreal(50)); | 
| 807 |  | 
| 808 |     evaluate<void>(scope: item, expression: "{ Drag.hotSpot.x = 5, Drag.hotSpot.y = 5 }" ); | 
| 809 |     QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.x" ), qreal(5)); | 
| 810 |     QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.y" ), qreal(5)); | 
| 811 |     QCOMPARE(evaluate<qreal>(item, "hotSpotX" ), qreal(5)); | 
| 812 |     QCOMPARE(evaluate<qreal>(item, "hotSpotY" ), qreal(5)); | 
| 813 |  | 
| 814 |     evaluate<void>(scope: item, expression: "Drag.start()" ); | 
| 815 |     QCOMPARE(dropTarget.position.x(), qreal(55)); | 
| 816 |     QCOMPARE(dropTarget.position.y(), qreal(55)); | 
| 817 |  | 
| 818 |     item->setPosition(QPointF(30, 20)); | 
| 819 |     QCoreApplication::processEvents(); | 
| 820 |     QCOMPARE(dropTarget.position.x(), qreal(35)); | 
| 821 |     QCOMPARE(dropTarget.position.y(), qreal(25)); | 
| 822 |  | 
| 823 |     evaluate<void>(scope: item, expression: "{ Drag.hotSpot.x = 10; Drag.hotSpot.y = 10 }" ); | 
| 824 |     QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.x" ), qreal(10)); | 
| 825 |     QCOMPARE(evaluate<qreal>(item, "Drag.hotSpot.y" ), qreal(10)); | 
| 826 |     QCOMPARE(evaluate<qreal>(item, "hotSpotX" ), qreal(10)); | 
| 827 |     QCOMPARE(evaluate<qreal>(item, "hotSpotY" ), qreal(10)); | 
| 828 |  | 
| 829 |     // Setting the hotSpot will deliver a move event in the event loop. | 
| 830 |     QCOMPARE(dropTarget.position.x(), qreal(35)); | 
| 831 |     QCOMPARE(dropTarget.position.y(), qreal(25)); | 
| 832 |     QCoreApplication::processEvents(); | 
| 833 |     QCOMPARE(dropTarget.position.x(), qreal(40)); | 
| 834 |     QCOMPARE(dropTarget.position.y(), qreal(30)); | 
| 835 |  | 
| 836 |     item->setPosition(QPointF(10, 20)); | 
| 837 |     QCoreApplication::processEvents(); | 
| 838 |     QCOMPARE(dropTarget.position.x(), qreal(20)); | 
| 839 |     QCOMPARE(dropTarget.position.y(), qreal(30)); | 
| 840 |  | 
| 841 |     evaluate<void>(scope: item, expression: "{ Drag.hotSpot.x = 10; Drag.hotSpot.y = 10 }" ); | 
| 842 | } | 
| 843 |  | 
| 844 | void tst_QQuickDrag::supportedActions() | 
| 845 | { | 
| 846 |     QQuickWindow window; | 
| 847 |     TestDropTarget dropTarget(window.contentItem()); | 
| 848 |     dropTarget.setSize(QSizeF(100, 100)); | 
| 849 |     QQmlComponent component(&engine); | 
| 850 |     component.setData( | 
| 851 |             "import QtQuick 2.0\n"  | 
| 852 |             "Item {\n"  | 
| 853 |                 "property int supportedActions: Drag.supportedActions\n"  | 
| 854 |                 "x: 50; y: 50\n"  | 
| 855 |                 "width: 10; height: 10\n"  | 
| 856 |             "}" , baseUrl: QUrl()); | 
| 857 |     QScopedPointer<QObject> object(component.create()); | 
| 858 |     QQuickItem *item = qobject_cast<QQuickItem *>(object: object.data()); | 
| 859 |     QVERIFY(item); | 
| 860 |     item->setParentItem(&dropTarget); | 
| 861 |  | 
| 862 |     QCOMPARE(evaluate<bool>(item, "Drag.supportedActions == Qt.CopyAction | Qt.MoveAction | Qt.LinkAction" ), true); | 
| 863 |     QCOMPARE(evaluate<bool>(item, "supportedActions == Qt.CopyAction | Qt.MoveAction | Qt.LinkAction" ), true); | 
| 864 |     evaluate<void>(scope: item, expression: "{ Drag.start(); Drag.cancel() }" ); | 
| 865 |     QCOMPARE(dropTarget.supportedActions, Qt::CopyAction | Qt::MoveAction | Qt::LinkAction); | 
| 866 |  | 
| 867 |     dropTarget.reset(); | 
| 868 |     evaluate<void>(scope: item, expression: "Drag.supportedActions = Qt.CopyAction | Qt.MoveAction" ); | 
| 869 |     QCOMPARE(evaluate<bool>(item, "Drag.supportedActions == Qt.CopyAction | Qt.MoveAction" ), true); | 
| 870 |     QCOMPARE(evaluate<bool>(item, "supportedActions == Qt.CopyAction | Qt.MoveAction" ), true); | 
| 871 |     evaluate<void>(scope: item, expression: "Drag.start()" ); | 
| 872 |     QCOMPARE(dropTarget.supportedActions, Qt::CopyAction | Qt::MoveAction); | 
| 873 |     QCOMPARE(dropTarget.leaveEvents, 0); | 
| 874 |     QCOMPARE(dropTarget.enterEvents, 1); | 
| 875 |  | 
| 876 |     // Changing the supported actions will restart the drag, after a delay to avoid any | 
| 877 |     // recursion. | 
| 878 |     evaluate<void>(scope: item, expression: "Drag.supportedActions = Qt.MoveAction" ); | 
| 879 |     QCOMPARE(evaluate<bool>(item, "Drag.supportedActions == Qt.MoveAction" ), true); | 
| 880 |     QCOMPARE(evaluate<bool>(item, "supportedActions == Qt.MoveAction" ), true); | 
| 881 |     item->setPosition(QPointF(60, 60)); | 
| 882 |     QCOMPARE(dropTarget.supportedActions, Qt::CopyAction | Qt::MoveAction); | 
| 883 |     QCOMPARE(dropTarget.leaveEvents, 0); | 
| 884 |     QCOMPARE(dropTarget.enterEvents, 1); | 
| 885 |     QCoreApplication::processEvents(); | 
| 886 |     QCOMPARE(dropTarget.supportedActions, Qt::MoveAction); | 
| 887 |     QCOMPARE(dropTarget.leaveEvents, 1); | 
| 888 |     QCOMPARE(dropTarget.enterEvents, 2); | 
| 889 |  | 
| 890 |     // Calling start with proposed actions will override the current actions for the next sequence. | 
| 891 |     evaluate<void>(scope: item, expression: "Drag.start(Qt.CopyAction)" ); | 
| 892 |     QCOMPARE(evaluate<bool>(item, "Drag.supportedActions == Qt.MoveAction" ), true); | 
| 893 |     QCOMPARE(evaluate<bool>(item, "supportedActions == Qt.MoveAction" ), true); | 
| 894 |     QCOMPARE(dropTarget.supportedActions, Qt::CopyAction); | 
| 895 |  | 
| 896 |     evaluate<void>(scope: item, expression: "Drag.start()" ); | 
| 897 |     QCOMPARE(evaluate<bool>(item, "Drag.supportedActions == Qt.MoveAction" ), true); | 
| 898 |     QCOMPARE(evaluate<bool>(item, "supportedActions == Qt.MoveAction" ), true); | 
| 899 |     QCOMPARE(dropTarget.supportedActions, Qt::MoveAction); | 
| 900 | } | 
| 901 |  | 
| 902 | void tst_QQuickDrag::proposedAction() | 
| 903 | { | 
| 904 |     QQuickWindow window; | 
| 905 |     TestDropTarget dropTarget(window.contentItem()); | 
| 906 |     dropTarget.setSize(QSizeF(100, 100)); | 
| 907 |     QQmlComponent component(&engine); | 
| 908 |     component.setData( | 
| 909 |             "import QtQuick 2.0\n"  | 
| 910 |             "Item {\n"  | 
| 911 |                 "property int proposedAction: Drag.proposedAction\n"  | 
| 912 |                 "x: 50; y: 50\n"  | 
| 913 |                 "width: 10; height: 10\n"  | 
| 914 |             "}" , baseUrl: QUrl()); | 
| 915 |     QScopedPointer<QObject> object(component.create()); | 
| 916 |     QQuickItem *item = qobject_cast<QQuickItem *>(object: object.data()); | 
| 917 |     QVERIFY(item); | 
| 918 |     item->setParentItem(&dropTarget); | 
| 919 |  | 
| 920 |     QCOMPARE(evaluate<bool>(item, "Drag.proposedAction == Qt.MoveAction" ), true); | 
| 921 |     QCOMPARE(evaluate<bool>(item, "proposedAction == Qt.MoveAction" ), true); | 
| 922 |     evaluate<void>(scope: item, expression: "{ Drag.start(); Drag.cancel() }" ); | 
| 923 |     QCOMPARE(dropTarget.defaultAction, Qt::MoveAction); | 
| 924 |     QCOMPARE(dropTarget.proposedAction, Qt::MoveAction); | 
| 925 |  | 
| 926 |     evaluate<void>(scope: item, expression: "Drag.proposedAction = Qt.CopyAction" ); | 
| 927 |     QCOMPARE(evaluate<bool>(item, "Drag.proposedAction == Qt.CopyAction" ), true); | 
| 928 |     QCOMPARE(evaluate<bool>(item, "proposedAction == Qt.CopyAction" ), true); | 
| 929 |     evaluate<void>(scope: item, expression: "Drag.start()" ); | 
| 930 |     QCOMPARE(dropTarget.defaultAction, Qt::CopyAction); | 
| 931 |     QCOMPARE(dropTarget.proposedAction, Qt::CopyAction); | 
| 932 |  | 
| 933 |     // The proposed action can change during a drag. | 
| 934 |     evaluate<void>(scope: item, expression: "Drag.proposedAction = Qt.MoveAction" ); | 
| 935 |     QCOMPARE(evaluate<bool>(item, "Drag.proposedAction == Qt.MoveAction" ), true); | 
| 936 |     QCOMPARE(evaluate<bool>(item, "proposedAction == Qt.MoveAction" ), true); | 
| 937 |     QCoreApplication::processEvents(); | 
| 938 |     QCOMPARE(dropTarget.defaultAction, Qt::MoveAction); | 
| 939 |     QCOMPARE(dropTarget.proposedAction, Qt::MoveAction); | 
| 940 |  | 
| 941 |     evaluate<void>(scope: item, expression: "Drag.proposedAction = Qt.LinkAction" ); | 
| 942 |     QCOMPARE(evaluate<bool>(item, "Drag.proposedAction == Qt.LinkAction" ), true); | 
| 943 |     QCOMPARE(evaluate<bool>(item, "proposedAction == Qt.LinkAction" ), true); | 
| 944 |     evaluate<void>(scope: item, expression: "Drag.drop()" ); | 
| 945 |     QCOMPARE(dropTarget.defaultAction, Qt::LinkAction); | 
| 946 |     QCOMPARE(dropTarget.proposedAction, Qt::LinkAction); | 
| 947 | } | 
| 948 |  | 
| 949 | void tst_QQuickDrag::keys() | 
| 950 | { | 
| 951 |     QQmlComponent component(&engine); | 
| 952 |     component.setData( | 
| 953 |             "import QtQuick 2.0\n"  | 
| 954 |             "Item {\n"  | 
| 955 |                 "property variant keys: Drag.keys\n"  | 
| 956 |                 "x: 50; y: 50\n"  | 
| 957 |                 "width: 10; height: 10\n"  | 
| 958 |             "}" , baseUrl: QUrl()); | 
| 959 |     QScopedPointer<QObject> object(component.create()); | 
| 960 |     QQuickItem *item = qobject_cast<QQuickItem *>(object: object.data()); | 
| 961 |     QVERIFY(item); | 
| 962 |  | 
| 963 |     QCOMPARE(evaluate<QStringList>(item, "Drag.keys" ), QStringList()); | 
| 964 |     QCOMPARE(evaluate<QStringList>(item, "keys" ), QStringList()); | 
| 965 |     QCOMPARE(item->property("keys" ).toStringList(), QStringList()); | 
| 966 |  | 
| 967 |     evaluate<void>(scope: item, expression: "Drag.keys = [\"red\", \"blue\"]" ); | 
| 968 |     QCOMPARE(evaluate<QStringList>(item, "Drag.keys" ), QStringList() << "red"  << "blue" ); | 
| 969 |     QCOMPARE(evaluate<QStringList>(item, "keys" ), QStringList() << "red"  << "blue" ); | 
| 970 |     QCOMPARE(item->property("keys" ).toStringList(), QStringList() << "red"  << "blue" ); | 
| 971 |  | 
| 972 |     // Test changing the keys restarts a drag. | 
| 973 |     QQuickWindow window; | 
| 974 |     item->setParentItem(window.contentItem()); | 
| 975 |     TestDropTarget dropTarget(window.contentItem()); | 
| 976 |     dropTarget.setSize(QSizeF(100, 100)); | 
| 977 |  | 
| 978 |     evaluate<void>(scope: item, expression: "Drag.start()" ); | 
| 979 |     QCOMPARE(dropTarget.leaveEvents, 0); | 
| 980 |     QCOMPARE(dropTarget.enterEvents, 1); | 
| 981 |  | 
| 982 |     evaluate<void>(scope: item, expression: "Drag.keys = [\"green\"]" ); | 
| 983 |     QCOMPARE(dropTarget.leaveEvents, 0); | 
| 984 |     QCOMPARE(dropTarget.enterEvents, 1); | 
| 985 |     QCoreApplication::processEvents(); | 
| 986 |     QCOMPARE(dropTarget.leaveEvents, 1); | 
| 987 |     QCOMPARE(dropTarget.enterEvents, 2); | 
| 988 | } | 
| 989 |  | 
| 990 | void tst_QQuickDrag::source() | 
| 991 | { | 
| 992 |  | 
| 993 |     QQmlComponent component(&engine); | 
| 994 |     component.setData( | 
| 995 |             "import QtQuick 2.0\n"  | 
| 996 |             "Item {\n"  | 
| 997 |                 "property Item source: Drag.source\n"  | 
| 998 |                 "x: 50; y: 50\n"  | 
| 999 |                 "width: 10; height: 10\n"  | 
| 1000 |                 "Item { id: proxySource; objectName: \"proxySource\" }\n"  | 
| 1001 |             "}" , baseUrl: QUrl()); | 
| 1002 |     QScopedPointer<QObject> object(component.create()); | 
| 1003 |     QQuickItem *item = qobject_cast<QQuickItem *>(object: object.data()); | 
| 1004 |     QVERIFY(item); | 
| 1005 |  | 
| 1006 |     QCOMPARE(evaluate<QObject *>(item, "Drag.source" ), static_cast<QObject *>(item)); | 
| 1007 |     QCOMPARE(evaluate<QObject *>(item, "source" ), static_cast<QObject *>(item)); | 
| 1008 |  | 
| 1009 |     QQuickItem *proxySource = item->findChild<QQuickItem *>(aName: "proxySource" ); | 
| 1010 |     QVERIFY(proxySource); | 
| 1011 |  | 
| 1012 |     evaluate<void>(scope: item, expression: "Drag.source = proxySource" ); | 
| 1013 |     QCOMPARE(evaluate<QObject *>(item, "Drag.source" ), static_cast<QObject *>(proxySource)); | 
| 1014 |     QCOMPARE(evaluate<QObject *>(item, "source" ), static_cast<QObject *>(proxySource)); | 
| 1015 |  | 
| 1016 |     evaluate<void>(scope: item, expression: "Drag.source = undefined" ); | 
| 1017 |     QCOMPARE(evaluate<QObject *>(item, "Drag.source" ), static_cast<QObject *>(item)); | 
| 1018 |     QCOMPARE(evaluate<QObject *>(item, "source" ), static_cast<QObject *>(item)); | 
| 1019 |  | 
| 1020 |     // Test changing the source restarts a drag. | 
| 1021 |     QQuickWindow window; | 
| 1022 |     item->setParentItem(window.contentItem()); | 
| 1023 |     TestDropTarget dropTarget(window.contentItem()); | 
| 1024 |     dropTarget.setSize(QSizeF(100, 100)); | 
| 1025 |  | 
| 1026 |     evaluate<void>(scope: item, expression: "Drag.start()" ); | 
| 1027 |     QCOMPARE(dropTarget.leaveEvents, 0); | 
| 1028 |     QCOMPARE(dropTarget.enterEvents, 1); | 
| 1029 |  | 
| 1030 |     evaluate<void>(scope: item, expression: "Drag.source = proxySource" ); | 
| 1031 |     QCOMPARE(dropTarget.leaveEvents, 0); | 
| 1032 |     QCOMPARE(dropTarget.enterEvents, 1); | 
| 1033 |     QCoreApplication::processEvents(); | 
| 1034 |     QCOMPARE(dropTarget.leaveEvents, 1); | 
| 1035 |     QCOMPARE(dropTarget.enterEvents, 2); | 
| 1036 | } | 
| 1037 |  | 
| 1038 | class RecursingDropTarget : public TestDropTarget | 
| 1039 | { | 
| 1040 | public: | 
| 1041 |     RecursingDropTarget(const QString &script, int type, QQuickItem *parent) | 
| 1042 |         : TestDropTarget(parent), script(script), type(type), item(nullptr) {} | 
| 1043 |  | 
| 1044 |     void setItem(QQuickItem *i) { item = i; } | 
| 1045 |  | 
| 1046 | protected: | 
| 1047 |     void dragEnterEvent(QDragEnterEvent *event) | 
| 1048 |     { | 
| 1049 |         TestDropTarget::dragEnterEvent(event); | 
| 1050 |         if (type == QEvent::DragEnter && enterEvents < 2) | 
| 1051 |             evaluate<void>(scope: item, expression: script); | 
| 1052 |     } | 
| 1053 |  | 
| 1054 |     void dragMoveEvent(QDragMoveEvent *event) | 
| 1055 |     { | 
| 1056 |         TestDropTarget::dragMoveEvent(event); | 
| 1057 |         if (type == QEvent::DragMove && moveEvents < 2) | 
| 1058 |             evaluate<void>(scope: item, expression: script); | 
| 1059 |     } | 
| 1060 |  | 
| 1061 |     void dragLeaveEvent(QDragLeaveEvent *event) | 
| 1062 |     { | 
| 1063 |         TestDropTarget::dragLeaveEvent(event); | 
| 1064 |         if (type == QEvent::DragLeave && leaveEvents < 2) | 
| 1065 |             evaluate<void>(scope: item, expression: script); | 
| 1066 |     } | 
| 1067 |  | 
| 1068 |     void dropEvent(QDropEvent *event) | 
| 1069 |     { | 
| 1070 |         TestDropTarget::dropEvent(event); | 
| 1071 |         if (type == QEvent::Drop && dropEvents < 2) | 
| 1072 |             evaluate<void>(scope: item, expression: script); | 
| 1073 |     } | 
| 1074 |  | 
| 1075 | private: | 
| 1076 |     QString script; | 
| 1077 |     int type; | 
| 1078 |     QQuickItem *item; | 
| 1079 |  | 
| 1080 | }; | 
| 1081 |  | 
| 1082 | void tst_QQuickDrag::recursion_data() | 
| 1083 | { | 
| 1084 |     QTest::addColumn<QString>(name: "script" ); | 
| 1085 |     QTest::addColumn<int>(name: "type" ); | 
| 1086 |     QTest::addColumn<int>(name: "moveEvents" ); | 
| 1087 |     QTest::addColumn<QRegularExpression>(name: "warning" ); | 
| 1088 |  | 
| 1089 |     QTest::newRow(dataTag: "Drag.start() in Enter" ) | 
| 1090 |             << QString("Drag.start()" ) | 
| 1091 |             << int(QEvent::DragEnter) | 
| 1092 |             << 1 | 
| 1093 |             << QRegularExpression(".*start\\(\\) cannot be called from within a drag event handler" ); | 
| 1094 |     QTest::newRow(dataTag: "Drag.cancel() in Enter" ) | 
| 1095 |             << QString("Drag.cancel()" ) | 
| 1096 |             << int(QEvent::DragEnter) | 
| 1097 |             << 1 | 
| 1098 |             << QRegularExpression(".*cancel\\(\\) cannot be called from within a drag event handler" ); | 
| 1099 |     QTest::newRow(dataTag: "Drag.drop() in Enter" ) | 
| 1100 |             << QString("Drag.drop()" ) | 
| 1101 |             << int(QEvent::DragEnter) | 
| 1102 |             << 1 | 
| 1103 |             << QRegularExpression(".*drop\\(\\) cannot be called from within a drag event handler" ); | 
| 1104 |     QTest::newRow(dataTag: "Drag.active = true in Enter" ) | 
| 1105 |             << QString("Drag.active = true" ) | 
| 1106 |             << int(QEvent::DragEnter) | 
| 1107 |             << 1 | 
| 1108 |             << QRegularExpression(); | 
| 1109 |     QTest::newRow(dataTag: "Drag.active = false in Enter" ) | 
| 1110 |             << QString("Drag.active = false" ) | 
| 1111 |             << int(QEvent::DragEnter) | 
| 1112 |             << 1 | 
| 1113 |             << QRegularExpression(".*active cannot be changed from within a drag event handler" ); | 
| 1114 |     QTest::newRow(dataTag: "move in Enter" ) | 
| 1115 |             << QString("x = 23" ) | 
| 1116 |             << int(QEvent::DragEnter) | 
| 1117 |             << 1 | 
| 1118 |             << QRegularExpression(); | 
| 1119 |  | 
| 1120 |     QTest::newRow(dataTag: "Drag.start() in Move" ) | 
| 1121 |             << QString("Drag.start()" ) | 
| 1122 |             << int(QEvent::DragMove) | 
| 1123 |             << 1 | 
| 1124 |             << QRegularExpression(".*start\\(\\) cannot be called from within a drag event handler" ); | 
| 1125 |     QTest::newRow(dataTag: "Drag.cancel() in Move" ) | 
| 1126 |             << QString("Drag.cancel()" ) | 
| 1127 |             << int(QEvent::DragMove) | 
| 1128 |             << 1 | 
| 1129 |             << QRegularExpression(".*cancel\\(\\) cannot be called from within a drag event handler" ); | 
| 1130 |     QTest::newRow(dataTag: "Drag.drop() in Move" ) | 
| 1131 |             << QString("Drag.drop()" ) | 
| 1132 |             << int(QEvent::DragMove) | 
| 1133 |             << 1 | 
| 1134 |             << QRegularExpression(".*drop\\(\\) cannot be called from within a drag event handler" ); | 
| 1135 |     QTest::newRow(dataTag: "Drag.active = true in Move" ) | 
| 1136 |             << QString("Drag.active = true" ) | 
| 1137 |             << int(QEvent::DragMove) | 
| 1138 |             << 1 | 
| 1139 |             << QRegularExpression(); | 
| 1140 |     QTest::newRow(dataTag: "Drag.active = false in Move" ) | 
| 1141 |             << QString("Drag.active = false" ) | 
| 1142 |             << int(QEvent::DragMove) | 
| 1143 |             << 1 | 
| 1144 |             << QRegularExpression(".*active cannot be changed from within a drag event handler" ); | 
| 1145 |     QTest::newRow(dataTag: "move in Move" ) | 
| 1146 |             << QString("x = 23" ) | 
| 1147 |             << int(QEvent::DragMove) | 
| 1148 |             << 2 | 
| 1149 |             << QRegularExpression(); | 
| 1150 |  | 
| 1151 |     QTest::newRow(dataTag: "Drag.start() in Leave" ) | 
| 1152 |             << QString("Drag.start()" ) | 
| 1153 |             << int(QEvent::DragLeave) | 
| 1154 |             << 1 | 
| 1155 |             << QRegularExpression(".*start\\(\\) cannot be called from within a drag event handler" ); | 
| 1156 |     QTest::newRow(dataTag: "Drag.cancel() in Leave" ) | 
| 1157 |             << QString("Drag.cancel()" ) | 
| 1158 |             << int(QEvent::DragLeave) | 
| 1159 |             << 1 | 
| 1160 |             << QRegularExpression(".*cancel\\(\\) cannot be called from within a drag event handler" ); | 
| 1161 |     QTest::newRow(dataTag: "Drag.drop() in Leave" ) | 
| 1162 |             << QString("Drag.drop()" ) | 
| 1163 |             << int(QEvent::DragLeave) | 
| 1164 |             << 1 | 
| 1165 |             << QRegularExpression(".*drop\\(\\) cannot be called from within a drag event handler" ); | 
| 1166 |     QTest::newRow(dataTag: "Drag.active = true in Leave" ) | 
| 1167 |             << QString("Drag.active = true" ) | 
| 1168 |             << int(QEvent::DragLeave) | 
| 1169 |             << 1 | 
| 1170 |             << QRegularExpression(".*active cannot be changed from within a drag event handler" ); | 
| 1171 |     QTest::newRow(dataTag: "Drag.active = false in Leave" ) | 
| 1172 |             << QString("Drag.active = false" ) | 
| 1173 |             << int(QEvent::DragLeave) | 
| 1174 |             << 1 | 
| 1175 |             << QRegularExpression(); | 
| 1176 |     QTest::newRow(dataTag: "move in Leave" ) | 
| 1177 |             << QString("x = 23" ) | 
| 1178 |             << int(QEvent::DragLeave) | 
| 1179 |             << 1 | 
| 1180 |             << QRegularExpression(); | 
| 1181 |  | 
| 1182 |     QTest::newRow(dataTag: "Drag.start() in Drop" ) | 
| 1183 |             << QString("Drag.start()" ) | 
| 1184 |             << int(QEvent::Drop) | 
| 1185 |             << 1 | 
| 1186 |             << QRegularExpression(".*start\\(\\) cannot be called from within a drag event handler" ); | 
| 1187 |     QTest::newRow(dataTag: "Drag.cancel() in Drop" ) | 
| 1188 |             << QString("Drag.cancel()" ) | 
| 1189 |             << int(QEvent::Drop) | 
| 1190 |             << 1 | 
| 1191 |             << QRegularExpression(".*cancel\\(\\) cannot be called from within a drag event handler" ); | 
| 1192 |     QTest::newRow(dataTag: "Drag.drop() in Drop" ) | 
| 1193 |             << QString("Drag.drop()" ) | 
| 1194 |             << int(QEvent::Drop) | 
| 1195 |             << 1 | 
| 1196 |             << QRegularExpression(".*drop\\(\\) cannot be called from within a drag event handler" ); | 
| 1197 |     QTest::newRow(dataTag: "Drag.active = true in Drop" ) | 
| 1198 |             << QString("Drag.active = true" ) | 
| 1199 |             << int(QEvent::Drop) | 
| 1200 |             << 1 | 
| 1201 |             << QRegularExpression(".*active cannot be changed from within a drag event handler" ); | 
| 1202 |     QTest::newRow(dataTag: "Drag.active = false in Drop" ) | 
| 1203 |             << QString("Drag.active = false" ) | 
| 1204 |             << int(QEvent::Drop) | 
| 1205 |             << 1 | 
| 1206 |             << QRegularExpression(); | 
| 1207 |     QTest::newRow(dataTag: "move in Drop" ) | 
| 1208 |             << QString("x = 23" ) | 
| 1209 |             << int(QEvent::Drop) | 
| 1210 |             << 1 | 
| 1211 |             << QRegularExpression(); | 
| 1212 | } | 
| 1213 |  | 
| 1214 | void tst_QQuickDrag::recursion() | 
| 1215 | { | 
| 1216 |     QFETCH(QString, script); | 
| 1217 |     QFETCH(int, type); | 
| 1218 |     QFETCH(int, moveEvents); | 
| 1219 |     QFETCH(QRegularExpression, warning); | 
| 1220 |  | 
| 1221 |     if (!warning.pattern().isEmpty()) | 
| 1222 |         QTest::ignoreMessage(type: QtWarningMsg, messagePattern: warning); | 
| 1223 |  | 
| 1224 |     QQuickWindow window; | 
| 1225 |     RecursingDropTarget dropTarget(script, type, window.contentItem()); | 
| 1226 |     dropTarget.setSize(QSizeF(100, 100)); | 
| 1227 |     QQmlComponent component(&engine); | 
| 1228 |     component.setData( | 
| 1229 |             "import QtQuick 2.0\n"  | 
| 1230 |             "Item {\n"  | 
| 1231 |                 "x: 50; y: 50\n"  | 
| 1232 |                 "width: 10; height: 10\n"  | 
| 1233 |             "}" , baseUrl: QUrl()); | 
| 1234 |     QScopedPointer<QObject> object(component.create()); | 
| 1235 |     QQuickItem *item = qobject_cast<QQuickItem *>(object: object.data()); | 
| 1236 |     QVERIFY(item); | 
| 1237 |     item->setParentItem(window.contentItem()); | 
| 1238 |  | 
| 1239 |     dropTarget.setItem(item); | 
| 1240 |  | 
| 1241 |     evaluate<void>(scope: item, expression: "Drag.start()" ); | 
| 1242 |     QCOMPARE(dropTarget.enterEvents, 1); | 
| 1243 |     QCOMPARE(dropTarget.moveEvents, 0); | 
| 1244 |     QCOMPARE(dropTarget.dropEvents, 0); | 
| 1245 |     QCOMPARE(dropTarget.leaveEvents, 0); | 
| 1246 |  | 
| 1247 |     evaluate<void>(scope: item, expression: "y = 15" ); | 
| 1248 |  | 
| 1249 |     // the evaluate statement above, y = 15, will cause | 
| 1250 |     // QQuickItem::setY(15) to be called, leading to an | 
| 1251 |     // event being posted that will be delivered | 
| 1252 |     // to RecursingDropTarget::dragMoveEvent(), hence | 
| 1253 |     // the following call to QCoreApplication::processEvents() | 
| 1254 |     QCoreApplication::processEvents(); | 
| 1255 |  | 
| 1256 |  | 
| 1257 |     // Regarding 'move in Move' when | 
| 1258 |     // RecursingDropTarget::dragMoveEvent() runs, | 
| 1259 |     // its call 'evaluate' triggers a second | 
| 1260 |     // move event (x = 23) that needs to be delivered. | 
| 1261 |     QCoreApplication::processEvents(); | 
| 1262 |  | 
| 1263 |     QCOMPARE(dropTarget.enterEvents, 1); | 
| 1264 |     QCOMPARE(dropTarget.moveEvents, moveEvents); | 
| 1265 |     QCOMPARE(dropTarget.dropEvents, 0); | 
| 1266 |     QCOMPARE(dropTarget.leaveEvents, 0); | 
| 1267 |  | 
| 1268 |     if (type == QEvent::Drop) { | 
| 1269 |         QCOMPARE(evaluate<bool>(item, "Drag.drop() == Qt.MoveAction" ), true); | 
| 1270 |         QCOMPARE(dropTarget.enterEvents, 1); | 
| 1271 |         QCOMPARE(dropTarget.moveEvents, moveEvents); | 
| 1272 |         QCOMPARE(dropTarget.dropEvents, 1); | 
| 1273 |         QCOMPARE(dropTarget.leaveEvents, 0); | 
| 1274 |     } else { | 
| 1275 |         evaluate<void>(scope: item, expression: "Drag.cancel()" ); | 
| 1276 |         QCOMPARE(dropTarget.enterEvents, 1); | 
| 1277 |         QCOMPARE(dropTarget.moveEvents, moveEvents); | 
| 1278 |         QCOMPARE(dropTarget.dropEvents, 0); | 
| 1279 |         QCOMPARE(dropTarget.leaveEvents, 1); | 
| 1280 |     } | 
| 1281 | } | 
| 1282 |  | 
| 1283 | void tst_QQuickDrag::noCrashWithImageProvider() | 
| 1284 | { | 
| 1285 |     // QTBUG-72045 | 
| 1286 |     QQmlComponent component(&engine); | 
| 1287 |     component.setData( | 
| 1288 |     R"(  | 
| 1289 |     import QtQuick 2.9  | 
| 1290 |     Item {  | 
| 1291 |         Rectangle {  | 
| 1292 |             id: item  | 
| 1293 |             width: 50  | 
| 1294 |             height: 50  | 
| 1295 |             anchors.centerIn: parent  | 
| 1296 |             color: "orange"  | 
| 1297 |             Component.onCompleted: {  | 
| 1298 |                 item.Drag.imageSource = "image://kill/me"  | 
| 1299 |             }  | 
| 1300 |         }  | 
| 1301 |     })" , baseUrl: QUrl()); | 
| 1302 |     QScopedPointer<QObject> object(component.create()); | 
| 1303 |     QQuickItem *item = qobject_cast<QQuickItem *>(object: object.data()); | 
| 1304 |     QVERIFY(item); | 
| 1305 | } | 
| 1306 |  | 
| 1307 |  | 
| 1308 | QTEST_MAIN(tst_QQuickDrag) | 
| 1309 |  | 
| 1310 | #include "tst_qquickdrag.moc" | 
| 1311 |  |