src/qt3support/other/q3dragobject.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt3Support module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "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 
       
    72 QT_BEGIN_NAMESPACE
       
    73 
       
    74 static QWidget *last_target = 0;
       
    75 
       
    76 class QDragMime;
       
    77 
       
    78 class Q3DragObjectPrivate : public QObjectPrivate
       
    79 {
       
    80     Q_DECLARE_PUBLIC(Q3DragObject)
       
    81 public:
       
    82     Q3DragObjectPrivate(): hot(0,0),pm_cursor(0) {}
       
    83     QPixmap pixmap;
       
    84     QPoint hot;
       
    85     // store default cursors
       
    86     QPixmap *pm_cursor;
       
    87 };
       
    88 
       
    89 class Q3TextDragPrivate : public Q3DragObjectPrivate
       
    90 {
       
    91     Q_DECLARE_PUBLIC(Q3TextDrag)
       
    92 public:
       
    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 
       
   104 class Q3StoredDragPrivate : public Q3DragObjectPrivate
       
   105 {
       
   106     Q_DECLARE_PUBLIC(Q3StoredDrag)
       
   107 public:
       
   108     Q3StoredDragPrivate() {}
       
   109     const char* fmt;
       
   110     QByteArray enc;
       
   111 };
       
   112 
       
   113 class Q3ImageDragPrivate : public Q3DragObjectPrivate
       
   114 {
       
   115     Q_DECLARE_PUBLIC(Q3ImageDrag)
       
   116 public:
       
   117     QImage img;
       
   118     QList<QByteArray> ofmts;
       
   119 };
       
   120 
       
   121 class QDragMime : public QMimeData
       
   122 {
       
   123 public:
       
   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 
       
   134 QDragMime::~QDragMime()
       
   135 {
       
   136     delete dragObject;
       
   137 }
       
   138 QByteArray QDragMime::data(const QString &mimetype) const
       
   139 {
       
   140     return dragObject->encodedData(mimetype.latin1());
       
   141 }
       
   142 
       
   143 bool QDragMime::hasFormat(const QString &mimetype) const
       
   144 {
       
   145     return dragObject->provides(mimetype.latin1());
       
   146 }
       
   147 
       
   148 QStringList 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 
       
   168 Q3DragObject::Q3DragObject(QWidget * dragSource, const char * name)
       
   169     : QObject(*(new Q3DragObjectPrivate), dragSource)
       
   170 {
       
   171     setObjectName(QLatin1String(name));
       
   172 }
       
   173 
       
   174 /*! \internal */
       
   175 Q3DragObject::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 
       
   185 Q3DragObject::~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 */
       
   205 void 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 */
       
   219 void 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 */
       
   229 QPixmap Q3DragObject::pixmap() const
       
   230 {
       
   231     return d_func()->pixmap;
       
   232 }
       
   233 
       
   234 /*!
       
   235     Returns the currently set pixmap hotspot.
       
   236 
       
   237     \sa setPixmap()
       
   238 */
       
   239 QPoint 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 */
       
   263 bool 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 */
       
   276 QWidget *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 */
       
   292 bool 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 */
       
   305 void 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 */
       
   317 void 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 */
       
   357 bool 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 
       
   409 QWidget * 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 
       
   445 static
       
   446 void 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 
       
   479 Q3TextDrag::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 
       
   492 Q3TextDrag::Q3TextDrag(QWidget * dragSource, const char * name)
       
   493     : Q3DragObject(*(new Q3TextDragPrivate), dragSource)
       
   494 {
       
   495     setObjectName(QLatin1String(name));
       
   496 }
       
   497 
       
   498 /*! \internal */
       
   499 Q3TextDrag::Q3TextDrag(Q3TextDragPrivate &dd, QWidget *dragSource)
       
   500     : Q3DragObject(dd, dragSource)
       
   501 {
       
   502 
       
   503 }
       
   504 
       
   505 /*!
       
   506     Destroys the text drag object.
       
   507 */
       
   508 Q3TextDrag::~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 */
       
   521 void 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 */
       
   530 void Q3TextDrag::setText(const QString &text)
       
   531 {
       
   532     d_func()->txt = text;
       
   533 }
       
   534 
       
   535 
       
   536 /*!
       
   537     \reimp
       
   538 */
       
   539 const char * Q3TextDrag::format(int i) const
       
   540 {
       
   541     if (i > 0)
       
   542         return 0;
       
   543     return d_func()->fmt.constData();
       
   544 }
       
   545 
       
   546 QTextCodec* 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 
       
   562 static 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 
       
   603 static
       
   604 QTextCodec* 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 */
       
   626 QByteArray 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 */
       
   642 bool 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 */
       
   666 bool 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 */
       
   726 bool 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 
       
   757 Q3ImageDrag::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 
       
   770 Q3ImageDrag::Q3ImageDrag(QWidget * dragSource, const char * name)
       
   771     : Q3DragObject(*(new Q3ImageDragPrivate), dragSource)
       
   772 {
       
   773     setObjectName(QLatin1String(name));
       
   774 }
       
   775 
       
   776 /*! \internal */
       
   777 Q3ImageDrag::Q3ImageDrag(Q3ImageDragPrivate &dd, QWidget *dragSource)
       
   778     : Q3DragObject(dd, dragSource)
       
   779 {
       
   780 }
       
   781 
       
   782 /*!
       
   783     Destroys the image drag object.
       
   784 */
       
   785 
       
   786 Q3ImageDrag::~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 */
       
   796 void 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 */
       
   825 const 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 */
       
   834 QByteArray 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 */
       
   864 bool 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 */
       
   877 bool 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 */
       
   906 bool 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 */
       
   946 Q3StoredDrag::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 */
       
   955 Q3StoredDrag::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 */
       
   964 Q3StoredDrag::~Q3StoredDrag()
       
   965 {
       
   966     delete [] (char*)d_func()->fmt;
       
   967 }
       
   968 
       
   969 /*!
       
   970     \reimp
       
   971 */
       
   972 const 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 
       
   992 void 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 */
       
  1004 QByteArray 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 */
       
  1046 Q3UriDrag::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 */
       
  1059 Q3UriDrag::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 */
       
  1069 Q3UriDrag::~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 */
       
  1080 void 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 */
       
  1104 bool 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 */
       
  1118 bool 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 
       
  1145 static 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 */
       
  1170 void 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 */
       
  1198 void 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 */
       
  1214 QByteArray 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 */
       
  1257 QByteArray 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 */
       
  1308 QString 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 */
       
  1342 QString 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 */
       
  1409 bool 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 */
       
  1434 bool 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 
       
  1471 Q3ColorDrag::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 
       
  1483 Q3ColorDrag::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 
       
  1496 void 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 
       
  1524 bool 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 
       
  1538 bool 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 
       
  1567 QT_END_NAMESPACE