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 "private/qguiapplication_p.h"
#include "qpa/qplatformintegration.h"
#include "qpa/qplatformdrag.h"
#include <qpixmap.h>
#include <qpoint.h>
#include "qdnd_p.h"
@ -223,6 +225,8 @@ QObject *QDrag::target() const
loop. Other events are still delivered to the application while
the operation is performed. On Windows, the Qt event loop is
blocked during the operation.
\sa cancel()
*/
Qt::DropAction QDrag::exec(Qt::DropActions supportedActions)
@ -377,6 +381,21 @@ Qt::DropAction QDrag::defaultAction() const
Q_D(const QDrag);
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)

View File

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

View File

@ -154,6 +154,20 @@ Qt::DropAction QPlatformDrag::defaultAction(Qt::DropActions possibleActions,
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.
*/

View File

@ -92,6 +92,7 @@ public:
virtual QMimeData *platformDropData() = 0;
virtual Qt::DropAction drag(QDrag *m_drag) = 0;
virtual void cancelDrag();
void updateAction(Qt::DropAction action);
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;
}
void QBasicDrag::cancelDrag()
{
if (m_eventLoop) {
cancel();
m_eventLoop->quit();
}
}
void QBasicDrag::restoreCursor()
{
if (m_restoreCursor) {

View File

@ -66,6 +66,7 @@ public:
virtual ~QBasicDrag();
virtual Qt::DropAction drag(QDrag *drag) Q_DECL_OVERRIDE;
void cancelDrag() 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;
do {
if (fEscapePressed) {
if (fEscapePressed || QWindowsDrag::isCanceled()) {
hr = ResultFromScode(DRAGDROP_S_CANCEL);
break;
}
@ -677,6 +677,8 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState,
\ingroup qt-lighthouse-win
*/
bool QWindowsDrag::m_canceled = false;
QWindowsDrag::QWindowsDrag() :
m_dropDataObject(0), m_cachedDropTargetHelper(0)
{
@ -806,6 +808,7 @@ Qt::DropAction QWindowsDrag::drag(QDrag *drag)
Qt::DropAction dragResult = Qt::IgnoreAction;
DWORD resultEffect;
QWindowsDrag::m_canceled = false;
QWindowsOleDropSource *windowDropSource = new QWindowsOleDropSource(this);
windowDropSource->createCursors();
QWindowsOleDataObject *dropDataObject = new QWindowsOleDataObject(dropData);

View File

@ -87,6 +87,8 @@ public:
Qt::DropAction drag(QDrag *drag) Q_DECL_OVERRIDE;
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; }
void setDropDataObject(IDataObject *dataObject) { m_dropDataObject = dataObject; }
@ -98,6 +100,8 @@ public:
QPixmap defaultCursor(Qt::DropAction action) const;
private:
static bool m_canceled;
QWindowsDropMimeData m_dropData;
IDataObject *m_dropDataObject;