tdf#120772: implement file manager -> LibO DnD

not sure if we should support also other than URL list mimetypes

Change-Id: Ida3f65637247822198b04682a3d1a7c196a24e0c
Reviewed-on: https://gerrit.libreoffice.org/66997
Tested-by: Jenkins
Reviewed-by: Katarina Behrens <Katarina.Behrens@cib.de>
diff --git a/vcl/inc/qt5/Qt5DragAndDrop.hxx b/vcl/inc/qt5/Qt5DragAndDrop.hxx
index f5ffac3..7ad5dfc 100644
--- a/vcl/inc/qt5/Qt5DragAndDrop.hxx
+++ b/vcl/inc/qt5/Qt5DragAndDrop.hxx
@@ -11,6 +11,7 @@
#pragma once

#include <cppuhelper/compbase.hxx>
#include <Qt5Clipboard.hxx>

#include <com/sun/star/datatransfer/dnd/XDragSource.hpp>
#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
@@ -18,6 +19,20 @@
#include <com/sun/star/lang/XServiceInfo.hpp>

class Qt5Frame;
class QMimeData;

class Qt5DnDTransferable : public Qt5Transferable
{
public:
    Qt5DnDTransferable(const QMimeData* pMimeData);
    virtual css::uno::Any SAL_CALL
    getTransferData(const css::datatransfer::DataFlavor& rFlavor) override;

    virtual std::vector<css::datatransfer::DataFlavor> getTransferDataFlavorsAsVector() override;

private:
    const QMimeData* m_pMimeData;
};

class Qt5DragSource
    : public cppu::WeakComponentImplHelper<css::datatransfer::dnd::XDragSource,
diff --git a/vcl/inc/qt5/Qt5Frame.hxx b/vcl/inc/qt5/Qt5Frame.hxx
index e88c1ea..669833f 100644
--- a/vcl/inc/qt5/Qt5Frame.hxx
+++ b/vcl/inc/qt5/Qt5Frame.hxx
@@ -37,6 +37,7 @@ class QWidget;
class Qt5MainWindow;
class Qt5DragSource;
class Qt5DropTarget;
class QMimeData;
class QPaintDevice;
class QScreen;
class QImage;
@@ -136,8 +137,8 @@ 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);
    void dropping(const int x, const int y);
    void draggingStarted(const int x, const int y, const QMimeData* pQMimeData);
    void dropping(const int x, const int y, const QMimeData* pQMimeData);

    virtual void SetExtendedFrameStyle(SalExtStyle nExtStyle) override;
    virtual void Show(bool bVisible, bool bNoActivate = false) override;
diff --git a/vcl/qt5/Qt5DragAndDrop.cxx b/vcl/qt5/Qt5DragAndDrop.cxx
index 092c2b2..201f251 100644
--- a/vcl/qt5/Qt5DragAndDrop.cxx
+++ b/vcl/qt5/Qt5DragAndDrop.cxx
@@ -14,6 +14,9 @@
#include <cppuhelper/supportsservice.hxx>
#include <sal/log.hxx>

#include <QtCore/QMimeData>
#include <QtCore/QUrl>

#include <Qt5DragAndDrop.hxx>
#include <Qt5Frame.hxx>
#include <Qt5Widget.hxx>
@@ -22,6 +25,65 @@ using namespace com::sun::star;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;

Qt5DnDTransferable::Qt5DnDTransferable(const QMimeData* pMimeData)
    : m_pMimeData(pMimeData)
{
}

css::uno::Any Qt5DnDTransferable::getTransferData(const css::datatransfer::DataFlavor& rFlavor)
{
    uno::Any aAny;
    assert(m_pMimeData);

    // FIXME: not sure if we should support more mimetypes here
    // (how to carry out external DnD with anything else than [file] URL?)
    if (m_pMimeData->hasUrls())
    {
        QList<QUrl> urlList = m_pMimeData->urls();

        if (urlList.size() > 0)
        {
            //FIXME: multiple URLs, here we take only 1st one
            QString url = urlList.at(0).path();
            std::string aStr = url.toStdString();
            Sequence<sal_Int8> aSeq(reinterpret_cast<const sal_Int8*>(aStr.c_str()), aStr.length());
            aAny <<= aSeq;
        }
    }
    return aAny;
}

