diff options
Diffstat (limited to 'src/gui/kernel')
-rw-r--r-- | src/gui/kernel/kernel.pri | 5 | ||||
-rw-r--r-- | src/gui/kernel/qdnd.cpp | 490 | ||||
-rw-r--r-- | src/gui/kernel/qdnd_p.h | 333 | ||||
-rw-r--r-- | src/gui/kernel/qdnd_qpa.cpp | 434 | ||||
-rw-r--r-- | src/gui/kernel/qdrag.cpp | 358 | ||||
-rw-r--r-- | src/gui/kernel/qdrag.h | 101 |
6 files changed, 1721 insertions, 0 deletions
diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index 6fda4fd62f..8662329a2d 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -9,6 +9,8 @@ HEADERS += \ kernel/qclipboard.h \ kernel/qcursor.h \ kernel/qcursor_p.h \ + kernel/qdrag.h \ + kernel/qdnd_p.h \ kernel/qevent.h \ kernel/qevent_p.h \ kernel/qkeysequence.h \ @@ -22,6 +24,9 @@ HEADERS += \ SOURCES += \ kernel/qclipboard.cpp \ kernel/qcursor.cpp \ + kernel/qdrag.cpp \ + kernel/qdnd.cpp \ + kernel/qdnd_qpa.cpp \ kernel/qevent.cpp \ kernel/qkeysequence.cpp \ kernel/qkeymapper.cpp \ diff --git a/src/gui/kernel/qdnd.cpp b/src/gui/kernel/qdnd.cpp new file mode 100644 index 0000000000..55fc3b09fc --- /dev/null +++ b/src/gui/kernel/qdnd.cpp @@ -0,0 +1,490 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplatformdefs.h" + +#include "qbitmap.h" +#include "qdrag.h" +#include "qpixmap.h" +#include "qevent.h" +#include "qfile.h" +#include "qtextcodec.h" +#include "qguiapplication.h" +#include "qpoint.h" +#include "qbuffer.h" +#include "qimage.h" +#include "qregexp.h" +#include "qdir.h" +#include "qdnd_p.h" +#include "qimagereader.h" +#include "qimagewriter.h" +#include "qdebug.h" +#include <ctype.h> + +#include <private/qguiapplication_p.h> + +#ifndef QT_NO_DRAGANDDROP + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_DRAGANDDROP + +//#define QDND_DEBUG + +#ifdef QDND_DEBUG +QString dragActionsToString(Qt::DropActions actions) +{ + QString str; + if (actions == Qt::IgnoreAction) { + if (!str.isEmpty()) + str += " | "; + str += "IgnoreAction"; + } + if (actions & Qt::LinkAction) { + if (!str.isEmpty()) + str += " | "; + str += "LinkAction"; + } + if (actions & Qt::CopyAction) { + if (!str.isEmpty()) + str += " | "; + str += "CopyAction"; + } + if (actions & Qt::MoveAction) { + if (!str.isEmpty()) + str += " | "; + str += "MoveAction"; + } + if ((actions & Qt::TargetMoveAction) == Qt::TargetMoveAction ) { + if (!str.isEmpty()) + str += " | "; + str += "TargetMoveAction"; + } + return str; +} + +QString KeyboardModifiersToString(Qt::KeyboardModifiers moderfies) +{ + QString str; + if (moderfies & Qt::ControlModifier) { + if (!str.isEmpty()) + str += " | "; + str += Qt::ControlModifier; + } + if (moderfies & Qt::AltModifier) { + if (!str.isEmpty()) + str += " | "; + str += Qt::AltModifier; + } + if (moderfies & Qt::ShiftModifier) { + if (!str.isEmpty()) + str += " | "; + str += Qt::ShiftModifier; + } + return str; +} +#endif + + +// the universe's only drag manager +QDragManager *QDragManager::instance = 0; + + +QDragManager::QDragManager() + : QObject(qApp) +{ + Q_ASSERT(!instance); + +#ifdef Q_WS_QWS + currentActionForOverrideCursor = Qt::IgnoreAction; +#endif + object = 0; + beingCancelled = false; + restoreCursor = false; + willDrop = false; + eventLoop = 0; + dropData = new QDropData(); + currentDropTarget = 0; +#ifdef Q_WS_X11 + xdndMimeTransferedPixmapIndex = 0; +#endif +} + + +QDragManager::~QDragManager() +{ +#ifndef QT_NO_CURSOR + if (restoreCursor) + QGuiApplication::restoreOverrideCursor(); +#endif + instance = 0; + delete dropData; +} + +QDragManager *QDragManager::self() +{ + if (!instance && !QGuiApplication::closingDown()) + instance = new QDragManager; + return instance; +} + +QPixmap QDragManager::dragCursor(Qt::DropAction action) const +{ + QDragPrivate * d = dragPrivate(); + if (d && d->customCursors.contains(action)) + return d->customCursors[action]; + else if (action == Qt::MoveAction) + return QGuiApplicationPrivate::instance()->getPixmapCursor(Qt::DragMoveCursor); + else if (action == Qt::CopyAction) + return QGuiApplicationPrivate::instance()->getPixmapCursor(Qt::DragCopyCursor); + else if (action == Qt::LinkAction) + return QGuiApplicationPrivate::instance()->getPixmapCursor(Qt::DragLinkCursor); +#ifdef Q_WS_WIN + else if (action == Qt::IgnoreAction) + return QGuiApplicationPrivate::instance()->getPixmapCursor(Qt::ForbiddenCursor); +#endif + return QPixmap(); +} + +bool QDragManager::hasCustomDragCursors() const +{ + QDragPrivate * d = dragPrivate(); + return d && !d->customCursors.isEmpty(); +} + +Qt::DropAction QDragManager::defaultAction(Qt::DropActions possibleActions, + Qt::KeyboardModifiers modifiers) const +{ +#ifdef QDND_DEBUG + qDebug("QDragManager::defaultAction(Qt::DropActions possibleActions)"); + qDebug("keyboard modifiers : %s", KeyboardModifiersToString(modifiers).latin1()); +#endif + + QDragPrivate *d = dragPrivate(); + Qt::DropAction defaultAction = d ? d->defaultDropAction : Qt::IgnoreAction; + + if (defaultAction == Qt::IgnoreAction) { + //This means that the drag was initiated by QDrag::start and we need to + //preserve the old behavior +#ifdef Q_WS_MAC + defaultAction = Qt::MoveAction; +#else + defaultAction = Qt::CopyAction; +#endif + } + +#ifdef Q_WS_MAC + if (modifiers & Qt::ControlModifier && modifiers & Qt::AltModifier) + defaultAction = Qt::LinkAction; + else if (modifiers & Qt::AltModifier) + defaultAction = Qt::CopyAction; + else if (modifiers & Qt::ControlModifier) + defaultAction = Qt::MoveAction; +#else + if (modifiers & Qt::ControlModifier && modifiers & Qt::ShiftModifier) + defaultAction = Qt::LinkAction; + else if (modifiers & Qt::ControlModifier) + defaultAction = Qt::CopyAction; + else if (modifiers & Qt::ShiftModifier) + defaultAction = Qt::MoveAction; + else if (modifiers & Qt::AltModifier) + defaultAction = Qt::LinkAction; +#endif + + // if the object is set take the list of possibles from it + if (object) + possibleActions = object->d_func()->possible_actions; + +#ifdef QDND_DEBUG + qDebug("possible actions : %s", dragActionsToString(possibleActions).latin1()); +#endif + + // Check if the action determined is allowed + if (!(possibleActions & defaultAction)) { + if (possibleActions & Qt::CopyAction) + defaultAction = Qt::CopyAction; + else if (possibleActions & Qt::MoveAction) + defaultAction = Qt::MoveAction; + else if (possibleActions & Qt::LinkAction) + defaultAction = Qt::LinkAction; + else + defaultAction = Qt::IgnoreAction; + } + +#ifdef QDND_DEBUG + qDebug("default action : %s", dragActionsToString(defaultAction).latin1()); +#endif + + return defaultAction; +} + +void QDragManager::setCurrentTarget(QObject *target, bool dropped) +{ + if (currentDropTarget == target) + return; + + currentDropTarget = target; + if (!dropped && object) { + object->d_func()->target = target; + emit object->targetChanged(target); + } + +} + +QObject *QDragManager::currentTarget() +{ + return currentDropTarget; +} + +#endif + +QDropData::QDropData() + : QInternalMimeData() +{ +} + +QDropData::~QDropData() +{ +} +#endif // QT_NO_DRAGANDDROP + +#if !(defined(QT_NO_DRAGANDDROP) && defined(QT_NO_CLIPBOARD)) + +static QStringList imageReadMimeFormats() +{ + QStringList formats; + QList<QByteArray> imageFormats = QImageReader::supportedImageFormats(); + for (int i = 0; i < imageFormats.size(); ++i) { + QString format = QLatin1String("image/"); + format += QString::fromLatin1(imageFormats.at(i).toLower()); + formats.append(format); + } + + //put png at the front because it is best + int pngIndex = formats.indexOf(QLatin1String("image/png")); + if (pngIndex != -1 && pngIndex != 0) + formats.move(pngIndex, 0); + + return formats; +} + + +static QStringList imageWriteMimeFormats() +{ + QStringList formats; + QList<QByteArray> imageFormats = QImageWriter::supportedImageFormats(); + for (int i = 0; i < imageFormats.size(); ++i) { + QString format = QLatin1String("image/"); + format += QString::fromLatin1(imageFormats.at(i).toLower()); + formats.append(format); + } + + //put png at the front because it is best + int pngIndex = formats.indexOf(QLatin1String("image/png")); + if (pngIndex != -1 && pngIndex != 0) + formats.move(pngIndex, 0); + + return formats; +} + +QInternalMimeData::QInternalMimeData() + : QMimeData() +{ +} + +QInternalMimeData::~QInternalMimeData() +{ +} + +bool QInternalMimeData::hasFormat(const QString &mimeType) const +{ + bool foundFormat = hasFormat_sys(mimeType); + if (!foundFormat && mimeType == QLatin1String("application/x-qt-image")) { + QStringList imageFormats = imageReadMimeFormats(); + for (int i = 0; i < imageFormats.size(); ++i) { + if ((foundFormat = hasFormat_sys(imageFormats.at(i)))) + break; + } + } + return foundFormat; +} + +QStringList QInternalMimeData::formats() const +{ + QStringList realFormats = formats_sys(); + if (!realFormats.contains(QLatin1String("application/x-qt-image"))) { + QStringList imageFormats = imageReadMimeFormats(); + for (int i = 0; i < imageFormats.size(); ++i) { + if (realFormats.contains(imageFormats.at(i))) { + realFormats += QLatin1String("application/x-qt-image"); + break; + } + } + } + return realFormats; +} + +QVariant QInternalMimeData::retrieveData(const QString &mimeType, QVariant::Type type) const +{ + QVariant data = retrieveData_sys(mimeType, type); + if (mimeType == QLatin1String("application/x-qt-image")) { + if (data.isNull() || (data.type() == QVariant::ByteArray && data.toByteArray().isEmpty())) { + // try to find an image + QStringList imageFormats = imageReadMimeFormats(); + for (int i = 0; i < imageFormats.size(); ++i) { + data = retrieveData_sys(imageFormats.at(i), type); + if (data.isNull() || (data.type() == QVariant::ByteArray && data.toByteArray().isEmpty())) + continue; + break; + } + } + // we wanted some image type, but all we got was a byte array. Convert it to an image. + if (data.type() == QVariant::ByteArray + && (type == QVariant::Image || type == QVariant::Pixmap || type == QVariant::Bitmap)) + data = QImage::fromData(data.toByteArray()); + + } else if (mimeType == QLatin1String("application/x-color") && data.type() == QVariant::ByteArray) { + QColor c; + QByteArray ba = data.toByteArray(); + if (ba.size() == 8) { + ushort * colBuf = (ushort *)ba.data(); + c.setRgbF(qreal(colBuf[0]) / qreal(0xFFFF), + qreal(colBuf[1]) / qreal(0xFFFF), + qreal(colBuf[2]) / qreal(0xFFFF), + qreal(colBuf[3]) / qreal(0xFFFF)); + data = c; + } else { + qWarning("Qt: Invalid color format"); + } + } else if (data.type() != type && data.type() == QVariant::ByteArray) { + // try to use mime data's internal conversion stuf. + QInternalMimeData *that = const_cast<QInternalMimeData *>(this); + that->setData(mimeType, data.toByteArray()); + data = QMimeData::retrieveData(mimeType, type); + that->clear(); + } + return data; +} + +bool QInternalMimeData::canReadData(const QString &mimeType) +{ + return imageReadMimeFormats().contains(mimeType); +} + +// helper functions for rendering mimedata to the system, this is needed because QMimeData is in core. +QStringList QInternalMimeData::formatsHelper(const QMimeData *data) +{ + QStringList realFormats = data->formats(); + if (realFormats.contains(QLatin1String("application/x-qt-image"))) { + // add all supported image formats + QStringList imageFormats = imageWriteMimeFormats(); + for (int i = 0; i < imageFormats.size(); ++i) { + if (!realFormats.contains(imageFormats.at(i))) + realFormats.append(imageFormats.at(i)); + } + } + return realFormats; +} + +bool QInternalMimeData::hasFormatHelper(const QString &mimeType, const QMimeData *data) +{ + + bool foundFormat = data->hasFormat(mimeType); + if (!foundFormat) { + if (mimeType == QLatin1String("application/x-qt-image")) { + // check all supported image formats + QStringList imageFormats = imageWriteMimeFormats(); + for (int i = 0; i < imageFormats.size(); ++i) { + if ((foundFormat = data->hasFormat(imageFormats.at(i)))) + break; + } + } else if (mimeType.startsWith(QLatin1String("image/"))) { + return data->hasImage() && imageWriteMimeFormats().contains(mimeType); + } + } + return foundFormat; +} + +QByteArray QInternalMimeData::renderDataHelper(const QString &mimeType, const QMimeData *data) +{ + QByteArray ba; + if (mimeType == QLatin1String("application/x-color")) { + /* QMimeData can only provide colors as QColor or the name + of a color as a QByteArray or a QString. So we need to do + the conversion to application/x-color here. + The application/x-color format is : + type: application/x-color + format: 16 + data[0]: red + data[1]: green + data[2]: blue + data[3]: opacity + */ + ba.resize(8); + ushort * colBuf = (ushort *)ba.data(); + QColor c = qvariant_cast<QColor>(data->colorData()); + colBuf[0] = ushort(c.redF() * 0xFFFF); + colBuf[1] = ushort(c.greenF() * 0xFFFF); + colBuf[2] = ushort(c.blueF() * 0xFFFF); + colBuf[3] = ushort(c.alphaF() * 0xFFFF); + } else { + ba = data->data(mimeType); + if (ba.isEmpty()) { + if (mimeType == QLatin1String("application/x-qt-image") && data->hasImage()) { + QImage image = qvariant_cast<QImage>(data->imageData()); + QBuffer buf(&ba); + buf.open(QBuffer::WriteOnly); + // would there not be PNG ?? + image.save(&buf, "PNG"); + } else if (mimeType.startsWith(QLatin1String("image/")) && data->hasImage()) { + QImage image = qvariant_cast<QImage>(data->imageData()); + QBuffer buf(&ba); + buf.open(QBuffer::WriteOnly); + image.save(&buf, mimeType.mid(mimeType.indexOf(QLatin1Char('/')) + 1).toLatin1().toUpper()); + } + } + } + return ba; +} + +#endif // QT_NO_DRAGANDDROP && QT_NO_CLIPBOARD + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qdnd_p.h b/src/gui/kernel/qdnd_p.h new file mode 100644 index 0000000000..cc74889bcb --- /dev/null +++ b/src/gui/kernel/qdnd_p.h @@ -0,0 +1,333 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDND_P_H +#define QDND_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "QtCore/qobject.h" +#include "QtCore/qmap.h" +#include "QtGui/qmime.h" +#include "QtGui/qdrag.h" +#include "QtGui/qpixmap.h" +#include "QtGui/qcursor.h" +#include "QtCore/qpoint.h" +#include "private/qobject_p.h" +#ifdef Q_WS_MAC +# include "private/qt_mac_p.h" +#endif + +#if defined(Q_WS_WIN) +# include <qt_windows.h> +# include <objidl.h> +#endif + +QT_BEGIN_NAMESPACE + +class QEventLoop; + +#if !(defined(QT_NO_DRAGANDDROP) && defined(QT_NO_CLIPBOARD)) + +class Q_GUI_EXPORT QInternalMimeData : public QMimeData +{ + Q_OBJECT +public: + QInternalMimeData(); + ~QInternalMimeData(); + + bool hasFormat(const QString &mimeType) const; + QStringList formats() const; + static bool canReadData(const QString &mimeType); + + + static QStringList formatsHelper(const QMimeData *data); + static bool hasFormatHelper(const QString &mimeType, const QMimeData *data); + static QByteArray renderDataHelper(const QString &mimeType, const QMimeData *data); + +protected: + QVariant retrieveData(const QString &mimeType, QVariant::Type type) const; + + virtual bool hasFormat_sys(const QString &mimeType) const = 0; + virtual QStringList formats_sys() const = 0; + virtual QVariant retrieveData_sys(const QString &mimeType, QVariant::Type type) const = 0; +}; + +#ifdef Q_WS_WIN +class QOleDataObject : public IDataObject +{ +public: + explicit QOleDataObject(QMimeData *mimeData); + virtual ~QOleDataObject(); + + void releaseQt(); + const QMimeData *mimeData() const; + DWORD reportedPerformedEffect() const; + + // IUnknown methods + STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj); + STDMETHOD_(ULONG,AddRef)(void); + STDMETHOD_(ULONG,Release)(void); + + // IDataObject methods + STDMETHOD(GetData)(LPFORMATETC pformatetcIn, LPSTGMEDIUM pmedium); + STDMETHOD(GetDataHere)(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium); + STDMETHOD(QueryGetData)(LPFORMATETC pformatetc); + STDMETHOD(GetCanonicalFormatEtc)(LPFORMATETC pformatetc, LPFORMATETC pformatetcOut); + STDMETHOD(SetData)(LPFORMATETC pformatetc, STGMEDIUM FAR * pmedium, + BOOL fRelease); + STDMETHOD(EnumFormatEtc)(DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc); + STDMETHOD(DAdvise)(FORMATETC FAR* pFormatetc, DWORD advf, + LPADVISESINK pAdvSink, DWORD FAR* pdwConnection); + STDMETHOD(DUnadvise)(DWORD dwConnection); + STDMETHOD(EnumDAdvise)(LPENUMSTATDATA FAR* ppenumAdvise); + +private: + ULONG m_refs; + QPointer<QMimeData> data; + int CF_PERFORMEDDROPEFFECT; + DWORD performedEffect; +}; + +class QOleEnumFmtEtc : public IEnumFORMATETC +{ +public: + explicit QOleEnumFmtEtc(const QVector<FORMATETC> &fmtetcs); + explicit QOleEnumFmtEtc(const QVector<LPFORMATETC> &lpfmtetcs); + virtual ~QOleEnumFmtEtc(); + + bool isNull() const; + + // IUnknown methods + STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj); + STDMETHOD_(ULONG,AddRef)(void); + STDMETHOD_(ULONG,Release)(void); + + // IEnumFORMATETC methods + STDMETHOD(Next)(ULONG celt, LPFORMATETC rgelt, ULONG FAR* pceltFetched); + STDMETHOD(Skip)(ULONG celt); + STDMETHOD(Reset)(void); + STDMETHOD(Clone)(LPENUMFORMATETC FAR* newEnum); + +private: + bool copyFormatEtc(LPFORMATETC dest, LPFORMATETC src) const; + + ULONG m_dwRefs; + ULONG m_nIndex; + QVector<LPFORMATETC> m_lpfmtetcs; + bool m_isNull; +}; + +#endif + +#endif //QT_NO_DRAGANDDROP && QT_NO_CLIPBOARD + +#ifndef QT_NO_DRAGANDDROP + +class QDragPrivate : public QObjectPrivate +{ +public: + QObject *source; + QObject *target; + QMimeData *data; + QPixmap pixmap; + QPoint hotspot; + Qt::DropActions possible_actions; + Qt::DropAction executed_action; + QMap<Qt::DropAction, QPixmap> customCursors; + Qt::DropAction defaultDropAction; +}; + +class QDropData : public QInternalMimeData +{ + Q_OBJECT +public: + QDropData(); + ~QDropData(); + +protected: + bool hasFormat_sys(const QString &mimeType) const; + QStringList formats_sys() const; + QVariant retrieveData_sys(const QString &mimeType, QVariant::Type type) const; + +#if defined(Q_WS_WIN) +public: + LPDATAOBJECT currentDataObject; +#endif +}; + +class Q_GUI_EXPORT QDragManager: public QObject { + Q_OBJECT + + QDragManager(); + ~QDragManager(); + // only friend classes can use QDragManager. + friend class QDrag; + friend class QDragMoveEvent; + friend class QDropEvent; + friend class QApplication; + + bool eventFilter(QObject *, QEvent *); + void timerEvent(QTimerEvent*); + +public: + Qt::DropAction drag(QDrag *); + + void cancel(bool deleteSource = true); + void move(const QPoint &); + void drop(); + void updatePixmap(); + QObject *source() const { return object ? object->d_func()->source : 0; } + QDragPrivate *dragPrivate() const { return object ? object->d_func() : 0; } + static QDragPrivate *dragPrivate(QDrag *drag) { return drag ? drag->d_func() : 0; } + + static QDragManager *self(); + Qt::DropAction defaultAction(Qt::DropActions possibleActions, + Qt::KeyboardModifiers modifiers) const; + + QDrag *object; + + void updateCursor(); + + bool beingCancelled; + bool restoreCursor; + bool willDrop; + QEventLoop *eventLoop; + + QPixmap dragCursor(Qt::DropAction action) const; + + bool hasCustomDragCursors() const; + + QDropData *dropData; + + void emitActionChanged(Qt::DropAction newAction) { if (object) emit object->actionChanged(newAction); } + + void setCurrentTarget(QObject *target, bool dropped = false); + QObject *currentTarget(); + +#ifdef Q_WS_X11 + QPixmap xdndMimeTransferedPixmap[2]; + int xdndMimeTransferedPixmapIndex; +#endif + +private: +#if defined(Q_WS_QWS) || defined(Q_WS_QPA) + Qt::DropAction currentActionForOverrideCursor; +#endif +#ifdef Q_OS_SYMBIAN +#ifndef QT_NO_CURSOR + QCursor overrideCursor; +#endif +#endif + QObject *currentDropTarget; + + static QDragManager *instance; + Q_DISABLE_COPY(QDragManager) +}; + + +#if defined(Q_WS_WIN) + +class QOleDropTarget : public IDropTarget +{ +public: + QOleDropTarget(QWidget* w); + virtual ~QOleDropTarget() {} + + void releaseQt(); + + // IUnknown methods + STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppvObj); + STDMETHOD_(ULONG, AddRef)(void); + STDMETHOD_(ULONG, Release)(void); + + // IDropTarget methods + STDMETHOD(DragEnter)(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect); + STDMETHOD(DragOver)(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect); + STDMETHOD(DragLeave)(); + STDMETHOD(Drop)(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect); + +private: + ULONG m_refs; + QWidget* widget; + QPointer<QWidget> currentWidget; + QRect answerRect; + QPoint lastPoint; + DWORD chosenEffect; + DWORD lastKeyState; + + void sendDragEnterEvent(QWidget *to, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect); +}; + +#endif + +#if defined (Q_WS_MAC) +class QCocoaDropData : public QInternalMimeData +{ + Q_OBJECT +public: + QCocoaDropData(CFStringRef pasteboard); + ~QCocoaDropData(); + +protected: + bool hasFormat_sys(const QString &mimeType) const; + QStringList formats_sys() const; + QVariant retrieveData_sys(const QString &mimeType, QVariant::Type type) const; +public: + CFStringRef dropPasteboard; +}; +#endif + +#endif // !QT_NO_DRAGANDDROP + + +QT_END_NAMESPACE + +#endif // QDND_P_H diff --git a/src/gui/kernel/qdnd_qpa.cpp b/src/gui/kernel/qdnd_qpa.cpp new file mode 100644 index 0000000000..e5715bb568 --- /dev/null +++ b/src/gui/kernel/qdnd_qpa.cpp @@ -0,0 +1,434 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qguiapplication.h" + +#ifndef QT_NO_DRAGANDDROP + +#include "qdatetime.h" +#include "qbitmap.h" +#include "qcursor.h" +#include "qevent.h" +#include "qpainter.h" +#include "qdnd_p.h" +#include "qwindow.h" + +QT_BEGIN_NAMESPACE + +QT_USE_NAMESPACE + +static QPixmap *defaultPm = 0; +static const int default_pm_hotx = -2; +static const int default_pm_hoty = -16; +static const char *const default_pm[] = { +"13 9 3 1", +". c None", +" c #000000", +"X c #FFFFFF", +"X X X X X X X", +" X X X X X X ", +"X ......... X", +" X.........X ", +"X ......... X", +" X.........X ", +"X ......... X", +" X X X X X X ", +"X X X X X X X", +}; + +// Shift/Ctrl handling, and final drop status +static Qt::DropAction global_accepted_action = Qt::CopyAction; +static Qt::DropActions possible_actions = Qt::IgnoreAction; + + +// static variables in place of a proper cross-process solution +static QDrag *drag_object; +static bool qt_qws_dnd_dragging = false; + + +static Qt::KeyboardModifiers oldstate; + +class QShapedPixmapWindow : public QWindow { + QPixmap pixmap; +public: + QShapedPixmapWindow() : + QWindow(0) + { + setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint); + // ### Should we set the surface type to raster? + // ### FIXME +// setAttribute(Qt::WA_TransparentForMouseEvents); + } + + void move(const QPoint &p) { + QRect g = geometry(); + g.setTopLeft(p); + setGeometry(g); + } + void setPixmap(QPixmap pm) + { + pixmap = pm; + // ### +// if (!pixmap.mask().isNull()) { +// setMask(pixmap.mask()); +// } else { +// clearMask(); +// } +// resize(pm.width(),pm.height()); + } + + // ### Get it painted again! +// void paintEvent(QPaintEvent*) +// { +// QPainter p(this); +// p.drawPixmap(0,0,pixmap); +// } +}; + + +static QShapedPixmapWindow *qt_qws_dnd_deco = 0; + + +void QDragManager::updatePixmap() +{ + if (qt_qws_dnd_deco) { + QPixmap pm; + QPoint pm_hot(default_pm_hotx,default_pm_hoty); + if (drag_object) { + pm = drag_object->pixmap(); + if (!pm.isNull()) + pm_hot = drag_object->hotSpot(); + } + if (pm.isNull()) { + if (!defaultPm) + defaultPm = new QPixmap(default_pm); + pm = *defaultPm; + } + qt_qws_dnd_deco->setPixmap(pm); + qt_qws_dnd_deco->move(QCursor::pos()-pm_hot); + if (willDrop) { + qt_qws_dnd_deco->show(); + } else { + qt_qws_dnd_deco->hide(); + } + } +} + +void QDragManager::timerEvent(QTimerEvent *) { } + +void QDragManager::move(const QPoint &) { } + +void QDragManager::updateCursor() +{ +#ifndef QT_NO_CURSOR + if (willDrop) { + if (qt_qws_dnd_deco) + qt_qws_dnd_deco->show(); + if (currentActionForOverrideCursor != global_accepted_action) { + QGuiApplication::changeOverrideCursor(QCursor(dragCursor(global_accepted_action), 0, 0)); + currentActionForOverrideCursor = global_accepted_action; + } + } else { + QCursor *overrideCursor = QGuiApplication::overrideCursor(); + if (!overrideCursor || overrideCursor->shape() != Qt::ForbiddenCursor) { + QGuiApplication::changeOverrideCursor(QCursor(Qt::ForbiddenCursor)); + currentActionForOverrideCursor = Qt::IgnoreAction; + } + if (qt_qws_dnd_deco) + qt_qws_dnd_deco->hide(); + } +#endif +} + + +bool QDragManager::eventFilter(QObject *o, QEvent *e) +{ +#if 0 + // ### + if (beingCancelled) { + if (e->type() == QEvent::KeyRelease && static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape) { + qApp->removeEventFilter(this); + Q_ASSERT(object == 0); + beingCancelled = false; + eventLoop->exit(); + return true; // block the key release + } + return false; + } + + + + if (!o->isWidgetType()) + return false; + + switch(e->type()) { + case QEvent::ShortcutOverride: + // prevent accelerators from firing while dragging + e->accept(); + return true; + + case QEvent::KeyPress: + case QEvent::KeyRelease: + { + QKeyEvent *ke = ((QKeyEvent*)e); + if (ke->key() == Qt::Key_Escape && e->type() == QEvent::KeyPress) { + cancel(); + qApp->removeEventFilter(this); + beingCancelled = false; + eventLoop->exit(); + } else { + updateCursor(); + } + return true; // Eat all key events + } + + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + { + if (!object) { //#### this should not happen + qWarning("QDragManager::eventFilter: No object"); + return true; + } + + QDragManager *manager = QDragManager::self(); + QMimeData *dropData = manager->object ? manager->dragPrivate()->data : manager->dropData; + if (manager->object) + possible_actions = manager->dragPrivate()->possible_actions; + else + possible_actions = Qt::IgnoreAction; + + QMouseEvent *me = (QMouseEvent *)e; + if (me->buttons()) { + Qt::DropAction prevAction = global_accepted_action; + QWidget *cw = QApplication::widgetAt(me->globalPos()); + + // Fix for when we move mouse on to the deco widget + if (qt_qws_dnd_deco && cw == qt_qws_dnd_deco) + cw = object->target(); + + while (cw && !cw->acceptDrops() && !cw->isWindow()) + cw = cw->parentWidget(); + + if (object->target() != cw) { + if (object->target()) { + QDragLeaveEvent dle; + QCoreApplication::sendEvent(object->target(), &dle); + willDrop = false; + global_accepted_action = Qt::IgnoreAction; + updateCursor(); + restoreCursor = true; + object->d_func()->target = 0; + } + if (cw && cw->acceptDrops()) { + object->d_func()->target = cw; + QDragEnterEvent dee(cw->mapFromGlobal(me->globalPos()), possible_actions, dropData, + me->buttons(), me->modifiers()); + QCoreApplication::sendEvent(object->target(), &dee); + willDrop = dee.isAccepted() && dee.dropAction() != Qt::IgnoreAction; + global_accepted_action = willDrop ? dee.dropAction() : Qt::IgnoreAction; + updateCursor(); + restoreCursor = true; + } + } else if (cw) { + QDragMoveEvent dme(cw->mapFromGlobal(me->globalPos()), possible_actions, dropData, + me->buttons(), me->modifiers()); + if (global_accepted_action != Qt::IgnoreAction) { + dme.setDropAction(global_accepted_action); + dme.accept(); + } + QCoreApplication::sendEvent(cw, &dme); + willDrop = dme.isAccepted(); + global_accepted_action = willDrop ? dme.dropAction() : Qt::IgnoreAction; + updatePixmap(); + updateCursor(); + } + if (global_accepted_action != prevAction) + emitActionChanged(global_accepted_action); + } + return true; // Eat all mouse events + } + + case QEvent::MouseButtonRelease: + { + qApp->removeEventFilter(this); + if (restoreCursor) { + willDrop = false; +#ifndef QT_NO_CURSOR + QGuiApplication::restoreOverrideCursor(); +#endif + restoreCursor = false; + } + if (object && object->target()) { + QMouseEvent *me = (QMouseEvent *)e; + + QDragManager *manager = QDragManager::self(); + QMimeData *dropData = manager->object ? manager->dragPrivate()->data : manager->dropData; + + QDropEvent de(object->target()->mapFromGlobal(me->globalPos()), possible_actions, dropData, + me->buttons(), me->modifiers()); + QCoreApplication::sendEvent(object->target(), &de); + if (de.isAccepted()) + global_accepted_action = de.dropAction(); + else + global_accepted_action = Qt::IgnoreAction; + + if (object) + object->deleteLater(); + drag_object = object = 0; + } + eventLoop->exit(); + return true; // Eat all mouse events + } + + default: + break; + } +#endif + return false; +} + +Qt::DropAction QDragManager::drag(QDrag *o) +{ + if (object == o || !o || !o->source()) + return Qt::IgnoreAction; + + if (object) { + cancel(); + qApp->removeEventFilter(this); + beingCancelled = false; + } + + object = drag_object = o; + qt_qws_dnd_deco = new QShapedPixmapWindow(); + oldstate = Qt::NoModifier; // #### Should use state that caused the drag +// drag_mode = mode; + + willDrop = false; + updatePixmap(); + updateCursor(); + restoreCursor = true; + object->d_func()->target = 0; + qApp->installEventFilter(this); + + global_accepted_action = Qt::CopyAction; +#ifndef QT_NO_CURSOR + qApp->setOverrideCursor(Qt::ArrowCursor); + restoreCursor = true; + updateCursor(); +#endif + + qt_qws_dnd_dragging = true; + + eventLoop = new QEventLoop; + (void) eventLoop->exec(); + delete eventLoop; + eventLoop = 0; + + delete qt_qws_dnd_deco; + qt_qws_dnd_deco = 0; + qt_qws_dnd_dragging = false; + + + return global_accepted_action; +} + + +void QDragManager::cancel(bool deleteSource) +{ +// qDebug("QDragManager::cancel"); + beingCancelled = true; + + if (object->target()) { + QDragLeaveEvent dle; + QCoreApplication::sendEvent(object->target(), &dle); + } + +#ifndef QT_NO_CURSOR + if (restoreCursor) { + QGuiApplication::restoreOverrideCursor(); + restoreCursor = false; + } +#endif + + if (drag_object) { + if (deleteSource) + object->deleteLater(); + drag_object = object = 0; + } + + delete qt_qws_dnd_deco; + qt_qws_dnd_deco = 0; + + global_accepted_action = Qt::IgnoreAction; +} + + +void QDragManager::drop() +{ +} + +QVariant QDropData::retrieveData_sys(const QString &mimetype, QVariant::Type type) const +{ + if (!drag_object) + return QVariant(); + QByteArray data = drag_object->mimeData()->data(mimetype); + if (type == QVariant::String) + return QString::fromUtf8(data); + return data; +} + +bool QDropData::hasFormat_sys(const QString &format) const +{ + return formats().contains(format); +} + +QStringList QDropData::formats_sys() const +{ + if (drag_object) + return drag_object->mimeData()->formats(); + return QStringList(); +} + + +#endif // QT_NO_DRAGANDDROP + + +QT_END_NAMESPACE diff --git a/src/gui/kernel/qdrag.cpp b/src/gui/kernel/qdrag.cpp new file mode 100644 index 0000000000..bb56d061c1 --- /dev/null +++ b/src/gui/kernel/qdrag.cpp @@ -0,0 +1,358 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qdrag.h> +#include <qpixmap.h> +#include <qpoint.h> +#include "qdnd_p.h" + +#ifndef QT_NO_DRAGANDDROP + +QT_BEGIN_NAMESPACE + +/*! + \class QDrag + \brief The QDrag class provides support for MIME-based drag and drop data + transfer. + + Drag and drop is an intuitive way for users to copy or move data around in an + application, and is used in many desktop environments as a mechanism for copying + data between applications. Drag and drop support in Qt is centered around the + QDrag class that handles most of the details of a drag and drop operation. + + The data to be transferred by the drag and drop operation is contained in a + QMimeData object. This is specified with the setMimeData() function in the + following way: + + \snippet doc/src/snippets/dragging/mainwindow.cpp 1 + + Note that setMimeData() assigns ownership of the QMimeData object to the + QDrag object. The QDrag must be constructed on the heap with a parent QObject + to ensure that Qt can clean up after the drag and drop operation has been + completed. + + A pixmap can be used to represent the data while the drag is in + progress, and will move with the cursor to the drop target. This + pixmap typically shows an icon that represents the MIME type of + the data being transferred, but any pixmap can be set with + setPixmap(). The cursor's hot spot can be given a position + relative to the top-left corner of the pixmap with the + setHotSpot() function. The following code positions the pixmap so + that the cursor's hot spot points to the center of its bottom + edge: + + \snippet doc/src/snippets/separations/finalwidget.cpp 2 + + \note On X11, the pixmap may not be able to keep up with the mouse + movements if the hot spot causes the pixmap to be displayed + directly under the cursor. + + The source and target widgets can be found with source() and target(). + These functions are often used to determine whether drag and drop operations + started and finished at the same widget, so that special behavior can be + implemented. + + QDrag only deals with the drag and drop operation itself. It is up to the + developer to decide when a drag operation begins, and how a QDrag object should + be constructed and used. For a given widget, it is often necessary to + reimplement \l{QWidget::mousePressEvent()}{mousePressEvent()} to determine + whether the user has pressed a mouse button, and reimplement + \l{QWidget::mouseMoveEvent()}{mouseMoveEvent()} to check whether a QDrag is + required. + + \sa {Drag and Drop}, QClipboard, QMimeData, QWindowsMime, QMacPasteboardMime, + {Draggable Icons Example}, {Draggable Text Example}, {Drop Site Example}, + {Fridge Magnets Example} +*/ + +/*! + Constructs a new drag object for the widget specified by \a dragSource. +*/ +QDrag::QDrag(QObject *dragSource) + : QObject(*new QDragPrivate, dragSource) +{ + Q_D(QDrag); + d->source = dragSource; + d->target = 0; + d->data = 0; + d->hotspot = QPoint(-10, -10); + d->possible_actions = Qt::CopyAction; + d->executed_action = Qt::IgnoreAction; + d->defaultDropAction = Qt::IgnoreAction; +} + +/*! + Destroys the drag object. +*/ +QDrag::~QDrag() +{ + Q_D(QDrag); + delete d->data; + QDragManager *manager = QDragManager::self(); + if (manager && manager->object == this) + manager->cancel(false); +} + +/*! + Sets the data to be sent to the given MIME \a data. Ownership of the data is + transferred to the QDrag object. +*/ +void QDrag::setMimeData(QMimeData *data) +{ + Q_D(QDrag); + if (d->data == data) + return; + if (d->data != 0) + delete d->data; + d->data = data; +} + +/*! + Returns the MIME data that is encapsulated by the drag object. +*/ +QMimeData *QDrag::mimeData() const +{ + Q_D(const QDrag); + return d->data; +} + +/*! + Sets \a pixmap as the pixmap used to represent the data in a drag + and drop operation. You can only set a pixmap before the drag is + started. +*/ +void QDrag::setPixmap(const QPixmap &pixmap) +{ + Q_D(QDrag); + d->pixmap = pixmap; +} + +/*! + Returns the pixmap used to represent the data in a drag and drop operation. +*/ +QPixmap QDrag::pixmap() const +{ + Q_D(const QDrag); + return d->pixmap; +} + +/*! + Sets the position of the hot spot relative to the top-left corner of the + pixmap used to the point specified by \a hotspot. + + \bold{Note:} on X11, the pixmap may not be able to keep up with the mouse + movements if the hot spot causes the pixmap to be displayed + directly under the cursor. +*/ +void QDrag::setHotSpot(const QPoint& hotspot) +{ + Q_D(QDrag); + d->hotspot = hotspot; +} + +/*! + Returns the position of the hot spot relative to the top-left corner of the + cursor. +*/ +QPoint QDrag::hotSpot() const +{ + Q_D(const QDrag); + return d->hotspot; +} + +/*! + Returns the source of the drag object. This is the widget where the drag + and drop operation originated. +*/ +QObject *QDrag::source() const +{ + Q_D(const QDrag); + return d->source; +} + +/*! + Returns the target of the drag and drop operation. This is the widget where + the drag object was dropped. +*/ +QObject *QDrag::target() const +{ + Q_D(const QDrag); + return d->target; +} + +/*! + \since 4.3 + + Starts the drag and drop operation and returns a value indicating the requested + drop action when it is completed. The drop actions that the user can choose + from are specified in \a supportedActions. The default proposed action will be selected + among the allowed actions in the following order: Move, Copy and Link. + + \bold{Note:} On Linux and Mac OS X, the drag and drop operation + can take some time, but this function does not block the event + loop. Other events are still delivered to the application while + the operation is performed. On Windows, the Qt event loop is + blocked while during the operation. +*/ + +Qt::DropAction QDrag::exec(Qt::DropActions supportedActions) +{ + return exec(supportedActions, Qt::IgnoreAction); +} + +/*! + \since 4.3 + + Starts the drag and drop operation and returns a value indicating the requested + drop action when it is completed. The drop actions that the user can choose + from are specified in \a supportedActions. + + The \a defaultDropAction determines which action will be proposed when the user performs a + drag without using modifier keys. + + \bold{Note:} On Linux and Mac OS X, the drag and drop operation + can take some time, but this function does not block the event + 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. However, QDrag::exec() on + Windows causes processEvents() to be called frequently to keep the GUI responsive. + If any loops or operations are called while a drag operation is active, it will block the drag operation. +*/ + +Qt::DropAction QDrag::exec(Qt::DropActions supportedActions, Qt::DropAction defaultDropAction) +{ + Q_D(QDrag); + if (!d->data) { + qWarning("QDrag: No mimedata set before starting the drag"); + return d->executed_action; + } + QDragManager *manager = QDragManager::self(); + d->defaultDropAction = Qt::IgnoreAction; + d->possible_actions = supportedActions; + + if (manager) { + if (defaultDropAction == Qt::IgnoreAction) { + if (supportedActions & Qt::MoveAction) { + d->defaultDropAction = Qt::MoveAction; + } else if (supportedActions & Qt::CopyAction) { + d->defaultDropAction = Qt::CopyAction; + } else if (supportedActions & Qt::LinkAction) { + d->defaultDropAction = Qt::LinkAction; + } + } else { + d->defaultDropAction = defaultDropAction; + } + d->executed_action = manager->drag(this); + } + + return d->executed_action; +} + +/*! + \obsolete + + \bold{Note:} It is recommended to use exec() instead of this function. + + Starts the drag and drop operation and returns a value indicating the requested + drop action when it is completed. The drop actions that the user can choose + from are specified in \a request. Qt::CopyAction is always allowed. + + \bold{Note:} Although the drag and drop operation can take some time, this function + does not block the event loop. Other events are still delivered to the application + while the operation is performed. + + \sa exec() +*/ +Qt::DropAction QDrag::start(Qt::DropActions request) +{ + Q_D(QDrag); + if (!d->data) { + qWarning("QDrag: No mimedata set before starting the drag"); + return d->executed_action; + } + QDragManager *manager = QDragManager::self(); + d->defaultDropAction = Qt::IgnoreAction; + d->possible_actions = request | Qt::CopyAction; + if (manager) + d->executed_action = manager->drag(this); + return d->executed_action; +} + +/*! + Sets the drag \a cursor for the \a action. This allows you + to override the default native cursors. To revert to using the + native cursor for \a action pass in a null QPixmap as \a cursor. + + The \a action can only be CopyAction, MoveAction or LinkAction. + All other values of DropAction are ignored. +*/ +void QDrag::setDragCursor(const QPixmap &cursor, Qt::DropAction action) +{ + Q_D(QDrag); + if (action != Qt::CopyAction && action != Qt::MoveAction && action != Qt::LinkAction) + return; + if (cursor.isNull()) + d->customCursors.remove(action); + else + d->customCursors[action] = cursor; +} + +/*! + \fn void QDrag::actionChanged(Qt::DropAction action) + + This signal is emitted when the \a action associated with the + drag changes. + + \sa targetChanged() +*/ + +/*! + \fn void QDrag::targetChanged(QObject *newTarget) + + This signal is emitted when the target of the drag and drop + operation changes, with \a newTarget the new target. + + \sa target(), actionChanged() +*/ + +QT_END_NAMESPACE + +#endif // QT_NO_DRAGANDDROP diff --git a/src/gui/kernel/qdrag.h b/src/gui/kernel/qdrag.h new file mode 100644 index 0000000000..d014382e8c --- /dev/null +++ b/src/gui/kernel/qdrag.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDRAG_H +#define QDRAG_H + +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +#ifndef QT_NO_DRAGANDDROP +class QMimeData; +class QDragPrivate; +class QPixmap; +class QPoint; +class QDragManager; + +class Q_GUI_EXPORT QDrag : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QDrag) +public: + explicit QDrag(QObject *dragSource); + ~QDrag(); + + void setMimeData(QMimeData *data); + QMimeData *mimeData() const; + + void setPixmap(const QPixmap &); + QPixmap pixmap() const; + + void setHotSpot(const QPoint &hotspot); + QPoint hotSpot() const; + + QObject *source() const; + QObject *target() const; + + Qt::DropAction start(Qt::DropActions supportedActions = Qt::CopyAction); + Qt::DropAction exec(Qt::DropActions supportedActions = Qt::MoveAction); + Qt::DropAction exec(Qt::DropActions supportedActions, Qt::DropAction defaultAction); + + void setDragCursor(const QPixmap &cursor, Qt::DropAction action); + +Q_SIGNALS: + void actionChanged(Qt::DropAction action); + void targetChanged(QObject *newTarget); + +private: + friend class QDragManager; + Q_DISABLE_COPY(QDrag) +}; + +#endif // QT_NO_DRAGANDDROP + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QDRAG_H |