1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquickdrag_p.h"
44 #include <private/qquickitem_p.h>
45 #include <QtQuick/private/qquickevents_p_p.h>
46 #include <private/qquickitemchangelistener_p.h>
47 #include <private/qv8engine_p.h>
48 #include <QtQml/qqmlinfo.h>
49 #include <QtGui/qevent.h>
53 class QQuickDragAttachedPrivate : public QObjectPrivate, public QQuickItemChangeListener
55 Q_DECLARE_PUBLIC(QQuickDragAttached)
57 static QQuickDragAttachedPrivate *get(QQuickDragAttached *attached) {
58 return static_cast<QQuickDragAttachedPrivate *>(QObjectPrivate::get(attached)); }
60 QQuickDragAttachedPrivate()
63 , proposedAction(Qt::MoveAction)
64 , supportedActions(Qt::MoveAction | Qt::CopyAction | Qt::LinkAction)
71 void itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &);
72 void deliverEvent(QQuickCanvas *canvas, QEvent *event);
73 void start() { start(supportedActions); }
74 void start(Qt::DropActions supportedActions);
75 void setTarget(QQuickItem *item);
77 QQuickDragGrabber dragGrabber;
79 QQmlGuard<QObject> source;
80 QQmlGuard<QObject> target;
81 QQuickItem *attachedItem;
82 QQuickDragMimeData *mimeData;
83 Qt::DropAction proposedAction;
84 Qt::DropActions supportedActions;
93 \qmlclass Drag QQuickDrag
94 \inqmlmodule QtQuick 2
95 \brief The Drag attached property provides drag and drop events for moved Items.
97 Using the Drag attached property any Item can made a source of drag and drop
98 events within a scene.
100 When a drag is \l active on an item any change in that items position will
101 generate a drag events that will be sent to any DropArea that intersects
102 the with new position of the item. Other items which implement drag and
103 drop event handlers can also receive these events.
105 The following snippet shows how an item can be dragged with a MouseArea.
106 However, dragging is not limited to mouse drags, anything that can move an item
107 can generate drag events, this can include touch events, animations and bindings.
109 \snippet doc/src/snippets/qml/drag.qml 0
111 A drag can be terminated either by canceling it with Drag.cancel() or setting
112 Drag.active to false, or it can be terminated with a drop event by calling
113 Drag.drop(). If the drop event is accepted Drag.drop() will return the
114 \l {supportedActions}{drop action} chosen by the recipient of the event,
115 otherwise it will return Qt.IgnoreAction.
119 void QQuickDragAttachedPrivate::itemGeometryChanged(QQuickItem *, const QRectF &newGeometry, const QRectF &oldGeometry)
121 Q_Q(QQuickDragAttached);
122 if (newGeometry.topLeft() == oldGeometry.topLeft() || !active || inEvent)
125 if (QQuickCanvas *canvas = attachedItem->canvas()) {
126 QPoint scenePos = attachedItem->mapToScene(hotSpot).toPoint();
127 QDragMoveEvent event(scenePos, mimeData->m_supportedActions, mimeData, Qt::NoButton, Qt::NoModifier);
128 QQuickDropEventEx::setProposedAction(&event, proposedAction);
129 deliverEvent(canvas, &event);
130 if (target != dragGrabber.target()) {
131 target = dragGrabber.target();
132 emit q->targetChanged();
137 void QQuickDragAttachedPrivate::deliverEvent(QQuickCanvas *canvas, QEvent *event)
141 QQuickCanvasPrivate::get(canvas)->deliverDragEvent(&dragGrabber, event);
145 QQuickDragAttached::QQuickDragAttached(QObject *parent)
146 : QObject(*new QQuickDragAttachedPrivate, parent)
148 Q_D(QQuickDragAttached);
149 d->attachedItem = qobject_cast<QQuickItem *>(parent);
150 d->source = d->attachedItem;
153 QQuickDragAttached::~QQuickDragAttached()
155 Q_D(QQuickDragAttached);
160 \qmlattachedproperty bool QtQuick2::Drag::active
162 This property holds whether a drag event sequence is currently active.
164 Setting this property to true will send a QDragEnter event to the scene
165 with the item's current position. Setting it to false will send a
168 While a drag is active any change in an item's position will send a QDragMove
169 event with item's new position to the scene.
172 bool QQuickDragAttached::isActive() const
174 Q_D(const QQuickDragAttached);
178 void QQuickDragAttached::setActive(bool active)
180 Q_D(QQuickDragAttached);
181 if (d->active != active) {
183 qmlInfo(this) << "active cannot be changed from within a drag event handler";
185 d->start(d->supportedActions);
192 \qmlattachedproperty Object QtQuick2::Drag::source
194 This property holds an object that is identified to recipients of drag events as
195 the source of the events. By default this is the item Drag property is attached to.
197 Changes to source while a Drag is active don't take effect until a new drag is started.
200 QObject *QQuickDragAttached::source() const
202 Q_D(const QQuickDragAttached);
206 void QQuickDragAttached::setSource(QObject *item)
208 Q_D(QQuickDragAttached);
209 if (d->source != item) {
211 emit sourceChanged();
215 void QQuickDragAttached::resetSource()
217 Q_D(QQuickDragAttached);
218 if (d->source != d->attachedItem) {
219 d->source = d->attachedItem;
220 emit sourceChanged();
225 \qmlattachedproperty Object QtQuick2::Drag::target
227 While a drag is active this property holds the last object to accept an
228 enter event from the dragged item, if the current drag position doesn't
229 intersect any accepting targets it is null.
231 When a drag is not active this property holds the object that accepted
232 the drop event that ended the drag, if no object accepted the drop or
233 the drag was canceled the target will then be null.
236 QObject *QQuickDragAttached::target() const
238 Q_D(const QQuickDragAttached);
243 \qmlattachedproperty QPointF QtQuick2::Drag::hotSpot
245 This property holds the drag position relative to the top left of the item.
247 By default this is (0, 0).
249 Changes to hotSpot will take effect when the next event is sent.
252 QPointF QQuickDragAttached::hotSpot() const
254 Q_D(const QQuickDragAttached);
258 void QQuickDragAttached::setHotSpot(const QPointF &hotSpot)
260 Q_D(QQuickDragAttached);
261 if (d->hotSpot != hotSpot) {
262 d->hotSpot = hotSpot;
263 emit hotSpotChanged();
264 // Send a move event if active?
269 \qmlattachedproperty stringlist QtQuick2::Drag::keys
271 This property holds a list of keys that can be used by a DropArea to filter drag events.
273 Changes to keys while a Drag is active don't take effect until a new drag is started.
276 QStringList QQuickDragAttached::keys() const
278 Q_D(const QQuickDragAttached);
282 void QQuickDragAttached::setKeys(const QStringList &keys)
284 Q_D(QQuickDragAttached);
285 if (d->keys != keys) {
292 \qmlattachedproperty flags QtQuick2::Drag::supportedActions
294 This property holds return values of Drag.drop() supported by the drag source.
296 Changes to supportedActions while a Drag is active don't take effect
297 until a new drag is started.
300 Qt::DropActions QQuickDragAttached::supportedActions() const
302 Q_D(const QQuickDragAttached);
303 return d->supportedActions;
306 void QQuickDragAttached::setSupportedActions(Qt::DropActions actions)
308 Q_D(QQuickDragAttached);
309 if (d->supportedActions != actions) {
310 d->supportedActions = actions;
311 emit supportedActionsChanged();
316 \qmlattachedproperty enumeration QtQuick2::Drag::proposedAction
318 This property holds an action that is recommended by the drag source as a
319 return value from Drag.drop().
321 Changes to proposedAction will take effect when the next event is sent.
324 Qt::DropAction QQuickDragAttached::proposedAction() const
326 Q_D(const QQuickDragAttached);
327 return d->proposedAction;
330 void QQuickDragAttached::setProposedAction(Qt::DropAction action)
332 Q_D(QQuickDragAttached);
333 if (d->proposedAction != action) {
334 d->proposedAction = action;
335 emit proposedActionChanged();
336 // send a move event with the new default action if active?
340 void QQuickDragAttachedPrivate::start(Qt::DropActions supportedActions)
342 Q_Q(QQuickDragAttached);
345 if (QQuickCanvas *canvas = attachedItem ? attachedItem->canvas() : 0) {
347 mimeData = new QQuickDragMimeData;
349 QQuickItemPrivate::get(attachedItem)->addItemChangeListener(this, QQuickItemPrivate::Geometry);
353 mimeData->m_source = source;
354 mimeData->m_supportedActions = supportedActions;
355 mimeData->m_keys = keys;
358 QPoint scenePos = attachedItem->mapToScene(hotSpot).toPoint();
359 QDragEnterEvent event(scenePos, supportedActions, mimeData, Qt::NoButton, Qt::NoModifier);
360 QQuickDropEventEx::setProposedAction(&event, proposedAction);
361 deliverEvent(canvas, &event);
363 emit q->activeChanged();
364 if (target != dragGrabber.target()) {
365 target = dragGrabber.target();
366 emit q->targetChanged();
372 \qmlattachedmethod void QtQuick2::Drag::start(flags supportedActions)
374 Starts sending drag events.
376 The optional \a supportedActions argument can be used to override the \l supportedActions
377 property for the started sequence.
380 void QQuickDragAttached::start(QQmlV8Function *args)
382 Q_D(QQuickDragAttached);
384 qmlInfo(this) << "start() cannot be called from within a drag event handler";
391 Qt::DropActions supportedActions = d->supportedActions;
392 // check arguments for supportedActions, maybe data?
393 if (args->Length() >= 1) {
394 v8::Local<v8::Value> v = (*args)[0];
396 supportedActions = Qt::DropActions(v->Int32Value());
399 d->start(supportedActions);
403 \qmlattachedmethod enum QtQuick2::Drag::drop()
405 Ends a drag sequence by sending a drop event to the target item.
407 Returns the action accepted by the target item. If the target item or a parent doesn't accept
408 the drop event then Qt.IgnoreAction will be returned.
410 The returned drop action may be one of:
413 \o Qt.CopyAction Copy the data to the target
414 \o Qt.MoveAction Move the data from the source to the target
415 \o Qt.LinkAction Create a link from the source to the target.
416 \o Qt.IgnoreAction Ignore the action (do nothing with the data).
421 int QQuickDragAttached::drop()
423 Q_D(QQuickDragAttached);
424 Qt::DropAction acceptedAction = Qt::IgnoreAction;
427 qmlInfo(this) << "drop() cannot be called from within a drag event handler";
428 return acceptedAction;
432 return acceptedAction;
437 if (QQuickCanvas *canvas = d->attachedItem->canvas()) {
438 QPoint scenePos = d->attachedItem->mapToScene(d->hotSpot).toPoint();
441 scenePos, d->mimeData->m_supportedActions, d->mimeData, Qt::NoButton, Qt::NoModifier);
442 QQuickDropEventEx::setProposedAction(&event, d->proposedAction);
443 d->deliverEvent(canvas, &event);
445 if (event.isAccepted()) {
446 acceptedAction = event.dropAction();
447 target = d->dragGrabber.target();
451 if (d->target != target) {
453 emit targetChanged();
456 emit activeChanged();
457 return acceptedAction;
461 \qmlattachedmethod void QtQuick2::Drag::cancel()
463 Ends a drag sequence.
466 void QQuickDragAttached::cancel()
468 Q_D(QQuickDragAttached);
471 qmlInfo(this) << "cancel() cannot be called from within a drag event handler";
479 if (QQuickCanvas *canvas = d->attachedItem->canvas()) {
480 QDragLeaveEvent event;
481 d->deliverEvent(canvas, &event);
486 emit targetChanged();
488 emit activeChanged();