Implement canceling of Qt-initiated drags.

- Add new virtual QPlatformDrag::cancelDrag()
  [avoiding a conflict with existing QBasicDrag::cancel()]
- Implement on Windows by returning DRAGDROP_S_CANCEL
  from IOleDropSource::QueryContinueDrag() as suggested on report.
- Implement in QBasicDrag by calling QBasicDrag::cancel()
  and quitting the event loop.
- Add new API static void QDrag::cancel() for it.

Task-number: QTBUG-47004
Change-Id: I4b4bb52e5fc226c8e04688ac1b0f9550daaf918e
Reviewed-by: Jørgen Lind <jorgen.lind@theqtcompany.com>
Reviewed-by: David Faure <david.faure@kdab.com>
This commit is contained in:
Friedemann Kleint 2015-07-10 13:35:11 +02:00
parent 746fbbe039
commit 6f65ddbc21
8 changed files with 53 additions and 1 deletions

View File

@ -33,6 +33,8 @@
#include <qdrag.h> #include <qdrag.h>
#include "private/qguiapplication_p.h" #include "private/qguiapplication_p.h"
#include "qpa/qplatformintegration.h"
#include "qpa/qplatformdrag.h"
#include <qpixmap.h> #include <qpixmap.h>
#include <qpoint.h> #include <qpoint.h>
#include "qdnd_p.h" #include "qdnd_p.h"
@ -223,6 +225,8 @@ QObject *QDrag::target() const
loop. Other events are still delivered to the application while loop. Other events are still delivered to the application while
the operation is performed. On Windows, the Qt event loop is the operation is performed. On Windows, the Qt event loop is
blocked during the operation. blocked during the operation.
\sa cancel()
*/ */
Qt::DropAction QDrag::exec(Qt::DropActions supportedActions) Qt::DropAction QDrag::exec(Qt::DropActions supportedActions)
@ -377,6 +381,21 @@ Qt::DropAction QDrag::defaultAction() const
Q_D(const QDrag); Q_D(const QDrag);
return d->default_action; return d->default_action;
} }
/*!
Cancels a drag operation initiated by Qt.
\note This is currently implemented on Windows and X11.
\since 5.6
\sa exec()
*/
void QDrag::cancel()
{
if (QPlatformDrag *platformDrag = QGuiApplicationPrivate::platformIntegration()->drag())
platformDrag->cancelDrag();
}
/*! /*!
\fn void QDrag::actionChanged(Qt::DropAction action) \fn void QDrag::actionChanged(Qt::DropAction action)

View File

@ -77,6 +77,8 @@ public:
Qt::DropActions supportedActions() const; Qt::DropActions supportedActions() const;
Qt::DropAction defaultAction() const; Qt::DropAction defaultAction() const;
static void cancel();
Q_SIGNALS: Q_SIGNALS:
void actionChanged(Qt::DropAction action); void actionChanged(Qt::DropAction action);
void targetChanged(QObject *newTarget); void targetChanged(QObject *newTarget);

View File

@ -154,6 +154,20 @@ Qt::DropAction QPlatformDrag::defaultAction(Qt::DropActions possibleActions,
return default_action; return default_action;
} }
/*!
\brief Cancels the currently active drag (only for drags of
the current application initiated by QPlatformDrag::drag()).
The default implementation does nothing.
\since 5.6
*/
void QPlatformDrag::cancelDrag()
{
Q_UNIMPLEMENTED();
}
/*! /*!
\brief Called to notify QDrag about changes of the current action. \brief Called to notify QDrag about changes of the current action.
*/ */

View File

@ -92,6 +92,7 @@ public:
virtual QMimeData *platformDropData() = 0; virtual QMimeData *platformDropData() = 0;
virtual Qt::DropAction drag(QDrag *m_drag) = 0; virtual Qt::DropAction drag(QDrag *m_drag) = 0;
virtual void cancelDrag();
void updateAction(Qt::DropAction action); void updateAction(Qt::DropAction action);
virtual Qt::DropAction defaultAction(Qt::DropActions possibleActions, Qt::KeyboardModifiers modifiers) const; virtual Qt::DropAction defaultAction(Qt::DropActions possibleActions, Qt::KeyboardModifiers modifiers) const;

