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 QtQuick module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
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 Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qquickdrag_p.h"
41
42#include <private/qguiapplication_p.h>
43#include <qpa/qplatformintegration.h>
44#include <private/qquickitem_p.h>
45#include <QtQuick/private/qquickevents_p_p.h>
46#include <private/qquickitemchangelistener_p.h>
47#include <private/qquickpixmapcache_p.h>
48#include <private/qv8engine_p.h>
49#include <private/qv4scopedvalue_p.h>
50#include <QtCore/qmimedata.h>
51#include <QtQml/qqmlinfo.h>
52#include <QtGui/qevent.h>
53#include <QtGui/qstylehints.h>
54#include <QtGui/qguiapplication.h>
55
56#if QT_CONFIG(draganddrop)
57#include <qpa/qplatformdrag.h>
58#include <QtGui/qdrag.h>
59
60QT_BEGIN_NAMESPACE
61
62class QQuickDragAttachedPrivate : public QObjectPrivate, public QQuickItemChangeListener
63{
64 Q_DECLARE_PUBLIC(QQuickDragAttached)
65public:
66 static QQuickDragAttachedPrivate *get(QQuickDragAttached *attached) {
67 return static_cast<QQuickDragAttachedPrivate *>(QObjectPrivate::get(attached)); }
68
69 QQuickDragAttachedPrivate()
70 : attachedItem(nullptr)
71 , mimeData(nullptr)
72 , proposedAction(Qt::MoveAction)
73 , supportedActions(Qt::MoveAction | Qt::CopyAction | Qt::LinkAction)
74 , active(false)
75 , listening(false)
76 , inEvent(false)
77 , dragRestarted(false)
78 , itemMoved(false)
79 , eventQueued(false)
80 , overrideActions(false)
81 , dragType(QQuickDrag::Internal)
82 {
83 }
84
85 void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) override;
86 void itemParentChanged(QQuickItem *, QQuickItem *parent) override;
87 void updatePosition();
88 void restartDrag();
89 void deliverEnterEvent();
90 void deliverMoveEvent();
91 void deliverLeaveEvent();
92 void deliverEvent(QQuickWindow *window, QEvent *event);
93 void start(Qt::DropActions supportedActions);
94 Qt::DropAction startDrag(Qt::DropActions supportedActions);
95 void setTarget(QQuickItem *item);
96
97 QQuickDragGrabber dragGrabber;
98
99 QPointer<QObject> source;
100 QPointer<QObject> target;
101 QPointer<QQuickWindow> window;
102 QQuickItem *attachedItem;
103 QQuickDragMimeData *mimeData;
104 Qt::DropAction proposedAction;
105 Qt::DropActions supportedActions;
106 bool active : 1;
107 bool listening : 1;
108 bool inEvent : 1;
109 bool dragRestarted : 1;
110 bool itemMoved : 1;
111 bool eventQueued : 1;
112 bool overrideActions : 1;
113 QPointF hotSpot;
114 QUrl imageSource;
115 QQuickPixmap pixmapLoader;
116 QStringList keys;
117 QVariantMap externalMimeData;
118 QQuickDrag::DragType dragType;
119};
120
121/*!
122 \qmltype Drag
123 \instantiates QQuickDrag
124 \inqmlmodule QtQuick
125 \ingroup qtquick-input
126 \brief For specifying drag and drop events for moved Items.
127
128 Using the Drag attached property, any Item can be made a source of drag and drop
129 events within a scene.
130
131 When a drag is \l active on an item, any change in that item's position will
132 generate a drag event that will be sent to any DropArea that intersects
133 with the new position of the item. Other items which implement drag and
134 drop event handlers can also receive these events.
135
136 The following snippet shows how an item can be dragged with a MouseArea.
137 However, dragging is not limited to mouse drags; anything that can move an item
138 can generate drag events, including touch events, animations and bindings.
139
140 \snippet qml/drag.qml 0
141
142 A drag can be terminated either by canceling it with Drag.cancel() or setting
143 Drag.active to false, or it can be terminated with a drop event by calling
144 Drag.drop(). If the drop event is accepted, Drag.drop() will return the
145 \l {supportedActions}{drop action} chosen by the recipient of the event,
146 otherwise it will return Qt.IgnoreAction.
147
148 \sa {Qt Quick Examples - Drag and Drop}, {Qt Quick Examples - externaldraganddrop}
149*/
150
151void QQuickDragAttachedPrivate::itemGeometryChanged(QQuickItem *, QQuickGeometryChange change,
152 const QRectF &)
153{
154 if (!change.positionChange() || !active || itemMoved)
155 return;
156 updatePosition();
157}
158
159void QQuickDragAttachedPrivate::itemParentChanged(QQuickItem *, QQuickItem *)
160{
161 if (!active || dragRestarted)
162 return;
163
164 QQuickWindow *newWindow = attachedItem->window();
165
166 if (window != newWindow)
167 restartDrag();
168 else if (window)
169 updatePosition();
170}
171
172void QQuickDragAttachedPrivate::updatePosition()
173{
174 Q_Q(QQuickDragAttached);
175 itemMoved = true;
176 if (!eventQueued) {
177 eventQueued = true;
178 QCoreApplication::postEvent(q, new QEvent(QEvent::User));
179 }
180}
181
182void QQuickDragAttachedPrivate::restartDrag()
183{
184 Q_Q(QQuickDragAttached);
185 dragRestarted = true;
186 if (!eventQueued) {
187 eventQueued = true;
188 QCoreApplication::postEvent(q, new QEvent(QEvent::User));
189 }
190}
191
192void QQuickDragAttachedPrivate::deliverEnterEvent()
193{
194 dragRestarted = false;
195 itemMoved = false;
196
197 window = attachedItem->window();
198
199 mimeData->m_source = source;
200 if (!overrideActions)
201 mimeData->m_supportedActions = supportedActions;
202 mimeData->m_keys = keys;
203
204 if (window) {
205 QPoint scenePos = attachedItem->mapToScene(hotSpot).toPoint();
206 QDragEnterEvent event(scenePos, mimeData->m_supportedActions, mimeData, Qt::NoButton, Qt::NoModifier);
207 QQuickDropEventEx::setProposedAction(&event, proposedAction);
208 deliverEvent(window, &event);
209 }
210}
211
212void QQuickDragAttachedPrivate::deliverMoveEvent()
213{
214 Q_Q(QQuickDragAttached);
215
216 itemMoved = false;
217 if (window) {
218 QPoint scenePos = attachedItem->mapToScene(hotSpot).toPoint();
219 QDragMoveEvent event(scenePos, mimeData->m_supportedActions, mimeData, Qt::NoButton, Qt::NoModifier);
220 QQuickDropEventEx::setProposedAction(&event, proposedAction);
221 deliverEvent(window, &event);
222 if (target != dragGrabber.target()) {
223 target = dragGrabber.target();
224 emit q->targetChanged();
225 }
226 }
227}
228
229void QQuickDragAttachedPrivate::deliverLeaveEvent()
230{
231 if (window) {
232 QDragLeaveEvent event;
233 deliverEvent(window, &event);
234 window = nullptr;
235 }
236}
237
238void QQuickDragAttachedPrivate::deliverEvent(QQuickWindow *window, QEvent *event)
239{
240 Q_ASSERT(!inEvent);
241 inEvent = true;
242 QQuickWindowPrivate::get(window)->deliverDragEvent(&dragGrabber, event);
243 inEvent = false;
244}
245
246bool QQuickDragAttached::event(QEvent *event)
247{
248 Q_D(QQuickDragAttached);
249
250 if (event->type() == QEvent::User) {
251 d->eventQueued = false;
252 if (d->dragRestarted) {
253 d->deliverLeaveEvent();
254 d->deliverEnterEvent();
255
256 if (d->target != d->dragGrabber.target()) {
257 d->target = d->dragGrabber.target();
258 emit targetChanged();
259 }
260 } else if (d->itemMoved) {
261 d->deliverMoveEvent();
262 }
263 return true;
264 } else {
265 return QObject::event(event);
266 }
267}
268
269QQuickDragAttached::QQuickDragAttached(QObject *parent)
270 : QObject(*new QQuickDragAttachedPrivate, parent)
271{
272 Q_D(QQuickDragAttached);
273 d->attachedItem = qobject_cast<QQuickItem *>(parent);
274 d->source = d->attachedItem;
275}
276
277QQuickDragAttached::~QQuickDragAttached()
278{
279 Q_D(QQuickDragAttached);
280 delete d->mimeData;
281}
282
283/*!
284 \qmlattachedproperty bool QtQuick::Drag::active
285
286 This property holds whether a drag event sequence is currently active.
287
288 Binding this property to the active property of \l MouseArea::drag will
289 cause \l startDrag to be called when the user starts dragging.
290
291 Setting this property to true will also send a QDragEnter event to the scene
292 with the item's current position. Setting it to false will send a
293 QDragLeave event.
294
295 While a drag is active any change in an item's position will send a QDragMove
296 event with item's new position to the scene.
297*/
298
299bool QQuickDragAttached::isActive() const
300{
301 Q_D(const QQuickDragAttached);
302 return d->active;
303}
304
305void QQuickDragAttached::setActive(bool active)
306{
307 Q_D(QQuickDragAttached);
308 if (d->active != active) {
309 if (d->inEvent)
310 qmlWarning(this) << "active cannot be changed from within a drag event handler";
311 else if (active) {
312 if (d->dragType == QQuickDrag::Internal) {
313 d->start(d->supportedActions);
314 } else {
315 d->active = true;
316 emit activeChanged();
317 if (d->dragType == QQuickDrag::Automatic) {
318 // There are different semantics than start() since startDrag()
319 // may be called after an internal drag is already started.
320 d->startDrag(d->supportedActions);
321 }
322 }
323 }
324 else
325 cancel();
326 }
327}
328
329/*!
330 \qmlattachedproperty Object QtQuick::Drag::source
331
332 This property holds an object that is identified to recipients of drag events as
333 the source of the events. By default this is the item that the Drag
334 property is attached to.
335
336 Changing the source while a drag is active will reset the sequence of drag events by
337 sending a drag leave event followed by a drag enter event with the new source.
338*/
339
340QObject *QQuickDragAttached::source() const
341{
342 Q_D(const QQuickDragAttached);
343 return d->source;
344}
345
346void QQuickDragAttached::setSource(QObject *item)
347{
348 Q_D(QQuickDragAttached);
349 if (d->source != item) {
350 d->source = item;
351 if (d->active)
352 d->restartDrag();
353 emit sourceChanged();
354 }
355}
356
357void QQuickDragAttached::resetSource()
358{
359 Q_D(QQuickDragAttached);
360 if (d->source != d->attachedItem) {
361 d->source = d->attachedItem;
362 if (d->active)
363 d->restartDrag();
364 emit sourceChanged();
365 }
366}
367
368/*!
369 \qmlattachedproperty Object QtQuick::Drag::target
370
371 While a drag is active this property holds the last object to accept an
372 enter event from the dragged item, if the current drag position doesn't
373 intersect any accepting targets it is null.
374
375 When a drag is not active this property holds the object that accepted
376 the drop event that ended the drag, if no object accepted the drop or
377 the drag was canceled the target will then be null.
378*/
379
380QObject *QQuickDragAttached::target() const
381{
382 Q_D(const QQuickDragAttached);
383 return d->target;
384}
385
386/*!
387 \qmlattachedproperty QPointF QtQuick::Drag::hotSpot
388
389 This property holds the drag position relative to the top left of the item.
390
391 By default this is (0, 0).
392
393 Changes to hotSpot trigger a new drag move with the updated position.
394*/
395
396QPointF QQuickDragAttached::hotSpot() const
397{
398 Q_D(const QQuickDragAttached);
399 return d->hotSpot;
400}
401
402void QQuickDragAttached::setHotSpot(const QPointF &hotSpot)
403{
404 Q_D(QQuickDragAttached);
405 if (d->hotSpot != hotSpot) {
406 d->hotSpot = hotSpot;
407
408 if (d->active)
409 d->updatePosition();
410
411 emit hotSpotChanged();
412 }
413}
414
415/*!
416 \qmlattachedproperty QUrl QtQuick::Drag::imageSource
417 \since 5.8
418
419 This property holds the URL of the image which will be used to represent
420 the data during the drag and drop operation. Changing this property after
421 the drag operation has started will have no effect.
422
423 The example below uses an item's contents as a drag image:
424
425 \snippet qml/externaldrag.qml 0
426
427 \sa Item::grabToImage()
428*/
429
430QUrl QQuickDragAttached::imageSource() const
431{
432 Q_D(const QQuickDragAttached);
433 return d->imageSource;
434}
435
436void QQuickDragAttached::setImageSource(const QUrl &url)
437{
438 Q_D(QQuickDragAttached);
439 if (d->imageSource != url) {
440 d->imageSource = url;
441
442 if (url.isEmpty()) {
443 d->pixmapLoader.clear();
444 } else {
445 d->pixmapLoader.load(qmlEngine(this), url);
446 }
447
448 Q_EMIT imageSourceChanged();
449 }
450}
451
452/*!
453 \qmlattachedproperty stringlist QtQuick::Drag::keys
454
455 This property holds a list of keys that can be used by a DropArea to filter drag events.
456
457 Changing the keys while a drag is active will reset the sequence of drag events by
458 sending a drag leave event followed by a drag enter event with the new source.
459*/
460
461QStringList QQuickDragAttached::keys() const
462{
463 Q_D(const QQuickDragAttached);
464 return d->keys;
465}
466
467void QQuickDragAttached::setKeys(const QStringList &keys)
468{
469 Q_D(QQuickDragAttached);
470 if (d->keys != keys) {
471 d->keys = keys;
472 if (d->active)
473 d->restartDrag();
474 emit keysChanged();
475 }
476}
477
478/*!
479 \qmlattachedproperty stringlist QtQuick::Drag::mimeData
480 \since 5.2
481
482 This property holds a map of mimeData that is used during startDrag.
483*/
484
485QVariantMap QQuickDragAttached::mimeData() const
486{
487 Q_D(const QQuickDragAttached);
488 return d->externalMimeData;
489}
490
491void QQuickDragAttached::setMimeData(const QVariantMap &mimeData)
492{
493 Q_D(QQuickDragAttached);
494 if (d->externalMimeData != mimeData) {
495 d->externalMimeData = mimeData;
496 emit mimeDataChanged();
497 }
498}
499
500/*!
501 \qmlattachedproperty flags QtQuick::Drag::supportedActions
502
503 This property holds return values of Drag.drop() supported by the drag source.
504
505 Changing the supportedActions while a drag is active will reset the sequence of drag
506 events by sending a drag leave event followed by a drag enter event with the new source.
507*/
508
509Qt::DropActions QQuickDragAttached::supportedActions() const
510{
511 Q_D(const QQuickDragAttached);
512 return d->supportedActions;
513}
514
515void QQuickDragAttached::setSupportedActions(Qt::DropActions actions)
516{
517 Q_D(QQuickDragAttached);
518 if (d->supportedActions != actions) {
519 d->supportedActions = actions;
520 if (d->active)
521 d->restartDrag();
522 emit supportedActionsChanged();
523 }
524}
525
526/*!
527 \qmlattachedproperty enumeration QtQuick::Drag::proposedAction
528
529 This property holds an action that is recommended by the drag source as a
530 return value from Drag.drop().
531
532 Changes to proposedAction will trigger a move event with the updated proposal.
533*/
534
535Qt::DropAction QQuickDragAttached::proposedAction() const
536{
537 Q_D(const QQuickDragAttached);
538 return d->proposedAction;
539}
540
541void QQuickDragAttached::setProposedAction(Qt::DropAction action)
542{
543 Q_D(QQuickDragAttached);
544 if (d->proposedAction != action) {
545 d->proposedAction = action;
546 // The proposed action shouldn't affect whether a drag is accepted
547 // so leave/enter events are excessive, but the target should still
548 // updated.
549 if (d->active)
550 d->updatePosition();
551 emit proposedActionChanged();
552 }
553}
554
555/*!
556 \qmlattachedproperty enumeration QtQuick::Drag::dragType
557 \since 5.2
558
559 This property indicates whether to automatically start drags, do nothing, or
560 to use backwards compatible internal drags. The default is to use backwards
561 compatible internal drags.
562
563 A drag can also be started manually using \l startDrag.
564
565 \list
566 \li Drag.None - do not start drags automatically
567 \li Drag.Automatic - start drags automatically
568 \li Drag.Internal (default) - start backwards compatible drags automatically
569 \endlist
570
571 When using \c Drag.Automatic you should also define \l mimeData and bind the
572 \l active property to the active property of MouseArea : \l {MouseArea::drag.active}
573*/
574
575QQuickDrag::DragType QQuickDragAttached::dragType() const
576{
577 Q_D(const QQuickDragAttached);
578 return d->dragType;
579}
580
581void QQuickDragAttached::setDragType(QQuickDrag::DragType dragType)
582{
583 Q_D(QQuickDragAttached);
584 if (d->dragType != dragType) {
585 d->dragType = dragType;
586 emit dragTypeChanged();
587 }
588}
589
590void QQuickDragAttachedPrivate::start(Qt::DropActions supportedActions)
591{
592 Q_Q(QQuickDragAttached);
593 Q_ASSERT(!active);
594
595 if (!mimeData)
596 mimeData = new QQuickDragMimeData;
597 if (!listening) {
598 QQuickItemPrivate::get(attachedItem)->addItemChangeListener(
599 this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Parent);
600 listening = true;
601 }
602
603 mimeData->m_supportedActions = supportedActions;
604 active = true;
605 itemMoved = false;
606 dragRestarted = false;
607
608 deliverEnterEvent();
609
610 if (target != dragGrabber.target()) {
611 target = dragGrabber.target();
612 emit q->targetChanged();
613 }
614
615 emit q->activeChanged();
616}
617
618/*!
619 \qmlattachedmethod void QtQuick::Drag::start(flags supportedActions)
620
621 Starts sending drag events. Used for starting old-style internal drags. \l startDrag is the
622 new-style, preferred method of starting drags.
623
624 The optional \a supportedActions argument can be used to override the \l supportedActions
625 property for the started sequence.
626*/
627
628void QQuickDragAttached::start(QQmlV4Function *args)
629{
630 Q_D(QQuickDragAttached);
631 if (d->inEvent) {
632 qmlWarning(this) << "start() cannot be called from within a drag event handler";
633 return;
634 }
635
636 if (d->active)
637 cancel();
638
639 d->overrideActions = false;
640 Qt::DropActions supportedActions = d->supportedActions;
641 // check arguments for supportedActions, maybe data?
642 if (args->length() >= 1) {
643 QV4::Scope scope(args->v4engine());
644 QV4::ScopedValue v(scope, (*args)[0]);
645 if (v->isInt32()) {
646 supportedActions = Qt::DropActions(v->integerValue());
647 d->overrideActions = true;
648 }
649 }
650
651 d->start(supportedActions);
652}
653
654/*!
655 \qmlattachedmethod enumeration QtQuick::Drag::drop()
656
657 Ends a drag sequence by sending a drop event to the target item.
658
659 Returns the action accepted by the target item. If the target item or a parent doesn't accept
660 the drop event then Qt.IgnoreAction will be returned.
661
662 The returned drop action may be one of:
663
664 \list
665 \li Qt.CopyAction Copy the data to the target
666 \li Qt.MoveAction Move the data from the source to the target
667 \li Qt.LinkAction Create a link from the source to the target.
668 \li Qt.IgnoreAction Ignore the action (do nothing with the data).
669 \endlist
670*/
671
672int QQuickDragAttached::drop()
673{
674 Q_D(QQuickDragAttached);
675 Qt::DropAction acceptedAction = Qt::IgnoreAction;
676
677 if (d->inEvent) {
678 qmlWarning(this) << "drop() cannot be called from within a drag event handler";
679 return acceptedAction;
680 }
681
682 if (d->itemMoved)
683 d->deliverMoveEvent();
684
685 if (!d->active)
686 return acceptedAction;
687 d->active = false;
688
689 QObject *target = nullptr;
690
691 if (d->window) {
692 QPoint scenePos = d->attachedItem->mapToScene(d->hotSpot).toPoint();
693
694 QDropEvent event(
695 scenePos, d->mimeData->m_supportedActions, d->mimeData, Qt::NoButton, Qt::NoModifier);
696 QQuickDropEventEx::setProposedAction(&event, d->proposedAction);
697 d->deliverEvent(d->window, &event);
698
699 if (event.isAccepted()) {
700 acceptedAction = event.dropAction();
701 target = d->dragGrabber.target();
702 }
703 }
704
705 if (d->target != target) {
706 d->target = target;
707 emit targetChanged();
708 }
709
710 emit activeChanged();
711 return acceptedAction;
712}
713
714/*!
715 \qmlattachedmethod void QtQuick::Drag::cancel()
716
717 Ends a drag sequence.
718*/
719
720void QQuickDragAttached::cancel()
721{
722 Q_D(QQuickDragAttached);
723
724 if (d->inEvent) {
725 qmlWarning(this) << "cancel() cannot be called from within a drag event handler";
726 return;
727 }
728
729 if (!d->active)
730 return;
731 d->active = false;
732 d->deliverLeaveEvent();
733
734 if (d->target) {
735 d->target = nullptr;
736 emit targetChanged();
737 }
738
739 emit activeChanged();
740}
741
742/*!
743 \qmlattachedsignal QtQuick::Drag::dragStarted()
744
745 This signal is emitted when a drag is started with the \l startDrag() method
746 or when it is started automatically using the \l dragType property.
747
748 The corresponding handler is \c onDragStarted.
749 */
750
751/*!
752 \qmlattachedsignal QtQuick::Drag::dragFinished(DropAction dropAction)
753
754 This signal is emitted when a drag finishes and the drag was started with the
755 \l startDrag() method or started automatically using the \l dragType property.
756
757 The corresponding handler is \c onDragFinished.
758 */
759
760Qt::DropAction QQuickDragAttachedPrivate::startDrag(Qt::DropActions supportedActions)
761{
762 Q_Q(QQuickDragAttached);
763
764 QDrag *drag = new QDrag(source ? source : q);
765 QMimeData *mimeData = new QMimeData();
766
767 for (auto it = externalMimeData.cbegin(), end = externalMimeData.cend(); it != end; ++it)
768 mimeData->setData(it.key(), it.value().toString().toUtf8());
769
770 drag->setMimeData(mimeData);
771 if (pixmapLoader.isReady()) {
772 drag->setPixmap(QPixmap::fromImage(pixmapLoader.image()));
773 }
774
775 drag->setHotSpot(hotSpot.toPoint());
776 emit q->dragStarted();
777
778 Qt::DropAction dropAction = drag->exec(supportedActions);
779
780 if (!QGuiApplicationPrivate::platformIntegration()->drag()->ownsDragObject())
781 drag->deleteLater();
782
783 deliverLeaveEvent();
784
785 if (target) {
786 target = nullptr;
787 emit q->targetChanged();
788 }
789
790 emit q->dragFinished(dropAction);
791
792 active = false;
793 emit q->activeChanged();
794
795 return dropAction;
796}
797
798
799/*!
800 \qmlattachedmethod void QtQuick::Drag::startDrag(flags supportedActions)
801
802 Starts sending drag events.
803
804 The optional \a supportedActions argument can be used to override the \l supportedActions
805 property for the started sequence.
806*/
807
808void QQuickDragAttached::startDrag(QQmlV4Function *args)
809{
810 Q_D(QQuickDragAttached);
811
812 if (d->inEvent) {
813 qmlWarning(this) << "startDrag() cannot be called from within a drag event handler";
814 return;
815 }
816
817 if (!d->active) {
818 qmlWarning(this) << "startDrag() drag must be active";
819 return;
820 }
821
822 Qt::DropActions supportedActions = d->supportedActions;
823
824 // check arguments for supportedActions
825 if (args->length() >= 1) {
826 QV4::Scope scope(args->v4engine());
827 QV4::ScopedValue v(scope, (*args)[0]);
828 if (v->isInt32()) {
829 supportedActions = Qt::DropActions(v->integerValue());
830 }
831 }
832
833 Qt::DropAction dropAction = d->startDrag(supportedActions);
834
835 args->setReturnValue(QV4::Encode((int)dropAction));
836}
837
838QQuickDrag::QQuickDrag(QObject *parent)
839: QObject(parent), _target(nullptr), _axis(XAndYAxis), _xmin(-FLT_MAX),
840_xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX), _active(false), _filterChildren(false),
841 _smoothed(true), _threshold(QGuiApplication::styleHints()->startDragDistance())
842{
843}
844
845QQuickDrag::~QQuickDrag()
846{
847}
848
849QQuickItem *QQuickDrag::target() const
850{
851 return _target;
852}
853
854void QQuickDrag::setTarget(QQuickItem *t)
855{
856 if (_target == t)
857 return;
858 _target = t;
859 emit targetChanged();
860}
861
862void QQuickDrag::resetTarget()
863{
864 if (_target == nullptr)
865 return;
866 _target = nullptr;
867 emit targetChanged();
868}
869
870QQuickDrag::Axis QQuickDrag::axis() const
871{
872 return _axis;
873}
874
875void QQuickDrag::setAxis(QQuickDrag::Axis a)
876{
877 if (_axis == a)
878 return;
879 _axis = a;
880 emit axisChanged();
881}
882
883qreal QQuickDrag::xmin() const
884{
885 return _xmin;
886}
887
888void QQuickDrag::setXmin(qreal m)
889{
890 if (_xmin == m)
891 return;
892 _xmin = m;
893 emit minimumXChanged();
894}
895
896qreal QQuickDrag::xmax() const
897{
898 return _xmax;
899}
900
901void QQuickDrag::setXmax(qreal m)
902{
903 if (_xmax == m)
904 return;
905 _xmax = m;
906 emit maximumXChanged();
907}
908
909qreal QQuickDrag::ymin() const
910{
911 return _ymin;
912}
913
914void QQuickDrag::setYmin(qreal m)
915{
916 if (_ymin == m)
917 return;
918 _ymin = m;
919 emit minimumYChanged();
920}
921
922qreal QQuickDrag::ymax() const
923{
924 return _ymax;
925}
926
927void QQuickDrag::setYmax(qreal m)
928{
929 if (_ymax == m)
930 return;
931 _ymax = m;
932 emit maximumYChanged();
933}
934
935bool QQuickDrag::smoothed() const
936{
937 return _smoothed;
938}
939
940void QQuickDrag::setSmoothed(bool smooth)
941{
942 if (_smoothed != smooth) {
943 _smoothed = smooth;
944 emit smoothedChanged();
945 }
946}
947
948qreal QQuickDrag::threshold() const
949{
950 return _threshold;
951}
952
953void QQuickDrag::setThreshold(qreal value)
954{
955 if (_threshold != value) {
956 _threshold = value;
957 emit thresholdChanged();
958 }
959}
960
961void QQuickDrag::resetThreshold()
962{
963 setThreshold(QGuiApplication::styleHints()->startDragDistance());
964}
965
966bool QQuickDrag::active() const
967{
968 return _active;
969}
970
971void QQuickDrag::setActive(bool drag)
972{
973 if (_active == drag)
974 return;
975 _active = drag;
976 emit activeChanged();
977}
978
979bool QQuickDrag::filterChildren() const
980{
981 return _filterChildren;
982}
983
984void QQuickDrag::setFilterChildren(bool filter)
985{
986 if (_filterChildren == filter)
987 return;
988 _filterChildren = filter;
989 emit filterChildrenChanged();
990}
991
992QQuickDragAttached *QQuickDrag::qmlAttachedProperties(QObject *obj)
993{
994 return new QQuickDragAttached(obj);
995}
996
997QT_END_NAMESPACE
998
999#include "moc_qquickdrag_p.cpp"
1000
1001#endif // draganddrop
1002