diff -r 000000000000 -r 1918ee327afb src/gui/kernel/qdnd_win.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gui/kernel/qdnd_win.cpp Mon Jan 11 14:00:40 2010 +0000 @@ -0,0 +1,1031 @@ +/**************************************************************************** +** +** Copyright (C) 2009 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 "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 +#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 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 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 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 +//--------------------------------------------------------------------- +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 (!(grfKeyState & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON))) { + return ResultFromScode(DRAGDROP_S_DROP); + } else { +#if defined(Q_OS_WINCE) + // grfKeyState is broken on CE, therefore need to check + // the state manually + if ((GetAsyncKeyState(VK_LBUTTON) == 0) && + (GetAsyncKeyState(VK_MBUTTON) == 0) && + (GetAsyncKeyState(VK_RBUTTON) == 0)) { + return ResultFromScode(DRAGDROP_S_DROP); + } +#else + 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; + } +} + +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 +//--------------------------------------------------------------------- + +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; + } + } + +} + +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 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; +} + +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) + +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