Changeset 337 for trunk/src/gui/kernel


Ignore:
Timestamp:
Nov 22, 2009, 9:48:35 PM (16 years ago)
Author:
Dmitry A. Kuminov
Message:

gui/kernel: mime: Implemented the fallback mime <-> clipboard converter for mime types not explicitly supported by specialized QPMMime implementations (see #28).

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

Legend:

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

    r334 r337  
    135135                                       QVariant::Type preferredType) const = 0;
    136136
     137protected:
     138
    137139    static ULONG registerMimeType(const QString &mime);
    138140
    139141    static ULONG allocateMemory(size_t size);
    140142    static void freeMemory(ULONG addr);
     143
     144    static QString formatName(ULONG format);
    141145
    142146private:
  • trunk/src/gui/kernel/qmime_pm.cpp

    r335 r337  
    100100    to MIME formats.
    101101
    102     Qt has predefined support for the following PM Clipboard formats:
     102    Qt has predefined support for the following PM Clipboard formats (custom
     103    formats registered in the system atom table by name are given in double
     104    quotes):
    103105
    104106    \table
    105107    \header \o PM Format \o Equivalent MIME type
    106     \row \o \c CF_TEXT        \o \c text/plain
    107     \row \o \c CF_BITMAP      \o \c{image/xyz}, where \c xyz is
    108                                  a \l{QImageWriter::supportedImageFormats()}{Qt image format}
     108    \row \o \c CF_TEXT          \o \c text/plain (system codepage,
     109                                   zero-terminated string)
     110    \row \o \c "text/unicode"   \o \c text/plain (16-bit Unicode, Mozilla-compatible,
     111                                   zero-terminated string)
     112    \row \o \c CF_BITMAP        \o \c{image/xyz}, where \c xyz is
     113                                    a \l{QImageWriter::supportedImageFormats()}{Qt image format}
     114    \row \o \c "x-mime:<mime>"  \o data in the format corresponding to the given
     115                                   MIME type \c <mime>
    109116    \endtable
    110117
    111     An example use of this class would be to map the PM Metafile
    112     clipboard format (\c CF_METAFILE) to and from the MIME type
     118    Note that all "x-mime:<mime>" formats use the CFI_POINTER storage type. That
     119    is, the clipboard contains a pointer to the memory block containing the MIME
     120    data in the corresponding format. The first 4 bytes of this memory block
     121    always contain the length of the subsequent MIME data array, in bytes.
     122
     123    An example use of this class by the user application would be to map the
     124    PM Metafile clipboard format (\c CF_METAFILE) to and from the MIME type
    113125    \c{image/x-metafile}. This conversion might simply be adding or removing a
    114126    header, or even just passing on the data. See \l{Drag and Drop} for more
     
    167179    ULONG data = 0;
    168180
    169     // allocate giveable memory for the array + dword for its size
    170     APIRET arc = DosAllocSharedMem((PVOID *)&data, NULL, size + 4,
     181    // allocate giveable memory for the array
     182    APIRET arc = DosAllocSharedMem((PVOID *)&data, NULL, size,
    171183                                   PAG_WRITE  | PAG_COMMIT | OBJ_GIVEABLE);
    172184    if (arc != NO_ERROR) {
     
    177189    }
    178190
    179     /// @todo I think we don't need it any more
    180 #if 0
    181     // get the size rounded to the page boundary (4K)
    182     ULONG sz = ~0, flags = 0;
    183     arc = DosQueryMem((PVOID)(data + size - 1), &sz, &flags);
    184     if (arc != NO_ERROR) {
    185 #ifndef QT_NO_DEBUG
    186         qWarning("QPMMime::allocateMemory: DosQueryMem failed with %lu", arc);
    187 #endif
    188         DosFreeMem((PVOID)data);
    189         return 0;
    190     }
    191     sz += (size - 1);
    192     // store the exact size to the last dword of the last page
    193     *(((ULONG *)(data + sz)) - 1) = size;
    194 #endif
    195 
    196191    return data;
    197192}
     
    226221    Converts the \a mimeData to the specified \a format.
    227222
    228     If \a data is not NULL, a handle to the converted data should then be placed
     223    If \a data is not NULL, a handle to the converted data should be then placed
    229224    in a variable pointed to by \a data and with the necessary flags describing
    230225    the handle returned in the \a flags variable.
    231226
    232     The following flags describing the data type are recognized:
     227    The following flags describing the data storage type are recognized:
    233228
    234229    \table
     
    280275
    281276    QList<QPMMime*> mimes = theMimeList()->mimes();
    282     for (int i = mimes.size()-1; i >= 0; --i) {
    283         QList<MimeCFPair> fmts = mimes[i]->mimesForFormats(formats);
     277    foreach(QPMMime *mime, mimes) {
     278        QList<MimeCFPair> fmts = mime->mimesForFormats(formats);
    284279        int priority = 0;
    285280        foreach (MimeCFPair fmt, fmts) {
     
    291286                    // replace if priority is higher, ignore otherwise
    292287                    if (priority < match.priority) {
    293                         match.converter = mimes[i];
     288                        match.converter = mime;
    294289                        match.format = fmt.second;
    295290                        match.priority = priority;
     
    299294            }
    300295            if (it == matches.end()) {
    301                 matches += Match(mimes[i], fmt.first, fmt.second, priority);
     296                matches += Match(mime, fmt.first, fmt.second, priority);
    302297            }
    303298        }
     
    313308
    314309    QList<QPMMime*> mimes = theMimeList()->mimes();
    315     for (int i = mimes.size()-1; i >= 0; --i) {
    316         QList<ULONG> cfs = mimes[i]->formatsForMimeData(mimeData);
     310    foreach(QPMMime *mime, mimes) {
     311        QList<ULONG> cfs = mime->formatsForMimeData(mimeData);
    317312        int priority = 0;
    318313        foreach (ULONG cf, cfs) {
     
    324319                    // replace if priority is higher, ignore otherwise
    325320                    if (priority < match.priority) {
    326                         match.converter = mimes[i];
     321                        match.converter = mime;
    327322                        match.priority = priority;
    328323                    }
     
    331326            }
    332327            if (it == matches.end()) {
    333                 matches += Match(mimes[i], cf, priority);
     328                matches += Match(mime, cf, priority);
    334329            }
    335330        }
     
    337332
    338333    return matches;
     334}
     335
     336QString QPMMime::formatName(ULONG format)
     337{
     338    QString name;
     339    HATOMTBL tbl = WinQuerySystemAtomTable();
     340    if (tbl != NULLHANDLE) {
     341        ULONG len = WinQueryAtomLength(tbl, format);
     342        QByteArray atom(len, '\0');
     343        WinQueryAtomName(tbl, format, atom.data(), atom.size() + 1);
     344        name = QString::fromLocal8Bit(atom);
     345    }
     346    return name;
    339347}
    340348
     
    346354    QPMMimeText();
    347355
     356    // for converting from Qt
    348357    QList<ULONG> formatsForMimeData(const QMimeData *mimeData) const;
    349358    bool convertFromMimeData(const QMimeData *mimeData, ULONG format,
    350359                             ULONG &flags, ULONG *data) const;
    351360
     361    // for converting to Qt
    352362    QList<MimeCFPair> mimesForFormats(const QList<ULONG> &formats) const;
    353363    QVariant convertFromFormat(ULONG format, ULONG flags, ULONG data,
     
    519529////////////////////////////////////////////////////////////////////////////////
    520530
     531class QPMMimeAnyMime : public QPMMime
     532{
     533public:
     534    QPMMimeAnyMime();
     535
     536    // for converting from Qt
     537    QList<ULONG> formatsForMimeData(const QMimeData *mimeData) const;
     538    bool convertFromMimeData(const QMimeData *mimeData, ULONG format,
     539                             ULONG &flags, ULONG *data) const;
     540
     541    // for converting to Qt
     542    QList<MimeCFPair> mimesForFormats(const QList<ULONG> &formats) const;
     543    QVariant convertFromFormat(ULONG format, ULONG flags, ULONG data,
     544                               const QString &mimeType,
     545                               QVariant::Type preferredType) const;
     546
     547private:
     548    ULONG registerMimeType(const QString &mime) const;
     549    QString registerFormat(ULONG format) const;
     550
     551    mutable QMap<QString, ULONG> cfMap;
     552    mutable QMap<ULONG, QString> mimeMap;
     553
     554    static QStringList ianaTypes;
     555    static QString mimePrefix;
     556    static QString customPrefix;
     557};
     558
     559// static
     560QStringList QPMMimeAnyMime::ianaTypes;
     561QString QPMMimeAnyMime::mimePrefix;
     562QString QPMMimeAnyMime::customPrefix;
     563
     564QPMMimeAnyMime::QPMMimeAnyMime()
     565{
     566    //MIME Media-Types
     567    if (!ianaTypes.size()) {
     568        ianaTypes.append(QLatin1String("application/"));
     569        ianaTypes.append(QLatin1String("audio/"));
     570        ianaTypes.append(QLatin1String("example/"));
     571        ianaTypes.append(QLatin1String("image/"));
     572        ianaTypes.append(QLatin1String("message/"));
     573        ianaTypes.append(QLatin1String("model/"));
     574        ianaTypes.append(QLatin1String("multipart/"));
     575        ianaTypes.append(QLatin1String("text/"));
     576        ianaTypes.append(QLatin1String("video/"));
     577
     578        mimePrefix = QLatin1String("x-mime:");
     579        customPrefix = QLatin1String("application/x-qt-pm-mime;value=\"");
     580    }
     581}
     582
     583QList<ULONG> QPMMimeAnyMime::formatsForMimeData(const QMimeData *mimeData) const
     584{
     585    QList<ULONG> cfs;
     586
     587    QStringList mimes = QInternalMimeData::formatsHelper(mimeData);
     588    foreach (QString mime, mimes) {
     589        ULONG cf = cfMap.value(mime);
     590        if (!cf)
     591            cf = registerMimeType(mime);
     592        if (cf)
     593            cfs << cf;
     594    }
     595
     596    return cfs;
     597}
     598
     599bool QPMMimeAnyMime::convertFromMimeData(const QMimeData *mimeData, ULONG format,
     600                                         ULONG &flags, ULONG *data) const
     601{
     602    QString mime = mimeMap.value(format);
     603    if (mime.isNull())
     604        return false;
     605
     606    flags = CFI_POINTER;
     607
     608    if (data == NULL)
     609        return true; // delayed rendering, nothing to do
     610
     611    QByteArray r = QInternalMimeData::renderDataHelper(mime, mimeData);
     612    if (r.isNull())
     613        return false;
     614
     615    *data = QPMMime::allocateMemory(r.size() + sizeof(ULONG));
     616    if (!*data)
     617        return false;
     618
     619    *((ULONG *)(*data)) = r.size();
     620    memcpy((void *)(*data + sizeof(ULONG)), r.data(), r.size());
     621    return true;
     622}
     623
     624QList<QPMMime::MimeCFPair> QPMMimeAnyMime::mimesForFormats(const QList<ULONG> &formats) const
     625{
     626    QList<MimeCFPair> mimes;
     627
     628    foreach (ULONG format, formats) {
     629        QString mime = mimeMap.value(format);
     630        if (mime.isEmpty())
     631            mime = registerFormat(format);
     632        if (!mime.isEmpty())
     633            mimes << qMakePair(mime, format);
     634    }
     635
     636    return mimes;
     637}
     638
     639QVariant QPMMimeAnyMime::convertFromFormat(ULONG format, ULONG flags, ULONG data,
     640                                           const QString &mimeType,
     641                                           QVariant::Type preferredType) const
     642{
     643    Q_UNUSED(preferredType);
     644
     645    QVariant ret;
     646
     647    if (cfMap.value(mimeType) != format)
     648        return ret;
     649
     650    if (!(flags & CFI_POINTER) || !data)
     651        return ret;
     652
     653    // get the real block size (always rounded to the page boundary (4K))
     654    ULONG sz = ~0, fl = 0, arc;
     655    arc = DosQueryMem((PVOID)data, &sz, &fl);
     656    if (arc != NO_ERROR) {
     657#ifndef QT_NO_DEBUG
     658        qWarning("QPMMimeText::convertFromFormat: DosQueryMem failed with %lu", arc);
     659#endif
     660        return ret;
     661    }
     662    ULONG size = *((ULONG *)data);
     663    if (!size || size + sizeof(ULONG) > sz)
     664        return ret;
     665
     666    // it should be enough to return the data and let QMimeData do the rest.
     667    ret = QByteArray((const char *)(data + sizeof(ULONG)), size);
     668    return ret;
     669}
     670
     671ULONG QPMMimeAnyMime::registerMimeType(const QString &mime) const
     672{
     673    if (mime.isEmpty())
     674        return 0;
     675
     676    QString mimeToReg = mime;
     677
     678    bool ianaType = false;
     679    foreach(QString prefix, ianaTypes) {
     680        if (mime.startsWith(prefix)) {
     681            ianaType = true;
     682            break;
     683        }
     684    }
     685    if (!ianaType) {
     686        // prepend the non-standard type with the prefix that makes it comply
     687        // with the standard
     688        mimeToReg = customPrefix + mime + QChar('\"');
     689    }
     690
     691    mimeToReg = mimePrefix + mimeToReg;
     692    ULONG cf = QPMMime::registerMimeType(mimeToReg);
     693    if (cf) {
     694        cfMap[mime] = cf;
     695        mimeMap[cf] = mime;
     696    }
     697    return cf;
     698}
     699
     700QString QPMMimeAnyMime::registerFormat(ULONG format) const
     701{
     702    QString mime;
     703
     704    if (!format)
     705        return mime;
     706
     707    QString atomStr = formatName(format);
     708    if (atomStr.startsWith(mimePrefix)) {
     709        // the format represents the mime type we can recognize
     710        mime = atomStr.mid(mimePrefix.size());
     711        if (!mime.isEmpty()) {
     712            cfMap[mime] = format;
     713            mimeMap[format] = mime;
     714        }
     715    }
     716    return mime;
     717}
     718
     719////////////////////////////////////////////////////////////////////////////////
     720
    521721QPMMimeList::QPMMimeList()
    522722    : initialized(false)
     
    535735    if (!initialized) {
    536736        initialized = true;
     737        new QPMMimeAnyMime; // must be the first (used as a fallback)
    537738        new QPMMimeText;
    538739    }
     
    542743{
    543744    init();
    544     list.append(mime);
     745    list.prepend(mime);
    545746}
    546747
Note: See TracChangeset for help on using the changeset viewer.