|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the QtCore module of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
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 |
|
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 |
|
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 |
|
91 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 |
|
103 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 withing 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 */ |
|
288 QMimeData::QMimeData() |
|
289 : QObject(*new QMimeDataPrivate, 0) |
|
290 { |
|
291 } |
|
292 |
|
293 /*! |
|
294 Destroys the MIME data object. |
|
295 */ |
|
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 */ |
|
307 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 */ |
|
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 */ |
|
349 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 */ |
|
361 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 */ |
|
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 */ |
|
386 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 */ |
|
397 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 */ |
|
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 */ |
|
422 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 */ |
|
439 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 */ |
|
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 */ |
|
468 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 */ |
|
486 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 */ |
|
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 */ |
|
512 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 */ |
|
521 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 */ |
|
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 */ |
|
560 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 */ |
|
576 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 */ |
|
600 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 */ |
|
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 */ |
|
621 void QMimeData::removeFormat(const QString &mimeType) |
|
622 { |
|
623 Q_D(QMimeData); |
|
624 d->removeData(mimeType); |
|
625 } |
|
626 |
|
627 QT_END_NAMESPACE |