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:
@@ -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
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user