std::vector<css::datatransfer::DataFlavor> Qt5DnDTransferable::getTransferDataFlavorsAsVector()
{
    std::vector<css::datatransfer::DataFlavor> aVector;
    css::datatransfer::DataFlavor aFlavor;

    if (m_pMimeData)
    {
        for (QString& rMimeType : m_pMimeData->formats())
        {
            // filter out non-MIME types such as TARGETS, MULTIPLE, TIMESTAMP
            if (rMimeType.indexOf('/') == -1)
                continue;

            if (rMimeType.startsWith("text/plain"))
            {
                aFlavor.MimeType = "text/plain;charset=utf-16";
                aFlavor.DataType = cppu::UnoType<OUString>::get();
                aVector.push_back(aFlavor);
            }
            else
            {
                aFlavor.MimeType = toOUString(rMimeType);
                aFlavor.DataType = cppu::UnoType<Sequence<sal_Int8>>::get();
                aVector.push_back(aFlavor);
            }
        }
    }

    return aVector;
}

Qt5DragSource::~Qt5DragSource()
{
    //if (m_pFrame)
diff --git a/vcl/qt5/Qt5Frame.cxx b/vcl/qt5/Qt5Frame.cxx
index e3ced2d..55e0eea 100644
--- a/vcl/qt5/Qt5Frame.cxx
+++ b/vcl/qt5/Qt5Frame.cxx
@@ -1059,7 +1059,7 @@ void Qt5Frame::deregisterDropTarget(Qt5DropTarget const* pDropTarget)
    m_pDropTarget = nullptr;
}

void Qt5Frame::draggingStarted(const int x, const int y)
void Qt5Frame::draggingStarted(const int x, const int y, const QMimeData* pQMimeData)
{
    assert(m_pDropTarget);

@@ -1072,7 +1072,10 @@ void Qt5Frame::draggingStarted(const int x, const int y)
    aEvent.SourceActions = css::datatransfer::dnd::DNDConstants::ACTION_MOVE;

    css::uno::Reference<css::datatransfer::XTransferable> xTransferable;
    xTransferable = Qt5DragSource::m_ActiveDragSource->GetTransferable();
    if (pQMimeData)
        xTransferable = new Qt5DnDTransferable(pQMimeData);
    else
        xTransferable = Qt5DragSource::m_ActiveDragSource->GetTransferable();

    if (!m_bInDrag && xTransferable.is())
    {
@@ -1087,7 +1090,7 @@ void Qt5Frame::draggingStarted(const int x, const int y)
        m_pDropTarget->fire_dragOver(aEvent);
}

void Qt5Frame::dropping(const int x, const int y)
void Qt5Frame::dropping(const int x, const int y, const QMimeData* pQMimeData)
{
    assert(m_pDropTarget);

@@ -1101,7 +1104,10 @@ void Qt5Frame::dropping(const int x, const int y)
    aEvent.SourceActions = css::datatransfer::dnd::DNDConstants::ACTION_MOVE;

    css::uno::Reference<css::datatransfer::XTransferable> xTransferable;
    xTransferable = Qt5DragSource::m_ActiveDragSource->GetTransferable();
    if (pQMimeData)
        xTransferable = new Qt5DnDTransferable(pQMimeData);
    else
        xTransferable = Qt5DragSource::m_ActiveDragSource->GetTransferable();
    aEvent.Transferable = xTransferable;

    m_pDropTarget->fire_drop(aEvent);
diff --git a/vcl/qt5/Qt5Widget.cxx b/vcl/qt5/Qt5Widget.cxx
index 4ce5652..2277946 100644
--- a/vcl/qt5/Qt5Widget.cxx
+++ b/vcl/qt5/Qt5Widget.cxx
@@ -204,14 +204,15 @@ void Qt5Widget::dragEnterEvent(QDragEnterEvent* event)
{
    if (event->mimeData()->hasFormat(m_InternalMimeType))
        event->accept();
    // else FIXME: external drag source
    else
        event->acceptProposedAction();
}

void Qt5Widget::dragMoveEvent(QDragMoveEvent* event)
{
    QPoint point = event->pos();

    m_pFrame->draggingStarted(point.x(), point.y());
    m_pFrame->draggingStarted(point.x(), point.y(), event->mimeData());
    QWidget::dragMoveEvent(event);
}

@@ -219,7 +220,7 @@ void Qt5Widget::dropEvent(QDropEvent* event)
{
    QPoint point = event->pos();

    m_pFrame->dropping(point.x(), point.y());
    m_pFrame->dropping(point.x(), point.y(), event->mimeData());
    QWidget::dropEvent(event);
}