| 1 | /****************************************************************************
|
|---|
| 2 | **
|
|---|
| 3 | ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
|---|
| 4 | ** Contact: Qt Software Information ([email protected])
|
|---|
| 5 | **
|
|---|
| 6 | ** Copyright (C) 2009 netlabs.org. OS/2 parts.
|
|---|
| 7 | **
|
|---|
| 8 | ** This file is part of the QtGui module of the Qt Toolkit.
|
|---|
| 9 | **
|
|---|
| 10 | ** $QT_BEGIN_LICENSE:LGPL$
|
|---|
| 11 | ** Commercial Usage
|
|---|
| 12 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
|---|
| 13 | ** accordance with the Qt Commercial License Agreement provided with the
|
|---|
| 14 | ** Software or, alternatively, in accordance with the terms contained in
|
|---|
| 15 | ** a written agreement between you and Nokia.
|
|---|
| 16 | **
|
|---|
| 17 | ** GNU Lesser General Public License Usage
|
|---|
| 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
|---|
| 19 | ** General Public License version 2.1 as published by the Free Software
|
|---|
| 20 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
|---|
| 21 | ** packaging of this file. Please review the following information to
|
|---|
| 22 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
|---|
| 23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|---|
| 24 | **
|
|---|
| 25 | ** In addition, as a special exception, Nokia gives you certain
|
|---|
| 26 | ** additional rights. These rights are described in the Nokia Qt LGPL
|
|---|
| 27 | ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
|
|---|
| 28 | ** package.
|
|---|
| 29 | **
|
|---|
| 30 | ** GNU General Public License Usage
|
|---|
| 31 | ** Alternatively, this file may be used under the terms of the GNU
|
|---|
| 32 | ** General Public License version 3.0 as published by the Free Software
|
|---|
| 33 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
|---|
| 34 | ** packaging of this file. Please review the following information to
|
|---|
| 35 | ** ensure the GNU General Public License version 3.0 requirements will be
|
|---|
| 36 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
|---|
| 37 | **
|
|---|
| 38 | ** If you are unsure which license is appropriate for your use, please
|
|---|
| 39 | ** contact the sales department at [email protected].
|
|---|
| 40 | ** $QT_END_LICENSE$
|
|---|
| 41 | **
|
|---|
| 42 | ****************************************************************************/
|
|---|
| 43 |
|
|---|
| 44 | #include "qmime.h"
|
|---|
| 45 |
|
|---|
| 46 | #include "qimagereader.h"
|
|---|
| 47 | #include "qimagewriter.h"
|
|---|
| 48 | #include "qdatastream.h"
|
|---|
| 49 | #include "qbuffer.h"
|
|---|
| 50 | #include "qt_os2.h"
|
|---|
| 51 | #include "qapplication_p.h"
|
|---|
| 52 | #include "qtextcodec.h"
|
|---|
| 53 | #include "qregexp.h"
|
|---|
| 54 | #include "qalgorithms.h"
|
|---|
| 55 | #include "qmap.h"
|
|---|
| 56 | #include "qdnd_p.h"
|
|---|
| 57 | #include "qurl.h"
|
|---|
| 58 | #include "qvariant.h"
|
|---|
| 59 | #include "qtextdocument.h"
|
|---|
| 60 | #include "qdir.h"
|
|---|
| 61 |
|
|---|
| 62 | #define QMIME_DEBUG
|
|---|
| 63 |
|
|---|
| 64 | QT_BEGIN_NAMESPACE
|
|---|
| 65 |
|
|---|
| 66 | class QPMMimeList
|
|---|
| 67 | {
|
|---|
| 68 | public:
|
|---|
| 69 | QPMMimeList();
|
|---|
| 70 | ~QPMMimeList();
|
|---|
| 71 | void addMime(QPMMime *mime);
|
|---|
| 72 | void removeMime(QPMMime *mime);
|
|---|
| 73 | QList<QPMMime*> mimes();
|
|---|
| 74 |
|
|---|
| 75 | private:
|
|---|
| 76 | void init();
|
|---|
| 77 | bool initialized;
|
|---|
| 78 | QList<QPMMime*> list;
|
|---|
| 79 | };
|
|---|
| 80 |
|
|---|
| 81 | Q_GLOBAL_STATIC(QPMMimeList, theMimeList);
|
|---|
| 82 |
|
|---|
| 83 |
|
|---|
| 84 | /*!
|
|---|
| 85 | \class QPMMime
|
|---|
| 86 | \brief The QMPMime class maps open-standard MIME to OS/2 PM Clipboard
|
|---|
| 87 | formats.
|
|---|
| 88 | \ingroup io
|
|---|
| 89 | \ingroup draganddrop
|
|---|
| 90 | \ingroup misc
|
|---|
| 91 |
|
|---|
| 92 | Qt's drag-and-drop and clipboard facilities use the MIME standard.
|
|---|
| 93 | On X11, this maps trivially to the Xdnd protocol, but on OS/2
|
|---|
| 94 | although some applications use MIME types to describe clipboard
|
|---|
| 95 | formats, others use arbitrary non-standardized naming conventions,
|
|---|
| 96 | or unnamed built-in formats of the Presentation Manager.
|
|---|
| 97 |
|
|---|
| 98 | By instantiating subclasses of QPMMime that provide conversions between OS/2
|
|---|
| 99 | PM Clipboard and MIME formats, you can convert proprietary clipboard formats
|
|---|
| 100 | to MIME formats.
|
|---|
| 101 |
|
|---|
| 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):
|
|---|
| 105 |
|
|---|
| 106 | \table
|
|---|
| 107 | \header \o PM Format \o Equivalent MIME type
|
|---|
| 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,
|
|---|
| 111 | zero-terminated string, Mozilla-compatible)
|
|---|
| 112 | \row \o \c "text/html" \o \c text/html (16-bit Unicode,
|
|---|
| 113 | zero-terminated string, Mozilla-compatible)
|
|---|
| 114 | \row \o \c CF_BITMAP \o \c{image/xyz}, where \c xyz is
|
|---|
| 115 | a \l{QImageWriter::supportedImageFormats()}{Qt image format}
|
|---|
| 116 | \row \o \c "x-mime:<mime>" \o data in the format corresponding to the given
|
|---|
| 117 | MIME type \c <mime>
|
|---|
| 118 | \endtable
|
|---|
| 119 |
|
|---|
| 120 | Note that all "x-mime:<mime>" formats use the CFI_POINTER storage type. That
|
|---|
| 121 | is, the clipboard contains a pointer to the memory block containing the MIME
|
|---|
| 122 | data in the corresponding format. The first 4 bytes of this memory block
|
|---|
| 123 | always contain the length of the subsequent MIME data array, in bytes.
|
|---|
| 124 |
|
|---|
| 125 | An example use of this class by the user application would be to map the
|
|---|
| 126 | PM Metafile clipboard format (\c CF_METAFILE) to and from the MIME type
|
|---|
| 127 | \c{image/x-metafile}. This conversion might simply be adding or removing a
|
|---|
| 128 | header, or even just passing on the data. See \l{Drag and Drop} for more
|
|---|
| 129 | information on choosing and definition MIME types.
|
|---|
| 130 | */
|
|---|
| 131 |
|
|---|
| 132 | /*!
|
|---|
| 133 | Constructs a new conversion object, adding it to the globally accessed
|
|---|
| 134 | list of available converters.
|
|---|
| 135 | */
|
|---|
| 136 | QPMMime::QPMMime()
|
|---|
| 137 | {
|
|---|
| 138 | theMimeList()->addMime(this);
|
|---|
| 139 | }
|
|---|
| 140 |
|
|---|
| 141 | /*!
|
|---|
| 142 | Destroys a conversion object, removing it from the global
|
|---|
| 143 | list of available converters.
|
|---|
| 144 | */
|
|---|
| 145 | QPMMime::~QPMMime()
|
|---|
| 146 | {
|
|---|
| 147 | theMimeList()->removeMime(this);
|
|---|
| 148 | }
|
|---|
| 149 |
|
|---|
| 150 | /*!
|
|---|
| 151 | Registers the MIME type \a mime, and returns an ID number
|
|---|
| 152 | identifying the format on OS/2. Intended to be used by QPMMime
|
|---|
| 153 | implementations for registering custom clipboard formats they use.
|
|---|
| 154 | */
|
|---|
| 155 | // static
|
|---|
| 156 | ULONG QPMMime::registerMimeType(const QString &mime)
|
|---|
| 157 | {
|
|---|
| 158 | ULONG cf = WinAddAtom(WinQuerySystemAtomTable(), mime.toLocal8Bit());
|
|---|
| 159 | if (!cf) {
|
|---|
| 160 | #ifndef QT_NO_DEBUG
|
|---|
| 161 | qWarning("QPMMime: WinAddAtom failed with %lX",
|
|---|
| 162 | WinGetLastError(NULLHANDLE));
|
|---|
| 163 | #endif
|
|---|
| 164 | return 0;
|
|---|
| 165 | }
|
|---|
| 166 |
|
|---|
| 167 | return cf;
|
|---|
| 168 | }
|
|---|
| 169 |
|
|---|
| 170 | /*!
|
|---|
| 171 | Unregisters the MIME type identified by \a id which was previously
|
|---|
| 172 | registered with registerMimeType().
|
|---|
| 173 | */
|
|---|
| 174 | // static
|
|---|
| 175 | void QPMMime::unregisterMimeType(ULONG mimeId)
|
|---|
| 176 | {
|
|---|
| 177 | WinDeleteAtom(WinQuerySystemAtomTable(), mimeId);
|
|---|
| 178 | }
|
|---|
| 179 |
|
|---|
| 180 | /*!
|
|---|
| 181 | Allocates a block of shared memory of the given size and returns the address
|
|---|
| 182 | of this block. This memory block may be then filled with data and returned
|
|---|
| 183 | by convertFromMimeData() as the value of the CFI_POINTER type.
|
|---|
| 184 | */
|
|---|
| 185 | // static
|
|---|
| 186 | ULONG QPMMime::allocateMemory(size_t size)
|
|---|
| 187 | {
|
|---|
| 188 | if (size == 0)
|
|---|
| 189 | return 0;
|
|---|
| 190 |
|
|---|
| 191 | ULONG data = 0;
|
|---|
| 192 |
|
|---|
| 193 | // allocate giveable memory for the array
|
|---|
| 194 | APIRET arc = DosAllocSharedMem((PVOID *)&data, NULL, size,
|
|---|
| 195 | PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE);
|
|---|
| 196 | if (arc != NO_ERROR) {
|
|---|
| 197 | #ifndef QT_NO_DEBUG
|
|---|
| 198 | qWarning("QPMMime::allocateMemory: DosAllocSharedMem failed with %lu", arc);
|
|---|
| 199 | #endif
|
|---|
| 200 | return 0;
|
|---|
| 201 | }
|
|---|
| 202 |
|
|---|
| 203 | return data;
|
|---|
| 204 | }
|
|---|
| 205 |
|
|---|
| 206 | /*!
|
|---|
| 207 | Frees memory allocated by allocateMemory(). Normally, not used because the
|
|---|
| 208 | CFI_POINTER memory blocks are owned by the system after
|
|---|
| 209 | convertFromMimeData() returns.
|
|---|
| 210 | */
|
|---|
| 211 | // static
|
|---|
| 212 | void QPMMime::freeMemory(ULONG addr)
|
|---|
| 213 | {
|
|---|
| 214 | DosFreeMem((PVOID)addr);
|
|---|
| 215 | }
|
|---|
| 216 |
|
|---|
| 217 | /*!
|
|---|
| 218 | \fn QList<MimeCFPair> QPMMime::formatsForMimeData(const QMimeData *mimeData) const
|
|---|
| 219 |
|
|---|
| 220 | Returns a list of ULONG values representing the different OS/2 PM
|
|---|
| 221 | clipboard formats that can be provided for the \a mimeData, in order of
|
|---|
| 222 | precedence (the most suitable format goes first), or an empty list if
|
|---|
| 223 | neither of the mime types provided by \a mimeData is supported by this
|
|---|
| 224 | converter. Note that each item in the returned list is actually a pair
|
|---|
| 225 | consisting of the mime type name and the corresponding format identifier.
|
|---|
| 226 |
|
|---|
| 227 | All subclasses must reimplement this pure virtual function.
|
|---|
| 228 | */
|
|---|
| 229 |
|
|---|
| 230 | /*!
|
|---|
| 231 | \fn bool QPMMime::convertFromMimeData(const QMimeData *mimeData, ULONG format,
|
|---|
| 232 | ULONG &flags, ULONG *data) const
|
|---|
| 233 |
|
|---|
| 234 | Converts the \a mimeData to the specified \a format.
|
|---|
| 235 |
|
|---|
| 236 | If \a data is not NULL, a handle to the converted data should be then placed
|
|---|
| 237 | in a variable pointed to by \a data and with the necessary flags describing
|
|---|
| 238 | the handle returned in the \a flags variable.
|
|---|
| 239 |
|
|---|
| 240 | The following flags describing the data storage type are recognized:
|
|---|
| 241 |
|
|---|
| 242 | \table
|
|---|
| 243 | \row \o \c CFI_POINTER \o \a data is a pointer to a block of memory
|
|---|
| 244 | allocated with QPMMime::allocateMemory()
|
|---|
| 245 | \row \o \c CFI_HANDLE \o \a data is a handle to the appropriate
|
|---|
| 246 | PM resource
|
|---|
| 247 | \endtable
|
|---|
| 248 |
|
|---|
| 249 | If \a data is NULL then a delayed conversion is requested by the caller.
|
|---|
| 250 | The implementation should return the appropriate flags in the \a flags
|
|---|
| 251 | variable and may perform the real data conversion later when this method is
|
|---|
| 252 | called again with \a data being non-NULL.
|
|---|
| 253 |
|
|---|
| 254 | Return true if the conversion was successful.
|
|---|
| 255 |
|
|---|
| 256 | All subclasses must reimplement this pure virtual function.
|
|---|
| 257 | */
|
|---|
| 258 |
|
|---|
| 259 | /*!
|
|---|
| 260 | \fn QList<MimeCFPair> QPMMime::mimesForFormats(const QList<ULONG> &formats) const
|
|---|
| 261 |
|
|---|
| 262 | Returns a list of mime types that will be created form the specified \a list
|
|---|
| 263 | of \a formats, in order of precedence (the most suitable mime type comes
|
|---|
| 264 | first), or an empty list if neither of the \a formats is supported by this
|
|---|
| 265 | converter. Note that each item in the returned list is actually a pair
|
|---|
| 266 | consisting of the mime type name and the corresponding format identifier.
|
|---|
| 267 |
|
|---|
| 268 | All subclasses must reimplement this pure virtual function.
|
|---|
| 269 | */
|
|---|
| 270 |
|
|---|
| 271 | /*!
|
|---|
| 272 | \fn QVariant QPMMime::convertFromFormat(ULONG format, ULONG flags, ULONG data,
|
|---|
| 273 | const QString &mimeType,
|
|---|
| 274 | QVariant::Type preferredType) const
|
|---|
| 275 |
|
|---|
| 276 | Returns a QVariant containing the converted from the \a data in the
|
|---|
| 277 | specified \a format with the given \a flags to the requested \a mimeType. If
|
|---|
| 278 | possible the QVariant should be of the \a preferredType to avoid needless
|
|---|
| 279 | conversions.
|
|---|
| 280 |
|
|---|
| 281 | All subclasses must reimplement this pure virtual function.
|
|---|
| 282 | */
|
|---|
| 283 |
|
|---|
| 284 | // static
|
|---|
| 285 | QList<QPMMime::Match> QPMMime::allConvertersFromFormats(const QList<ULONG> &formats)
|
|---|
| 286 | {
|
|---|
| 287 | QList<Match> matches;
|
|---|
| 288 |
|
|---|
| 289 | QList<QPMMime*> mimes = theMimeList()->mimes();
|
|---|
| 290 | foreach(QPMMime *mime, mimes) {
|
|---|
| 291 | QList<MimeCFPair> fmts = mime->mimesForFormats(formats);
|
|---|
| 292 | int priority = 0;
|
|---|
| 293 | foreach (MimeCFPair fmt, fmts) {
|
|---|
| 294 | ++priority;
|
|---|
| 295 | QList<Match>::iterator it = matches.begin();
|
|---|
| 296 | for (; it != matches.end(); ++it) {
|
|---|
| 297 | Match &match = *it;
|
|---|
| 298 | if (match.mime == fmt.mime) {
|
|---|
| 299 | // replace if priority is higher, ignore otherwise
|
|---|
| 300 | if (priority < match.priority) {
|
|---|
| 301 | match.converter = mime;
|
|---|
| 302 | match.format = fmt.format;
|
|---|
| 303 | match.priority = priority;
|
|---|
| 304 | }
|
|---|
| 305 | break;
|
|---|
| 306 | }
|
|---|
| 307 | }
|
|---|
| 308 | if (it == matches.end()) {
|
|---|
| 309 | matches += Match(mime, fmt.mime, fmt.format, priority);
|
|---|
| 310 | }
|
|---|
| 311 | }
|
|---|
| 312 | }
|
|---|
| 313 |
|
|---|
| 314 | return matches;
|
|---|
| 315 | }
|
|---|
| 316 |
|
|---|
| 317 | // static
|
|---|
| 318 | QList<QPMMime::Match> QPMMime::allConvertersFromMimeData(const QMimeData *mimeData)
|
|---|
| 319 | {
|
|---|
| 320 | QList<Match> matches;
|
|---|
| 321 |
|
|---|
| 322 | QList<QPMMime*> mimes = theMimeList()->mimes();
|
|---|
| 323 | foreach(QPMMime *mime, mimes) {
|
|---|
| 324 | QList<MimeCFPair> fmts = mime->formatsForMimeData(mimeData);
|
|---|
| 325 | int priority = 0;
|
|---|
| 326 | foreach (MimeCFPair fmt, fmts) {
|
|---|
| 327 | ++priority;
|
|---|
| 328 | QList<Match>::iterator it = matches.begin();
|
|---|
| 329 | for (; it != matches.end(); ++it) {
|
|---|
| 330 | Match &match = *it;
|
|---|
| 331 | if (mime == mimes.last()) { // QPMMimeAnyMime?
|
|---|
| 332 | if (match.mime == fmt.mime){
|
|---|
| 333 | // we assume that specialized converters (that come
|
|---|
| 334 | // first) provide a more precise conversion than
|
|---|
| 335 | // QPMMimeAnyMime and don't let it get into the list in
|
|---|
| 336 | // order to avoid unnecessary duplicate representations
|
|---|
| 337 | break;
|
|---|
| 338 | }
|
|---|
| 339 | }
|
|---|
| 340 | if (match.format == fmt.format) {
|
|---|
| 341 | // replace if priority is higher, ignore otherwise
|
|---|
| 342 | if (priority < match.priority) {
|
|---|
| 343 | match.converter = mime;
|
|---|
| 344 | match.mime = fmt.mime;
|
|---|
| 345 | match.priority = priority;
|
|---|
| 346 | }
|
|---|
| 347 | break;
|
|---|
| 348 | }
|
|---|
| 349 | }
|
|---|
| 350 | if (it == matches.end()) {
|
|---|
| 351 | matches += Match(mime, fmt.mime, fmt.format, priority);
|
|---|
| 352 | }
|
|---|
| 353 | }
|
|---|
| 354 | }
|
|---|
| 355 |
|
|---|
| 356 | return matches;
|
|---|
| 357 | }
|
|---|
| 358 |
|
|---|
| 359 | QString QPMMime::formatName(ULONG format)
|
|---|
| 360 | {
|
|---|
| 361 | QString name;
|
|---|
| 362 | HATOMTBL tbl = WinQuerySystemAtomTable();
|
|---|
| 363 | if (tbl != NULLHANDLE) {
|
|---|
| 364 | ULONG len = WinQueryAtomLength(tbl, format);
|
|---|
| 365 | QByteArray atom(len, '\0');
|
|---|
| 366 | WinQueryAtomName(tbl, format, atom.data(), atom.size() + 1);
|
|---|
| 367 | name = QString::fromLocal8Bit(atom);
|
|---|
| 368 | }
|
|---|
| 369 | return name;
|
|---|
| 370 | }
|
|---|
| 371 |
|
|---|
| 372 | ////////////////////////////////////////////////////////////////////////////////
|
|---|
| 373 |
|
|---|
| 374 | class QPMMimeText : public QPMMime
|
|---|
| 375 | {
|
|---|
| 376 | public:
|
|---|
| 377 | QPMMimeText();
|
|---|
| 378 | ~QPMMimeText();
|
|---|
| 379 |
|
|---|
| 380 | // for converting from Qt
|
|---|
| 381 | QList<MimeCFPair> formatsForMimeData(const QMimeData *mimeData) const;
|
|---|
| 382 | bool convertFromMimeData(const QMimeData *mimeData, ULONG format,
|
|---|
| 383 | ULONG &flags, ULONG *data) const;
|
|---|
| 384 |
|
|---|
| 385 | // for converting to Qt
|
|---|
| 386 | QList<MimeCFPair> mimesForFormats(const QList<ULONG> &formats) const;
|
|---|
| 387 | QVariant convertFromFormat(ULONG format, ULONG flags, ULONG data,
|
|---|
| 388 | const QString &mimeType,
|
|---|
| 389 | QVariant::Type preferredType) const;
|
|---|
| 390 |
|
|---|
| 391 | const ULONG CF_TextUnicode;
|
|---|
| 392 | const ULONG CF_TextHtml;
|
|---|
| 393 | };
|
|---|
| 394 |
|
|---|
| 395 | QPMMimeText::QPMMimeText()
|
|---|
| 396 | // "text/unicode" is what Mozilla uses to for unicode
|
|---|
| 397 | : CF_TextUnicode (registerMimeType(QLatin1String("text/unicode")))
|
|---|
| 398 | // "text/html" is what Mozilla uses to for HTML
|
|---|
| 399 | , CF_TextHtml (registerMimeType(QLatin1String("text/html")))
|
|---|
| 400 | {
|
|---|
| 401 | }
|
|---|
| 402 |
|
|---|
| 403 | QPMMimeText::~QPMMimeText()
|
|---|
| 404 | {
|
|---|
| 405 | unregisterMimeType(CF_TextHtml);
|
|---|
| 406 | unregisterMimeType(CF_TextUnicode);
|
|---|
| 407 | }
|
|---|
| 408 |
|
|---|
| 409 | QList<QPMMime::MimeCFPair> QPMMimeText::formatsForMimeData(const QMimeData *mimeData) const
|
|---|
| 410 | {
|
|---|
| 411 | QList<MimeCFPair> fmts;
|
|---|
| 412 | // prefer HTML as it's reacher
|
|---|
| 413 | if (mimeData->hasHtml())
|
|---|
| 414 | fmts << MimeCFPair(QLatin1String("text/html"), CF_TextHtml);
|
|---|
| 415 | // prefer unicode over local8Bit
|
|---|
| 416 | if (mimeData->hasText())
|
|---|
| 417 | fmts << MimeCFPair(QLatin1String("text/plain"), CF_TextUnicode)
|
|---|
| 418 | << MimeCFPair(QLatin1String("text/plain"), CF_TEXT);
|
|---|
| 419 | return fmts;
|
|---|
| 420 | }
|
|---|
| 421 |
|
|---|
| 422 | // text/plain is defined as using CRLF, but so many programs don't,
|
|---|
| 423 | // and programmers just look for '\n' in strings.
|
|---|
| 424 | // OS/2 really needs CRLF, so we ensure it here.
|
|---|
| 425 | bool QPMMimeText::convertFromMimeData(const QMimeData *mimeData, ULONG format,
|
|---|
| 426 | ULONG &flags, ULONG *data) const
|
|---|
| 427 | {
|
|---|
| 428 | if (!mimeData->hasText() ||
|
|---|
| 429 | (format != CF_TEXT && format != CF_TextUnicode && format != CF_TextHtml))
|
|---|
| 430 | return false;
|
|---|
| 431 |
|
|---|
| 432 | flags = CFI_POINTER;
|
|---|
| 433 |
|
|---|
| 434 | if (data == NULL)
|
|---|
| 435 | return true; // delayed rendering, nothing to do
|
|---|
| 436 |
|
|---|
| 437 | QByteArray r;
|
|---|
| 438 |
|
|---|
| 439 | if (format == CF_TEXT) {
|
|---|
| 440 | QByteArray str = mimeData->text().toLocal8Bit();
|
|---|
| 441 | // Anticipate required space for CRLFs at 1/40
|
|---|
| 442 | int maxsize = str.size()+str.size()/40+1;
|
|---|
| 443 | r.fill('\0', maxsize);
|
|---|
| 444 | char *o = r.data();
|
|---|
| 445 | const char *d = str.data();
|
|---|
| 446 | const int s = str.size();
|
|---|
| 447 | bool cr = false;
|
|---|
| 448 | int j = 0;
|
|---|
| 449 | for (int i = 0; i < s; i++) {
|
|---|
| 450 | char c = d[i];
|
|---|
| 451 | if (c == '\r')
|
|---|
| 452 | cr = true;
|
|---|
| 453 | else {
|
|---|
| 454 | if (c == '\n') {
|
|---|
| 455 | if (!cr)
|
|---|
| 456 | o[j++] = '\r';
|
|---|
| 457 | }
|
|---|
| 458 | cr = false;
|
|---|
| 459 | }
|
|---|
| 460 | o[j++] = c;
|
|---|
| 461 | if (j+1 >= maxsize) {
|
|---|
| 462 | maxsize += maxsize/4;
|
|---|
| 463 | r.resize(maxsize);
|
|---|
| 464 | o = r.data();
|
|---|
| 465 | }
|
|---|
| 466 | }
|
|---|
| 467 | if (j < r.size())
|
|---|
| 468 | o[j] = '\0';
|
|---|
| 469 | } else if (format == CF_TextUnicode || CF_TextHtml) {
|
|---|
| 470 | QString str = format == CF_TextUnicode ?
|
|---|
| 471 | mimeData->text() : mimeData->html();
|
|---|
| 472 | const QChar *u = str.unicode();
|
|---|
| 473 | QString res;
|
|---|
| 474 | const int s = str.length();
|
|---|
| 475 | int maxsize = s + s/40 + 3;
|
|---|
| 476 | res.resize(maxsize);
|
|---|
| 477 | int ri = 0;
|
|---|
| 478 | bool cr = false;
|
|---|
| 479 | for (int i = 0; i < s; ++i) {
|
|---|
| 480 | if (*u == QLatin1Char('\r'))
|
|---|
| 481 | cr = true;
|
|---|
| 482 | else {
|
|---|
| 483 | if (*u == QLatin1Char('\n') && !cr)
|
|---|
| 484 | res[ri++] = QLatin1Char('\r');
|
|---|
| 485 | cr = false;
|
|---|
| 486 | }
|
|---|
| 487 | res[ri++] = *u;
|
|---|
| 488 | if (ri+3 >= maxsize) {
|
|---|
| 489 | maxsize += maxsize/4;
|
|---|
| 490 | res.resize(maxsize);
|
|---|
| 491 | }
|
|---|
| 492 | ++u;
|
|---|
| 493 | }
|
|---|
| 494 | res.truncate(ri);
|
|---|
| 495 | const int byteLength = res.length()*2;
|
|---|
| 496 | r.fill('\0', byteLength + 2);
|
|---|
| 497 | memcpy(r.data(), res.unicode(), byteLength);
|
|---|
| 498 | r[byteLength] = 0;
|
|---|
| 499 | r[byteLength+1] = 0;
|
|---|
| 500 | } else{
|
|---|
| 501 | return false;
|
|---|
| 502 | }
|
|---|
| 503 |
|
|---|
| 504 | *data = QPMMime::allocateMemory(r.size());
|
|---|
| 505 | if (!*data)
|
|---|
| 506 | return false;
|
|---|
| 507 |
|
|---|
| 508 | memcpy((void *)*data, r.data(), r.size());
|
|---|
| 509 | return true;
|
|---|
| 510 | }
|
|---|
| 511 |
|
|---|
| 512 | QList<QPMMime::MimeCFPair> QPMMimeText::mimesForFormats(const QList<ULONG> &formats) const
|
|---|
| 513 | {
|
|---|
| 514 | QList<MimeCFPair> mimes;
|
|---|
| 515 | // prefer HTML as it's reacher
|
|---|
| 516 | if (formats.contains(CF_TextHtml))
|
|---|
| 517 | mimes << MimeCFPair(QLatin1String("text/html"), CF_TextHtml);
|
|---|
| 518 | // prefer unicode over local8Bit
|
|---|
| 519 | if (formats.contains(CF_TextUnicode))
|
|---|
| 520 | mimes << MimeCFPair(QLatin1String("text/plain"), CF_TextUnicode);
|
|---|
| 521 | if (formats.contains(CF_TEXT))
|
|---|
| 522 | mimes << MimeCFPair(QLatin1String("text/plain"), CF_TEXT);
|
|---|
| 523 | return mimes;
|
|---|
| 524 | }
|
|---|
| 525 |
|
|---|
| 526 | QVariant QPMMimeText::convertFromFormat(ULONG format, ULONG flags, ULONG data,
|
|---|
| 527 | const QString &mimeType,
|
|---|
| 528 | QVariant::Type preferredType) const
|
|---|
| 529 | {
|
|---|
| 530 | QVariant ret;
|
|---|
| 531 |
|
|---|
| 532 | if (!mimeType.startsWith(QLatin1String("text/plain")) &&
|
|---|
| 533 | !mimeType.startsWith(QLatin1String("text/html")))
|
|---|
| 534 | return ret;
|
|---|
| 535 | if ((format != CF_TEXT && format != CF_TextUnicode && format != CF_TextHtml) ||
|
|---|
| 536 | !(flags & CFI_POINTER) || !data)
|
|---|
| 537 | return ret;
|
|---|
| 538 |
|
|---|
| 539 | QString str;
|
|---|
| 540 |
|
|---|
| 541 | if (format == CF_TEXT) {
|
|---|
| 542 | const char *d = (const char *)data;
|
|---|
| 543 | QByteArray r("");
|
|---|
| 544 | if (*d) {
|
|---|
| 545 | const int s = qstrlen(d);
|
|---|
| 546 | r.fill('\0', s);
|
|---|
| 547 | char *o = r.data();
|
|---|
| 548 | int j = 0;
|
|---|
| 549 | for (int i = 0; i < s; i++) {
|
|---|
| 550 | char c = d[i];
|
|---|
| 551 | if (c != '\r')
|
|---|
| 552 | o[j++] = c;
|
|---|
| 553 | }
|
|---|
| 554 | }
|
|---|
| 555 | str = QString::fromLocal8Bit(r);
|
|---|
| 556 | } else if (format == CF_TextUnicode || CF_TextHtml) {
|
|---|
| 557 | str = QString::fromUtf16((const unsigned short *)data);
|
|---|
| 558 | str.replace(QLatin1String("\r\n"), QLatin1String("\n"));
|
|---|
| 559 | }
|
|---|
| 560 |
|
|---|
| 561 | if (preferredType == QVariant::String)
|
|---|
| 562 | ret = str;
|
|---|
| 563 | else
|
|---|
| 564 | ret = str.toUtf8();
|
|---|
| 565 |
|
|---|
| 566 | return ret;
|
|---|
| 567 | }
|
|---|
| 568 |
|
|---|
| 569 | ////////////////////////////////////////////////////////////////////////////////
|
|---|
| 570 |
|
|---|
| 571 | class QPMMimeImage : public QPMMime
|
|---|
| 572 | {
|
|---|
| 573 | public:
|
|---|
| 574 | QPMMimeImage();
|
|---|
| 575 |
|
|---|
| 576 | // for converting from Qt
|
|---|
| 577 | QList<MimeCFPair> formatsForMimeData(const QMimeData *mimeData) const;
|
|---|
| 578 | bool convertFromMimeData(const QMimeData *mimeData, ULONG format,
|
|---|
| 579 | ULONG &flags, ULONG *data) const;
|
|---|
| 580 | // for converting to Qt
|
|---|
| 581 | QList<MimeCFPair> mimesForFormats(const QList<ULONG> &formats) const;
|
|---|
| 582 | QVariant convertFromFormat(ULONG format, ULONG flags, ULONG data,
|
|---|
| 583 | const QString &mimeType,
|
|---|
| 584 | QVariant::Type preferredType) const;
|
|---|
| 585 | };
|
|---|
| 586 |
|
|---|
| 587 | QPMMimeImage::QPMMimeImage()
|
|---|
| 588 | {
|
|---|
| 589 | }
|
|---|
| 590 |
|
|---|
| 591 | QList<QPMMime::MimeCFPair> QPMMimeImage::formatsForMimeData(const QMimeData *mimeData) const
|
|---|
| 592 | {
|
|---|
| 593 | QList<MimeCFPair> fmts;
|
|---|
| 594 | if (mimeData->hasImage()) {
|
|---|
| 595 | // "application/x-qt-image" seems to be used as a single name for all
|
|---|
| 596 | // "image/xxx" types in Qt
|
|---|
| 597 | fmts << MimeCFPair(QLatin1String("application/x-qt-image"), CF_BITMAP);
|
|---|
| 598 | }
|
|---|
| 599 | return fmts;
|
|---|
| 600 | }
|
|---|
| 601 |
|
|---|
| 602 | bool QPMMimeImage::convertFromMimeData(const QMimeData *mimeData, ULONG format,
|
|---|
| 603 | ULONG &flags, ULONG *data) const
|
|---|
| 604 | {
|
|---|
| 605 | if (!mimeData->hasImage() || format != CF_BITMAP)
|
|---|
| 606 | return false;
|
|---|
| 607 |
|
|---|
| 608 | flags = CFI_HANDLE;
|
|---|
| 609 |
|
|---|
| 610 | if (data == NULL)
|
|---|
| 611 | return true; // delayed rendering, nothing to do
|
|---|
| 612 |
|
|---|
| 613 | QImage img = qvariant_cast<QImage>(mimeData->imageData());
|
|---|
| 614 | if (img.isNull())
|
|---|
| 615 | return false;
|
|---|
| 616 |
|
|---|
| 617 | QPixmap pm = QPixmap::fromImage(img);
|
|---|
| 618 | if (pm.isNull())
|
|---|
| 619 | return false;
|
|---|
| 620 |
|
|---|
| 621 | HBITMAP bmp = pm.toPmHBITMAP(0, true);
|
|---|
| 622 | if (bmp == NULLHANDLE)
|
|---|
| 623 | return false;
|
|---|
| 624 |
|
|---|
| 625 | *data = bmp;
|
|---|
| 626 | return true;
|
|---|
| 627 | }
|
|---|
| 628 |
|
|---|
| 629 | QList<QPMMime::MimeCFPair> QPMMimeImage::mimesForFormats(const QList<ULONG> &formats) const
|
|---|
| 630 | {
|
|---|
| 631 | QList<MimeCFPair> mimes;
|
|---|
| 632 | if (formats.contains(CF_BITMAP))
|
|---|
| 633 | mimes << MimeCFPair(QLatin1String("application/x-qt-image"), CF_BITMAP);
|
|---|
| 634 | return mimes;
|
|---|
| 635 | }
|
|---|
| 636 |
|
|---|
| 637 | QVariant QPMMimeImage::convertFromFormat(ULONG format, ULONG flags, ULONG data,
|
|---|
| 638 | const QString &mimeType,
|
|---|
| 639 | QVariant::Type preferredType) const
|
|---|
| 640 | {
|
|---|
| 641 | Q_UNUSED(preferredType);
|
|---|
| 642 |
|
|---|
| 643 | QVariant ret;
|
|---|
| 644 |
|
|---|
| 645 | if (mimeType != QLatin1String("application/x-qt-image"))
|
|---|
| 646 | return ret;
|
|---|
| 647 | if (format != CF_BITMAP || !(flags & CFI_HANDLE) || !data)
|
|---|
| 648 | return ret;
|
|---|
| 649 |
|
|---|
| 650 | QPixmap pm = QPixmap::fromPmHBITMAP((HBITMAP)data);
|
|---|
| 651 | if (pm.isNull())
|
|---|
| 652 | return ret;
|
|---|
| 653 |
|
|---|
| 654 | ret = pm.toImage();
|
|---|
| 655 | return ret;
|
|---|
| 656 | }
|
|---|
| 657 |
|
|---|
| 658 | ////////////////////////////////////////////////////////////////////////////////
|
|---|
| 659 |
|
|---|
| 660 | class QPMMimeAnyMime : public QPMMime
|
|---|
| 661 | {
|
|---|
| 662 | public:
|
|---|
| 663 | QPMMimeAnyMime();
|
|---|
| 664 | ~QPMMimeAnyMime();
|
|---|
| 665 |
|
|---|
| 666 | // for converting from Qt
|
|---|
| 667 | QList<MimeCFPair> formatsForMimeData(const QMimeData *mimeData) const;
|
|---|
| 668 | bool convertFromMimeData(const QMimeData *mimeData, ULONG format,
|
|---|
| 669 | ULONG &flags, ULONG *data) const;
|
|---|
| 670 | // for converting to Qt
|
|---|
| 671 | QList<MimeCFPair> mimesForFormats(const QList<ULONG> &formats) const;
|
|---|
| 672 | QVariant convertFromFormat(ULONG format, ULONG flags, ULONG data,
|
|---|
| 673 | const QString &mimeType,
|
|---|
| 674 | QVariant::Type preferredType) const;
|
|---|
| 675 |
|
|---|
| 676 | private:
|
|---|
| 677 | ULONG registerMimeType(const QString &mime) const;
|
|---|
| 678 | QString registerFormat(ULONG format) const;
|
|---|
| 679 |
|
|---|
| 680 | mutable QMap<QString, ULONG> cfMap;
|
|---|
| 681 | mutable QMap<ULONG, QString> mimeMap;
|
|---|
| 682 |
|
|---|
| 683 | static QStringList ianaTypes;
|
|---|
| 684 | static QString mimePrefix;
|
|---|
| 685 | static QString customPrefix;
|
|---|
| 686 | };
|
|---|
| 687 |
|
|---|
| 688 | // static
|
|---|
| 689 | QStringList QPMMimeAnyMime::ianaTypes;
|
|---|
| 690 | QString QPMMimeAnyMime::mimePrefix;
|
|---|
| 691 | QString QPMMimeAnyMime::customPrefix;
|
|---|
| 692 |
|
|---|
| 693 | QPMMimeAnyMime::QPMMimeAnyMime()
|
|---|
| 694 | {
|
|---|
| 695 | //MIME Media-Types
|
|---|
| 696 | if (!ianaTypes.size()) {
|
|---|
| 697 | ianaTypes.append(QLatin1String("application/"));
|
|---|
| 698 | ianaTypes.append(QLatin1String("audio/"));
|
|---|
| 699 | ianaTypes.append(QLatin1String("example/"));
|
|---|
| 700 | ianaTypes.append(QLatin1String("image/"));
|
|---|
| 701 | ianaTypes.append(QLatin1String("message/"));
|
|---|
| 702 | ianaTypes.append(QLatin1String("model/"));
|
|---|
| 703 | ianaTypes.append(QLatin1String("multipart/"));
|
|---|
| 704 | ianaTypes.append(QLatin1String("text/"));
|
|---|
| 705 | ianaTypes.append(QLatin1String("video/"));
|
|---|
| 706 |
|
|---|
| 707 | mimePrefix = QLatin1String("x-mime:");
|
|---|
| 708 | customPrefix = QLatin1String("application/x-qt-pm-mime;value=\"");
|
|---|
| 709 | }
|
|---|
| 710 | }
|
|---|
| 711 |
|
|---|
| 712 | QPMMimeAnyMime::~QPMMimeAnyMime()
|
|---|
| 713 | {
|
|---|
| 714 | foreach(ULONG cf, cfMap.values())
|
|---|
| 715 | unregisterMimeType(cf);
|
|---|
| 716 | }
|
|---|
| 717 |
|
|---|
| 718 | QList<QPMMime::MimeCFPair> QPMMimeAnyMime::formatsForMimeData(const QMimeData *mimeData) const
|
|---|
| 719 | {
|
|---|
| 720 | QList<MimeCFPair> fmts;
|
|---|
| 721 |
|
|---|
| 722 | QStringList mimes = QInternalMimeData::formatsHelper(mimeData);
|
|---|
| 723 | foreach (QString mime, mimes) {
|
|---|
| 724 | ULONG cf = cfMap.value(mime);
|
|---|
| 725 | if (!cf)
|
|---|
| 726 | cf = registerMimeType(mime);
|
|---|
| 727 | if (cf)
|
|---|
| 728 | fmts << MimeCFPair(mime, cf);
|
|---|
| 729 | }
|
|---|
| 730 |
|
|---|
| 731 | return fmts;
|
|---|
| 732 | }
|
|---|
| 733 |
|
|---|
| 734 | bool QPMMimeAnyMime::convertFromMimeData(const QMimeData *mimeData, ULONG format,
|
|---|
| 735 | ULONG &flags, ULONG *data) const
|
|---|
| 736 | {
|
|---|
| 737 | QString mime = mimeMap.value(format);
|
|---|
| 738 | if (mime.isNull())
|
|---|
| 739 | return false;
|
|---|
| 740 |
|
|---|
| 741 | flags = CFI_POINTER;
|
|---|
| 742 |
|
|---|
| 743 | if (data == NULL)
|
|---|
| 744 | return true; // delayed rendering, nothing to do
|
|---|
| 745 |
|
|---|
| 746 | QByteArray r = QInternalMimeData::renderDataHelper(mime, mimeData);
|
|---|
| 747 | if (r.isNull())
|
|---|
| 748 | return false;
|
|---|
| 749 |
|
|---|
| 750 | *data = QPMMime::allocateMemory(r.size() + sizeof(ULONG));
|
|---|
| 751 | if (!*data)
|
|---|
| 752 | return false;
|
|---|
| 753 |
|
|---|
| 754 | *((ULONG *)(*data)) = r.size();
|
|---|
| 755 | memcpy((void *)(*data + sizeof(ULONG)), r.data(), r.size());
|
|---|
| 756 | return true;
|
|---|
| 757 | }
|
|---|
| 758 |
|
|---|
| 759 | QList<QPMMime::MimeCFPair> QPMMimeAnyMime::mimesForFormats(const QList<ULONG> &formats) const
|
|---|
| 760 | {
|
|---|
| 761 | QList<MimeCFPair> mimes;
|
|---|
| 762 |
|
|---|
| 763 | foreach (ULONG format, formats) {
|
|---|
| 764 | QString mime = mimeMap.value(format);
|
|---|
| 765 | if (mime.isEmpty())
|
|---|
| 766 | mime = registerFormat(format);
|
|---|
| 767 | if (!mime.isEmpty())
|
|---|
| 768 | mimes << MimeCFPair(mime, format);
|
|---|
| 769 | }
|
|---|
| 770 |
|
|---|
| 771 | return mimes;
|
|---|
| 772 | }
|
|---|
| 773 |
|
|---|
| 774 | QVariant QPMMimeAnyMime::convertFromFormat(ULONG format, ULONG flags, ULONG data,
|
|---|
| 775 | const QString &mimeType,
|
|---|
| 776 | QVariant::Type preferredType) const
|
|---|
| 777 | {
|
|---|
| 778 | Q_UNUSED(preferredType);
|
|---|
| 779 |
|
|---|
| 780 | QVariant ret;
|
|---|
| 781 |
|
|---|
| 782 | if (cfMap.value(mimeType) != format)
|
|---|
| 783 | return ret;
|
|---|
| 784 |
|
|---|
| 785 | if (!(flags & CFI_POINTER) || !data)
|
|---|
| 786 | return ret;
|
|---|
| 787 |
|
|---|
| 788 | // get the real block size (always rounded to the page boundary (4K))
|
|---|
| 789 | ULONG sz = ~0, fl = 0, arc;
|
|---|
| 790 | arc = DosQueryMem((PVOID)data, &sz, &fl);
|
|---|
| 791 | if (arc != NO_ERROR) {
|
|---|
| 792 | #ifndef QT_NO_DEBUG
|
|---|
| 793 | qWarning("QPMMimeText::convertFromFormat: DosQueryMem failed with %lu", arc);
|
|---|
| 794 | #endif
|
|---|
| 795 | return ret;
|
|---|
| 796 | }
|
|---|
| 797 | ULONG size = *((ULONG *)data);
|
|---|
| 798 | if (!size || size + sizeof(ULONG) > sz)
|
|---|
| 799 | return ret;
|
|---|
| 800 |
|
|---|
| 801 | // it should be enough to return the data and let QMimeData do the rest.
|
|---|
| 802 | ret = QByteArray((const char *)(data + sizeof(ULONG)), size);
|
|---|
| 803 | return ret;
|
|---|
| 804 | }
|
|---|
| 805 |
|
|---|
| 806 | ULONG QPMMimeAnyMime::registerMimeType(const QString &mime) const
|
|---|
| 807 | {
|
|---|
| 808 | if (mime.isEmpty())
|
|---|
| 809 | return 0;
|
|---|
| 810 |
|
|---|
| 811 | QString mimeToReg = mime;
|
|---|
| 812 |
|
|---|
| 813 | bool ianaType = false;
|
|---|
| 814 | foreach(QString prefix, ianaTypes) {
|
|---|
| 815 | if (mime.startsWith(prefix)) {
|
|---|
| 816 | ianaType = true;
|
|---|
| 817 | break;
|
|---|
| 818 | }
|
|---|
| 819 | }
|
|---|
| 820 | if (!ianaType) {
|
|---|
| 821 | // prepend the non-standard type with the prefix that makes it comply
|
|---|
| 822 | // with the standard
|
|---|
| 823 | mimeToReg = customPrefix + mime + QLatin1Char('\"');
|
|---|
| 824 | }
|
|---|
| 825 |
|
|---|
| 826 | mimeToReg = mimePrefix + mimeToReg;
|
|---|
| 827 | ULONG cf = QPMMime::registerMimeType(mimeToReg);
|
|---|
| 828 | if (cf) {
|
|---|
| 829 | cfMap[mime] = cf;
|
|---|
| 830 | mimeMap[cf] = mime;
|
|---|
| 831 | }
|
|---|
| 832 | return cf;
|
|---|
| 833 | }
|
|---|
| 834 |
|
|---|
| 835 | QString QPMMimeAnyMime::registerFormat(ULONG format) const
|
|---|
| 836 | {
|
|---|
| 837 | QString mime;
|
|---|
| 838 |
|
|---|
| 839 | if (!format)
|
|---|
| 840 | return mime;
|
|---|
| 841 |
|
|---|
| 842 | QString atomStr = formatName(format);
|
|---|
| 843 | if (atomStr.startsWith(mimePrefix)) {
|
|---|
| 844 | // the format represents the mime type we can recognize
|
|---|
| 845 | // increase the reference count
|
|---|
| 846 | ULONG cf = QPMMime::registerMimeType(atomStr);
|
|---|
| 847 | Q_ASSERT(cf == format);
|
|---|
| 848 | // extract the real mime type (w/o our prefix)
|
|---|
| 849 | mime = atomStr.mid(mimePrefix.size());
|
|---|
| 850 | if (!mime.isEmpty()) {
|
|---|
| 851 | cfMap[mime] = cf;
|
|---|
| 852 | mimeMap[cf] = mime;
|
|---|
| 853 | }
|
|---|
| 854 | }
|
|---|
| 855 | return mime;
|
|---|
| 856 | }
|
|---|
| 857 |
|
|---|
| 858 | ////////////////////////////////////////////////////////////////////////////////
|
|---|
| 859 |
|
|---|
| 860 | QPMMimeList::QPMMimeList()
|
|---|
| 861 | : initialized(false)
|
|---|
| 862 | {
|
|---|
| 863 | }
|
|---|
| 864 |
|
|---|
| 865 | QPMMimeList::~QPMMimeList()
|
|---|
| 866 | {
|
|---|
| 867 | while (list.size())
|
|---|
| 868 | delete list.first();
|
|---|
| 869 | }
|
|---|
| 870 |
|
|---|
| 871 |
|
|---|
| 872 | void QPMMimeList::init()
|
|---|
| 873 | {
|
|---|
| 874 | if (!initialized) {
|
|---|
| 875 | initialized = true;
|
|---|
| 876 | new QPMMimeAnyMime; // must be the first (used as a fallback)
|
|---|
| 877 | new QPMMimeImage;
|
|---|
| 878 | new QPMMimeText;
|
|---|
| 879 | }
|
|---|
| 880 | }
|
|---|
| 881 |
|
|---|
| 882 | void QPMMimeList::addMime(QPMMime *mime)
|
|---|
| 883 | {
|
|---|
| 884 | init();
|
|---|
| 885 | list.prepend(mime);
|
|---|
| 886 | }
|
|---|
| 887 |
|
|---|
| 888 | void QPMMimeList::removeMime(QPMMime *mime)
|
|---|
| 889 | {
|
|---|
| 890 | init();
|
|---|
| 891 | list.removeAll(mime);
|
|---|
| 892 | }
|
|---|
| 893 |
|
|---|
| 894 | QList<QPMMime*> QPMMimeList::mimes()
|
|---|
| 895 | {
|
|---|
| 896 | init();
|
|---|
| 897 | return list;
|
|---|
| 898 | }
|
|---|
| 899 |
|
|---|
| 900 | QT_END_NAMESPACE
|
|---|