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

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