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