[Libreoffice-commits] core.git: vcl/inc vcl/qt5 vcl/unx

Jan-Marek Glogowski (via logerrit) logerrit at kemper.freedesktop.org
Thu Aug 22 12:29:46 UTC 2019


 vcl/inc/qt5/Qt5DragAndDrop.hxx  |   21 +----
 vcl/inc/qt5/Qt5Frame.hxx        |   10 +-
 vcl/inc/qt5/Qt5Tools.hxx        |    3 
 vcl/inc/qt5/Qt5Transferable.hxx |    2 
 vcl/inc/qt5/Qt5Widget.hxx       |    2 
 vcl/qt5/Qt5DragAndDrop.cxx      |   93 ++++++++----------------
 vcl/qt5/Qt5Frame.cxx            |  153 ++++++++++++++++++++++++++++------------
 vcl/qt5/Qt5Tools.cxx            |   12 +++
 vcl/qt5/Qt5Widget.cxx           |   32 +-------
 vcl/unx/kf5/KF5SalFrame.hxx     |    4 -
 10 files changed, 174 insertions(+), 158 deletions(-)

New commits:
commit 3355be0616c24c5e44b71e7623c4191ed9c69074
Author:     Jan-Marek Glogowski <jan-marek.glogowski at extern.cib.de>
AuthorDate: Thu Aug 8 17:59:20 2019 +0000
Commit:     Jan-Marek Glogowski <glogow at fbihome.de>
CommitDate: Thu Aug 22 14:29:03 2019 +0200

    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 at posteo.de>
    Tested-by: Jenkins
    Reviewed-by: Jan-Marek Glogowski <glogow at fbihome.de>

diff --git a/vcl/inc/qt5/Qt5DragAndDrop.hxx b/vcl/inc/qt5/Qt5DragAndDrop.hxx
index dcd6cb5e4048..0ec9ce5bbcb2 100644
--- a/vcl/inc/qt5/Qt5DragAndDrop.hxx
+++ b/vcl/inc/qt5/Qt5DragAndDrop.hxx
@@ -25,7 +25,6 @@ class Qt5DragSource
     osl::Mutex m_aMutex;
     Qt5Frame* m_pFrame;
     css::uno::Reference<css::datatransfer::dnd::XDragSourceListener> m_xListener;
-    css::uno::Reference<css::datatransfer::XTransferable> m_xTrans;
 
 public:
     Qt5DragSource()
@@ -55,17 +54,7 @@ public:
 
     css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
 
-    void dragFailed();
-    void fire_dragEnd(sal_Int8 nAction);
-
-    static Qt5DragSource* m_ActiveDragSource;
-    static bool m_bDropSuccessSet;
-    static bool m_bDropSuccess;
-
-    css::uno::Reference<css::datatransfer::XTransferable> const& GetTransferable() const
-    {
-        return m_xTrans;
-    }
+    void fire_dragEnd(sal_Int8 nAction, bool bSuccessful);
 };
 
 class Qt5DropTarget
