From 423f7ab80f814c5f4e4784e70bd3c36c44497314 Mon Sep 17 00:00:00 2001 From: Joerg Bornemann Date: Wed, 16 Dec 2015 12:38:16 +0100 Subject: Implement drag and drop support Create a QDrag for drag and drop operations that are started in the web page. React on drag and drop event of QWidget and QQuickItem. Task-number: QTBUG-43008 Change-Id: If09f09de6e6d5b5f02835985a17cc6bc3262f411 Reviewed-by: Alexandru Croitor Reviewed-by: Allan Sandfeld Jensen --- src/core/type_conversion.cpp | 10 ++ src/core/type_conversion.h | 11 ++ src/core/web_contents_adapter.cpp | 156 ++++++++++++++++++++++++++++ src/core/web_contents_adapter.h | 11 ++ src/core/web_contents_adapter_client.h | 8 +- src/core/web_contents_adapter_p.h | 11 ++ src/core/web_contents_view_qt.cpp | 56 ++++++++-- src/core/web_contents_view_qt.h | 6 +- src/webengine/api/qquickwebengineview.cpp | 48 ++++++++- src/webengine/api/qquickwebengineview_p.h | 4 + src/webengine/api/qquickwebengineview_p_p.h | 3 + src/webenginewidgets/api/qwebenginepage.cpp | 12 +++ src/webenginewidgets/api/qwebenginepage_p.h | 3 + src/webenginewidgets/api/qwebengineview.cpp | 35 +++++++ src/webenginewidgets/api/qwebengineview.h | 4 + 15 files changed, 367 insertions(+), 11 deletions(-) diff --git a/src/core/type_conversion.cpp b/src/core/type_conversion.cpp index d4b988552..99a7da099 100644 --- a/src/core/type_conversion.cpp +++ b/src/core/type_conversion.cpp @@ -37,6 +37,7 @@ #include "type_conversion.h" #include +#include #include namespace QtWebEngineCore { @@ -116,6 +117,14 @@ QImage toQImage(const SkBitmap &bitmap) return image; } +QImage toQImage(const gfx::ImageSkiaRep &imageSkiaRep) +{ + QImage image = toQImage(imageSkiaRep.sk_bitmap()); + if (!image.isNull() && imageSkiaRep.scale() != 1.0f) + image.setDevicePixelRatio(imageSkiaRep.scale()); + return image; +} + int flagsFromModifiers(Qt::KeyboardModifiers modifiers) { int modifierFlags = ui::EF_NONE; @@ -140,4 +149,5 @@ int flagsFromModifiers(Qt::KeyboardModifiers modifiers) return modifierFlags; } + } // namespace QtWebEngineCore diff --git a/src/core/type_conversion.h b/src/core/type_conversion.h index da0ee3e5c..5cf7267f2 100644 --- a/src/core/type_conversion.h +++ b/src/core/type_conversion.h @@ -46,6 +46,7 @@ #include #include #include +#include #include "base/files/file_path.h" #include "base/time/time.h" #include "content/public/common/file_chooser_file_info.h" @@ -58,6 +59,10 @@ #include "ui/gfx/geometry/rect_f.h" #include "url/gurl.h" +namespace gfx { +class ImageSkiaRep; +} + namespace QtWebEngineCore { inline QString toQt(const base::string16 &string) @@ -83,6 +88,11 @@ inline base::string16 toString16(const QString &qString) #endif } +inline base::NullableString16 toNullableString16(const QString &qString) +{ + return base::NullableString16(toString16(qString), qString.isNull()); +} + inline QUrl toQt(const GURL &url) { return QUrl(QString::fromStdString(url.spec())); @@ -150,6 +160,7 @@ inline QImage toQImage(const SkBitmap &bitmap, QImage::Format format) } QImage toQImage(const SkBitmap &bitmap); +QImage toQImage(const gfx::ImageSkiaRep &imageSkiaRep); inline QMatrix4x4 toQt(const SkMatrix44 &m) { diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index 923bb1e2d..ad582d7d3 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -55,6 +55,7 @@ #include "web_engine_context.h" #include "web_engine_settings.h" +#include #include "base/values.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" @@ -65,6 +66,7 @@ #include "content/public/browser/navigation_entry.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/favicon_status.h" +#include #include "content/public/common/page_state.h" #include "content/public/common/page_zoom.h" #include "content/public/common/renderer_preferences.h" @@ -77,7 +79,10 @@ #include #include #include +#include #include +#include +#include #include namespace QtWebEngineCore { @@ -312,6 +317,9 @@ WebContentsAdapterPrivate::WebContentsAdapterPrivate() , adapterClient(0) , nextRequestId(CallbackDirectory::ReservedCallbackIdsEnd) , lastFindRequestId(0) + , currentDropData(nullptr) + , currentDropAction(Qt::IgnoreAction) + , inDragUpdateLoop(false) { } @@ -961,6 +969,154 @@ void WebContentsAdapter::setWebChannel(QWebChannel *channel) channel->connectTo(d->webChannelTransport.get()); } +static QMimeData *mimeDataFromDropData(const content::DropData &dropData) +{ + QMimeData *mimeData = new QMimeData(); + if (!dropData.text.is_null()) { + mimeData->setText(toQt(dropData.text.string())); + return mimeData; + } + if (!dropData.html.is_null()) { + mimeData->setHtml(toQt(dropData.html.string())); + return mimeData; + } + if (dropData.url.is_valid()) { + mimeData->setUrls(QList() << toQt(dropData.url)); + return mimeData; + } + return mimeData; +} + +void WebContentsAdapter::startDragging(QObject *dragSource, const content::DropData &dropData, + Qt::DropActions allowedActions, const QPixmap &pixmap, + const QPoint &offset) +{ + Q_D(WebContentsAdapter); + + if (d->currentDropData) + return; + + // Clear certain fields of the drop data to not run into DCHECKs + // of DropDataToWebDragData in render_view_impl.cc. + content::DropData fixedDropData = dropData; + fixedDropData.download_metadata.clear(); + fixedDropData.file_contents.clear(); + fixedDropData.file_description_filename.clear(); + + d->currentDropAction = Qt::IgnoreAction; + d->currentDropData = &fixedDropData; + QDrag *drag = new QDrag(dragSource); // will be deleted by Qt's DnD implementation + drag->setMimeData(mimeDataFromDropData(fixedDropData)); + if (!pixmap.isNull()) { + drag->setPixmap(pixmap); + drag->setHotSpot(offset); + } + + { + base::MessageLoop::ScopedNestableTaskAllower allow(base::MessageLoop::current()); + drag->exec(allowedActions); + } + + content::RenderViewHost *rvh = d->webContents->GetRenderViewHost(); + rvh->DragSourceSystemDragEnded(); + d->currentDropData = nullptr; +} + +static blink::WebDragOperationsMask toWeb(const Qt::DropActions action) +{ + int result = blink::WebDragOperationNone; + if (action & Qt::CopyAction) + result |= blink::WebDragOperationCopy; + if (action & Qt::LinkAction) + result |= blink::WebDragOperationLink; + if (action & Qt::MoveAction) + result |= blink::WebDragOperationMove; + return static_cast(result); +} + +static void fillDropDataFromMimeData(content::DropData *dropData, const QMimeData *mimeData) +{ + if (mimeData->hasText()) + dropData->text = toNullableString16(mimeData->text()); + if (mimeData->hasHtml()) + dropData->html = toNullableString16(mimeData->html()); + Q_FOREACH (const QUrl &url, mimeData->urls()) { + if (url.isLocalFile()) { + ui::FileInfo uifi; + uifi.path = toFilePath(url.toLocalFile()); + dropData->filenames.push_back(uifi); + } + } +} + +void WebContentsAdapter::enterDrag(QDragEnterEvent *e, const QPoint &screenPos) +{ + Q_D(WebContentsAdapter); + + scoped_ptr ownedDropData; + const content::DropData *rvhDropData = d->currentDropData; + if (!rvhDropData) { + // The drag originated outside the WebEngineView. + ownedDropData.reset(new content::DropData); + fillDropDataFromMimeData(ownedDropData.get(), e->mimeData()); + rvhDropData = ownedDropData.get(); + } + + content::RenderViewHost *rvh = d->webContents->GetRenderViewHost(); + rvh->DragTargetDragEnter(*rvhDropData, toGfx(e->pos()), toGfx(screenPos), + toWeb(e->possibleActions()), + flagsFromModifiers(e->keyboardModifiers())); +} + +Qt::DropAction WebContentsAdapter::updateDragPosition(QDragMoveEvent *e, const QPoint &screenPos) +{ + Q_D(WebContentsAdapter); + content::RenderViewHost *rvh = d->webContents->GetRenderViewHost(); + rvh->DragTargetDragOver(toGfx(e->pos()), toGfx(screenPos), toWeb(e->possibleActions()), + blink::WebInputEvent::LeftButtonDown); + + // Wait until we get notified via RenderViewHostDelegateView::UpdateDragCursor. This calls + // WebContentsAdapter::updateDragAction that will eventually quit the nested loop. + base::RunLoop loop; + d->inDragUpdateLoop = true; + d->dragUpdateLoopQuitClosure = loop.QuitClosure(); + loop.Run(); + + return d->currentDropAction; +} + +void WebContentsAdapter::updateDragAction(Qt::DropAction action) +{ + Q_D(WebContentsAdapter); + d->currentDropAction = action; + finishDragUpdate(); +} + +void WebContentsAdapter::finishDragUpdate() +{ + Q_D(WebContentsAdapter); + if (d->inDragUpdateLoop) { + d->dragUpdateLoopQuitClosure.Run(); + d->inDragUpdateLoop = false; + } +} + +void WebContentsAdapter::endDragging(const QPoint &clientPos, const QPoint &screenPos) +{ + Q_D(WebContentsAdapter); + finishDragUpdate(); + content::RenderViewHost *rvh = d->webContents->GetRenderViewHost(); + rvh->DragTargetDrop(toGfx(clientPos), toGfx(screenPos), 0); +} + +void WebContentsAdapter::leaveDrag() +{ + Q_D(WebContentsAdapter); + finishDragUpdate(); + content::RenderViewHost *rvh = d->webContents->GetRenderViewHost(); + rvh->DragTargetDragLeave(); +} + WebContentsAdapterClient::RenderProcessTerminationStatus WebContentsAdapterClient::renderProcessExitStatus(int terminationStatus) { auto status = WebContentsAdapterClient::RenderProcessTerminationStatus(-1); diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h index 01da38894..d38979177 100644 --- a/src/core/web_contents_adapter.h +++ b/src/core/web_contents_adapter.h @@ -52,6 +52,8 @@ struct WebPreferences; QT_BEGIN_NAMESPACE class QAccessibleInterface; +class QDragEnterEvent; +class QDragMoveEvent; class QWebChannel; QT_END_NAMESPACE @@ -153,6 +155,15 @@ public: QPointF lastScrollOffset() const; QSizeF lastContentsSize() const; + void startDragging(QObject *dragSource, const content::DropData &dropData, + Qt::DropActions allowedActions, const QPixmap &pixmap, const QPoint &offset); + void enterDrag(QDragEnterEvent *e, const QPoint &screenPos); + Qt::DropAction updateDragPosition(QDragMoveEvent *e, const QPoint &screenPos); + void updateDragAction(Qt::DropAction action); + void finishDragUpdate(); + void endDragging(const QPoint &clientPos, const QPoint &screenPos); + void leaveDrag(); + // meant to be used within WebEngineCore only content::WebContents *webContents() const; diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h index 92d5aa093..b19cc5241 100644 --- a/src/core/web_contents_adapter_client.h +++ b/src/core/web_contents_adapter_client.h @@ -50,6 +50,10 @@ QT_FORWARD_DECLARE_CLASS(QKeyEvent) QT_FORWARD_DECLARE_CLASS(QVariant) QT_FORWARD_DECLARE_CLASS(CertificateErrorController) +namespace content { +struct DropData; +} + namespace QtWebEngineCore { class AuthenticationDialogController; @@ -243,9 +247,11 @@ public: virtual void allowCertificateError(const QSharedPointer &errorController) = 0; virtual void updateScrollPosition(const QPointF &position) = 0; virtual void updateContentsSize(const QSizeF &size) = 0; + virtual void startDragging(const content::DropData &dropData, Qt::DropActions allowedActions, + const QPixmap &pixmap, const QPoint &offset) = 0; virtual BrowserContextAdapter* browserContextAdapter() = 0; - + virtual WebContentsAdapter* webContentsAdapter() = 0; }; } // namespace QtWebEngineCore diff --git a/src/core/web_contents_adapter_p.h b/src/core/web_contents_adapter_p.h index 093b9059d..63f075bce 100644 --- a/src/core/web_contents_adapter_p.h +++ b/src/core/web_contents_adapter_p.h @@ -50,6 +50,7 @@ #include "web_contents_adapter.h" +#include #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" @@ -57,6 +58,12 @@ QT_FORWARD_DECLARE_CLASS(QWebChannel) +class WebEngineContext; + +namespace content { +struct DropData; +} + namespace QtWebEngineCore { class BrowserContextAdapter; @@ -81,6 +88,10 @@ public: WebContentsAdapterClient *adapterClient; quint64 nextRequestId; int lastFindRequestId; + const content::DropData *currentDropData; + Qt::DropAction currentDropAction; + bool inDragUpdateLoop; + base::Closure dragUpdateLoopQuitClosure; }; } // namespace QtWebEngineCore diff --git a/src/core/web_contents_view_qt.cpp b/src/core/web_contents_view_qt.cpp index 67addacd5..153966aea 100644 --- a/src/core/web_contents_view_qt.cpp +++ b/src/core/web_contents_view_qt.cpp @@ -40,10 +40,14 @@ #include "content_browser_client_qt.h" #include "render_widget_host_view_qt_delegate.h" #include "type_conversion.h" +#include "web_contents_adapter.h" #include "web_engine_context.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/public/common/context_menu_params.h" +#include + +#include namespace QtWebEngineCore { @@ -164,15 +168,51 @@ void WebContentsViewQt::ShowContextMenu(content::RenderFrameHost *, const conten m_client->contextMenuRequested(contextMenuData); } -void WebContentsViewQt::StartDragging(const content::DropData& drop_data, blink::WebDragOperationsMask allowed_ops, const gfx::ImageSkia& image, const gfx::Vector2d& image_offset, const content::DragEventSourceInfo& event_info) +Qt::DropActions toQtDropActions(blink::WebDragOperationsMask ops) +{ + Qt::DropActions result; + if (ops & blink::WebDragOperationCopy) + result |= Qt::CopyAction; + if (ops & blink::WebDragOperationLink) + result |= Qt::LinkAction; + if (ops & blink::WebDragOperationMove || ops & blink::WebDragOperationDelete) + result |= Qt::MoveAction; + return result; +} + +Qt::DropAction toQt(blink::WebDragOperation op) +{ + if (op == blink::WebDragOperationCopy) + return Qt::CopyAction; + if (op == blink::WebDragOperationLink) + return Qt::LinkAction; + if (op == blink::WebDragOperationMove || op == blink::WebDragOperationDelete) + return Qt::MoveAction; + return Qt::IgnoreAction; +} + +void WebContentsViewQt::StartDragging(const content::DropData &drop_data, + blink::WebDragOperationsMask allowed_ops, + const gfx::ImageSkia &image, + const gfx::Vector2d &image_offset, + const content::DragEventSourceInfo &event_info) +{ + Q_UNUSED(event_info); + + QPixmap pixmap; + QPoint hotspot; + pixmap = QPixmap::fromImage(toQImage(image.GetRepresentation(m_client->dpiScale()))); + if (!pixmap.isNull()) { + hotspot.setX(image_offset.x()); + hotspot.setY(image_offset.y()); + } + + m_client->startDragging(drop_data, toQtDropActions(allowed_ops), pixmap, hotspot); +} + +void WebContentsViewQt::UpdateDragCursor(blink::WebDragOperation dragOperation) { - Q_UNUSED(&drop_data); - Q_UNUSED(allowed_ops); - Q_UNUSED(&image); - Q_UNUSED(&image_offset); - Q_UNUSED(&event_info); - // Tell the renderer to cancel the drag, see StartDragging's declaration in render_view_host_delegate_view.h for info. - m_webContents->SystemDragEnded(); + m_client->webContentsAdapter()->updateDragAction(toQt(dragOperation)); } void WebContentsViewQt::TakeFocus(bool reverse) diff --git a/src/core/web_contents_view_qt.h b/src/core/web_contents_view_qt.h index cbbca2371..084fa615d 100644 --- a/src/core/web_contents_view_qt.h +++ b/src/core/web_contents_view_qt.h @@ -104,7 +104,11 @@ public: virtual gfx::Rect GetViewBounds() const Q_DECL_OVERRIDE { QT_NOT_YET_IMPLEMENTED return gfx::Rect(); } - virtual void StartDragging(const content::DropData& drop_data, blink::WebDragOperationsMask allowed_ops, const gfx::ImageSkia& image, const gfx::Vector2d& image_offset, const content::DragEventSourceInfo& event_info) Q_DECL_OVERRIDE; + void StartDragging(const content::DropData &drop_data, blink::WebDragOperationsMask allowed_ops, + const gfx::ImageSkia &image, const gfx::Vector2d &image_offset, + const content::DragEventSourceInfo &event_info) Q_DECL_OVERRIDE; + + void UpdateDragCursor(blink::WebDragOperation dragOperation) Q_DECL_OVERRIDE; virtual void ShowContextMenu(content::RenderFrameHost *, const content::ContextMenuParams ¶ms) Q_DECL_OVERRIDE; diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index 7b0ed0a33..df1f46852 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -621,6 +621,11 @@ BrowserContextAdapter *QQuickWebEngineViewPrivate::browserContextAdapter() return m_profile->d_ptr->browserContext(); } +WebContentsAdapter *QQuickWebEngineViewPrivate::webContentsAdapter() +{ + return adapter.data(); +} + WebEngineSettings *QQuickWebEngineViewPrivate::webEngineSettings() const { return m_settings->d_ptr.data(); @@ -749,7 +754,8 @@ QQuickWebEngineView::QQuickWebEngineView(QQuickItem *parent) Q_D(QQuickWebEngineView); d->e->q_ptr = d->q_ptr = this; this->setActiveFocusOnTab(true); - this->setFlags(QQuickItem::ItemIsFocusScope | QQuickItem::ItemAcceptsInputMethod); + this->setFlags(QQuickItem::ItemIsFocusScope | QQuickItem::ItemAcceptsInputMethod + | QQuickItem::ItemAcceptsDrops); #ifndef QT_NO_ACCESSIBILITY QQuickAccessibleAttached *accessible = QQuickAccessibleAttached::qmlAttachedProperties(this); @@ -999,6 +1005,13 @@ void QQuickWebEngineViewPrivate::renderProcessTerminated( renderProcessExitStatus(terminationStatus)), exitCode); } +void QQuickWebEngineViewPrivate::startDragging(const content::DropData &dropData, + Qt::DropActions allowedActions, + const QPixmap &pixmap, const QPoint &offset) +{ + adapter->startDragging(q_ptr->window(), dropData, allowedActions, pixmap, offset); +} + bool QQuickWebEngineView::isLoading() const { Q_D(const QQuickWebEngineView); @@ -1265,6 +1278,39 @@ void QQuickWebEngineView::itemChange(ItemChange change, const ItemChangeData &va QQuickItem::itemChange(change, value); } +static QPoint mapToScreen(const QQuickItem *item, const QPoint &clientPos) +{ + return item->window()->position() + item->mapToScene(clientPos).toPoint(); +} + +void QQuickWebEngineView::dragEnterEvent(QDragEnterEvent *e) +{ + Q_D(QQuickWebEngineView); + e->accept(); + d->adapter->enterDrag(e, mapToScreen(this, e->pos())); +} + +void QQuickWebEngineView::dragLeaveEvent(QDragLeaveEvent *e) +{ + Q_D(QQuickWebEngineView); + e->accept(); + d->adapter->leaveDrag(); +} + +void QQuickWebEngineView::dragMoveEvent(QDragMoveEvent *e) +{ + Q_D(QQuickWebEngineView); + e->accept(); + d->adapter->updateDragPosition(e, mapToScreen(this, e->pos())); +} + +void QQuickWebEngineView::dropEvent(QDropEvent *e) +{ + Q_D(QQuickWebEngineView); + e->accept(); + d->adapter->endDragging(e->pos(), mapToScreen(this, e->pos())); +} + void QQuickWebEngineView::triggerWebAction(WebAction action) { Q_D(QQuickWebEngineView); diff --git a/src/webengine/api/qquickwebengineview_p.h b/src/webengine/api/qquickwebengineview_p.h index 9f7a45156..c533d0fca 100644 --- a/src/webengine/api/qquickwebengineview_p.h +++ b/src/webengine/api/qquickwebengineview_p.h @@ -329,6 +329,10 @@ Q_SIGNALS: protected: void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); void itemChange(ItemChange, const ItemChangeData &); + void dragEnterEvent(QDragEnterEvent *e) Q_DECL_OVERRIDE; + void dragLeaveEvent(QDragLeaveEvent *e) Q_DECL_OVERRIDE; + void dragMoveEvent(QDragMoveEvent *e) Q_DECL_OVERRIDE; + void dropEvent(QDropEvent *e) Q_DECL_OVERRIDE; private: Q_DECLARE_PRIVATE(QQuickWebEngineView) diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h index 69ba60ccd..beb5b49bc 100644 --- a/src/webengine/api/qquickwebengineview_p_p.h +++ b/src/webengine/api/qquickwebengineview_p_p.h @@ -174,8 +174,11 @@ public: int exitCode) Q_DECL_OVERRIDE; virtual void updateScrollPosition(const QPointF &position) Q_DECL_OVERRIDE; virtual void updateContentsSize(const QSizeF &size) Q_DECL_OVERRIDE; + void startDragging(const content::DropData &dropData, Qt::DropActions allowedActions, + const QPixmap &pixmap, const QPoint &offset) Q_DECL_OVERRIDE; virtual QtWebEngineCore::BrowserContextAdapter *browserContextAdapter() Q_DECL_OVERRIDE; + QtWebEngineCore::WebContentsAdapter *webContentsAdapter() Q_DECL_OVERRIDE; void setDevicePixelRatio(qreal); void adoptWebContents(QtWebEngineCore::WebContentsAdapter *webContents); diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp index ec98a8346..d69437641 100644 --- a/src/webenginewidgets/api/qwebenginepage.cpp +++ b/src/webenginewidgets/api/qwebenginepage.cpp @@ -421,6 +421,11 @@ BrowserContextAdapter *QWebEnginePagePrivate::browserContextAdapter() return profile->d_ptr->browserContext(); } +WebContentsAdapter *QWebEnginePagePrivate::webContentsAdapter() +{ + return adapter.data(); +} + QWebEnginePage::QWebEnginePage(QObject* parent) : QObject(parent) , d_ptr(new QWebEnginePagePrivate()) @@ -1089,6 +1094,13 @@ void QWebEnginePagePrivate::renderProcessTerminated(RenderProcessTerminationStat terminationStatus), exitCode); } +void QWebEnginePagePrivate::startDragging(const content::DropData &dropData, + Qt::DropActions allowedActions, const QPixmap &pixmap, + const QPoint &offset) +{ + adapter->startDragging(view, dropData, allowedActions, pixmap, offset); +} + QMenu *QWebEnginePage::createStandardContextMenu() { Q_D(QWebEnginePage); diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h index 2ec5f6288..e7f4cac4e 100644 --- a/src/webenginewidgets/api/qwebenginepage_p.h +++ b/src/webenginewidgets/api/qwebenginepage_p.h @@ -126,8 +126,11 @@ public: int exitCode) Q_DECL_OVERRIDE; virtual void updateScrollPosition(const QPointF &position) Q_DECL_OVERRIDE; virtual void updateContentsSize(const QSizeF &size) Q_DECL_OVERRIDE; + void startDragging(const content::DropData &dropData, Qt::DropActions allowedActions, + const QPixmap &pixmap, const QPoint &offset) Q_DECL_OVERRIDE; virtual QtWebEngineCore::BrowserContextAdapter *browserContextAdapter() Q_DECL_OVERRIDE; + QtWebEngineCore::WebContentsAdapter *webContentsAdapter() Q_DECL_OVERRIDE; void updateAction(QWebEnginePage::WebAction) const; void updateNavigationActions(); diff --git a/src/webenginewidgets/api/qwebengineview.cpp b/src/webenginewidgets/api/qwebengineview.cpp index 362849732..e066f2d0e 100644 --- a/src/webenginewidgets/api/qwebengineview.cpp +++ b/src/webenginewidgets/api/qwebengineview.cpp @@ -122,6 +122,7 @@ QWebEngineView::QWebEngineView(QWidget *parent) { Q_D(QWebEngineView); d->q_ptr = this; + setAcceptDrops(true); // This causes the child RenderWidgetHostViewQtDelegateWidgets to fill this widget. setLayout(new QStackedLayout); @@ -312,6 +313,40 @@ void QWebEngineView::hideEvent(QHideEvent *event) page()->d_ptr->wasHidden(); } +void QWebEngineView::dragEnterEvent(QDragEnterEvent *e) +{ + Q_D(QWebEngineView); + e->accept(); + d->page->d_ptr->adapter->enterDrag(e, mapToGlobal(e->pos())); +} + +void QWebEngineView::dragLeaveEvent(QDragLeaveEvent *e) +{ + Q_D(QWebEngineView); + e->accept(); + d->page->d_ptr->adapter->leaveDrag(); +} + +void QWebEngineView::dragMoveEvent(QDragMoveEvent *e) +{ + Q_D(QWebEngineView); + QtWebEngineCore::WebContentsAdapter *adapter = d->page->d_ptr->adapter.data(); + Qt::DropAction dropAction = adapter->updateDragPosition(e, mapToGlobal(e->pos())); + if (Qt::IgnoreAction == dropAction) { + e->ignore(); + } else { + e->setDropAction(dropAction); + e->accept(); + } +} + +void QWebEngineView::dropEvent(QDropEvent *e) +{ + Q_D(QWebEngineView); + e->accept(); + d->page->d_ptr->adapter->endDragging(e->pos(), mapToGlobal(e->pos())); +} + #ifndef QT_NO_ACCESSIBILITY int QWebEngineViewAccessible::childCount() const { diff --git a/src/webenginewidgets/api/qwebengineview.h b/src/webenginewidgets/api/qwebengineview.h index e16bbf4af..432813395 100644 --- a/src/webenginewidgets/api/qwebengineview.h +++ b/src/webenginewidgets/api/qwebengineview.h @@ -122,6 +122,10 @@ protected: virtual bool event(QEvent*) Q_DECL_OVERRIDE; virtual void showEvent(QShowEvent *) Q_DECL_OVERRIDE; virtual void hideEvent(QHideEvent *) Q_DECL_OVERRIDE; + void dragEnterEvent(QDragEnterEvent *e) Q_DECL_OVERRIDE; + void dragLeaveEvent(QDragLeaveEvent *e) Q_DECL_OVERRIDE; + void dragMoveEvent(QDragMoveEvent *e) Q_DECL_OVERRIDE; + void dropEvent(QDropEvent *e) Q_DECL_OVERRIDE; private: Q_DISABLE_COPY(QWebEngineView) -- cgit v1.2.3