source: trunk/src/gui/kernel/qdnd_win.cpp@ 467

Last change on this file since 467 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 30.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qapplication.h"
43
44#include "qapplication_p.h"
45#include "qevent.h"
46#include "qpainter.h"
47#include "qwidget.h"
48#include "qbuffer.h"
49#include "qdatastream.h"
50#include "qcursor.h"
51#include "qt_windows.h"
52#include <shlobj.h>
53#ifndef QT_NO_ACCESSIBILITY
54#include "qaccessible.h"
55#endif
56#include "qdnd_p.h"
57#include "qdebug.h"
58
59#if defined(Q_OS_WINCE)
60#include "qguifunctions_wince.h"
61#endif
62
63// support for xbuttons
64#ifndef MK_XBUTTON1
65#define MK_XBUTTON1 0x0020
66#define MK_XBUTTON2 0x0040
67#endif
68
69QT_BEGIN_NAMESPACE
70
71#if !(defined(QT_NO_DRAGANDDROP) && defined(QT_NO_CLIPBOARD))
72
73//---------------------------------------------------------------------
74// QOleDataObject Constructor
75//---------------------------------------------------------------------
76
77QOleDataObject::QOleDataObject(QMimeData *mimeData)
78{
79 m_refs = 1;
80 data = mimeData;
81 CF_PERFORMEDDROPEFFECT = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT);
82 performedEffect = DROPEFFECT_NONE;
83}
84
85QOleDataObject::~QOleDataObject()
86{
87}
88
89void QOleDataObject::releaseQt()
90{
91 data = 0;
92}
93
94const QMimeData *QOleDataObject::mimeData() const
95{
96 return data;
97}
98
99DWORD QOleDataObject::reportedPerformedEffect() const
100{
101 return performedEffect;
102}
103
104//---------------------------------------------------------------------
105// IUnknown Methods
106//---------------------------------------------------------------------
107
108STDMETHODIMP
109QOleDataObject::QueryInterface(REFIID iid, void FAR* FAR* ppv)
110{
111 if (iid == IID_IUnknown || iid == IID_IDataObject) {
112 *ppv = this;
113 AddRef();
114 return NOERROR;
115 }
116 *ppv = NULL;
117 return ResultFromScode(E_NOINTERFACE);
118}
119
120STDMETHODIMP_(ULONG)
121QOleDataObject::AddRef(void)
122{
123 return ++m_refs;
124}
125
126STDMETHODIMP_(ULONG)
127QOleDataObject::Release(void)
128{
129 if (--m_refs == 0) {
130 releaseQt();
131 delete this;
132 return 0;
133 }
134 return m_refs;
135}
136
137//---------------------------------------------------------------------
138// IDataObject Methods
139//
140// The following methods are NOT supported for data transfer using the
141// clipboard or drag-drop:
142//
143// IDataObject::SetData -- return E_NOTIMPL
144// IDataObject::DAdvise -- return OLE_E_ADVISENOTSUPPORTED
145// ::DUnadvise
146// ::EnumDAdvise
147// IDataObject::GetCanonicalFormatEtc -- return E_NOTIMPL
148// (NOTE: must set pformatetcOut->ptd = NULL)
149//---------------------------------------------------------------------
150
151STDMETHODIMP
152QOleDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium)
153{
154#ifdef QDND_DEBUG
155 qDebug("QOleDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium)");
156#ifndef Q_OS_WINCE
157 char buf[256] = {0};
158 GetClipboardFormatNameA(pformatetc->cfFormat, buf, 255);
159 qDebug("CF = %d : %s", pformatetc->cfFormat, buf);
160#endif
161#endif
162
163 if (!data)
164 return ResultFromScode(DATA_E_FORMATETC);
165
166 QWindowsMime *converter = QWindowsMime::converterFromMime(*pformatetc, data);
167
168 if (converter && converter->convertFromMime(*pformatetc, data, pmedium))
169 return ResultFromScode(S_OK);
170 else
171 return ResultFromScode(DATA_E_FORMATETC);
172}
173
174STDMETHODIMP
175QOleDataObject::GetDataHere(LPFORMATETC, LPSTGMEDIUM)
176{
177 return ResultFromScode(DATA_E_FORMATETC);
178}
179
180STDMETHODIMP
181QOleDataObject::QueryGetData(LPFORMATETC pformatetc)
182{
183#ifdef QDND_DEBUG
184 qDebug("QOleDataObject::QueryGetData(LPFORMATETC pformatetc)");
185#endif
186
187 if (!data)
188 return ResultFromScode(DATA_E_FORMATETC);
189
190 if (QWindowsMime::converterFromMime(*pformatetc, data))
191 return ResultFromScode(S_OK);
192 return ResultFromScode(S_FALSE);
193}
194
195STDMETHODIMP
196QOleDataObject::GetCanonicalFormatEtc(LPFORMATETC, LPFORMATETC pformatetcOut)
197{
198 pformatetcOut->ptd = NULL;
199 return ResultFromScode(E_NOTIMPL);
200}
201
202STDMETHODIMP
203QOleDataObject::SetData(LPFORMATETC pFormatetc, STGMEDIUM *pMedium, BOOL fRelease)
204{
205 if (pFormatetc->cfFormat == CF_PERFORMEDDROPEFFECT && pMedium->tymed == TYMED_HGLOBAL) {
206 DWORD * val = (DWORD*)GlobalLock(pMedium->hGlobal);
207 performedEffect = *val;
208 GlobalUnlock(pMedium->hGlobal);
209 if (fRelease)
210 ReleaseStgMedium(pMedium);
211 return ResultFromScode(S_OK);
212 }
213 return ResultFromScode(E_NOTIMPL);
214}
215
216
217STDMETHODIMP
218QOleDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc)
219{
220#ifdef QDND_DEBUG
221 qDebug("QOleDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc)");
222#endif
223
224 if (!data)
225 return ResultFromScode(DATA_E_FORMATETC);
226
227 SCODE sc = S_OK;
228
229 QVector<FORMATETC> fmtetcs;
230 if (dwDirection == DATADIR_GET) {
231 fmtetcs = QWindowsMime::allFormatsForMime(data);
232 } else {
233 FORMATETC formatetc;
234 formatetc.cfFormat = CF_PERFORMEDDROPEFFECT;
235 formatetc.dwAspect = DVASPECT_CONTENT;
236 formatetc.lindex = -1;
237 formatetc.ptd = NULL;
238 formatetc.tymed = TYMED_HGLOBAL;
239 fmtetcs.append(formatetc);
240 }
241
242 QOleEnumFmtEtc *enumFmtEtc = new QOleEnumFmtEtc(fmtetcs);
243 *ppenumFormatEtc = enumFmtEtc;
244 if (enumFmtEtc->isNull()) {
245 delete enumFmtEtc;
246 *ppenumFormatEtc = NULL;
247 sc = E_OUTOFMEMORY;
248 }
249
250 return ResultFromScode(sc);
251}
252
253STDMETHODIMP
254QOleDataObject::DAdvise(FORMATETC FAR*, DWORD,
255 LPADVISESINK, DWORD FAR*)
256{
257 return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
258}
259
260
261STDMETHODIMP
262QOleDataObject::DUnadvise(DWORD)
263{
264 return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
265}
266
267STDMETHODIMP
268QOleDataObject::EnumDAdvise(LPENUMSTATDATA FAR*)
269{
270 return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
271}
272
273#endif // QT_NO_DRAGANDDROP && QT_NO_CLIPBOARD
274
275#ifndef QT_NO_DRAGANDDROP
276
277//#define QDND_DEBUG
278
279#ifdef QDND_DEBUG
280extern QString dragActionsToString(Qt::DropActions actions);
281#endif
282
283Qt::DropActions translateToQDragDropActions(DWORD pdwEffects)
284{
285 Qt::DropActions actions = Qt::IgnoreAction;
286 if (pdwEffects & DROPEFFECT_LINK)
287 actions |= Qt::LinkAction;
288 if (pdwEffects & DROPEFFECT_COPY)
289 actions |= Qt::CopyAction;
290 if (pdwEffects & DROPEFFECT_MOVE)
291 actions |= Qt::MoveAction;
292 return actions;
293}
294
295Qt::DropAction translateToQDragDropAction(DWORD pdwEffect)
296{
297 if (pdwEffect & DROPEFFECT_LINK)
298 return Qt::LinkAction;
299 if (pdwEffect & DROPEFFECT_COPY)
300 return Qt::CopyAction;
301 if (pdwEffect & DROPEFFECT_MOVE)
302 return Qt::MoveAction;
303 return Qt::IgnoreAction;
304}
305
306DWORD translateToWinDragEffects(Qt::DropActions action)
307{
308 DWORD effect = DROPEFFECT_NONE;
309 if (action & Qt::LinkAction)
310 effect |= DROPEFFECT_LINK;
311 if (action & Qt::CopyAction)
312 effect |= DROPEFFECT_COPY;
313 if (action & Qt::MoveAction)
314 effect |= DROPEFFECT_MOVE;
315 return effect;
316}
317
318Qt::KeyboardModifiers toQtKeyboardModifiers(DWORD keyState)
319{
320 Qt::KeyboardModifiers modifiers = Qt::NoModifier;
321
322 if (keyState & MK_SHIFT)
323 modifiers |= Qt::ShiftModifier;
324 if (keyState & MK_CONTROL)
325 modifiers |= Qt::ControlModifier;
326 if (keyState & MK_ALT)
327 modifiers |= Qt::AltModifier;
328
329 return modifiers;
330}
331
332Qt::MouseButtons toQtMouseButtons(DWORD keyState)
333{
334 Qt::MouseButtons buttons = Qt::NoButton;
335
336 if (keyState & MK_LBUTTON)
337 buttons |= Qt::LeftButton;
338 if (keyState & MK_RBUTTON)
339 buttons |= Qt::RightButton;
340 if (keyState & MK_MBUTTON)
341 buttons |= Qt::MidButton;
342
343 return buttons;
344}
345
346class QOleDropSource : public IDropSource
347{
348public:
349 QOleDropSource();
350 virtual ~QOleDropSource();
351
352 void createCursors();
353
354 // IUnknown methods
355 STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObj);
356 STDMETHOD_(ULONG,AddRef)(void);
357 STDMETHOD_(ULONG,Release)(void);
358
359 // IDropSource methods
360 STDMETHOD(QueryContinueDrag)(BOOL fEscapePressed, DWORD grfKeyState);
361 STDMETHOD(GiveFeedback)(DWORD dwEffect);
362
363private:
364 Qt::MouseButtons currentButtons;
365 Qt::DropAction currentAction;
366 QMap <Qt::DropAction, QCursor> cursors;
367
368 ULONG m_refs;
369};
370
371
372QOleDropSource::QOleDropSource()
373{
374 currentButtons = Qt::NoButton;
375 m_refs = 1;
376 currentAction = Qt::IgnoreAction;
377}
378
379QOleDropSource::~QOleDropSource()
380{
381}
382
383void QOleDropSource::createCursors()
384{
385 QDragManager *manager = QDragManager::self();
386 if (manager && manager->object
387 && (!manager->object->pixmap().isNull()
388 || manager->hasCustomDragCursors())) {
389 QPixmap pm = manager->object->pixmap();
390 QList<Qt::DropAction> actions;
391 actions << Qt::MoveAction << Qt::CopyAction << Qt::LinkAction;
392 if (!manager->object->pixmap().isNull())
393 actions << Qt::IgnoreAction;
394 QPoint hotSpot = manager->object->hotSpot();
395 for (int cnum = 0; cnum < actions.size(); ++cnum) {
396 QPixmap cpm = manager->dragCursor(actions.at(cnum));
397 int w = cpm.width();
398 int h = cpm.height();
399
400 if (!pm.isNull()) {
401 int x1 = qMin(-hotSpot.x(),0);
402 int x2 = qMax(pm.width()-hotSpot.x(),cpm.width());
403 int y1 = qMin(-hotSpot.y(),0);
404 int y2 = qMax(pm.height()-hotSpot.y(),cpm.height());
405
406 w = x2-x1+1;
407 h = y2-y1+1;
408 }
409
410 QRect srcRect = pm.rect();
411 QPoint pmDest = QPoint(qMax(0, -hotSpot.x()), qMax(0, -hotSpot.y()));
412 QPoint newHotSpot = hotSpot;
413
414#if !defined(Q_OS_WINCE) || defined(GWES_ICONCURS)
415 bool limitedCursorSize = (QSysInfo::WindowsVersion & QSysInfo::WV_DOS_based)
416 || (QSysInfo::WindowsVersion == QSysInfo::WV_NT)
417 || (QSysInfo::WindowsVersion == QSysInfo::WV_CE);
418
419 if (limitedCursorSize) {
420 // Limited cursor size
421 int reqw = GetSystemMetrics(SM_CXCURSOR);
422 int reqh = GetSystemMetrics(SM_CYCURSOR);
423
424 QPoint hotspotInPM = newHotSpot - pmDest;
425 if (reqw < w) {
426 // Not wide enough - move objectpm right
427 qreal r = qreal(newHotSpot.x()) / w;
428 newHotSpot = QPoint(int(r * reqw), newHotSpot.y());
429 if (newHotSpot.x() + cpm.width() > reqw)
430 newHotSpot.setX(reqw - cpm.width());
431
432 srcRect = QRect(QPoint(hotspotInPM.x() - newHotSpot.x(), srcRect.top()), QSize(reqw, srcRect.height()));
433 }
434 if (reqh < h) {
435 qreal r = qreal(newHotSpot.y()) / h;
436 newHotSpot = QPoint(newHotSpot.x(), int(r * reqh));
437 if (newHotSpot.y() + cpm.height() > reqh)
438 newHotSpot.setY(reqh - cpm.height());
439
440 srcRect = QRect(QPoint(srcRect.left(), hotspotInPM.y() - newHotSpot.y()), QSize(srcRect.width(), reqh));
441 }
442 // Always use system cursor size
443 w = reqw;
444 h = reqh;
445 }
446#endif
447 QPixmap newCursor(w, h);
448 if (!pm.isNull()) {
449 newCursor.fill(QColor(0, 0, 0, 0));
450 QPainter p(&newCursor);
451 p.drawPixmap(pmDest, pm, srcRect);
452 p.drawPixmap(qMax(0,newHotSpot.x()),qMax(0,newHotSpot.y()),cpm);
453 } else {
454 newCursor = cpm;
455 }
456
457#ifndef QT_NO_CURSOR
458 cursors[actions.at(cnum)] = QCursor(newCursor, pm.isNull() ? 0 : qMax(0,newHotSpot.x()),
459 pm.isNull() ? 0 : qMax(0,newHotSpot.y()));
460#endif
461 }
462 }
463}
464
465
466
467//---------------------------------------------------------------------
468// IUnknown Methods
469//---------------------------------------------------------------------
470
471
472STDMETHODIMP
473QOleDropSource::QueryInterface(REFIID iid, void FAR* FAR* ppv)
474{
475 if(iid == IID_IUnknown || iid == IID_IDropSource)
476 {
477 *ppv = this;
478 ++m_refs;
479 return NOERROR;
480 }
481 *ppv = NULL;
482 return ResultFromScode(E_NOINTERFACE);
483}
484
485
486STDMETHODIMP_(ULONG)
487QOleDropSource::AddRef(void)
488{
489 return ++m_refs;
490}
491
492
493STDMETHODIMP_(ULONG)
494QOleDropSource::Release(void)
495{
496 if(--m_refs == 0)
497 {
498 delete this;
499 return 0;
500 }
501 return m_refs;
502}
503
504static inline Qt::MouseButtons keystate_to_mousebutton(DWORD grfKeyState)
505{
506 Qt::MouseButtons result;
507 if (grfKeyState & MK_LBUTTON)
508 result |= Qt::LeftButton;
509 if (grfKeyState & MK_MBUTTON)
510 result |= Qt::MidButton;
511 if (grfKeyState & MK_RBUTTON)
512 result |= Qt::RightButton;
513 if (grfKeyState & MK_XBUTTON1)
514 result |= Qt::XButton1;
515 if (grfKeyState & MK_XBUTTON2)
516 result |= Qt::XButton2;
517 return result;
518}
519
520//---------------------------------------------------------------------
521// IDropSource Methods
522//---------------------------------------------------------------------
523STDMETHODIMP
524QOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
525{
526#ifdef QDND_DEBUG
527 qDebug("QOleDropSource::QueryContinueDrag(fEscapePressed %d, grfKeyState %d)", fEscapePressed, grfKeyState);
528#endif
529
530 if (fEscapePressed) {
531 return ResultFromScode(DRAGDROP_S_CANCEL);
532 } else if (!(grfKeyState & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON))) {
533 return ResultFromScode(DRAGDROP_S_DROP);
534 } else {
535#if defined(Q_OS_WINCE)
536 // grfKeyState is broken on CE, therefore need to check
537 // the state manually
538 if ((GetAsyncKeyState(VK_LBUTTON) == 0) &&
539 (GetAsyncKeyState(VK_MBUTTON) == 0) &&
540 (GetAsyncKeyState(VK_RBUTTON) == 0)) {
541 return ResultFromScode(DRAGDROP_S_DROP);
542 }
543#else
544 if (currentButtons == Qt::NoButton) {
545 currentButtons = keystate_to_mousebutton(grfKeyState);
546 } else {
547 Qt::MouseButtons buttons = keystate_to_mousebutton(grfKeyState);
548 if (!(currentButtons & buttons))
549 return ResultFromScode(DRAGDROP_S_DROP);
550 }
551#endif
552 qApp->processEvents();
553 return NOERROR;
554 }
555}
556
557STDMETHODIMP
558QOleDropSource::GiveFeedback(DWORD dwEffect)
559{
560 Qt::DropAction action = translateToQDragDropAction(dwEffect);
561
562#ifdef QDND_DEBUG
563 qDebug("QOleDropSource::GiveFeedback(DWORD dwEffect)");
564 qDebug("dwEffect = %s", dragActionsToString(action).toLatin1().data());
565#endif
566
567 if (currentAction != action) {
568 currentAction = action;
569 QDragManager::self()->emitActionChanged(currentAction);
570 }
571
572 if (cursors.contains(currentAction)) {
573#ifndef QT_NO_CURSOR
574 SetCursor(cursors[currentAction].handle());
575#endif
576 return ResultFromScode(S_OK);
577 }
578
579 return ResultFromScode(DRAGDROP_S_USEDEFAULTCURSORS);
580}
581
582//---------------------------------------------------------------------
583// QOleDropTarget
584//---------------------------------------------------------------------
585
586QOleDropTarget::QOleDropTarget(QWidget* w)
587: widget(w)
588{
589 m_refs = 1;
590}
591
592void QOleDropTarget::releaseQt()
593{
594 widget = 0;
595}
596
597//---------------------------------------------------------------------
598// IUnknown Methods
599//---------------------------------------------------------------------
600
601
602STDMETHODIMP
603QOleDropTarget::QueryInterface(REFIID iid, void FAR* FAR* ppv)
604{
605 if(iid == IID_IUnknown || iid == IID_IDropTarget)
606 {
607 *ppv = this;
608 AddRef();
609 return NOERROR;
610 }
611 *ppv = NULL;
612 return ResultFromScode(E_NOINTERFACE);
613}
614
615
616STDMETHODIMP_(ULONG)
617QOleDropTarget::AddRef(void)
618{
619 return ++m_refs;
620}
621
622
623STDMETHODIMP_(ULONG)
624QOleDropTarget::Release(void)
625{
626 if(--m_refs == 0)
627 {
628 delete this;
629 return 0;
630 }
631 return m_refs;
632}
633
634//---------------------------------------------------------------------
635// IDropTarget Methods
636//---------------------------------------------------------------------
637
638STDMETHODIMP
639QOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
640{
641#ifdef QDND_DEBUG
642 qDebug("QOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)");
643#endif
644
645 if (!QApplicationPrivate::tryModalHelper(widget)) {
646 *pdwEffect = DROPEFFECT_NONE;
647 return NOERROR;
648 }
649
650 QDragManager *manager = QDragManager::self();
651 manager->dropData->currentDataObject = pDataObj;
652 manager->dropData->currentDataObject->AddRef();
653 sendDragEnterEvent(widget, grfKeyState, pt, pdwEffect);
654 *pdwEffect = chosenEffect;
655
656 return NOERROR;
657}
658
659void QOleDropTarget::sendDragEnterEvent(QWidget *dragEnterWidget, DWORD grfKeyState,
660 POINTL pt, LPDWORD pdwEffect)
661{
662 Q_ASSERT(dragEnterWidget);
663 lastPoint = dragEnterWidget->mapFromGlobal(QPoint(pt.x,pt.y));
664 lastKeyState = grfKeyState;
665
666 chosenEffect = DROPEFFECT_NONE;
667 currentWidget = dragEnterWidget;
668
669 QDragManager *manager = QDragManager::self();
670 QMimeData * md = manager->source() ? manager->dragPrivate()->data : manager->dropData;
671 QDragEnterEvent enterEvent(lastPoint, translateToQDragDropActions(*pdwEffect), md,
672 toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState));
673 QApplication::sendEvent(dragEnterWidget, &enterEvent);
674 answerRect = enterEvent.answerRect();
675
676 if (enterEvent.isAccepted()) {
677 chosenEffect = translateToWinDragEffects(enterEvent.dropAction());
678 }
679
680 // Documentation states that a drag move event is sendt immidiatly after
681 // a drag enter event. This will honor widgets overriding dragMoveEvent only:
682 if (enterEvent.isAccepted()) {
683 QDragMoveEvent moveEvent(lastPoint, translateToQDragDropActions(*pdwEffect), md,
684 toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState));
685 answerRect = enterEvent.answerRect();
686 moveEvent.setDropAction(enterEvent.dropAction());
687 moveEvent.accept(); // accept by default, since enter event was accepted.
688
689 QApplication::sendEvent(dragEnterWidget, &moveEvent);
690 if (moveEvent.isAccepted()) {
691 answerRect = moveEvent.answerRect();
692 chosenEffect = translateToWinDragEffects(moveEvent.dropAction());
693 } else {
694 chosenEffect = DROPEFFECT_NONE;
695 }
696 }
697
698}
699
700STDMETHODIMP
701QOleDropTarget::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
702{
703#ifdef QDND_DEBUG
704 qDebug("QOleDropTarget::DragOver(grfKeyState %d, pt (%d,%d), pdwEffect %d)", grfKeyState, pt.x, pt.y, pdwEffect);
705#endif
706
707 QWidget *dragOverWidget = widget->childAt(widget->mapFromGlobal(QPoint(pt.x, pt.y)));
708 if (!dragOverWidget)
709 dragOverWidget = widget;
710
711
712 if (!QApplicationPrivate::tryModalHelper(dragOverWidget)
713 || !dragOverWidget->testAttribute(Qt::WA_DropSiteRegistered)) {
714 *pdwEffect = DROPEFFECT_NONE;
715 return NOERROR;
716 }
717
718 QPoint tmpPoint = dragOverWidget->mapFromGlobal(QPoint(pt.x, pt.y));
719 // see if we should compress this event
720 if ((tmpPoint == lastPoint || answerRect.contains(tmpPoint)) && lastKeyState == grfKeyState) {
721 *pdwEffect = chosenEffect;
722 return NOERROR;
723 }
724
725 if (!dragOverWidget->internalWinId() && dragOverWidget != currentWidget) {
726 QPointer<QWidget> dragOverWidgetGuard(dragOverWidget);
727 // Send drag leave event to the previous drag widget.
728 QDragLeaveEvent dragLeave;
729 if (currentWidget)
730 QApplication::sendEvent(currentWidget, &dragLeave);
731 if (!dragOverWidgetGuard) {
732 dragOverWidget = widget->childAt(widget->mapFromGlobal(QPoint(pt.x, pt.y)));
733 if (!dragOverWidget)
734 dragOverWidget = widget;
735 }
736 // Send drag enter event to the current drag widget.
737 sendDragEnterEvent(dragOverWidget, grfKeyState, pt, pdwEffect);
738 }
739
740 QDragManager *manager = QDragManager::self();
741 QMimeData *md = manager->source() ? manager->dragPrivate()->data : manager->dropData;
742
743 QDragMoveEvent oldEvent(lastPoint, translateToQDragDropActions(*pdwEffect), md,
744 toQtMouseButtons(lastKeyState), toQtKeyboardModifiers(lastKeyState));
745
746
747 lastPoint = tmpPoint;
748 lastKeyState = grfKeyState;
749
750 QDragMoveEvent e(lastPoint, translateToQDragDropActions(*pdwEffect), md,
751 toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState));
752 if (chosenEffect != DROPEFFECT_NONE) {
753 if (oldEvent.dropAction() == e.dropAction() &&
754 oldEvent.keyboardModifiers() == e.keyboardModifiers())
755 e.setDropAction(translateToQDragDropAction(chosenEffect));
756 e.accept();
757 }
758 QApplication::sendEvent(dragOverWidget, &e);
759
760 answerRect = e.answerRect();
761 if (e.isAccepted())
762 chosenEffect = translateToWinDragEffects(e.dropAction());
763 else
764 chosenEffect = DROPEFFECT_NONE;
765 *pdwEffect = chosenEffect;
766
767 return NOERROR;
768}
769
770STDMETHODIMP
771QOleDropTarget::DragLeave()
772{
773#ifdef QDND_DEBUG
774 qDebug("QOleDropTarget::DragLeave()");
775#endif
776
777 if (!QApplicationPrivate::tryModalHelper(widget)) {
778 return NOERROR;
779 }
780
781 currentWidget = 0;
782 QDragLeaveEvent e;
783 QApplication::sendEvent(widget, &e);
784
785 QDragManager *manager = QDragManager::self();
786
787 if (manager->dropData->currentDataObject) { // Sanity
788 manager->dropData->currentDataObject->Release();
789 manager->dropData->currentDataObject = 0;
790 }
791
792 return NOERROR;
793}
794
795#define KEY_STATE_BUTTON_MASK (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)
796
797STDMETHODIMP
798QOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
799{
800#ifdef QDND_DEBUG
801 qDebug("QOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, grfKeyState %d, POINTL pt, LPDWORD pdwEffect)", grfKeyState);
802#endif
803
804 QWidget *dropWidget = widget->childAt(widget->mapFromGlobal(QPoint(pt.x, pt.y)));
805 if (!dropWidget)
806 dropWidget = widget;
807
808 if (!QApplicationPrivate::tryModalHelper(dropWidget)
809 || !dropWidget->testAttribute(Qt::WA_DropSiteRegistered)) {
810 *pdwEffect = DROPEFFECT_NONE;
811 return NOERROR;
812 }
813
814 lastPoint = dropWidget->mapFromGlobal(QPoint(pt.x,pt.y));
815 // grfKeyState does not all ways contain button state in the drop so if
816 // it doesn't then use the last known button state;
817 if ((grfKeyState & KEY_STATE_BUTTON_MASK) == 0)
818 grfKeyState |= lastKeyState & KEY_STATE_BUTTON_MASK;
819 lastKeyState = grfKeyState;
820
821 QDragManager *manager = QDragManager::self();
822 QMimeData *md = manager->source() ? manager->dragPrivate()->data : manager->dropData;
823 QDropEvent e(lastPoint, translateToQDragDropActions(*pdwEffect), md,
824 toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState));
825 if (chosenEffect != DROPEFFECT_NONE) {
826 e.setDropAction(translateToQDragDropAction(chosenEffect));
827 }
828 QApplication::sendEvent(dropWidget, &e);
829
830 if (chosenEffect != DROPEFFECT_NONE) {
831 e.accept();
832 }
833
834
835 if (e.isAccepted()) {
836 if (e.dropAction() == Qt::MoveAction || e.dropAction() == Qt::TargetMoveAction) {
837 if (e.dropAction() == Qt::MoveAction)
838 chosenEffect = DROPEFFECT_MOVE;
839 else
840 chosenEffect = DROPEFFECT_COPY;
841 HGLOBAL hData = GlobalAlloc(0, sizeof(DWORD));
842 if (hData) {
843 DWORD *moveEffect = (DWORD *)GlobalLock(hData);;
844 *moveEffect = DROPEFFECT_MOVE;
845 GlobalUnlock(hData);
846 STGMEDIUM medium;
847 memset(&medium, 0, sizeof(STGMEDIUM));
848 medium.tymed = TYMED_HGLOBAL;
849 medium.hGlobal = hData;
850 FORMATETC format;
851 format.cfFormat = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT);
852 format.tymed = TYMED_HGLOBAL;
853 format.ptd = 0;
854 format.dwAspect = 1;
855 format.lindex = -1;
856 manager->dropData->currentDataObject->SetData(&format, &medium, true);
857 }
858 } else {
859 chosenEffect = translateToWinDragEffects(e.dropAction());
860 }
861 } else {
862 chosenEffect = DROPEFFECT_NONE;
863 }
864 *pdwEffect = chosenEffect;
865
866
867 if (manager->dropData->currentDataObject) {
868 manager->dropData->currentDataObject->Release();
869 manager->dropData->currentDataObject = 0;
870 }
871
872 return NOERROR;
873
874 // We won't get any mouserelease-event, so manually adjust qApp state:
875///### test this QApplication::winMouseButtonUp();
876}
877
878//---------------------------------------------------------------------
879// QDropData
880//---------------------------------------------------------------------
881
882bool QDropData::hasFormat_sys(const QString &mimeType) const
883{
884 if (!currentDataObject) // Sanity
885 return false;
886
887 return QWindowsMime::converterToMime(mimeType, currentDataObject) != 0;
888}
889
890QStringList QDropData::formats_sys() const
891{
892 QStringList fmts;
893 if (!currentDataObject) // Sanity
894 return fmts;
895
896 fmts = QWindowsMime::allMimesForFormats(currentDataObject);
897
898 return fmts;
899}
900
901QVariant QDropData::retrieveData_sys(const QString &mimeType, QVariant::Type type) const
902{
903 QVariant result;
904
905 if (!currentDataObject) // Sanity
906 return result;
907
908 QWindowsMime *converter = QWindowsMime::converterToMime(mimeType, currentDataObject);
909
910 if (converter)
911 result = converter->convertToMime(mimeType, currentDataObject, type);
912
913 return result;
914}
915
916Qt::DropAction QDragManager::drag(QDrag *o)
917
918{
919#ifdef QDND_DEBUG
920 qDebug("QDragManager::drag(QDrag *drag)");
921#endif
922
923 if (object == o || !o || !o->d_func()->source)
924 return Qt::IgnoreAction;
925
926 if (object) {
927 cancel();
928 qApp->removeEventFilter(this);
929 beingCancelled = false;
930 }
931
932 object = o;
933
934#ifdef QDND_DEBUG
935 qDebug("actions = %s", dragActionsToString(dragPrivate()->possible_actions).toLatin1().data());
936#endif
937
938 dragPrivate()->target = 0;
939
940#ifndef QT_NO_ACCESSIBILITY
941 QAccessible::updateAccessibility(this, 0, QAccessible::DragDropStart);
942#endif
943
944 DWORD resultEffect;
945 QOleDropSource *src = new QOleDropSource();
946 src->createCursors();
947 QOleDataObject *obj = new QOleDataObject(o->mimeData());
948 DWORD allowedEffects = translateToWinDragEffects(dragPrivate()->possible_actions);
949
950#if !defined(Q_OS_WINCE) || defined(GWES_ICONCURS)
951 HRESULT r = DoDragDrop(obj, src, allowedEffects, &resultEffect);
952#else
953 HRESULT r = DRAGDROP_S_CANCEL;
954 resultEffect = DROPEFFECT_MOVE;
955#endif
956
957 Qt::DropAction ret = Qt::IgnoreAction;
958 if (r == DRAGDROP_S_DROP) {
959 if (obj->reportedPerformedEffect() == DROPEFFECT_MOVE && resultEffect != DROPEFFECT_MOVE) {
960 ret = Qt::TargetMoveAction;
961 resultEffect = DROPEFFECT_MOVE;
962 } else {
963 ret = translateToQDragDropAction(resultEffect);
964 }
965 // Force it to be a copy if an unsupported operation occurred.
966 // This indicates a bug in the drop target.
967 if (resultEffect != DROPEFFECT_NONE && !(resultEffect & allowedEffects))
968 ret = Qt::CopyAction;
969 } else {
970 dragPrivate()->target = 0;
971 }
972
973 // clean up
974 obj->releaseQt();
975 obj->Release(); // Will delete obj if refcount becomes 0
976 src->Release(); // Will delete src if refcount becomes 0
977 object = 0;
978 o->setMimeData(0);
979 o->deleteLater();
980
981#ifndef QT_NO_ACCESSIBILITY
982 QAccessible::updateAccessibility(this, 0, QAccessible::DragDropEnd);
983#endif
984
985 return ret;
986}
987
988void QDragManager::cancel(bool /* deleteSource */)
989{
990 if (object) {
991 beingCancelled = true;
992 object = 0;
993 }
994
995#ifndef QT_NO_CURSOR
996 // insert cancel code here ######## todo
997
998 if (restoreCursor) {
999 QApplication::restoreOverrideCursor();
1000 restoreCursor = false;
1001 }
1002#endif
1003#ifndef QT_NO_ACCESSIBILITY
1004 QAccessible::updateAccessibility(this, 0, QAccessible::DragDropEnd);
1005#endif
1006}
1007
1008void QDragManager::updatePixmap()
1009{
1010 // not used in windows implementation
1011}
1012
1013bool QDragManager::eventFilter(QObject *, QEvent *)
1014{
1015 // not used in windows implementation
1016 return false;
1017}
1018
1019void QDragManager::timerEvent(QTimerEvent*)
1020{
1021 // not used in windows implementation
1022}
1023
1024void QDragManager::move(const QPoint &)
1025{
1026 // not used in windows implementation
1027}
1028
1029void QDragManager::drop()
1030{
1031 // not used in windows implementation
1032}
1033
1034QT_END_NAMESPACE
1035
1036#endif // QT_NO_DRAGANDDROP
Note: See TracBrowser for help on using the repository browser.