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