Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qmimedata.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include "qmimedata.h"
6
7#include "private/qobject_p.h"
8#include "qurl.h"
9#include "qstringlist.h"
11
13
14using namespace Qt::StringLiterals;
15
16static inline QString textUriListLiteral() { return u"text/uri-list"_s; }
17static inline QString textHtmlLiteral() { return u"text/html"_s; }
18static inline QString textPlainLiteral() { return u"text/plain"_s; }
19static inline QString textPlainUtf8Literal() { return u"text/plain;charset=utf-8"_s; }
20static inline QString applicationXColorLiteral() { return u"application/x-color"_s; }
21static inline QString applicationXQtImageLiteral() { return u"application/x-qt-image"_s; }
22
29
31{
32 Q_DECLARE_PUBLIC(QMimeData)
33public:
35 void setData(const QString &format, const QVariant &data);
36 QVariant getData(const QString &format) const;
37
38 QVariant retrieveTypedData(const QString &format, QMetaType type) const;
39
40 std::vector<QMimeDataStruct>::iterator find(const QString &format) noexcept {
41 const auto formatEquals = [](const QString &format) {
42 return [&format](const QMimeDataStruct &s) { return s.format == format; };
43 };
45 }
46
48 return const_cast<QMimeDataPrivate*>(this)->find(format);
49 }
50
52};
53
54void QMimeDataPrivate::removeData(const QString &format)
55{
56 const auto it = find(format);
57 if (it != dataList.end())
58 dataList.erase(it);
59}
60
61void QMimeDataPrivate::setData(const QString &format, const QVariant &data)
62{
63 const auto it = find(format);
64 if (it == dataList.end())
65 dataList.push_back({format, data});
66 else
67 it->data = data;
68}
69
70
71QVariant QMimeDataPrivate::getData(const QString &format) const
72{
73 const auto it = find(format);
74 if (it == dataList.cend())
75 return {};
76 else
77 return it->data;
78}
79
80static QList<QVariant> dataToUrls(QByteArrayView text)
81{
82 QList<QVariant> list;
83 qsizetype newLineIndex = -1;
84 qsizetype from = 0;
85 const char *begin = text.data();
86 while ((newLineIndex = text.indexOf('\n', from)) != -1) {
87 const auto bav = QByteArrayView(begin + from, begin + newLineIndex).trimmed();
88 if (!bav.isEmpty())
89 list.push_back(QUrl::fromEncoded(bav));
90 from = newLineIndex + 1;
91 if (from >= text.size())
92 break;
93 }
94 if (from != text.size()) {
95 const auto bav = QByteArrayView(begin + from, text.end()).trimmed();
96 if (!bav.isEmpty())
97 list.push_back(QUrl::fromEncoded(bav));
98 }
99 return list;
100}
101
102QVariant QMimeDataPrivate::retrieveTypedData(const QString &format, QMetaType type) const
103{
104 Q_Q(const QMimeData);
105 int typeId = type.id();
106
107 QVariant data = q->retrieveData(format, type);
108
109 // Text data requested: fallback to URL data if available
110 if (format == "text/plain"_L1 && !data.isValid()) {
111 data = retrieveTypedData(textUriListLiteral(), QMetaType(QMetaType::QVariantList));
112 if (const QUrl *url = get_if<QUrl>(&std::as_const(data))) {
113 data = QVariant(url->toDisplayString());
114 } else if (const QVariantList *list = get_if<QVariantList>(&std::as_const(data))) {
115 QString text;
116 int numUrls = 0;
117 for (const auto &element : *list) {
118 if (const QUrl *url = get_if<QUrl>(&element)) {
119 text += url->toDisplayString();
120 text += u'\n';
121 ++numUrls;
122 }
123 }
124 if (numUrls == 1)
125 text.chop(1); // no final '\n' if there's only one URL
126 data = QVariant(text);
127 }
128 }
129
130 if (data.metaType() == type || !data.isValid())
131 return data;
132
133 // provide more conversion possibilities than just what QVariant provides
134
135 // URLs can be lists as well...
136 if ((typeId == QMetaType::QUrl && data.metaType().id() == QMetaType::QVariantList)
137 || (typeId == QMetaType::QVariantList && data.metaType().id() == QMetaType::QUrl))
138 return data;
139
140 // images and pixmaps are interchangeable
141 if ((typeId == QMetaType::QPixmap && data.metaType().id() == QMetaType::QImage)
142 || (typeId == QMetaType::QImage && data.metaType().id() == QMetaType::QPixmap))
143 return data;
144
145 if (const QByteArray *ba = get_if<QByteArray>(&std::as_const(data))) {
146 // see if we can convert to the requested type
147 switch (typeId) {
148 case QMetaType::QString: {
149 if (ba->isNull())
150 return QVariant();
151 if (format == "text/html"_L1) {
152 QStringDecoder decoder = QStringDecoder::decoderForHtml(*ba);
153 if (decoder.isValid()) {
154 return QString(decoder(*ba));
155 }
156 // fall back to utf8
157 }
158 return QString::fromUtf8(*ba);
159 }
160 case QMetaType::QColor: {
161 QVariant newData = data;
162 newData.convert(QMetaType(QMetaType::QColor));
163 return newData;
164 }
165 case QMetaType::QVariantList: {
166 if (format != "text/uri-list"_L1)
167 break;
168 Q_FALLTHROUGH();
169 }
170 case QMetaType::QUrl: {
171 auto bav = data.view<QByteArrayView>();
172 // Qt 3.x will send text/uri-list with a trailing
173 // null-terminator (that is *not* sent for any other
174 // text/* mime-type), so chop it off
175 if (bav.endsWith('\0'))
176 bav.chop(1);
177 return dataToUrls(bav);
178 }
179 default:
180 break;
181 }
182
183 } else if (typeId == QMetaType::QByteArray) {
184
185 // try to convert to bytearray
186 switch (data.metaType().id()) {
187 case QMetaType::QByteArray:
188 case QMetaType::QColor:
189 return data.toByteArray();
190 case QMetaType::QString:
191 return data.toString().toUtf8();
192 case QMetaType::QUrl:
193 return data.toUrl().toEncoded();
194 case QMetaType::QVariantList: {
195 // has to be list of URLs
196 QByteArray result;
197 const QList<QVariant> list = data.toList();
198 for (const auto &element : list) {
199 if (const QUrl *url = get_if<QUrl>(&element)) {
200 result += url->toEncoded();
201 result += "\r\n";
202 }
203 }
204 if (!result.isEmpty())
205 return result;
206 break;
207 }
208 default:
209 break;
210 }
211 }
212 return data;
213}
214
215/*!
216 \class QMimeData
217 \inmodule QtCore
218 \brief The QMimeData class provides a container for data that records information
219 about its MIME type.
220
221 QMimeData is used to describe information that can be stored in
222 the \l{QClipboard}{clipboard}, and transferred via the \l{drag
223 and drop} mechanism. QMimeData objects associate the data that
224 they hold with the corresponding MIME types to ensure that
225 information can be safely transferred between applications, and
226 copied around within the same application.
227
228 QMimeData objects are usually created using \c new and supplied
229 to QDrag or QClipboard objects. This is to enable Qt to manage
230 the memory that they use.
231
232 A single QMimeData object can store the same data using several
233 different formats at the same time. The formats() function
234 returns a list of the available formats in order of preference.
235 The data() function returns the raw data associated with a MIME
236 type, and setData() allows you to set the data for a MIME type.
237
238 For the most common MIME types, QMimeData provides convenience
239 functions to access the data:
240
241 \table
242 \header \li Tester \li Getter \li Setter \li MIME Types
243 \row \li hasText() \li text() \li setText() \li \c text/plain
244 \row \li hasHtml() \li html() \li setHtml() \li \c text/html
245 \row \li hasUrls() \li urls() \li setUrls() \li \c text/uri-list
246 \row \li hasImage() \li imageData() \li setImageData() \li \c image/ *
247 \row \li hasColor() \li colorData() \li setColorData() \li \c application/x-color
248 \endtable
249
250 For example, if your write a widget that accepts URL drags, you
251 would end up writing code like this:
252
253 \snippet code/src_corelib_kernel_qmimedata.cpp 0
254
255 There are three approaches for storing custom data in a QMimeData
256 object:
257
258 \list 1
259 \li Custom data can be stored directly in a QMimeData object as a
260 QByteArray using setData(). For example:
261
262 \snippet code/src_corelib_kernel_qmimedata.cpp 1
263
264 \li We can subclass QMimeData and reimplement hasFormat(),
265 formats(), and retrieveData().
266
267 \li If the drag and drop operation occurs within a single
268 application, we can subclass QMimeData and add extra data in
269 it, and use a qobject_cast() in the receiver's drop event
270 handler. For example:
271
272 \snippet code/src_corelib_kernel_qmimedata.cpp 2
273 \endlist
274
275 \section1 Platform-Specific MIME Types
276
277 On Windows, formats() will also return custom formats available
278 in the MIME data, using the \c{x-qt-windows-mime} subtype to
279 indicate that they represent data in non-standard formats.
280 The formats will take the following form:
281
282 \snippet code/src_corelib_kernel_qmimedata.cpp 3
283
284 The following are examples of custom MIME types:
285
286 \snippet code/src_corelib_kernel_qmimedata.cpp 4
287
288 The \c value declaration of each format describes the way in which the
289 data is encoded.
290
291 In some cases (e.g. dropping multiple email attachments), multiple data
292 values are available. They can be accessed by adding an \c index value:
293
294 \snippet code/src_corelib_kernel_qmimedata.cpp 8
295
296 On Windows, the MIME format does not always map directly to the
297 clipboard formats. Qt provides QWindowsMimeConverter to map clipboard
298 formats to open-standard MIME formats. Similarly, the
299 QUtiMimeConverter maps MIME to Uniform Type Identifiers on macOS and iOS.
300
301 \sa QClipboard, QDragEnterEvent, QDragMoveEvent, QDropEvent, QDrag,
302 {Drag and Drop}
303*/
304
305/*!
306 Constructs a new MIME data object with no data in it.
307*/
308QMimeData::QMimeData()
309 : QObject(*new QMimeDataPrivate, nullptr)
310{
311}
312
313/*!
314 Destroys the MIME data object.
315*/
316QMimeData::~QMimeData()
317{
318}
319
320/*!
321 Returns a list of URLs contained within the MIME data object.
322
323 URLs correspond to the MIME type \c text/uri-list.
324
325 \sa hasUrls(), data()
326*/
327QList<QUrl> QMimeData::urls() const
328{
329 Q_D(const QMimeData);
330 const QVariant data = d->retrieveTypedData(textUriListLiteral(), QMetaType(QMetaType::QVariantList));
331 QList<QUrl> urls;
332 if (const QUrl *url = get_if<QUrl>(&data)) {
333 urls.append(*url);
334 } else if (const QVariantList *list = get_if<QVariantList>(&data)) {
335 for (const auto &element : *list) {
336 if (const QUrl *url = get_if<QUrl>(&element))
337 urls.append(*url);
338 }
339 }
340 return urls;
341}
342
343/*!
344 Sets the URLs stored in the MIME data object to those specified by \a urls.
345
346 URLs correspond to the MIME type \c text/uri-list.
347
348 Since Qt 5.0, setUrls also exports the urls as plain text, if setText
349 was not called before, to make it possible to drop them into any lineedit
350 and text editor.
351
352 \sa hasUrls(), setData()
353*/
354void QMimeData::setUrls(const QList<QUrl> &urls)
355{
356 Q_D(QMimeData);
357 d->setData(textUriListLiteral(), QList<QVariant>(urls.cbegin(), urls.cend()));
358}
359
360/*!
361 Returns \c true if the object can return a list of urls; otherwise
362 returns \c false.
363
364 URLs correspond to the MIME type \c text/uri-list.
365
366 \sa setUrls(), urls(), hasFormat()
367*/
368bool QMimeData::hasUrls() const
369{
370 return hasFormat(textUriListLiteral());
371}
372
373
374/*!
375 Returns the plain text (MIME type \c text/plain) representation of
376 the data if this object contains plain text. If it contains some other
377 content, this function makes a best effort to convert it to plain text.
378
379 \sa hasText(), html(), data()
380*/
381QString QMimeData::text() const
382{
383 Q_D(const QMimeData);
384 QVariant utf8Text = d->retrieveTypedData(textPlainUtf8Literal(), QMetaType(QMetaType::QString));
385 if (!utf8Text.isNull())
386 return utf8Text.toString();
387
388 QVariant data = d->retrieveTypedData(textPlainLiteral(), QMetaType(QMetaType::QString));
389 return data.toString();
390}
391
392/*!
393 Sets \a text as the plain text (MIME type \c text/plain) used to
394 represent the data.
395
396 \sa hasText(), setHtml(), setData()
397*/
398void QMimeData::setText(const QString &text)
399{
400 Q_D(QMimeData);
401 d->setData(textPlainLiteral(), text);
402}
403
404/*!
405 Returns \c true if the object can return plain text (MIME type \c
406 text/plain); otherwise returns \c false.
407
408 \sa setText(), text(), hasHtml(), hasFormat()
409*/
410bool QMimeData::hasText() const
411{
412 return hasFormat(textPlainLiteral()) || hasFormat(textPlainUtf8Literal()) || hasUrls();
413}
414
415/*!
416 Returns a string if the data stored in the object is HTML (MIME
417 type \c text/html); otherwise returns an empty string.
418
419 \sa hasHtml(), setData()
420*/
421QString QMimeData::html() const
422{
423 Q_D(const QMimeData);
424 QVariant data = d->retrieveTypedData(textHtmlLiteral(), QMetaType(QMetaType::QString));
425 return data.toString();
426}
427
428/*!
429 Sets \a html as the HTML (MIME type \c text/html) used to
430 represent the data.
431
432 \sa hasHtml(), setText(), setData()
433*/
434void QMimeData::setHtml(const QString &html)
435{
436 Q_D(QMimeData);
437 d->setData(textHtmlLiteral(), html);
438}
439
440/*!
441 Returns \c true if the object can return HTML (MIME type \c
442 text/html); otherwise returns \c false.
443
444 \sa setHtml(), html(), hasFormat()
445*/
446bool QMimeData::hasHtml() const
447{
448 return hasFormat(textHtmlLiteral());
449}
450
451/*!
452 Returns a QVariant storing a QImage if the object can return an
453 image; otherwise returns a null variant.
454
455 A QVariant is used because QMimeData belongs to the Qt Core
456 module, whereas QImage belongs to Qt GUI. To convert the
457 QVariant to a QImage, simply use qvariant_cast(). For example:
458
459 \snippet code/src_corelib_kernel_qmimedata.cpp 5
460
461 \sa hasImage()
462*/
463QVariant QMimeData::imageData() const
464{
465 Q_D(const QMimeData);
466 return d->retrieveTypedData(applicationXQtImageLiteral(), QMetaType(QMetaType::QImage));
467}
468
469/*!
470 Sets the data in the object to the given \a image.
471
472 A QVariant is used because QMimeData belongs to the Qt Core
473 module, whereas QImage belongs to Qt GUI. The conversion
474 from QImage to QVariant is implicit. For example:
475
476 \snippet code/src_corelib_kernel_qmimedata.cpp 6
477
478 \sa hasImage(), setData()
479*/
480void QMimeData::setImageData(const QVariant &image)
481{
482 Q_D(QMimeData);
483 d->setData(applicationXQtImageLiteral(), image);
484}
485
486/*!
487 Returns \c true if the object can return an image; otherwise returns
488 false.
489
490 \sa setImageData(), imageData(), hasFormat()
491*/
492bool QMimeData::hasImage() const
493{
494 return hasFormat(applicationXQtImageLiteral());
495}
496
497/*!
498 Returns a color if the data stored in the object represents a
499 color (MIME type \c application/x-color); otherwise returns a
500 null variant.
501
502 A QVariant is used because QMimeData belongs to the Qt Core
503 module, whereas QColor belongs to Qt GUI. To convert the
504 QVariant to a QColor, simply use qvariant_cast(). For example:
505
506 \snippet code/src_corelib_kernel_qmimedata.cpp 7
507
508 \sa hasColor(), setColorData(), data()
509*/
510QVariant QMimeData::colorData() const
511{
512 Q_D(const QMimeData);
513 return d->retrieveTypedData(applicationXColorLiteral(), QMetaType(QMetaType::QColor));
514}
515
516/*!
517 Sets the color data in the object to the given \a color.
518
519 Colors correspond to the MIME type \c application/x-color.
520
521 \sa hasColor(), setData()
522*/
523void QMimeData::setColorData(const QVariant &color)
524{
525 Q_D(QMimeData);
526 d->setData(applicationXColorLiteral(), color);
527}
528
529
530/*!
531 Returns \c true if the object can return a color (MIME type \c
532 application/x-color); otherwise returns \c false.
533
534 \sa setColorData(), colorData(), hasFormat()
535*/
536bool QMimeData::hasColor() const
537{
538 return hasFormat(applicationXColorLiteral());
539}
540
541/*!
542 Returns the data stored in the object in the format described by
543 the MIME type specified by \a mimeType. If this object does not contain
544 data for the \a mimeType MIME type (see hasFormat()), this function may
545 perform a best effort conversion to it.
546
547 \sa hasFormat(), setData()
548*/
549QByteArray QMimeData::data(const QString &mimeType) const
550{
551 Q_D(const QMimeData);
552 QVariant data = d->retrieveTypedData(mimeType, QMetaType(QMetaType::QByteArray));
553 return data.toByteArray();
554}
555
556/*!
557 Sets the data associated with the MIME type given by \a mimeType
558 to the specified \a data.
559
560 For the most common types of data, you can call the higher-level
561 functions setText(), setHtml(), setUrls(), setImageData(), and
562 setColorData() instead.
563
564 Note that if you want to use a custom data type in an item view drag and drop
565 operation, you must register it as a Qt \l{QMetaType}{meta type}, using the
566 Q_DECLARE_METATYPE() macro, and implement stream operators for it.
567
568 \sa hasFormat(), QMetaType, {QMetaType::}{Q_DECLARE_METATYPE()}
569*/
570void QMimeData::setData(const QString &mimeType, const QByteArray &data)
571{
572 Q_D(QMimeData);
573
574 if (mimeType == "text/uri-list"_L1) {
575 auto ba = QByteArrayView(data);
576 if (ba.endsWith('\0'))
577 ba.chop(1);
578 d->setData(mimeType, dataToUrls(ba));
579 } else {
580 d->setData(mimeType, QVariant(data));
581 }
582}
583
584/*!
585 Returns \c true if the object can return data for the MIME type
586 specified by \a mimeType; otherwise returns \c false.
587
588 For the most common types of data, you can call the higher-level
589 functions hasText(), hasHtml(), hasUrls(), hasImage(), and
590 hasColor() instead.
591
592 \sa formats(), setData(), data()
593*/
594bool QMimeData::hasFormat(const QString &mimeType) const
595{
596 // formats() is virtual and could be reimplemented in sub-classes,
597 // so we have to use it here.
598 return formats().contains(mimeType);
599}
600
601/*!
602 Returns a list of formats supported by the object. This is a list
603 of MIME types for which the object can return suitable data. The
604 formats in the list are in a priority order.
605
606 For the most common types of data, you can call the higher-level
607 functions hasText(), hasHtml(), hasUrls(), hasImage(), and
608 hasColor() instead.
609
610 \sa hasFormat(), setData(), data()
611*/
612QStringList QMimeData::formats() const
613{
614 Q_D(const QMimeData);
615 QStringList list;
616 list.reserve(static_cast<int>(d->dataList.size()));
617 for (auto &e : d->dataList)
618 list += e.format;
619 return list;
620}
621
622/*!
623 Returns a variant with the given \a type containing data for the
624 MIME type specified by \a mimeType. If the object does not
625 support the MIME type or variant type given, a null variant is
626 returned instead.
627
628 This function is called by the general data() getter and by the
629 convenience getters (text(), html(), urls(), imageData(), and
630 colorData()). You can reimplement it if you want to store your
631 data using a custom data structure (instead of a QByteArray,
632 which is what setData() provides). You would then also need
633 to reimplement hasFormat() and formats().
634
635 \sa data()
636*/
637QVariant QMimeData::retrieveData(const QString &mimeType, QMetaType type) const
638{
639 Q_UNUSED(type);
640 Q_D(const QMimeData);
641 return d->getData(mimeType);
642}
643
644/*!
645 Removes all the MIME type and data entries in the object.
646*/
647void QMimeData::clear()
648{
649 Q_D(QMimeData);
650 d->dataList.clear();
651}
652
653/*!
654 \since 4.4
655
656 Removes the data entry for \a mimeType in the object.
657*/
658void QMimeData::removeFormat(const QString &mimeType)
659{
660 Q_D(QMimeData);
661 d->removeData(mimeType);
662}
663
664QT_END_NAMESPACE
665
666#include "moc_qmimedata.cpp"
QVariant getData(const QString &format) const
Definition qmimedata.cpp:71
QVariant retrieveTypedData(const QString &format, QMetaType type) const
void setData(const QString &format, const QVariant &data)
Definition qmimedata.cpp:61
\inmodule QtCore
Combined button and popup list for selecting options.
Q_DECLARE_TYPEINFO(QMimeDataStruct, Q_RELOCATABLE_TYPE)
static QString textPlainLiteral()
Definition qmimedata.cpp:18
static QList< QVariant > dataToUrls(QByteArrayView text)
Definition qmimedata.cpp:80
static QString textPlainUtf8Literal()
Definition qmimedata.cpp:19
static QString applicationXQtImageLiteral()
Definition qmimedata.cpp:21
static QString textUriListLiteral()
Definition qmimedata.cpp:16
static QString textHtmlLiteral()
Definition qmimedata.cpp:17
static QString applicationXColorLiteral()
Definition qmimedata.cpp:20