blob: dc78a02bd2b06b49c5b818e7ade5ce9abd87006c [file] [log] [blame]
/****************************************************************************
**
** 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