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