| /**************************************************************************** |
| ** |
| ** Copyright (C) 2011 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$ |
| ** GNU Lesser General Public License Usage |
| ** 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. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU General |
| ** Public License version 3.0 as published by the Free Software Foundation |
| ** and appearing in the file LICENSE.GPL included in the packaging of this |
| ** file. Please review the following information to ensure the GNU General |
| ** Public License version 3.0 requirements will be met: |
| ** http://www.gnu.org/copyleft/gpl.html. |
| ** |
| ** Other Usage |
| ** Alternatively, this file may be used in accordance with the terms and |
| ** conditions contained in a signed written agreement between you and Nokia. |
| ** |
| ** |
| ** |
| ** |
| ** |
| ** $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 |