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 "qquickdroparea_p.h"
41#include "qquickdrag_p.h"
42#include "qquickitem_p.h"
43
44#include <private/qv4arraybuffer_p.h>
45
46#include <QtCore/qregularexpression.h>
47
48QT_BEGIN_NAMESPACE
49
50QQuickDropAreaDrag::QQuickDropAreaDrag(QQuickDropAreaPrivate *d, QObject *parent)
51 : QObject(parent)
52 , d(d)
53{
54}
55
56QQuickDropAreaDrag::~QQuickDropAreaDrag()
57{
58}
59
60class QQuickDropAreaPrivate : public QQuickItemPrivate
61{
62 Q_DECLARE_PUBLIC(QQuickDropArea)
63
64public:
65 QQuickDropAreaPrivate();
66 ~QQuickDropAreaPrivate();
67
68 bool hasMatchingKey(const QStringList &keys) const;
69
70 QStringList getKeys(const QMimeData *mimeData) const;
71
72 QStringList keys;
73 QRegularExpression keyRegExp;
74 QPointF dragPosition;
75 QQuickDropAreaDrag *drag;
76 QPointer<QObject> source;
77 bool containsDrag;
78};
79
80QQuickDropAreaPrivate::QQuickDropAreaPrivate()
81 : drag(nullptr)
82 , containsDrag(false)
83{
84}
85
86QQuickDropAreaPrivate::~QQuickDropAreaPrivate()
87{
88 delete drag;
89}
90
91/*!
92 \qmltype DropArea
93 \instantiates QQuickDropArea
94 \inherits Item
95 \inqmlmodule QtQuick
96 \ingroup qtquick-input
97 \brief For specifying drag and drop handling in an area.
98
99 A DropArea is an invisible item which receives events when other items are
100 dragged over it.
101
102 The \l Drag attached property can be used to notify the DropArea when an Item is
103 dragged over it.
104
105 The \l keys property can be used to filter drag events which don't include
106 a matching key.
107
108 The \l drag.source property is communicated to the source of a drag event as
109 the recipient of a drop on the drag target.
110
111 \sa {Qt Quick Examples - Drag and Drop}, {Qt Quick Examples - externaldraganddrop}
112*/
113
114QQuickDropArea::QQuickDropArea(QQuickItem *parent)
115 : QQuickItem(*new QQuickDropAreaPrivate, parent)
116{
117 setFlags(ItemAcceptsDrops);
118}
119
120QQuickDropArea::~QQuickDropArea()
121{
122}
123
124/*!
125 \qmlproperty bool QtQuick::DropArea::containsDrag
126
127 This property identifies whether the DropArea currently contains any
128 dragged items.
129*/
130
131bool QQuickDropArea::containsDrag() const
132{
133 Q_D(const QQuickDropArea);
134 return d->containsDrag;
135}
136
137/*!
138 \qmlproperty stringlist QtQuick::DropArea::keys
139
140 This property holds a list of drag keys a DropArea will accept.
141
142 If no keys are listed the DropArea will accept events from any drag source,
143 otherwise the drag source must have at least one compatible key.
144
145 \sa QtQuick::Drag::keys
146*/
147
148QStringList QQuickDropArea::keys() const
149{
150 Q_D(const QQuickDropArea);
151 return d->keys;
152}
153
154void QQuickDropArea::setKeys(const QStringList &keys)
155{
156 Q_D(QQuickDropArea);
157 if (d->keys != keys) {
158 d->keys = keys;
159
160 if (keys.isEmpty()) {
161 d->keyRegExp = QRegularExpression();
162 } else {
163 QString pattern = QLatin1Char('(') + QRegularExpression::escape(str: keys.first());
164 for (int i = 1; i < keys.count(); ++i)
165 pattern += QLatin1Char('|') + QRegularExpression::escape(str: keys.at(i));
166 pattern += QLatin1Char(')');
167 d->keyRegExp = QRegularExpression(
168 QRegularExpression::anchoredPattern(expression: pattern.replace(before: QLatin1String("\\*"),
169 after: QLatin1String(".+"))));
170 }
171 emit keysChanged();
172 }
173}
174
175QQuickDropAreaDrag *QQuickDropArea::drag()
176{
177 Q_D(QQuickDropArea);
178 if (!d->drag)
179 d->drag = new QQuickDropAreaDrag(d);
180 return d->drag;
181}
182
183/*!
184 \qmlproperty Object QtQuick::DropArea::drag.source
185
186 This property holds the source of a drag.
187*/
188
189QObject *QQuickDropAreaDrag::source() const
190{
191 return d->source;
192}
193
194/*!
195 \qmlpropertygroup QtQuick::DropArea::drag
196 \qmlproperty qreal QtQuick::DropArea::drag.x
197 \qmlproperty qreal QtQuick::DropArea::drag.y
198
199 These properties hold the coordinates of the last drag event.
200*/
201
202qreal QQuickDropAreaDrag::x() const
203{
204 return d->dragPosition.x();
205}
206
207qreal QQuickDropAreaDrag::y() const
208{
209 return d->dragPosition.y();
210}
211
212/*!
213 \qmlsignal QtQuick::DropArea::positionChanged(DragEvent drag)
214
215 This signal is emitted when the position of a \a drag has changed.
216*/
217
218void QQuickDropArea::dragMoveEvent(QDragMoveEvent *event)
219{
220 Q_D(QQuickDropArea);
221 if (!d->containsDrag)
222 return;
223
224 d->dragPosition = event->pos();
225 if (d->drag)
226 emit d->drag->positionChanged();
227
228 event->accept();
229 QQuickDropEvent dragTargetEvent(d, event);
230 emit positionChanged(drag: &dragTargetEvent);
231}
232
233bool QQuickDropAreaPrivate::hasMatchingKey(const QStringList &keys) const
234{
235 if (keyRegExp.pattern().isEmpty())
236 return true;
237
238 for (const QString &key : keys) {
239 if (key.contains(re: keyRegExp))
240 return true;
241 }
242 return false;
243}
244
245QStringList QQuickDropAreaPrivate::getKeys(const QMimeData *mimeData) const
246{
247 if (const QQuickDragMimeData *dragMime = qobject_cast<const QQuickDragMimeData *>(object: mimeData))
248 return dragMime->keys();
249 return mimeData->formats();
250}
251
252/*!
253 \qmlsignal QtQuick::DropArea::entered(DragEvent drag)
254
255 This signal is emitted when a \a drag enters the bounds of a DropArea.
256*/
257
258void QQuickDropArea::dragEnterEvent(QDragEnterEvent *event)
259{
260 Q_D(QQuickDropArea);
261 const QMimeData *mimeData = event->mimeData();
262 if (!d->effectiveEnable || d->containsDrag || !mimeData || !d->hasMatchingKey(keys: d->getKeys(mimeData)))
263 return;
264
265 d->dragPosition = event->pos();
266
267 event->accept();
268
269 QQuickDropEvent dragTargetEvent(d, event);
270 emit entered(drag: &dragTargetEvent);
271 if (!event->isAccepted())
272 return;
273
274 d->containsDrag = true;
275 if (QQuickDragMimeData *dragMime = qobject_cast<QQuickDragMimeData *>(object: const_cast<QMimeData *>(mimeData)))
276 d->source = dragMime->source();
277 else
278 d->source = event->source();
279 d->dragPosition = event->pos();
280 if (d->drag) {
281 emit d->drag->positionChanged();
282 emit d->drag->sourceChanged();
283 }
284 emit containsDragChanged();
285}
286
287/*!
288 \qmlsignal QtQuick::DropArea::exited()
289
290 This signal is emitted when a drag exits the bounds of a DropArea.
291*/
292
293void QQuickDropArea::dragLeaveEvent(QDragLeaveEvent *)
294{
295 Q_D(QQuickDropArea);
296 if (!d->containsDrag)
297 return;
298
299 emit exited();
300
301 d->containsDrag = false;
302 d->source = nullptr;
303 emit containsDragChanged();
304 if (d->drag)
305 emit d->drag->sourceChanged();
306}
307
308/*!
309 \qmlsignal QtQuick::DropArea::dropped(DragEvent drop)
310
311 This signal is emitted when a \a drop event occurs within the bounds of
312 a DropArea.
313*/
314
315void QQuickDropArea::dropEvent(QDropEvent *event)
316{
317 Q_D(QQuickDropArea);
318 if (!d->containsDrag)
319 return;
320
321 QQuickDropEvent dragTargetEvent(d, event);
322 emit dropped(drop: &dragTargetEvent);
323
324 d->containsDrag = false;
325 d->source = nullptr;
326 emit containsDragChanged();
327 if (d->drag)
328 emit d->drag->sourceChanged();
329}
330
331/*!
332 \qmltype DragEvent
333 \instantiates QQuickDropEvent
334 \inqmlmodule QtQuick
335 \ingroup qtquick-input-events
336 \brief Provides information about a drag event.
337
338 The position of the drag event can be obtained from the \l x and \l y
339 properties, and the \l keys property identifies the drag keys of the event
340 \l {drag.source}{source}.
341
342 The existence of specific drag types can be determined using the \l hasColor,
343 \l hasHtml, \l hasText, and \l hasUrls properties.
344
345 The list of all supplied formats can be determined using the \l formats property.
346
347 Specific drag types can be obtained using the \l colorData, \l html, \l text,
348 and \l urls properties.
349
350 A string version of any available mimeType can be obtained using \l getDataAsString.
351*/
352
353/*!
354 \qmlproperty real QtQuick::DragEvent::x
355
356 This property holds the x coordinate of a drag event.
357*/
358
359/*!
360 \qmlproperty real QtQuick::DragEvent::y
361
362 This property holds the y coordinate of a drag event.
363*/
364
365/*!
366 \qmlproperty Object QtQuick::DragEvent::drag.source
367
368 This property holds the source of a drag event.
369*/
370
371/*!
372 \qmlproperty stringlist QtQuick::DragEvent::keys
373
374 This property holds a list of keys identifying the data type or source of a
375 drag event.
376*/
377
378/*!
379 \qmlproperty enumeration QtQuick::DragEvent::action
380
381 This property holds the action that the \l {drag.source}{source} is to perform on an accepted drop.
382
383 The drop action may be one of:
384
385 \list
386 \li Qt.CopyAction Copy the data to the target.
387 \li Qt.MoveAction Move the data from the source to the target.
388 \li Qt.LinkAction Create a link from the source to the target.
389 \li Qt.IgnoreAction Ignore the action (do nothing with the data).
390 \endlist
391*/
392
393/*!
394 \qmlproperty flags QtQuick::DragEvent::supportedActions
395
396 This property holds the set of \l {action}{actions} supported by the
397 drag source.
398*/
399
400/*!
401 \qmlproperty flags QtQuick::DragEvent::proposedAction
402 \since 5.2
403
404 This property holds the set of \l {action}{actions} proposed by the
405 drag source.
406*/
407
408/*!
409 \qmlproperty bool QtQuick::DragEvent::accepted
410
411 This property holds whether the drag event was accepted by a handler.
412
413 The default value is true.
414*/
415
416/*!
417 \qmlmethod QtQuick::DragEvent::accept()
418 \qmlmethod QtQuick::DragEvent::accept(enumeration action)
419
420 Accepts the drag event.
421
422 If an \a action is specified it will overwrite the value of the \l action property.
423*/
424
425/*!
426 \qmlmethod QtQuick::DragEvent::acceptProposedAction()
427 \since 5.2
428
429 Accepts the drag event with the \l proposedAction.
430*/
431
432/*!
433 \qmlproperty bool QtQuick::DragEvent::hasColor
434 \since 5.2
435
436 This property holds whether the drag event contains a color item.
437*/
438
439/*!
440 \qmlproperty bool QtQuick::DragEvent::hasHtml
441 \since 5.2
442
443 This property holds whether the drag event contains a html item.
444*/
445
446/*!
447 \qmlproperty bool QtQuick::DragEvent::hasText
448 \since 5.2
449
450 This property holds whether the drag event contains a text item.
451*/
452
453/*!
454 \qmlproperty bool QtQuick::DragEvent::hasUrls
455 \since 5.2
456
457 This property holds whether the drag event contains one or more url items.
458*/
459
460/*!
461 \qmlproperty color QtQuick::DragEvent::colorData
462 \since 5.2
463
464 This property holds color data, if any.
465*/
466
467/*!
468 \qmlproperty string QtQuick::DragEvent::html
469 \since 5.2
470
471 This property holds html data, if any.
472*/
473
474/*!
475 \qmlproperty string QtQuick::DragEvent::text
476 \since 5.2
477
478 This property holds text data, if any.
479*/
480
481/*!
482 \qmlproperty urllist QtQuick::DragEvent::urls
483 \since 5.2
484
485 This property holds a list of urls, if any.
486*/
487
488/*!
489 \qmlproperty stringlist QtQuick::DragEvent::formats
490 \since 5.2
491
492 This property holds a list of mime type formats contained in the drag data.
493*/
494
495/*!
496 \qmlmethod string QtQuick::DragEvent::getDataAsString(string format)
497 \since 5.2
498
499 Returns the data for the given \a format converted to a string. \a format should be one contained in the \l formats property.
500*/
501
502/*!
503 \qmlmethod string QtQuick::DragEvent::getDataAsArrayBuffer(string format)
504 \since 5.5
505
506 Returns the data for the given \a format into an ArrayBuffer, which can
507 easily be translated into a QByteArray. \a format should be one contained in the \l formats property.
508*/
509
510QObject *QQuickDropEvent::source() const
511{
512 if (const QQuickDragMimeData *dragMime = qobject_cast<const QQuickDragMimeData *>(object: event->mimeData()))
513 return dragMime->source();
514 else
515 return event->source();
516}
517
518QStringList QQuickDropEvent::keys() const
519{
520 return d->getKeys(mimeData: event->mimeData());
521}
522
523bool QQuickDropEvent::hasColor() const
524{
525 return event->mimeData()->hasColor();
526}
527
528bool QQuickDropEvent::hasHtml() const
529{
530 return event->mimeData()->hasHtml();
531}
532
533bool QQuickDropEvent::hasText() const
534{
535 return event->mimeData()->hasText();
536}
537
538bool QQuickDropEvent::hasUrls() const
539{
540 return event->mimeData()->hasUrls();
541}
542
543QVariant QQuickDropEvent::colorData() const
544{
545 return event->mimeData()->colorData();
546}
547
548QString QQuickDropEvent::html() const
549{
550 return event->mimeData()->html();
551}
552
553QString QQuickDropEvent::text() const
554{
555 return event->mimeData()->text();
556}
557
558QList<QUrl> QQuickDropEvent::urls() const
559{
560 return event->mimeData()->urls();
561}
562
563QStringList QQuickDropEvent::formats() const
564{
565 return event->mimeData()->formats();
566}
567
568void QQuickDropEvent::getDataAsString(QQmlV4Function *args)
569{
570 if (args->length() != 0) {
571 QV4::ExecutionEngine *v4 = args->v4engine();
572 QV4::Scope scope(v4);
573 QV4::ScopedValue v(scope, (*args)[0]);
574 QString format = v->toQString();
575 QString rv = QString::fromUtf8(str: event->mimeData()->data(mimetype: format));
576 args->setReturnValue(v4->newString(s: rv)->asReturnedValue());
577 }
578}
579
580void QQuickDropEvent::getDataAsArrayBuffer(QQmlV4Function *args)
581{
582 if (args->length() != 0) {
583 QV4::ExecutionEngine *v4 = args->v4engine();
584 QV4::Scope scope(v4);
585 QV4::ScopedValue v(scope, (*args)[0]);
586 const QString format = v->toQString();
587 args->setReturnValue(v4->newArrayBuffer(array: event->mimeData()->data(mimetype: format))->asReturnedValue());
588 }
589}
590
591void QQuickDropEvent::acceptProposedAction(QQmlV4Function *)
592{
593 event->acceptProposedAction();
594}
595
596void QQuickDropEvent::accept(QQmlV4Function *args)
597{
598 Qt::DropAction action = event->dropAction();
599
600 if (args->length() >= 1) {
601 QV4::Scope scope(args->v4engine());
602 QV4::ScopedValue v(scope, (*args)[0]);
603 if (v->isInt32())
604 action = Qt::DropAction(v->integerValue());
605 }
606
607 // get action from arguments.
608 event->setDropAction(action);
609 event->accept();
610}
611
612
613QT_END_NAMESPACE
614
615#include "moc_qquickdroparea_p.cpp"
616

source code of qtdeclarative/src/quick/items/qquickdroparea.cpp