1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "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>
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)
70 void itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &);
71 void start() { start(supportedActions); }
72 void start(Qt::DropActions supportedActions);
73 void setTarget(QQuickItem *item);
75 QQuickDragGrabber dragGrabber;
77 QDeclarativeGuard<QObject> source;
78 QDeclarativeGuard<QObject> target;
79 QQuickItem *attachedItem;
80 QQuickDragMimeData *mimeData;
81 Qt::DropAction proposedAction;
82 Qt::DropActions supportedActions;
90 \qmlclass Drag QQuickDrag
91 \inqmlmodule QtQuick 2
92 \brief The Drag attached property provides drag and drop events for moved Items.
94 Using the Drag attached property any Item can made a source of drag and drop
95 events within a scene.
97 When a drag is \l active on an item any change in that items position will
98 generate a drag events that will be sent to any DropArea that intersects
99 the with new position of the item. Other items which implement drag and
100 drop event handlers can also receive these events.
102 The following snippet shows how an item can be dragged with a MouseArea.
103 However, dragging is not limited to mouse drags, anything that can move an item
104 can generate drag events, this can include touch events, animations and bindings.
106 \snippet doc/src/snippets/declarative/drag.qml 0
108 A drag can be terminated either by canceling it with Drag.cancel() or setting
109 Drag.active to false, or it can be terminated with a drop event by calling
110 Drag.drop(). If the drop event is accepted Drag.drop() will return the
111 \l {supportedActions}{drop action} chosen by the recipient of the event,
112 otherwise it will return Qt.IgnoreAction.
116 void QQuickDragAttachedPrivate::itemGeometryChanged(QQuickItem *, const QRectF &newGeometry, const QRectF &oldGeometry)
118 Q_Q(QQuickDragAttached);
119 if (newGeometry.topLeft() == oldGeometry.topLeft() || !active)
122 if (QQuickCanvas *canvas = attachedItem->canvas()) {
123 QPoint scenePos = attachedItem->mapToScene(hotSpot).toPoint();
124 QDragMoveEvent event(scenePos, mimeData->m_supportedActions, mimeData, Qt::NoButton, Qt::NoModifier);
125 QQuickDropEventEx::setProposedAction(&event, proposedAction);
126 QQuickCanvasPrivate::get(canvas)->deliverDragEvent(&dragGrabber, &event);
127 if (target != dragGrabber.target()) {
128 target = dragGrabber.target();
129 emit q->targetChanged();
134 QQuickDragAttached::QQuickDragAttached(QObject *parent)
135 : QObject(*new QQuickDragAttachedPrivate, parent)
137 Q_D(QQuickDragAttached);
138 d->attachedItem = qobject_cast<QQuickItem *>(parent);
139 d->source = d->attachedItem;
142 QQuickDragAttached::~QQuickDragAttached()
144 Q_D(QQuickDragAttached);
149 \qmlattachedproperty bool QtQuick2::Drag::active
151 This property holds whether a drag event sequence is currently active.
153 Setting this property to true will send a QDragEnter event to the scene
154 with the item's current position. Setting it to false will send a
157 While a drag is active any change in an item's position will send a QDragMove
158 event with item's new position to the scene.
161 bool QQuickDragAttached::isActive() const
163 Q_D(const QQuickDragAttached);
167 void QQuickDragAttached::setActive(bool active)
169 Q_D(QQuickDragAttached);
170 if (d->active != active) {
172 d->start(d->supportedActions);
179 \qmlattachedproperty Object QtQuick2::Drag::source
181 This property holds an object that is identified to recipients of drag events as
182 the source of the events. By default this is the item Drag property is attached to.
184 Changes to source while a Drag is active don't take effect until a new drag is started.
187 QObject *QQuickDragAttached::source() const
189 Q_D(const QQuickDragAttached);
193 void QQuickDragAttached::setSource(QObject *item)
195 Q_D(QQuickDragAttached);
196 if (d->source != item) {
198 emit sourceChanged();
202 void QQuickDragAttached::resetSource()
204 Q_D(QQuickDragAttached);
205 if (d->source != d->attachedItem) {
206 d->source = d->attachedItem;
207 emit sourceChanged();
212 \qmlattachedproperty Object QtQuick2::Drag::target
214 While a drag is active this property holds the last object to accept an
215 enter event from the dragged item, if the current drag position doesn't
216 intersect any accepting targets it is null.
218 When a drag is not active this property holds the object that accepted
219 the drop event that ended the drag, if no object accepted the drop or
220 the drag was canceled the target will then be null.
223 QObject *QQuickDragAttached::target() const
225 Q_D(const QQuickDragAttached);
230 \qmlattachedproperty QPointF QtQuick2::Drag::hotSpot
232 This property holds the drag position relative to the top left of the item.
234 By default this is (0, 0).
236 Changes to hotSpot will take effect when the next event is sent.
239 QPointF QQuickDragAttached::hotSpot() const
241 Q_D(const QQuickDragAttached);
245 void QQuickDragAttached::setHotSpot(const QPointF &hotSpot)
247 Q_D(QQuickDragAttached);
248 if (d->hotSpot != hotSpot) {
249 d->hotSpot = hotSpot;
250 emit hotSpotChanged();
251 // Send a move event if active?
256 \qmlattachedproperty stringlist QtQuick2::Drag::keys
258 This property holds a list of keys that can be used by a DropArea to filter drag events.
260 Changes to keys while a Drag is active don't take effect until a new drag is started.
263 QStringList QQuickDragAttached::keys() const
265 Q_D(const QQuickDragAttached);
269 void QQuickDragAttached::setKeys(const QStringList &keys)
271 Q_D(QQuickDragAttached);
272 if (d->keys != keys) {
279 \qmlattachedproperty flags QtQuick2::Drag::supportedActions
281 This property holds return values of Drag.drop() supported by the drag source.
283 Changes to supportedActions while a Drag is active don't take effect
284 until a new drag is started.
287 Qt::DropActions QQuickDragAttached::supportedActions() const
289 Q_D(const QQuickDragAttached);
290 return d->supportedActions;
293 void QQuickDragAttached::setSupportedActions(Qt::DropActions actions)
295 Q_D(QQuickDragAttached);
296 if (d->supportedActions != actions) {
297 d->supportedActions = actions;
298 emit supportedActionsChanged();
303 \qmlattachedproperty enumeration QtQuick2::Drag::proposedAction
305 This property holds an action that is recommended by the drag source as a
306 return value from Drag.drop().
308 Changes to proposedAction will take effect when the next event is sent.
311 Qt::DropAction QQuickDragAttached::proposedAction() const
313 Q_D(const QQuickDragAttached);
314 return d->proposedAction;
317 void QQuickDragAttached::setProposedAction(Qt::DropAction action)
319 Q_D(QQuickDragAttached);
320 if (d->proposedAction != action) {
321 d->proposedAction = action;
322 emit proposedActionChanged();
323 // send a move event with the new default action if active?
327 void QQuickDragAttachedPrivate::start(Qt::DropActions supportedActions)
329 Q_Q(QQuickDragAttached);
332 if (QQuickCanvas *canvas = attachedItem ? attachedItem->canvas() : 0) {
334 mimeData = new QQuickDragMimeData;
336 QQuickItemPrivate::get(attachedItem)->addItemChangeListener(this, QQuickItemPrivate::Geometry);
340 mimeData->m_source = source;
341 mimeData->m_supportedActions = supportedActions;
342 mimeData->m_keys = keys;
345 QPoint scenePos = attachedItem->mapToScene(hotSpot).toPoint();
346 QDragEnterEvent event(scenePos, supportedActions, mimeData, Qt::NoButton, Qt::NoModifier);
347 QQuickDropEventEx::setProposedAction(&event, proposedAction);
348 QQuickCanvasPrivate::get(canvas)->deliverDragEvent(&dragGrabber, &event);
350 emit q->activeChanged();
351 if (target != dragGrabber.target()) {
352 target = dragGrabber.target();
353 emit q->targetChanged();
359 \qmlattachedmethod void QtQuick2::Drag::start(flags supportedActions)
361 Starts sending drag events.
363 The optional \a supportedActions argument can be used to override the \l supportedActions
364 property for the started sequence.
367 void QQuickDragAttached::start(QDeclarativeV8Function *args)
369 Q_D(QQuickDragAttached);
373 Qt::DropActions supportedActions = d->supportedActions;
374 // check arguments for supportedActions, maybe data?
375 if (args->Length() >= 1) {
376 v8::Local<v8::Value> v = (*args)[0];
378 supportedActions = Qt::DropActions(v->Int32Value());
381 d->start(supportedActions);
385 \qmlattachedmethod enum QtQuick2::Drag::drop()
387 Ends a drag sequence by sending a drop event to the target item.
389 Returns the action accepted by the target item. If the target item or a parent doesn't accept
390 the drop event then Qt.IgnoreAction will be returned.
392 The returned drop action may be one of:
395 \o Qt.CopyAction Copy the data to the target
396 \o Qt.MoveAction Move the data from the source to the target
397 \o Qt.LinkAction Create a link from the source to the target.
398 \o Qt.IgnoreAction Ignore the action (do nothing with the data).
403 int QQuickDragAttached::drop()
405 Q_D(QQuickDragAttached);
406 Qt::DropAction acceptedAction = Qt::IgnoreAction;
409 return acceptedAction;
413 if (QQuickCanvas *canvas = d->attachedItem->canvas()) {
414 QPoint scenePos = d->attachedItem->mapToScene(d->hotSpot).toPoint();
417 scenePos, d->mimeData->m_supportedActions, d->mimeData, Qt::NoButton, Qt::NoModifier);
418 QQuickDropEventEx::setProposedAction(&event, d->proposedAction);
419 QQuickCanvasPrivate::get(canvas)->deliverDragEvent(&d->dragGrabber, &event);
421 if (event.isAccepted()) {
422 acceptedAction = event.dropAction();
423 target = d->dragGrabber.target();
428 if (d->target != target) {
430 emit targetChanged();
433 emit activeChanged();
434 return acceptedAction;
438 \qmlattachedmethod void QtQuick2::Drag::cancel()
440 Ends a drag sequence.
443 void QQuickDragAttached::cancel()
445 Q_D(QQuickDragAttached);
449 if (QQuickCanvas *canvas = d->attachedItem->canvas()) {
450 QDragLeaveEvent event;
451 QQuickCanvasPrivate::get(canvas)->deliverDragEvent(&d->dragGrabber, &event);
457 emit targetChanged();
459 emit activeChanged();