| /**************************************************************************** |
| ** |
| ** 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$ |
| ** GNU Lesser General Public License Usage |
| ** 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. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU General |
| ** Public License version 3.0 as published by the Free Software Foundation |
| ** and appearing in the file LICENSE.GPL included in the packaging of this |
| ** file. Please review the following information to ensure the GNU General |
| ** Public License version 3.0 requirements will be met: |
| ** http://www.gnu.org/copyleft/gpl.html. |
| ** |
| ** Other Usage |
| ** Alternatively, this file may be used in accordance with the terms and |
| ** conditions contained in a signed written agreement between you and Nokia. |
| ** |
| ** |
| ** |
| ** |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qapplication.h" |
| |
| #include "qapplication_p.h" |
| #include "qevent.h" |
| #include "qpainter.h" |
| #include "qwidget.h" |
| #include "qbuffer.h" |
| #include "qdatastream.h" |
| #include "qcursor.h" |
| #include "qt_windows.h" |
| #include <shlobj.h> |
| #ifndef QT_NO_ACCESSIBILITY |
| #include "qaccessible.h" |
| #endif |
| #include "qdnd_p.h" |
| #include "qdebug.h" |
| |
| #if defined(Q_OS_WINCE) |
| #include "qguifunctions_wince.h" |
| #endif |
| |
| // support for xbuttons |
| #ifndef MK_XBUTTON1 |
| #define MK_XBUTTON1 0x0020 |
| #define MK_XBUTTON2 0x0040 |
| #endif |
| |
| QT_BEGIN_NAMESPACE |
| |
| #if !(defined(QT_NO_DRAGANDDROP) && defined(QT_NO_CLIPBOARD)) |
| |
| //--------------------------------------------------------------------- |
| // QOleDataObject Constructor |
| //--------------------------------------------------------------------- |
| |
| QOleDataObject::QOleDataObject(QMimeData *mimeData) |
| { |
| m_refs = 1; |
| data = mimeData; |
| CF_PERFORMEDDROPEFFECT = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT); |
| performedEffect = DROPEFFECT_NONE; |
| } |
| |
| QOleDataObject::~QOleDataObject() |
| { |
| } |
| |
| void QOleDataObject::releaseQt() |
| { |
| data = 0; |
| } |
| |
| const QMimeData *QOleDataObject::mimeData() const |
| { |
| return data; |
| } |
| |
| DWORD QOleDataObject::reportedPerformedEffect() const |
| { |
| return performedEffect; |
| } |
| |
| //--------------------------------------------------------------------- |
| // IUnknown Methods |
| //--------------------------------------------------------------------- |
| |
| STDMETHODIMP |
| QOleDataObject::QueryInterface(REFIID iid, void FAR* FAR* ppv) |
| { |
| if (iid == IID_IUnknown || iid == IID_IDataObject) { |
| *ppv = this; |
| AddRef(); |
| return NOERROR; |
| } |
| *ppv = NULL; |
| return ResultFromScode(E_NOINTERFACE); |
| } |
| |
| STDMETHODIMP_(ULONG) |
| QOleDataObject::AddRef(void) |
| { |
| return ++m_refs; |
| } |
| |
| STDMETHODIMP_(ULONG) |
| QOleDataObject::Release(void) |
| { |
| if (--m_refs == 0) { |
| releaseQt(); |
| delete this; |
| return 0; |
| } |
| return m_refs; |
| } |
| |
| //--------------------------------------------------------------------- |
| // IDataObject Methods |
| // |
| // The following methods are NOT supported for data transfer using the |
| // clipboard or drag-drop: |
| // |
| // IDataObject::SetData -- return E_NOTIMPL |
| // IDataObject::DAdvise -- return OLE_E_ADVISENOTSUPPORTED |
| // ::DUnadvise |
| // ::EnumDAdvise |
| // IDataObject::GetCanonicalFormatEtc -- return E_NOTIMPL |
| // (NOTE: must set pformatetcOut->ptd = NULL) |
| //--------------------------------------------------------------------- |
| |
| STDMETHODIMP |
| QOleDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium) |
| { |
| #ifdef QDND_DEBUG |
| qDebug("QOleDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium)"); |
| #ifndef Q_OS_WINCE |
| wchar_t buf[256] = {0}; |
| GetClipboardFormatName(pformatetc->cfFormat, buf, 255); |
| qDebug("CF = %d : %s", pformatetc->cfFormat, QString::fromWCharArray(buf)); |
| #endif |
| #endif |
| |
| if (!data) |
| return ResultFromScode(DATA_E_FORMATETC); |
| |
| QWindowsMime *converter = QWindowsMime::converterFromMime(*pformatetc, data); |
| |
| if (converter && converter->convertFromMime(*pformatetc, data, pmedium)) |
| return ResultFromScode(S_OK); |
| else |
| return ResultFromScode(DATA_E_FORMATETC); |
| } |
| |
| STDMETHODIMP |
| QOleDataObject::GetDataHere(LPFORMATETC, LPSTGMEDIUM) |
| { |
| return ResultFromScode(DATA_E_FORMATETC); |
| } |
| |
| STDMETHODIMP |
| QOleDataObject::QueryGetData(LPFORMATETC pformatetc) |
| { |
| #ifdef QDND_DEBUG |
| qDebug("QOleDataObject::QueryGetData(LPFORMATETC pformatetc)"); |
| #endif |
| |
| if (!data) |
| return ResultFromScode(DATA_E_FORMATETC); |
| |
| if (QWindowsMime::converterFromMime(*pformatetc, data)) |
| return ResultFromScode(S_OK); |
| return ResultFromScode(S_FALSE); |
| } |
| |
| STDMETHODIMP |
| QOleDataObject::GetCanonicalFormatEtc(LPFORMATETC, LPFORMATETC pformatetcOut) |
| { |
| pformatetcOut->ptd = NULL; |
| return ResultFromScode(E_NOTIMPL); |
| } |
| |
| STDMETHODIMP |
| QOleDataObject::SetData(LPFORMATETC pFormatetc, STGMEDIUM *pMedium, BOOL fRelease) |
| { |
| if (pFormatetc->cfFormat == CF_PERFORMEDDROPEFFECT && pMedium->tymed == TYMED_HGLOBAL) { |
| DWORD * val = (DWORD*)GlobalLock(pMedium->hGlobal); |
| performedEffect = *val; |
| GlobalUnlock(pMedium->hGlobal); |
| if (fRelease) |
| ReleaseStgMedium(pMedium); |
| return ResultFromScode(S_OK); |
| } |
| return ResultFromScode(E_NOTIMPL); |
| } |
| |
| |
| STDMETHODIMP |
| QOleDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc) |
| { |
| #ifdef QDND_DEBUG |
| qDebug("QOleDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc)"); |
| #endif |
| |
| if (!data) |
| return ResultFromScode(DATA_E_FORMATETC); |
| |
| SCODE sc = S_OK; |
| |
| QVector<FORMATETC> fmtetcs; |
| if (dwDirection == DATADIR_GET) { |
| fmtetcs = QWindowsMime::allFormatsForMime(data); |
| } else { |
| FORMATETC formatetc; |
| formatetc.cfFormat = CF_PERFORMEDDROPEFFECT; |
| formatetc.dwAspect = DVASPECT_CONTENT; |
| formatetc.lindex = -1; |
| formatetc.ptd = NULL; |
| formatetc.tymed = TYMED_HGLOBAL; |
| fmtetcs.append(formatetc); |
| } |
| |
| QOleEnumFmtEtc *enumFmtEtc = new QOleEnumFmtEtc(fmtetcs); |
| *ppenumFormatEtc = enumFmtEtc; |
| if (enumFmtEtc->isNull()) { |
| delete enumFmtEtc; |
| *ppenumFormatEtc = NULL; |
| sc = E_OUTOFMEMORY; |
| } |
| |
| return ResultFromScode(sc); |
| } |
| |
| STDMETHODIMP |
| QOleDataObject::DAdvise(FORMATETC FAR*, DWORD, |
| LPADVISESINK, DWORD FAR*) |
| { |
| return ResultFromScode(OLE_E_ADVISENOTSUPPORTED); |
| } |
| |
| |
| STDMETHODIMP |
| QOleDataObject::DUnadvise(DWORD) |
| { |
| return ResultFromScode(OLE_E_ADVISENOTSUPPORTED); |
| } |
| |
| STDMETHODIMP |
| QOleDataObject::EnumDAdvise(LPENUMSTATDATA FAR*) |
| { |
| return ResultFromScode(OLE_E_ADVISENOTSUPPORTED); |
| } |
| |
| #endif // QT_NO_DRAGANDDROP && QT_NO_CLIPBOARD |
| |
| #ifndef QT_NO_DRAGANDDROP |
| |
| //#define QDND_DEBUG |
| |
| #ifdef QDND_DEBUG |
| extern QString dragActionsToString(Qt::DropActions actions); |
| #endif |
| |
| Qt::DropActions translateToQDragDropActions(DWORD pdwEffects) |
| { |
| Qt::DropActions actions = Qt::IgnoreAction; |
| if (pdwEffects & DROPEFFECT_LINK) |
| actions |= Qt::LinkAction; |
| if (pdwEffects & DROPEFFECT_COPY) |
| actions |= Qt::CopyAction; |
| if (pdwEffects & DROPEFFECT_MOVE) |
| actions |= Qt::MoveAction; |
| return actions; |
| } |
| |
| Qt::DropAction translateToQDragDropAction(DWORD pdwEffect) |
| { |
| if (pdwEffect & DROPEFFECT_LINK) |
| return Qt::LinkAction; |
| if (pdwEffect & DROPEFFECT_COPY) |
| return Qt::CopyAction; |
| if (pdwEffect & DROPEFFECT_MOVE) |
| return Qt::MoveAction; |
| return Qt::IgnoreAction; |
| } |
| |
| DWORD translateToWinDragEffects(Qt::DropActions action) |
| { |
| DWORD effect = DROPEFFECT_NONE; |
| if (action & Qt::LinkAction) |
| effect |= DROPEFFECT_LINK; |
| if (action & Qt::CopyAction) |
| effect |= DROPEFFECT_COPY; |
| if (action & Qt::MoveAction) |
| effect |= DROPEFFECT_MOVE; |
| return effect; |
| } |
| |
| Qt::KeyboardModifiers toQtKeyboardModifiers(DWORD keyState) |
| { |
| Qt::KeyboardModifiers modifiers = Qt::NoModifier; |
| |
| if (keyState & MK_SHIFT) |
| modifiers |= Qt::ShiftModifier; |
| if (keyState & MK_CONTROL) |
| modifiers |= Qt::ControlModifier; |
| if (keyState & MK_ALT) |
| modifiers |= Qt::AltModifier; |
| |
| return modifiers; |
| } |
| |
| Qt::MouseButtons toQtMouseButtons(DWORD keyState) |
| { |
| Qt::MouseButtons buttons = Qt::NoButton; |
| |
| if (keyState & MK_LBUTTON) |
| buttons |= Qt::LeftButton; |
| if (keyState & MK_RBUTTON) |
| buttons |= Qt::RightButton; |
| if (keyState & MK_MBUTTON) |
| buttons |= Qt::MidButton; |
| |
| return buttons; |
| } |
| |
| class QOleDropSource : public IDropSource |
| { |
| public: |
| QOleDropSource(); |
| virtual ~QOleDropSource(); |
| |
| void createCursors(); |
| |
| // IUnknown methods |
| STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObj); |
| STDMETHOD_(ULONG,AddRef)(void); |
| STDMETHOD_(ULONG,Release)(void); |
| |
| // IDropSource methods |
| STDMETHOD(QueryContinueDrag)(BOOL fEscapePressed, DWORD grfKeyState); |
| STDMETHOD(GiveFeedback)(DWORD dwEffect); |
| |
| private: |
| Qt::MouseButtons currentButtons; |
| Qt::DropAction currentAction; |
| QMap <Qt::DropAction, QCursor> cursors; |
| |
| ULONG m_refs; |
| }; |
| |
| |
| QOleDropSource::QOleDropSource() |
| { |
| currentButtons = Qt::NoButton; |
| m_refs = 1; |
| currentAction = Qt::IgnoreAction; |
| } |
| |
| QOleDropSource::~QOleDropSource() |
| { |
| } |
| |
| void QOleDropSource::createCursors() |
| { |
| QDragManager *manager = QDragManager::self(); |
| if (manager && manager->object |
| && (!manager->object->pixmap().isNull() |
| || manager->hasCustomDragCursors())) { |
| QPixmap pm = manager->object->pixmap(); |
| QList<Qt::DropAction> actions; |
| actions << Qt::MoveAction << Qt::CopyAction << Qt::LinkAction; |
| if (!manager->object->pixmap().isNull()) |
| actions << Qt::IgnoreAction; |
| QPoint hotSpot = manager->object->hotSpot(); |
| for (int cnum = 0; cnum < actions.size(); ++cnum) { |
| QPixmap cpm = manager->dragCursor(actions.at(cnum)); |
| int w = cpm.width(); |
| int h = cpm.height(); |
| |
| if (!pm.isNull()) { |
| int x1 = qMin(-hotSpot.x(), 0); |
| int x2 = qMax(pm.width() - hotSpot.x(), cpm.width()); |
| int y1 = qMin(-hotSpot.y(), 0); |
| int y2 = qMax(pm.height() - hotSpot.y(), cpm.height()); |
| |
| w = x2 - x1 + 1; |
| h = y2 - y1 + 1; |
| } |
| |
| QRect srcRect = pm.rect(); |
| QPoint pmDest = QPoint(qMax(0, -hotSpot.x()), qMax(0, -hotSpot.y())); |
| QPoint newHotSpot = hotSpot; |
| |
| #if defined(Q_OS_WINCE) |
| // Limited cursor size |
| int reqw = GetSystemMetrics(SM_CXCURSOR); |
| int reqh = GetSystemMetrics(SM_CYCURSOR); |
| |
| QPoint hotspotInPM = newHotSpot - pmDest; |
| if (reqw < w) { |
| // Not wide enough - move objectpm right |
| qreal r = qreal(newHotSpot.x()) / w; |
| newHotSpot = QPoint(int(r * reqw), newHotSpot.y()); |
| if (newHotSpot.x() + cpm.width() > reqw) |
| newHotSpot.setX(reqw - cpm.width()); |
| |
| srcRect = QRect(QPoint(hotspotInPM.x() - newHotSpot.x(), srcRect.top()), QSize(reqw, srcRect.height())); |
| } |
| if (reqh < h) { |
| qreal r = qreal(newHotSpot.y()) / h; |
| newHotSpot = QPoint(newHotSpot.x(), int(r * reqh)); |
| if (newHotSpot.y() + cpm.height() > reqh) |
| newHotSpot.setY(reqh - cpm.height()); |
| |
| srcRect = QRect(QPoint(srcRect.left(), hotspotInPM.y() - newHotSpot.y()), QSize(srcRect.width(), reqh)); |
| } |
| // Always use system cursor size |
| w = reqw; |
| h = reqh; |
| #endif |
| |
| QPixmap newCursor(w, h); |
| if (!pm.isNull()) { |
| newCursor.fill(QColor(0, 0, 0, 0)); |
| QPainter p(&newCursor); |
| p.drawPixmap(pmDest, pm, srcRect); |
| p.drawPixmap(qMax(0,newHotSpot.x()),qMax(0,newHotSpot.y()),cpm); |
| } else { |
| newCursor = cpm; |
| } |
| |
| #ifndef QT_NO_CURSOR |
| cursors[actions.at(cnum)] = QCursor(newCursor, pm.isNull() ? 0 : qMax(0,newHotSpot.x()), |
| pm.isNull() ? 0 : qMax(0,newHotSpot.y())); |
| #endif |
| } |
| } |
| } |
| |
| |
| |
| //--------------------------------------------------------------------- |
| // IUnknown Methods |
| //--------------------------------------------------------------------- |
| |
| |
| STDMETHODIMP |
| QOleDropSource::QueryInterface(REFIID iid, void FAR* FAR* ppv) |
| { |
| if(iid == IID_IUnknown || iid == IID_IDropSource) |
| { |
| *ppv = this; |
| ++m_refs; |
| return NOERROR; |
| } |
| *ppv = NULL; |
| return ResultFromScode(E_NOINTERFACE); |
| } |
| |
| |
| STDMETHODIMP_(ULONG) |
| QOleDropSource::AddRef(void) |
| { |
| return ++m_refs; |
| } |
| |
| |
| STDMETHODIMP_(ULONG) |
| QOleDropSource::Release(void) |
| { |
| if(--m_refs == 0) |
| { |
| delete this; |
| return 0; |
| } |
| return m_refs; |
| } |
| |
| static inline Qt::MouseButtons keystate_to_mousebutton(DWORD grfKeyState) |
| { |
| Qt::MouseButtons result; |
| if (grfKeyState & MK_LBUTTON) |
| result |= Qt::LeftButton; |
| if (grfKeyState & MK_MBUTTON) |
| result |= Qt::MidButton; |
| if (grfKeyState & MK_RBUTTON) |
| result |= Qt::RightButton; |
| if (grfKeyState & MK_XBUTTON1) |
| result |= Qt::XButton1; |
| if (grfKeyState & MK_XBUTTON2) |
| result |= Qt::XButton2; |
| return result; |
| } |
| |
| //--------------------------------------------------------------------- |
| // IDropSource Methods |
| //--------------------------------------------------------------------- |
| QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP |
| QOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) |
| { |
| #ifdef QDND_DEBUG |
| qDebug("QOleDropSource::QueryContinueDrag(fEscapePressed %d, grfKeyState %d)", fEscapePressed, grfKeyState); |
| #endif |
| |
| if (fEscapePressed) { |
| return ResultFromScode(DRAGDROP_S_CANCEL); |
| } else if ((GetAsyncKeyState(VK_LBUTTON) == 0) |
| && (GetAsyncKeyState(VK_MBUTTON) == 0) |
| && (GetAsyncKeyState(VK_RBUTTON) == 0)) { |
| // grfKeyState is broken on CE & some Windows XP versions, |
| // therefore we need to check the state manually |
| return ResultFromScode(DRAGDROP_S_DROP); |
| } else { |
| #if !defined(Q_OS_WINCE) |
| if (currentButtons == Qt::NoButton) { |
| currentButtons = keystate_to_mousebutton(grfKeyState); |
| } else { |
| Qt::MouseButtons buttons = keystate_to_mousebutton(grfKeyState); |
| if (!(currentButtons & buttons)) |
| return ResultFromScode(DRAGDROP_S_DROP); |
| } |
| #endif |
| QApplication::processEvents(); |
| return NOERROR; |
| } |
| } |
| |
| QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP |
| QOleDropSource::GiveFeedback(DWORD dwEffect) |
| { |
| Qt::DropAction action = translateToQDragDropAction(dwEffect); |
| |
| #ifdef QDND_DEBUG |
| qDebug("QOleDropSource::GiveFeedback(DWORD dwEffect)"); |
| qDebug("dwEffect = %s", dragActionsToString(action).toLatin1().data()); |
| #endif |
| |
| if (currentAction != action) { |
| currentAction = action; |
| QDragManager::self()->emitActionChanged(currentAction); |
| } |
| |
| if (cursors.contains(currentAction)) { |
| #ifndef QT_NO_CURSOR |
| SetCursor(cursors[currentAction].handle()); |
| #endif |
| return ResultFromScode(S_OK); |
| } |
| |
| return ResultFromScode(DRAGDROP_S_USEDEFAULTCURSORS); |
| } |
| |
| //--------------------------------------------------------------------- |
| // QOleDropTarget |
| //--------------------------------------------------------------------- |
| |
| QOleDropTarget::QOleDropTarget(QWidget* w) |
| : widget(w) |
| { |
| m_refs = 1; |
| } |
| |
| void QOleDropTarget::releaseQt() |
| { |
| widget = 0; |
| } |
| |
| //--------------------------------------------------------------------- |
| // IUnknown Methods |
| //--------------------------------------------------------------------- |
| |
| |
| STDMETHODIMP |
| QOleDropTarget::QueryInterface(REFIID iid, void FAR* FAR* ppv) |
| { |
| if(iid == IID_IUnknown || iid == IID_IDropTarget) |
| { |
| *ppv = this; |
| AddRef(); |
| return NOERROR; |
| } |
| *ppv = NULL; |
| return ResultFromScode(E_NOINTERFACE); |
| } |
| |
| |
| STDMETHODIMP_(ULONG) |
| QOleDropTarget::AddRef(void) |
| { |
| return ++m_refs; |
| } |
| |
| |
| STDMETHODIMP_(ULONG) |
| QOleDropTarget::Release(void) |
| { |
| if(--m_refs == 0) |
| { |
| delete this; |
| return 0; |
| } |
| return m_refs; |
| } |
| |
| //--------------------------------------------------------------------- |
| // IDropTarget Methods |
| //--------------------------------------------------------------------- |
| |
| QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP |
| QOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) |
| { |
| #ifdef QDND_DEBUG |
| qDebug("QOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)"); |
| #endif |
| |
| if (!QApplicationPrivate::tryModalHelper(widget)) { |
| *pdwEffect = DROPEFFECT_NONE; |
| return NOERROR; |
| } |
| |
| QDragManager *manager = QDragManager::self(); |
| manager->dropData->currentDataObject = pDataObj; |
| manager->dropData->currentDataObject->AddRef(); |
| sendDragEnterEvent(widget, grfKeyState, pt, pdwEffect); |
| *pdwEffect = chosenEffect; |
| |
| return NOERROR; |
| } |
| |
| void QOleDropTarget::sendDragEnterEvent(QWidget *dragEnterWidget, DWORD grfKeyState, |
| POINTL pt, LPDWORD pdwEffect) |
| { |
| Q_ASSERT(dragEnterWidget); |
| lastPoint = dragEnterWidget->mapFromGlobal(QPoint(pt.x,pt.y)); |
| lastKeyState = grfKeyState; |
| |
| chosenEffect = DROPEFFECT_NONE; |
| currentWidget = dragEnterWidget; |
| |
| QDragManager *manager = QDragManager::self(); |
| QMimeData * md = manager->source() ? manager->dragPrivate()->data : manager->dropData; |
| QDragEnterEvent enterEvent(lastPoint, translateToQDragDropActions(*pdwEffect), md, |
| toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState)); |
| QApplication::sendEvent(dragEnterWidget, &enterEvent); |
| answerRect = enterEvent.answerRect(); |
| |
| if (enterEvent.isAccepted()) { |
| chosenEffect = translateToWinDragEffects(enterEvent.dropAction()); |
| } |
| |
| // Documentation states that a drag move event is sendt immidiatly after |
| // a drag enter event. This will honor widgets overriding dragMoveEvent only: |
| if (enterEvent.isAccepted()) { |
| QDragMoveEvent moveEvent(lastPoint, translateToQDragDropActions(*pdwEffect), md, |
| toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState)); |
| answerRect = enterEvent.answerRect(); |
| moveEvent.setDropAction(enterEvent.dropAction()); |
| moveEvent.accept(); // accept by default, since enter event was accepted. |
| |
| QApplication::sendEvent(dragEnterWidget, &moveEvent); |
| if (moveEvent.isAccepted()) { |
| answerRect = moveEvent.answerRect(); |
| chosenEffect = translateToWinDragEffects(moveEvent.dropAction()); |
| } else { |
| chosenEffect = DROPEFFECT_NONE; |
| } |
| } |
| |
| } |
| |
| QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP |
| QOleDropTarget::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) |
| { |
| #ifdef QDND_DEBUG |
| qDebug("QOleDropTarget::DragOver(grfKeyState %d, pt (%d,%d), pdwEffect %d)", grfKeyState, pt.x, pt.y, pdwEffect); |
| #endif |
| |
| QWidget *dragOverWidget = widget->childAt(widget->mapFromGlobal(QPoint(pt.x, pt.y))); |
| if (!dragOverWidget) |
| dragOverWidget = widget; |
| |
| |
| if (!QApplicationPrivate::tryModalHelper(dragOverWidget) |
| || !dragOverWidget->testAttribute(Qt::WA_DropSiteRegistered)) { |
| *pdwEffect = DROPEFFECT_NONE; |
| return NOERROR; |
| } |
| |
| QPoint tmpPoint = dragOverWidget->mapFromGlobal(QPoint(pt.x, pt.y)); |
| // see if we should compress this event |
| if ((tmpPoint == lastPoint || answerRect.contains(tmpPoint)) && lastKeyState == grfKeyState) { |
| *pdwEffect = chosenEffect; |
| return NOERROR; |
| } |
| |
| if (!dragOverWidget->internalWinId() && dragOverWidget != currentWidget) { |
| QPointer<QWidget> dragOverWidgetGuard(dragOverWidget); |
| // Send drag leave event to the previous drag widget. |
| QDragLeaveEvent dragLeave; |
| if (currentWidget) |
| QApplication::sendEvent(currentWidget, &dragLeave); |
| if (!dragOverWidgetGuard) { |
| dragOverWidget = widget->childAt(widget->mapFromGlobal(QPoint(pt.x, pt.y))); |
| if (!dragOverWidget) |
| dragOverWidget = widget; |
| } |
| // Send drag enter event to the current drag widget. |
| sendDragEnterEvent(dragOverWidget, grfKeyState, pt, pdwEffect); |
| } |
| |
| QDragManager *manager = QDragManager::self(); |
| QMimeData *md = manager->source() ? manager->dragPrivate()->data : manager->dropData; |
| |
| QDragMoveEvent oldEvent(lastPoint, translateToQDragDropActions(*pdwEffect), md, |
| toQtMouseButtons(lastKeyState), toQtKeyboardModifiers(lastKeyState)); |
| |
| |
| lastPoint = tmpPoint; |
| lastKeyState = grfKeyState; |
| |
| QDragMoveEvent e(lastPoint, translateToQDragDropActions(*pdwEffect), md, |
| toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState)); |
| if (chosenEffect != DROPEFFECT_NONE) { |
| if (oldEvent.dropAction() == e.dropAction() && |
| oldEvent.keyboardModifiers() == e.keyboardModifiers()) |
| e.setDropAction(translateToQDragDropAction(chosenEffect)); |
| e.accept(); |
| } |
| QApplication::sendEvent(dragOverWidget, &e); |
| |
| answerRect = e.answerRect(); |
| if (e.isAccepted()) |
| chosenEffect = translateToWinDragEffects(e.dropAction()); |
| else |
| chosenEffect = DROPEFFECT_NONE; |
| *pdwEffect = chosenEffect; |
| |
| return NOERROR; |
| } |
| |
| QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP |
| QOleDropTarget::DragLeave() |
| { |
| #ifdef QDND_DEBUG |
| qDebug("QOleDropTarget::DragLeave()"); |
| #endif |
| |
| if (!QApplicationPrivate::tryModalHelper(widget)) { |
| return NOERROR; |
| } |
| |
| currentWidget = 0; |
| QDragLeaveEvent e; |
| QApplication::sendEvent(widget, &e); |
| |
| QDragManager *manager = QDragManager::self(); |
| |
| if (manager->dropData->currentDataObject) { // Sanity |
| manager->dropData->currentDataObject->Release(); |
| manager->dropData->currentDataObject = 0; |
| } |
| |
| return NOERROR; |
| } |
| |
| #define KEY_STATE_BUTTON_MASK (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON) |
| |
| QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP |
| QOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) |
| { |
| #ifdef QDND_DEBUG |
| qDebug("QOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, grfKeyState %d, POINTL pt, LPDWORD pdwEffect)", grfKeyState); |
| #endif |
| |
| QWidget *dropWidget = widget->childAt(widget->mapFromGlobal(QPoint(pt.x, pt.y))); |
| if (!dropWidget) |
| dropWidget = widget; |
| |
| if (!QApplicationPrivate::tryModalHelper(dropWidget) |
| || !dropWidget->testAttribute(Qt::WA_DropSiteRegistered)) { |
| *pdwEffect = DROPEFFECT_NONE; |
| return NOERROR; |
| } |
| |
| lastPoint = dropWidget->mapFromGlobal(QPoint(pt.x,pt.y)); |
| // grfKeyState does not all ways contain button state in the drop so if |
| // it doesn't then use the last known button state; |
| if ((grfKeyState & KEY_STATE_BUTTON_MASK) == 0) |
| grfKeyState |= lastKeyState & KEY_STATE_BUTTON_MASK; |
| lastKeyState = grfKeyState; |
| |
| QDragManager *manager = QDragManager::self(); |
| QMimeData *md = manager->source() ? manager->dragPrivate()->data : manager->dropData; |
| QDropEvent e(lastPoint, translateToQDragDropActions(*pdwEffect), md, |
| toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState)); |
| if (chosenEffect != DROPEFFECT_NONE) { |
| e.setDropAction(translateToQDragDropAction(chosenEffect)); |
| } |
| QApplication::sendEvent(dropWidget, &e); |
| |
| if (chosenEffect != DROPEFFECT_NONE) { |
| e.accept(); |
| } |
| |
| |
| if (e.isAccepted()) { |
| if (e.dropAction() == Qt::MoveAction || e.dropAction() == Qt::TargetMoveAction) { |
| if (e.dropAction() == Qt::MoveAction) |
| chosenEffect = DROPEFFECT_MOVE; |
| else |
| chosenEffect = DROPEFFECT_COPY; |
| HGLOBAL hData = GlobalAlloc(0, sizeof(DWORD)); |
| if (hData) { |
| DWORD *moveEffect = (DWORD *)GlobalLock(hData);; |
| *moveEffect = DROPEFFECT_MOVE; |
| GlobalUnlock(hData); |
| STGMEDIUM medium; |
| memset(&medium, 0, sizeof(STGMEDIUM)); |
| medium.tymed = TYMED_HGLOBAL; |
| medium.hGlobal = hData; |
| FORMATETC format; |
| format.cfFormat = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT); |
| format.tymed = TYMED_HGLOBAL; |
| format.ptd = 0; |
| format.dwAspect = 1; |
| format.lindex = -1; |
| manager->dropData->currentDataObject->SetData(&format, &medium, true); |
| } |
| } else { |
| chosenEffect = translateToWinDragEffects(e.dropAction()); |
| } |
| } else { |
| chosenEffect = DROPEFFECT_NONE; |
| } |
| *pdwEffect = chosenEffect; |
| |
| |
| if (manager->dropData->currentDataObject) { |
| manager->dropData->currentDataObject->Release(); |
| manager->dropData->currentDataObject = 0; |
| } |
| |
| return NOERROR; |
| |
| // We won't get any mouserelease-event, so manually adjust qApp state: |
| ///### test this QApplication::winMouseButtonUp(); |
| } |
| |
| //--------------------------------------------------------------------- |
| // QDropData |
| //--------------------------------------------------------------------- |
| |
| bool QDropData::hasFormat_sys(const QString &mimeType) const |
| { |
| if (!currentDataObject) // Sanity |
| return false; |
| |
| return QWindowsMime::converterToMime(mimeType, currentDataObject) != 0; |
| } |
| |
| QStringList QDropData::formats_sys() const |
| { |
| QStringList fmts; |
| if (!currentDataObject) // Sanity |
| return fmts; |
| |
| fmts = QWindowsMime::allMimesForFormats(currentDataObject); |
| |
| return fmts; |
| } |
| |
| QVariant QDropData::retrieveData_sys(const QString &mimeType, QVariant::Type type) const |
| { |
| QVariant result; |
| |
| if (!currentDataObject) // Sanity |
| return result; |
| |
| QWindowsMime *converter = QWindowsMime::converterToMime(mimeType, currentDataObject); |
| |
| if (converter) |
| result = converter->convertToMime(mimeType, currentDataObject, type); |
| |
| return result; |
| } |
| |
| Qt::DropAction QDragManager::drag(QDrag *o) |
| |
| { |
| #ifdef QDND_DEBUG |
| qDebug("QDragManager::drag(QDrag *drag)"); |
| #endif |
| |
| if (object == o || !o || !o->d_func()->source) |
| return Qt::IgnoreAction; |
| |
| if (object) { |
| cancel(); |
| qApp->removeEventFilter(this); |
| beingCancelled = false; |
| } |
| |
| object = o; |
| |
| #ifdef QDND_DEBUG |
| qDebug("actions = %s", dragActionsToString(dragPrivate()->possible_actions).toLatin1().data()); |
| #endif |
| |
| dragPrivate()->target = 0; |
| |
| #ifndef QT_NO_ACCESSIBILITY |
| QAccessible::updateAccessibility(this, 0, QAccessible::DragDropStart); |
| #endif |
| |
| DWORD resultEffect; |
| QOleDropSource *src = new QOleDropSource(); |
| src->createCursors(); |
| QOleDataObject *obj = new QOleDataObject(o->mimeData()); |
| DWORD allowedEffects = translateToWinDragEffects(dragPrivate()->possible_actions); |
| |
| #if !defined(Q_OS_WINCE) || defined(GWES_ICONCURS) |
| HRESULT r = DoDragDrop(obj, src, allowedEffects, &resultEffect); |
| #else |
| HRESULT r = DRAGDROP_S_CANCEL; |
| resultEffect = DROPEFFECT_MOVE; |
| #endif |
| |
| Qt::DropAction ret = Qt::IgnoreAction; |
| if (r == DRAGDROP_S_DROP) { |
| if (obj->reportedPerformedEffect() == DROPEFFECT_MOVE && resultEffect != DROPEFFECT_MOVE) { |
| ret = Qt::TargetMoveAction; |
| resultEffect = DROPEFFECT_MOVE; |
| } else { |
| ret = translateToQDragDropAction(resultEffect); |
| } |
| // Force it to be a copy if an unsupported operation occurred. |
| // This indicates a bug in the drop target. |
| if (resultEffect != DROPEFFECT_NONE && !(resultEffect & allowedEffects)) |
| ret = Qt::CopyAction; |
| } else { |
| dragPrivate()->target = 0; |
| } |
| |
| // clean up |
| obj->releaseQt(); |
| obj->Release(); // Will delete obj if refcount becomes 0 |
| src->Release(); // Will delete src if refcount becomes 0 |
| object = 0; |
| o->setMimeData(0); |
| o->deleteLater(); |
| |
| #ifndef QT_NO_ACCESSIBILITY |
| QAccessible::updateAccessibility(this, 0, QAccessible::DragDropEnd); |
| #endif |
| |
| return ret; |
| } |
| |
| void QDragManager::cancel(bool /* deleteSource */) |
| { |
| if (object) { |
| beingCancelled = true; |
| object = 0; |
| } |
| |
| #ifndef QT_NO_CURSOR |
| // insert cancel code here ######## todo |
| |
| if (restoreCursor) { |
| QApplication::restoreOverrideCursor(); |
| restoreCursor = false; |
| } |
| #endif |
| #ifndef QT_NO_ACCESSIBILITY |
| QAccessible::updateAccessibility(this, 0, QAccessible::DragDropEnd); |
| #endif |
| } |
| |
| void QDragManager::updatePixmap() |
| { |
| // not used in windows implementation |
| } |
| |
| bool QDragManager::eventFilter(QObject *, QEvent *) |
| { |
| // not used in windows implementation |
| return false; |
| } |
| |
| void QDragManager::timerEvent(QTimerEvent*) |
| { |
| // not used in windows implementation |
| } |
| |
| void QDragManager::move(const QPoint &) |
| { |
| // not used in windows implementation |
| } |
| |
| void QDragManager::drop() |
| { |
| // not used in windows implementation |
| } |
| |
| QT_END_NAMESPACE |
| |
| #endif // QT_NO_DRAGANDDROP |