summaryrefslogtreecommitdiffstats
path: root/src/platformsupport/dnd/qsimpledrag.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/platformsupport/dnd/qsimpledrag.cpp')
-rw-r--r--src/platformsupport/dnd/qsimpledrag.cpp318
1 files changed, 227 insertions, 91 deletions
diff --git a/src/platformsupport/dnd/qsimpledrag.cpp b/src/platformsupport/dnd/qsimpledrag.cpp
index d0d08c2445..d3cecd4e44 100644
--- a/src/platformsupport/dnd/qsimpledrag.cpp
+++ b/src/platformsupport/dnd/qsimpledrag.cpp
@@ -56,147 +56,283 @@
#include "qimagereader.h"
#include "qimagewriter.h"
+#include <QtCore/QEventLoop>
+#include <QtCore/QDebug>
+
#include <private/qguiapplication_p.h>
#include <private/qdnd_p.h>
+#include <QtPlatformSupport/private/qshapedpixmapdndwindow_p.h>
+
QT_BEGIN_NAMESPACE
-class QDropData : public QInternalMimeData
-{
-public:
- QDropData();
- ~QDropData();
+/*!
+ \class QBasicDrag
+ \brief QBasicDrag is a base class for implementing platform drag and drop.
+ \since 5.0
+ \internal
+ \ingroup qpa
-protected:
- bool hasFormat_sys(const QString &mimeType) const;
- QStringList formats_sys() const;
- QVariant retrieveData_sys(const QString &mimeType, QVariant::Type type) const;
-};
+ QBasicDrag implements QPlatformDrag::drag() by running a local event loop in which
+ it tracks mouse movements and moves the drag icon (QShapedPixmapWindow) accordingly.
+ It provides new virtuals allowing for querying whether the receiving window
+ (within the Qt application or outside) accepts the drag and sets the state accordingly.
+*/
-QSimpleDrag::QSimpleDrag()
+QBasicDrag::QBasicDrag() :
+ m_restoreCursor(false), m_eventLoop(0),
+ m_executed_drop_action(Qt::IgnoreAction), m_can_drop(false),
+ m_drag(0), m_drag_icon_window(0), m_cursor_drop_action(Qt::IgnoreAction)
{
- m_dropData = new QDropData();
- currentWindow = 0;
}
-QSimpleDrag::~QSimpleDrag()
+QBasicDrag::~QBasicDrag()
{
- delete m_dropData;
+ delete m_drag_icon_window;
}
-QMimeData *QSimpleDrag::platformDropData()
+void QBasicDrag::enableEventFilter()
{
- return m_dropData;
+ qApp->installEventFilter(this);
}
-void QSimpleDrag::cancel()
+void QBasicDrag::disableEventFilter()
{
- QDragManager *m = QDragManager::self();
-// qDebug("QDragManager::cancel");
- if (m->object->target()) {
- QDragLeaveEvent dle;
- QCoreApplication::sendEvent(m->object->target(), &dle);
- }
-
+ qApp->removeEventFilter(this);
}
-void QSimpleDrag::move(const QMouseEvent *me)
+bool QBasicDrag::eventFilter(QObject *o, QEvent *e)
{
- QWindow *window = QGuiApplication::topLevelAt(me->globalPos());
- QPoint pos;
- if (window)
- pos = me->globalPos() - window->geometry().topLeft();
+ if (!m_drag) {
+ if (e->type() == QEvent::KeyRelease && static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape) {
+ disableEventFilter();
+ exitDndEventLoop();
+ return true; // block the key release
+ }
+ return false;
+ }
- QDragManager *m = QDragManager::self();
+ if (!qobject_cast<QWindow *>(o))
+ return false;
- if (me->buttons()) {
- Qt::DropAction prevAction = m->global_accepted_action;
+ switch (e->type()) {
+ case QEvent::ShortcutOverride:
+ // prevent accelerators from firing while dragging
+ e->accept();
+ return true;
+
+ case QEvent::KeyPress:
+ case QEvent::KeyRelease:
+ {
+ QKeyEvent *ke = static_cast<QKeyEvent *>(e);
+ if (ke->key() == Qt::Key_Escape && e->type() == QEvent::KeyPress) {
+ cancel();
+ resetDndState(true);
+ disableEventFilter();
+ exitDndEventLoop();
- if (currentWindow != window) {
- if (currentWindow) {
- QDragLeaveEvent dle;
- QCoreApplication::sendEvent(currentWindow, &dle);
- m->willDrop = false;
- m->global_accepted_action = Qt::IgnoreAction;
- }
- currentWindow = window;
- if (currentWindow) {
- QDragEnterEvent dee(pos, m->possible_actions, m->dropData(), me->buttons(), me->modifiers());
- QCoreApplication::sendEvent(currentWindow, &dee);
- m->willDrop = dee.isAccepted() && dee.dropAction() != Qt::IgnoreAction;
- m->global_accepted_action = m->willDrop ? dee.dropAction() : Qt::IgnoreAction;
- }
- m->updateCursor();
- } else if (window) {
- Q_ASSERT(currentWindow);
- QDragMoveEvent dme(pos, m->possible_actions, m->dropData(), me->buttons(), me->modifiers());
- if (m->global_accepted_action != Qt::IgnoreAction) {
- dme.setDropAction(m->global_accepted_action);
- dme.accept();
}
- QCoreApplication::sendEvent(currentWindow, &dme);
- m->willDrop = dme.isAccepted();
- m->global_accepted_action = m->willDrop ? dme.dropAction() : Qt::IgnoreAction;
- m->updatePixmap();
- m->updateCursor();
+ return true; // Eat all key events
}
- if (m->global_accepted_action != prevAction)
- m->emitActionChanged(m->global_accepted_action);
+
+ case QEvent::MouseMove:
+ move(static_cast<QMouseEvent *>(e));
+ return true; // Eat all mouse events
+
+ case QEvent::MouseButtonRelease:
+ disableEventFilter();
+
+ if (canDrop()) {
+ drop(static_cast<QMouseEvent *>(e));
+ resetDndState(false);
+ } else {
+ cancel();
+ resetDndState(true);
+ }
+ exitDndEventLoop();
+ return true; // Eat all mouse events
+
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::Wheel:
+ return true;
+ default:
+ break;
}
+ return false;
}
-void QSimpleDrag::drop(const QMouseEvent *me)
+Qt::DropAction QBasicDrag::drag(QDrag *o)
{
- QDragManager *m = QDragManager::self();
+ m_drag = o;
+ m_executed_drop_action = Qt::IgnoreAction;
+ m_can_drop = false;
+ m_restoreCursor = true;
+#ifndef QT_NO_CURSOR
+ qApp->setOverrideCursor(Qt::DragCopyCursor);
+ updateCursor(m_executed_drop_action);
+#endif
+ startDrag();
+ m_eventLoop = new QEventLoop;
+ m_eventLoop->exec();
+ delete m_eventLoop;
+ m_eventLoop = 0;
+ m_drag = 0;
+ endDrag();
+ return m_executed_drop_action;
+}
- QWindow *window = QGuiApplication::topLevelAt(me->globalPos());
+void QBasicDrag::resetDndState(bool /* deleteSource */)
+{
+ if (m_restoreCursor) {
+#ifndef QT_NO_CURSOR
+ QGuiApplication::restoreOverrideCursor();
+#endif
+ m_restoreCursor = false;
+ }
+}
+
+void QBasicDrag::startDrag()
+{
+ if (!m_drag_icon_window)
+ m_drag_icon_window = new QShapedPixmapWindow();
+
+ m_drag_icon_window->setPixmap(m_drag->pixmap());
+ m_drag_icon_window->setHotspot(m_drag->hotSpot());
+ m_drag_icon_window->updateGeometry();
+ m_drag_icon_window->setVisible(true);
+
+ enableEventFilter();
+}
+
+void QBasicDrag::endDrag()
+{
+}
+
+void QBasicDrag::cancel()
+{
+ disableEventFilter();
+ m_drag_icon_window->setVisible(false);
+}
+
+void QBasicDrag::move(const QMouseEvent *)
+{
+ if (m_drag)
+ m_drag_icon_window->updateGeometry();
+}
- if (window) {
- QPoint pos = me->globalPos() - window->geometry().topLeft();
+void QBasicDrag::drop(const QMouseEvent *)
+{
+ disableEventFilter();
+ m_drag_icon_window->setVisible(false);
+}
+
+void QBasicDrag::exitDndEventLoop()
+{
+ if (m_eventLoop && m_eventLoop->isRunning())
+ m_eventLoop->exit();
+}
- QDropEvent de(pos, m->possible_actions, m->dropData(), me->buttons(), me->modifiers());
- QCoreApplication::sendEvent(window, &de);
- if (de.isAccepted())
- m->global_accepted_action = de.dropAction();
- else
- m->global_accepted_action = Qt::IgnoreAction;
+void QBasicDrag::updateCursor(Qt::DropAction action)
+{
+ Qt::CursorShape cursorShape = Qt::ForbiddenCursor;
+ if (canDrop()) {
+ switch (action) {
+ case Qt::CopyAction:
+ cursorShape = Qt::DragCopyCursor;
+ break;
+ case Qt::LinkAction:
+ cursorShape = Qt::DragLinkCursor;
+ break;
+ default:
+ cursorShape = Qt::DragMoveCursor;
+ break;
+ }
}
- currentWindow = 0;
+
+ QCursor *cursor = qApp->overrideCursor();
+ if (cursor && cursorShape != cursor->shape()) {
+ qApp->changeOverrideCursor(QCursor(cursorShape));
+ }
+ updateAction(action);
}
+/*!
+ \class QSimpleDrag
+ \brief QSimpleDrag implements QBasicDrag for Drag and Drop operations within the Qt Application itself.
+ \since 5.0
+ \internal
+ \ingroup qpa
+ The class checks whether the receiving window is a window of the Qt application
+ and sets the state accordingly. It does not take windows of other applications
+ into account.
+*/
-QDropData::QDropData()
- : QInternalMimeData()
+QSimpleDrag::QSimpleDrag() : m_current_window(0)
{
}
-QDropData::~QDropData()
+QMimeData *QSimpleDrag::platformDropData()
{
+ if (drag())
+ return drag()->mimeData();
+ return 0;
}
-QVariant QDropData::retrieveData_sys(const QString &mimetype, QVariant::Type type) const
+void QSimpleDrag::startDrag()
{
- QDrag *object = QDragManager::self()->object;
- if (!object)
- return QVariant();
- QByteArray data = object->mimeData()->data(mimetype);
- if (type == QVariant::String)
- return QString::fromUtf8(data);
- return data;
+ QBasicDrag::startDrag();
+ m_current_window = QGuiApplication::topLevelAt(QCursor::pos());
+ if (m_current_window) {
+ QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(m_current_window, drag()->mimeData(), QCursor::pos(), drag()->supportedActions());
+ setCanDrop(response.isAccepted());
+ updateCursor(response.acceptedAction());
+ } else {
+ setCanDrop(false);
+ updateCursor(Qt::IgnoreAction);
+ }
+ setExecutedDropAction(Qt::IgnoreAction);
}
-bool QDropData::hasFormat_sys(const QString &format) const
+void QSimpleDrag::cancel()
{
- return formats().contains(format);
+ QBasicDrag::cancel();
+ if (drag())
+ QWindowSystemInterface::handleDrag(m_current_window, 0, QPoint(), Qt::IgnoreAction);
+ m_current_window = 0;
}
-QStringList QDropData::formats_sys() const
+void QSimpleDrag::move(const QMouseEvent *me)
{
- QDrag *object = QDragManager::self()->object;
- if (object)
- return object->mimeData()->formats();
- return QStringList();
+ QBasicDrag::move(me);
+ QWindow *window = QGuiApplication::topLevelAt(me->globalPos());
+ if (!window)
+ return;
+
+ const QPoint pos = me->globalPos() - window->geometry().topLeft();
+ const QPlatformDragQtResponse qt_response =
+ QWindowSystemInterface::handleDrag(window, drag()->mimeData(), pos, drag()->supportedActions());
+
+ updateCursor(qt_response.acceptedAction());
+ setCanDrop(qt_response.isAccepted());
+}
+
+void QSimpleDrag::drop(const QMouseEvent *me)
+{
+ QBasicDrag::drop(me);
+ QWindow *window = QGuiApplication::topLevelAt(me->globalPos());
+ if (!window)
+ return;
+
+ const QPoint pos = me->globalPos() - window->geometry().topLeft();
+ const QPlatformDropQtResponse response =
+ QWindowSystemInterface::handleDrop(window, drag()->mimeData(),pos, drag()->supportedActions());
+ if (response.isAccepted()) {
+ setExecutedDropAction(response.acceptedAction());
+ } else {
+ setExecutedDropAction(Qt::IgnoreAction);
+ }
}
QT_END_NAMESPACE