Changeset 441 for trunk/src


Ignore:
Timestamp:
Dec 26, 2009, 2:14:18 AM (16 years ago)
Author:
Dmitry A. Kuminov
Message:

gui: QPMMime: Adding more DND support code, fixing the build.

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

Legend:

Unmodified
Added
Removed
  • trunk/src/gui/kernel/qmime.h

    r439 r441  
    115115*/
    116116
    117 typedef unsigned long ULONG;
     117#if !defined(QT_NO_DRAGANDDROP)
     118QT_END_NAMESPACE
     119#include "private/qpmobjectwindow_pm_p.h"
     120QT_BEGIN_NAMESPACE
     121#endif
    118122
    119123class QPMCoopDragWorker;
     
    125129#if !defined(QT_NO_DRAGANDDROP)
    126130
     131    typedef QList<QByteArray> QByteArrayList;
     132
    127133    class DragWorker
    128134    {
    129135    public:
    130         DragWorker() : data(0) {}
     136        DragWorker() : src(0) {}
    131137        virtual ~DragWorker() {}
    132138
     
    177183        {
    178184        public:
    179             virtual const char *format( const char *drf ) const = 0;
     185            virtual const QString &format(const char *drf) const = 0;
    180186            virtual bool provide(const char *drf, const QByteArray &allData,
    181187                                 ULONG itemIndex, QByteArray &itemData) = 0;
     
    246252
    247253        static bool canRender(DRAGITEM *item, const char *drf );
    248         static bool getSupportedRMFs(DRAGITEM *item, QPtrList<QStrList> &list);
     254        static bool getSupportedRMFs(DRAGITEM *item, QList<QByteArrayList> &list);
    249255
    250256    private:
     
    297303    static QByteArray querySourceNameFull(DRAGITEM *item);
    298304    static bool canTargetRenderAsOS2File(DRAGITEM *item, QByteArray *fullName = 0);
    299     static bool parseRMFs(HSTR rmfs, QList<QList<QByteArray> > &list);
     305    static bool parseRMFs(HSTR rmfs, QList<QByteArrayList> &list);
    300306    static bool parseRMF(HSTR rmf, QByteArray &mechanism, QByteArray &format);
    301307
  • trunk/src/gui/kernel/qmime_pm.cpp

    r439 r441  
    6363
    6464#ifdef QDND_DEBUG
     65#   include "qdebug.h"
    6566#   define DEBUG(a) qDebug a
    6667#else
     
    7273#if !defined(QT_NO_DRAGANDDROP)
    7374
    74 // @todo remove
    75 //#define DRT_URL "UniformResourceLocator"
    76 //
    77 //#define DRM_OS2FILE "DRM_OS2FILE"
    78 //#define DRM_SHAREDMEM "DRM_SHAREDMEM"
    79 //
    80 //#define DRF_UNKNOWN "DRF_UNKNOWN"
    81 //#define DRF_TEXT "DRF_TEXT"
    82 //#define DRF_POINTERDATA "DRF_POINTERDATA"
    83 //
    84 //#define MIME_TEXT_PLAIN "text/plain"
    85 //#define MIME_TEXT_PLAIN_CHARSET_SYSTEM "text/plain;charset=system"
    86 //#define MIME_TEXT_URI_LIST "text/uri-list"
     75// Undoc'd DC_PREPAREITEM, see
     76// http://lxr.mozilla.org/seamonkey/source/widget/src/os2/nsDragService.cpp
     77#if !defined (DC_PREPAREITEM)
     78#define DC_PREPAREITEM 0x40
     79#endif
    8780
    8881/*! \internal
     
    241234        ULONG index;
    242235        Provider *provider;
    243         QCString drm;
    244         QCString drf;
     236        QByteArray drm;
     237        QByteArray drf;
    245238        DRAGTRANSFER *xfer;
    246239        bool rendered;
     
    255248        DrfProvider() : prov(0) {}
    256249        DrfProvider(const char *d, Provider *p) : drf(d), prov(p) {}
    257         const QByteArray drf;
    258         Provider * const prov;
     250        QByteArray drf;
     251        Provider *prov;
    259252    };
    260253
     
    378371    // (however, it doesn't help when dropping objects to it -- WPS still
    379372    // chooses DRM_OS2FILE).
    380     formats = "("DRM_SHAREDMEM","DRM_OS2FILE")x(" + formats + "),"
    381               "<"DRM_SHAREDMEM","DRF_POINTERDATA">";
     373    formats = "(DRM_SHAREDMEM,DRM_OS2FILE)x(" + formats + "),"
     374              "<DRM_SHAREDMEM,DRF_POINTERDATA>";
    382375
    383376    DEBUG(() << "DefaultDragWorker: formats" << formats
     
    400393
    401394    DEBUG(() << "DefaultDragWorker: Preparing item" <<  itemIndex << "(id "
    402              << item->ulItemID << ") for <" << drm << "," << drf ">");
     395             << item->ulItemID << ") for <" << drm << "," << drf << ">");
    403396
    404397    Provider *p = d->providerFor(drf);
     
    469462                 << "(id " << xfer->pditem->ulItemID << ")");
    470463
    471         QCString drm, drf;
     464        QByteArray drm, drf;
    472465        if (!parseRMF(xfer->hstrSelectedRMF, drm, drf))
    473466            Q_ASSERT(/* parseRMF() = */ FALSE);
     
    525518
    526519        bool renderOk = false;
    527         QByteArray allData =
    528             source()->encodedData(req->provider->format(req->drf));
     520
     521        QByteArray allData = source()->data(req->provider->format(req->drf));
    529522        QByteArray itemData;
    530523
     
    534527        if (renderOk) {
    535528            enum DRM { OS2File, SharedMem } drmType;
    536             if (qstrcmp(req->drm, DRM_SHAREDMEM) == 0) drmType = SharedMem;
     529            if (qstrcmp(req->drm, "DRM_SHAREDMEM") == 0) drmType = SharedMem;
    537530            else drmType = OS2File;
    538531
    539532            if (drmType == OS2File) {
    540                 QCString renderToName = queryHSTR(req->xfer->hstrRenderToName);
     533                QByteArray renderToName = queryHSTR(req->xfer->hstrRenderToName);
    541534                Q_ASSERT(!renderToName.isEmpty());
    542535                renderOk = !renderToName.isEmpty();
     
    544537                    DEBUG(() << "DefaultDragWorker: Will write to" << renderToName);
    545538                    QFile file(QFile::decodeName(renderToName));
    546                     renderOk = file.open(IO_WriteOnly);
     539                    renderOk = file.open(QIODevice::WriteOnly);
    547540                    if (renderOk) {
    548                         Q_LONG written =
    549                             file.writeBlock(itemData.data(), itemData.size());
    550                         renderOk = written == (Q_LONG) itemData.size() &&
    551                                    file.status() == IO_Ok;
     541                        qint64 written = file.write(itemData, itemData.size());
     542                        renderOk = written == itemData.size();
    552543                        file.close();
    553544                        if (renderOk && req->xfer->pditem->hstrType) {
     
    626617            DEBUG(("DefaultDragWorker: Freed DRAGTRANSFER: "
    627618                   "req->xfer %p size %lu (0x%08lX) flags 0x%08lX",
    628                    req->xfer, size, size, flags);
     619                   req->xfer, size, size, flags));
    629620        }
    630621#endif
     
    686677            // first provider
    687678            d->itemCnt = itemCnt;
    688             d->providers.insert(Data::DrfProvider(drf, provider));
     679            d->providers.append(Data::DrfProvider(drf, provider));
    689680            return true;
    690681        }
     
    693684            // ensure there are no dups (several providers for the same drf)
    694685            if (!d->providerFor(drf))
    695                 d->providers.insert(Data::DrfProvider(drf, provider));
     686                d->providers.append(Data::DrfProvider(drf, provider));
    696687            return true;
    697688        }
     
    703694bool QPMMime::DefaultDragWorker::canRender(const char *drm)
    704695{
    705     return qstrcmp(drm, DRM_SHAREDMEM) == 0 ||
    706            qstrcmp(drm, DRM_OS2FILE) == 0;
     696    return qstrcmp(drm, "DRM_SHAREDMEM") == 0 ||
     697           qstrcmp(drm, "DRM_OS2FILE") == 0;
    707698}
    708699
     
    715706        MimeProvider() : prov(NULL) {}
    716707        MimeProvider(const QString &m, Provider *p) : mime(m), prov(p) {}
    717         const QString mime;
    718         Provider * const prov;
     708        QString mime;
     709        Provider *prov;
    719710    };
    720711
     
    736727    bool got_DM_RENDERCOMPLETE : 1;
    737728    USHORT flags_DM_RENDERCOMPLETE;
    738     int waiting_DM_RENDERCOMPLETE;
     729
     730    QEventLoop eventLoop;
    739731};
    740732
     
    744736    d->sending_DM_RENDER = d->got_DM_RENDERCOMPLETE = false;
    745737    d->flags_DM_RENDERCOMPLETE = 0;
    746     d->waiting_DM_RENDERCOMPLETE = 0;
    747738}
    748739
     
    754745void QPMMime::DefaultDropWorker::cleanup(bool isAccepted, bool isActAccepted)
    755746{
    756     if (d->waiting_DM_RENDERCOMPLETE != 0) {
     747    if (d->eventLoop.isRunning()) {
    757748#ifndef QT_NO_DEBUG
    758749        qWarning("The previous drag source didn't post DM_RENDERCOMPLETE!\n"
    759750                 "Contact the drag source developer.");
    760751#endif
    761         qApp->eventLoop()->exitLoop();
     752        d->eventLoop.exit(1);
    762753    }
    763754
     
    766757    d->sending_DM_RENDER = d->got_DM_RENDERCOMPLETE = false;
    767758    d->flags_DM_RENDERCOMPLETE = 0;
    768     d->waiting_DM_RENDERCOMPLETE = 0;
    769759}
    770760
     
    774764}
    775765
    776 bool QPMMime::DefaultDropWorker::provides(const char *format) const
    777 {
    778     return d->providerFor(format) != NULL;
    779 }
    780 
    781 int QPMMime::DefaultDropWorker::formatCount() const
    782 {
    783     return d->providers.count();
    784 }
    785 
    786 const char *QPMMime::DefaultDropWorker::format(int fn) const
    787 {
    788     if (fn >= 0 && (uint) fn < d->providers.count())
    789         return d->providers[ fn ].mime;
    790     return NULL;
    791 }
    792 
    793 static QCString composeTempFileName()
    794 {
    795     static char defTmpDir[ 3 ] = { 0 };
    796     const char *tmpDir = getenv("TEMP");
    797     if (!tmpDir) tmpDir = getenv("TMP");
    798     if (!tmpDir || !QFile::exists(QFile::decodeName(tmpDir))) {
    799         if (!defTmpDir[ 0 ]) {
    800             ULONG bootDrive = 0;
    801             DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE,
    802                             &bootDrive, sizeof (bootDrive));
    803             defTmpDir[ 0 ] = bootDrive;
    804             defTmpDir[ 1 ] = ':';
    805         }
    806         tmpDir = defTmpDir;
    807     }
     766bool QPMMime::DefaultDropWorker::hasFormat(const QString &mimeType) const
     767{
     768    return d->providerFor(mimeType) != NULL;
     769}
     770
     771// @todo
     772//int QPMMime::DefaultDropWorker::formatCount() const
     773//{
     774//    return d->providers.count();
     775//}
     776
     777QStringList QPMMime::DefaultDropWorker::formats() const
     778{
     779    QStringList mimes;
     780    foreach(const Data::MimeProvider &p, d->providers)
     781        mimes << p.mime;
     782    return mimes;
     783}
     784
     785static QByteArray composeTempFileName()
     786{
     787    QByteArray tmpDir =
     788        QFile::encodeName(QDir::toNativeSeparators(QDir::tempPath()));
    808789
    809790    static bool srandDone = false;
     
    817798    int attempts = Attempts;
    818799
    819     QCString tmpName;
     800    QString tmpName;
    820801    do {
    821         tmpName.sprintf("%s\\%08lX.tmp", tmpDir, num);
    822         if (!QFile::exists(QFile::decodeName(tmpName)))
     802        tmpName.sprintf("%s\\%08lX.tmp", tmpDir.constData(), num);
     803        if (!QFile::exists(tmpName))
    823804            break;
    824805        num = rand();
     
    827808    Q_ASSERT(attempts > 0);
    828809    if (attempts <= 0)
    829         tmpName.resize(0);
    830 
    831     return tmpName;
    832 }
    833 
    834 QByteArray QPMMime::DefaultDropWorker::encodedData(const char *format) const
    835 {
    836     DEBUG("DefaultDropWorker::encodedData(" << format << ")");
    837 
    838     QByteArray data;
     810        tmpName.clear();
     811
     812    return QFile::encodeName(tmpName);
     813}
     814
     815QVariant QPMMime::DefaultDropWorker::retrieveData(const QString &mimeType,
     816                                                  QVariant::Type type) const
     817{
     818    Q_UNUSED(type);
     819
     820    DEBUG(() << "DefaultDropWorker::retrieveData(" << mimeType << ")");
     821
     822    QVariant ret;
    839823
    840824    Q_ASSERT(info());
    841825    if (!info())
    842         return data;
     826        return ret;
    843827
    844828    ULONG itemCount = DrgQueryDragitemCount(info());
    845829    Q_ASSERT(itemCount);
    846830    if (!itemCount)
    847         return data;
    848 
    849     Provider *provider = d->providerFor(format);
     831        return ret;
     832
     833    Provider *provider = d->providerFor(mimeType);
    850834    if (!provider)
    851         return data;
    852 
    853     const char *drf = provider->drf(format);
     835        return ret;
     836
     837    const char *drf = provider->drf(mimeType);
    854838    Q_ASSERT(drf);
    855839    if (!drf)
    856         return data;
     840        return ret;
    857841
    858842    // Note: Allocating and freeing DRAGTRANSFER structures is a real mess. It's
     
    868852    // always allocate a new struct per every item. It seems to work.
    869853
    870     QCString renderToName = composeTempFileName();
     854    QByteArray renderToName = composeTempFileName();
    871855    HSTR hstrRenderToName = DrgAddStrHandle(renderToName);
    872856
    873857    HSTR rmfOS2File =
    874         DrgAddStrHandle(QCString().sprintf("<"DRM_OS2FILE",%s>", drf));
     858        DrgAddStrHandle(QString().sprintf("<DRM_OS2FILE,%s>", drf).toLocal8Bit());
    875859    HSTR rmfSharedMem =
    876         DrgAddStrHandle(QCString().sprintf("<"DRM_SHAREDMEM",%s>", drf));
     860        DrgAddStrHandle(QString().sprintf("<DRM_SHAREDMEM,%s>", drf).toLocal8Bit());
    877861
    878862    MRESULT mrc;
     
    880864
    881865    DRAGTRANSFER *xfer = NULL;
    882     QCString srcFileName;
     866    QByteArray srcFileName;
    883867
    884868    QByteArray allData, itemData;
     
    897881        // determine the mechanism to use (prefer DRM_SHAREDMEM)
    898882
    899         if (DrgVerifyRMF(item, DRM_SHAREDMEM, drf) &&
    900              DrgVerifyRMF(item, DRM_SHAREDMEM, DRF_POINTERDATA))
     883        if (DrgVerifyRMF(item, "DRM_SHAREDMEM", drf) &&
     884             DrgVerifyRMF(item, "DRM_SHAREDMEM", "DRF_POINTERDATA"))
    901885            drm = SharedMem;
    902         if (DrgVerifyRMF(item, DRM_OS2FILE, drf)) {
     886        if (DrgVerifyRMF(item, "DRM_OS2FILE", drf)) {
    903887            srcFileName = querySourceNameFull(item);
    904888            // If the source provides the full file name, we prefer DRM_OS2FILE
     
    950934
    951935            mrc = (MRESULT)TRUE;
    952             if ((item->fsControl & DC_PREPARE) |
    953                  (item->fsControl & DC_PREPAREITEM)) {
     936            if ((item->fsControl & DC_PREPARE) ||
     937                (item->fsControl & DC_PREPAREITEM)) {
    954938                DEBUG(("DefaultDropWorker: Sending DM_RENDERPREPARE to 0x%08lX...",
    955939                       info()->hwndSource));
     
    957941                                         MPFROMP (xfer), 0);
    958942                DEBUG(("DefaultDropWorker: Finisned sending DM_RENDERPREPARE\n"
    959                        " mrc %p xfer->fsReply 0x%08hX", mrc, xfer->fsReply);
     943                       " mrc %p xfer->fsReply 0x%08hX", mrc, xfer->fsReply));
    960944                renderOk = (BOOL) mrc;
    961945            }
     
    979963                } else {
    980964                    // synchronously wait for DM_RENDERCOMPLETE
    981                     d->waiting_DM_RENDERCOMPLETE = qApp->loopLevel() + 1;
    982965                    DEBUG(() << "DefaultDropWorker: Waiting for DM_RENDERCOMPLETE...");
    983                     int level = qApp->eventLoop()->enterLoop();
     966                    int result = d->eventLoop.exec();
    984967                    DEBUG(("DefaultDropWorker: Finished waiting for "
    985                            "DM_RENDERCOMPLETE (%d)\n"
     968                           "DM_RENDERCOMPLETE (result %d)\n"
    986969                           " got_DM_RENDERCOMPLETE %d usFS 0x%hX",
    987                            level, d->got_DM_RENDERCOMPLETE, d->flags_DM_RENDERCOMPLETE));
    988                     Q_UNUSED(level);
     970                           result, d->got_DM_RENDERCOMPLETE, d->flags_DM_RENDERCOMPLETE));
     971                    Q_UNUSED(result);
    989972                    // JFTR: at this point, cleanup() might have been called,
    990973                    // as a result of either program exit or getting another
     
    992975                    // DM_RENDERCOMPLETE from the source. Use data members with
    993976                    // care!
    994                     d->waiting_DM_RENDERCOMPLETE = 0;
    995977                    renderOk = d->got_DM_RENDERCOMPLETE &&
    996978                               (d->flags_DM_RENDERCOMPLETE & DMFL_RENDEROK);
     
    1000982            }
    1001983        } else {
    1002             DEBUG(() << "DefaultDropWorker: Source supports <" << DRM_OS2FILE
    1003                      << "," << drf << "> and provides a file" << srcFileName
     984            DEBUG(() << "DefaultDropWorker: Source supports <DRM_OS2FILE,"
     985                     << drf << "> and provides a file" << srcFileName
    1004986                     << "for item" << item << "(no need to render)");
    1005987            renderOk = true;
     
    1010992                DEBUG(() << "DefaultDragWorker: Will read from" << srcFileName);
    1011993                QFile file(QFile::decodeName(srcFileName));
    1012                 renderOk = file.open(IO_ReadOnly);
     994                renderOk = file.open(QIODevice::ReadOnly);
    1013995                if (renderOk) {
    1014996                    itemData = file.readAll();
    1015                     renderOk = file.status() == IO_Ok;
     997                    renderOk = file.error() == QFile::NoError;
    1016998                    file.close();
    1017999                }
     
    10301012                        DEBUG(("DefaultDropWorker: Got shared data %p size %lu "
    10311013                               "(0x%08lX) flags 0x%08lX", ptr, size, size, flags));
    1032                         Q_ASSERT(flags & (PAG_COMMIT | PAG_READ | PAG_BASE) ==
     1014                        Q_ASSERT((flags & (PAG_COMMIT | PAG_READ | PAG_BASE)) ==
    10331015                                 (PAG_COMMIT | PAG_READ | PAG_BASE));
    1034                         renderOk = flags & (PAG_COMMIT | PAG_READ | PAG_BASE) ==
     1016                        renderOk = (flags & (PAG_COMMIT | PAG_READ | PAG_BASE)) ==
    10351017                                   (PAG_COMMIT | PAG_READ | PAG_BASE);
    10361018#ifndef QT_NO_DEBUG
     
    10461028                        if (renderOk) {
    10471029                            itemData.resize(realSize);
    1048                             memcpy(itemData.data(), ptr + sizeof (ULONG), realSize);
     1030                            memcpy(itemData.data(), ptr + sizeof(ULONG), realSize);
    10491031                        }
    10501032                    }
     
    10581040
    10591041        if (renderOk)
    1060             renderOk = provider->provide(format, i, itemData, allData);
     1042            renderOk = provider->provide(mimeType, i, itemData, allData);
    10611043
    10621044        if (needToTalk) {
     
    10861068
    10871069    if (renderOk)
    1088         data = allData;
    1089 
    1090     return data;
     1070        ret = allData;
     1071
     1072    return ret;
    10911073}
    10921074
     
    11001082                return (MRESULT)FALSE;
    11011083
    1102             DEBUG("DefaultDropWorker: Got DM_RENDERCOMPLETE");
     1084            DEBUG(("DefaultDropWorker: Got DM_RENDERCOMPLETE"));
    11031085            d->got_DM_RENDERCOMPLETE = true;
    11041086            d->flags_DM_RENDERCOMPLETE = SHORT1FROMMP(mp2);
     
    11171099
    11181100            // stop synchronous waiting for DM_RENDERCOMPLETE
    1119             if (d->waiting_DM_RENDERCOMPLETE != 0)
    1120                 qApp->eventLoop()->exitLoop();
     1101            if (d->eventLoop.isRunning())
     1102                d->eventLoop.exit();
    11211103            return (MRESULT)FALSE;
    11221104        }
     
    11281110}
    11291111
    1130 bool QPMMime::DefaultDropWorker::addProvider(const char *format,
     1112bool QPMMime::DefaultDropWorker::addProvider(const QString &mimeType,
    11311113                                             Provider *provider)
    11321114{
    1133     Q_ASSERT(format && provider);
    1134     if (format && provider && !d->exclusive) {
     1115    Q_ASSERT(!mimeType.isEmpty() && provider);
     1116    if (!mimeType.isEmpty() && provider && !d->exclusive) {
    11351117        // ensure there are no dups (several providers for the same mime)
    1136         if (!d->providerFor(format))
    1137             d->providers.insert(Data::MimeProvider(format, provider));
     1118        if (!d->providerFor(mimeType))
     1119            d->providers.append(Data::MimeProvider(mimeType, provider));
    11381120        return true;
    11391121    }
     
    11411123}
    11421124
    1143 bool QPMMime::DefaultDropWorker::addExclusiveProvider(const char *format,
     1125bool QPMMime::DefaultDropWorker::addExclusiveProvider(const QString &mimeType,
    11441126                                                      Provider *provider)
    11451127{
    1146     Q_ASSERT(format && provider);
    1147     if (format && provider && !d->exclusive) {
     1128    Q_ASSERT(!mimeType.isEmpty() && provider);
     1129    if (!mimeType.isEmpty() && provider && !d->exclusive) {
    11481130        d->exclusive = true;
    11491131        d->providers.clear();
    1150         d->providers.insert(Data::MimeProvider(format, provider));
     1132        d->providers.append(Data::MimeProvider(mimeType, provider));
    11511133        return true;
    11521134    }
     
    11571139bool QPMMime::DefaultDropWorker::canRender(DRAGITEM *item, const char *drf)
    11581140{
    1159     return DrgVerifyRMF(item, DRM_OS2FILE, drf) ||
    1160            (DrgVerifyRMF(item, DRM_SHAREDMEM, drf) &&
    1161             DrgVerifyRMF(item, DRM_SHAREDMEM, DRF_POINTERDATA));
    1162 }
    1163 
     1141    return DrgVerifyRMF(item, "DRM_OS2FILE", drf) ||
     1142           (DrgVerifyRMF(item, "DRM_SHAREDMEM", drf) &&
     1143            DrgVerifyRMF(item, "DRM_SHAREDMEM", "DRF_POINTERDATA"));
     1144}
     1145
     1146/*! \internal
     1147
     1148    Parses the rendering mechanism/format specification of the given \a item
     1149    and stores only those mechanism branches in the given \a list that represent
     1150    mechanisms supported by this worker. Returns false if fails to parse the
     1151    RMF specification. Note that if no supported mechanisms are found, true is
     1152    returned but the \a list will simply contain zero items.
     1153
     1154    \note The method clears the given \a list variable before proceeding.
     1155
     1156    \sa canRender(), PMMime::parseRMFs()
     1157*/
    11641158// static
    1165 /*! \internal
    1166   Parses the rendering mechanism/format specification of the given \a item
    1167   and stores only those mechanism branches in the given \a list that represent
    1168   mechanisms supported by this worker. Returns false if fails to parse the
    1169   RMF specification. Note that if no supported mechanisms are found, true is
    1170   returned but the \a list will simply contain zero items.
    1171   \note The method clears the given \a list variable before proceeding and sets
    1172   auto-deletion to true.
    1173   \sa canRender(), PMMime::parseRMFs()
    1174 */
    11751159bool QPMMime::DefaultDropWorker::getSupportedRMFs(DRAGITEM *item,
    1176                                                   QPtrList<QStrList> &list)
     1160                                                  QList<QByteArrayList> &list)
    11771161{
    11781162    if (!parseRMFs(item->hstrRMF, list))
    11791163        return false;
    11801164
    1181     for (QStrList *mech = list.first(); mech;) {
    1182         const char *drm = mech->first();
    1183         if (qstrcmp(drm, DRM_OS2FILE) == 0) {
    1184             mech = list.next();
     1165    for (QList<QByteArrayList>::iterator rmf = list.begin(); rmf != list.end();) {
     1166        QByteArrayList::iterator mf = rmf->begin();
     1167        Q_ASSERT(mf != rmf->end());
     1168        const char *drm = *mf;
     1169        if (qstrcmp(drm, "DRM_OS2FILE") == 0) {
     1170            ++rmf;
    11851171            continue;
    11861172        }
    1187         if (qstrcmp(drm, DRM_SHAREDMEM) == 0) {
    1188             const char *drf = mech->next();
     1173        if (qstrcmp(drm, "DRM_SHAREDMEM") == 0) {
    11891174            // accept DRM_SHAREDMEM only if there is DRF_POINTERDATA
    1190             for(; drf; drf = mech->next()) {
    1191                 if (qstrcmp(drf, DRF_POINTERDATA) == 0)
     1175            for(; mf != rmf->end(); ++mf) {
     1176                const char *drf = *mf;
     1177                if (qstrcmp(drf, "DRF_POINTERDATA") == 0)
    11921178                    break;
    11931179            }
    1194             if (drf) {
    1195                 mech = list.next();
     1180            if (mf != rmf->end()) {
     1181                ++rmf;
    11961182                continue;
    11971183            }
    11981184        }
    11991185        // remove the unsupported mechanism branch from the list
    1200         bool wasLast = list.getLast() == mech;
    1201         list.removeRef(mech);
    1202         // after deleting the last item, the current one will be set to the new
    1203         // last item which was already analyzed earlier, so set to 0 to stop
    1204         mech = wasLast ? 0 : list.current();
     1186        rmf = list.erase(rmf);
    12051187    }
    12061188
     
    15181500}
    15191501
     1502#if !defined(QT_NO_DRAGANDDROP)
     1503
     1504/*!
     1505    Returns a string represented by \a hstr.
     1506*/
     1507// static
     1508QByteArray QPMMime::queryHSTR(HSTR hstr)
     1509{
     1510    QByteArray str;
     1511    ULONG len = DrgQueryStrNameLen(hstr);
     1512    if (len) {
     1513        str.resize(len);
     1514        DrgQueryStrName(hstr, str.size() + 1 /* \0 */, str.data());
     1515    }
     1516    return str;
     1517}
     1518
     1519/*!
     1520    Returns a string that is a concatenation of \c hstrContainerName and
     1521    \c hstrSourceName fileds of the given \a item structure.
     1522*/
     1523// static
     1524QByteArray QPMMime::querySourceNameFull(DRAGITEM *item)
     1525{
     1526    QByteArray fullName;
     1527    if (!item)
     1528        return fullName;
     1529
     1530    ULONG pathLen = DrgQueryStrNameLen(item->hstrContainerName);
     1531    ULONG nameLen = DrgQueryStrNameLen(item->hstrSourceName);
     1532    if (!pathLen || !nameLen)
     1533        return fullName;
     1534
     1535    fullName.resize(pathLen + nameLen);
     1536    DrgQueryStrName(item->hstrContainerName, pathLen + 1, fullName.data());
     1537    DrgQueryStrName(item->hstrSourceName, nameLen + 1, fullName.data() + pathLen);
     1538
     1539    return fullName;
     1540}
     1541
     1542/*! \internal
     1543
     1544    Checks that the given drag \a item supports the DRM_OS2FILE rendering
     1545    mechanism and can be rendered by a target w/o involving the source (i.e.,
     1546    DRM_OS2FILE is the first supported format and a valid file name with full
     1547    path is provided). If the function returns TRUE, \a fullName (if not NULL)
     1548    will be assigned the item's full source file name (composed from
     1549    \c hstrContainerName and \c hstrSourceName fields).
     1550 */
     1551// static
     1552bool QPMMime::canTargetRenderAsOS2File(DRAGITEM *item, QByteArray *fullName /*= 0*/)
     1553{
     1554    if ( !item )
     1555        return false;
     1556
     1557    if (item->fsControl & (DC_PREPARE | DC_PREPAREITEM))
     1558        return false;
     1559
     1560    {
     1561        // DrgVerifyNativeRMF doesn't work on my system (ECS 1.2.1 GA):
     1562        // it always returns FALSE regardless of arguments. Use simplified
     1563        // hstrRMF parsing to determine whether DRM_OS2FILE is the native
     1564        // mechanism or not (i.e. "^\s*[\(<]\s*DRM_OS2FILE\s*,.*").
     1565
     1566        QByteArray rmf = queryHSTR(item->hstrRMF);
     1567        bool ok = false;
     1568        int i = rmf.indexOf("DRM_OS2FILE");
     1569        if (i >= 1) {
     1570            for (int j = i - 1; j >= 0; --j) {
     1571                char ch = rmf[j];
     1572                if (ch == ' ')
     1573                    continue;
     1574                if (ch == '<' || ch == '(') {
     1575                    if (ok)
     1576                        return false;
     1577                    ok = true;
     1578                } else {
     1579                    return false;
     1580                }
     1581            }
     1582        }
     1583        if (ok) {
     1584            ok = false;
     1585            int drmLen = strlen("DRM_OS2FILE");
     1586            for (int j = i + drmLen; j < (int) rmf.size(); ++j) {
     1587                char ch = rmf[j];
     1588                if (ch == ' ')
     1589                    continue;
     1590                if (ch == ',') {
     1591                    ok = true;
     1592                    break;
     1593                }
     1594                return false;
     1595            }
     1596        }
     1597        if (!ok)
     1598            return false;
     1599    }
     1600
     1601    QByteArray srcFullName = querySourceNameFull(item);
     1602    if (srcFullName.isEmpty())
     1603        return false;
     1604
     1605    QByteArray srcFullName2(srcFullName.size(), '\0');
     1606    APIRET rc = DosQueryPathInfo(srcFullName, FIL_QUERYFULLNAME,
     1607                                 srcFullName2.data(), srcFullName2.size());
     1608    if (rc != 0)
     1609        return false;
     1610
     1611    QString s1 = QFile::decodeName(srcFullName);
     1612    QString s2 = QFile::decodeName(srcFullName2);
     1613
     1614    if (s1.compare(s2, Qt::CaseInsensitive) != 0)
     1615        return false;
     1616
     1617    if (fullName)
     1618        *fullName = srcFullName;
     1619    return true;
     1620}
     1621
     1622/*! \internal
     1623
     1624    Parses the given \a rmfs list (full rendering mechanism/format specification)
     1625    and builds a \a list of mechanism branches. Each mechanism branch is also a
     1626    list, where the first item is the mechahism name and all subsequent items are
     1627    formats supported by this mechanism. Returns false if fails to parse \a rmf.
     1628
     1629    \note The method clears the given \a list variable before proceeding.
     1630*/
     1631// static
     1632bool QPMMime::parseRMFs(HSTR rmfs, QList<QByteArrayList> &list)
     1633{
     1634    // The format of the RMF list is "elem {,elem,elem...}"
     1635    // where elem is "(mechanism{,mechanism...}) x (format{,format...})"
     1636    // or "<mechanism,format>".
     1637    // We use a simple FSM to parse it. In terms of FSM, the format is:
     1638    //
     1639    // STRT ( BCM m CMCH echanism CMCH , NCM m CMCH echanism CMCH ) ECM x
     1640    //     SCMF ( BCF f CFCH ormat CFCH , NCF f CFCH ormat CFCH ) ECF , STRT
     1641    // STRT < BP m PMCH echanism PMCH , SPMF f PFCH ormat PFCH > EP , STRT
     1642
     1643    QByteArray str = queryHSTR(rmfs);
     1644    uint len = str.length();
     1645
     1646    enum {
     1647        // states
     1648        STRT = 0, BCM, CMCH, NCM, ECM, SCMF, BCF, CFCH, NCF, ECF,
     1649        BP, PMCH, SPMF, PFCH, EP,
     1650        STATES_COUNT,
     1651        // pseudo states
     1652        Err, Skip,
     1653        // inputs
     1654        obr = 0, cbr, xx, lt, gt, cm, any, ws,
     1655        INPUTS_COUNT,
     1656    };
     1657
     1658    static const char Chars[] =  { '(', ')', 'x', 'X', '<', '>', ',', ' ', 0 };
     1659    static const char Inputs[] = { obr, cbr, xx,  xx,  lt,  gt,  cm,  ws };
     1660    static const uchar Fsm [STATES_COUNT] [INPUTS_COUNT] = {
     1661             /* 0 obr  1 cbr  2 xx   3 lt   4 gt   5 cm   6 any  7 ws */
     1662/* STRT 0  */ { BCM,   Err,   Err,   BP,    Err,   Err,   Err,   Skip },
     1663/* BCM  1  */ { Err,   Err,   Err,   Err,   Err,   Err,   CMCH,  Skip },
     1664/* CMCH 2  */ { Err,   ECM,   CMCH,  Err,   Err,   NCM,   CMCH,  CMCH },
     1665/* NCM  3  */ { Err,   Err,   Err,   Err,   Err,   Err,   CMCH,  Skip },
     1666/* ECM  4  */ { Err,   Err,   SCMF,  Err,   Err,   Err,   Err,   Skip },
     1667/* SCMF 5  */ { BCF,   Err,   Err,   Err,   Err,   Err,   Err,   Skip },
     1668/* BCF  6  */ { Err,   Err,   Err,   Err,   Err,   Err,   CFCH,  Skip },
     1669/* CFCH 7  */ { Err,   ECF,   CFCH,  Err,   Err,   NCF,   CFCH,  CFCH },
     1670/* NCF  8  */ { Err,   Err,   Err,   Err,   Err,   Err,   CFCH,  Skip },
     1671/* ECF  9  */ { Err,   Err,   Err,   Err,   Err,   STRT,  Err,   Skip },
     1672/* BP   10 */ { Err,   Err,   Err,   Err,   Err,   Err,   PMCH,  Skip },
     1673/* PMCH 11 */ { Err,   Err,   PMCH,  Err,   Err,   SPMF,  PMCH,  PMCH  },
     1674/* SPMF 12 */ { Err,   Err,   Err,   Err,   Err,   Err,   PFCH,  Skip },
     1675/* PFCH 13 */ { Err,   Err,   PFCH,  Err,   EP,    Err,   PFCH,  PFCH },
     1676/* EP   14 */ { Err,   Err,   Err,   Err,   Err,   STRT,  Err,   Skip }
     1677    };
     1678
     1679    list.clear();
     1680
     1681    QList<QByteArrayList*> refList;
     1682
     1683    QByteArray buf;
     1684    QList<QByteArrayList>::iterator rmf;
     1685
     1686    uint state = STRT;
     1687    uint start = 0, end = 0, space = 0;
     1688
     1689    for (uint i = 0; i < len && state != Err ; ++i) {
     1690        char ch = str[i];
     1691        char *p = strchr(Chars, ch);
     1692        uint input = p ? Inputs[p - Chars] : any;
     1693        uint newState = Fsm[state][input];
     1694        switch (newState) {
     1695            case Skip:
     1696                continue;
     1697            case CMCH:
     1698            case CFCH:
     1699            case PMCH:
     1700            case PFCH:
     1701                if (state != newState)
     1702                    start = end = i;
     1703                ++end;
     1704                // accumulate trailing space for truncation
     1705                if (input == ws) ++space;
     1706                else space = 0;
     1707                break;
     1708            case NCM:
     1709            case ECM:
     1710            case SPMF:
     1711                buf = QByteArray(str.data() + start, end - start - space);
     1712                // find the mechanism branch in the output list
     1713                for (rmf = list.begin(); rmf != list.end(); ++rmf) {
     1714                    if (rmf->first() == buf)
     1715                        break;
     1716                }
     1717                if (rmf == list.end()) {
     1718                    // append to the output list if not found
     1719                    QByteArrayList newRmf;
     1720                    newRmf.append(buf);
     1721                    rmf = list.insert(list.end(), newRmf);
     1722                }
     1723                // store a refecence in the helper list for making a cross product
     1724                refList.append(&*rmf);
     1725                start = end = 0;
     1726                break;
     1727            case NCF:
     1728            case ECF:
     1729            case EP:
     1730                buf = QByteArray(str.data() + start, end - start - space);
     1731                // make a cross product with all current mechanisms
     1732                foreach(QByteArrayList *rmfRef, refList)
     1733                    rmfRef->append(buf);
     1734                if (newState != NCF)
     1735                    refList.clear();
     1736                start = end = 0;
     1737                break;
     1738            default:
     1739                break;
     1740        }
     1741        state = newState;
     1742    }
     1743
     1744    return state == ECF || state == EP;
     1745}
     1746
     1747/*! \internal
     1748
     1749    Splits the given \a rmf (rendering mechanism/format pair) to a \a mechanism
     1750    and a \a format string. Returns FALSE if fails to parse \a rmf.
     1751 */
     1752// static
     1753bool QPMMime::parseRMF(HSTR rmf, QByteArray &mechanism, QByteArray &format)
     1754{
     1755    QList<QByteArrayList> list;
     1756    if (!parseRMFs(rmf, list))
     1757        return false;
     1758
     1759    if (list.count() != 1 || list.first().count() != 2)
     1760        return false;
     1761
     1762    QByteArrayList first = list.first();
     1763    mechanism = first.at(0);
     1764    format = first.at(1);
     1765
     1766    return true;
     1767}
     1768
     1769/*! \internal */
     1770// static
     1771QPMMime::DefaultDragWorker *QPMMime::defaultCoopDragWorker()
     1772{
     1773    static DefaultDragWorker defCoopDragWorker(false /* exclusive */);
     1774    return &defCoopDragWorker;
     1775}
     1776
     1777// static
     1778/*! \internal */
     1779QPMMime::DefaultDragWorker *QPMMime::defaultExclDragWorker()
     1780{
     1781    static DefaultDragWorker defExclDragWorker(false /* exclusive */);
     1782    return &defExclDragWorker;
     1783}
     1784
     1785/*! \internal */
     1786// static
     1787QPMMime::DefaultDropWorker *QPMMime::defaultDropWorker()
     1788{
     1789    static DefaultDropWorker defaultDropWorker;
     1790    return &defaultDropWorker;
     1791}
     1792
     1793#endif // !QT_NO_DRAGANDDROP
     1794
    15201795////////////////////////////////////////////////////////////////////////////////
    15211796
Note: See TracChangeset for help on using the changeset viewer.