source: trunk/src/qt3support/other/q3dragobject.cpp@ 160

Last change on this file since 160 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 41.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the Qt3Support module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qplatformdefs.h"
43
44#ifndef QT_NO_MIME
45
46#include "q3dragobject.h"
47#include "qpixmap.h"
48#include "qevent.h"
49#include "qfile.h"
50#include "qtextcodec.h"
51#include "qapplication.h"
52#include "qpoint.h"
53#include "qwidget.h"
54#include "qbuffer.h"
55#include "qimagereader.h"
56#include "qimagewriter.h"
57#include "qimage.h"
58#include "qregexp.h"
59#include "qdir.h"
60#include "qdrag.h"
61#include "q3strlist.h"
62#include "q3cstring.h"
63
64#include <private/qobject_p.h>
65
66#include <ctype.h>
67#if defined(Q_OS_WINCE)
68#include <winsock.h>
69#include "qfunctions_wince.h"
70#endif
71
72QT_BEGIN_NAMESPACE
73
74static QWidget *last_target = 0;
75
76class QDragMime;
77
78class Q3DragObjectPrivate : public QObjectPrivate
79{
80 Q_DECLARE_PUBLIC(Q3DragObject)
81public:
82 Q3DragObjectPrivate(): hot(0,0),pm_cursor(0) {}
83 QPixmap pixmap;
84 QPoint hot;
85 // store default cursors
86 QPixmap *pm_cursor;
87};
88
89class Q3TextDragPrivate : public Q3DragObjectPrivate
90{
91 Q_DECLARE_PUBLIC(Q3TextDrag)
92public:
93 Q3TextDragPrivate() { setSubType(QLatin1String("plain")); }
94 void setSubType(const QString & st) {
95 subtype = st;
96 fmt = QString(QLatin1String("text/")).toLatin1() + subtype.toLatin1();
97 }
98
99 QString txt;
100 QString subtype;
101 QByteArray fmt;
102};
103
104class Q3StoredDragPrivate : public Q3DragObjectPrivate
105{
106 Q_DECLARE_PUBLIC(Q3StoredDrag)
107public:
108 Q3StoredDragPrivate() {}
109 const char* fmt;
110 QByteArray enc;
111};
112
113class Q3ImageDragPrivate : public Q3DragObjectPrivate
114{
115 Q_DECLARE_PUBLIC(Q3ImageDrag)
116public:
117 QImage img;
118 QList<QByteArray> ofmts;
119};
120
121class QDragMime : public QMimeData
122{
123public:
124 QDragMime(Q3DragObject *parent) : QMimeData(), dragObject(parent) { }
125 ~QDragMime();
126
127 QByteArray data(const QString &mimetype) const;
128 bool hasFormat(const QString &mimetype) const;
129 QStringList formats() const;
130
131 QPointer<Q3DragObject> dragObject;
132};
133
134QDragMime::~QDragMime()
135{
136 delete dragObject;
137}
138QByteArray QDragMime::data(const QString &mimetype) const
139{
140 return dragObject->encodedData(mimetype.latin1());
141}
142
143bool QDragMime::hasFormat(const QString &mimetype) const
144{
145 return dragObject->provides(mimetype.latin1());
146}
147
148QStringList QDragMime::formats() const
149{
150 int i = 0;
151 const char *format;
152 QStringList f;
153 while ((format = dragObject->format(i))) {
154 f.append(QLatin1String(format));
155 ++i;
156 }
157 return f;
158}
159
160/*!
161 Constructs a drag object called \a name with a parent \a
162 dragSource.
163
164 Note that the drag object will be deleted when the \a dragSource is
165 deleted.
166*/
167
168Q3DragObject::Q3DragObject(QWidget * dragSource, const char * name)
169 : QObject(*(new Q3DragObjectPrivate), dragSource)
170{
171 setObjectName(QLatin1String(name));
172}
173
174/*! \internal */
175Q3DragObject::Q3DragObject(Q3DragObjectPrivate &dd, QWidget *dragSource)
176 : QObject(dd, dragSource)
177{
178}
179
180/*!
181 Destroys the drag object, canceling any drag and drop operation in
182 which it is involved.
183*/
184
185Q3DragObject::~Q3DragObject()
186{
187}
188
189#ifndef QT_NO_DRAGANDDROP
190/*!
191 Set the pixmap, \a pm, to display while dragging the object. The
192 platform-specific implementation will use this where it can - so
193 provide a small masked pixmap, and do not assume that the user
194 will actually see it. For example, cursors on Windows 95 are of
195 limited size.
196
197 The \a hotspot is the point on (or off) the pixmap that should be
198 under the cursor as it is dragged. It is relative to the top-left
199 pixel of the pixmap.
200
201 \warning We have seen problems with drag cursors on different
202 graphics hardware and driver software on Windows. Setting the
203 graphics acceleration in the display settings down one tick solved
204 the problems in all cases.
205*/
206void Q3DragObject::setPixmap(QPixmap pm, const QPoint& hotspot)
207{
208 Q_D(Q3DragObject);
209 d->pixmap = pm;
210 d->hot = hotspot;
211#if 0
212 QDragManager *manager = QDragManager::self();
213 if (manager && manager->object == d->data)
214 manager->updatePixmap();
215#endif
216}
217
218/*!
219 \overload
220
221 Uses a hotspot that positions the pixmap below and to the right of
222 the mouse pointer. This allows the user to clearly see the point
223 on the window where they are dragging the data.
224*/
225void Q3DragObject::setPixmap(QPixmap pm)
226{
227 setPixmap(pm,QPoint(-10, -10));
228}
229
230/*!
231 Returns the currently set pixmap, or a null pixmap if none is set.
232
233 \sa QPixmap::isNull()
234*/
235QPixmap Q3DragObject::pixmap() const
236{
237 return d_func()->pixmap;
238}
239
240/*!
241 Returns the currently set pixmap hotspot.
242
243 \sa setPixmap()
244*/
245QPoint Q3DragObject::pixmapHotSpot() const
246{
247 return d_func()->hot;
248}
249
250/*!
251 Starts a drag operation using the contents of this object, using
252 DragDefault mode.
253
254 The function returns true if the caller should delete the original
255 copy of the dragged data (but see target()); otherwise returns
256 false.
257
258 If the drag contains \e references to information (e.g. file names
259 in a Q3UriDrag are references) then the return value should always
260 be ignored, as the target is expected to directly manipulate the
261 content referred to by the drag object. On X11 the return value should
262 always be correct anyway, but on Windows this is not necessarily
263 the case; e.g. the file manager starts a background process to
264 move files, so the source \e{must not} delete the files!
265
266 Note that on Windows the drag operation will start a blocking modal
267 event loop that will not dispatch any QTimers.
268*/
269bool Q3DragObject::drag()
270{
271 return drag(DragDefault);
272}
273
274/*!
275 After the drag completes, this function will return the QWidget
276 which received the drop, or 0 if the data was dropped on another
277 application.
278
279 This can be useful for detecting the case where drag and drop is
280 to and from the same widget.
281*/
282QWidget *Q3DragObject::target()
283{
284 return last_target;
285}
286
287/*!
288 Starts a drag operation using the contents of this object, using
289 \c DragMove mode. Be sure to read the constraints described in
290 drag().
291
292 Returns true if the data was dragged as a \e move, indicating that
293 the caller should remove the original source of the data (the drag
294 object must continue to have a copy); otherwise returns false.
295
296 \sa drag() dragCopy() dragLink()
297*/
298bool Q3DragObject::dragMove()
299{
300 return drag(DragMove);
301}
302
303
304/*!
305 Starts a drag operation using the contents of this object, using
306 \c DragCopy mode. Be sure to read the constraints described in
307 drag().
308
309 \sa drag() dragMove() dragLink()
310*/
311void Q3DragObject::dragCopy()
312{
313 (void)drag(DragCopy);
314}
315
316/*!
317 Starts a drag operation using the contents of this object, using
318 \c DragLink mode. Be sure to read the constraints described in
319 drag().
320
321 \sa drag() dragCopy() dragMove()
322*/
323void Q3DragObject::dragLink()
324{
325 (void)drag(DragLink);
326}
327
328
329/*!
330 \enum Q3DragObject::DragMode
331
332 This enum describes the possible drag modes.
333
334 \value DragDefault The mode is determined heuristically.
335 \value DragCopy The data is copied.
336 \value DragMove The data is moved.
337 \value DragLink The data is linked.
338 \value DragCopyOrMove The user chooses the mode by using the
339 \key{Shift} key to switch from the default
340 copy mode to move mode.
341*/
342
343
344/*!
345 \overload
346 Starts a drag operation using the contents of this object.
347
348 At this point, the object becomes owned by Qt, not the
349 application. You should not delete the drag object or anything it
350 references. The actual transfer of data to the target application
351 will be done during future event processing - after that time the
352 drag object will be deleted.
353
354 Returns true if the dragged data was dragged as a \e move,
355 indicating that the caller should remove the original source of
356 the data (the drag object must continue to have a copy); otherwise
357 returns false.
358
359 The \a mode specifies the drag mode (see
360 \l{Q3DragObject::DragMode}.) Normally one of the simpler drag(),
361 dragMove(), or dragCopy() functions would be used instead.
362*/
363bool Q3DragObject::drag(DragMode mode)
364{
365 Q_D(Q3DragObject);
366 QDragMime *data = new QDragMime(this);
367 int i = 0;
368 const char *fmt;
369 while ((fmt = format(i))) {
370 data->setData(QLatin1String(fmt), encodedData(fmt));
371 ++i;
372 }
373
374 QDrag *drag = new QDrag(qobject_cast<QWidget *>(parent()));
375 drag->setMimeData(data);
376 drag->setPixmap(d->pixmap);
377 drag->setHotSpot(d->hot);
378
379 Qt::DropActions allowedOps;
380 Qt::DropAction defaultOp = Qt::IgnoreAction;
381 switch(mode) {
382 default:
383 case DragDefault:
384 case DragCopyOrMove:
385 allowedOps = Qt::CopyAction|Qt::MoveAction;
386 defaultOp = Qt::IgnoreAction;
387 break;
388 case DragCopy:
389 allowedOps = Qt::CopyAction;
390 defaultOp = Qt::CopyAction;
391 break;
392 case DragMove:
393 allowedOps = Qt::MoveAction;
394 defaultOp = Qt::MoveAction;
395 break;
396 case DragLink:
397 allowedOps = Qt::LinkAction;
398 defaultOp = Qt::LinkAction;
399 break;
400 }
401 bool retval = (drag->exec(allowedOps, defaultOp) == Qt::MoveAction);
402 last_target = drag->target();
403
404 return retval;
405}
406
407#endif
408
409
410/*!
411 Returns a pointer to the widget where this object originated (the drag
412 source).
413*/
414
415QWidget * Q3DragObject::source()
416{
417 if (parent() && parent()->isWidgetType())
418 return (QWidget *)parent();
419 else
420 return 0;
421}
422
423
424/*!
425 \class Q3DragObject
426
427 \brief The Q3DragObject class encapsulates MIME-based data
428 transfer.
429
430 \compat
431
432 Q3DragObject is the base class for all data that needs to be
433 transferred between and within applications, both for drag and
434 drop and for the clipboard.
435
436 See the \link dnd.html Drag and drop documentation\endlink for an
437 overview of how to provide drag and drop in your application.
438
439 See the QClipboard documentation for an overview of how to provide
440 cut and paste in your application.
441
442 The drag() function is used to start a drag operation. You can
443 specify the \l DragMode in the call or use one of the convenience
444 functions dragCopy(), dragMove(), or dragLink(). The drag source
445 where the data originated is retrieved with source(). If the data
446 was dropped on a widget within the application, target() will
447 return a pointer to that widget. Specify the pixmap to display
448 during the drag with setPixmap().
449*/
450
451static
452void stripws(QByteArray& s)
453{
454 int f;
455 while ((f = s.indexOf(' ')) >= 0)
456 s.remove(f,1);
457}
458
459/*!
460 \class Q3TextDrag
461
462 \brief The Q3TextDrag class is a drag and drop object for
463 transferring plain and Unicode text.
464
465 \compat
466
467 Plain text is passed in a QString which may contain multiple lines
468 (i.e. may contain newline characters). The drag target will receive
469 the newlines according to the runtime environment, e.g. LF on Unix,
470 and CRLF on Windows.
471
472 Qt provides no built-in mechanism for delivering only a single-line.
473
474 For more information about drag and drop, see the Q3DragObject class
475 and the \link dnd.html drag and drop documentation\endlink.
476*/
477
478
479/*!
480 Constructs a text drag object with the given \a name, and sets its data
481 to \a text. The \a dragSource is the widget that the drag operation started
482 from.
483*/
484
485Q3TextDrag::Q3TextDrag(const QString &text, QWidget * dragSource, const char * name)
486 : Q3DragObject(*new Q3TextDragPrivate, dragSource)
487{
488 setObjectName(QLatin1String(name));
489 setText(text);
490}
491
492
493/*!
494 Constructs a default text drag object with the given \a name.
495 The \a dragSource is the widget that the drag operation started from.
496*/
497
498Q3TextDrag::Q3TextDrag(QWidget * dragSource, const char * name)
499 : Q3DragObject(*(new Q3TextDragPrivate), dragSource)
500{
501 setObjectName(QLatin1String(name));
502}
503
504/*! \internal */
505Q3TextDrag::Q3TextDrag(Q3TextDragPrivate &dd, QWidget *dragSource)
506 : Q3DragObject(dd, dragSource)
507{
508
509}
510
511/*!
512 Destroys the text drag object.
513*/
514Q3TextDrag::~Q3TextDrag()
515{
516
517}
518
519/*!
520 \fn void Q3TextDrag::setSubtype(const QString &subtype)
521
522 Sets the MIME \a subtype of the text being dragged. The default subtype
523 is "plain", so the default MIME type of the text is "text/plain".
524 You might use this to declare that the text is "text/html" by calling
525 setSubtype("html").
526*/
527void Q3TextDrag::setSubtype(const QString & st)
528{
529 d_func()->setSubType(st);
530}
531
532/*!
533 Sets the \a text to be dragged. You will need to call this if you did
534 not pass the text during construction.
535*/
536void Q3TextDrag::setText(const QString &text)
537{
538 d_func()->txt = text;
539}
540
541
542/*!
543 \reimp
544*/
545const char * Q3TextDrag::format(int i) const
546{
547 if (i > 0)
548 return 0;
549 return d_func()->fmt.constData();
550}
551
552QTextCodec* qt_findcharset(const QByteArray& mimetype)
553{
554 int i=mimetype.indexOf("charset=");
555 if (i >= 0) {
556 QByteArray cs = mimetype.mid(i+8);
557 stripws(cs);
558 i = cs.indexOf(';');
559 if (i >= 0)
560 cs = cs.left(i);
561 // win98 often has charset=utf16, and we need to get the correct codec for
562 // it to be able to get Unicode text drops.
563 if (cs == "utf16")
564 cs = "ISO-10646-UCS-2";
565 // May return 0 if unknown charset
566 return QTextCodec::codecForName(cs);
567 }
568 // no charset=, use locale
569 return QTextCodec::codecForName("utf-8");
570}
571
572static QTextCodec *codecForHTML(const QByteArray &ba)
573{
574 // determine charset
575 int mib = 0;
576 int pos;
577 QTextCodec *c = 0;
578
579 if (ba.size() > 1 && (((uchar)ba[0] == 0xfe && (uchar)ba[1] == 0xff)
580 || ((uchar)ba[0] == 0xff && (uchar)ba[1] == 0xfe))) {
581 mib = 1015; // utf16
582 } else if (ba.size() > 2
583 && (uchar)ba[0] == 0xef
584 && (uchar)ba[1] == 0xbb
585 && (uchar)ba[2] == 0xbf) {
586 mib = 106; // utf-8
587 } else {
588 pos = 0;
589 while ((pos = ba.indexOf('<', pos)) != -1) {
590 int end = ba.indexOf('>', pos+1);
591 if (end == -1)
592 break;
593 const QString str(QString::fromLatin1(ba.mid(pos, end-pos)));
594 if (str.contains(QLatin1String("meta http-equiv="), Qt::CaseInsensitive)) {
595 pos = str.indexOf(QLatin1String("charset="), 0, Qt::CaseInsensitive) + int(strlen("charset="));
596 if (pos != -1) {
597 int pos2 = ba.indexOf('\"', pos+1);
598 QByteArray cs = ba.mid(pos, pos2-pos);
599 c = QTextCodec::codecForName(cs);
600 if (c)
601 return c;
602 }
603 }
604 pos = end;
605 }
606 }
607 if (mib)
608 c = QTextCodec::codecForMib(mib);
609
610 return c;
611}
612
613static
614QTextCodec* findcodec(const QMimeSource* e)
615{
616 QTextCodec* r = 0;
617 const char* f;
618 int i;
619 for (i=0; (f=e->format(i)); i++) {
620 bool html = !qstrnicmp(f, "text/html", 9);
621 if (html)
622 r = codecForHTML(e->encodedData(f));
623 if (!r)
624 r = qt_findcharset(QByteArray(f).toLower());
625 if (r)
626 return r;
627 }
628 return 0;
629}
630
631
632
633/*!
634 \reimp
635*/
636QByteArray Q3TextDrag::encodedData(const char* mime) const
637{
638 Q_D(const Q3TextDrag);
639 if (mime != d->fmt)
640 return QByteArray();
641 return d->txt.toUtf8();
642}
643
644/*!
645 \fn bool Q3TextDrag::canDecode(const QMimeSource *source)
646
647 Returns true if the information in the MIME \a source can be decoded
648 into a QString; otherwise returns false.
649
650 \sa decode()
651*/
652bool Q3TextDrag::canDecode(const QMimeSource* e)
653{
654 const char* f;
655 for (int i=0; (f=e->format(i)); i++) {
656 if (0==qstrnicmp(f,"text/",5)) {
657 return findcodec(e) != 0;
658 }
659 }
660 return false;
661}
662
663/*!
664 \fn bool Q3TextDrag::decode(const QMimeSource *source, QString &string, QString &subtype)
665
666 \overload
667
668 Attempts to decode the dropped information in the MIME \a source into
669 the \a string given.
670 Returns true if successful; otherwise returns false. If \a subtype
671 is null, any text subtype is accepted; otherwise only the
672 specified \a subtype is accepted.
673
674 \sa canDecode()
675*/
676bool Q3TextDrag::decode(const QMimeSource* e, QString& str, QString& subtype)
677{
678 if(!e)
679 return false;
680
681 const char* mime;
682 for (int i=0; (mime = e->format(i)); i++) {
683 if (0==qstrnicmp(mime,"text/",5)) {
684 QByteArray m(mime);
685 m = m.toLower();
686 int semi = m.indexOf(';');
687 if (semi < 0)
688 semi = m.length();
689 QString foundst(QString::fromLatin1(m.mid(5,semi-5)));
690 if (subtype.isNull() || foundst == subtype) {
691 bool html = !qstrnicmp(mime, "text/html", 9);
692 QTextCodec* codec = 0;
693 if (html)
694 // search for the charset tag in the HTML
695 codec = codecForHTML(e->encodedData(mime));
696 if (!codec)
697 codec = qt_findcharset(m);
698 if (codec) {
699 QByteArray payload;
700
701 payload = e->encodedData(mime);
702 if (payload.size()) {
703 int l;
704 if (codec->mibEnum() != 1015) {
705 // length is at NUL or payload.size()
706 l = 0;
707 while (l < (int)payload.size() && payload[l])
708 l++;
709 } else {
710 l = payload.size();
711 }
712
713 str = codec->toUnicode(payload,l);
714
715 if (subtype.isNull())
716 subtype = foundst;
717
718 return true;
719 }
720 }
721 }
722 }
723 }
724 return false;
725}
726
727/*!
728 \fn bool Q3TextDrag::decode(const QMimeSource *source, QString &string)
729
730 Attempts to decode the dropped information in the MIME \a source into
731 the \a string given.
732 Returns true if successful; otherwise returns false.
733
734 \sa canDecode()
735*/
736bool Q3TextDrag::decode(const QMimeSource* e, QString& str)
737{
738 QString st;
739 return decode(e, str, st);
740}
741
742
743/*
744 Q3ImageDrag could use an internal MIME type for communicating QPixmaps
745 and QImages rather than always converting to raw data. This is available
746 for that purpose and others. It is not currently used.
747*/
748
749/*!
750 \class Q3ImageDrag
751
752 \brief The Q3ImageDrag class provides a drag and drop object for
753 transferring images.
754
755 \compat
756
757 Images are offered to the receiving application in multiple
758 formats, determined by Qt's output formats.
759*/
760
761/*!
762 Constructs an image drag object with the given \a name, and sets its
763 data to \a image. The \a dragSource is the widget that the drag operation
764 started from.
765*/
766
767Q3ImageDrag::Q3ImageDrag(QImage image,
768 QWidget * dragSource, const char * name)
769 : Q3DragObject(*(new Q3ImageDragPrivate), dragSource)
770{
771 setObjectName(QLatin1String(name));
772 setImage(image);
773}
774
775/*!
776 Constructs a default image drag object with the given \a name.
777 The \a dragSource is the widget that the drag operation started from.
778*/
779
780Q3ImageDrag::Q3ImageDrag(QWidget * dragSource, const char * name)
781 : Q3DragObject(*(new Q3ImageDragPrivate), dragSource)
782{
783 setObjectName(QLatin1String(name));
784}
785
786/*! \internal */
787Q3ImageDrag::Q3ImageDrag(Q3ImageDragPrivate &dd, QWidget *dragSource)
788 : Q3DragObject(dd, dragSource)
789{
790}
791
792/*!
793 Destroys the image drag object.
794*/
795
796Q3ImageDrag::~Q3ImageDrag()
797{
798 // nothing
799}
800
801
802/*!
803 Sets the \a image to be dragged. You will need to call this if you did
804 not pass the image during construction.
805*/
806void Q3ImageDrag::setImage(QImage image)
807{
808 Q_D(Q3ImageDrag);
809 d->img = image;
810 QList<QByteArray> formats = QImageWriter::supportedImageFormats();
811 formats.removeAll("PBM"); // remove non-raw PPM
812 if (image.depth()!=32) {
813 // BMP better than PPM for paletted images
814 if (formats.removeAll("BMP")) // move to front
815 formats.insert(0,"BMP");
816 }
817 // PNG is best of all
818 if (formats.removeAll("PNG")) // move to front
819 formats.insert(0,"PNG");
820
821 for(int i = 0; i < formats.count(); i++) {
822 QByteArray format("image/");
823 format += formats.at(i);
824 format = format.toLower();
825 if (format == "image/pbmraw")
826 format = "image/ppm";
827 d->ofmts.append(format);
828 }
829 d->ofmts.append("application/x-qt-image");
830}
831
832/*!
833 \reimp
834*/
835const char * Q3ImageDrag::format(int i) const
836{
837 Q_D(const Q3ImageDrag);
838 return i < d->ofmts.count() ? d->ofmts.at(i).data() : 0;
839}
840
841/*!
842 \reimp
843*/
844QByteArray Q3ImageDrag::encodedData(const char* fmt) const
845{
846 Q_D(const Q3ImageDrag);
847 QString imgFormat(fmt);
848 if (imgFormat == QLatin1String("application/x-qt-image"))
849 imgFormat = QLatin1String("image/PNG");
850
851 if (imgFormat.startsWith("image/")){
852 QByteArray f(imgFormat.mid(6).toAscii());
853 QByteArray dat;
854 QBuffer w(&dat);
855 w.open(QIODevice::WriteOnly);
856 QImageWriter writer(&w, f.toUpper());
857 if (!writer.write(d->img))
858 return QByteArray();
859 w.close();
860 return dat;
861 } else {
862 return QByteArray();
863 }
864}
865
866/*!
867 \fn bool Q3ImageDrag::canDecode(const QMimeSource *source)
868
869 Returns true if the information in the MIME \a source can be decoded
870 into an image; otherwise returns false.
871
872 \sa decode()
873*/
874bool Q3ImageDrag::canDecode(const QMimeSource* e)
875{
876 return e->provides("application/x-qt-image");
877}
878
879/*!
880 \fn bool Q3ImageDrag::decode(const QMimeSource *source, QImage &image)
881
882 Decode the dropped information in the MIME \a source into the \a image.
883 Returns true if successful; otherwise returns false.
884
885 \sa canDecode()
886*/
887bool Q3ImageDrag::decode(const QMimeSource* e, QImage& img)
888{
889 if (!e)
890 return false;
891
892 QByteArray payload = e->encodedData("application/x-qt-image");
893 if (payload.isEmpty())
894 return false;
895
896 img.loadFromData(payload);
897 if (img.isNull())
898 return false;
899
900 return true;
901}
902
903/*!
904 \fn bool Q3ImageDrag::decode(const QMimeSource *source, QPixmap &pixmap)
905
906 \overload
907
908 Decodes the dropped information in the MIME \a source into the \a pixmap.
909 Returns true if successful; otherwise returns false.
910
911 This is a convenience function that converts the information to a QPixmap
912 via a QImage.
913
914 \sa canDecode()
915*/
916bool Q3ImageDrag::decode(const QMimeSource* e, QPixmap& pm)
917{
918 if (!e)
919 return false;
920
921 QImage img;
922 // We avoid dither, since the image probably came from this display
923 if (decode(e, img)) {
924 pm = QPixmap::fromImage(img, Qt::AvoidDither);
925 if (pm.isNull())
926 return false;
927
928 return true;
929 }
930 return false;
931}
932
933
934
935
936/*!
937 \class Q3StoredDrag
938 \brief The Q3StoredDrag class provides a simple stored-value drag object for arbitrary MIME data.
939
940 \compat
941
942 When a block of data has only one representation, you can use a
943 Q3StoredDrag to hold it.
944
945 For more information about drag and drop, see the Q3DragObject
946 class and the \link dnd.html drag and drop documentation\endlink.
947*/
948
949/*!
950 Constructs a Q3StoredDrag. The \a dragSource and \a name are passed
951 to the Q3DragObject constructor, and the format is set to \a
952 mimeType.
953
954 The data will be unset. Use setEncodedData() to set it.
955*/
956Q3StoredDrag::Q3StoredDrag(const char* mimeType, QWidget * dragSource, const char * name) :
957 Q3DragObject(*new Q3StoredDragPrivate, dragSource)
958{
959 Q_D(Q3StoredDrag);
960 setObjectName(QLatin1String(name));
961 d->fmt = qstrdup(mimeType);
962}
963
964/*! \internal */
965Q3StoredDrag::Q3StoredDrag(Q3StoredDragPrivate &dd, const char* mimeType, QWidget * dragSource)
966 : Q3DragObject(dd, dragSource)
967{
968 d_func()->fmt = qstrdup(mimeType);
969}
970
971/*!
972 Destroys the drag object.
973*/
974Q3StoredDrag::~Q3StoredDrag()
975{
976 delete [] (char*)d_func()->fmt;
977}
978
979/*!
980 \reimp
981*/
982const char * Q3StoredDrag::format(int i) const
983{
984 if (i==0)
985 return d_func()->fmt;
986 else
987 return 0;
988}
989
990
991/*!
992 \fn void Q3StoredDrag::setEncodedData(const QByteArray &data)
993
994 Sets the encoded \a data of this drag object. The encoded data is
995 delivered to drop sites; it must be in a strictly defined and portable
996 format.
997
998 The drag object can't be dropped (by the user) until this function
999 has been called.
1000*/
1001
1002void Q3StoredDrag::setEncodedData(const QByteArray & encodedData)
1003{
1004 d_func()->enc = encodedData;
1005}
1006
1007/*!
1008 \fn QByteArray Q3StoredDrag::encodedData(const char *format) const
1009
1010 Returns the stored data in the \a format given.
1011
1012 \sa setEncodedData()
1013*/
1014QByteArray Q3StoredDrag::encodedData(const char* m) const
1015{
1016 if (!qstricmp(m, d_func()->fmt))
1017 return d_func()->enc;
1018 else
1019 return QByteArray();
1020}
1021
1022
1023/*!
1024 \class Q3UriDrag
1025 \brief The Q3UriDrag class provides a drag object for a list of URI references.
1026
1027 \compat
1028
1029 URIs are a useful way to refer to files that may be distributed
1030 across multiple machines. A URI will often refer to a file on a
1031 machine local to both the drag source and the drop target, so the
1032 URI can be equivalent to passing a file name but is more
1033 extensible.
1034
1035 Use URIs in Unicode form so that the user can comfortably edit and
1036 view them. For use in HTTP or other protocols, use the correctly
1037 escaped ASCII form.
1038
1039 You can convert a list of file names to file URIs using
1040 setFileNames(), or into human-readable form with setUnicodeUris().
1041
1042 Static functions are provided to convert between filenames and
1043 URIs; e.g. uriToLocalFile() and localFileToUri(). Static functions
1044 are also provided to convert URIs to and from human-readable form;
1045 e.g. uriToUnicodeUri() and unicodeUriToUri().
1046 You can also decode URIs from a MIME source into a list with
1047 decodeLocalFiles() and decodeToUnicodeUris().
1048*/
1049
1050/*!
1051 Constructs an object to drag the list of \a uris.
1052 The \a dragSource and \a name are passed to the Q3StoredDrag constructor.
1053
1054 Note that URIs are always in escaped UTF8 encoding.
1055*/
1056Q3UriDrag::Q3UriDrag(const Q3StrList &uris, QWidget * dragSource, const char * name) :
1057 Q3StoredDrag("text/uri-list", dragSource)
1058{
1059 setObjectName(QLatin1String(name));
1060 setUris(uris);
1061}
1062
1063/*!
1064 Constructs an object to drag with the given \a name.
1065 You must call setUris() before you start the drag().
1066 Both the \a dragSource and the \a name are passed to the Q3StoredDrag
1067 constructor.
1068*/
1069Q3UriDrag::Q3UriDrag(QWidget * dragSource, const char * name) :
1070 Q3StoredDrag("text/uri-list", dragSource)
1071{
1072 setObjectName(QLatin1String(name));
1073}
1074#endif
1075
1076/*!
1077 Destroys the URI drag object.
1078*/
1079Q3UriDrag::~Q3UriDrag()
1080{
1081}
1082
1083/*!
1084 \fn void Q3UriDrag::setUris(const QList<QByteArray> &list)
1085
1086 Changes the \a list of URIs to be dragged.
1087
1088 Note that URIs are always in escaped UTF8 encoding.
1089*/
1090void Q3UriDrag::setUris(const QList<QByteArray> &uris)
1091{
1092 QByteArray a;
1093 int c = 0;
1094 int i;
1095 int count = uris.count();
1096 for (i = 0; i < count; ++i)
1097 c += uris.at(i).size() + 2; //length + \r\n
1098 a.reserve(c+1);
1099 for (i = 0; i < count; ++i) {
1100 a.append(uris.at(i));
1101 a.append("\r\n");
1102 }
1103 a[c] = 0;
1104 setEncodedData(a);
1105}
1106
1107
1108/*!
1109 \fn bool Q3UriDrag::canDecode(const QMimeSource *source)
1110
1111 Returns true if decode() can decode the MIME \a source; otherwise
1112 returns false.
1113*/
1114bool Q3UriDrag::canDecode(const QMimeSource* e)
1115{
1116 return e->provides("text/uri-list");
1117}
1118
1119/*!
1120 \fn bool Q3UriDrag::decode(const QMimeSource* source, Q3StrList& list)
1121
1122 Decodes URIs from the MIME \a source, placing the result in the \a list.
1123 The list is cleared before any items are inserted.
1124
1125 Returns true if the MIME \a source contained a valid list of URIs;
1126 otherwise returns false.
1127*/
1128bool Q3UriDrag::decode(const QMimeSource* e, Q3StrList& l)
1129{
1130 QByteArray payload = e->encodedData("text/uri-list");
1131 if (payload.size()) {
1132 l.clear();
1133 l.setAutoDelete(true);
1134 uint c=0;
1135 const char* data = payload.data();
1136 while ((int)c < payload.size() && data[c]) {
1137 uint f = c;
1138 // Find line end
1139 while ((int)c < payload.size() && data[c] && data[c]!='\r'
1140 && data[c] != '\n')
1141 c++;
1142 Q3CString s(data+f,c-f+1);
1143 if (s[0] != '#') // non-comment?
1144 l.append(s);
1145 // Skip junk
1146 while ((int)c < payload.size() && data[c] &&
1147 (data[c]=='\n' || data[c]=='\r'))
1148 c++;
1149 }
1150 return true;
1151 }
1152 return false;
1153}
1154
1155static uint htod(int h)
1156{
1157 if (isdigit(h))
1158 return h - '0';
1159 return tolower(h) - 'a' + 10;
1160}
1161
1162/*!
1163 \fn Q3UriDrag::setFilenames(const QStringList &list)
1164
1165 \obsolete
1166
1167 Sets the filename's in the drag object to those in the given \a
1168 list.
1169
1170 Use setFileNames() instead.
1171*/
1172
1173/*!
1174 \fn void Q3UriDrag::setFileNames(const QStringList &filenames)
1175
1176 Sets the URIs to be local file URIs equivalent to the \a filenames.
1177
1178 \sa localFileToUri(), setUris()
1179*/
1180void Q3UriDrag::setFileNames(const QStringList & fnames)
1181{
1182 QList<QByteArray> uris;
1183 for (QStringList::ConstIterator i = fnames.begin();
1184 i != fnames.end(); ++i) {
1185 QByteArray fileUri = localFileToUri(*i);
1186 if (!fileUri.isEmpty())
1187 uris.append(fileUri);
1188 }
1189
1190 setUris(uris);
1191}
1192
1193/*!
1194 \fn void Q3UriDrag::setFileNames(const QString &name)
1195 \fn void Q3UriDrag::setFilenames(const QString &name)
1196
1197 Same as setFileNames(QStringList(\a name)).
1198*/
1199
1200/*!
1201 \fn void Q3UriDrag::setUnicodeUris(const QStringList &list)
1202
1203 Sets the URIs in the \a list to be Unicode URIs (only useful for
1204 displaying to humans).
1205
1206 \sa localFileToUri(), setUris()
1207*/
1208void Q3UriDrag::setUnicodeUris(const QStringList & uuris)
1209{
1210 QList<QByteArray> uris;
1211 for (int i = 0; i < uuris.count(); ++i)
1212 uris.append(unicodeUriToUri(uuris.at(i)));
1213 setUris(uris);
1214}
1215
1216/*!
1217 \fn QByteArray Q3UriDrag::unicodeUriToUri(const QString &string)
1218
1219 Returns the URI equivalent of the Unicode URI given in the \a string
1220 (only useful for displaying to humans).
1221
1222 \sa uriToLocalFile()
1223*/
1224QByteArray Q3UriDrag::unicodeUriToUri(const QString& uuri)
1225{
1226 QByteArray utf8 = uuri.toUtf8();
1227 QByteArray escutf8;
1228 int n = utf8.length();
1229 bool isFile = uuri.startsWith(QLatin1String("file://"));
1230 for (int i=0; i<n; i++) {
1231 if ((utf8[i] >= 'a' && utf8[i] <= 'z')
1232 || utf8[i] == '/'
1233 || (utf8[i] >= '0' && utf8[i] <= '9')
1234 || (utf8[i] >= 'A' && utf8[i] <= 'Z')
1235
1236 || utf8[i] == '-' || utf8[i] == '_'
1237 || utf8[i] == '.' || utf8[i] == '!'
1238 || utf8[i] == '~' || utf8[i] == '*'
1239 || utf8[i] == '(' || utf8[i] == ')'
1240 || utf8[i] == '\''
1241
1242 // Allow this through, so that all URI-references work.
1243 || (!isFile && utf8[i] == '#')
1244
1245 || utf8[i] == ';'
1246 || utf8[i] == '?' || utf8[i] == ':'
1247 || utf8[i] == '@' || utf8[i] == '&'
1248 || utf8[i] == '=' || utf8[i] == '+'
1249 || utf8[i] == '$' || utf8[i] == ',')
1250 {
1251 escutf8 += utf8[i];
1252 } else {
1253 // Everything else is escaped as %HH
1254 QString s;
1255 s.sprintf("%%%02x",(uchar)utf8[i]);
1256 escutf8 += s.latin1();
1257 }
1258 }
1259 return escutf8;
1260}
1261
1262/*!
1263 Returns the URI equivalent to the absolute local \a filename.
1264
1265 \sa uriToLocalFile()
1266*/
1267QByteArray Q3UriDrag::localFileToUri(const QString& filename)
1268{
1269 QString r = filename;
1270
1271 //check that it is an absolute file
1272 if (QDir::isRelativePath(r))
1273 return QByteArray();
1274#ifdef Q_WS_WIN
1275
1276
1277 bool hasHost = false;
1278 // convert form network path
1279 if (r.left(2) == QLatin1String("\\\\") || r.left(2) == QLatin1String("//")) {
1280 r.remove(0, 2);
1281 hasHost = true;
1282 }
1283
1284 // Slosh -> Slash
1285 int slosh;
1286 while ((slosh=r.indexOf(QLatin1Char('\\'))) >= 0) {
1287 r[slosh] = QLatin1Char('/');
1288 }
1289
1290 // Drive
1291 if (r[0] != QLatin1Char('/') && !hasHost)
1292 r.insert(0,QLatin1Char('/'));
1293
1294#endif
1295#if defined (Q_WS_X11) && 0
1296 // URL without the hostname is considered to be errorneous by XDnD.
1297 // See: http://www.newplanetsoftware.com/xdnd/dragging_files.html
1298 // This feature is not active because this would break dnd between old and new qt apps.
1299 char hostname[257];
1300 if (gethostname(hostname, 255) == 0) {
1301 hostname[256] = '\0';
1302 r.prepend(QString::fromLatin1(hostname));
1303 }
1304#endif
1305 return unicodeUriToUri(QString(QLatin1String("file://") + r));
1306}
1307
1308/*!
1309 \fn QString Q3UriDrag::uriToUnicodeUri(const char *string)
1310
1311 Returns the Unicode URI (only useful for displaying to humans)
1312 equivalent of the URI given in the \a string.
1313
1314 Note that URIs are always in escaped UTF8 encoding.
1315
1316 \sa localFileToUri()
1317*/
1318QString Q3UriDrag::uriToUnicodeUri(const char* uri)
1319{
1320 QByteArray utf8;
1321
1322 while (*uri) {
1323 switch (*uri) {
1324 case '%': {
1325 uint ch = (uchar) uri[1];
1326 if (ch && uri[2]) {
1327 ch = htod(ch) * 16 + htod((uchar) uri[2]);
1328 utf8 += (char) ch;
1329 uri += 2;
1330 }
1331 }
1332 break;
1333 default:
1334 utf8 += *uri;
1335 }
1336 ++uri;
1337 }
1338
1339 return QString::fromUtf8(utf8);
1340}
1341
1342/*!
1343 \fn QString Q3UriDrag::uriToLocalFile(const char *string)
1344
1345 Returns the name of a local file equivalent to the URI given in the
1346 \a string, or an empty string if it does not refer to a local file.
1347
1348 Note that URIs are always in escaped UTF8 encoding.
1349
1350 \sa localFileToUri()
1351*/
1352QString Q3UriDrag::uriToLocalFile(const char* uri)
1353{
1354 QString file;
1355
1356 if (!uri)
1357 return file;
1358 if (0==qstrnicmp(uri,"file:/",6)) // It is a local file uri
1359 uri += 6;
1360 else if (QString(QLatin1String(uri)).indexOf(QLatin1String(":/")) != -1) // It is a different scheme uri
1361 return file;
1362
1363 bool local = uri[0] != '/' || (uri[0] != '\0' && uri[1] == '/');
1364#ifdef Q_WS_X11
1365 // do we have a hostname?
1366 if (!local && uri[0] == '/' && uri[2] != '/') {
1367 // then move the pointer to after the 'hostname/' part of the uri
1368 const char* hostname_end = strchr(uri+1, '/');
1369 if (hostname_end != NULL) {
1370 char hostname[257];
1371 if (gethostname(hostname, 255) == 0) {
1372 hostname[256] = '\0';
1373 if (qstrncmp(uri+1, hostname, hostname_end - (uri+1)) == 0) {
1374 uri = hostname_end + 1; // point after the slash
1375 local = true;
1376 }
1377 }
1378 }
1379 }
1380#endif
1381 if (local) {
1382 file = uriToUnicodeUri(uri);
1383 if (uri[1] == '/') {
1384 file.remove((uint)0,1);
1385 } else {
1386 file.insert(0, QLatin1Char('/'));
1387 }
1388#ifdef Q_WS_WIN
1389 if (file.length() > 2 && file[0] == QLatin1Char('/') && file[2] == QLatin1Char('|')) {
1390 file[2] = QLatin1Char(':');
1391 file.remove(0,1);
1392 } else if (file.length() > 2 && file[0] == QLatin1Char('/') && file[1].isLetter() && file[2] == QLatin1Char(':')) {
1393 file.remove(0, 1);
1394 }
1395 // Leave slash as slashes.
1396#endif
1397 }
1398#ifdef Q_WS_WIN
1399 else {
1400 file = uriToUnicodeUri(uri);
1401 // convert to network path
1402 file.insert(1, QLatin1Char('/')); // leave as forward slashes
1403 }
1404#endif
1405
1406 return file;
1407}
1408
1409/*!
1410 \fn bool Q3UriDrag::decodeLocalFiles(const QMimeSource *source, QStringList &list)
1411
1412 Decodes URIs from the MIME \a source, converting them to local filenames
1413 where possible, and places them in the \a list (which is first cleared).
1414
1415 Returns true if the MIME \a source contained a valid list of URIs;
1416 otherwise returns false. The list will be empty if no URIs referred to
1417 local files.
1418*/
1419bool Q3UriDrag::decodeLocalFiles(const QMimeSource* e, QStringList& l)
1420{
1421 Q3StrList u;
1422 if (!decode(e, u))
1423 return false;
1424
1425 l.clear();
1426 for (uint i = 0; i < u.count(); ++i) {
1427 QString lf = uriToLocalFile(u.at(i));
1428 if (!lf.isEmpty())
1429 l.append(lf);
1430 }
1431 return true;
1432}
1433
1434/*!
1435 \fn bool Q3UriDrag::decodeToUnicodeUris(const QMimeSource *source, QStringList &list)
1436
1437 Decodes URIs from the MIME \a source, converting them to Unicode URIs
1438 (only useful for displaying to humans), and places them in the \a list
1439 (which is first cleared).
1440
1441 Returns true if the MIME \a source contained a valid list of URIs;
1442 otherwise returns false.
1443*/
1444bool Q3UriDrag::decodeToUnicodeUris(const QMimeSource* e, QStringList& l)
1445{
1446 Q3StrList u;
1447 if (!decode(e, u))
1448 return false;
1449
1450 l.clear();
1451 for (uint i = 0; i < u.count(); ++i)
1452 l.append(uriToUnicodeUri(u.at(i)));
1453
1454 return true;
1455}
1456
1457/*!
1458 \class Q3ColorDrag
1459
1460 \brief The Q3ColorDrag class provides a drag and drop object for
1461 transferring colors between widgets.
1462
1463 \compat
1464
1465 This class provides a drag object which can be used to transfer data
1466 about colors for drag and drop and in the clipboard. For example, it
1467 is used in QColorDialog.
1468
1469 The color is set in the constructor but can be changed with
1470 setColor().
1471
1472 For more information about drag and drop, see the Q3DragObject class
1473 and the \link dnd.html drag and drop documentation\endlink.
1474*/
1475
1476/*!
1477 Constructs a color drag object with the given \a col. Passes \a
1478 dragsource and \a name to the Q3StoredDrag constructor.
1479*/
1480
1481Q3ColorDrag::Q3ColorDrag(const QColor &col, QWidget *dragsource, const char *name)
1482 : Q3StoredDrag("application/x-color", dragsource)
1483{
1484 setObjectName(QLatin1String(name));
1485 setColor(col);
1486}
1487
1488/*!
1489 Constructs a color drag object with a white color. Passes \a
1490 dragsource and \a name to the Q3StoredDrag constructor.
1491*/
1492
1493Q3ColorDrag::Q3ColorDrag(QWidget *dragsource, const char *name)
1494 : Q3StoredDrag("application/x-color", dragsource)
1495{
1496 setObjectName(QLatin1String(name));
1497 setColor(Qt::white);
1498}
1499
1500/*!
1501 \fn void Q3ColorDrag::setColor(const QColor &color)
1502
1503 Sets the \a color of the color drag.
1504*/
1505
1506void Q3ColorDrag::setColor(const QColor &col)
1507{
1508 short r = (col.red() << 8) | col.red();
1509 short g = (col.green() << 8) | col.green();
1510 short b = (col.blue() << 8) | col.blue();
1511
1512 // make sure we transmit data in network order
1513 r = htons(r);
1514 g = htons(g);
1515 b = htons(b);
1516
1517 ushort rgba[4] = {
1518 r, g, b,
1519 0xffff // Alpha not supported yet.
1520 };
1521 QByteArray data;
1522 data.resize(sizeof(rgba));
1523 memcpy(data.data(), rgba, sizeof(rgba));
1524 setEncodedData(data);
1525}
1526
1527/*!
1528 \fn bool Q3ColorDrag::canDecode(QMimeSource *source)
1529
1530 Returns true if the color drag object can decode the MIME \a source;
1531 otherwise returns false.
1532*/
1533
1534bool Q3ColorDrag::canDecode(QMimeSource *e)
1535{
1536 return e->provides("application/x-color");
1537}
1538
1539/*!
1540 \fn bool Q3ColorDrag::decode(QMimeSource *source, QColor &color)
1541
1542 Decodes the MIME \a source, and sets the decoded values to the
1543 given \a color. Returns true if the decoding is successful.
1544 Returns false if the size of the encoded data is not the
1545 expected size.
1546*/
1547
1548bool Q3ColorDrag::decode(QMimeSource *e, QColor &col)
1549{
1550 QByteArray data = e->encodedData("application/x-color");
1551 ushort rgba[4];
1552 if (data.size() != sizeof(rgba))
1553 return false;
1554
1555 memcpy(rgba, data.constData(), sizeof(rgba));
1556
1557 short r = rgba[0];
1558 short g = rgba[1];
1559 short b = rgba[2];
1560 short a = rgba[3];
1561
1562 // data is in network order
1563 r = ntohs(r);
1564 g = ntohs(g);
1565 b = ntohs(b);
1566 a = ntohs(a);
1567
1568 r = (r >> 8) & 0xff;
1569 g = (g >> 8) & 0xff;
1570 b = (b >> 8) & 0xff;
1571 a = (a >> 8) & 0xff;
1572
1573 col.setRgb(r, g, b, a);
1574 return true;
1575}
1576
1577QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.