107void QQuickDragAttachedPrivate::deliverEnterEvent()
109 dragRestarted =
false;
112 window = attachedItem->window();
114 mimeData->m_source = source;
115 if (!overrideActions)
116 mimeData->m_supportedActions = supportedActions;
117 mimeData->m_keys = keys;
120 QDragEnterEvent event(attachedItem->mapToScene(hotSpot), mimeData->m_supportedActions,
121 mimeData, Qt::NoButton, Qt::NoModifier);
122 QQuickDropEventEx::setProposedAction(&event, proposedAction);
123 deliverEvent(window, &event);
127void QQuickDragAttachedPrivate::deliverMoveEvent()
129 Q_Q(QQuickDragAttached);
133 QDragMoveEvent event(attachedItem->mapToScene(hotSpot), mimeData->m_supportedActions,
134 mimeData, Qt::NoButton, Qt::NoModifier);
135 QQuickDropEventEx::setProposedAction(&event, proposedAction);
136 deliverEvent(window, &event);
137 if (target != dragGrabber.target()) {
138 target = dragGrabber.target();
139 emit q->targetChanged();
186QQuickDragAttached::QQuickDragAttached(QObject *parent)
187 : QObject(*
new QQuickDragAttachedPrivate, parent)
189 Q_D(QQuickDragAttached);
190 d->attachedItem = qobject_cast<QQuickItem *>(parent);
191 d->source = d->attachedItem;
222void QQuickDragAttached::setActive(
bool active)
224 Q_D(QQuickDragAttached);
225 if (d->active != active) {
227 qmlWarning(
this) <<
"active cannot be changed from within a drag event handler";
228 else if (d->executingNativeDrag) {
233 if (d->dragType == QQuickDrag::Internal) {
234 d->start(d->supportedActions);
237 emit activeChanged();
238 if (d->dragType == QQuickDrag::Automatic) {
239 bool grabbingItemPixmap =
false;
243 if (
auto grab = d->attachedItem->grabToImage()) {
244 grabbingItemPixmap =
true;
245 QObject::connect(grab.data(), &QQuickItemGrabResult::ready,
this,
248 const QPixmap pixmap = QPixmap::fromImage(grab->image());
249 d->startDrag(d->supportedActions, pixmap);
254 if (!grabbingItemPixmap) {
259 QMetaObject::invokeMethod(
this, [
this] {
260 Q_D(QQuickDragAttached);
262 d->startDrag(d->supportedActions);
263 }, Qt::QueuedConnection);
416QSize QQuickDragAttached::imageSourceSize()
const
418 Q_D(
const QQuickDragAttached);
419 int width = d->imageSourceSize.width();
420 int height = d->imageSourceSize.height();
424 width = d->pixmapLoader.width();
429 height = d->pixmapLoader.height();
433 return QSize(width, height);
436void QQuickDragAttached::setImageSourceSize(
const QSize &size)
438 Q_D(QQuickDragAttached);
439 if (d->imageSourceSize != size) {
440 d->imageSourceSize = size;
442 if (!d->imageSource.isEmpty())
445 Q_EMIT imageSourceSizeChanged();
588void QQuickDragAttachedPrivate::start(Qt::DropActions supportedActions)
590 Q_Q(QQuickDragAttached);
594 mimeData =
new QQuickDragMimeData;
596 QQuickItemPrivate::get(attachedItem)->addItemChangeListener(
597 this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Parent);
601 mimeData->m_supportedActions = supportedActions;
604 dragRestarted =
false;
608 if (target != dragGrabber.target()) {
609 target = dragGrabber.target();
610 emit q->targetChanged();
613 emit q->activeChanged();
626void QQuickDragAttached::start(QQmlV4FunctionPtr args)
628 Q_D(QQuickDragAttached);
630 qmlWarning(
this) <<
"start() cannot be called from within a drag event handler";
637 d->overrideActions =
false;
638 Qt::DropActions supportedActions = d->supportedActions;
640 if (args->length() >= 1) {
641 QV4::Scope scope(args->v4engine());
642 QV4::ScopedValue v(scope, (*args)[0]);
644 supportedActions = Qt::DropActions(v->integerValue());
645 d->overrideActions =
true;
649 d->start(supportedActions);
668int QQuickDragAttached::drop()
670 Q_D(QQuickDragAttached);
671 Qt::DropAction acceptedAction = Qt::IgnoreAction;
674 qmlWarning(
this) <<
"drop() cannot be called from within a drag event handler";
675 return acceptedAction;
679 d->deliverMoveEvent();
682 return acceptedAction;
685 QObject *target =
nullptr;
688 QPoint scenePos = d->attachedItem->mapToScene(d->hotSpot).toPoint();
691 scenePos, d->mimeData->m_supportedActions, d->mimeData, Qt::NoButton, Qt::NoModifier);
692 QQuickDropEventEx::setProposedAction(&event, d->proposedAction);
693 d->deliverEvent(d->window, &event);
695 if (event.isAccepted()) {
696 acceptedAction = event.dropAction();
697 target = d->dragGrabber.target();
701 if (d->target != target) {
703 emit targetChanged();
706 emit activeChanged();
707 return acceptedAction;
756QMimeData *QQuickDragAttachedPrivate::createMimeData()
const
758 Q_Q(
const QQuickDragAttached);
759 QMimeData *mimeData =
new QMimeData();
761 for (
const auto [mimeType, value] : externalMimeData.asKeyValueRange()) {
762 switch (value.typeId()) {
763 case QMetaType::QByteArray:
765 mimeData->setData(mimeType, value.toByteArray());
767 case QMetaType::QString: {
768 const QString text = value.toString();
769 if (mimeType == u"text/plain"_s) {
770 mimeData->setText(text);
771 }
else if (mimeType == u"text/html"_s) {
772 mimeData->setHtml(text);
773 }
else if (mimeType == u"text/uri-list"_s) {
776 const auto lines = text.split(u"\r\n"_s, Qt::SkipEmptyParts);
777 for (
const auto &line : lines) {
778 const QUrl url(line);
782 qmlWarning(q) << line <<
" is not a valid URI";
785 mimeData->setUrls(urls);
786 }
else if (mimeType.startsWith(u"text/"_s)) {
787 if (qsizetype charsetIdx = mimeType.lastIndexOf(u";charset="_s); charsetIdx != -1) {
788 charsetIdx +=
sizeof(
";charset=") - 1;
789 const QByteArray encoding = mimeType.mid(charsetIdx).toUtf8();
790 QStringEncoder encoder(encoding);
791 if (encoder.isValid())
792 mimeData->setData(mimeType, encoder.encode(text));
794 qmlWarning(q) <<
"Don't know how to encode text as " << mimeType;
796 mimeData->setData(mimeType, text.toUtf8());
799 mimeData->setData(mimeType, text.toUtf8());
803 case QMetaType::QVariantList:
804 case QMetaType::QStringList:
805 if (mimeType == u"text/uri-list"_s) {
806 const QVariantList values = value.toList();
808 urls.reserve(values.size());
810 for (qsizetype index = 0; index < values.size(); ++index) {
811 const QUrl url = values.at(index).value<QUrl>();
816 qmlWarning(q) <<
"Value '" << values.at(index) <<
"' at index " << index
817 <<
" is not a valid URI";
821 mimeData->setUrls(urls);
824 case QMetaType::QColor:
825 if (mimeType == u"application/x-color"_s)
826 mimeData->setColorData(value);
828 case QMetaType::QImage:
829 if (
const QByteArray mimeTypeUtf8 = mimeType.toUtf8();
830 QImageWriter::supportedMimeTypes().contains(mimeTypeUtf8)) {
831 const auto imageFormats = QImageWriter::imageFormatsForMimeType(mimeTypeUtf8);
832 if (imageFormats.isEmpty()) {
833 mimeData->setImageData(value);
836 const QImage image = value.value<QImage>();
839 QBuffer buffer(&bytes);
840 QImageWriter encoder(&buffer, imageFormats.first());
841 encoder.write(image);
843 mimeData->setData(mimeType, bytes);
848 qmlWarning(q) <<
"Don't know how to encode variant of type " << value.metaType()
849 <<
" as mime type " << mimeType;
851 mimeData->setData(mimeType, value.toString().toUtf8());
859void QQuickDragAttachedPrivate::loadPixmap()
861 Q_Q(QQuickDragAttached);
863 QUrl loadUrl = imageSource;
864 const QQmlContext *context = qmlContext(q->parent());
866 loadUrl = context->resolvedUrl(imageSource);
867 pixmapLoader.load(context ? context->engine() :
nullptr, loadUrl, QRect(), q->imageSourceSize());
870Qt::DropAction QQuickDragAttachedPrivate::startDrag(Qt::DropActions supportedActions,
873 Q_Q(QQuickDragAttached);
875 QDrag *drag =
new QDrag(source ? source : q);
877 drag->setMimeData(createMimeData());
878 if (!pixmap.isNull())
879 drag->setPixmap(pixmap);
880 else if (pixmapLoader.isReady())
881 drag->setPixmap(QPixmap::fromImage(pixmapLoader.image()));
883 drag->setHotSpot(hotSpot.toPoint());
884 emit q->dragStarted();
886 executingNativeDrag =
true;
887 Qt::DropAction dropAction = drag->exec(supportedActions);
888 executingNativeDrag =
false;
890 if (!QGuiApplicationPrivate::platformIntegration()->drag()->ownsDragObject())
897 emit q->targetChanged();
900 emit q->dragFinished(dropAction);
903 emit q->activeChanged();
918void QQuickDragAttached::startDrag(QQmlV4FunctionPtr args)
920 Q_D(QQuickDragAttached);
923 qmlWarning(
this) <<
"startDrag() cannot be called from within a drag event handler";
928 qmlWarning(
this) <<
"startDrag() drag must be active";
932 Qt::DropActions supportedActions = d->supportedActions;
935 if (args->length() >= 1) {
936 QV4::Scope scope(args->v4engine());
937 QV4::ScopedValue v(scope, (*args)[0]);
939 supportedActions = Qt::DropActions(v->integerValue());
943 Qt::DropAction dropAction = d->startDrag(supportedActions);
945 args->setReturnValue(QV4::Encode((
int)dropAction));
948QQuickDrag::QQuickDrag(QObject *parent)
949: QObject(parent), _target(
nullptr), _axis(XAndYAxis), _xmin(-FLT_MAX),
950_xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX), _active(
false), _filterChildren(
false),
951 _smoothed(
true), _threshold(QGuiApplication::styleHints()->startDragDistance())