Ignore:
Timestamp:
Dec 30, 2009, 2:32:09 AM (16 years ago)
Author:
Dmitry A. Kuminov
Message:

gui: DND: Implemented dropping text to Qt applications.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/gui/kernel/qdnd_pm.cpp

    r442 r444  
    5757#include "qt_os2.h"
    5858
    59 #define QDND_DEBUG // in pair with qmime_pm.cpp
     59//#define QDND_DEBUG // in pair with qmime_pm.cpp
    6060
    6161#ifdef QDND_DEBUG
     
    8989    bool hasFormat_sys(const QString &mimeType);
    9090    QStringList formats_sys();
    91     QVariant retrieveData_sys(const QString &mimeType, QVariant::Type type);
     91    QVariant retrieveData_sys(const QString &mimeType,
     92                              QVariant::Type preferredType);
    9293
    9394private:
     
    209210
    210211QVariant QPMDragData::retrieveData_sys(const QString &mimeType,
    211                                        QVariant::Type type)
     212                                       QVariant::Type preferredType)
    212213{
    213214    QVariant result;
     
    222223    foreach (QPMMime::DropWorker *w, workers) {
    223224        if (w->hasFormat(mimeType)) {
    224             result = w->retrieveData(mimeType, type);
     225            result = w->retrieveData(mimeType, preferredType);
    225226            break;
    226227        }
     
    270271MRESULT qt_dispatchDragAndDrop(QWidget *widget, const QMSG &qmsg)
    271272{
    272     // @todo maybe delete last*Op variables
    273 
    274     static HWND lastDragOverHwnd = 0; // last target window
     273    static QWidget *lastDragOverWidget = 0; // last target widget
    275274    static USHORT lastDragOverOp = 0; // last DM_DRAGOVER operation
    276275
    277276    static USHORT supportedOps = 0; // operations supported by all items
     277    static bool sourceAllowsOp = false; // does source allow requested operation
    278278
    279279    static USHORT lastDropReply = DOR_NEVERDROP; // last reply to DM_DRAGOVER
    280280    static USHORT lastOpRequest = DO_UNKNOWN; // last op requested in DM_DRAGOVER
    281281
    282     static Qt::DropAction lastProposedAction = Qt::IgnoreAction; // last proposed action
     282    static Qt::DropAction lastProposedAction = Qt::CopyAction; // last proposed action
    283283    static QRect lastAnswerRect; // last accepted rectangle from the target
    284284    // @todo use lastAnswerRect to compress DM_DRAGOVER events
     
    289289
    290290    BOOL ok = FALSE;
     291
     292    QDragManager *manager = QDragManager::self();
    291293
    292294    switch (qmsg.msg) {
     
    294296            DEBUG(("DM_DRAGOVER: hwnd %lX di %p x %d y %d", qmsg.hwnd, qmsg.mp1,
    295297                   SHORT1FROMMP(qmsg.mp2), SHORT2FROMMP(qmsg.mp2)));
    296 
    297             bool first = lastDragOverHwnd != qmsg.hwnd;
    298             if (first) {
    299                 // the first DM_DRAGOVER message
    300                 lastDragOverHwnd = qmsg.hwnd;
    301                 lastDropReply = DOR_NEVERDROP;
    302                 lastOpRequest = DO_UNKNOWN;
    303                 lastProposedAction = Qt::IgnoreAction;
    304                 lastAnswerRect = QRect();
    305                 supportedOps = DO_COPYABLE | DO_MOVEABLE | DO_LINKABLE;
    306                 // ensure drag data is reset (just in case of a wrong msg flow...)
    307                 dragData.reset();
    308             }
    309 
    310             Q_ASSERT(first || widget->acceptDrops());
    311             if (!widget->acceptDrops()) {
    312                 if (!first) {
    313                     // Odin32 apps are dramatically bogus, they continue to send
    314                     // DM_DRAGOVER even if we reply DOR_NEVERDROP. Simulate
    315                     // DM_DRAGLEAVE
    316                     lastDragOverHwnd = 0;
    317                     dragData.reset();
    318                 }
    319                 return MRFROM2SHORT(DOR_NEVERDROP, 0);
    320             }
    321298
    322299            DRAGINFO *info = (DRAGINFO *)qmsg.mp1;
     
    325302            if (!ok || !info)
    326303                return MRFROM2SHORT(DOR_NEVERDROP, 0);
     304
     305            // flip y coordinate
     306            QPoint pnt(info->xDrop, info->yDrop);
     307            pnt.setY(QApplication::desktop()->height() - (pnt.y() + 1));
     308            pnt = widget->mapFromGlobal(pnt);
     309
     310            QWidget *dragOverWidget = widget->childAt(pnt);
     311            if (!dragOverWidget)
     312                dragOverWidget = widget;
     313
     314            bool first = lastDragOverWidget != dragOverWidget;
     315            if (first) {
     316                // the first DM_DRAGOVER message
     317                if (lastDragOverWidget != 0) {
     318                    // send drag leave to the old widget
     319                    dragData.reset();
     320                    QPointer<QWidget> dragOverWidgetGuard(dragOverWidget);
     321                    QDragLeaveEvent dle;
     322                    QApplication::sendEvent(lastDragOverWidget, &dle);
     323                    if (!dragOverWidgetGuard) {
     324                        dragOverWidget = widget->childAt(pnt);
     325                        if (!dragOverWidget)
     326                            dragOverWidget = widget;
     327                    }
     328                }
     329                lastDragOverWidget = dragOverWidget;
     330                lastDragOverOp = 0;
     331                supportedOps = DO_COPYABLE | DO_MOVEABLE | DO_LINKABLE;
     332                sourceAllowsOp = false;
     333                lastDropReply = DOR_NEVERDROP;
     334                lastOpRequest = DO_UNKNOWN;
     335                lastProposedAction = manager->defaultAction(toQDragDropActions(supportedOps),
     336                                                            Qt::NoModifier);
     337                lastAnswerRect = QRect();
     338                // ensure drag data is reset (just in case of a wrong msg flow...)
     339                dragData.reset();
     340            }
     341
     342            if (!dragOverWidget->acceptDrops()) {
     343                // We don't reply with DOR_NEVERDROP here because in this
     344                // case PM will stop sending DM_DRAGOVER to the given HWND but
     345                // we may have another non-native child (that has the same HWND)
     346                // at a different position that accepts drops
     347                DrgFreeDraginfo(info);
     348                return MRFROM2SHORT(DOR_NODROP, 0);
     349            }
    327350
    328351            USHORT dropReply = DOR_DROP;
     
    352375            if (dropReply != DOR_NEVERDROP) {
    353376
    354                 bool sourceAllowsOp = false;
    355 
    356377                if (first || lastDragOverOp != info->usOperation) {
    357378                    // the current drop operation was changed by a modifier key
     
    373394                // the drop. Other platforms seem to do the same.
    374395
    375                 // flip y coordinate
    376                 QPoint pnt(info->xDrop, info->yDrop);
    377                 pnt.setY(QApplication::desktop()->height() - (pnt.y() + 1));
    378                 pnt = widget->mapFromGlobal(pnt);
    379 
    380                 QDragManager *manager = QDragManager::self();
    381396                QMimeData *data = manager->source() ? manager->dragPrivate()->data : manager->dropData;
    382397
     
    388403                                        QApplication::mouseButtons(),
    389404                                        QApplication::keyboardModifiers());
    390                     QApplication::sendEvent(widget, &dee);
     405                    QApplication::sendEvent(dragOverWidget, &dee);
    391406                    // if not allowed or not accepted, always reply DOR_NODROP
    392                     // to have DM_DRAGOVER delivered to us again in any case
     407                    // to have DM_DRAGOVER delivered to us again for a new test
    393408                    if (sourceAllowsOp && dee.isAccepted()) {
    394409                        dropReply = DOR_DROP;
    395410                        action = dee.dropAction();
     411                        lastProposedAction = dee.proposedAction();
    396412                        lastAnswerRect = dee.answerRect();
    397413                    } else {
     
    410426                    dme.setDropAction(action);
    411427                    dme.accept();
    412                     QApplication::sendEvent(widget, &dme);
     428                    QApplication::sendEvent(dragOverWidget, &dme);
    413429                    if (sourceAllowsOp && dme.isAccepted()) {
    414430                        dropReply = DOR_DROP;
    415431                        action = dme.dropAction();
     432                        lastProposedAction = dme.proposedAction();
     433                        lastAnswerRect = dme.answerRect();
    416434                    } else {
    417435                        dropReply = DOR_NODROP;
     
    431449
    432450            // Odin32 apps produce incorrect message flow, ignore
    433             Q_ASSERT(lastDragOverHwnd != 0);
    434             if (lastDragOverHwnd == 0)
     451            Q_ASSERT(lastDragOverWidget != 0);
     452            if (lastDragOverWidget == 0)
    435453                return 0;
    436454
    437             lastDragOverHwnd = 0;
     455            QDragLeaveEvent de;
     456            QApplication::sendEvent(lastDragOverWidget, &de);
     457
     458            lastDragOverWidget = 0;
    438459            dragData.reset();
    439460
    440             if (!widget->acceptDrops())
    441                 return 0;
    442 
    443             QDragLeaveEvent de;
    444             QApplication::sendEvent(widget, &de);
    445461            return 0;
    446462        }
     
    449465
    450466            // Odin32 apps produce incorrect message flow, ignore
    451             Q_ASSERT(lastDragOverHwnd != 0);
    452             if (lastDragOverHwnd == 0)
     467            Q_ASSERT(lastDragOverWidget != 0);
     468            if (lastDragOverWidget == 0)
    453469                return 0;
    454470
    455471            // Odin32 apps send DM_DROP even if we replied DOR_NEVERDROP or
    456472            // DOR_NODROP, simulate DM_DRAGLEAVE
    457             Q_ASSERT(lastDropReply == DM_DROP);
    458             if (lastDropReply != DM_DROP) {
    459                 WinSendMsg(qmsg.hwnd, DM_DRAGLEAVE, 0, 0);
     473            Q_ASSERT(lastDropReply == DOR_DROP);
     474            if (lastDropReply != DOR_DROP) {
     475                QMSG qmsg2 = qmsg;
     476                qmsg2.msg = DM_DRAGLEAVE;
     477                qt_dispatchDragAndDrop(widget, qmsg2);
    460478                return 0;
    461479            }
    462 
    463             lastDragOverHwnd = 0;
    464 
    465             Q_ASSERT(widget->acceptDrops());
    466             if (!widget->acceptDrops())
    467                 return 0;
    468480
    469481            DRAGINFO *info = (DRAGINFO *)qmsg.mp1;
     
    471483            Q_ASSERT(ok && info);
    472484            if (!ok || !info)
    473                 return MRFROM2SHORT(DOR_NEVERDROP, 0);
    474 
    475             Q_ASSERT(lastOpRequest == info->usOperation);
     485                return 0;
    476486
    477487            // flip y coordinate
     
    480490            pnt = widget->mapFromGlobal(pnt);
    481491
     492            Q_ASSERT(lastOpRequest == info->usOperation);
     493
     494            Q_ASSERT(lastDragOverWidget->acceptDrops());
     495            if (!lastDragOverWidget->acceptDrops()) {
     496                DrgDeleteDraginfoStrHandles(info);
     497                DrgFreeDraginfo(info);
     498                return 0;
     499            }
     500
    482501            QDragManager *manager = QDragManager::self();
    483502            QMimeData *data = manager->source() ? manager->dragPrivate()->data : manager->dropData;
     
    492511                de.setDropAction(action);
    493512
    494             QApplication::sendEvent(widget, &de);
     513            QApplication::sendEvent(lastDragOverWidget, &de);
    495514
    496515            if (lastDropReply == DOR_DROP)
    497516                de.accept();
    498517
     518            lastDragOverWidget = 0;
    499519            dragData.reset(de.isAccepted());
    500520
Note: See TracChangeset for help on using the changeset viewer.