Merge branch 'qt-dnd'
Initial drag-and-drop implementation for wxQt. Closes https://github.com/wxWidgets/wxWidgets/pull/1205
This commit is contained in:
365
src/qt/dnd.cpp
365
src/qt/dnd.cpp
@@ -11,53 +11,380 @@
|
||||
#if wxUSE_DRAG_AND_DROP
|
||||
|
||||
#include "wx/dnd.h"
|
||||
#include "wx/scopedarray.h"
|
||||
#include "wx/window.h"
|
||||
|
||||
wxDropTarget::wxDropTarget(wxDataObject *WXUNUSED(dataObject))
|
||||
#include "wx/qt/private/converter.h"
|
||||
|
||||
#include <QDrag>
|
||||
#include <QWidget>
|
||||
#include <QMimeData>
|
||||
#include <QCloseEvent>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
wxDragResult DropActionToDragResult(Qt::DropAction action)
|
||||
{
|
||||
switch ( action )
|
||||
{
|
||||
case Qt::IgnoreAction:
|
||||
return wxDragCancel;
|
||||
case Qt::CopyAction:
|
||||
return wxDragCopy;
|
||||
case Qt::MoveAction:
|
||||
case Qt::TargetMoveAction:
|
||||
return wxDragMove;
|
||||
case Qt::LinkAction:
|
||||
return wxDragLink;
|
||||
}
|
||||
|
||||
wxFAIL_MSG("Illegal drop action");
|
||||
return wxDragNone;
|
||||
}
|
||||
|
||||
Qt::DropAction DragResultToDropAction(wxDragResult result)
|
||||
{
|
||||
switch ( result )
|
||||
{
|
||||
case wxDragCopy:
|
||||
return Qt::CopyAction;
|
||||
case wxDragMove:
|
||||
return Qt::MoveAction;
|
||||
case wxDragLink:
|
||||
return Qt::LinkAction;
|
||||
case wxDragError:
|
||||
case wxDragNone:
|
||||
case wxDragCancel:
|
||||
return Qt::IgnoreAction;
|
||||
}
|
||||
|
||||
wxFAIL_MSG("Illegal drag result");
|
||||
return Qt::IgnoreAction;
|
||||
}
|
||||
|
||||
void AddDataFormat(wxDataObject* dataObject,
|
||||
QMimeData* mimeData,
|
||||
const wxDataFormat& format)
|
||||
{
|
||||
const size_t data_size = dataObject->GetDataSize(format);
|
||||
|
||||
QByteArray data(static_cast<int>(data_size), Qt::Initialization());
|
||||
dataObject->GetDataHere(format, data.data());
|
||||
|
||||
mimeData->setData(wxQtConvertString(format.GetMimeType()), data);
|
||||
}
|
||||
|
||||
QMimeData* CreateMimeData(wxDataObject* dataObject)
|
||||
{
|
||||
QMimeData* mimeData = new QMimeData();
|
||||
|
||||
const size_t count = dataObject->GetFormatCount();
|
||||
|
||||
wxScopedArray<wxDataFormat> array(dataObject->GetFormatCount());
|
||||
dataObject->GetAllFormats(array.get());
|
||||
|
||||
for ( size_t i = 0; i < count; i++ )
|
||||
{
|
||||
AddDataFormat(dataObject, mimeData, array[i]);
|
||||
}
|
||||
|
||||
return mimeData;
|
||||
}
|
||||
|
||||
void SetDragCursor(QDrag& drag,
|
||||
const wxCursor& cursor,
|
||||
Qt::DropAction action)
|
||||
{
|
||||
if ( cursor.IsOk() )
|
||||
drag.setDragCursor(cursor.GetHandle().pixmap(), action);
|
||||
}
|
||||
|
||||
class PendingMimeDataSetter
|
||||
{
|
||||
public:
|
||||
PendingMimeDataSetter(const QMimeData*& targetMimeData,
|
||||
const QMimeData* mimeData)
|
||||
: m_targetMimeData(targetMimeData)
|
||||
{
|
||||
m_targetMimeData = mimeData;
|
||||
}
|
||||
|
||||
~PendingMimeDataSetter()
|
||||
{
|
||||
m_targetMimeData = NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
const QMimeData*& m_targetMimeData;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class wxDropTarget::Impl : public QObject
|
||||
{
|
||||
public:
|
||||
explicit Impl(wxDropTarget* dropTarget)
|
||||
: m_dropTarget(dropTarget),
|
||||
m_widget(NULL),
|
||||
m_pendingMimeData(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
~Impl()
|
||||
{
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
void ConnectTo(QWidget* widget)
|
||||
{
|
||||
Disconnect();
|
||||
|
||||
m_widget = widget;
|
||||
|
||||
if ( m_widget != NULL )
|
||||
{
|
||||
m_widget->setAcceptDrops(true);
|
||||
m_widget->installEventFilter(this);
|
||||
}
|
||||
}
|
||||
|
||||
void Disconnect()
|
||||
{
|
||||
if ( m_widget != NULL )
|
||||
{
|
||||
m_widget->setAcceptDrops(false);
|
||||
m_widget->removeEventFilter(this);
|
||||
m_widget = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool eventFilter(QObject* watched, QEvent* event) wxOVERRIDE
|
||||
{
|
||||
if ( m_dropTarget != NULL )
|
||||
{
|
||||
switch ( event->type() )
|
||||
{
|
||||
case QEvent::Drop:
|
||||
OnDrop(event);
|
||||
return true;
|
||||
|
||||
case QEvent::DragEnter:
|
||||
OnEnter(event);
|
||||
return true;
|
||||
|
||||
case QEvent::DragMove:
|
||||
OnMove(event);
|
||||
return true;
|
||||
|
||||
case QEvent::DragLeave:
|
||||
OnLeave(event);
|
||||
return true;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return QObject::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
void OnEnter(QEvent* event)
|
||||
{
|
||||
QDragEnterEvent *e = static_cast<QDragEnterEvent*>(event);
|
||||
|
||||
const PendingMimeDataSetter setter(m_pendingMimeData, e->mimeData());
|
||||
|
||||
if ( !CanDropHere() )
|
||||
{
|
||||
e->setDropAction(Qt::IgnoreAction);
|
||||
return;
|
||||
}
|
||||
|
||||
event->accept();
|
||||
|
||||
const QPoint where = e->pos();
|
||||
const wxDragResult proposedResult =
|
||||
DropActionToDragResult(e->proposedAction());
|
||||
const wxDragResult result = m_dropTarget->OnEnter(where.x(),
|
||||
where.y(),
|
||||
proposedResult);
|
||||
|
||||
e->setDropAction(DragResultToDropAction(result));
|
||||
}
|
||||
|
||||
void OnLeave(QEvent* event)
|
||||
{
|
||||
event->accept();
|
||||
m_dropTarget->OnLeave();
|
||||
}
|
||||
|
||||
void OnMove(QEvent* event)
|
||||
{
|
||||
event->accept();
|
||||
|
||||
QDragMoveEvent *e = static_cast<QDragMoveEvent*>(event);
|
||||
|
||||
const PendingMimeDataSetter setter(m_pendingMimeData, e->mimeData());
|
||||
|
||||
const QPoint where = e->pos();
|
||||
const wxDragResult proposedResult =
|
||||
DropActionToDragResult(e->proposedAction());
|
||||
const wxDragResult result = m_dropTarget->OnDragOver(where.x(),
|
||||
where.y(),
|
||||
proposedResult);
|
||||
|
||||
e->setDropAction(DragResultToDropAction(result));
|
||||
}
|
||||
|
||||
void OnDrop(QEvent* event)
|
||||
{
|
||||
event->accept();
|
||||
|
||||
const QDropEvent *e = static_cast<QDropEvent*>(event);
|
||||
|
||||
const PendingMimeDataSetter setter(m_pendingMimeData, e->mimeData());
|
||||
|
||||
const QPoint where = e->pos();
|
||||
if ( m_dropTarget->OnDrop(where.x(), where.y()) )
|
||||
{
|
||||
m_dropTarget->OnData(where.x(),
|
||||
where.y(),
|
||||
DropActionToDragResult(e->dropAction()));
|
||||
}
|
||||
}
|
||||
|
||||
const QMimeData* GetMimeData() const
|
||||
{
|
||||
return m_pendingMimeData;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
bool CanDropHere() const
|
||||
{
|
||||
return !m_dropTarget->GetMatchingPair().GetMimeType().empty();
|
||||
}
|
||||
|
||||
wxDropTarget* m_dropTarget;
|
||||
QWidget* m_widget;
|
||||
const QMimeData* m_pendingMimeData;
|
||||
};
|
||||
|
||||
wxDropTarget::wxDropTarget(wxDataObject *dataObject)
|
||||
: wxDropTargetBase(dataObject),
|
||||
m_pImpl(new Impl(this))
|
||||
{
|
||||
}
|
||||
|
||||
wxDropTarget::~wxDropTarget()
|
||||
{
|
||||
delete m_pImpl;
|
||||
}
|
||||
|
||||
bool wxDropTarget::OnDrop(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y))
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
wxDragResult wxDropTarget::OnData(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), wxDragResult WXUNUSED(def))
|
||||
wxDragResult wxDropTarget::OnData(wxCoord WXUNUSED(x),
|
||||
wxCoord WXUNUSED(y),
|
||||
wxDragResult def)
|
||||
{
|
||||
return wxDragResult();
|
||||
return GetData() ? def : wxDragNone;
|
||||
}
|
||||
|
||||
bool wxDropTarget::GetData()
|
||||
{
|
||||
return false;
|
||||
const wxDataFormat droppedFormat = GetMatchingPair();
|
||||
|
||||
const wxString& mimeType = droppedFormat.GetMimeType();
|
||||
if ( mimeType.empty() )
|
||||
return false;
|
||||
|
||||
const QString qMimeType = wxQtConvertString(mimeType);
|
||||
const QByteArray data = m_pImpl->GetMimeData()->data(qMimeType);
|
||||
|
||||
return m_dataObject->SetData(droppedFormat, data.size(), data.data());
|
||||
}
|
||||
|
||||
wxDataFormat wxDropTarget::GetMatchingPair()
|
||||
{
|
||||
wxFAIL_MSG("wxDropTarget::GetMatchingPair() not implemented in src/qt/dnd.cpp");
|
||||
return wxDF_INVALID;
|
||||
const QMimeData* mimeData = m_pImpl->GetMimeData();
|
||||
if ( mimeData == NULL || m_dataObject == NULL )
|
||||
return wxFormatInvalid;
|
||||
|
||||
const QStringList formats = mimeData->formats();
|
||||
for ( int i = 0; i < formats.count(); ++i )
|
||||
{
|
||||
const wxDataFormat format(wxQtConvertString(formats[i]));
|
||||
|
||||
if ( m_dataObject->IsSupportedFormat(format) )
|
||||
{
|
||||
return format;
|
||||
}
|
||||
}
|
||||
return wxFormatInvalid;
|
||||
}
|
||||
|
||||
//##############################################################################
|
||||
void wxDropTarget::ConnectTo(QWidget* widget)
|
||||
{
|
||||
m_pImpl->ConnectTo(widget);
|
||||
}
|
||||
|
||||
void wxDropTarget::Disconnect()
|
||||
{
|
||||
m_pImpl->Disconnect();
|
||||
}
|
||||
|
||||
wxDropSource::wxDropSource( wxWindow *WXUNUSED(win),
|
||||
const wxIcon &WXUNUSED(copy),
|
||||
const wxIcon &WXUNUSED(move),
|
||||
const wxIcon &WXUNUSED(none))
|
||||
//###########################################################################
|
||||
|
||||
wxDropSource::wxDropSource(wxWindow *win,
|
||||
const wxCursor ©,
|
||||
const wxCursor &move,
|
||||
const wxCursor &none)
|
||||
: wxDropSourceBase(copy, move, none),
|
||||
m_parentWindow(win)
|
||||
{
|
||||
}
|
||||
|
||||
wxDropSource::wxDropSource( wxDataObject& WXUNUSED(data),
|
||||
wxWindow *WXUNUSED(win),
|
||||
const wxIcon &WXUNUSED(copy),
|
||||
const wxIcon &WXUNUSED(move),
|
||||
const wxIcon &WXUNUSED(none))
|
||||
wxDropSource::wxDropSource(wxDataObject& data,
|
||||
wxWindow *win,
|
||||
const wxCursor ©,
|
||||
const wxCursor &move,
|
||||
const wxCursor &none)
|
||||
: wxDropSourceBase(copy, move, none),
|
||||
m_parentWindow(win)
|
||||
{
|
||||
SetData(data);
|
||||
}
|
||||
|
||||
wxDragResult wxDropSource::DoDragDrop(int WXUNUSED(flags))
|
||||
wxDragResult wxDropSource::DoDragDrop(int flags /*=wxDrag_CopyOnly*/)
|
||||
{
|
||||
return wxDragResult();
|
||||
wxCHECK_MSG(m_data != NULL, wxDragNone,
|
||||
wxT("No data in wxDropSource!"));
|
||||
|
||||
wxCHECK_MSG(m_parentWindow != NULL, wxDragNone,
|
||||
wxT("NULL parent window in wxDropSource!"));
|
||||
|
||||
QDrag drag(m_parentWindow->GetHandle());
|
||||
drag.setMimeData(CreateMimeData(m_data));
|
||||
|
||||
SetDragCursor(drag, m_cursorCopy, Qt::CopyAction);
|
||||
SetDragCursor(drag, m_cursorMove, Qt::MoveAction);
|
||||
SetDragCursor(drag, m_cursorStop, Qt::IgnoreAction);
|
||||
|
||||
const Qt::DropActions actions =
|
||||
flags == wxDrag_CopyOnly
|
||||
? Qt::CopyAction
|
||||
: Qt::CopyAction | Qt::MoveAction;
|
||||
|
||||
const Qt::DropAction defaultAction =
|
||||
flags == wxDrag_DefaultMove
|
||||
? Qt::MoveAction
|
||||
: Qt::CopyAction;
|
||||
|
||||
return DropActionToDragResult(drag.exec(actions, defaultAction));
|
||||
}
|
||||
|
||||
#endif // wxUSE_DRAG_AND_DROP
|
||||
|
Reference in New Issue
Block a user