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

Last change on this file since 807 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

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