summaryrefslogtreecommitdiffstats
path: root/src/platformsupport/dnd/qsimpledrag.cpp
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@nokia.com>2012-02-22 10:58:28 +0100
committerQt by Nokia <qt-info@nokia.com>2012-02-29 20:10:30 +0100
commit3a72a1c7ed5adcdf3e473b50cc9c932e9290ee81 (patch)
treec9c6ab476e935c1141675382c051ef86e003440d /src/platformsupport/dnd/qsimpledrag.cpp
parent70784b9069fbd1c73eddbbfc83ffb44b2ca15854 (diff)
Refactor the QPA dnd interface.
- Give QPlatformDrag a synchronous drag() function returning the Qt::DropAction - Move the base functionality for asynchronous event handling to the platformsupport library as QBasicDrag (extendable base class handling drag icon and providing new virtuals) and QSimpleDrag (sample implementation for drag within the Qt application). - Change the Windows implementation accordingly. - Change XCB to be based on QBasicDrag. - Clean up QDragManager. Change-Id: I654f76f0e55a385ba189bd74f3ceaded6a8fe318 Reviewed-by: Morten Johan Sørvig <morten.sorvig@nokia.com>
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