@@ -76,11 +65,11 @@ class Qt5DropTarget
 {
     osl::Mutex m_aMutex;
     Qt5Frame* m_pFrame;
-    sal_Int8 mnDragAction;
-    sal_Int8 mnDropAction;
+    sal_Int8 m_nDropAction;
     bool m_bActive;
     sal_Int8 m_nDefaultActions;
     std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> m_aListeners;
+    bool m_bDropSuccessful;
 
 public:
     Qt5DropTarget();
@@ -115,10 +104,12 @@ public:
     css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
 
     void fire_dragEnter(const css::datatransfer::dnd::DropTargetDragEnterEvent& dtde);
+    void fire_dragExit(const css::datatransfer::dnd::DropTargetEvent& dte);
     void fire_dragOver(const css::datatransfer::dnd::DropTargetDragEnterEvent& dtde);
     void fire_drop(const css::datatransfer::dnd::DropTargetDropEvent& dtde);
 
-    sal_Int8 proposedDragAction() const { return mnDragAction; }
+    sal_Int8 proposedDropAction() const { return m_nDropAction; }
+    bool dropSuccessful() const { return m_bDropSuccessful; }
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/qt5/Qt5Frame.hxx b/vcl/inc/qt5/Qt5Frame.hxx
index 4c94b846bc93..e296ce92db29 100644
--- a/vcl/inc/qt5/Qt5Frame.hxx
+++ b/vcl/inc/qt5/Qt5Frame.hxx
@@ -56,6 +56,8 @@ class Qt5MainWindow;
 class Qt5Menu;
 class Qt5SvpGraphics;
 
+class QDragMoveEvent;
+class QDropEvent;
 class QImage;
 class QMimeData;
 class QPaintDevice;
@@ -159,10 +161,10 @@ public:
     virtual void deregisterDragSource(Qt5DragSource const* pDragSource);
     virtual void registerDropTarget(Qt5DropTarget* pDropTarget);
     virtual void deregisterDropTarget(Qt5DropTarget const* pDropTarget);
-    void draggingStarted(const int x, const int y, Qt::DropActions eActions,
-                         Qt::KeyboardModifiers eKeyMod, const QMimeData* pQMimeData);
-    void dropping(const int x, const int y, Qt::KeyboardModifiers eKeyMod,
-                  const QMimeData* pQMimeData);
+
+    void handleDragLeave();
+    void handleDragMove(QDragMoveEvent* pEvent);
+    void handleDrop(QDropEvent* pEvent);
 
     virtual void SetExtendedFrameStyle(SalExtStyle nExtStyle) override;
     virtual void Show(bool bVisible, bool bNoActivate = false) override;
diff --git a/vcl/inc/qt5/Qt5Tools.hxx b/vcl/inc/qt5/Qt5Tools.hxx
index 6b1fb1adcc7e..697b703e28f4 100644
--- a/vcl/inc/qt5/Qt5Tools.hxx
+++ b/vcl/inc/qt5/Qt5Tools.hxx
@@ -70,6 +70,7 @@ inline QColor toQColor(const Color& rColor)
 
 Qt::DropActions toQtDropActions(sal_Int8 dragOperation);
 sal_Int8 toVclDropActions(Qt::DropActions dragOperation);
+sal_Int8 toVclDropAction(Qt::DropAction dragOperation);
 Qt::DropAction getPreferredDropAction(sal_Int8 dragOperation);
 
 inline QList<int> toQList(const css::uno::Sequence<sal_Int32>& aSequence)
@@ -126,8 +127,6 @@ inline sal_uInt16 getFormatBits(QImage::Format eFormat)
     }
 }
 
