summaryrefslogtreecommitdiff
path: root/vcl/qt5/Qt5Frame.cxx
diff options
context:
space:
mode:
authorJan-Marek Glogowski <jan-marek.glogowski@extern.cib.de>2019-08-08 17:59:20 +0000
committerJan-Marek Glogowski <glogow@fbihome.de>2019-08-22 14:29:03 +0200
commit3355be0616c24c5e44b71e7623c4191ed9c69074 (patch)
tree9343975454c1656c16222ac09bd0cc9e22a43dd4 /vcl/qt5/Qt5Frame.cxx
parentbafd4194b6ffbe4d6adfe01404196d787800dabe (diff)
tdf#126560 Qt5 fix D'n'D key-modifier handling
The patch has still one problem: the key-modifier state isn't reflected by the cursor, unless the user moves the mouse. There is an upstream Qt bug, reported in 2016-09 against Qt 5.6.1! It is supposed to be fixed in Qt 5.12, according to the bug report at https://bugreports.qt.io/browse/QTBUG-56218, which is still open. I thought about adding a configure test, but I couldn't imagine any realistic way to write it. And after Michael Weghorn found the bug is actually not fixed, as claimed in one of the comments, I decided to drop the warning. Change-Id: Ice8ebc4ea149282b4c1551e755efe3d4856cf782 Reviewed-on: https://gerrit.libreoffice.org/77174 Reviewed-by: Michael Weghorn <m.weghorn@posteo.de> Tested-by: Jenkins Reviewed-by: Jan-Marek Glogowski <glogow@fbihome.de>
Diffstat (limited to 'vcl/qt5/Qt5Frame.cxx')
-rw-r--r--vcl/qt5/Qt5Frame.cxx153
1 files changed, 108 insertions, 45 deletions
diff --git a/vcl/qt5/Qt5Frame.cxx b/vcl/qt5/Qt5Frame.cxx
index 142cb12aa199..cd850e6c3c0f 100644
--- a/vcl/qt5/Qt5Frame.cxx
+++ b/vcl/qt5/Qt5Frame.cxx
@@ -36,6 +36,8 @@
#include <QtCore/QPoint>
#include <QtCore/QSize>
#include <QtCore/QThread>
+#include <QtGui/QDragMoveEvent>
+#include <QtGui/QDropEvent>
#include <QtGui/QIcon>
#include <QtGui/QWindow>
#include <QtGui/QScreen>
@@ -1187,84 +1189,145 @@ void Qt5Frame::deregisterDropTarget(Qt5DropTarget const* pDropTarget)
m_pDropTarget = nullptr;
}
-void Qt5Frame::draggingStarted(const int x, const int y, Qt::DropActions eActions,
- Qt::KeyboardModifiers eKeyMod, const QMimeData* pQMimeData)
+static css::uno::Reference<css::datatransfer::XTransferable>
+lcl_getXTransferable(const QMimeData* pMimeData)
{
- assert(m_pDropTarget);
+ css::uno::Reference<css::datatransfer::XTransferable> xTransferable;
+ const Qt5MimeData* pQt5MimeData = dynamic_cast<const Qt5MimeData*>(pMimeData);
+ if (!pQt5MimeData)
+ xTransferable = new Qt5DnDTransferable(pMimeData);
+ else
+ xTransferable = pQt5MimeData->xTransferable();
+ return xTransferable;
+}
- sal_Int8 nUserDropAction = css::datatransfer::dnd::DNDConstants::ACTION_MOVE;
+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.
+ const sal_Int8 nFilterActions
+ = nSourceActions | css::datatransfer::dnd::DNDConstants::ACTION_DEFAULT;
+
+ // check the key modifiers to detect a user-overridden DnD action
+ const Qt::KeyboardModifiers eKeyMod = pEvent->keyboardModifiers();
+ 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 &= nFilterActions;
+
+ // 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 = dynamic_cast<const Qt5MimeData*>(pMimeData)
+ ? css::datatransfer::dnd::DNDConstants::ACTION_MOVE
+ : css::datatransfer::dnd::DNDConstants::ACTION_COPY;
+ nUserDropAction &= nFilterActions;
+
+ // 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 Qt5Frame::handleDragMove(QDragMoveEvent* 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;
aEvent.Source = static_cast<css::datatransfer::dnd::XDropTarget*>(m_pDropTarget);
aEvent.Context = static_cast<css::datatransfer::dnd::XDropTargetDragContext*>(m_pDropTarget);
- aEvent.LocationX = x;
- aEvent.LocationY = y;
-
- // system drop action if neither Shift nor Control is held
- if (!(eKeyMod & (Qt::ShiftModifier | Qt::ControlModifier)))
- aEvent.DropAction = getPreferredDropAction(eActions);
- // otherwise user-preferred action
- else
- aEvent.DropAction = nUserDropAction;
- aEvent.SourceActions = toVclDropActions(eActions);
+ aEvent.LocationX = pEvent->pos().x();
+ aEvent.LocationY = pEvent->pos().y();
+ aEvent.DropAction = nUserDropAction;
+ aEvent.SourceActions = nSourceActions;
- css::uno::Reference<css::datatransfer::XTransferable> xTransferable;
- if (!pQMimeData->hasFormat(sInternalMimeType))
- xTransferable = new Qt5DnDTransferable(pQMimeData);
- else
- xTransferable = Qt5DragSource::m_ActiveDragSource->GetTransferable();
-
- if (!m_bInDrag && xTransferable.is())
+ // ask the drop target to accept our drop action
+ if (!m_bInDrag)
{
- css::uno::Sequence<css::datatransfer::DataFlavor> aFormats
- = xTransferable->getTransferDataFlavors();
- aEvent.SupportedDataFlavors = aFormats;
-
+ aEvent.SupportedDataFlavors = lcl_getXTransferable(pMimeData)->getTransferDataFlavors();
m_pDropTarget->fire_dragEnter(aEvent);
m_bInDrag = true;
}
else
m_pDropTarget->fire_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();
}
-void Qt5Frame::dropping(const int x, const int y, Qt::KeyboardModifiers eKeyMod,
- const QMimeData* pQMimeData)
+void Qt5Frame::handleDrop(QDropEvent* 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;
aEvent.Source = static_cast<css::datatransfer::dnd::XDropTarget*>(m_pDropTarget);
aEvent.Context = static_cast<css::datatransfer::dnd::XDropTargetDropContext*>(m_pDropTarget);
- aEvent.LocationX = x;
- aEvent.LocationY = y;
-
- if (!(eKeyMod & (Qt::ShiftModifier | Qt::ControlModifier)))
- aEvent.DropAction = m_pDropTarget->proposedDragAction()
- | css::datatransfer::dnd::DNDConstants::ACTION_DEFAULT;
- else
- aEvent.DropAction = m_pDropTarget->proposedDragAction();
- aEvent.SourceActions = css::datatransfer::dnd::DNDConstants::ACTION_MOVE;
-
- css::uno::Reference<css::datatransfer::XTransferable> xTransferable;
- if (!pQMimeData->hasFormat(sInternalMimeType))
- xTransferable = new Qt5DnDTransferable(pQMimeData);
- else
- xTransferable = Qt5DragSource::m_ActiveDragSource->GetTransferable();
- aEvent.Transferable = xTransferable;
+ aEvent.LocationX = pEvent->pos().x();
+ aEvent.LocationY = pEvent->pos().y();
+ aEvent.SourceActions = nSourceActions;
+ aEvent.DropAction = nUserDropAction;
+ aEvent.Transferable = lcl_getXTransferable(pEvent->mimeData());
+ // ask the drop target to accept our drop action
m_pDropTarget->fire_drop(aEvent);
m_bInDrag = false;
- if (m_pDragSource)
+ const bool bDropSuccessful = m_pDropTarget->dropSuccessful();
+ const sal_Int8 nDropAction = m_pDropTarget->proposedDropAction();
+
+ // inform the drag source of the drag-origin frame of the drop result
+ if (pEvent->source())
{
- m_pDragSource->fire_dragEnd(m_pDropTarget->proposedDragAction());
+ Qt5Widget* pWidget = dynamic_cast<Qt5Widget*>(pEvent->source());
+ assert(pWidget); // AFAIK there shouldn't be any non-Qt5Widget as source in LO itself
+ if (pWidget)
+ pWidget->getFrame().m_pDragSource->fire_dragEnd(nDropAction, bDropSuccessful);
}
+
+ // the drop target accepted our drop action => inform Qt
+ if (bDropSuccessful)
+ {
+ pEvent->setDropAction(getPreferredDropAction(nDropAction));
+ pEvent->accept();
+ }
+ else // or maybe someone else likes it?
+ pEvent->ignore();
+}
+
+void Qt5Frame::handleDragLeave()
+{
+ css::datatransfer::dnd::DropTargetEvent aEvent;
+ aEvent.Source = static_cast<css::datatransfer::dnd::XDropTarget*>(m_pDropTarget);
+ m_pDropTarget->fire_dragExit(aEvent);
+ m_bInDrag = false;
}
cairo_t* Qt5Frame::getCairoContext() const