tdf#130857 qt: Extract helpers to convert Qt drag/drop to LO events

Extract some logic from QtFrame to helper functions,
in order to reuse that for QtInstanceWidget in an upcoming
commit.

Logic to multiply the scale factor/device pixel ratio
remains in QtFrame as it is specific to that one.

Change-Id: I6a155b404d9af31a244a5bcc8b5f78ee3b90d55d
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/187245
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
Tested-by: Jenkins
This commit is contained in:
Michael Weghorn
2025-07-01 20:05:54 +02:00
parent 9c9e53d3ba
commit cc4dbbf714
3 changed files with 130 additions and 89 deletions
+8
View File
@@ -21,6 +21,8 @@
#include <config_vclplug.h>
#include "QtDragAndDrop.hxx"
#include <QtCore/QDate>
#include <QtCore/QPoint>
#include <QtCore/QRect>
@@ -40,6 +42,7 @@
#include <vcl/qt/QtUtils.hxx>
#include <vcl/vclenum.hxx>
#include <com/sun/star/datatransfer/dnd/DropTargetDragEnterEvent.hpp>
#include <com/sun/star/lang/Locale.hpp>
#include <com/sun/star/uno/Sequence.hxx>
#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
@@ -97,6 +100,11 @@ inline Date toDate(const QDate& rDate) { return Date(rDate.day(), rDate.month(),
Qt::DropActions toQtDropActions(sal_Int8 dragOperation);
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);
Qt::DropAction getPreferredDropAction(sal_Int8 dragOperation);
inline QList<int> toQList(const css::uno::Sequence<sal_Int32>& aSequence)
+12 -89
View File
@@ -1346,86 +1346,21 @@ void QtFrame::registerDropTarget(QtDropTarget* pDropTarget)
GetQtInstance().RunInMainThread([this]() { m_pQWidget->setAcceptDrops(true); });
}
static css::uno::Reference<css::datatransfer::XTransferable>
lcl_getXTransferable(const QMimeData* pMimeData)
{
css::uno::Reference<css::datatransfer::XTransferable> xTransferable;
const QtMimeData* pQtMimeData = qobject_cast<const QtMimeData*>(pMimeData);
if (!pQtMimeData)
xTransferable = new QtDnDTransferable(pMimeData);
else
xTransferable = pQtMimeData->xTransferable();
return xTransferable;
}
static sal_Int8 lcl_getUserDropAction(const QDropEvent* pEvent, const sal_Int8 nSourceActions,
const QMimeData* pMimeData)
{
// we completely ignore all proposals by the Qt event, as they don't
// match at all with the preferred LO DnD actions.
// check the key modifiers to detect a user-overridden DnD action
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
const Qt::KeyboardModifiers eKeyMod = pEvent->modifiers();
#else
const Qt::KeyboardModifiers eKeyMod = pEvent->keyboardModifiers();
#endif
sal_Int8 nUserDropAction = 0;
if ((eKeyMod & Qt::ShiftModifier) && !(eKeyMod & Qt::ControlModifier))
nUserDropAction = css::datatransfer::dnd::DNDConstants::ACTION_MOVE;
else if ((eKeyMod & Qt::ControlModifier) && !(eKeyMod & Qt::ShiftModifier))
nUserDropAction = css::datatransfer::dnd::DNDConstants::ACTION_COPY;
else if ((eKeyMod & Qt::ShiftModifier) && (eKeyMod & Qt::ControlModifier))
nUserDropAction = css::datatransfer::dnd::DNDConstants::ACTION_LINK;
nUserDropAction &= nSourceActions;
// select the default DnD action, if there isn't a user preference
if (0 == nUserDropAction)
{
// default LO internal action is move, but default external action is copy
nUserDropAction = qobject_cast<const QtMimeData*>(pMimeData)
? css::datatransfer::dnd::DNDConstants::ACTION_MOVE
: css::datatransfer::dnd::DNDConstants::ACTION_COPY;
nUserDropAction &= nSourceActions;
// if the default doesn't match any allowed source action, fall back to the
// preferred of all allowed source actions
if (0 == nUserDropAction)
nUserDropAction = toVclDropAction(getPreferredDropAction(nSourceActions));
// this is "our" preference, but actually we would even prefer any default,
// if there is any
nUserDropAction |= css::datatransfer::dnd::DNDConstants::ACTION_DEFAULT;
}
return nUserDropAction;
}
void QtFrame::handleDragMove(QDragMoveEvent* pEvent)
{
assert(pEvent);
assert(m_pDropTarget);
// prepare our suggested drop action for the drop target
const sal_Int8 nSourceActions = toVclDropActions(pEvent->possibleActions());
const QMimeData* pMimeData = pEvent->mimeData();
const sal_Int8 nUserDropAction = lcl_getUserDropAction(pEvent, nSourceActions, pMimeData);
css::datatransfer::dnd::DropTargetDragEnterEvent aEvent
= toVclDropTargetDragEnterEvent(*pEvent, m_pDropTarget, !m_bInDrag);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
const QPoint aPos = pEvent->position().toPoint() * devicePixelRatioF();
#else
const QPoint aPos = pEvent->pos() * devicePixelRatioF();
#endif
css::datatransfer::dnd::DropTargetDragEnterEvent aEvent;
aEvent.Source = static_cast<css::datatransfer::dnd::XDropTarget*>(m_pDropTarget);
aEvent.Context = static_cast<css::datatransfer::dnd::XDropTargetDragContext*>(m_pDropTarget);
aEvent.LocationX = aPos.x();
aEvent.LocationY = aPos.y();
aEvent.DropAction = nUserDropAction;
aEvent.SourceActions = nSourceActions;
const qreal fDevicePixelRatio = devicePixelRatioF();
aEvent.LocationX *= fDevicePixelRatio;
aEvent.LocationY *= fDevicePixelRatio;
// ask the drop target to accept our drop action
if (!m_bInDrag)
{
aEvent.SupportedDataFlavors = lcl_getXTransferable(pMimeData)->getTransferDataFlavors();
m_pDropTarget->fire_dragEnter(aEvent);
m_bInDrag = true;
}
@@ -1444,27 +1379,15 @@ void QtFrame::handleDragMove(QDragMoveEvent* pEvent)
void QtFrame::handleDrop(QDropEvent* pEvent)
{
assert(pEvent);
assert(m_pDropTarget);
// prepare our suggested drop action for the drop target
const sal_Int8 nSourceActions = toVclDropActions(pEvent->possibleActions());
const sal_Int8 nUserDropAction
= lcl_getUserDropAction(pEvent, nSourceActions, pEvent->mimeData());
css::datatransfer::dnd::DropTargetDropEvent aEvent
= toVclDropTargetDropEvent(*pEvent, m_pDropTarget);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
const QPoint aPos = pEvent->position().toPoint() * devicePixelRatioF();
#else
const QPoint aPos = pEvent->pos() * devicePixelRatioF();
#endif
css::datatransfer::dnd::DropTargetDropEvent aEvent;
aEvent.Source = static_cast<css::datatransfer::dnd::XDropTarget*>(m_pDropTarget);
aEvent.Context = static_cast<css::datatransfer::dnd::XDropTargetDropContext*>(m_pDropTarget);
aEvent.LocationX = aPos.x();
aEvent.LocationY = aPos.y();
aEvent.SourceActions = nSourceActions;
aEvent.DropAction = nUserDropAction;
aEvent.Transferable = lcl_getXTransferable(pEvent->mimeData());
const qreal fDevicePixelRatio = devicePixelRatioF();
aEvent.LocationX *= fDevicePixelRatio;
aEvent.LocationY *= fDevicePixelRatio;
// ask the drop target to accept our drop action
m_pDropTarget->fire_drop(aEvent);
+110
View File
@@ -18,8 +18,10 @@
*/
#include <QtTools.hxx>
#include <QtFont.hxx>
#include <QtFontFace.hxx>
#include <QtTransferable.hxx>
#include <unx/fontmanager.hxx>
#include <cairo.h>
@@ -229,6 +231,114 @@ sal_Int8 toVclDropAction(Qt::DropAction dragOperation)
return nRet;
}
static css::uno::Reference<css::datatransfer::XTransferable>
lcl_getXTransferable(const QMimeData* pMimeData)
{
css::uno::Reference<css::datatransfer::XTransferable> xTransferable;
const QtMimeData* pQtMimeData = qobject_cast<const QtMimeData*>(pMimeData);
if (!pQtMimeData)
xTransferable = new QtDnDTransferable(pMimeData);
else
xTransferable = pQtMimeData->xTransferable();
return xTransferable;
}
static sal_Int8 lcl_getUserDropAction(const QDropEvent& rEvent, const sal_Int8 nSourceActions,
const QMimeData* pMimeData)
{
// we completely ignore all proposals by the Qt event, as they don't
// match at all with the preferred LO DnD actions.
// check the key modifiers to detect a user-overridden DnD action
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
const Qt::KeyboardModifiers eKeyMod = rEvent.modifiers();
#else
const Qt::KeyboardModifiers eKeyMod = rEvent.keyboardModifiers();
#endif
sal_Int8 nUserDropAction = 0;
if ((eKeyMod & Qt::ShiftModifier) && !(eKeyMod & Qt::ControlModifier))
nUserDropAction = css::datatransfer::dnd::DNDConstants::ACTION_MOVE;
else if ((eKeyMod & Qt::ControlModifier) && !(eKeyMod & Qt::ShiftModifier))
nUserDropAction = css::datatransfer::dnd::DNDConstants::ACTION_COPY;
else if ((eKeyMod & Qt::ShiftModifier) && (eKeyMod & Qt::ControlModifier))
nUserDropAction = css::datatransfer::dnd::DNDConstants::ACTION_LINK;
nUserDropAction &= nSourceActions;
// select the default DnD action, if there isn't a user preference
if (0 == nUserDropAction)
{
// default LO internal action is move, but default external action is copy
nUserDropAction = qobject_cast<const QtMimeData*>(pMimeData)
? css::datatransfer::dnd::DNDConstants::ACTION_MOVE
: css::datatransfer::dnd::DNDConstants::ACTION_COPY;
nUserDropAction &= nSourceActions;
// if the default doesn't match any allowed source action, fall back to the
// preferred of all allowed source actions
if (0 == nUserDropAction)
nUserDropAction = toVclDropAction(getPreferredDropAction(nSourceActions));
// this is "our" preference, but actually we would even prefer any default,
// if there is any
nUserDropAction |= css::datatransfer::dnd::DNDConstants::ACTION_DEFAULT;
}
return nUserDropAction;
}
css::datatransfer::dnd::DropTargetDragEnterEvent
toVclDropTargetDragEnterEvent(const QDragMoveEvent& rEvent, QtDropTarget* pDropTarget,
bool bSetDataFlavors)
{
// prepare our suggested drop action for the drop target
const sal_Int8 nSourceActions = toVclDropActions(rEvent.possibleActions());
const QMimeData* pMimeData = rEvent.mimeData();
const sal_Int8 nUserDropAction = lcl_getUserDropAction(rEvent, nSourceActions, pMimeData);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
const QPoint aPos = rEvent.position().toPoint();
#else
const QPoint aPos = rEvent.pos();
#endif
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.DropAction = nUserDropAction;
aEvent.SourceActions = nSourceActions;
if (bSetDataFlavors)
aEvent.SupportedDataFlavors = lcl_getXTransferable(pMimeData)->getTransferDataFlavors();
return aEvent;
}
css::datatransfer::dnd::DropTargetDropEvent toVclDropTargetDropEvent(const QDropEvent& rEvent,
QtDropTarget* pDropTarget)
{
// prepare our suggested drop action for the drop target
const sal_Int8 nSourceActions = toVclDropActions(rEvent.possibleActions());
const sal_Int8 nUserDropAction
= lcl_getUserDropAction(rEvent, nSourceActions, rEvent.mimeData());
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
const QPoint aPos = rEvent.position().toPoint();
#else
const QPoint aPos = rEvent.pos();
#endif
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.SourceActions = nSourceActions;
aEvent.DropAction = nUserDropAction;
aEvent.Transferable = lcl_getXTransferable(rEvent.mimeData());
return aEvent;
}
Qt::DropAction getPreferredDropAction(sal_Int8 dragOperation)
{
Qt::DropAction eAct = Qt::IgnoreAction;