-static const QString sInternalMimeType = "application/x-libreoffice-dnditem";
-
 typedef struct _cairo_surface cairo_surface_t;
 struct CairoDeleter
 {
diff --git a/vcl/inc/qt5/Qt5Transferable.hxx b/vcl/inc/qt5/Qt5Transferable.hxx
index df06661bb9fd..0d1cc70502aa 100644
--- a/vcl/inc/qt5/Qt5Transferable.hxx
+++ b/vcl/inc/qt5/Qt5Transferable.hxx
@@ -117,6 +117,8 @@ public:
     QStringList formats() const override;
 
     bool deepCopy(QMimeData** const) const;
+
+    css::datatransfer::XTransferable* xTransferable() const { return m_aContents.get(); }
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/qt5/Qt5Widget.hxx b/vcl/inc/qt5/Qt5Widget.hxx
index 85523951cda2..a69c86876a44 100644
--- a/vcl/inc/qt5/Qt5Widget.hxx
+++ b/vcl/inc/qt5/Qt5Widget.hxx
@@ -57,6 +57,7 @@ class Qt5Widget : public QWidget
     virtual void mousePressEvent(QMouseEvent*) override;
     virtual void mouseReleaseEvent(QMouseEvent*) override;
     virtual void dragEnterEvent(QDragEnterEvent*) override;
+    virtual void dragLeaveEvent(QDragLeaveEvent*) override;
     virtual void dragMoveEvent(QDragMoveEvent*) override;
     virtual void dropEvent(QDropEvent*) override;
     virtual void moveEvent(QMoveEvent*) override;
@@ -74,7 +75,6 @@ public:
     Qt5Widget(Qt5Frame& rFrame, Qt::WindowFlags f = Qt::WindowFlags());
 
     Qt5Frame& getFrame() const { return m_rFrame; }
-    void startDrag(sal_Int8 nSourceActions);
     void endExtTextInput();
 
     static bool handleEvent(Qt5Frame&, const QWidget&, QEvent*);
diff --git a/vcl/qt5/Qt5DragAndDrop.cxx b/vcl/qt5/Qt5DragAndDrop.cxx
index ea26d5aaeb6f..3f57f3bc303e 100644
--- a/vcl/qt5/Qt5DragAndDrop.cxx
+++ b/vcl/qt5/Qt5DragAndDrop.cxx
@@ -16,13 +16,12 @@
 
 #include <Qt5DragAndDrop.hxx>
 #include <Qt5Frame.hxx>
+#include <Qt5Transferable.hxx>
 #include <Qt5Widget.hxx>
 
-using namespace com::sun::star;
+#include <QtGui/QDrag>
 
-bool Qt5DragSource::m_bDropSuccessSet = false;
-bool Qt5DragSource::m_bDropSuccess = false;
-Qt5DragSource* Qt5DragSource::m_ActiveDragSource = nullptr;
+using namespace com::sun::star;
 
 Qt5DragSource::~Qt5DragSource() {}
 
@@ -60,52 +59,35 @@ void Qt5DragSource::startDrag(
     const css::uno::Reference<css::datatransfer::dnd::XDragSourceListener>& rListener)
 {
     m_xListener = rListener;
-    m_xTrans = rTrans;
 
     if (m_pFrame)
     {
-        Qt5Widget* qw = static_cast<Qt5Widget*>(m_pFrame->GetQWidget());
-        m_ActiveDragSource = this;
-        m_bDropSuccessSet = false;
-        m_bDropSuccess = false;
-        qw->startDrag(sourceActions);
+        QDrag* drag = new QDrag(m_pFrame->GetQWidget());
+        drag->setMimeData(new Qt5MimeData(rTrans));
+        // just a reminder that exec starts a nested event loop, so everything after
+        // this call is just executed, after D'n'D has finished!
+        drag->exec(toQtDropActions(sourceActions), getPreferredDropAction(sourceActions));
     }
-    else
-        dragFailed();
-}
 
-void Qt5DragSource::dragFailed()
-{
-    if (m_xListener.is())
-    {
-        datatransfer::dnd::DragSourceDropEvent aEv;
-        aEv.DropAction = datatransfer::dnd::DNDConstants::ACTION_NONE;
-        aEv.DropSuccess = false;
-        auto xListener = m_xListener;
-        m_xListener.clear();
-        xListener->dragDropEnd(aEv);
-    }
+    // the drop will eventually call fire_dragEnd, which will clear the listener.
+    // if D'n'D ends without success, we just get a leave event without any indicator,
+    // but the event loop will be terminated, so we have to try to inform the source of
+    // a failure in any way.
+    fire_dragEnd(datatransfer::dnd::DNDConstants::ACTION_NONE, false);
 }
 
-void Qt5DragSource::fire_dragEnd(sal_Int8 nAction)
+void Qt5DragSource::fire_dragEnd(sal_Int8 nAction, bool bDropSuccessful)
 {
     if (m_xListener.is())
     {
         datatransfer::dnd::DragSourceDropEvent aEv;
         aEv.DropAction = nAction;
-
-        // internal DnD can accept the drop
-        // but still fail in Qt5DropTarget::dropComplete
-        if (m_bDropSuccessSet)
-            aEv.DropSuccess = m_bDropSuccess;
-        else
-            aEv.DropSuccess = true;
+        aEv.DropSuccess = bDropSuccessful;
 
         auto xListener = m_xListener;
         m_xListener.clear();
         xListener->dragDropEnd(aEv);
     }
-    m_ActiveDragSource = nullptr;
 }
 
 OUString SAL_CALL Qt5DragSource::getImplementationName()
@@ -175,8 +157,7 @@ void Qt5DropTarget::initialize(const uno::Sequence<uno::Any>& rArguments)
                                     static_cast<OWeakObject*>(this));
     }
 
