source: trunk/src/gui/kernel/qdnd.cpp@ 447

Last change on this file since 447 was 447, checked in by Dmitry A. Kuminov, 15 years ago

gui: DnD: Implemented support for painting in widgets during drag and draw.

File size: 20.4 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qplatformdefs.h"
43
44#include "qbitmap.h"
45#include "qdrag.h"
46#include "qpixmap.h"
47#include "qevent.h"
48#include "qfile.h"
49#include "qtextcodec.h"
50#include "qapplication.h"
51#include "qpoint.h"
52#include "qwidget.h"
53#include "qbuffer.h"
54#include "qimage.h"
55#include "qregexp.h"
56#include "qdir.h"
57#include "qdnd_p.h"
58#include "qimagereader.h"
59#include "qimagewriter.h"
60#include "qdebug.h"
61#include <ctype.h>
62
63#ifndef QT_NO_DRAGANDDROP
64
65QT_BEGIN_NAMESPACE
66
67// These pixmaps approximate the images in the Windows User Interface Guidelines.
68
69// XPM
70
71static const char * const move_xpm[] = {
72"11 20 3 1",
73". c None",
74#if defined(Q_WS_WIN)
75"a c #000000",
76"X c #FFFFFF", // Windows cursor is traditionally white
77#else
78"a c #FFFFFF",
79"X c #000000", // X11 cursor is traditionally black
80#endif
81"aa.........",
82"aXa........",
83"aXXa.......",
84"aXXXa......",
85"aXXXXa.....",
86"aXXXXXa....",
87"aXXXXXXa...",
88"aXXXXXXXa..",
89"aXXXXXXXXa.",
90"aXXXXXXXXXa",
91"aXXXXXXaaaa",
92"aXXXaXXa...",
93"aXXaaXXa...",
94"aXa..aXXa..",
95"aa...aXXa..",
96"a.....aXXa.",
97"......aXXa.",
98".......aXXa",
99".......aXXa",
100"........aa."};
101
102#if defined(Q_WS_WIN) || defined(Q_WS_PM)
103/* XPM */
104static const char * const ignore_xpm[] = {
105"24 30 3 1",
106". c None",
107#if defined(Q_WS_WIN)
108"a c #000000",
109"X c #FFFFFF", // Windows cursor is traditionally white
110#else
111"a c #FFFFFF",
112"X c #000000", // OS/2 cursor is traditionally black
113#endif
114"aa......................",
115"aXa.....................",
116"aXXa....................",
117"aXXXa...................",
118"aXXXXa..................",
119"aXXXXXa.................",
120"aXXXXXXa................",
121"aXXXXXXXa...............",
122"aXXXXXXXXa..............",
123"aXXXXXXXXXa.............",
124"aXXXXXXaaaa.............",
125"aXXXaXXa................",
126"aXXaaXXa................",
127"aXa..aXXa...............",
128"aa...aXXa...............",
129"a.....aXXa..............",
130"......aXXa.....XXXX.....",
131".......aXXa..XXaaaaXX...",
132".......aXXa.XaaaaaaaaX..",
133"........aa.XaaaXXXXaaaX.",
134"...........XaaaaX..XaaX.",
135"..........XaaXaaaX..XaaX",
136"..........XaaXXaaaX.XaaX",
137"..........XaaX.XaaaXXaaX",
138"..........XaaX..XaaaXaaX",
139"...........XaaX..XaaaaX.",
140"...........XaaaXXXXaaaX.",
141"............XaaaaaaaaX..",
142".............XXaaaaXX...",
143"...............XXXX....."};
144#endif
145
146/* XPM */
147static const char * const copy_xpm[] = {
148"24 30 3 1",
149". c None",
150"a c #000000",
151"X c #FFFFFF",
152#if defined(Q_WS_WIN) // Windows cursor is traditionally white
153"aa......................",
154"aXa.....................",
155"aXXa....................",
156"aXXXa...................",
157"aXXXXa..................",
158"aXXXXXa.................",
159"aXXXXXXa................",
160"aXXXXXXXa...............",
161"aXXXXXXXXa..............",
162"aXXXXXXXXXa.............",
163"aXXXXXXaaaa.............",
164"aXXXaXXa................",
165"aXXaaXXa................",
166"aXa..aXXa...............",
167"aa...aXXa...............",
168"a.....aXXa..............",
169"......aXXa..............",
170".......aXXa.............",
171".......aXXa.............",
172"........aa...aaaaaaaaaaa",
173#else
174"XX......................",
175"XaX.....................",
176"XaaX....................",
177"XaaaX...................",
178"XaaaaX..................",
179"XaaaaaX.................",
180"XaaaaaaX................",
181"XaaaaaaaX...............",
182"XaaaaaaaaX..............",
183"XaaaaaaaaaX.............",
184"XaaaaaaXXXX.............",
185"XaaaXaaX................",
186"XaaXXaaX................",
187"XaX..XaaX...............",
188"XX...XaaX...............",
189"X.....XaaX..............",
190"......XaaX..............",
191".......XaaX.............",
192".......XaaX.............",
193"........XX...aaaaaaaaaaa",
194#endif
195".............aXXXXXXXXXa",
196".............aXXXXXXXXXa",
197".............aXXXXaXXXXa",
198".............aXXXXaXXXXa",
199".............aXXaaaaaXXa",
200".............aXXXXaXXXXa",
201".............aXXXXaXXXXa",
202".............aXXXXXXXXXa",
203".............aXXXXXXXXXa",
204".............aaaaaaaaaaa"};
205
206/* XPM */
207static const char * const link_xpm[] = {
208"24 30 3 1",
209". c None",
210"a c #000000",
211"X c #FFFFFF",
212#if defined(Q_WS_WIN) // Windows cursor is traditionally white
213"aa......................",
214"aXa.....................",
215"aXXa....................",
216"aXXXa...................",
217"aXXXXa..................",
218"aXXXXXa.................",
219"aXXXXXXa................",
220"aXXXXXXXa...............",
221"aXXXXXXXXa..............",
222"aXXXXXXXXXa.............",
223"aXXXXXXaaaa.............",
224"aXXXaXXa................",
225"aXXaaXXa................",
226"aXa..aXXa...............",
227"aa...aXXa...............",
228"a.....aXXa..............",
229"......aXXa..............",
230".......aXXa.............",
231".......aXXa.............",
232"........aa...aaaaaaaaaaa",
233#else
234"XX......................",
235"XaX.....................",
236"XaaX....................",
237"XaaaX...................",
238"XaaaaX..................",
239"XaaaaaX.................",
240"XaaaaaaX................",
241"XaaaaaaaX...............",
242"XaaaaaaaaX..............",
243"XaaaaaaaaaX.............",
244"XaaaaaaXXXX.............",
245"XaaaXaaX................",
246"XaaXXaaX................",
247"XaX..XaaX...............",
248"XX...XaaX...............",
249"X.....XaaX..............",
250"......XaaX..............",
251".......XaaX.............",
252".......XaaX.............",
253"........XX...aaaaaaaaaaa",
254#endif
255".............aXXXXXXXXXa",
256".............aXXXaaaaXXa",
257".............aXXXXaaaXXa",
258".............aXXXaaaaXXa",
259".............aXXaaaXaXXa",
260".............aXXaaXXXXXa",
261".............aXXaXXXXXXa",
262".............aXXXaXXXXXa",
263".............aXXXXXXXXXa",
264".............aaaaaaaaaaa"};
265
266#ifndef QT_NO_DRAGANDDROP
267
268//#define QDND_DEBUG
269
270#ifdef QDND_DEBUG
271QString dragActionsToString(Qt::DropActions actions)
272{
273 QString str;
274 if (actions == Qt::IgnoreAction) {
275 if (!str.isEmpty())
276 str += " | ";
277 str += "IgnoreAction";
278 }
279 if (actions & Qt::LinkAction) {
280 if (!str.isEmpty())
281 str += " | ";
282 str += "LinkAction";
283 }
284 if (actions & Qt::CopyAction) {
285 if (!str.isEmpty())
286 str += " | ";
287 str += "CopyAction";
288 }
289 if (actions & Qt::MoveAction) {
290 if (!str.isEmpty())
291 str += " | ";
292 str += "MoveAction";
293 }
294 if ((actions & Qt::TargetMoveAction) == Qt::TargetMoveAction ) {
295 if (!str.isEmpty())
296 str += " | ";
297 str += "TargetMoveAction";
298 }
299 return str;
300}
301
302QString KeyboardModifiersToString(Qt::KeyboardModifiers moderfies)
303{
304 QString str;
305 if (moderfies & Qt::ControlModifier) {
306 if (!str.isEmpty())
307 str += " | ";
308 str += Qt::ControlModifier;
309 }
310 if (moderfies & Qt::AltModifier) {
311 if (!str.isEmpty())
312 str += " | ";
313 str += Qt::AltModifier;
314 }
315 if (moderfies & Qt::ShiftModifier) {
316 if (!str.isEmpty())
317 str += " | ";
318 str += Qt::ShiftModifier;
319 }
320 return str;
321}
322#endif
323
324
325// the universe's only drag manager
326QDragManager *QDragManager::instance = 0;
327
328
329QDragManager::QDragManager()
330 : QObject(qApp)
331{
332 Q_ASSERT(!instance);
333
334#if defined(Q_WS_WIN) || defined(Q_WS_PM)
335 n_cursor = 4;
336#else
337 n_cursor = 3;
338#endif
339
340#ifdef Q_WS_QWS
341 currentActionForOverrideCursor = Qt::IgnoreAction;
342#endif
343 pm_cursor = new QPixmap[n_cursor];
344 pm_cursor[0] = QPixmap((const char **)move_xpm);
345 pm_cursor[1] = QPixmap((const char **)copy_xpm);
346 pm_cursor[2] = QPixmap((const char **)link_xpm);
347#if defined(Q_WS_WIN) || defined(Q_WS_PM)
348 pm_cursor[3] = QPixmap((const char **)ignore_xpm);
349#endif
350 object = 0;
351 beingCancelled = false;
352 restoreCursor = false;
353 willDrop = false;
354 eventLoop = 0;
355 dropData = new QDropData();
356 currentDropTarget = 0;
357#ifdef Q_WS_X11
358 xdndMimeTransferedPixmapIndex = 0;
359#endif
360#ifdef Q_WS_PM
361 init_sys();
362#endif
363}
364
365
366QDragManager::~QDragManager()
367{
368#ifdef Q_WS_PM
369 uninit_sys();
370#endif
371#ifndef QT_NO_CURSOR
372 if (restoreCursor)
373 QApplication::restoreOverrideCursor();
374#endif
375 instance = 0;
376 delete [] pm_cursor;
377 delete dropData;
378}
379
380QDragManager *QDragManager::self()
381{
382 if (!instance && qApp && !qApp->closingDown())
383 instance = new QDragManager;
384 return instance;
385}
386
387QPixmap QDragManager::dragCursor(Qt::DropAction action) const
388{
389 QDragPrivate * d = dragPrivate();
390 if (d && d->customCursors.contains(action))
391 return d->customCursors[action];
392 else if (action == Qt::MoveAction)
393 return pm_cursor[0];
394 else if (action == Qt::CopyAction)
395 return pm_cursor[1];
396 else if (action == Qt::LinkAction)
397 return pm_cursor[2];
398#ifdef Q_WS_WIN
399 else if (action == Qt::IgnoreAction)
400 return pm_cursor[3];
401#endif
402 return QPixmap();
403}
404
405bool QDragManager::hasCustomDragCursors() const
406{
407 QDragPrivate * d = dragPrivate();
408 return d && !d->customCursors.isEmpty();
409}
410
411Qt::DropAction QDragManager::defaultAction(Qt::DropActions possibleActions,
412 Qt::KeyboardModifiers modifiers) const
413{
414#ifdef QDND_DEBUG
415 qDebug("QDragManager::defaultAction(Qt::DropActions possibleActions)");
416 qDebug("keyboard modifiers : %s", KeyboardModifiersToString(modifiers).latin1());
417#endif
418
419 QDragPrivate *d = dragPrivate();
420 Qt::DropAction defaultAction = d ? d->defaultDropAction : Qt::IgnoreAction;
421
422 if (defaultAction == Qt::IgnoreAction) {
423 //This means that the drag was initiated by QDrag::start and we need to
424 //preserve the old behavior
425#ifdef Q_WS_MAC
426 defaultAction = Qt::MoveAction;
427#else
428 defaultAction = Qt::CopyAction;
429#endif
430 }
431
432#ifdef Q_WS_MAC
433 if (modifiers & Qt::ControlModifier && modifiers & Qt::AltModifier)
434 defaultAction = Qt::LinkAction;
435 else if (modifiers & Qt::AltModifier)
436 defaultAction = Qt::CopyAction;
437 else if (modifiers & Qt::ControlModifier)
438 defaultAction = Qt::MoveAction;
439#else
440 if (modifiers & Qt::ControlModifier && modifiers & Qt::ShiftModifier)
441 defaultAction = Qt::LinkAction;
442 else if (modifiers & Qt::ControlModifier)
443 defaultAction = Qt::CopyAction;
444 else if (modifiers & Qt::ShiftModifier)
445 defaultAction = Qt::MoveAction;
446 else if (modifiers & Qt::AltModifier)
447 defaultAction = Qt::LinkAction;
448#endif
449
450 // if the object is set take the list of possibles from it
451 if (object)
452 possibleActions = object->d_func()->possible_actions;
453
454#ifdef QDND_DEBUG
455 qDebug("possible actions : %s", dragActionsToString(possibleActions).latin1());
456#endif
457
458 // Check if the action determined is allowed
459 if (!(possibleActions & defaultAction)) {
460 if (possibleActions & Qt::CopyAction)
461 defaultAction = Qt::CopyAction;
462 else if (possibleActions & Qt::MoveAction)
463 defaultAction = Qt::MoveAction;
464 else if (possibleActions & Qt::LinkAction)
465 defaultAction = Qt::LinkAction;
466 else
467 defaultAction = Qt::IgnoreAction;
468 }
469
470#ifdef QDND_DEBUG
471 qDebug("default action : %s", dragActionsToString(defaultAction).latin1());
472#endif
473
474 return defaultAction;
475}
476
477void QDragManager::setCurrentTarget(QWidget *target, bool dropped)
478{
479 if (currentDropTarget == target)
480 return;
481
482 currentDropTarget = target;
483 if (!dropped && object) {
484 object->d_func()->target = target;
485 emit object->targetChanged(target);
486 }
487
488}
489
490QWidget *QDragManager::currentTarget()
491{
492 return currentDropTarget;
493}
494
495#endif
496
497QDropData::QDropData()
498 : QInternalMimeData()
499{
500#ifdef Q_WS_PM
501 d = 0;
502#endif
503}
504
505QDropData::~QDropData()
506{
507}
508#endif // QT_NO_DRAGANDDROP
509
510#if !(defined(QT_NO_DRAGANDDROP) && defined(QT_NO_CLIPBOARD))
511
512static QStringList imageReadMimeFormats()
513{
514 QStringList formats;
515 QList<QByteArray> imageFormats = QImageReader::supportedImageFormats();
516 for (int i = 0; i < imageFormats.size(); ++i) {
517 QString format = QLatin1String("image/");
518 format += QString::fromLatin1(imageFormats.at(i).toLower());
519 formats.append(format);
520 }
521
522 //put png at the front because it is best
523 int pngIndex = formats.indexOf(QLatin1String("image/png"));
524 if (pngIndex != -1 && pngIndex != 0)
525 formats.move(pngIndex, 0);
526
527 return formats;
528}
529
530
531static QStringList imageWriteMimeFormats()
532{
533 QStringList formats;
534 QList<QByteArray> imageFormats = QImageWriter::supportedImageFormats();
535 for (int i = 0; i < imageFormats.size(); ++i) {
536 QString format = QLatin1String("image/");
537 format += QString::fromLatin1(imageFormats.at(i).toLower());
538 formats.append(format);
539 }
540
541 //put png at the front because it is best
542 int pngIndex = formats.indexOf(QLatin1String("image/png"));
543 if (pngIndex != -1 && pngIndex != 0)
544 formats.move(pngIndex, 0);
545
546 return formats;
547}
548
549QInternalMimeData::QInternalMimeData()
550 : QMimeData()
551{
552}
553
554QInternalMimeData::~QInternalMimeData()