source: trunk/src/gui/kernel/qmime_pm.cpp@ 427

Last change on this file since 427 was 423, checked in by Dmitry A. Kuminov, 16 years ago

general: Fixed a bunch of deprecated QString/QChar initializers.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Revision Author Id
File size: 27.6 KB
Line 
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
64QT_BEGIN_NAMESPACE
65
66class QPMMimeList
67{
68public:
69 QPMMimeList();
70 ~QPMMimeList();
71 void addMime(QPMMime *mime);
72 void removeMime(QPMMime *mime);
73 QList<QPMMime*> mimes();
74
75private:
76 void init();
77 bool initialized;
78 QList<QPMMime*> list;
79};
80
81Q_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/*!
133Constructs a new conversion object, adding it to the globally accessed
134list of available converters.
135*/
136QPMMime::QPMMime()
137{
138 theMimeList()->addMime(this);
139}
140
141/*!
142Destroys a conversion object, removing it from the global
143list of available converters.
144*/
145QPMMime::~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
156ULONG 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
175void 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
186ULONG 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
212void 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
285QList<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
318QList<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
359QString 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
374class QPMMimeText : public QPMMime
375{
376public:
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
395QPMMimeText::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
403QPMMimeText::~QPMMimeText()
404{
405 unregisterMimeType(CF_TextHtml);
406 unregisterMimeType(CF_TextUnicode);
407}
408
409QList<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.
425bool 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
512QList<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
526QVariant 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
571class QPMMimeImage : public QPMMime
572{
573public:
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
587QPMMimeImage::QPMMimeImage()
588{
589}
590
591QList<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
602bool 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
629QList<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
637QVariant 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
660class QPMMimeAnyMime : public QPMMime
661{
662public:
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
676private:
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
689QStringList QPMMimeAnyMime::ianaTypes;
690QString QPMMimeAnyMime::mimePrefix;
691QString QPMMimeAnyMime::customPrefix;
692
693QPMMimeAnyMime::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
712QPMMimeAnyMime::~QPMMimeAnyMime()
713{
714 foreach(ULONG cf, cfMap.values())
715 unregisterMimeType(cf);
716}
717
718QList<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
734bool 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
759QList<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
774QVariant 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
806ULONG 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
835QString 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
860QPMMimeList::QPMMimeList()
861 : initialized(false)
862{
863}
864
865QPMMimeList::~QPMMimeList()
866{
867 while (list.size())
868 delete list.first();
869}
870
871
872void 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
882void QPMMimeList::addMime(QPMMime *mime)
883{
884 init();
885 list.prepend(mime);
886}
887
888void QPMMimeList::removeMime(QPMMime *mime)
889{
890 init();
891 list.removeAll(mime);
892}
893
894QList<QPMMime*> QPMMimeList::mimes()
895{
896 init();
897 return list;
898}
899
900QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.