-    mnDragAction = datatransfer::dnd::DNDConstants::ACTION_NONE;
-    mnDropAction = datatransfer::dnd::DNDConstants::ACTION_NONE;
+    m_nDropAction = datatransfer::dnd::DNDConstants::ACTION_NONE;
 
     m_pFrame = reinterpret_cast<Qt5Frame*>(nFrame);
     m_pFrame->registerDropTarget(this);
@@ -239,6 +220,8 @@ void Qt5DropTarget::fire_dragOver(const css::datatransfer::dnd::DropTargetDragEn
 
 void Qt5DropTarget::fire_drop(const css::datatransfer::dnd::DropTargetDropEvent& dtde)
 {
+    m_bDropSuccessful = true;
+
     osl::ClearableGuard<osl::Mutex> aGuard(m_aMutex);
     std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners(
         m_aListeners);
@@ -250,40 +233,28 @@ void Qt5DropTarget::fire_drop(const css::datatransfer::dnd::DropTargetDropEvent&
     }
 }
 
-void Qt5DropTarget::acceptDrag(sal_Int8 dragOperation)
+void Qt5DropTarget::fire_dragExit(const css::datatransfer::dnd::DropTargetEvent& dte)
 {
-    mnDragAction = dragOperation;
-    return;
-}
+    osl::ClearableGuard<::osl::Mutex> aGuard(m_aMutex);
+    std::vector<css::uno::Reference<css::datatransfer::dnd::XDropTargetListener>> aListeners(
+        m_aListeners);
+    aGuard.clear();
 
-void Qt5DropTarget::rejectDrag()
-{
-    mnDragAction = 0;
-    return;
+    for (auto const& listener : aListeners)
+        listener->dragExit(dte);
 }
 
-void Qt5DropTarget::acceptDrop(sal_Int8 dropOperation)
-{
-    mnDropAction = dropOperation;
-    return;
-}
+void Qt5DropTarget::acceptDrag(sal_Int8 dragOperation) { m_nDropAction = dragOperation; }
 
-void Qt5DropTarget::rejectDrop()
-{
-    mnDropAction = 0;
-    return;
-}
+void Qt5DropTarget::rejectDrag() { m_nDropAction = 0; }
+
+void Qt5DropTarget::acceptDrop(sal_Int8 dropOperation) { m_nDropAction = dropOperation; }
+
+void Qt5DropTarget::rejectDrop() { m_nDropAction = 0; }
 
 void Qt5DropTarget::dropComplete(sal_Bool success)
 {
-    // internal DnD
-    if (Qt5DragSource::m_ActiveDragSource)
-    {
-        Qt5DragSource::m_bDropSuccessSet = true;
-        Qt5DragSource::m_bDropSuccess = success;
-    }
-
-    return;
+    m_bDropSuccessful = (m_bDropSuccessful && success);
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
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
diff --git a/vcl/qt5/Qt5Tools.cxx b/vcl/qt5/Qt5Tools.cxx
index cff661ba8a34..24e60b9e1375 100644
--- a/vcl/qt5/Qt5Tools.cxx
+++ b/vcl/qt5/Qt5Tools.cxx
@@ -80,6 +80,18 @@ sal_Int8 toVclDropActions(Qt::DropActions dragOperation)
     return nRet;
 }
 
+sal_Int8 toVclDropAction(Qt::DropAction dragOperation)
+{
+    sal_Int8 nRet(0);
+    if (dragOperation == Qt::CopyAction)
+        nRet = css::datatransfer::dnd::DNDConstants::ACTION_COPY;
+    else if (dragOperation == Qt::MoveAction)
+        nRet = css::datatransfer::dnd::DNDConstants::ACTION_MOVE;
+    else if (dragOperation == Qt::LinkAction)
+        nRet = css::datatransfer::dnd::DNDConstants::ACTION_LINK;
+    return nRet;
+}
+
 Qt::DropAction getPreferredDropAction(sal_Int8 dragOperation)
 {
     Qt::DropAction eAct = Qt::IgnoreAction;
diff --git a/vcl/qt5/Qt5Widget.cxx b/vcl/qt5/Qt5Widget.cxx
index f3dbfd516716..4c1c474aa159 100644
--- a/vcl/qt5/Qt5Widget.cxx
+++ b/vcl/qt5/Qt5Widget.cxx
@@ -24,6 +24,7 @@
 #include <Qt5Graphics.hxx>
 #include <Qt5Instance.hxx>
 #include <Qt5SvpGraphics.hxx>
+#include <Qt5Transferable.hxx>
 #include <Qt5Tools.hxx>
 
 #include <QtCore/QMimeData>
@@ -214,41 +215,20 @@ void Qt5Widget::wheelEvent(QWheelEvent* pEvent)
     pEvent->accept();
 }
 
-void Qt5Widget::startDrag(sal_Int8 nSourceActions)
-{
-    // internal drag source
-    QMimeData* mimeData = new QMimeData;
-    mimeData->setData(sInternalMimeType, nullptr);
-
-    QDrag* drag = new QDrag(this);
-    drag->setMimeData(mimeData);
-    drag->exec(toQtDropActions(nSourceActions), Qt::MoveAction);
-}
-
 void Qt5Widget::dragEnterEvent(QDragEnterEvent* event)
 {
-    if (event->mimeData()->hasFormat(sInternalMimeType))
+    if (dynamic_cast<const Qt5MimeData*>(event->mimeData()))
         event->accept();
     else
         event->acceptProposedAction();
 }
 
-void Qt5Widget::dragMoveEvent(QDragMoveEvent* event)
-{
-    QPoint point = event->pos();
+// also called when a drop is rejected
+void Qt5Widget::dragLeaveEvent(QDragLeaveEvent*) { m_rFrame.handleDragLeave(); }
 
-    m_rFrame.draggingStarted(point.x(), point.y(), event->possibleActions(),
-                             event->keyboardModifiers(), event->mimeData());
-    QWidget::dragMoveEvent(event);
-}
-
-void Qt5Widget::dropEvent(QDropEvent* event)
-{
-    QPoint point = event->pos();
+void Qt5Widget::dragMoveEvent(QDragMoveEvent* pEvent) { m_rFrame.handleDragMove(pEvent); }
 
-    m_rFrame.dropping(point.x(), point.y(), event->keyboardModifiers(), event->mimeData());
-    QWidget::dropEvent(event);
-}
+void Qt5Widget::dropEvent(QDropEvent* pEvent) { m_rFrame.handleDrop(pEvent); }
 
 void Qt5Widget::moveEvent(QMoveEvent* event)
 {
diff --git a/vcl/unx/kf5/KF5SalFrame.hxx b/vcl/unx/kf5/KF5SalFrame.hxx
index 091a5b019ca7..f757535c2f35 100644
--- a/vcl/unx/kf5/KF5SalFrame.hxx
+++ b/vcl/unx/kf5/KF5SalFrame.hxx
@@ -38,10 +38,6 @@ public:
     virtual SalGraphics* AcquireGraphics() override;
     virtual void ReleaseGraphics(SalGraphics* pGraphics) override;
     virtual void UpdateSettings(AllSettings& rSettings) override;
-
-    virtual LanguageType GetInputLanguage() override { return LANGUAGE_SYSTEM; }
-    virtual SalPointerState GetPointerState() override { return SalPointerState(); }
-    virtual KeyIndicatorState GetIndicatorState() override { return KeyIndicatorState(); }
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list