|
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 |