src/qt3support/other/q3dragobject.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/qt3support/other/q3dragobject.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,1567 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt3Support module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qplatformdefs.h"
+
+#ifndef QT_NO_MIME
+
+#include "q3dragobject.h"
+#include "qpixmap.h"
+#include "qevent.h"
+#include "qfile.h"
+#include "qtextcodec.h"
+#include "qapplication.h"
+#include "qpoint.h"
+#include "qwidget.h"
+#include "qbuffer.h"
+#include "qimagereader.h"
+#include "qimagewriter.h"
+#include "qimage.h"
+#include "qregexp.h"
+#include "qdir.h"
+#include "qdrag.h"
+#include "q3strlist.h"
+#include "q3cstring.h"
+
+#include <private/qobject_p.h>
+
+#include <ctype.h>
+#if defined(Q_OS_WINCE)
+#include <winsock.h>
+#include "qfunctions_wince.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+static QWidget *last_target = 0;
+
+class QDragMime;
+
+class Q3DragObjectPrivate : public QObjectPrivate
+{
+    Q_DECLARE_PUBLIC(Q3DragObject)
+public:
+    Q3DragObjectPrivate(): hot(0,0),pm_cursor(0) {}
+    QPixmap pixmap;
+    QPoint hot;
+    // store default cursors
+    QPixmap *pm_cursor;
+};
+
+class Q3TextDragPrivate : public Q3DragObjectPrivate
+{
+    Q_DECLARE_PUBLIC(Q3TextDrag)
+public:
+    Q3TextDragPrivate() { setSubType(QLatin1String("plain")); }
+    void setSubType(const QString & st) {
+        subtype = st;
+        fmt = "text/" + subtype.toLatin1();
+    }
+
+    QString txt;
+    QString subtype;
+    QByteArray fmt;
+};
+
+class Q3StoredDragPrivate : public Q3DragObjectPrivate
+{
+    Q_DECLARE_PUBLIC(Q3StoredDrag)
+public:
+    Q3StoredDragPrivate() {}
+    const char* fmt;
+    QByteArray enc;
+};
+
+class Q3ImageDragPrivate : public Q3DragObjectPrivate
+{
+    Q_DECLARE_PUBLIC(Q3ImageDrag)
+public:
+    QImage img;
+    QList<QByteArray> ofmts;
+};
+
+class QDragMime : public QMimeData
+{
+public:
+    QDragMime(Q3DragObject *parent) : QMimeData(), dragObject(parent) { }
+    ~QDragMime();
+
+    QByteArray data(const QString &mimetype) const;
+    bool hasFormat(const QString &mimetype) const;
+    QStringList formats() const;
+
+    QPointer<Q3DragObject> dragObject;
+};
+
+QDragMime::~QDragMime()
+{
+    delete dragObject;
+}
+QByteArray QDragMime::data(const QString &mimetype) const
+{
+    return dragObject->encodedData(mimetype.latin1());
+}
+
+bool QDragMime::hasFormat(const QString &mimetype) const
+{
+    return dragObject->provides(mimetype.latin1());
+}
+
+QStringList QDragMime::formats() const
+{
+    int i = 0;
+    const char *format;
+    QStringList f;
+    while ((format = dragObject->format(i))) {
+        f.append(QLatin1String(format));
+        ++i;
+    }
+    return f;
+}
+
+/*!
+    Constructs a drag object called \a name with a parent \a
+    dragSource.
+
+    Note that the drag object will be deleted when the \a dragSource is
+    deleted.
+*/
+
+Q3DragObject::Q3DragObject(QWidget * dragSource, const char * name)
+    : QObject(*(new Q3DragObjectPrivate), dragSource)
+{
+    setObjectName(QLatin1String(name));
+}
+
+/*! \internal */
+Q3DragObject::Q3DragObject(Q3DragObjectPrivate &dd, QWidget *dragSource)
+    : QObject(dd, dragSource)
+{
+}
+
+/*!
+    Destroys the drag object, canceling any drag and drop operation in
+    which it is involved.
+*/
+
+Q3DragObject::~Q3DragObject()
+{
+}
+
+#ifndef QT_NO_DRAGANDDROP
+/*!
+    Set the pixmap, \a pm, to display while dragging the object. The
+    platform-specific implementation will use this where it can - so
+    provide a small masked pixmap, and do not assume that the user
+    will actually see it.
+
+    The \a hotspot is the point on (or off) the pixmap that should be
+    under the cursor as it is dragged. It is relative to the top-left
+    pixel of the pixmap.
+
+    \warning We have seen problems with drag cursors on different
+    graphics hardware and driver software on Windows. Setting the
+    graphics acceleration in the display settings down one tick solved
+    the problems in all cases.
+*/
+void Q3DragObject::setPixmap(QPixmap pm, const QPoint& hotspot)
+{
+    Q_D(Q3DragObject);
+    d->pixmap = pm;
+    d->hot = hotspot;
+}
+
+/*!
+    \overload
+
+    Uses a hotspot that positions the pixmap below and to the right of
+    the mouse pointer. This allows the user to clearly see the point
+    on the window where they are dragging the data.
+*/
+void Q3DragObject::setPixmap(QPixmap pm)
+{
+    setPixmap(pm,QPoint(-10, -10));
+}
+
+/*!
+    Returns the currently set pixmap, or a null pixmap if none is set.
+
+    \sa QPixmap::isNull()
+*/
+QPixmap Q3DragObject::pixmap() const
+{
+    return d_func()->pixmap;
+}
+
+/*!
+    Returns the currently set pixmap hotspot.
+
+    \sa setPixmap()
+*/
+QPoint Q3DragObject::pixmapHotSpot() const
+{
+    return d_func()->hot;
+}
+
+/*!
+    Starts a drag operation using the contents of this object, using
+    DragDefault mode.
+
+    The function returns true if the caller should delete the original
+    copy of the dragged data (but see target()); otherwise returns
+    false.
+
+    If the drag contains \e references to information (e.g. file names
+    in a Q3UriDrag are references) then the return value should always
+    be ignored, as the target is expected to directly manipulate the
+    content referred to by the drag object. On X11 the return value should
+    always be correct anyway, but on Windows this is not necessarily
+    the case; e.g. the file manager starts a background process to
+    move files, so the source \e{must not} delete the files!
+
+    Note that on Windows the drag operation will start a blocking modal
+    event loop that will not dispatch any QTimers.
+*/
+bool Q3DragObject::drag()
+{
+    return drag(DragDefault);
+}
+
+/*!
+    After the drag completes, this function will return the QWidget
+   which received the drop, or 0 if the data was dropped on another
+    application.
+
+    This can be useful for detecting the case where drag and drop is
+    to and from the same widget.
+*/
+QWidget *Q3DragObject::target()
+{
+    return last_target;
+}
+
+/*!
+    Starts a drag operation using the contents of this object, using
+    \c DragMove mode. Be sure to read the constraints described in
+    drag().
+
+    Returns true if the data was dragged as a \e move, indicating that
+    the caller should remove the original source of the data (the drag
+    object must continue to have a copy); otherwise returns false.
+
+    \sa drag() dragCopy() dragLink()
+*/
+bool Q3DragObject::dragMove()
+{
+    return drag(DragMove);
+}
+
+
+/*!
+    Starts a drag operation using the contents of this object, using
+    \c DragCopy mode. Be sure to read the constraints described in
+    drag().
+
+    \sa drag() dragMove() dragLink()
+*/
+void Q3DragObject::dragCopy()
+{
+    (void)drag(DragCopy);
+}
+
+/*!
+    Starts a drag operation using the contents of this object, using
+    \c DragLink mode. Be sure to read the constraints described in
+    drag().
+
+    \sa drag() dragCopy() dragMove()
+*/
+void Q3DragObject::dragLink()
+{
+    (void)drag(DragLink);
+}
+
+
+/*!
+    \enum Q3DragObject::DragMode
+
+    This enum describes the possible drag modes.
+
+    \value DragDefault     The mode is determined heuristically.
+    \value DragCopy        The data is copied.
+    \value DragMove        The data is moved.
+    \value DragLink        The data is linked.
+    \value DragCopyOrMove  The user chooses the mode by using the
+                           \key{Shift} key to switch from the default
+                           copy mode to move mode.
+*/
+
+
+/*!
+    \overload
+    Starts a drag operation using the contents of this object.
+
+    At this point, the object becomes owned by Qt, not the
+    application. You should not delete the drag object or anything it
+    references. The actual transfer of data to the target application
+    will be done during future event processing - after that time the
+    drag object will be deleted.
+
+    Returns true if the dragged data was dragged as a \e move,
+    indicating that the caller should remove the original source of
+    the data (the drag object must continue to have a copy); otherwise
+    returns false.
+
+    The \a mode specifies the drag mode (see
+    \l{Q3DragObject::DragMode}.) Normally one of the simpler drag(),
+    dragMove(), or dragCopy() functions would be used instead.
+*/
+bool Q3DragObject::drag(DragMode mode)
+{
+    Q_D(Q3DragObject);
+    QDragMime *data = new QDragMime(this);
+    int i = 0;
+    const char *fmt;
+    while ((fmt = format(i))) {
+        data->setData(QLatin1String(fmt), encodedData(fmt));
+        ++i;
+    }
+
+    QDrag *drag = new QDrag(qobject_cast<QWidget *>(parent()));
+    drag->setMimeData(data);
+    drag->setPixmap(d->pixmap);
+    drag->setHotSpot(d->hot);
+
+    Qt::DropActions allowedOps;
+    Qt::DropAction defaultOp = Qt::IgnoreAction;
+    switch(mode) {
+    default:
+    case DragDefault:
+    case DragCopyOrMove:
+        allowedOps = Qt::CopyAction|Qt::MoveAction;
+        defaultOp = Qt::IgnoreAction;
+        break;
+    case DragCopy:
+        allowedOps = Qt::CopyAction;
+        defaultOp = Qt::CopyAction;
+        break;
+    case DragMove:
+        allowedOps = Qt::MoveAction;
+        defaultOp = Qt::MoveAction;
+        break;
+    case DragLink:
+        allowedOps = Qt::LinkAction;
+        defaultOp = Qt::LinkAction;
+        break;
+    }
+    bool retval = (drag->exec(allowedOps, defaultOp) == Qt::MoveAction);
+    last_target = drag->target();
+
+    return retval;
+}
+
+#endif
+
+
+/*!
+    Returns a pointer to the widget where this object originated (the drag
+    source).
+*/
+
+QWidget * Q3DragObject::source()
+{
+    if (parent() && parent()->isWidgetType())
+        return (QWidget *)parent();
+    else
+        return 0;
+}
+
+
+/*!
+    \class Q3DragObject
+
+    \brief The Q3DragObject class encapsulates MIME-based data
+    transfer.
+
+    \compat
+
+    Q3DragObject is the base class for all data that needs to be
+    transferred between and within applications, both for drag and
+    drop and for the clipboard.
+
+    See the \link dnd.html Drag and drop documentation\endlink for an
+    overview of how to provide drag and drop in your application.
+
+    See the QClipboard documentation for an overview of how to provide
+    cut and paste in your application.
+
+    The drag() function is used to start a drag operation. You can
+    specify the \l DragMode in the call or use one of the convenience
+    functions dragCopy(), dragMove(), or dragLink(). The drag source
+    where the data originated is retrieved with source(). If the data
+    was dropped on a widget within the application, target() will
+    return a pointer to that widget. Specify the pixmap to display
+    during the drag with setPixmap().
+*/
+
+static
+void stripws(QByteArray& s)
+{
+    int f;
+    while ((f = s.indexOf(' ')) >= 0)
+        s.remove(f,1);
+}
+
+/*!
+    \class Q3TextDrag
+
+    \brief The Q3TextDrag class is a drag and drop object for
+    transferring plain and Unicode text.
+
+    \compat
+
+    Plain text is passed in a QString which may contain multiple lines
+    (i.e. may contain newline characters). The drag target will receive
+    the newlines according to the runtime environment, e.g. LF on Unix,
+    and CRLF on Windows.
+
+    Qt provides no built-in mechanism for delivering only a single-line.
+
+    For more information about drag and drop, see the Q3DragObject class
+    and the \link dnd.html drag and drop documentation\endlink.
+*/
+
+
+/*!
+    Constructs a text drag object with the given \a name, and sets its data
+    to \a text. The \a dragSource is the widget that the drag operation started
+    from.
+*/
+
+Q3TextDrag::Q3TextDrag(const QString &text, QWidget * dragSource, const char * name)
+    : Q3DragObject(*new Q3TextDragPrivate, dragSource)
+{
+    setObjectName(QLatin1String(name));
+    setText(text);
+}
+
+
+/*!
+    Constructs a default text drag object with the given \a name.
+    The \a dragSource is the widget that the drag operation started from.
+*/
+
+Q3TextDrag::Q3TextDrag(QWidget * dragSource, const char * name)
+    : Q3DragObject(*(new Q3TextDragPrivate), dragSource)
+{
+    setObjectName(QLatin1String(name));
+}
+
+/*! \internal */
+Q3TextDrag::Q3TextDrag(Q3TextDragPrivate &dd, QWidget *dragSource)
+    : Q3DragObject(dd, dragSource)
+{
+
+}
+
+/*!
+    Destroys the text drag object.
+*/
+Q3TextDrag::~Q3TextDrag()
+{
+
+}
+
+/*!
+    \fn void Q3TextDrag::setSubtype(const QString &subtype)
+
+    Sets the MIME \a subtype of the text being dragged. The default subtype
+    is "plain", so the default MIME type of the text is "text/plain".
+    You might use this to declare that the text is "text/html" by calling
+    setSubtype("html").
+*/
+void Q3TextDrag::setSubtype(const QString & st)
+{
+    d_func()->setSubType(st);
+}
+
+/*!
+    Sets the \a text to be dragged. You will need to call this if you did
+    not pass the text during construction.
+*/
+void Q3TextDrag::setText(const QString &text)
+{
+    d_func()->txt = text;
+}
+
+
+/*!
+    \reimp
+*/
+const char * Q3TextDrag::format(int i) const
+{
+    if (i > 0)
+        return 0;
+    return d_func()->fmt.constData();
+}
+
+QTextCodec* qt_findcharset(const QByteArray& mimetype)
+{
+    int i=mimetype.indexOf("charset=");
+    if (i >= 0) {
+        QByteArray cs = mimetype.mid(i+8);
+        stripws(cs);
+        i = cs.indexOf(';');
+        if (i >= 0)
+            cs = cs.left(i);
+        // May return 0 if unknown charset
+        return QTextCodec::codecForName(cs);
+    }
+    // no charset=, use locale
+    return QTextCodec::codecForName("utf-8");
+}
+
+static QTextCodec *codecForHTML(const QByteArray &ba)
+{
+    // determine charset
+    int mib = 0;
+    int pos;
+    QTextCodec *c = 0;
+
+    if (ba.size() > 1 && (((uchar)ba[0] == 0xfe && (uchar)ba[1] == 0xff)
+                          || ((uchar)ba[0] == 0xff && (uchar)ba[1] == 0xfe))) {
+        mib = 1015; // utf16
+    } else if (ba.size() > 2
+               && (uchar)ba[0] == 0xef
+               && (uchar)ba[1] == 0xbb
+               && (uchar)ba[2] == 0xbf) {
+        mib = 106; // utf-8
+    } else {
+        pos = 0;
+        while ((pos = ba.indexOf('<', pos)) != -1) {
+            int end = ba.indexOf('>', pos+1);
+            if (end == -1)
+                break;
+            const QString str(QString::fromLatin1(ba.mid(pos, end-pos)));
+            if (str.contains(QLatin1String("meta http-equiv="), Qt::CaseInsensitive)) {
+                pos = str.indexOf(QLatin1String("charset="), 0, Qt::CaseInsensitive) + int(strlen("charset="));
+                if (pos != -1) {
+                    int pos2 = ba.indexOf('\"', pos+1);
+                    QByteArray cs = ba.mid(pos, pos2-pos);
+                    c = QTextCodec::codecForName(cs);
+                    if (c)
+                        return c;
+                }
+            }
+            pos = end;
+        }
+    }
+    if (mib)
+        c = QTextCodec::codecForMib(mib);
+
+    return c;
+}
+
+static
+QTextCodec* findcodec(const QMimeSource* e)
+{
+    QTextCodec* r = 0;
+    const char* f;
+    int i;
+    for (i=0; (f=e->format(i)); i++) {
+        bool html = !qstrnicmp(f, "text/html", 9);
+        if (html)
+            r = codecForHTML(e->encodedData(f));
+        if (!r)
+            r = qt_findcharset(QByteArray(f).toLower());
+        if (r)
+            return r;
+    }
+    return 0;
+}
+
+
+
+/*!
+    \reimp
+*/
+QByteArray Q3TextDrag::encodedData(const char* mime) const
+{
+    Q_D(const Q3TextDrag);
+    if (mime != d->fmt)
+        return QByteArray();
+    return d->txt.toUtf8();
+}
+
+/*!
+    \fn bool Q3TextDrag::canDecode(const QMimeSource *source)
+
+    Returns true if the information in the MIME \a source can be decoded
+    into a QString; otherwise returns false.
+
+    \sa decode()
+*/
+bool Q3TextDrag::canDecode(const QMimeSource* e)
+{
+    const char* f;
+    for (int i=0; (f=e->format(i)); i++) {
+        if (0==qstrnicmp(f,"text/",5)) {
+            return findcodec(e) != 0;
+        }
+    }
+    return false;
+}
+
+/*!
+    \fn bool Q3TextDrag::decode(const QMimeSource *source, QString &string, QString &subtype)
+
+    \overload
+
+    Attempts to decode the dropped information in the MIME \a source into
+    the \a string given.
+    Returns true if successful; otherwise returns false. If \a subtype
+    is null, any text subtype is accepted; otherwise only the
+    specified \a subtype is accepted.
+
+    \sa canDecode()
+*/
+bool Q3TextDrag::decode(const QMimeSource* e, QString& str, QString& subtype)
+{
+    if(!e)
+        return false;
+
+    const char* mime;
+    for (int i=0; (mime = e->format(i)); i++) {
+        if (0==qstrnicmp(mime,"text/",5)) {
+            QByteArray m(mime);
+            m = m.toLower();
+            int semi = m.indexOf(';');
+            if (semi < 0)
+                semi = m.length();
+            QString foundst(QString::fromLatin1(m.mid(5,semi-5)));
+            if (subtype.isNull() || foundst == subtype) {
+                bool html = !qstrnicmp(mime, "text/html", 9);
+                QTextCodec* codec = 0;
+                if (html)
+                    // search for the charset tag in the HTML
+                    codec = codecForHTML(e->encodedData(mime));
+                if (!codec)
+                    codec = qt_findcharset(m);
+                if (codec) {
+                    QByteArray payload;
+
+                    payload = e->encodedData(mime);
+                    if (payload.size()) {
+                        int l;
+                        if (codec->mibEnum() != 1015) {
+                            // length is at NUL or payload.size()
+                            l = 0;
+                            while (l < (int)payload.size() && payload[l])
+                                l++;
+                        } else {
+                            l = payload.size();
+                        }
+
+                        str = codec->toUnicode(payload,l);
+
+                        if (subtype.isNull())
+                            subtype = foundst;
+
+                        return true;
+                    }
+                }
+            }
+        }
+    }
+    return false;
+}
+
+/*!
+    \fn bool Q3TextDrag::decode(const QMimeSource *source, QString &string)
+
+    Attempts to decode the dropped information in the MIME \a source into
+    the \a string given.
+    Returns true if successful; otherwise returns false.
+
+    \sa canDecode()
+*/
+bool Q3TextDrag::decode(const QMimeSource* e, QString& str)
+{
+    QString st;
+    return decode(e, str, st);
+}
+
+
+/*
+  Q3ImageDrag could use an internal MIME type for communicating QPixmaps
+  and QImages rather than always converting to raw data. This is available
+  for that purpose and others. It is not currently used.
+*/
+
+/*!
+    \class Q3ImageDrag
+
+    \brief The Q3ImageDrag class provides a drag and drop object for
+    transferring images.
+
+    \compat
+
+    Images are offered to the receiving application in multiple
+    formats, determined by Qt's output formats.
+*/
+
+/*!
+    Constructs an image drag object with the given \a name, and sets its
+    data to \a image. The \a dragSource is the widget that the drag operation
+    started from.
+*/
+
+Q3ImageDrag::Q3ImageDrag(QImage image,
+                        QWidget * dragSource, const char * name)
+    : Q3DragObject(*(new Q3ImageDragPrivate), dragSource)
+{
+    setObjectName(QLatin1String(name));
+    setImage(image);
+}
+
+/*!
+    Constructs a default image drag object with the given \a name.
+    The \a dragSource is the widget that the drag operation started from.
+*/
+
+Q3ImageDrag::Q3ImageDrag(QWidget * dragSource, const char * name)
+    : Q3DragObject(*(new Q3ImageDragPrivate), dragSource)
+{
+    setObjectName(QLatin1String(name));
+}
+
+/*! \internal */
+Q3ImageDrag::Q3ImageDrag(Q3ImageDragPrivate &dd, QWidget *dragSource)
+    : Q3DragObject(dd, dragSource)
+{
+}
+
+/*!
+    Destroys the image drag object.
+*/
+
+Q3ImageDrag::~Q3ImageDrag()
+{
+    // nothing
+}
+
+
+/*!
+    Sets the \a image to be dragged. You will need to call this if you did
+    not pass the image during construction.
+*/
+void Q3ImageDrag::setImage(QImage image)
+{
+    Q_D(Q3ImageDrag);
+    d->img = image;
+    QList<QByteArray> formats = QImageWriter::supportedImageFormats();
+    formats.removeAll("PBM"); // remove non-raw PPM
+    if (image.depth()!=32) {
+        // BMP better than PPM for paletted images
+        if (formats.removeAll("BMP")) // move to front
+            formats.insert(0,"BMP");
+    }
+    // PNG is best of all
+    if (formats.removeAll("PNG")) // move to front
+        formats.insert(0,"PNG");
+
+    for(int i = 0; i < formats.count(); i++) {
+        QByteArray format("image/");
+        format += formats.at(i);
+        format = format.toLower();
+        if (format == "image/pbmraw")
+            format = "image/ppm";
+        d->ofmts.append(format);
+    }
+    d->ofmts.append("application/x-qt-image");
+}
+
+/*!
+    \reimp
+*/
+const char * Q3ImageDrag::format(int i) const
+{
+    Q_D(const Q3ImageDrag);
+    return i < d->ofmts.count() ? d->ofmts.at(i).data() : 0;
+}
+
+/*!
+    \reimp
+*/
+QByteArray Q3ImageDrag::encodedData(const char* fmt) const
+{
+    Q_D(const Q3ImageDrag);
+    QString imgFormat(fmt);
+    if (imgFormat == QLatin1String("application/x-qt-image"))
+        imgFormat = QLatin1String("image/PNG");
+
+    if (imgFormat.startsWith("image/")){
+        QByteArray f(imgFormat.mid(6).toAscii());
+        QByteArray dat;
+        QBuffer w(&dat);
+        w.open(QIODevice::WriteOnly);
+        QImageWriter writer(&w, f.toUpper());
+        if (!writer.write(d->img))
+            return QByteArray();
+        w.close();
+        return dat;
+    } else {
+        return QByteArray();
+    }
+}
+
+/*!
+    \fn bool Q3ImageDrag::canDecode(const QMimeSource *source)
+
+    Returns true if the information in the MIME \a source can be decoded
+    into an image; otherwise returns false.
+
+    \sa decode()
+*/
+bool Q3ImageDrag::canDecode(const QMimeSource* e)
+{
+    return e->provides("application/x-qt-image");
+}
+
+/*!
+    \fn bool Q3ImageDrag::decode(const QMimeSource *source, QImage &image)
+
+    Decode the dropped information in the MIME \a source into the \a image.
+    Returns true if successful; otherwise returns false.
+
+    \sa canDecode()
+*/
+bool Q3ImageDrag::decode(const QMimeSource* e, QImage& img)
+{
+    if (!e)
+        return false;
+
+    QByteArray payload = e->encodedData("application/x-qt-image");
+    if (payload.isEmpty())
+        return false;
+
+    img.loadFromData(payload);
+    if (img.isNull())
+        return false;
+
+    return true;
+}
+
+/*!
+    \fn bool Q3ImageDrag::decode(const QMimeSource *source, QPixmap &pixmap)
+
+    \overload
+
+    Decodes the dropped information in the MIME \a source into the \a pixmap.
+    Returns true if successful; otherwise returns false.
+
+    This is a convenience function that converts the information to a QPixmap
+    via a QImage.
+
+    \sa canDecode()
+*/
+bool Q3ImageDrag::decode(const QMimeSource* e, QPixmap& pm)
+{
+    if (!e)
+        return false;
+
+    QImage img;
+    // We avoid dither, since the image probably came from this display
+    if (decode(e, img)) {
+        pm = QPixmap::fromImage(img, Qt::AvoidDither);
+        if (pm.isNull())
+            return false;
+
+        return true;
+    }
+    return false;
+}
+
+
+
+
+/*!
+    \class Q3StoredDrag
+    \brief The Q3StoredDrag class provides a simple stored-value drag object for arbitrary MIME data.
+
+    \compat
+
+    When a block of data has only one representation, you can use a
+    Q3StoredDrag to hold it.
+
+    For more information about drag and drop, see the Q3DragObject
+    class and the \link dnd.html drag and drop documentation\endlink.
+*/
+
+/*!
+    Constructs a Q3StoredDrag. The \a dragSource and \a name are passed
+    to the Q3DragObject constructor, and the format is set to \a
+    mimeType.
+
+    The data will be unset. Use setEncodedData() to set it.
+*/
+Q3StoredDrag::Q3StoredDrag(const char* mimeType, QWidget * dragSource, const char * name) :
+    Q3DragObject(*new Q3StoredDragPrivate, dragSource)
+{
+    Q_D(Q3StoredDrag);
+    setObjectName(QLatin1String(name));
+    d->fmt = qstrdup(mimeType);
+}
+
+/*! \internal */
+Q3StoredDrag::Q3StoredDrag(Q3StoredDragPrivate &dd, const char* mimeType, QWidget * dragSource)
+    : Q3DragObject(dd, dragSource)
+{
+    d_func()->fmt = qstrdup(mimeType);
+}
+
+/*!
+    Destroys the drag object.
+*/
+Q3StoredDrag::~Q3StoredDrag()
+{
+    delete [] (char*)d_func()->fmt;
+}
+
+/*!
+    \reimp
+*/
+const char * Q3StoredDrag::format(int i) const
+{
+    if (i==0)
+        return d_func()->fmt;
+    else
+        return 0;
+}
+
+
+/*!
+    \fn void Q3StoredDrag::setEncodedData(const QByteArray &data)
+
+    Sets the encoded \a data of this drag object. The encoded data is
+    delivered to drop sites; it must be in a strictly defined and portable
+    format.
+
+    The drag object can't be dropped (by the user) until this function
+    has been called.
+*/
+
+void Q3StoredDrag::setEncodedData(const QByteArray & encodedData)
+{
+    d_func()->enc = encodedData;
+}
+
+/*!
+    \fn QByteArray Q3StoredDrag::encodedData(const char *format) const
+
+    Returns the stored data in the \a format given.
+
+    \sa setEncodedData()
+*/
+QByteArray Q3StoredDrag::encodedData(const char* m) const
+{
+    if (!qstricmp(m, d_func()->fmt))
+        return d_func()->enc;
+    else
+        return QByteArray();
+}
+
+
+/*!
+    \class Q3UriDrag
+    \brief The Q3UriDrag class provides a drag object for a list of URI references.
+
+    \compat
+
+    URIs are a useful way to refer to files that may be distributed
+    across multiple machines. A URI will often refer to a file on a
+    machine local to both the drag source and the drop target, so the
+    URI can be equivalent to passing a file name but is more
+    extensible.
+
+    Use URIs in Unicode form so that the user can comfortably edit and
+    view them. For use in HTTP or other protocols, use the correctly
+    escaped ASCII form.
+
+    You can convert a list of file names to file URIs using
+    setFileNames(), or into human-readable form with setUnicodeUris().
+
+    Static functions are provided to convert between filenames and
+    URIs; e.g. uriToLocalFile() and localFileToUri(). Static functions
+    are also provided to convert URIs to and from human-readable form;
+    e.g. uriToUnicodeUri() and unicodeUriToUri().
+    You can also decode URIs from a MIME source into a list with
+    decodeLocalFiles() and decodeToUnicodeUris().
+*/
+
+/*!
+    Constructs an object to drag the list of \a uris.
+    The \a dragSource and \a name are passed to the Q3StoredDrag constructor.
+
+    Note that URIs are always in escaped UTF8 encoding.
+*/
+Q3UriDrag::Q3UriDrag(const Q3StrList &uris, QWidget * dragSource, const char * name) :
+    Q3StoredDrag("text/uri-list", dragSource)
+{
+    setObjectName(QLatin1String(name));
+    setUris(uris);
+}
+
+/*!
+    Constructs an object to drag with the given \a name.
+    You must call setUris() before you start the drag().
+    Both the \a dragSource and the \a name are passed to the Q3StoredDrag
+    constructor.
+*/
+Q3UriDrag::Q3UriDrag(QWidget * dragSource, const char * name) :
+    Q3StoredDrag("text/uri-list", dragSource)
+{
+    setObjectName(QLatin1String(name));
+}
+#endif
+
+/*!
+    Destroys the URI drag object.
+*/
+Q3UriDrag::~Q3UriDrag()
+{
+}
+
+/*!
+    \fn void Q3UriDrag::setUris(const QList<QByteArray> &list)
+
+    Changes the \a list of URIs to be dragged.
+
+    Note that URIs are always in escaped UTF8 encoding.
+*/
+void Q3UriDrag::setUris(const QList<QByteArray> &uris)
+{
+    QByteArray a;
+    int c = 0;
+    int i;
+    int count = uris.count();
+    for (i = 0; i < count; ++i)
+        c += uris.at(i).size() + 2; //length + \r\n
+    a.reserve(c+1);
+    for (i = 0; i < count; ++i) {
+        a.append(uris.at(i));
+        a.append("\r\n");
+    }
+    a[c] = 0;
+    setEncodedData(a);
+}
+
+
+/*!
+    \fn bool Q3UriDrag::canDecode(const QMimeSource *source)
+
+    Returns true if decode() can decode the MIME \a source; otherwise
+    returns false.
+*/
+bool Q3UriDrag::canDecode(const QMimeSource* e)
+{
+    return e->provides("text/uri-list");
+}
+
+/*!
+    \fn bool Q3UriDrag::decode(const QMimeSource* source, Q3StrList& list)
+
+    Decodes URIs from the MIME \a source, placing the result in the \a list.
+    The list is cleared before any items are inserted.
+
+    Returns true if the MIME \a source contained a valid list of URIs;
+    otherwise returns false.
+*/
+bool Q3UriDrag::decode(const QMimeSource* e, Q3StrList& l)
+{
+    QByteArray payload = e->encodedData("text/uri-list");
+    if (payload.size()) {
+        l.clear();
+        l.setAutoDelete(true);
+        uint c=0;
+        const char* data = payload.data();
+        while ((int)c < payload.size() && data[c]) {
+            uint f = c;
+            // Find line end
+            while ((int)c < payload.size() && data[c] && data[c]!='\r'
+                   && data[c] != '\n')
+                c++;
+            Q3CString s(data+f,c-f+1);
+            if (s[0] != '#') // non-comment?
+                l.append(s);
+            // Skip junk
+            while ((int)c < payload.size() && data[c] &&
+                   (data[c]=='\n' || data[c]=='\r'))
+                c++;
+        }
+        return true;
+    }
+    return false;
+}
+
+static uint htod(int h)
+{
+    if (isdigit(h))
+        return h - '0';
+    return tolower(h) - 'a' + 10;
+}
+
+/*!
+  \fn Q3UriDrag::setFilenames(const QStringList &list)
+
+  \obsolete
+
+  Sets the filename's in the drag object to those in the given \a
+  list.
+
+  Use setFileNames() instead.
+*/
+
+/*!
+    \fn void Q3UriDrag::setFileNames(const QStringList &filenames)
+
+    Sets the URIs to be local file URIs equivalent to the \a filenames.
+
+    \sa localFileToUri(), setUris()
+*/
+void Q3UriDrag::setFileNames(const QStringList & fnames)
+{
+    QList<QByteArray> uris;
+    for (QStringList::ConstIterator i = fnames.begin();
+    i != fnames.end(); ++i) {
+        QByteArray fileUri = localFileToUri(*i);
+        if (!fileUri.isEmpty())
+            uris.append(fileUri);
+    }
+
+    setUris(uris);
+}
+
+/*!
+    \fn void Q3UriDrag::setFileNames(const QString &name)
+    \fn void Q3UriDrag::setFilenames(const QString &name)
+
+    Same as setFileNames(QStringList(\a name)).
+*/
+
+/*!
+    \fn void Q3UriDrag::setUnicodeUris(const QStringList &list)
+
+    Sets the URIs in the \a list to be Unicode URIs (only useful for
+    displaying to humans).
+
+    \sa localFileToUri(), setUris()
+*/
+void Q3UriDrag::setUnicodeUris(const QStringList & uuris)
+{
+    QList<QByteArray> uris;
+    for (int i = 0; i < uuris.count(); ++i)
+        uris.append(unicodeUriToUri(uuris.at(i)));
+    setUris(uris);
+}
+
+/*!
+    \fn QByteArray Q3UriDrag::unicodeUriToUri(const QString &string)
+
+    Returns the URI equivalent of the Unicode URI given in the \a string
+    (only useful for displaying to humans).
+
+    \sa uriToLocalFile()
+*/
+QByteArray Q3UriDrag::unicodeUriToUri(const QString& uuri)
+{
+    QByteArray utf8 = uuri.toUtf8();
+    QByteArray escutf8;
+    int n = utf8.length();
+    bool isFile = uuri.startsWith(QLatin1String("file://"));
+    for (int i=0; i<n; i++) {
+        if ((utf8[i] >= 'a' && utf8[i] <= 'z')
+          || utf8[i] == '/'
+          || (utf8[i] >= '0' && utf8[i] <= '9')
+          || (utf8[i] >= 'A' && utf8[i] <= 'Z')
+
+          || utf8[i] == '-' || utf8[i] == '_'
+          || utf8[i] == '.' || utf8[i] == '!'
+          || utf8[i] == '~' || utf8[i] == '*'
+          || utf8[i] == '(' || utf8[i] == ')'
+          || utf8[i] == '\''
+
+          // Allow this through, so that all URI-references work.
+          || (!isFile && utf8[i] == '#')
+
+          || utf8[i] == ';'
+          || utf8[i] == '?' || utf8[i] == ':'
+          || utf8[i] == '@' || utf8[i] == '&'
+          || utf8[i] == '=' || utf8[i] == '+'
+          || utf8[i] == '$' || utf8[i] == ',')
+        {
+            escutf8 += utf8[i];
+        } else {
+            // Everything else is escaped as %HH
+            QString s;
+            s.sprintf("%%%02x",(uchar)utf8[i]);
+            escutf8 += s.latin1();
+        }
+    }
+    return escutf8;
+}
+
+/*!
+    Returns the URI equivalent to the absolute local \a filename.
+
+    \sa uriToLocalFile()
+*/
+QByteArray Q3UriDrag::localFileToUri(const QString& filename)
+{
+    QString r = filename;
+
+    //check that it is an absolute file
+    if (QDir::isRelativePath(r))
+        return QByteArray();
+#ifdef Q_WS_WIN
+
+
+    bool hasHost = false;
+    // convert form network path
+    if (r.left(2) == QLatin1String("\\\\") || r.left(2) == QLatin1String("//")) {
+        r.remove(0, 2);
+        hasHost = true;
+    }
+
+    // Slosh -> Slash
+    int slosh;
+    while ((slosh=r.indexOf(QLatin1Char('\\'))) >= 0) {
+        r[slosh] = QLatin1Char('/');
+    }
+
+    // Drive
+    if (r[0] != QLatin1Char('/') && !hasHost)
+        r.insert(0,QLatin1Char('/'));
+
+#endif
+#if defined (Q_WS_X11) && 0
+    // URL without the hostname is considered to be errorneous by XDnD.
+    // See: http://www.newplanetsoftware.com/xdnd/dragging_files.html
+    // This feature is not active because this would break dnd between old and new qt apps.
+    char hostname[257];
+    if (gethostname(hostname, 255) == 0) {
+        hostname[256] = '\0';
+        r.prepend(QString::fromLatin1(hostname));
+    }
+#endif
+    return unicodeUriToUri(QLatin1String("file://") + r);
+}
+
+/*!
+    \fn QString Q3UriDrag::uriToUnicodeUri(const char *string)
+
+    Returns the Unicode URI (only useful for displaying to humans)
+    equivalent of the URI given in the \a string.
+
+    Note that URIs are always in escaped UTF8 encoding.
+
+    \sa localFileToUri()
+*/
+QString Q3UriDrag::uriToUnicodeUri(const char* uri)
+{
+    QByteArray utf8;
+
+    while (*uri) {
+        switch (*uri) {
+          case '%': {
+                uint ch = (uchar) uri[1];
+                if (ch && uri[2]) {
+                    ch = htod(ch) * 16 + htod((uchar) uri[2]);
+                    utf8 += (char) ch;
+                    uri += 2;
+                }
+            }
+            break;
+          default:
+            utf8 += *uri;
+        }
+        ++uri;
+    }
+
+    return QString::fromUtf8(utf8);
+}
+
+/*!
+    \fn QString Q3UriDrag::uriToLocalFile(const char *string)
+
+    Returns the name of a local file equivalent to the URI given in the
+    \a string, or an empty string if it does not refer to a local file.
+
+    Note that URIs are always in escaped UTF8 encoding.
+
+    \sa localFileToUri()
+*/
+QString Q3UriDrag::uriToLocalFile(const char* uri)
+{
+    QString file;
+
+    if (!uri)
+        return file;
+    if (0==qstrnicmp(uri,"file:/",6)) // It is a local file uri
+        uri += 6;
+    else if (QString::fromLatin1(uri).indexOf(QLatin1String(":/")) != -1) // It is a different scheme uri
+        return file;
+
+    bool local = uri[0] != '/' || (uri[0] != '\0' && uri[1] == '/');
+#ifdef Q_WS_X11
+    // do we have a hostname?
+    if (!local && uri[0] == '/' && uri[2] != '/') {
+        // then move the pointer to after the 'hostname/' part of the uri
+        const char* hostname_end = strchr(uri+1, '/');
+        if (hostname_end != NULL) {
+            char hostname[257];
+            if (gethostname(hostname, 255) == 0) {
+                hostname[256] = '\0';
+                if (qstrncmp(uri+1, hostname, hostname_end - (uri+1)) == 0) {
+                    uri = hostname_end + 1; // point after the slash
+                    local = true;
+                }
+            }
+        }
+    }
+#endif
+    if (local) {
+        file = uriToUnicodeUri(uri);
+        if (uri[1] == '/') {
+            file.remove((uint)0,1);
+        } else {
+                file.insert(0, QLatin1Char('/'));
+        }
+#ifdef Q_WS_WIN
+        if (file.length() > 2 && file[0] == QLatin1Char('/') && file[2] == QLatin1Char('|')) {
+            file[2] = QLatin1Char(':');
+            file.remove(0,1);
+        } else if (file.length() > 2 && file[0] == QLatin1Char('/') && file[1].isLetter() && file[2] == QLatin1Char(':')) {
+            file.remove(0, 1);
+        }
+        // Leave slash as slashes.
+#endif
+    }
+#ifdef Q_WS_WIN
+    else {
+        file = uriToUnicodeUri(uri);
+        // convert to network path
+        file.insert(1, QLatin1Char('/')); // leave as forward slashes
+    }
+#endif
+
+    return file;
+}
+
+/*!
+    \fn bool Q3UriDrag::decodeLocalFiles(const QMimeSource *source, QStringList &list)
+
+    Decodes URIs from the MIME \a source, converting them to local filenames
+    where possible, and places them in the \a list (which is first cleared).
+
+    Returns true if the MIME \a source contained a valid list of URIs;
+    otherwise returns false. The list will be empty if no URIs referred to
+    local files.
+*/
+bool Q3UriDrag::decodeLocalFiles(const QMimeSource* e, QStringList& l)
+{
+    Q3StrList u;
+    if (!decode(e, u))
+        return false;
+
+    l.clear();
+    for (uint i = 0; i < u.count(); ++i) {
+        QString lf = uriToLocalFile(u.at(i));
+        if (!lf.isEmpty())
+            l.append(lf);
+    }
+    return true;
+}
+
+/*!
+    \fn bool Q3UriDrag::decodeToUnicodeUris(const QMimeSource *source, QStringList &list)
+
+    Decodes URIs from the MIME \a source, converting them to Unicode URIs
+    (only useful for displaying to humans), and places them in the \a list
+    (which is first cleared).
+
+    Returns true if the MIME \a source contained a valid list of URIs;
+    otherwise returns false.
+*/
+bool Q3UriDrag::decodeToUnicodeUris(const QMimeSource* e, QStringList& l)
+{
+    Q3StrList u;
+    if (!decode(e, u))
+        return false;
+
+    l.clear();
+    for (uint i = 0; i < u.count(); ++i)
+        l.append(uriToUnicodeUri(u.at(i)));
+
+    return true;
+}
+
+/*!
+    \class Q3ColorDrag
+
+    \brief The Q3ColorDrag class provides a drag and drop object for
+    transferring colors between widgets.
+
+    \compat
+
+    This class provides a drag object which can be used to transfer data
+    about colors for drag and drop and in the clipboard. For example, it
+    is used in QColorDialog.
+
+    The color is set in the constructor but can be changed with
+    setColor().
+
+    For more information about drag and drop, see the Q3DragObject class
+    and the \link dnd.html drag and drop documentation\endlink.
+*/
+
+/*!
+    Constructs a color drag object with the given \a col. Passes \a
+    dragsource and \a name to the Q3StoredDrag constructor.
+*/
+
+Q3ColorDrag::Q3ColorDrag(const QColor &col, QWidget *dragsource, const char *name)
+    : Q3StoredDrag("application/x-color", dragsource)
+{
+    setObjectName(QLatin1String(name));
+    setColor(col);
+}
+
+/*!
+    Constructs a color drag object with a white color. Passes \a
+    dragsource and \a name to the Q3StoredDrag constructor.
+*/
+
+Q3ColorDrag::Q3ColorDrag(QWidget *dragsource, const char *name)
+    : Q3StoredDrag("application/x-color", dragsource)
+{
+    setObjectName(QLatin1String(name));
+    setColor(Qt::white);
+}
+
+/*!
+    \fn void Q3ColorDrag::setColor(const QColor &color)
+
+    Sets the \a color of the color drag.
+*/
+
+void Q3ColorDrag::setColor(const QColor &col)
+{
+    short r = (col.red()   << 8) | col.red();
+    short g = (col.green() << 8) | col.green();
+    short b = (col.blue()  << 8) | col.blue();
+
+    // make sure we transmit data in network order
+    r = htons(r);
+    g = htons(g);
+    b = htons(b);
+
+    ushort rgba[4] = {
+        r, g, b,
+        0xffff // Alpha not supported yet.
+    };
+    QByteArray data;
+    data.resize(sizeof(rgba));
+    memcpy(data.data(), rgba, sizeof(rgba));
+    setEncodedData(data);
+}
+
+/*!
+    \fn bool Q3ColorDrag::canDecode(QMimeSource *source)
+
+    Returns true if the color drag object can decode the MIME \a source;
+    otherwise returns false.
+*/
+
+bool Q3ColorDrag::canDecode(QMimeSource *e)
+{
+    return e->provides("application/x-color");
+}
+
+/*!
+    \fn bool Q3ColorDrag::decode(QMimeSource *source, QColor &color)
+
+    Decodes the MIME \a source, and sets the decoded values to the
+    given \a color. Returns true if the decoding is successful.
+    Returns false if the size of the encoded data is not the
+    expected size.
+*/
+
+bool Q3ColorDrag::decode(QMimeSource *e, QColor &col)
+{
+    QByteArray data = e->encodedData("application/x-color");
+    ushort rgba[4];
+    if (data.size() != sizeof(rgba))
+        return false;
+
+    memcpy(rgba, data.constData(), sizeof(rgba));
+
+    short r = rgba[0];
+    short g = rgba[1];
+    short b = rgba[2];
+    short a = rgba[3];
+
+    // data is in network order
+    r = ntohs(r);
+    g = ntohs(g);
+    b = ntohs(b);
+    a = ntohs(a);
+
+    r = (r >> 8) & 0xff;
+    g = (g >> 8) & 0xff;
+    b = (b >> 8) & 0xff;
+    a = (a >> 8) & 0xff;
+
+    col.setRgb(r, g, b, a);
+    return true;
+}
+
+QT_END_NAMESPACE