vcl/inc/DropTarget.hxx | 2 - vcl/inc/qt5/QtDragAndDrop.hxx | 7 +++- vcl/inc/qt5/QtFrame.hxx | 2 - vcl/inc/qt5/QtTools.hxx | 6 +-- vcl/qt5/QtDragAndDrop.cxx | 47 +++++++++++++++++++++++++++++- vcl/qt5/QtFrame.cxx | 64 +++++++----------------------------------- vcl/qt5/QtTools.cxx | 14 ++++----- vcl/qt5/QtWidget.cxx | 8 ----- 8 files changed, 76 insertions(+), 74 deletions(-)
New commits: commit 0582d5af672def2daeaf5042aed1bcceb1a7a7d7 Author: Michael Weghorn <[email protected]> AuthorDate: Wed Jul 23 13:36:22 2025 +0200 Commit: Michael Weghorn <[email protected]> CommitDate: Wed Jul 23 22:55:55 2025 +0200 tdf#130857 qt dnd: Move some logic from QtFrame to QtDropTarget Move most of the logic to handle the various Qt drop event types from QtFrame to QtDropTarget. This will allow reusing the logic in an upcoming commit implementing QtInstanceWidget::get_drop_target. The order in QtFrame::handleDrop slightly changes as the drag source is now notified after the QEvent has been accepted, but that shouldn't be relevant. No change in behavior expected or seen in a quick test of dragging and dropping text from Kate or Gedit to Writer and vice versa or between two Writer windows. Change-Id: I2b4df4459028b7c2b1da300306e12f032a7605ff Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188231 Reviewed-by: Michael Weghorn <[email protected]> Tested-by: Jenkins diff --git a/vcl/inc/DropTarget.hxx b/vcl/inc/DropTarget.hxx index 00686524ff9a..dc7a53b75707 100644 --- a/vcl/inc/DropTarget.hxx +++ b/vcl/inc/DropTarget.hxx @@ -41,7 +41,7 @@ public: void dragEnter(const css::datatransfer::dnd::DropTargetDragEnterEvent& dtde) noexcept; void dragExit() noexcept; void dragOver(const css::datatransfer::dnd::DropTargetDragEvent& dtde) noexcept; - virtual void drop(const css::datatransfer::dnd::DropTargetDropEvent& dtde) noexcept; + void drop(const css::datatransfer::dnd::DropTargetDropEvent& dtde) noexcept; // XDropTarget virtual void SAL_CALL addDropTargetListener( diff --git a/vcl/inc/qt5/QtDragAndDrop.hxx b/vcl/inc/qt5/QtDragAndDrop.hxx index 364431994fbb..c999718b8f3a 100644 --- a/vcl/inc/qt5/QtDragAndDrop.hxx +++ b/vcl/inc/qt5/QtDragAndDrop.hxx @@ -18,6 +18,9 @@ #include <cppuhelper/compbase.hxx> #include <QtCore/QObject> +#include <QtGui/QDragEnterEvent> +#include <QtGui/QDragMoveEvent> +#include <QtGui/QDropEvent> class QtFrame; @@ -83,7 +86,9 @@ public: sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override; css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; - virtual void drop(const css::datatransfer::dnd::DropTargetDropEvent& dtde) noexcept override; + void handleDragEnterEvent(QDragEnterEvent& rEvent, qreal fScaleFactor); + void handleDragMoveEvent(QDragMoveEvent& rEvent, qreal fScaleFactor); + void handleDropEvent(QDropEvent& rEvent, qreal fScaleFactor); sal_Int8 proposedDropAction() const { return m_nDropAction; } bool dropSuccessful() const { return m_bDropSuccessful; } diff --git a/vcl/qt5/QtDragAndDrop.cxx b/vcl/qt5/QtDragAndDrop.cxx index 9a72758e3cbb..04c1198d0307 100644 --- a/vcl/qt5/QtDragAndDrop.cxx +++ b/vcl/qt5/QtDragAndDrop.cxx @@ -135,11 +135,54 @@ css::uno::Sequence<OUString> SAL_CALL QtDropTarget::getSupportedServiceNames() QtDropTarget::~QtDropTarget() {} -void QtDropTarget::drop(const css::datatransfer::dnd::DropTargetDropEvent& dtde) noexcept +void QtDropTarget::handleDragEnterEvent(QDragEnterEvent& rEvent, qreal fScaleFactor) +{ + css::datatransfer::dnd::DropTargetDragEnterEvent aEvent + = toVclDropTargetDragEnterEvent(rEvent, this, true, fScaleFactor); + dragEnter(aEvent); + + if (qobject_cast<const QtMimeData*>(rEvent.mimeData())) + rEvent.accept(); + else + rEvent.acceptProposedAction(); +} + +void QtDropTarget::handleDragMoveEvent(QDragMoveEvent& rEvent, qreal fScaleFactor) +{ + css::datatransfer::dnd::DropTargetDragEnterEvent aEvent + = toVclDropTargetDragEnterEvent(rEvent, this, false, fScaleFactor); + dragOver(aEvent); + + // the drop target accepted our drop action => inform Qt + if (proposedDropAction() != 0) + { + rEvent.setDropAction(getPreferredDropAction(proposedDropAction())); + rEvent.accept(); + } + else // or maybe someone else likes it? + rEvent.ignore(); +} + +void QtDropTarget::handleDropEvent(QDropEvent& rEvent, qreal fScaleFactor) { m_bDropSuccessful = true; - DropTarget::drop(dtde); + // ask the drop target to accept our drop action + css::datatransfer::dnd::DropTargetDropEvent aEvent + = toVclDropTargetDropEvent(rEvent, this, fScaleFactor); + drop(aEvent); + + const bool bDropSuccessful = dropSuccessful(); + const sal_Int8 nDropAction = proposedDropAction(); + + // the drop target accepted our drop action => inform Qt + if (bDropSuccessful) + { + rEvent.setDropAction(getPreferredDropAction(nDropAction)); + rEvent.accept(); + } + else // or maybe someone else likes it? + rEvent.ignore(); } void QtDropTarget::acceptDrag(sal_Int8 dragOperation) { m_nDropAction = dragOperation; } diff --git a/vcl/qt5/QtFrame.cxx b/vcl/qt5/QtFrame.cxx index 58728e574735..b1298b2075cb 100644 --- a/vcl/qt5/QtFrame.cxx +++ b/vcl/qt5/QtFrame.cxx @@ -1350,15 +1350,7 @@ void QtFrame::handleDragEnter(QDragEnterEvent* pEvent) assert(pEvent); assert(m_pDropTarget); - css::datatransfer::dnd::DropTargetDragEnterEvent aEvent - = toVclDropTargetDragEnterEvent(*pEvent, m_pDropTarget, true, devicePixelRatioF()); - - m_pDropTarget->dragEnter(aEvent); - - if (qobject_cast<const QtMimeData*>(pEvent->mimeData())) - pEvent->accept(); - else - pEvent->acceptProposedAction(); + m_pDropTarget->handleDragEnterEvent(*pEvent, devicePixelRatioF()); } void QtFrame::handleDragMove(QDragMoveEvent* pEvent) @@ -1366,19 +1358,7 @@ void QtFrame::handleDragMove(QDragMoveEvent* pEvent) assert(pEvent); assert(m_pDropTarget); - css::datatransfer::dnd::DropTargetDragEnterEvent aEvent - = toVclDropTargetDragEnterEvent(*pEvent, m_pDropTarget, false, devicePixelRatioF()); - - m_pDropTarget->dragOver(aEvent); - - // the drop target accepted our drop action => inform Qt - if (m_pDropTarget->proposedDropAction() != 0) - { - pEvent->setDropAction(getPreferredDropAction(m_pDropTarget->proposedDropAction())); - pEvent->accept(); - } - else // or maybe someone else likes it? - pEvent->ignore(); + m_pDropTarget->handleDragMoveEvent(*pEvent, devicePixelRatioF()); } void QtFrame::handleDrop(QDropEvent* pEvent) @@ -1386,14 +1366,7 @@ void QtFrame::handleDrop(QDropEvent* pEvent) assert(pEvent); assert(m_pDropTarget); - css::datatransfer::dnd::DropTargetDropEvent aEvent - = toVclDropTargetDropEvent(*pEvent, m_pDropTarget, devicePixelRatioF()); - - // ask the drop target to accept our drop action - m_pDropTarget->drop(aEvent); - - const bool bDropSuccessful = m_pDropTarget->dropSuccessful(); - const sal_Int8 nDropAction = m_pDropTarget->proposedDropAction(); + m_pDropTarget->handleDropEvent(*pEvent, devicePixelRatioF()); // inform the drag source of the drag-origin frame of the drop result if (pEvent->source()) @@ -1401,17 +1374,9 @@ void QtFrame::handleDrop(QDropEvent* pEvent) QtWidget* pWidget = qobject_cast<QtWidget*>(pEvent->source()); assert(pWidget); // AFAIK there shouldn't be any non-Qt5Widget as source in LO itself if (pWidget) - pWidget->frame().m_pDragSource->fire_dragEnd(nDropAction, bDropSuccessful); - } - - // the drop target accepted our drop action => inform Qt - if (bDropSuccessful) - { - pEvent->setDropAction(getPreferredDropAction(nDropAction)); - pEvent->accept(); + pWidget->frame().m_pDragSource->fire_dragEnd(m_pDropTarget->proposedDropAction(), + m_pDropTarget->dropSuccessful()); } - else // or maybe someone else likes it? - pEvent->ignore(); } void QtFrame::handleDragLeave() { m_pDropTarget->dragExit(); } commit f2d1f3fb783149ceba7757618f572d074dc095ed Author: Michael Weghorn <[email protected]> AuthorDate: Wed Jul 23 13:11:56 2025 +0200 Commit: Michael Weghorn <[email protected]> CommitDate: Wed Jul 23 22:55:50 2025 +0200 tdf#130857 qt dnd: Let helpers multiply scale factor Let the toVclDropTargetDragEnterEvent and toVclDropTargetDropEvent take the scale factor as a param and multiply it to the x and y coords in there instead of doing so in a separate step in QtFrame after calling the helper functions. This will allow moving more logic from QtFrame to QtDropTarget in an upcoming commit to prepare for implementing QtInstanceWidget::get_drop_target etc. without duplicating that logic. Change-Id: I152614be5db73378e4d7ec965975a68c19203a8b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188230 Tested-by: Jenkins Reviewed-by: Michael Weghorn <[email protected]> diff --git a/vcl/inc/qt5/QtTools.hxx b/vcl/inc/qt5/QtTools.hxx index ea35710bc9b6..c97d87f4c881 100644 --- a/vcl/inc/qt5/QtTools.hxx +++ b/vcl/inc/qt5/QtTools.hxx @@ -105,9 +105,9 @@ sal_Int8 toVclDropActions(Qt::DropActions dragOperation); sal_Int8 toVclDropAction(Qt::DropAction dragOperation); css::datatransfer::dnd::DropTargetDragEnterEvent toVclDropTargetDragEnterEvent(const QDragMoveEvent& rEvent, QtDropTarget* pDropTarget, - bool bSetDataFlavors); -css::datatransfer::dnd::DropTargetDropEvent toVclDropTargetDropEvent(const QDropEvent& rEvent, - QtDropTarget* pDropTarget); + bool bSetDataFlavors, qreal fScaleFactor); +css::datatransfer::dnd::DropTargetDropEvent +toVclDropTargetDropEvent(const QDropEvent& rEvent, QtDropTarget* pDropTarget, qreal fScaleFactor); Qt::DropAction getPreferredDropAction(sal_Int8 dragOperation); inline QList<int> toQList(const css::uno::Sequence<sal_Int32>& aSequence) diff --git a/vcl/qt5/QtFrame.cxx b/vcl/qt5/QtFrame.cxx index 68ac5a9f7b53..58728e574735 100644 --- a/vcl/qt5/QtFrame.cxx +++ b/vcl/qt5/QtFrame.cxx @@ -1351,11 +1351,7 @@ void QtFrame::handleDragEnter(QDragEnterEvent* pEvent) assert(m_pDropTarget); css::datatransfer::dnd::DropTargetDragEnterEvent aEvent - = toVclDropTargetDragEnterEvent(*pEvent, m_pDropTarget, true); - - const qreal fDevicePixelRatio = devicePixelRatioF(); - aEvent.LocationX *= fDevicePixelRatio; - aEvent.LocationY *= fDevicePixelRatio; + = toVclDropTargetDragEnterEvent(*pEvent, m_pDropTarget, true, devicePixelRatioF()); m_pDropTarget->dragEnter(aEvent); @@ -1371,11 +1367,7 @@ void QtFrame::handleDragMove(QDragMoveEvent* pEvent) assert(m_pDropTarget); css::datatransfer::dnd::DropTargetDragEnterEvent aEvent - = toVclDropTargetDragEnterEvent(*pEvent, m_pDropTarget, false); - - const qreal fDevicePixelRatio = devicePixelRatioF(); - aEvent.LocationX *= fDevicePixelRatio; - aEvent.LocationY *= fDevicePixelRatio; + = toVclDropTargetDragEnterEvent(*pEvent, m_pDropTarget, false, devicePixelRatioF()); m_pDropTarget->dragOver(aEvent); @@ -1395,11 +1387,7 @@ void QtFrame::handleDrop(QDropEvent* pEvent) assert(m_pDropTarget); css::datatransfer::dnd::DropTargetDropEvent aEvent - = toVclDropTargetDropEvent(*pEvent, m_pDropTarget); - - const qreal fDevicePixelRatio = devicePixelRatioF(); - aEvent.LocationX *= fDevicePixelRatio; - aEvent.LocationY *= fDevicePixelRatio; + = toVclDropTargetDropEvent(*pEvent, m_pDropTarget, devicePixelRatioF()); // ask the drop target to accept our drop action m_pDropTarget->drop(aEvent); diff --git a/vcl/qt5/QtTools.cxx b/vcl/qt5/QtTools.cxx index b94cd2f0d11d..e17936ebfa9c 100644 --- a/vcl/qt5/QtTools.cxx +++ b/vcl/qt5/QtTools.cxx @@ -318,7 +318,7 @@ static sal_Int8 lcl_getUserDropAction(const QDropEvent& rEvent, const sal_Int8 n css::datatransfer::dnd::DropTargetDragEnterEvent toVclDropTargetDragEnterEvent(const QDragMoveEvent& rEvent, QtDropTarget* pDropTarget, - bool bSetDataFlavors) + bool bSetDataFlavors, qreal fScaleFactor) { // prepare our suggested drop action for the drop target const sal_Int8 nSourceActions = toVclDropActions(rEvent.possibleActions()); @@ -334,8 +334,8 @@ toVclDropTargetDragEnterEvent(const QDragMoveEvent& rEvent, QtDropTarget* pDropT css::datatransfer::dnd::DropTargetDragEnterEvent aEvent; aEvent.Source = static_cast<css::datatransfer::dnd::XDropTarget*>(pDropTarget); aEvent.Context = pDropTarget; - aEvent.LocationX = aPos.x(); - aEvent.LocationY = aPos.y(); + aEvent.LocationX = aPos.x() * fScaleFactor; + aEvent.LocationY = aPos.y() * fScaleFactor; aEvent.DropAction = nUserDropAction; aEvent.SourceActions = nSourceActions; @@ -345,8 +345,8 @@ toVclDropTargetDragEnterEvent(const QDragMoveEvent& rEvent, QtDropTarget* pDropT return aEvent; } -css::datatransfer::dnd::DropTargetDropEvent toVclDropTargetDropEvent(const QDropEvent& rEvent, - QtDropTarget* pDropTarget) +css::datatransfer::dnd::DropTargetDropEvent +toVclDropTargetDropEvent(const QDropEvent& rEvent, QtDropTarget* pDropTarget, qreal fScaleFactor) { // prepare our suggested drop action for the drop target const sal_Int8 nSourceActions = toVclDropActions(rEvent.possibleActions()); @@ -362,8 +362,8 @@ css::datatransfer::dnd::DropTargetDropEvent toVclDropTargetDropEvent(const QDrop css::datatransfer::dnd::DropTargetDropEvent aEvent; aEvent.Source = static_cast<css::datatransfer::dnd::XDropTarget*>(pDropTarget); aEvent.Context = pDropTarget; - aEvent.LocationX = aPos.x(); - aEvent.LocationY = aPos.y(); + aEvent.LocationX = aPos.x() * fScaleFactor; + aEvent.LocationY = aPos.y() * fScaleFactor; aEvent.SourceActions = nSourceActions; aEvent.DropAction = nUserDropAction; aEvent.Transferable = lcl_getXTransferable(rEvent.mimeData()); commit 171a9fc90a80b36ef4f1c842d4c77bdcb416eb92 Author: Michael Weghorn <[email protected]> AuthorDate: Wed Jul 23 12:08:33 2025 +0200 Commit: Michael Weghorn <[email protected]> CommitDate: Wed Jul 23 22:55:44 2025 +0200 tdf#130857 qt dnd: Align QDragEnterEvent handling with other DnD events For all of the other Drag'n'Drop events, QtWidget forwards them to the QtFrame and that one implements the logic, but for the QDragEnterEvent in QtWidget::dragEnterEvent, QtWidget was handling it directly. However, then the handling of the QDragMoveEvent in QtFrame::handleDragMove (called from QtWidget::drageMoveEvent) was still handling the first time it was called specially, by calling QtDropTarget::dragEnter and setting QtFrame::m_bInDrag to true, i.e. it was implementing logic that sounds actually related to the QDragEnterEvent, not the QDragMoveEvent. Instead, also forward the QDragEnterEvent from the QtWidget to its QtFrame and consider that one the start of the drag action (call QtDropTarget::dragEnter there instead) and move the previous logic from QtWidget::dragEnterEvent to accept the event there, too. The QDragEnterEvent doc [1] says: > A widget must accept this event in order to receive > the drag move events that are sent while the drag and > drop action is in progress. The drag enter event is > always immediately followed by a drag move event. Therefore, even without this change in place, QtDropTarget::dragEnter would be called instantly after the processing of the QDragEnterEvent when the subsequent QDragMoveEvent was handled, but doing that when the actual enter event occurs seems more logical (and straightforward) to me, as each of the Qt events now results in the corresponding method to notify listeners of the QtDropTarget getting called: * QDragEnterEvent: QtDropTarget::dragEnter * QDragMoveEvent: QtDropTarget::dragOver * QDropEvent: QtDropTarget::drop * QDragLeaveEvent: QtDropTarget::dragExit This also means that QtFrame::m_bInDrag is no longer needed to distinguis the first QDragMoveEvent (directly following the QDragEnterEvent) from later ones, so drop that member. No change in behavior expected or seen in a quick test of dragging and dropping text from Kate or Gedit to Writer and vice versa or between two Writer windows. [1] https://doc.qt.io/qt-6/qdragenterevent.html#details Change-Id: I3878ca79aaf81af7fd36335bf2f90ccf0be9bf63 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188229 Tested-by: Jenkins Reviewed-by: Michael Weghorn <[email protected]> diff --git a/vcl/inc/qt5/QtFrame.hxx b/vcl/inc/qt5/QtFrame.hxx index 4e3f00a59353..d57cf20e1502 100644 --- a/vcl/inc/qt5/QtFrame.hxx +++ b/vcl/inc/qt5/QtFrame.hxx @@ -95,7 +95,6 @@ class VCLPLUG_QT_PUBLIC QtFrame : public QObject, public SalFrame QPointer<QtDragSource> m_pDragSource; QPointer<QtDropTarget> m_pDropTarget; - bool m_bInDrag; bool m_bDefaultSize; bool m_bDefaultPos; @@ -165,6 +164,7 @@ public: void registerDragSource(QtDragSource* pDragSource); void registerDropTarget(QtDropTarget* pDropTarget); + void handleDragEnter(QDragEnterEvent* pEvent); void handleDragLeave(); void handleDragMove(QDragMoveEvent* pEvent); void handleDrop(QDropEvent* pEvent); diff --git a/vcl/qt5/QtFrame.cxx b/vcl/qt5/QtFrame.cxx index b67ed31017d2..68ac5a9f7b53 100644 --- a/vcl/qt5/QtFrame.cxx +++ b/vcl/qt5/QtFrame.cxx @@ -77,7 +77,6 @@ QtFrame::QtFrame(QtFrame* pParent, SalFrameStyleFlags nStyle, bool bUseCairo) , m_ePointerStyle(PointerStyle::Arrow) , m_pDragSource(nullptr) , m_pDropTarget(nullptr) - , m_bInDrag(false) , m_bDefaultSize(true) , m_bDefaultPos(true) , m_bFullScreen(false) @@ -1346,26 +1345,39 @@ void QtFrame::registerDropTarget(QtDropTarget* pDropTarget) GetQtInstance().RunInMainThread([this]() { m_pQWidget->setAcceptDrops(true); }); } -void QtFrame::handleDragMove(QDragMoveEvent* pEvent) +void QtFrame::handleDragEnter(QDragEnterEvent* pEvent) { assert(pEvent); assert(m_pDropTarget); css::datatransfer::dnd::DropTargetDragEnterEvent aEvent - = toVclDropTargetDragEnterEvent(*pEvent, m_pDropTarget, !m_bInDrag); + = toVclDropTargetDragEnterEvent(*pEvent, m_pDropTarget, true); const qreal fDevicePixelRatio = devicePixelRatioF(); aEvent.LocationX *= fDevicePixelRatio; aEvent.LocationY *= fDevicePixelRatio; - // ask the drop target to accept our drop action - if (!m_bInDrag) - { - m_pDropTarget->dragEnter(aEvent); - m_bInDrag = true; - } + m_pDropTarget->dragEnter(aEvent); + + if (qobject_cast<const QtMimeData*>(pEvent->mimeData())) + pEvent->accept(); else - m_pDropTarget->dragOver(aEvent); + pEvent->acceptProposedAction(); +} + +void QtFrame::handleDragMove(QDragMoveEvent* pEvent) +{ + assert(pEvent); + assert(m_pDropTarget); + + css::datatransfer::dnd::DropTargetDragEnterEvent aEvent + = toVclDropTargetDragEnterEvent(*pEvent, m_pDropTarget, false); + + const qreal fDevicePixelRatio = devicePixelRatioF(); + aEvent.LocationX *= fDevicePixelRatio; + aEvent.LocationY *= fDevicePixelRatio; + + m_pDropTarget->dragOver(aEvent); // the drop target accepted our drop action => inform Qt if (m_pDropTarget->proposedDropAction() != 0) @@ -1391,7 +1403,6 @@ void QtFrame::handleDrop(QDropEvent* pEvent) // ask the drop target to accept our drop action m_pDropTarget->drop(aEvent); - m_bInDrag = false; const bool bDropSuccessful = m_pDropTarget->dropSuccessful(); const sal_Int8 nDropAction = m_pDropTarget->proposedDropAction(); @@ -1415,11 +1426,7 @@ void QtFrame::handleDrop(QDropEvent* pEvent) pEvent->ignore(); } -void QtFrame::handleDragLeave() -{ - m_pDropTarget->dragExit(); - m_bInDrag = false; -} +void QtFrame::handleDragLeave() { m_pDropTarget->dragExit(); } void QtFrame::handleMoveEvent(QMoveEvent*) { CallCallback(SalEvent::Move, nullptr); } diff --git a/vcl/qt5/QtWidget.cxx b/vcl/qt5/QtWidget.cxx index bed1dc319236..1d68099f1599 100644 --- a/vcl/qt5/QtWidget.cxx +++ b/vcl/qt5/QtWidget.cxx @@ -201,13 +201,7 @@ void QtWidget::wheelEvent(QWheelEvent* pEvent) pEvent->accept(); } -void QtWidget::dragEnterEvent(QDragEnterEvent* event) -{ - if (qobject_cast<const QtMimeData*>(event->mimeData())) - event->accept(); - else - event->acceptProposedAction(); -} +void QtWidget::dragEnterEvent(QDragEnterEvent* pEvent) { m_rFrame.handleDragEnter(pEvent); } // also called when a drop is rejected void QtWidget::dragLeaveEvent(QDragLeaveEvent*) { m_rFrame.handleDragLeave(); }
