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