diff --git a/include/wx/qt/dnd.h b/include/wx/qt/dnd.h index 6edd330f6e..ec8bf6feb3 100644 --- a/include/wx/qt/dnd.h +++ b/include/wx/qt/dnd.h @@ -10,22 +10,30 @@ #define wxDROP_ICON(name) wxICON(name) +class QMimeData; + class WXDLLIMPEXP_CORE wxDropTarget : public wxDropTargetBase { public: - wxDropTarget(wxDataObject *dataObject = NULL ); + wxDropTarget(wxDataObject *dataObject = NULL); - virtual bool OnDrop(wxCoord x, wxCoord y); - virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def); - virtual bool GetData(); + virtual bool OnDrop(wxCoord x, wxCoord y) wxOVERRIDE; + virtual wxDragResult OnData(wxCoord x, wxCoord y, wxDragResult def) wxOVERRIDE; + virtual bool GetData() wxOVERRIDE; wxDataFormat GetMatchingPair(); -protected: + void OnQtEnter(QEvent* event); + void OnQtLeave(QEvent* event); + void OnQtMove(QEvent* event); + void OnQtDrop(QEvent* event); private: -}; + class PendingMimeDataSetter; + friend class PendingMimeDataSetter; + const QMimeData* m_pendingMimeData; +}; class WXDLLIMPEXP_CORE wxDropSource: public wxDropSourceBase { diff --git a/include/wx/qt/window.h b/include/wx/qt/window.h index a2f1542a27..130267f75e 100644 --- a/include/wx/qt/window.h +++ b/include/wx/qt/window.h @@ -10,6 +10,7 @@ #define _WX_QT_WINDOW_H_ #include +#include class QShortcut; template < class T > class QList; @@ -216,6 +217,16 @@ protected: QWidget *m_qtWindow; private: + class DnDEventAdapter : public QObject + { + public: + DnDEventAdapter(); + virtual bool eventFilter(QObject* watched, QEvent* event); + void SetDropTarget(wxDropTarget* dropTarget, QWidget* window); + private: + wxDropTarget *m_dropTarget; + }; + void Init(); QScrollArea *m_qtContainer; @@ -238,6 +249,10 @@ private: bool m_processingShortcut; #endif // wxUSE_ACCEL +#if wxUSE_DRAG_AND_DROP + DnDEventAdapter dnd_event_adapter; +#endif + wxDECLARE_DYNAMIC_CLASS_NO_COPY( wxWindowQt ); }; diff --git a/src/qt/dataobj.cpp b/src/qt/dataobj.cpp index b1cb3b7fd2..e6f8f6e1be 100644 --- a/src/qt/dataobj.cpp +++ b/src/qt/dataobj.cpp @@ -102,6 +102,12 @@ bool wxDataFormat::operator!=(wxDataFormatId format) const bool wxDataFormat::operator==(const wxDataFormat& format) const { + // If mime types match, then that's good enough. + // (Could be comparing a standard constructed format to a + // custom constructed one, where both are actually the same.) + if (!m_mimeType.empty() && m_mimeType == format.m_mimeType) + return true; + return m_mimeType == format.m_mimeType && m_formatId == format.m_formatId; } diff --git a/src/qt/dnd.cpp b/src/qt/dnd.cpp index 68922e2f8b..750b19524d 100644 --- a/src/qt/dnd.cpp +++ b/src/qt/dnd.cpp @@ -18,6 +18,7 @@ #include #include #include +#include namespace { @@ -38,6 +39,21 @@ namespace } } + Qt::DropAction DragResultToDropAction(wxDragResult result) + { + switch ( result ) + { + case wxDragCopy: + return Qt::CopyAction; + case wxDragMove: + return Qt::MoveAction; + case wxDragLink: + return Qt::LinkAction; + default: + return Qt::IgnoreAction; + } + } + void AddDataFormat(wxDataObject* dataObject, QMimeData* mimeData, const wxDataFormat& format) { const size_t data_size = dataObject->GetDataSize(format); @@ -66,29 +82,120 @@ namespace } } -wxDropTarget::wxDropTarget(wxDataObject *WXUNUSED(dataObject)) +class wxDropTarget::PendingMimeDataSetter +{ +public: + PendingMimeDataSetter(wxDropTarget* dropTarget, const QMimeData* mimeData) + : m_dropTarget(dropTarget) + { + m_dropTarget->m_pendingMimeData = mimeData; + } + + ~PendingMimeDataSetter() + { + m_dropTarget->m_pendingMimeData = NULL; + } + +private: + wxDropTarget* m_dropTarget; + +}; + +wxDropTarget::wxDropTarget(wxDataObject *dataObject) + : wxDropTargetBase(dataObject), + m_pendingMimeData(NULL) { } bool wxDropTarget::OnDrop(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y)) { - return false; + return !GetMatchingPair().GetMimeType().empty(); } -wxDragResult wxDropTarget::OnData(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), wxDragResult WXUNUSED(def)) +wxDragResult wxDropTarget::OnData(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), wxDragResult default_drag_result) { - return wxDragResult(); + GetData(); + return default_drag_result; } bool wxDropTarget::GetData() { - return false; + const wxDataFormat droppedFormat = GetMatchingPair(); + + const wxString mimeType = droppedFormat.GetMimeType(); + if ( mimeType.empty() ) + return false; + + const QByteArray data = m_pendingMimeData->data(wxQtConvertString(mimeType)); + + 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; + if ( m_pendingMimeData == NULL || m_dataObject == NULL ) + return wxFormatInvalid; + + const QStringList formats = m_pendingMimeData->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::OnQtEnter(QEvent* event) +{ + event->accept(); + + QDragEnterEvent *e = static_cast(event); + const QPoint where = e->pos(); + + PendingMimeDataSetter setter(this, e->mimeData()); + + wxDragResult result = OnEnter(where.x(), where.y(), DropActionToDragResult(e->proposedAction())); + + e->setDropAction(DragResultToDropAction(result)); +} + +void wxDropTarget::OnQtLeave(QEvent* event) +{ + event->accept(); + OnLeave(); +} + +void wxDropTarget::OnQtMove(QEvent* event) +{ + event->accept(); + + QDragMoveEvent *e = static_cast(event); + const QPoint where = e->pos(); + + PendingMimeDataSetter setter(this, e->mimeData()); + + wxDragResult result = OnDragOver(where.x(), where.y(), DropActionToDragResult(e->proposedAction())); + + e->setDropAction(DragResultToDropAction(result)); +} + +void wxDropTarget::OnQtDrop(QEvent* event) +{ + event->accept(); + + const QDropEvent *e = static_cast(event); + const QPoint where = e->pos(); + + PendingMimeDataSetter setter(this, e->mimeData()); + + if ( OnDrop(where.x(), where.y()) ) + { + OnData(where.x(), where.y(), DropActionToDragResult(e->dropAction())); + } } //############################################################################## diff --git a/src/qt/window.cpp b/src/qt/window.cpp index 88e1b4b1e0..d638daa64b 100644 --- a/src/qt/window.cpp +++ b/src/qt/window.cpp @@ -31,12 +31,12 @@ #endif // WX_PRECOMP #include "wx/window.h" +#include "wx/dnd.h" #include "wx/tooltip.h" #include "wx/qt/private/utils.h" #include "wx/qt/private/converter.h" #include "wx/qt/private/winevent.h" - #define VERT_SCROLLBAR_POSITION 0, 1 #define HORZ_SCROLLBAR_POSITION 1, 0 @@ -193,9 +193,6 @@ static const char WINDOW_POINTER_PROPERTY_NAME[] = "wxWindowPointer"; return const_cast< wxWindowQt * >( ( variant.value< const wxWindow * >() )); } - - - static wxWindowQt *s_capturedWindow = NULL; /* static */ wxWindowQt *wxWindowBase::DoFindFocus() @@ -225,6 +222,8 @@ void wxWindowQt::Init() #endif m_qtWindow = NULL; m_qtContainer = NULL; + + m_dropTarget = NULL; } wxWindowQt::wxWindowQt() @@ -688,9 +687,9 @@ void wxWindowQt::ScrollWindow( int dx, int dy, const wxRect *rect ) #if wxUSE_DRAG_AND_DROP -void wxWindowQt::SetDropTarget( wxDropTarget * WXUNUSED( dropTarget ) ) +void wxWindowQt::SetDropTarget( wxDropTarget *dropTarget ) { - wxMISSING_IMPLEMENTATION( __FUNCTION__ ); + dnd_event_adapter.SetDropTarget(dropTarget, m_qtWindow); } #endif @@ -1543,3 +1542,60 @@ QPainter *wxWindowQt::QtGetPainter() { return m_qtPainter; } + +//############################################################################## +// DnDEventAdapter +//############################################################################## + +wxWindow::DnDEventAdapter::DnDEventAdapter() : m_dropTarget(NULL) +{ +} + +bool wxWindow::DnDEventAdapter::eventFilter(QObject* watched, QEvent* event) +{ + if ( m_dropTarget != NULL ) + { + switch ( event->type() ) + { + case QEvent::Drop: + m_dropTarget->OnQtDrop(event); + return true; + + case QEvent::DragEnter: + m_dropTarget->OnQtEnter(event); + return true; + + case QEvent::DragMove: + m_dropTarget->OnQtMove(event); + return true; + + case QEvent::DragLeave: + m_dropTarget->OnQtLeave(event); + return true; + + default: + break; + } + } + + return QObject::eventFilter(watched, event); +} + +void wxWindow::DnDEventAdapter::SetDropTarget(wxDropTarget* dropTarget, QWidget* window) +{ + if ( m_dropTarget == dropTarget ) + return; + + m_dropTarget = dropTarget; + + if ( m_dropTarget == NULL ) + { + window->removeEventFilter(this); + window->setAcceptDrops(false); + } + else + { + window->installEventFilter(this); + window->setAcceptDrops(true); + } +}