source: trunk/src/kernel/qdragobject.cpp@ 96

Last change on this file since 96 was 96, checked in by dmik, 19 years ago

QTextDrag: decode() gives mime types in Unicode encodings a higher priprity (to guarantee loseless decoding); "text/whatever" w/o any charset is reported as the first mime format (for better integration with native drop targets).

  • Property svn:keywords set to Id
File size: 46.2 KB
Line 
1/****************************************************************************
2** $Id: qdragobject.cpp 96 2006-07-06 21:11:46Z dmik $
3**
4** Implementation of Drag and Drop support
5**
6** Copyright (C) 1992-2003 Trolltech AS. All rights reserved.
7**
8** This file is part of the kernel module of the Qt GUI Toolkit.
9**
10** This file may be distributed under the terms of the Q Public License
11** as defined by Trolltech AS of Norway and appearing in the file
12** LICENSE.QPL included in the packaging of this file.
13**
14** This file may be distributed and/or modified under the terms of the
15** GNU General Public License version 2 as published by the Free Software
16** Foundation and appearing in the file LICENSE.GPL included in the
17** packaging of this file.
18**
19** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
20** licenses may use this file in accordance with the Qt Commercial License
21** Agreement provided with the Software.
22**
23** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
24** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
25**
26** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
27** information about Qt Commercial License Agreements.
28** See http://www.trolltech.com/qpl/ for QPL licensing information.
29** See http://www.trolltech.com/gpl/ for GPL licensing information.
30**
31** Contact info@trolltech.com if any conditions of this licensing are
32** not clear to you.
33**
34**********************************************************************/
35
36#include "qplatformdefs.h"
37
38// POSIX Large File Support redefines open -> open64
39#if defined(open)
40# undef open
41#endif
42
43#ifndef QT_NO_MIME
44
45#include "qdragobject.h"
46#include "qtextcodec.h"
47#include "qapplication.h"
48#include "qpoint.h"
49#include "qwidget.h"
50#include "qbuffer.h"
51#include "qgif.h"
52#include "qregexp.h"
53#include "qdir.h"
54#include <ctype.h>
55
56// both a struct for storing stuff in and a wrapper to avoid polluting
57// the name space
58
59class QDragObjectData
60{
61public:
62 QDragObjectData(): hot(0,0) {}
63 QPixmap pixmap;
64 QPoint hot;
65 // store default cursors
66 QPixmap *pm_cursor;
67};
68
69static QWidget* last_target;
70
71/*!
72 After the drag completes, this function will return the QWidget
73 which received the drop, or 0 if the data was dropped on another
74 application.
75
76 This can be useful for detecting the case where drag and drop is
77 to and from the same widget.
78*/
79QWidget * QDragObject::target()
80{
81 return last_target;
82}
83
84/*!
85 \internal
86 Sets the target.
87*/
88void QDragObject::setTarget(QWidget* t)
89{
90 last_target = t;
91}
92
93class QStoredDragData
94{
95public:
96 QStoredDragData() {}
97 const char* fmt;
98 QByteArray enc;
99};
100
101
102// These pixmaps approximate the images in the Windows User Interface Guidelines.
103
104// XPM
105
106static const char * const move_xpm[] = {
107"11 20 3 1",
108". c None",
109#if defined(Q_WS_WIN)
110"a c #000000",
111"X c #FFFFFF", // Windows cursor is traditionally white
112#else
113"a c #FFFFFF",
114"X c #000000", // X11 cursor is traditionally black
115#endif
116"aa.........",
117"aXa........",
118"aXXa.......",
119"aXXXa......",
120"aXXXXa.....",
121"aXXXXXa....",
122"aXXXXXXa...",
123"aXXXXXXXa..",
124"aXXXXXXXXa.",
125"aXXXXXXXXXa",
126"aXXXXXXaaaa",
127"aXXXaXXa...",
128"aXXaaXXa...",
129"aXa..aXXa..",
130"aa...aXXa..",
131"a.....aXXa.",
132"......aXXa.",
133".......aXXa",
134".......aXXa",
135"........aa."};
136
137/* XPM */
138static const char * const copy_xpm[] = {
139"24 30 3 1",
140". c None",
141"a c #000000",
142"X c #FFFFFF",
143#if defined(Q_WS_WIN) // Windows cursor is traditionally white
144"aa......................",
145"aXa.....................",
146"aXXa....................",
147"aXXXa...................",
148"aXXXXa..................",
149"aXXXXXa.................",
150"aXXXXXXa................",
151"aXXXXXXXa...............",
152"aXXXXXXXXa..............",
153"aXXXXXXXXXa.............",
154"aXXXXXXaaaa.............",
155"aXXXaXXa................",
156"aXXaaXXa................",
157"aXa..aXXa...............",
158"aa...aXXa...............",
159"a.....aXXa..............",
160"......aXXa..............",
161".......aXXa.............",
162".......aXXa.............",
163"........aa...aaaaaaaaaaa",
164#else
165"XX......................",
166"XaX.....................",
167"XaaX....................",
168"XaaaX...................",
169"XaaaaX..................",
170"XaaaaaX.................",
171"XaaaaaaX................",
172"XaaaaaaaX...............",
173"XaaaaaaaaX..............",
174"XaaaaaaaaaX.............",
175"XaaaaaaXXXX.............",
176"XaaaXaaX................",
177"XaaXXaaX................",
178"XaX..XaaX...............",
179"XX...XaaX...............",
180"X.....XaaX..............",
181"......XaaX..............",
182".......XaaX.............",
183".......XaaX.............",
184"........XX...aaaaaaaaaaa",
185#endif
186".............aXXXXXXXXXa",
187".............aXXXXXXXXXa",
188".............aXXXXaXXXXa",
189".............aXXXXaXXXXa",
190".............aXXaaaaaXXa",
191".............aXXXXaXXXXa",
192".............aXXXXaXXXXa",
193".............aXXXXXXXXXa",
194".............aXXXXXXXXXa",
195".............aaaaaaaaaaa"};
196
197/* XPM */
198static const char * const link_xpm[] = {
199"24 30 3 1",
200". c None",
201"a c #000000",
202"X c #FFFFFF",
203#if defined(Q_WS_WIN) // Windows cursor is traditionally white
204"aa......................",
205"aXa.....................",
206"aXXa....................",
207"aXXXa...................",
208"aXXXXa..................",
209"aXXXXXa.................",
210"aXXXXXXa................",
211"aXXXXXXXa...............",
212"aXXXXXXXXa..............",
213"aXXXXXXXXXa.............",
214"aXXXXXXaaaa.............",
215"aXXXaXXa................",
216"aXXaaXXa................",
217"aXa..aXXa...............",
218"aa...aXXa...............",
219"a.....aXXa..............",
220"......aXXa..............",
221".......aXXa.............",
222".......aXXa.............",
223"........aa...aaaaaaaaaaa",
224#else
225"XX......................",
226"XaX.....................",
227"XaaX....................",
228"XaaaX...................",
229"XaaaaX..................",
230"XaaaaaX.................",
231"XaaaaaaX................",
232"XaaaaaaaX...............",
233"XaaaaaaaaX..............",
234"XaaaaaaaaaX.............",
235"XaaaaaaXXXX.............",
236"XaaaXaaX................",
237"XaaXXaaX................",
238"XaX..XaaX...............",
239"XX...XaaX...............",
240"X.....XaaX..............",
241"......XaaX..............",
242".......XaaX.............",
243".......XaaX.............",
244"........XX...aaaaaaaaaaa",
245#endif
246".............aXXXXXXXXXa",
247".............aXXXaaaaXXa",
248".............aXXXXaaaXXa",
249".............aXXXaaaaXXa",
250".............aXXaaaXaXXa",
251".............aXXaaXXXXXa",
252".............aXXaXXXXXXa",
253".............aXXXaXXXXXa",
254".............aXXXXXXXXXa",
255".............aaaaaaaaaaa"};
256
257#ifndef QT_NO_DRAGANDDROP
258
259// the universe's only drag manager
260QDragManager * qt_dnd_manager = 0;
261
262
263QDragManager::QDragManager()
264 : QObject( qApp, "global drag manager" )
265{
266 n_cursor = 3;
267 pm_cursor = new QPixmap[n_cursor];
268 pm_cursor[0] = QPixmap((const char **)move_xpm);
269 pm_cursor[1] = QPixmap((const char **)copy_xpm);
270 pm_cursor[2] = QPixmap((const char **)link_xpm);
271 object = 0;
272 dragSource = 0;
273 dropWidget = 0;
274 if ( !qt_dnd_manager )
275 qt_dnd_manager = this;
276 beingCancelled = FALSE;
277 restoreCursor = FALSE;
278 willDrop = FALSE;
279}
280
281
282QDragManager::~QDragManager()
283{
284#ifndef QT_NO_CURSOR
285 if ( restoreCursor )
286 QApplication::restoreOverrideCursor();
287#endif
288 qt_dnd_manager = 0;
289 delete [] pm_cursor;
290}
291
292#endif
293
294
295/*!
296 Constructs a drag object called \a name, which is a child of \a
297 dragSource.
298
299 Note that the drag object will be deleted when \a dragSource is
300 deleted.
301*/
302
303QDragObject::QDragObject( QWidget * dragSource, const char * name )
304 : QObject( dragSource, name )
305{
306 d = new QDragObjectData();
307 d->pm_cursor = 0;
308#ifndef QT_NO_DRAGANDDROP
309 if ( !qt_dnd_manager && qApp )
310 (void)new QDragManager();
311#endif
312}
313
314
315/*!
316 Destroys the drag object, canceling any drag and drop operation in
317 which it is involved, and frees up the storage used.
318*/
319
320QDragObject::~QDragObject()
321{
322#ifndef QT_NO_DRAGANDDROP
323 if ( qt_dnd_manager && qt_dnd_manager->object == this )
324 qt_dnd_manager->cancel( FALSE );
325 if ( d->pm_cursor ) {
326 for ( int i = 0; i < qt_dnd_manager->n_cursor; i++ )
327 qt_dnd_manager->pm_cursor[i] = d->pm_cursor[i];
328 delete [] d->pm_cursor;
329 }
330#endif
331 delete d;
332}
333
334#ifndef QT_NO_DRAGANDDROP
335/*!
336 Set the pixmap \a pm to display while dragging the object. The
337 platform-specific implementation will use this where it can - so
338 provide a small masked pixmap, and do not assume that the user
339 will actually see it. For example, cursors on Windows 95 are of
340 limited size.
341
342 The \a hotspot is the point on (or off) the pixmap that should be
343 under the cursor as it is dragged. It is relative to the top-left
344 pixel of the pixmap.
345
346 \warning We have seen problems with drag cursors on different
347 graphics hardware and driver software on Windows. Setting the
348 graphics acceleration in the display settings down one tick solved
349 the problems in all cases.
350*/
351void QDragObject::setPixmap(QPixmap pm, const QPoint& hotspot)
352{
353 d->pixmap = pm;
354 d->hot = hotspot;
355 if ( qt_dnd_manager && qt_dnd_manager->object == this )
356 qt_dnd_manager->updatePixmap();
357}
358
359/*!
360 \overload
361 Uses a hotspot that positions the pixmap below and to the right of
362 the mouse pointer. This allows the user to clearly see the point
363 on the window which they are dragging the data onto.
364*/
365void QDragObject::setPixmap(QPixmap pm)
366{
367 setPixmap(pm,QPoint(-10, -10));
368}
369
370/*!
371 Returns the currently set pixmap (which \link QPixmap::isNull()
372 isNull()\endlink if none is set).
373*/
374QPixmap QDragObject::pixmap() const
375{
376 return d->pixmap;
377}
378
379/*!
380 Returns the currently set pixmap hotspot.
381*/
382QPoint QDragObject::pixmapHotSpot() const
383{
384 return d->hot;
385}
386
387#if 0
388
389// ## reevaluate for Qt 4
390/*!
391 Set the \a cursor used when dragging in mode \a m.
392 Note: X11 only allow bitmaps for cursors.
393*/
394void QDragObject::setCursor( DragMode m, const QPixmap &cursor )
395{
396 if ( d->pm_cursor == 0 ) {
397 // safe default cursors
398 d->pm_cursor = new QPixmap[qt_dnd_manager->n_cursor];
399 for ( int i = 0; i < qt_dnd_manager->n_cursor; i++ )
400 d->pm_cursor[i] = qt_dnd_manager->pm_cursor[i];
401 }
402
403 int index;
404 switch ( m ) {
405 case DragCopy:
406 index = 1;
407 break;
408 case DragLink:
409 index = 2;
410 break;
411 default:
412 index = 0;
413 break;
414 }
415
416 // override default cursor
417 for ( index = 0; index < qt_dnd_manager->n_cursor; index++ )
418 qt_dnd_manager->pm_cursor[index] = cursor;
419}
420
421/*!
422 Returns the cursor used when dragging in mode \a m, or null if no cursor
423 has been set for that mode.
424*/
425QPixmap *QDragObject::cursor( DragMode m ) const
426{
427 if ( !d->pm_cursor )
428 return 0;
429
430 int index;
431 switch ( m ) {
432 case DragCopy:
433 index = 1;
434 break;
435 case DragLink:
436 index = 2;
437 break;
438 default:
439 index = 0;
440 break;
441 }
442
443 return qt_dnd_manager->pm_cursor+index;
444}
445
446#endif // 0
447
448/*!
449 Starts a drag operation using the contents of this object, using
450 DragDefault mode.
451
452 The function returns TRUE if the caller should delete the original
453 copy of the dragged data (but see target()); otherwise returns
454 FALSE.
455
456 If the drag contains \e references to information (e.g. file names
457 in a QUriDrag are references) then the return value should always
458 be ignored, as the target is expected to manipulate the
459 referred-to content directly. On X11 the return value should
460 always be correct anyway, but on Windows this is not necessarily
461 the case (e.g. the file manager starts a background process to
462 move files, so the source \e{must not} delete the files!)
463
464 Note that on Windows the drag operation will spin a blocking modal
465 event loop that will not dispatch any QTimers.
466*/
467bool QDragObject::drag()
468{
469 return drag( DragDefault );
470}
471
472
473/*!
474 Starts a drag operation using the contents of this object, using
475 \c DragMove mode. Be sure to read the constraints described in
476 drag().
477
478 \sa drag() dragCopy() dragLink()
479*/
480bool QDragObject::dragMove()
481{
482 return drag( DragMove );
483}
484
485
486/*!
487 Starts a drag operation using the contents of this object, using
488 \c DragCopy mode. Be sure to read the constraints described in
489 drag().
490
491 \sa drag() dragMove() dragLink()
492*/
493void QDragObject::dragCopy()
494{
495 (void)drag( DragCopy );
496}
497
498/*!
499 Starts a drag operation using the contents of this object, using
500 \c DragLink mode. Be sure to read the constraints described in
501 drag().
502
503 \sa drag() dragCopy() dragMove()
504*/
505void QDragObject::dragLink()
506{
507 (void)drag( DragLink );
508}
509
510
511/*!
512 \enum QDragObject::DragMode
513
514 This enum describes the possible drag modes.
515
516 \value DragDefault The mode is determined heuristically.
517 \value DragCopy The data is copied, never moved.
518 \value DragMove The data is moved, if dragged at all.
519 \value DragLink The data is linked, if dragged at all.
520 \value DragCopyOrMove The user chooses the mode by using a
521 control key to switch from the default.
522*/
523
524
525/*!
526 \overload
527 Starts a drag operation using the contents of this object.
528
529 At this point, the object becomes owned by Qt, not the
530 application. You should not delete the drag object or anything it
531 references. The actual transfer of data to the target application
532 will be done during future event processing - after that time the
533 drag object will be deleted.
534
535 Returns TRUE if the dragged data was dragged as a \e move,
536 indicating that the caller should remove the original source of
537 the data (the drag object must continue to have a copy); otherwise
538 returns FALSE.
539
540 The \a mode specifies the drag mode (see
541 \l{QDragObject::DragMode}.) Normally one of the simpler drag(),
542 dragMove(), or dragCopy() functions would be used instead.
543*/
544bool QDragObject::drag( DragMode mode )
545{
546 if ( qt_dnd_manager )
547 return qt_dnd_manager->drag( this, mode );
548 else
549 return FALSE;
550}
551
552#endif
553
554
555/*!
556 Returns a pointer to the drag source where this object originated.
557*/
558
559QWidget * QDragObject::source()
560{
561 if ( parent() && parent()->isWidgetType() )
562 return (QWidget *)parent();
563 else
564 return 0;
565}
566
567
568/*!
569 \class QDragObject qdragobject.h
570
571 \brief The QDragObject class encapsulates MIME-based data
572 transfer.
573
574 \ingroup draganddrop
575
576 QDragObject is the base class for all data that needs to be
577 transferred between and within applications, both for drag and
578 drop and for the \link qclipboard.html clipboard\endlink.
579
580 See the \link dnd.html Drag-and-drop documentation\endlink for an
581 overview of how to provide drag and drop in your application.
582
583 See the QClipboard documentation for an overview of how to provide
584 cut-and-paste in your application.
585
586 The drag() function is used to start a drag operation. You can
587 specify the \l DragMode in the call or use one of the convenience
588 functions dragCopy(), dragMove() or dragLink(). The drag source
589 where the data originated is retrieved with source(). If the data
590 was dropped on a widget within the application, target() will
591 return a pointer to that widget. Specify the pixmap to display
592 during the drag with setPixmap().
593*/
594
595static
596void stripws(QCString& s)
597{
598 int f;
599 while ( (f=s.find(' ')) >= 0 )
600 s.remove(f,1);
601}
602
603static
604const char * staticCharset(int i)
605{
606 static QCString localcharset;
607
608 switch ( i ) {
609#if defined(Q_WS_PM)
610 // We want "text/whatever" w/o any charset to be the first (the "default")
611 // mime type of the QTextDrag object, so that a rendering mechanism/format
612 // pair for it will be the first in the RMF list, wchich is essential for
613 // some native drop targets (i.e. WPS) to render text correctly. Note that
614 // it won't hide unicode data from Qt apps because QTextDrag::decode()
615 // for Q_WS_PM prefers unicode mime types (see the implementation below).
616 case 0:
617 return "";
618 case 1:
619 if ( localcharset.isNull() ) {
620 QTextCodec *localCodec = QTextCodec::codecForLocale();
621 if ( localCodec ) {
622 localcharset = localCodec->name();
623 localcharset = localcharset.lower();
624 stripws(localcharset);
625 } else {
626 localcharset = "";
627 }
628 }
629 return localcharset;
630 case 2:
631 return "UTF-8";
632 case 3:
633 return "ISO-10646-UCS-2";
634#else
635 case 0:
636 return "UTF-8";
637 case 1:
638 return "ISO-10646-UCS-2";
639 case 2:
640 return ""; // in the 3rd place - some Xdnd targets might only look at 3
641 case 3:
642 if ( localcharset.isNull() ) {
643 QTextCodec *localCodec = QTextCodec::codecForLocale();
644 if ( localCodec ) {
645 localcharset = localCodec->name();
646 localcharset = localcharset.lower();
647 stripws(localcharset);
648 } else {
649 localcharset = "";
650 }
651 }
652 return localcharset;
653#endif
654 }
655 return 0;
656}
657
658
659class QTextDragPrivate {
660public:
661 QTextDragPrivate();
662
663 enum { nfmt=4 };
664
665 QString txt;
666 QCString fmt[nfmt];
667 QCString subtype;
668
669 void setSubType(const QCString & st)
670 {
671 subtype = st.lower();
672 for ( int i=0; i<nfmt; i++ ) {
673 fmt[i] = "text/";
674 fmt[i].append(subtype);
675 QCString cs = staticCharset(i);
676 if ( !cs.isEmpty() ) {
677 fmt[i].append(";charset=");
678 fmt[i].append(cs);
679 }
680 }
681 }
682};
683
684inline QTextDragPrivate::QTextDragPrivate()
685{
686 setSubType("plain");
687}
688
689/*!
690 Sets the MIME subtype of the text being dragged to \a st. The
691 default subtype is "plain", so the default MIME type of the text
692 is "text/plain". You might use this to declare that the text is
693 "text/html" by calling setSubtype("html").
694*/
695void QTextDrag::setSubtype( const QCString & st)
696{
697 d->setSubType(st);
698}
699
700/*!
701 \class QTextDrag qdragobject.h
702
703 \brief The QTextDrag class is a drag and drop object for
704 transferring plain and Unicode text.
705
706 \ingroup draganddrop
707
708 Plain text is passed in a QString which may contain multiple lines
709 (i.e. may contain newline characters). The drag target will receive
710 the newlines according to the runtime environment, e.g. LF on Unix,
711 and CRLF on Windows.
712
713 Qt provides no built-in mechanism for delivering only a single-line.
714
715 For more information about drag and drop, see the QDragObject class
716 and the \link dnd.html drag and drop documentation\endlink.
717*/
718
719
720/*!
721 Constructs a text drag object and sets its data to \a text. \a
722 dragSource must be the drag source; \a name is the object name.
723*/
724
725QTextDrag::QTextDrag( const QString &text,
726 QWidget * dragSource, const char * name )
727 : QDragObject( dragSource, name )
728{
729 d = new QTextDragPrivate;
730 setText( text );
731}
732
733
734/*!
735 Constructs a default text drag object. \a dragSource must be the
736 drag source; \a name is the object name.
737*/
738
739QTextDrag::QTextDrag( QWidget * dragSource, const char * name )
740 : QDragObject( dragSource, name )
741{
742 d = new QTextDragPrivate;
743}
744
745
746/*!
747 Destroys the text drag object and frees up all allocated
748 resources.
749*/
750QTextDrag::~QTextDrag()
751{
752 delete d;
753}
754
755
756/*!
757 Sets the text to be dragged to \a text. You will need to call this
758 if you did not pass the text during construction.
759*/
760void QTextDrag::setText( const QString &text )
761{
762 d->txt = text;
763}
764
765
766/*!
767 \reimp
768*/
769const char * QTextDrag::format(int i) const
770{
771 if ( i >= d->nfmt )
772 return 0;
773 return d->fmt[i];
774}
775
776QTextCodec* qt_findcharset(const QCString& mimetype)
777{
778 int i=mimetype.find("charset=");
779 if ( i >= 0 ) {
780 QCString cs = mimetype.mid(i+8);
781 stripws(cs);
782 i = cs.find(';');
783 if ( i >= 0 )
784 cs = cs.left(i);
785 // win98 often has charset=utf16, and we need to get the correct codec for
786 // it to be able to get Unicode text drops.
787 if ( cs == "utf16" )
788 cs = "ISO-10646-UCS-2";
789 // May return 0 if unknown charset
790 return QTextCodec::codecForName(cs);
791 }
792 // no charset=, use locale
793 return QTextCodec::codecForLocale();
794}
795
796static QTextCodec *codecForHTML(const QCString &ba)
797{
798 // determine charset
799 int mib = 0;
800 int pos;
801 QTextCodec *c = 0;
802
803 if (ba.size() > 1 && (((uchar)ba[0] == 0xfe && (uchar)ba[1] == 0xff)
804 || ((uchar)ba[0] == 0xff && (uchar)ba[1] == 0xfe))) {
805 mib = 1000; // utf16
806 } else if (ba.size() > 2
807 && (uchar)ba[0] == 0xef
808 && (uchar)ba[1] == 0xbb
809 && (uchar)ba[2] == 0xbf) {
810 mib = 106; // utf-8
811 } else {
812 pos = 0;
813 while ((pos = ba.find("<meta http-equiv=", pos, FALSE)) != -1) {
814 int end = ba.find('>', pos+1);
815 if (end == -1)
816 break;
817 pos = ba.find("charset=", pos, FALSE) + strlen("charset=");
818 if (pos != -1 && pos < end) {
819 int pos2 = ba.find('\"', pos+1);
820 QCString cs = ba.mid(pos, pos2-pos);
821 c = QTextCodec::codecForName(cs);
822 if (c)
823 return c;
824 }
825 pos = end;
826 }
827 }
828 if (mib)
829 c = QTextCodec::codecForMib(mib);
830
831 return c;
832}
833
834static
835QTextCodec* findcodec(const QMimeSource* e)
836{
837 QTextCodec* r = 0;
838 const char* f;
839 int i;
840 for ( i=0; (f=e->format(i)); i++ ) {
841 bool html = !qstrnicmp(f, "text/html", 9);
842 if (html)
843 r = codecForHTML(QCString(e->encodedData(f)));
844 if (!r)
845 r = qt_findcharset(QCString(f).lower());
846 if (r)
847 return r;
848 }
849 return 0;
850}
851
852
853
854/*!
855 \reimp
856*/
857QByteArray QTextDrag::encodedData(const char* mime) const
858{
859 QCString r;
860 if ( 0==qstrnicmp(mime,"text/",5) ) {
861 QCString m(mime);
862 m = m.lower();
863 QTextCodec *codec = qt_findcharset(m);
864 if ( !codec )
865 return r;
866 QString text( d->txt );
867#if defined(Q_WS_WIN) || defined(Q_WS_PM)
868 int index = text.find( QString::fromLatin1("\r\n"), 0 );
869 while ( index != -1 ) {
870 text.replace( index, 2, QChar('\n') );
871 index = text.find( "\r\n", index );
872 }
873#endif
874 r = codec->fromUnicode(text);
875 if (!codec || codec->mibEnum() != 1000) {
876 // Don't include NUL in size (QCString::resize() adds NUL)
877#if defined(Q_WS_WIN)
878 // This is needed to ensure the \0 isn't lost on Windows 95
879 if ( qWinVersion() & Qt::WV_DOS_based )
880 ((QByteArray&)r).resize(r.length()+1);
881 else
882#endif
883 ((QByteArray&)r).resize(r.length());
884 }
885 }
886 return r;
887}
888
889/*!
890 Returns TRUE if the information in \a e can be decoded into a
891 QString; otherwise returns FALSE.
892
893 \sa decode()
894*/
895bool QTextDrag::canDecode( const QMimeSource* e )
896{
897 const char* f;
898 for (int i=0; (f=e->format(i)); i++) {
899 if ( 0==qstrnicmp(f,"text/",5) ) {
900 return findcodec(e) != 0;
901 }
902 }
903 return 0;
904}
905
906/*!
907 \overload
908
909 Attempts to decode the dropped information in \a e into \a str.
910 Returns TRUE if successful; otherwise returns FALSE. If \a subtype
911 is null, any text subtype is accepted; otherwise only the
912 specified \a subtype is accepted.
913
914 \sa canDecode()
915*/
916bool QTextDrag::decode( const QMimeSource* e, QString& str, QCString& subtype )
917{
918 if(!e)
919 return FALSE;
920
921 if ( e->cacheType == QMimeSource::Text ) {
922 str = *e->cache.txt.str;
923 subtype = *e->cache.txt.subtype;
924 return TRUE;
925 }
926
927#if defined(Q_WS_PM)
928 // We give Unicode formats a higher priority, so that if there are several
929 // encodings of the same subtype present in the given mime source, a
930 // Unicode one will be used for decoding. Otherwise, the first recognized
931 // format will be choosen.
932 int fallbackMime = -1;
933 bool secondPass = FALSE;
934
935 const char *mime;
936 for( int i = 0; /* FOREVER */; ++i ) {
937 mime = e->format( i );
938 if ( !mime ) {
939 // We went through all mimes but didn't find Unicode. If there is
940 // a fall-back mime, iterate again starting directly from it.
941 if ( !secondPass && fallbackMime >= 0 ) {
942 i = fallbackMime - 1; // will do ++i on continue
943 secondPass = TRUE;
944 continue;
945 }
946 break;
947 }
948#else
949 const char* mime;
950 for (int i=0; (mime = e->format(i)); i++) {
951#endif
952 if ( 0==qstrnicmp(mime,"text/",5) ) {
953 QCString m(mime);
954 m = m.lower();
955 int semi = m.find(';');
956 if ( semi < 0 )
957 semi = m.length();
958 QCString foundst = m.mid(5,semi-5);
959 if ( subtype.isNull() || foundst == subtype ) {
960 bool html = !qstrnicmp(mime, "text/html", 9);
961 QTextCodec* codec = 0;
962 if (html)
963 // search for the charset tag in the HTML
964 codec = codecForHTML(QCString(e->encodedData(mime)));
965 if (!codec)
966 codec = qt_findcharset(m);
967 if ( codec ) {
968#if defined(Q_WS_PM)
969 if ( codec->mibEnum() == 1000 /* ISO-10646-UCS-2 */ ||
970 codec->mibEnum() == 106 /* UTF-8 */ ) {
971 // no need to try it again on the second pass
972 if ( secondPass )
973 continue;
974 } else if ( !secondPass ) {
975 // memorize the fall-back mime on the first pass
976 if ( fallbackMime < 0 )
977 fallbackMime = i;
978 continue;
979 }
980#endif
981 QByteArray payload;
982 payload = e->encodedData(mime);
983 if ( payload.size() ) {
984 int l;
985 if ( codec->mibEnum() != 1000) {
986 // length is at NUL or payload.size()
987 l = 0;
988 while ( l < (int)payload.size() && payload[l] )
989 l++;
990 } else {
991 l = payload.size();
992 }
993
994 str = codec->toUnicode(payload,l);
995
996 if ( subtype.isNull() )
997 subtype = foundst;
998
999 QMimeSource *m = (QMimeSource*)e;
1000 m->clearCache();
1001 m->cacheType = QMimeSource::Text;
1002 m->cache.txt.str = new QString( str );
1003 m->cache.txt.subtype = new QCString( subtype );
1004
1005 return TRUE;
1006 }
1007 }
1008 }
1009 }
1010 }
1011 return FALSE;
1012}
1013
1014/*!
1015 Attempts to decode the dropped information in \a e into \a str.
1016 Returns TRUE if successful; otherwise returns FALSE.
1017
1018 \sa canDecode()
1019*/
1020bool QTextDrag::decode( const QMimeSource* e, QString& str )
1021{
1022 QCString st;
1023 return decode(e,str,st);
1024}
1025
1026
1027/*
1028 QImageDrag could use an internal MIME type for communicating QPixmaps
1029 and QImages rather than always converting to raw data. This is available
1030 for that purpose and others. It is not currently used.
1031*/
1032class QImageDragData
1033{
1034public:
1035};
1036
1037
1038/*!
1039 \class QImageDrag qdragobject.h
1040
1041 \brief The QImageDrag class provides a drag and drop object for
1042 transferring images.
1043
1044 \ingroup draganddrop
1045
1046 Images are offered to the receiving application in multiple
1047 formats, determined by Qt's \link QImage::outputFormats() output
1048 formats\endlink.
1049
1050 For more information about drag and drop, see the QDragObject
1051 class and the \link dnd.html drag and drop documentation\endlink.
1052*/
1053
1054/*!
1055 Constructs an image drag object and sets its data to \a image. \a
1056 dragSource must be the drag source; \a name is the object name.
1057*/
1058
1059QImageDrag::QImageDrag( QImage image,
1060 QWidget * dragSource, const char * name )
1061 : QDragObject( dragSource, name ),
1062 d(0)
1063{
1064 setImage( image );
1065}
1066
1067/*!
1068 Constructs a default image drag object. \a dragSource must be the
1069 drag source; \a name is the object name.
1070*/
1071
1072QImageDrag::QImageDrag( QWidget * dragSource, const char * name )
1073 : QDragObject( dragSource, name ),
1074 d(0)
1075{
1076}
1077
1078
1079/*!
1080 Destroys the image drag object and frees up all allocated
1081 resources.
1082*/
1083
1084QImageDrag::~QImageDrag()
1085{
1086 // nothing
1087}
1088
1089
1090/*!
1091 Sets the image to be dragged to \a image. You will need to call
1092 this if you did not pass the image during construction.
1093*/
1094void QImageDrag::setImage( QImage image )
1095{
1096 img = image; // ### detach?
1097 ofmts = QImage::outputFormats();
1098 ofmts.remove("PBM"); // remove non-raw PPM
1099 if ( image.depth()!=32 ) {
1100 // BMP better than PPM for paletted images
1101 if ( ofmts.remove("BMP") ) // move to front
1102 ofmts.insert(0,"BMP");
1103 }
1104 // PNG is best of all
1105 if ( ofmts.remove("PNG") ) // move to front
1106 ofmts.insert(0,"PNG");
1107
1108 if(cacheType == QMimeSource::NoCache) { //cache it
1109 cacheType = QMimeSource::Graphics;
1110 cache.gfx.img = new QImage( img );
1111 cache.gfx.pix = 0;
1112 }
1113}
1114
1115/*!
1116 \reimp
1117*/
1118const char * QImageDrag::format(int i) const
1119{
1120 if ( i < (int)ofmts.count() ) {
1121 static QCString str;
1122 str.sprintf("image/%s",(((QImageDrag*)this)->ofmts).at(i));
1123 str = str.lower();
1124 if ( str == "image/pbmraw" )
1125 str = "image/ppm";
1126 return str;
1127 } else {
1128 return 0;
1129 }
1130}
1131
1132/*!
1133 \reimp
1134*/
1135QByteArray QImageDrag::encodedData(const char* fmt) const
1136{
1137 if ( qstrnicmp( fmt, "image/", 6 )==0 ) {
1138 QCString f = fmt+6;
1139 QByteArray data;
1140 QBuffer w( data );
1141 w.open( IO_WriteOnly );
1142 QImageIO io( &w, f.upper() );
1143 io.setImage( img );
1144 if ( !io.write() )
1145 return QByteArray();
1146 w.close();
1147 return data;
1148 } else {
1149 return QByteArray();
1150 }
1151}
1152
1153/*!
1154 Returns TRUE if the information in mime source \a e can be decoded
1155 into an image; otherwise returns FALSE.
1156
1157 \sa decode()
1158*/
1159bool QImageDrag::canDecode( const QMimeSource* e ) {
1160 QStrList fileFormats = QImageIO::inputFormats();
1161
1162 fileFormats.first();
1163 while ( fileFormats.current()) {
1164 QCString format = fileFormats.current();
1165 QCString type = "image/" + format.lower();
1166 if ( e->provides(type.data()))
1167 return TRUE;
1168 fileFormats.next();
1169 }
1170
1171 return FALSE;
1172}
1173
1174/*!
1175 Attempts to decode the dropped information in mime source \a e
1176 into \a img. Returns TRUE if successful; otherwise returns FALSE.
1177
1178 \sa canDecode()
1179*/
1180bool QImageDrag::decode( const QMimeSource* e, QImage& img )
1181{
1182 if ( !e )
1183 return FALSE;
1184 if ( e->cacheType == QMimeSource::Graphics ) {
1185 img = *e->cache.gfx.img;
1186 return TRUE;
1187 }
1188
1189 QByteArray payload;
1190 QStrList fileFormats = QImageIO::inputFormats();
1191 // PNG is best of all
1192 if ( fileFormats.remove("PNG") ) // move to front
1193 fileFormats.insert(0,"PNG");
1194 fileFormats.first();
1195 while ( fileFormats.current() ) {
1196 QCString format = fileFormats.current();
1197 fileFormats.next();
1198
1199 QCString type = "image/" + format.lower();
1200 if ( ! e->provides( type.data() ) ) continue;
1201 payload = e->encodedData( type.data() );
1202 if ( !payload.isEmpty() )
1203 break;
1204 }
1205
1206 if ( payload.isEmpty() )
1207 return FALSE;
1208
1209 img.loadFromData(payload);
1210 if ( img.isNull() )
1211 return FALSE;
1212 QMimeSource *m = (QMimeSource*)e;
1213 m->clearCache();
1214 m->cacheType = QMimeSource::Graphics;
1215 m->cache.gfx.img = new QImage( img );
1216 m->cache.gfx.pix = 0;
1217 return TRUE;
1218}
1219
1220/*!
1221 \overload
1222
1223 Attempts to decode the dropped information in mime source \a e
1224 into pixmap \a pm. Returns TRUE if successful; otherwise returns
1225 FALSE.
1226
1227 This is a convenience function that converts to a QPixmap via a
1228 QImage.
1229
1230 \sa canDecode()
1231*/
1232bool QImageDrag::decode( const QMimeSource* e, QPixmap& pm )
1233{
1234 if ( !e )
1235 return FALSE;
1236
1237 if ( e->cacheType == QMimeSource::Graphics && e->cache.gfx.pix) {
1238 pm = *e->cache.gfx.pix;
1239 return TRUE;
1240 }
1241
1242 QImage img;
1243 // We avoid dither, since the image probably came from this display
1244 if ( decode( e, img ) ) {
1245 if ( !pm.convertFromImage( img, AvoidDither ) )
1246 return FALSE;
1247 // decode initialized the cache for us
1248
1249 QMimeSource *m = (QMimeSource*)e;
1250 m->cache.gfx.pix = new QPixmap( pm );
1251 return TRUE;
1252 }
1253 return FALSE;
1254}
1255
1256
1257
1258
1259/*!
1260 \class QStoredDrag qdragobject.h
1261 \brief The QStoredDrag class provides a simple stored-value drag object for arbitrary MIME data.
1262
1263 \ingroup draganddrop
1264
1265 When a block of data has only one representation, you can use a
1266 QStoredDrag to hold it.
1267
1268 For more information about drag and drop, see the QDragObject
1269 class and the \link dnd.html drag and drop documentation\endlink.
1270*/
1271
1272/*!
1273 Constructs a QStoredDrag. The \a dragSource and \a name are passed
1274 to the QDragObject constructor, and the format is set to \a
1275 mimeType.
1276
1277 The data will be unset. Use setEncodedData() to set it.
1278*/
1279QStoredDrag::QStoredDrag( const char* mimeType, QWidget * dragSource, const char * name ) :
1280 QDragObject(dragSource,name)
1281{
1282 d = new QStoredDragData();
1283 d->fmt = qstrdup(mimeType);
1284}
1285
1286/*!
1287 Destroys the drag object and frees up all allocated resources.
1288*/
1289QStoredDrag::~QStoredDrag()
1290{
1291 delete [] (char*)d->fmt;
1292 delete d;
1293}
1294
1295/*!
1296 \reimp
1297*/
1298const char * QStoredDrag::format(int i) const
1299{
1300 if ( i==0 )
1301 return d->fmt;
1302 else
1303 return 0;
1304}
1305
1306
1307/*!
1308 Sets the encoded data of this drag object to \a encodedData. The
1309 encoded data is what's delivered to the drop sites. It must be in
1310 a strictly defined and portable format.
1311
1312 The drag object can't be dropped (by the user) until this function
1313 has been called.
1314*/
1315
1316void QStoredDrag::setEncodedData( const QByteArray & encodedData )
1317{
1318 d->enc = encodedData.copy();
1319}
1320
1321/*!
1322 Returns the stored data. \a m contains the data's format.
1323
1324 \sa setEncodedData()
1325*/
1326QByteArray QStoredDrag::encodedData(const char* m) const
1327{
1328 if ( !qstricmp(m,d->fmt) )
1329 return d->enc;
1330 else
1331 return QByteArray();
1332}
1333
1334
1335/*!
1336 \class QUriDrag qdragobject.h
1337 \brief The QUriDrag class provides a drag object for a list of URI references.
1338
1339 \ingroup draganddrop
1340
1341 URIs are a useful way to refer to files that may be distributed
1342 across multiple machines. A URI will often refer to a file on a
1343 machine local to both the drag source and the drop target, so the
1344 URI can be equivalent to passing a file name but is more
1345 extensible.
1346
1347 Use URIs in Unicode form so that the user can comfortably edit and
1348 view them. For use in HTTP or other protocols, use the correctly
1349 escaped ASCII form.
1350
1351 You can convert a list of file names to file URIs using
1352 setFileNames(), or into human-readble form with setUnicodeUris().
1353
1354 Static functions are provided to convert between filenames and
1355 URIs, e.g. uriToLocalFile() and localFileToUri(), and to and from
1356 human-readable form, e.g. uriToUnicodeUri(), unicodeUriToUri().
1357 You can also decode URIs from a mimesource into a list with
1358 decodeLocalFiles() and decodeToUnicodeUris().
1359*/
1360
1361/*!
1362 Constructs an object to drag the list of URIs in \a uris. The \a
1363 dragSource and \a name arguments are passed on to QStoredDrag.
1364 Note that URIs are always in escaped UTF8 encoding.
1365*/
1366QUriDrag::QUriDrag( QStrList uris,
1367 QWidget * dragSource, const char * name ) :
1368 QStoredDrag( "text/uri-list", dragSource, name )
1369{
1370 setUris(uris);
1371}
1372
1373/*!
1374 Constructs an object to drag. You must call setUris() before you
1375 start the drag(). Passes \a dragSource and \a name to the
1376 QStoredDrag constructor.
1377*/
1378QUriDrag::QUriDrag( QWidget * dragSource, const char * name ) :
1379 QStoredDrag( "text/uri-list", dragSource, name )
1380{
1381}
1382
1383/*!
1384 Destroys the object.
1385*/
1386QUriDrag::~QUriDrag()
1387{
1388}
1389
1390/*!
1391 Changes the list of \a uris to be dragged.
1392
1393 Note that URIs are always in escaped UTF8 encoding.
1394*/
1395void QUriDrag::setUris( QStrList uris )
1396{
1397 QByteArray a;
1398 int c=0;
1399 for ( const char* s = uris.first(); s; s = uris.next() ) {
1400 int l = qstrlen(s);
1401 a.resize(c+l+2);
1402 memcpy(a.data()+c,s,l);
1403 memcpy(a.data()+c+l,"\r\n",2);
1404 c+=l+2;
1405 }
1406 a.resize(c+1);
1407 a[c] = 0;
1408 setEncodedData(a);
1409}
1410
1411
1412/*!
1413 Returns TRUE if decode() would be able to decode \a e; otherwise
1414 returns FALSE.
1415*/
1416bool QUriDrag::canDecode( const QMimeSource* e )
1417{
1418 return e->provides( "text/uri-list" );
1419}
1420
1421/*!
1422 Decodes URIs from \a e, placing the result in \a l (which is first
1423 cleared).
1424
1425 Returns TRUE if \a e contained a valid list of URIs; otherwise
1426 returns FALSE.
1427*/
1428bool QUriDrag::decode( const QMimeSource* e, QStrList& l )
1429{
1430 QByteArray payload = e->encodedData( "text/uri-list" );
1431 if ( payload.size() ) {
1432 l.clear();
1433 l.setAutoDelete(TRUE);
1434 uint c=0;
1435 const char* d = payload.data();
1436 while (c < payload.size() && d[c]) {
1437 uint f = c;
1438 // Find line end
1439 while (c < payload.size() && d[c] && d[c]!='\r'
1440 && d[c] != '\n')
1441 c++;
1442 QCString s(d+f,c-f+1);
1443 if ( s[0] != '#' ) // non-comment?
1444 l.append( s );
1445 // Skip junk
1446 while (c < payload.size() && d[c] &&
1447 (d[c]=='\n' || d[c]=='\r'))
1448 c++;
1449 }
1450 return TRUE;
1451 }
1452 return FALSE;
1453}
1454
1455static uint htod( int h )
1456{
1457 if ( isdigit(h) )
1458 return h - '0';
1459 return tolower( h ) - 'a' + 10;
1460}
1461
1462/*!
1463 \fn QUriDrag::setFilenames( const QStringList & )
1464 \obsolete
1465
1466 Use setFileNames() instead (notice the N).
1467*/
1468
1469/*!
1470 Sets the URIs to be the local-file URIs equivalent to \a fnames.
1471
1472 \sa localFileToUri(), setUris()
1473*/
1474void QUriDrag::setFileNames( const QStringList & fnames )
1475{
1476 QStrList uris;
1477 for ( QStringList::ConstIterator i = fnames.begin();
1478 i != fnames.end(); ++i ) {
1479 QCString fileUri = localFileToUri(*i);
1480 if (!fileUri.isEmpty())
1481 uris.append(fileUri);
1482 }
1483 setUris( uris );
1484}
1485
1486/*!
1487 Sets the URIs in \a uuris to be the Unicode URIs (only useful for
1488 displaying to humans).
1489
1490 \sa localFileToUri(), setUris()
1491*/
1492void QUriDrag::setUnicodeUris( const QStringList & uuris )
1493{
1494 QStrList uris;
1495 for ( QStringList::ConstIterator i = uuris.begin();
1496 i != uuris.end(); ++i )
1497 uris.append( unicodeUriToUri(*i) );
1498 setUris( uris );
1499}
1500
1501/*!
1502 Returns the URI equivalent of the Unicode URI given in \a uuri
1503 (only useful for displaying to humans).
1504
1505 \sa uriToLocalFile()
1506*/
1507QCString QUriDrag::unicodeUriToUri(const QString& uuri)
1508{
1509 QCString utf8 = uuri.utf8();
1510 QCString escutf8;
1511 int n = utf8.length();
1512 for (int i=0; i<n; i++) {
1513 if ( utf8[i] >= 'a' && utf8[i] <= 'z'
1514 || utf8[i] == '/'
1515 || utf8[i] >= '0' && utf8[i] <= '9'
1516 || utf8[i] >= 'A' && utf8[i] <= 'Z'
1517
1518 || utf8[i] == '-' || utf8[i] == '_'
1519 || utf8[i] == '.' || utf8[i] == '!'
1520 || utf8[i] == '~' || utf8[i] == '*'
1521 || utf8[i] == '(' || utf8[i] == ')'
1522 || utf8[i] == '\''
1523
1524 // Allow this through, so that all URI-references work.
1525 || utf8[i] == '#'
1526
1527 || utf8[i] == ';'
1528 || utf8[i] == '?' || utf8[i] == ':'
1529 || utf8[i] == '@' || utf8[i] == '&'
1530 || utf8[i] == '=' || utf8[i] == '+'
1531 || utf8[i] == '$' || utf8[i] == ',' )
1532 {
1533 escutf8 += utf8[i];
1534 } else {
1535 // Everything else is escaped as %HH
1536 QCString s(4);
1537 s.sprintf("%%%02x",(uchar)utf8[i]);
1538 escutf8 += s;
1539 }
1540 }
1541 return escutf8;
1542}
1543
1544/*!
1545 Returns the URI equivalent to the absolute local file \a filename.
1546
1547 \sa uriToLocalFile()
1548*/
1549QCString QUriDrag::localFileToUri(const QString& filename)
1550{
1551 QString r = filename;
1552
1553 //check that it is an absolute file
1554 if (QDir::isRelativePath(r))
1555 return QCString();
1556
1557#if defined(Q_WS_WIN) || defined(Q_WS_PM)
1558
1559
1560 bool hasHost = false;
1561 // convert form network path
1562 if (r.left(2) == "\\\\" || r.left(2) == "//") {
1563 r.remove(0, 2);
1564 hasHost = true;
1565 }
1566
1567 // Slosh -> Slash
1568 int slosh;
1569 while ( (slosh=r.find('\\')) >= 0 ) {
1570 r[slosh] = '/';
1571 }
1572
1573 // Drive
1574 if ( r[0] != '/' && !hasHost)
1575 r.insert(0,'/');
1576
1577#endif
1578#if defined ( Q_WS_X11 ) && 0
1579 // URL without the hostname is considered to be errorneous by XDnD.
1580 // See: http://www.newplanetsoftware.com/xdnd/dragging_files.html
1581 // This feature is not active because this would break dnd between old and new qt apps.
1582 char hostname[257];
1583 if ( gethostname( hostname, 255 ) == 0 ) {
1584 hostname[256] = '\0';
1585 r.prepend( QString::fromLatin1( hostname ) );
1586 }
1587#endif
1588 return unicodeUriToUri(QString("file://" + r));
1589}
1590
1591/*!
1592 Returns the Unicode URI (only useful for displaying to humans)
1593 equivalent of \a uri.
1594
1595 Note that URIs are always in escaped UTF8 encoding.
1596
1597 \sa localFileToUri()
1598*/
1599QString QUriDrag::uriToUnicodeUri(const char* uri)
1600{
1601 QCString utf8;
1602
1603 while (*uri) {
1604 switch (*uri) {
1605 case '%': {
1606 uint ch = (uchar) uri[1];
1607 if ( ch && uri[2] ) {
1608 ch = htod( ch ) * 16 + htod( (uchar) uri[2] );
1609 utf8 += (char) ch;
1610 uri += 2;
1611 }
1612 }
1613 break;
1614 default:
1615 utf8 += *uri;
1616 }
1617 ++uri;
1618 }
1619
1620 return QString::fromUtf8(utf8);
1621}
1622
1623/*!
1624 Returns the name of a local file equivalent to \a uri or a null
1625 string if \a uri is not a local file.
1626
1627 Note that URIs are always in escaped UTF8 encoding.
1628
1629 \sa localFileToUri()
1630*/
1631QString QUriDrag::uriToLocalFile(const char* uri)
1632{
1633 QString file;
1634
1635 if (!uri)
1636 return file;
1637 if (0==qstrnicmp(uri,"file:/",6)) // It is a local file uri
1638 uri += 6;
1639 else if (QString(uri).find(":/") != -1) // It is a different scheme uri
1640 return file;
1641
1642 bool local = uri[0] != '/' || ( uri[0] != '\0' && uri[1] == '/' );
1643#ifdef Q_WS_X11
1644 // do we have a hostname?
1645 if ( !local && uri[0] == '/' && uri[2] != '/' ) {
1646 // then move the pointer to after the 'hostname/' part of the uri
1647 const char* hostname_end = strchr( uri+1, '/' );
1648 if ( hostname_end != NULL ) {
1649 char hostname[ 257 ];
1650 if ( gethostname( hostname, 255 ) == 0 ) {
1651 hostname[ 256 ] = '\0';
1652 if ( qstrncmp( uri+1, hostname, hostname_end - ( uri+1 )) == 0 ) {
1653 uri = hostname_end + 1; // point after the slash
1654 local = TRUE;
1655 }
1656 }
1657 }
1658 }
1659#endif
1660 if ( local ) {
1661 file = uriToUnicodeUri(uri);
1662 if ( uri[1] == '/' ) {
1663 file.remove((uint)0,1);
1664 } else {
1665 file.insert(0,'/');
1666 }
1667#if defined(Q_WS_WIN) || defined(Q_WS_PM)
1668 if ( file.length() > 2 && file[0] == '/' && file[2] == '|' ) {
1669 file[2] = ':';
1670 file.remove(0,1);
1671 } else if (file.length() > 2 && file[0] == '/' && file[1].isLetter() && file[2] == ':') {
1672 file.remove(0, 1);
1673 }
1674 // Leave slash as slashes.
1675#endif
1676 }
1677#if defined(Q_WS_WIN) || defined(Q_WS_PM)
1678 else {
1679 file = uriToUnicodeUri(uri);
1680 // convert to network path
1681 file.insert(1, '/'); // leave as forward slashes
1682 }
1683#endif
1684
1685 return file;
1686}
1687
1688/*!
1689 Decodes URIs from the mime source event \a e, converts them to
1690 local files if they refer to local files, and places them in \a l
1691 (which is first cleared).
1692
1693 Returns TRUE if \e contained a valid list of URIs; otherwise
1694 returns FALSE. The list will be empty if no URIs were local files.
1695*/
1696bool QUriDrag::decodeLocalFiles( const QMimeSource* e, QStringList& l )
1697{
1698 QStrList u;
1699 if ( !decode( e, u ) )
1700 return FALSE;
1701
1702 l.clear();
1703 for (const char* s=u.first(); s; s=u.next()) {
1704 QString lf = uriToLocalFile(s);
1705 if ( !lf.isNull() )
1706 l.append( lf );
1707 }
1708 return TRUE;
1709}
1710
1711/*!
1712 Decodes URIs from the mime source event \a e, converts them to
1713 Unicode URIs (only useful for displaying to humans), placing them
1714 in \a l (which is first cleared).
1715
1716 Returns TRUE if \e contained a valid list of URIs; otherwise
1717 returns FALSE.
1718*/
1719bool QUriDrag::decodeToUnicodeUris( const QMimeSource* e, QStringList& l )
1720{
1721 QStrList u;
1722 if ( !decode( e, u ) )
1723 return FALSE;
1724
1725 l.clear();
1726 for (const char* s=u.first(); s; s=u.next())
1727 l.append( uriToUnicodeUri(s) );
1728
1729 return TRUE;
1730}
1731
1732
1733#ifndef QT_NO_DRAGANDDROP
1734/*!
1735 If the source of the drag operation is a widget in this
1736 application, this function returns that source, otherwise it
1737 returns 0. The source of the operation is the first parameter to
1738 drag object subclasses.
1739
1740 This is useful if your widget needs special behavior when dragging
1741 to itself, etc.
1742
1743 See QDragObject::QDragObject() and subclasses.
1744*/
1745QWidget* QDropEvent::source() const
1746{
1747 return qt_dnd_manager ? qt_dnd_manager->dragSource : 0;
1748}
1749#endif
1750
1751/*!
1752 \class QColorDrag qdragobject.h
1753
1754 \brief The QColorDrag class provides a drag and drop object for
1755 transferring colors.
1756
1757 \ingroup draganddrop
1758
1759 This class provides a drag object which can be used to transfer data
1760 about colors for drag and drop and in the clipboard. For example, it
1761 is used in QColorDialog.
1762
1763 The color is set in the constructor but can be changed with
1764 setColor().
1765
1766 For more information about drag and drop, see the QDragObject class
1767 and the \link dnd.html drag and drop documentation\endlink.
1768*/
1769
1770/*!
1771 Constructs a color drag object with the color \a col. Passes \a
1772 dragsource and \a name to the QStoredDrag constructor.
1773*/
1774
1775QColorDrag::QColorDrag( const QColor &col, QWidget *dragsource, const char *name )
1776 : QStoredDrag( "application/x-color", dragsource, name )
1777{
1778 setColor( col );
1779}
1780
1781/*!
1782 Constructs a color drag object with a white color. Passes \a
1783 dragsource and \a name to the QStoredDrag constructor.
1784*/
1785
1786QColorDrag::QColorDrag( QWidget *dragsource, const char *name )
1787 : QStoredDrag( "application/x-color", dragsource, name )
1788{
1789 setColor( Qt::white );
1790}
1791
1792/*!
1793 Sets the color of the color drag to \a col.
1794*/
1795
1796void QColorDrag::setColor( const QColor &col )
1797{
1798 short r = (col.red() << 8) | col.red();
1799 short g = (col.green() << 8) | col.green();
1800 short b = (col.blue() << 8) | col.blue();
1801
1802 // make sure we transmit data in network order
1803 r = htons(r);
1804 g = htons(g);
1805 b = htons(b);
1806
1807 ushort rgba[4] = {
1808 r, g, b,
1809 0xffff // Alpha not supported yet.
1810 };
1811 QByteArray data(sizeof(rgba));
1812 memcpy(data.data(), rgba, sizeof(rgba));
1813 setEncodedData(data);
1814}
1815
1816/*!
1817 Returns TRUE if the color drag object can decode the mime source
1818 \a e; otherwise returns FALSE.
1819*/
1820
1821bool QColorDrag::canDecode( QMimeSource *e )
1822{
1823 return e->provides( "application/x-color" );
1824}
1825
1826/*!
1827 Decodes the mime source \a e and sets the decoded values to \a
1828 col.
1829*/
1830
1831bool QColorDrag::decode( QMimeSource *e, QColor &col )
1832{
1833 QByteArray data = e->encodedData("application/x-color");
1834 ushort rgba[4];
1835 if (data.size() != sizeof(rgba))
1836 return FALSE;
1837
1838 memcpy(rgba, data.data(), sizeof(rgba));
1839
1840 short r = rgba[0];
1841 short g = rgba[1];
1842 short b = rgba[2];
1843
1844 // data is in network order
1845 r = ntohs(r);
1846 g = ntohs(g);
1847 b = ntohs(b);
1848
1849 r = (r >> 8) & 0xff;
1850 g = (g >> 8) & 0xff;
1851 b = (b >> 8) & 0xff;
1852
1853 col.setRgb(r, g, b);
1854 return TRUE;
1855}
1856
1857#endif // QT_NO_MIME
Note: See TracBrowser for help on using the repository browser.