Changeset 444


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

gui: DND: Implemented dropping text to Qt applications.

Location:
trunk/src/gui/kernel
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • TabularUnified 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
  • TabularUnified trunk/src/gui/kernel/qmime.h

    r443 r444  
    148148        virtual HWND hwnd() const = 0;
    149149        // methods implemented if isExclusive() == TRUE and itemCount() == 0
    150         virtual DRAGINFO *createDragInfo(const char *name, USHORT supportedOps)
    151                                         { return NULL; }
     150        virtual DRAGINFO *createDragInfo(const QString &targetName, USHORT supportedOps)
     151                                        { return 0; }
    152152        // methods implemented if itemCount() >= 0
    153153        virtual QByteArray composeFormatString() { return QByteArray(); }
    154154        virtual bool prepare(const char *drm, const char *drf, DRAGITEM *item,
    155                              ULONG itemIndex) { return FALSE; }
     155                             ULONG itemIndex) { return false; }
    156156        virtual void defaultFileType(const char *&type, const char *&ext) {};
    157157
     
    185185        {
    186186        public:
    187             virtual const QString &format(const char *drf) const = 0;
     187            virtual QString format(const char *drf) const = 0;
    188188            virtual bool provide(const char *drf, const QByteArray &allData,
    189189                                 ULONG itemIndex, QByteArray &itemData) = 0;
     
    217217        virtual bool hasFormat(const QString &mimeType) const = 0;
    218218        virtual QStringList formats() const = 0;
    219         virtual QVariant retrieveData(const QString &mimeType, QVariant::Type type) const = 0;
     219        virtual QVariant retrieveData(const QString &mimeType,
     220                                      QVariant::Type preferredType) const = 0;
    220221
    221222    private:
     
    236237        bool hasFormat(const QString &mimeType) const;
    237238        QStringList formats() const;
    238         QVariant retrieveData(const QString &mimeType, QVariant::Type type) const;
     239        QVariant retrieveData(const QString &mimeType,
     240                              QVariant::Type preferredType) const;
    239241
    240242        // QPMObjectWindow interface
  • TabularUnified trunk/src/gui/kernel/qmime_pm.cpp

    r442 r444  
    6060#include "qdir.h"
    6161
    62 #define QDND_DEBUG // in pair with qdnd_pm.cpp
     62//#define QDND_DEBUG // in pair with qdnd_pm.cpp
    6363
    6464#ifdef QDND_DEBUG
     
    769769}
    770770
    771 // @todo
     771// @todo remove
    772772//int QPMMime::DefaultDropWorker::formatCount() const
    773773//{
     
    814814
    815815QVariant QPMMime::DefaultDropWorker::retrieveData(const QString &mimeType,
    816                                                   QVariant::Type type) const
    817 {
    818     Q_UNUSED(type);
    819 
    820     DEBUG(() << "DefaultDropWorker::retrieveData(" << mimeType << ")");
     816                                                  QVariant::Type preferredType) const
     817{
     818    Q_UNUSED(preferredType);
     819
     820    DEBUG(() << "DefaultDropWorker::retrieveData: mimeType" << mimeType);
    821821
    822822    QVariant ret;
     
    10001000                bool ok = file.remove();
    10011001                Q_ASSERT((ok = ok));
     1002                Q_UNUSED(ok);
    10021003            } else {
    10031004                Q_ASSERT(xfer->hstrRenderToName);
     
    10881089            if (d->sending_DM_RENDER)
    10891090            {
     1091#ifndef QT_NO_DEBUG
    10901092                DRAGTRANSFER *xfer = (DRAGTRANSFER *) mp1;
    1091 #ifndef QT_NO_DEBUG
    10921093                qWarning("Drag item 0x%08lX sent DM_RENDERCOMPLETE w/o first "
    10931094                         "replying to DM_RENDER!\n"
     
    14201421    All subclasses must reimplement this pure virtual function.
    14211422*/
     1423
     1424// @todo add DnD interfaces docs
    14221425
    14231426// static
     
    17881791QPMMime::DefaultDragWorker *QPMMime::defaultExclDragWorker()
    17891792{
    1790     static DefaultDragWorker defExclDragWorker(false /* exclusive */);
     1793    static DefaultDragWorker defExclDragWorker(true /* exclusive */);
    17911794    return &defExclDragWorker;
    17921795}
     
    18211824                               QVariant::Type preferredType) const;
    18221825
     1826#if !defined(QT_NO_DRAGANDDROP)
     1827
     1828    // Direct Manipulation (DND) converter interface
     1829    DragWorker *dragWorkerFor(const QString &mimeType, QMimeData *mimeData);
     1830    DropWorker *dropWorkerFor(DRAGINFO *info);
     1831
     1832    class NativeFileDrag : public DragWorker, public QPMObjectWindow
     1833    {
     1834    public:
     1835        // DragWorker interface
     1836        bool cleanup(bool isCancelled) { return true; } // always disallow Move
     1837        bool isExclusive() const { return true; }
     1838        ULONG itemCount() const { return 0; } // super exclusive
     1839        HWND hwnd() const { return QPMObjectWindow::hwnd(); }
     1840        DRAGINFO *createDragInfo(const QString &targetName, USHORT supportedOps);
     1841        // QPMObjectWindow interface (dummy implementation, we don't need to interact)
     1842        MRESULT message(ULONG msg, MPARAM mp1, MPARAM mp2) { return 0; }
     1843    };
     1844
     1845    class NativeFileDrop : public DropWorker
     1846    {
     1847    public:
     1848        // DropWorker interface
     1849        bool isExclusive() const { return true; }
     1850        bool hasFormat(const QString &mimeType) const;
     1851        QStringList formats() const;
     1852        QVariant retrieveData(const QString &mimeType,
     1853                              QVariant::Type preferredType) const;
     1854    };
     1855
     1856    class TextDragProvider : public DefaultDragWorker::Provider
     1857    {
     1858    public:
     1859        TextDragProvider() : exclusive(false) {}
     1860        bool exclusive;
     1861        // Provider interface
     1862        QString format(const char *drf) const;
     1863        bool provide(const char *drf, const QByteArray &allData,
     1864                     ULONG itemIndex, QByteArray &itemData);
     1865        void fileType(const char *drf, const char *&type, const char *&ext);
     1866    };
     1867
     1868    class TextDropProvider : public DefaultDropWorker::Provider
     1869    {
     1870    public:
     1871        // Provider interface
     1872        const char *drf(const QString &mimeType) const;
     1873        bool provide(const QString &format, ULONG itemIndex,
     1874                     const QByteArray &itemData, QByteArray &allData);
     1875    };
     1876
     1877#endif // !QT_NO_DRAGANDDROP
     1878
    18231879    const ULONG CF_TextUnicode;
    18241880    const ULONG CF_TextHtml;
     1881
     1882#if !defined(QT_NO_DRAGANDDROP)
     1883    NativeFileDrag nativeFileDrag;
     1884    NativeFileDrop nativeFileDrop;
     1885    TextDragProvider textDragProvider;
     1886    TextDropProvider textDropProvider;
     1887#endif // !QT_NO_DRAGANDDROP
    18251888};
    18261889
     
    19992062}
    20002063
     2064#if !defined(QT_NO_DRAGANDDROP)
     2065
     2066DRAGINFO *QPMMimeText::NativeFileDrag::createDragInfo(const QString &targetName,
     2067                                                      USHORT supportedOps)
     2068{
     2069    Q_ASSERT(source());
     2070    if (!source())
     2071        return 0;
     2072
     2073    // obtain the list of files
     2074    QList<QUrl> list;
     2075    if (source()->hasUrls())
     2076        list = source()->urls();
     2077    ULONG itemCnt = list.count();
     2078    Q_ASSERT(itemCnt);
     2079    if (!itemCnt)
     2080        return 0;
     2081
     2082    DEBUG(() << "QPMMimeText::NativeFileDrag: itemCnt" << itemCnt);
     2083
     2084    DRAGINFO *info = DrgAllocDraginfo(itemCnt);
     2085    Q_ASSERT(info);
     2086    if (!info)
     2087        return 0;
     2088
     2089    bool ok = true;
     2090    QList<QUrl>::iterator it = list.begin();
     2091    for (ULONG i = 0; i < itemCnt; ++i, ++it) {
     2092        DRAGITEM *item = DrgQueryDragitemPtr(info, i);
     2093        Q_ASSERT(item);
     2094        if (!item) {
     2095            ok = false;
     2096            break;
     2097        }
     2098
     2099        QByteArray fileName = QFile::encodeName(QDir::convertSeparators(it->toLocalFile()));
     2100
     2101        int sep = fileName.lastIndexOf('\\');
     2102        Q_ASSERT(sep > 0 && sep < fileName.length() - 1);
     2103        if (sep <= 0 || sep >= fileName.length() - 1) {
     2104            ok = false;
     2105            break;
     2106        }
     2107
     2108        item->hstrSourceName = DrgAddStrHandle(fileName.data() + sep + 1);
     2109        fileName.truncate(sep + 1);
     2110        item->hstrContainerName = DrgAddStrHandle(fileName);
     2111
     2112        DEBUG(() << "QPMMimeText::NativeFileDrag: item" << i
     2113                 << "dir" << queryHSTR(item->hstrContainerName)
     2114                 << "name" << queryHSTR(item->hstrSourceName));
     2115
     2116        item->hwndItem = hwnd();
     2117        item->ulItemID = 0;
     2118        item->hstrType = DrgAddStrHandle(DRT_UNKNOWN);
     2119        item->hstrRMF = DrgAddStrHandle("<DRM_OS2FILE,DRF_UNKNOWN>");
     2120        item->hstrTargetName = 0;
     2121        item->cxOffset = 0;
     2122        item->cyOffset = 0;
     2123        item->fsControl = 0;
     2124        item->fsSupportedOps = supportedOps;
     2125    }
     2126
     2127    if (!ok) {
     2128        DrgFreeDraginfo(info);
     2129        info = 0;
     2130    }
     2131
     2132    return info;
     2133}
     2134
     2135bool QPMMimeText::NativeFileDrop::hasFormat(const QString &mimeType) const
     2136{
     2137    return mimeType == QLatin1String("text/uri-list");
     2138}
     2139
     2140QStringList QPMMimeText::NativeFileDrop::formats() const
     2141{
     2142    QStringList mimes;
     2143    mimes << QLatin1String("text/uri-list");
     2144    return mimes;
     2145}
     2146
     2147QVariant QPMMimeText::NativeFileDrop::retrieveData(const QString &mimeType,
     2148                                                   QVariant::Type preferredType) const
     2149{
     2150    QVariant result;
     2151
     2152    Q_ASSERT(info());
     2153    if (!info())
     2154        return result;
     2155
     2156    ULONG itemCount = DrgQueryDragitemCount(info());
     2157    Q_ASSERT(itemCount);
     2158    if (!itemCount)
     2159        return result;
     2160
     2161    // sanity check
     2162    if (mimeType != QLatin1String("text/uri-list"))
     2163        return result;
     2164
     2165    QList<QVariant> urls;
     2166
     2167    for (ULONG i = 0; i < itemCount; ++i) {
     2168        DRAGITEM *item = DrgQueryDragitemPtr(info(), i);
     2169        Q_ASSERT(item);
     2170        QByteArray fullName;
     2171        if (!item || !canTargetRenderAsOS2File(item, &fullName))
     2172            return result;
     2173        QString fn = QFile::decodeName(fullName);
     2174        urls += QUrl::fromLocalFile(fn).toString();
     2175    }
     2176
     2177    if (preferredType == QVariant::Url && urls.size() == 1)
     2178        result = urls.at(0);
     2179    else if (!urls.isEmpty())
     2180        result = urls;
     2181
     2182    return result;
     2183}
     2184
     2185QString QPMMimeText::TextDragProvider::format(const char *drf) const
     2186{
     2187    QString result;
     2188
     2189    if (qstrcmp(drf, "DRF_TEXT") == 0) {
     2190        if (exclusive)
     2191            result = QLatin1String("text/uri-list");
     2192        else
     2193            result = QLatin1String("text/plain");
     2194    }
     2195    return result;
     2196}
     2197
     2198bool QPMMimeText::TextDragProvider::provide(const char *drf,
     2199                                            const QByteArray &allData,
     2200                                            ULONG itemIndex,
     2201                                            QByteArray &itemData)
     2202{
     2203    if (qstrcmp(drf, "DRF_TEXT") == 0) {
     2204        if (exclusive) {
     2205            // locate the required item
     2206            int dataSize = allData.size();
     2207            if (!dataSize)
     2208                return false;
     2209            int begin = 0, end = 0, next = 0;
     2210            do {
     2211                begin = next;
     2212                end = allData.indexOf('\r', begin);
     2213                if (end >= 0) {
     2214                    next = end + 1;
     2215                    if (next < dataSize && allData[next] == '\n')
     2216                        ++next;
     2217                } else {
     2218                    end = allData.indexOf('\n', begin);
     2219                    if (end >= 0)
     2220                        next = end + 1;
     2221                }
     2222            } while (itemIndex-- && end >= 0 && next < dataSize);
     2223            int urlLen = end - begin;
     2224            if (urlLen <= 0)
     2225                return false;
     2226            QUrl url = QUrl(QString::fromUtf8(allData.data() + begin, urlLen));
     2227            if (!url.isValid())
     2228                return false;
     2229            itemData = url.toEncoded();
     2230        } else {
     2231            itemData = allData;
     2232        }
     2233        return true;
     2234    }
     2235    return false;
     2236}
     2237
     2238void QPMMimeText::TextDragProvider::fileType(const char *drf, const char *&type,
     2239                                             const char *&ext)
     2240{
     2241    if (qstrcmp(drf, "DRF_TEXT") == 0) {
     2242        if (exclusive) {
     2243            type = "UniformResourceLocator";
     2244            // no extension for URLs
     2245        } else {
     2246            type = DRT_TEXT;
     2247            ext = "txt";
     2248        }
     2249    }
     2250};
     2251
     2252const char *QPMMimeText::TextDropProvider::drf(const QString &mimeType) const
     2253{
     2254    // sanity check
     2255    if (mimeType == QLatin1String("text/plain") ||
     2256        mimeType == QLatin1String("text/uri-list"))
     2257        return "DRF_TEXT";
     2258    return 0;
     2259}
     2260
     2261bool QPMMimeText::TextDropProvider::provide(const QString &mimeType,
     2262                                            ULONG itemIndex,
     2263                                            const QByteArray &itemData,
     2264                                            QByteArray &allData)
     2265{
     2266    if (mimeType == QLatin1String("text/plain")) {
     2267        allData = itemData;
     2268        return true;
     2269    }
     2270
     2271    if (mimeType == QLatin1String("text/uri-list")) {
     2272        QUrl url = QUrl::fromEncoded(itemData);
     2273        if (!url.isValid())
     2274            return false;
     2275        // append the URL to the list
     2276        allData += url.toString().toUtf8();
     2277        allData += "\r\n";
     2278        return true;
     2279    }
     2280
     2281    return false;
     2282}
     2283
     2284QPMMime::DragWorker *QPMMimeText::dragWorkerFor(const QString &mimeType,
     2285                                                QMimeData *mimeData)
     2286{
     2287    if (mimeType == QLatin1String("text/plain")) {
     2288        // add a cooperative provider
     2289        textDragProvider.exclusive = false;
     2290        DefaultDragWorker *defWorker = defaultCoopDragWorker();
     2291        defWorker->addProvider("DRF_TEXT", &textDragProvider);
     2292        return defWorker;
     2293    }
     2294
     2295    if (mimeType == QLatin1String("text/uri-list")) {
     2296        // see what kind of items text/uri-list represents
     2297        QList<QUrl> urls = mimeData->urls();
     2298        int fileCnt = 0;
     2299        foreach (const QUrl &url, urls) {
     2300            if (url.scheme() == QLatin1String("file"))
     2301                ++fileCnt;
     2302        }
     2303        if (fileCnt && fileCnt == urls.count()) {
     2304            // all items are local files, return an exclusive file drag worker
     2305            return &nativeFileDrag;
     2306        }
     2307        if (urls.count() && !fileCnt) {
     2308            // all items are non-files, add an exclusive provider for the
     2309            // specified item count
     2310            textDragProvider.exclusive = true;
     2311            DefaultDragWorker *defWorker = defaultExclDragWorker();
     2312            bool ok = defWorker->addProvider("DRF_TEXT", &textDragProvider,
     2313                                             urls.count());
     2314            return ok ? defWorker : 0;
     2315        }
     2316        // if items are mixed, we return NULL to fallback to QPMMimeAnyMime
     2317    }
     2318
     2319    return 0;
     2320}
     2321
     2322QPMMime::DropWorker *QPMMimeText::dropWorkerFor(DRAGINFO *info)
     2323{
     2324    ULONG itemCount = DrgQueryDragitemCount(info);
     2325    Q_ASSERT(itemCount);
     2326    if (!itemCount)
     2327        return 0;
     2328
     2329    if (itemCount == 1) {
     2330        DRAGITEM *item = DrgQueryDragitemPtr(info, 0);
     2331        Q_ASSERT(item);
     2332        if (!item)
     2333            return 0;
     2334        // proceed only if the target cannot render DRM_OS2FILE on its own
     2335        // and if the item type is not "UniformResourceLocator" (which will be
     2336        // processed below)
     2337        if (!canTargetRenderAsOS2File(item) &&
     2338            !DrgVerifyType(item, "UniformResourceLocator")) {
     2339            DefaultDropWorker *defWorker = defaultDropWorker();
     2340            // check that we support one of DRMs and the format is DRF_TEXT
     2341            if (defWorker->canRender(item, "DRF_TEXT")) {
     2342                // add a cooperative provider (can coexist with others)
     2343                defWorker->addProvider(QLatin1String("text/plain"),
     2344                                        &textDropProvider);
     2345                return defWorker;
     2346            }
     2347            return 0;
     2348        }
     2349    }
     2350
     2351    // Either the target can render DRM_OS2FILE on its own (so it's a valid
     2352    // file/directory name), or it's an "UniformResourceLocator", or there is
     2353    // more than one drag item. Check that all items are of either one type
     2354    // or another. If so, we can represent them as 'text/uri-list'.
     2355    bool allAreFiles = true;
     2356    bool allAreURLs = true;
     2357    DefaultDropWorker *defWorker = defaultDropWorker();
     2358    for (ULONG i = 0; i < itemCount; ++i) {
     2359        DRAGITEM *item = DrgQueryDragitemPtr(info, i);
     2360        Q_ASSERT(item);
     2361        if (!item)
     2362            return 0;
     2363        if (allAreFiles)
     2364            allAreFiles &= canTargetRenderAsOS2File(item);
     2365        if (allAreURLs)
     2366            allAreURLs &= DrgVerifyType(item, "UniformResourceLocator") &&
     2367                          defWorker->canRender(item, "DRF_TEXT");
     2368        if (!allAreFiles && !allAreURLs)
     2369            return 0;
     2370    }
     2371
     2372    if (allAreFiles) {
     2373        // return an exclusive drop worker
     2374        return &nativeFileDrop;
     2375    }
     2376
     2377    // add an exclusive provider (can neither coexist with other workers
     2378    // or providers)
     2379    bool ok = defWorker->addExclusiveProvider(QLatin1String("text/uri-list"),
     2380                                              &textDropProvider);
     2381    return ok ? defWorker : 0;
     2382}
     2383
     2384#endif // !QT_NO_DRAGANDDROP
     2385
    20012386////////////////////////////////////////////////////////////////////////////////
    20022387
Note: See TracChangeset for help on using the changeset viewer.