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/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.