View File

@ -191,6 +191,14 @@ Qt::DropAction QBasicDrag::drag(QDrag *o)
return m_executed_drop_action; return m_executed_drop_action;
} }
void QBasicDrag::cancelDrag()
{
if (m_eventLoop) {
cancel();
m_eventLoop->quit();
}
}
void QBasicDrag::restoreCursor() void QBasicDrag::restoreCursor()
{ {
if (m_restoreCursor) { if (m_restoreCursor) {

View File

@ -66,6 +66,7 @@ public:
virtual ~QBasicDrag(); virtual ~QBasicDrag();
virtual Qt::DropAction drag(QDrag *drag) Q_DECL_OVERRIDE; virtual Qt::DropAction drag(QDrag *drag) Q_DECL_OVERRIDE;
void cancelDrag() Q_DECL_OVERRIDE;
virtual bool eventFilter(QObject *o, QEvent *e) Q_DECL_OVERRIDE; virtual bool eventFilter(QObject *o, QEvent *e) Q_DECL_OVERRIDE;

View File

@ -397,7 +397,7 @@ QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
{ {
HRESULT hr = S_OK; HRESULT hr = S_OK;
do { do {
if (fEscapePressed) { if (fEscapePressed || QWindowsDrag::isCanceled()) {
hr = ResultFromScode(DRAGDROP_S_CANCEL); hr = ResultFromScode(DRAGDROP_S_CANCEL);
break; break;
} }
@ -677,6 +677,8 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState,
\ingroup qt-lighthouse-win \ingroup qt-lighthouse-win
*/ */
bool QWindowsDrag::m_canceled = false;
QWindowsDrag::QWindowsDrag() : QWindowsDrag::QWindowsDrag() :
m_dropDataObject(0), m_cachedDropTargetHelper(0) m_dropDataObject(0), m_cachedDropTargetHelper(0)
{ {
@ -806,6 +808,7 @@ Qt::DropAction QWindowsDrag::drag(QDrag *drag)
Qt::DropAction dragResult = Qt::IgnoreAction; Qt::DropAction dragResult = Qt::IgnoreAction;
DWORD resultEffect; DWORD resultEffect;
QWindowsDrag::m_canceled = false;
QWindowsOleDropSource *windowDropSource = new QWindowsOleDropSource(this); QWindowsOleDropSource *windowDropSource = new QWindowsOleDropSource(this);
windowDropSource->createCursors(); windowDropSource->createCursors();
QWindowsOleDataObject *dropDataObject = new QWindowsOleDataObject(dropData); QWindowsOleDataObject *dropDataObject = new QWindowsOleDataObject(dropData);

View File

@ -87,6 +87,8 @@ public:
Qt::DropAction drag(QDrag *drag) Q_DECL_OVERRIDE; Qt::DropAction drag(QDrag *drag) Q_DECL_OVERRIDE;
static QWindowsDrag *instance(); static QWindowsDrag *instance();
void cancelDrag() Q_DECL_OVERRIDE { QWindowsDrag::m_canceled = true; }
static bool isCanceled() { return QWindowsDrag::m_canceled; }
IDataObject *dropDataObject() const { return m_dropDataObject; } IDataObject *dropDataObject() const { return m_dropDataObject; }
void setDropDataObject(IDataObject *dataObject) { m_dropDataObject = dataObject; } void setDropDataObject(IDataObject *dataObject) { m_dropDataObject = dataObject; }
@ -98,6 +100,8 @@ public:
QPixmap defaultCursor(Qt::DropAction action) const; QPixmap defaultCursor(Qt::DropAction action) const;
private: private:
static bool m_canceled;
QWindowsDropMimeData m_dropData; QWindowsDropMimeData m_dropData;
IDataObject *m_dropDataObject; IDataObject *m_dropDataObject;