~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/gui/kernel/qdnd.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
 
4
**
 
5
** This file is part of the gui module of the Qt Toolkit.
 
6
**
 
7
** This file may be distributed under the terms of the Q Public License
 
8
** as defined by Trolltech AS of Norway and appearing in the file
 
9
** LICENSE.QPL included in the packaging of this file.
 
10
**
 
11
** This file may be distributed and/or modified under the terms of the
 
12
** GNU General Public License version 2 as published by the Free Software
 
13
** Foundation and appearing in the file LICENSE.GPL included in the
 
14
** packaging of this file.
 
15
**
 
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
 
17
**   information about Qt Commercial License Agreements.
 
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
 
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
 
20
**
 
21
** Contact info@trolltech.com if any conditions of this licensing are
 
22
** not clear to you.
 
23
**
 
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
26
**
 
27
****************************************************************************/
 
28
 
 
29
#include "qplatformdefs.h"
 
30
 
 
31
#include "qbitmap.h"
 
32
#include "qdrag.h"
 
33
#include "qpixmap.h"
 
34
#include "qevent.h"
 
35
#include "qfile.h"
 
36
#include "qtextcodec.h"
 
37
#include "qapplication.h"
 
38
#include "qpoint.h"
 
39
#include "qwidget.h"
 
40
#include "qbuffer.h"
 
41
#include "qimage.h"
 
42
#include "qregexp.h"
 
43
#include "qdir.h"
 
44
#include "qdnd_p.h"
 
45
#include "qimagereader.h"
 
46
#include "qimagewriter.h"
 
47
#include "qdebug.h"
 
48
#include <ctype.h>
 
49
 
 
50
// These pixmaps approximate the images in the Windows User Interface Guidelines.
 
51
 
 
52
// XPM
 
53
 
 
54
static const char * const move_xpm[] = {
 
55
"11 20 3 1",
 
56
".        c None",
 
57
#if defined(Q_WS_WIN)
 
58
"a        c #000000",
 
59
"X        c #FFFFFF", // Windows cursor is traditionally white
 
60
#else
 
61
"a        c #FFFFFF",
 
62
"X        c #000000", // X11 cursor is traditionally black
 
63
#endif
 
64
"aa.........",
 
65
"aXa........",
 
66
"aXXa.......",
 
67
"aXXXa......",
 
68
"aXXXXa.....",
 
69
"aXXXXXa....",
 
70
"aXXXXXXa...",
 
71
"aXXXXXXXa..",
 
72
"aXXXXXXXXa.",
 
73
"aXXXXXXXXXa",
 
74
"aXXXXXXaaaa",
 
75
"aXXXaXXa...",
 
76
"aXXaaXXa...",
 
77
"aXa..aXXa..",
 
78
"aa...aXXa..",
 
79
"a.....aXXa.",
 
80
"......aXXa.",
 
81
".......aXXa",
 
82
".......aXXa",
 
83
"........aa."};
 
84
 
 
85
/* XPM */
 
86
static const char * const copy_xpm[] = {
 
87
"24 30 3 1",
 
88
".        c None",
 
89
"a        c #000000",
 
90
"X        c #FFFFFF",
 
91
#if defined(Q_WS_WIN) // Windows cursor is traditionally white
 
92
"aa......................",
 
93
"aXa.....................",
 
94
"aXXa....................",
 
95
"aXXXa...................",
 
96
"aXXXXa..................",
 
97
"aXXXXXa.................",
 
98
"aXXXXXXa................",
 
99
"aXXXXXXXa...............",
 
100
"aXXXXXXXXa..............",
 
101
"aXXXXXXXXXa.............",
 
102
"aXXXXXXaaaa.............",
 
103
"aXXXaXXa................",
 
104
"aXXaaXXa................",
 
105
"aXa..aXXa...............",
 
106
"aa...aXXa...............",
 
107
"a.....aXXa..............",
 
108
"......aXXa..............",
 
109
".......aXXa.............",
 
110
".......aXXa.............",
 
111
"........aa...aaaaaaaaaaa",
 
112
#else
 
113
"XX......................",
 
114
"XaX.....................",
 
115
"XaaX....................",
 
116
"XaaaX...................",
 
117
"XaaaaX..................",
 
118
"XaaaaaX.................",
 
119
"XaaaaaaX................",
 
120
"XaaaaaaaX...............",
 
121
"XaaaaaaaaX..............",
 
122
"XaaaaaaaaaX.............",
 
123
"XaaaaaaXXXX.............",
 
124
"XaaaXaaX................",
 
125
"XaaXXaaX................",
 
126
"XaX..XaaX...............",
 
127
"XX...XaaX...............",
 
128
"X.....XaaX..............",
 
129
"......XaaX..............",
 
130
".......XaaX.............",
 
131
".......XaaX.............",
 
132
"........XX...aaaaaaaaaaa",
 
133
#endif
 
134
".............aXXXXXXXXXa",
 
135
".............aXXXXXXXXXa",
 
136
".............aXXXXaXXXXa",
 
137
".............aXXXXaXXXXa",
 
138
".............aXXaaaaaXXa",
 
139
".............aXXXXaXXXXa",
 
140
".............aXXXXaXXXXa",
 
141
".............aXXXXXXXXXa",
 
142
".............aXXXXXXXXXa",
 
143
".............aaaaaaaaaaa"};
 
144
 
 
145
/* XPM */
 
146
static const char * const link_xpm[] = {
 
147
"24 30 3 1",
 
148
".        c None",
 
149
"a        c #000000",
 
150
"X        c #FFFFFF",
 
151
#if defined(Q_WS_WIN) // Windows cursor is traditionally white
 
152
"aa......................",
 
153
"aXa.....................",
 
154
"aXXa....................",
 
155
"aXXXa...................",
 
156
"aXXXXa..................",
 
157
"aXXXXXa.................",
 
158
"aXXXXXXa................",
 
159
"aXXXXXXXa...............",
 
160
"aXXXXXXXXa..............",
 
161
"aXXXXXXXXXa.............",
 
162
"aXXXXXXaaaa.............",
 
163
"aXXXaXXa................",
 
164
"aXXaaXXa................",
 
165
"aXa..aXXa...............",
 
166
"aa...aXXa...............",
 
167
"a.....aXXa..............",
 
168
"......aXXa..............",
 
169
".......aXXa.............",
 
170
".......aXXa.............",
 
171
"........aa...aaaaaaaaaaa",
 
172
#else
 
173
"XX......................",
 
174
"XaX.....................",
 
175
"XaaX....................",
 
176
"XaaaX...................",
 
177
"XaaaaX..................",
 
178
"XaaaaaX.................",
 
179
"XaaaaaaX................",
 
180
"XaaaaaaaX...............",
 
181
"XaaaaaaaaX..............",
 
182
"XaaaaaaaaaX.............",
 
183
"XaaaaaaXXXX.............",
 
184
"XaaaXaaX................",
 
185
"XaaXXaaX................",
 
186
"XaX..XaaX...............",
 
187
"XX...XaaX...............",
 
188
"X.....XaaX..............",
 
189
"......XaaX..............",
 
190
".......XaaX.............",
 
191
".......XaaX.............",
 
192
"........XX...aaaaaaaaaaa",
 
193
#endif
 
194
".............aXXXXXXXXXa",
 
195
".............aXXXaaaaXXa",
 
196
".............aXXXXaaaXXa",
 
197
".............aXXXaaaaXXa",
 
198
".............aXXaaaXaXXa",
 
199
".............aXXaaXXXXXa",
 
200
".............aXXaXXXXXXa",
 
201
".............aXXXaXXXXXa",
 
202
".............aXXXXXXXXXa",
 
203
".............aaaaaaaaaaa"};
 
204
 
 
205
#ifndef QT_NO_DRAGANDDROP
 
206
 
 
207
//#define QDND_DEBUG
 
208
 
 
209
#ifdef QDND_DEBUG
 
210
QString dragActionsToString(Qt::DropActions actions)
 
211
{
 
212
    QString str;
 
213
    if (actions == Qt::IgnoreAction) {
 
214
        if (!str.isEmpty())
 
215
            str += " | ";
 
216
        str += "IgnoreAction";
 
217
    }
 
218
    if (actions & Qt::LinkAction) {
 
219
        if (!str.isEmpty())
 
220
            str += " | ";
 
221
        str += "LinkAction";
 
222
    }
 
223
    if (actions & Qt::CopyAction) {
 
224
        if (!str.isEmpty())
 
225
            str += " | ";
 
226
        str += "CopyAction";
 
227
    }
 
228
    if (actions & Qt::MoveAction) {
 
229
        if (!str.isEmpty())
 
230
            str += " | ";
 
231
        str += "MoveAction";
 
232
    }
 
233
    if ((actions & Qt::TargetMoveAction) == Qt::TargetMoveAction ) {
 
234
        if (!str.isEmpty())
 
235
            str += " | ";
 
236
        str += "TargetMoveAction";
 
237
    }
 
238
    return str;
 
239
}
 
240
 
 
241
QString KeyboardModifiersToString(Qt::KeyboardModifiers moderfies)
 
242
{
 
243
    QString str;
 
244
    if (moderfies & Qt::ControlModifier) {
 
245
        if (!str.isEmpty())
 
246
            str += " | ";
 
247
        str += Qt::ControlModifier;
 
248
    }
 
249
    if (moderfies & Qt::AltModifier) {
 
250
        if (!str.isEmpty())
 
251
            str += " | ";
 
252
        str += Qt::AltModifier;
 
253
    }
 
254
    if (moderfies & Qt::ShiftModifier) {
 
255
        if (!str.isEmpty())
 
256
            str += " | ";
 
257
        str += Qt::ShiftModifier;
 
258
    }
 
259
    return str;
 
260
}
 
261
#endif
 
262
 
 
263
 
 
264
// the universe's only drag manager
 
265
QDragManager *QDragManager::instance = 0;
 
266
 
 
267
 
 
268
QDragManager::QDragManager()
 
269
    : QObject(qApp)
 
270
{
 
271
    Q_ASSERT(!instance);
 
272
    n_cursor = 3;
 
273
    pm_cursor = new QPixmap[n_cursor];
 
274
    pm_cursor[0] = QPixmap((const char **)move_xpm);
 
275
    pm_cursor[1] = QPixmap((const char **)copy_xpm);
 
276
    pm_cursor[2] = QPixmap((const char **)link_xpm);
 
277
    object = 0;
 
278
    beingCancelled = false;
 
279
    restoreCursor = false;
 
280
    willDrop = false;
 
281
    eventLoop = 0;
 
282
    dropData = new QDropData();
 
283
}
 
284
 
 
285
 
 
286
QDragManager::~QDragManager()
 
287
{
 
288
#ifndef QT_NO_CURSOR
 
289
    if (restoreCursor)
 
290
        QApplication::restoreOverrideCursor();
 
291
#endif
 
292
    instance = 0;
 
293
    delete [] pm_cursor;
 
294
    delete dropData;
 
295
}
 
296
 
 
297
QDragManager *QDragManager::self()
 
298
{
 
299
    if (!instance && qApp && !qApp->closingDown())
 
300
        instance = new QDragManager;
 
301
    return instance;
 
302
}
 
303
 
 
304
QPixmap QDragManager::dragCursor(Qt::DropAction action) const
 
305
{
 
306
    QDragPrivate * d = dragPrivate();
 
307
    if (d && d->customCursors.contains(action))
 
308
        return d->customCursors[action];
 
309
    else if (action == Qt::MoveAction)
 
310
        return pm_cursor[0];
 
311
    else if (action == Qt::CopyAction)
 
312
        return pm_cursor[1];
 
313
    else if (action == Qt::LinkAction)
 
314
        return pm_cursor[2];
 
315
    return 0;
 
316
}
 
317
 
 
318
bool QDragManager::hasCustomDragCursors() const
 
319
{
 
320
    QDragPrivate * d = dragPrivate();
 
321
    return d && !d->customCursors.isEmpty();
 
322
}
 
323
 
 
324
Qt::DropAction QDragManager::defaultAction(Qt::DropActions possibleActions,
 
325
                                           Qt::KeyboardModifiers modifiers) const
 
326
{
 
327
    Qt::DropAction defaultAction = Qt::CopyAction;
 
328
 
 
329
#ifdef QDND_DEBUG
 
330
    qDebug("QDragManager::defaultAction(Qt::DropActions possibleActions)");
 
331
    qDebug("keyboard modifiers : %s", KeyboardModifiersToString(modifiers).latin1());
 
332
#endif
 
333
 
 
334
#ifdef Q_WS_MAC
 
335
    if (modifiers & Qt::ControlModifier && modifiers & Qt::AltModifier)
 
336
        defaultAction = Qt::LinkAction;
 
337
    else if (modifiers & Qt::AltModifier)
 
338
        defaultAction = Qt::CopyAction;
 
339
    else
 
340
        defaultAction = Qt::MoveAction;
 
341
#else
 
342
    if (modifiers & Qt::ControlModifier && modifiers & Qt::ShiftModifier)
 
343
        defaultAction = Qt::LinkAction;
 
344
    else if (modifiers & Qt::ControlModifier)
 
345
        defaultAction = Qt::CopyAction;
 
346
    else if (modifiers & Qt::ShiftModifier)
 
347
        defaultAction = Qt::MoveAction;
 
348
    else if (modifiers & Qt::AltModifier)
 
349
        defaultAction = Qt::LinkAction;
 
350
#endif
 
351
 
 
352
    // if the object is set take the list of possibles from it
 
353
    if (object)
 
354
        possibleActions = object->d_func()->possible_actions;
 
355
 
 
356
#ifdef QDND_DEBUG
 
357
    qDebug("possible actions : %s", dragActionsToString(possibleActions).latin1());
 
358
#endif
 
359
 
 
360
    // Check if the action determined is allowed
 
361
    if (!(possibleActions & defaultAction))
 
362
        defaultAction = Qt::CopyAction;
 
363
 
 
364
#ifdef QDND_DEBUG
 
365
    qDebug("default action : %s", dragActionsToString(defaultAction).latin1());
 
366
#endif
 
367
 
 
368
    return defaultAction;
 
369
}
 
370
 
 
371
#endif
 
372
 
 
373
static QStringList imageReadMimeFormats()
 
374
{
 
375
    QStringList formats;
 
376
    QList<QByteArray> imageFormats = QImageReader::supportedImageFormats();
 
377
    for (int i = 0; i < imageFormats.size(); ++i) {
 
378
        QString format = QLatin1String("image/");
 
379
        format += QString::fromLatin1(imageFormats.at(i).toLower());
 
380
        formats.append(format);
 
381
    }
 
382
 
 
383
    //put png at the front because it is best
 
384
    int pngIndex = formats.indexOf(QLatin1String("image/png"));
 
385
    if (pngIndex != -1 && pngIndex != 0)
 
386
        formats.move(pngIndex, 0);
 
387
 
 
388
    return formats;
 
389
}
 
390
 
 
391
 
 
392
static QStringList imageWriteMimeFormats()
 
393
{
 
394
    QStringList formats;
 
395
    QList<QByteArray> imageFormats = QImageWriter::supportedImageFormats();
 
396
    for (int i = 0; i < imageFormats.size(); ++i) {
 
397
        QString format = QLatin1String("image/");
 
398
        format += QString::fromLatin1(imageFormats.at(i).toLower());
 
399
        formats.append(format);
 
400
    }
 
401
 
 
402
    //put png at the front because it is best
 
403
    int pngIndex = formats.indexOf(QLatin1String("image/png"));
 
404
    if (pngIndex != -1 && pngIndex != 0)
 
405
        formats.move(pngIndex, 0);
 
406
 
 
407
    return formats;
 
408
}
 
409
 
 
410
QInternalMimeData::QInternalMimeData()
 
411
    : QMimeData()
 
412
{
 
413
}
 
414
 
 
415
QInternalMimeData::~QInternalMimeData()
 
416
{
 
417
}
 
418
 
 
419
bool QInternalMimeData::hasFormat(const QString &mimeType) const
 
420
{
 
421
    bool foundFormat = hasFormat_sys(mimeType);
 
422
    if (!foundFormat && mimeType == QLatin1String("application/x-qt-image")) {
 
423
        QStringList imageFormats = imageReadMimeFormats();
 
424
        for (int i = 0; i < imageFormats.size(); ++i) {
 
425
            if ((foundFormat = hasFormat_sys(imageFormats.at(i))))
 
426
                break;
 
427
        }
 
428
    }
 
429
    return foundFormat;
 
430
}
 
431
 
 
432
QStringList QInternalMimeData::formats() const
 
433
{
 
434
    QStringList realFormats = formats_sys();
 
435
    if (!realFormats.contains(QLatin1String("application/x-qt-image"))) {
 
436
        QStringList imageFormats = imageReadMimeFormats();
 
437
        for (int i = 0; i < imageFormats.size(); ++i) {
 
438
            if (realFormats.contains(imageFormats.at(i))) {
 
439
                realFormats += QLatin1String("application/x-qt-image");
 
440
                break;
 
441
            }
 
442
        }
 
443
    }
 
444
    return realFormats;
 
445
}
 
446
 
 
447
QVariant QInternalMimeData::retrieveData(const QString &mimeType, QVariant::Type type) const
 
448
{
 
449
    QVariant data = retrieveData_sys(mimeType, type);
 
450
    if (mimeType == QLatin1String("application/x-qt-image")) {
 
451
        if (data.isNull() || (data.type() == QVariant::ByteArray && data.toByteArray().isEmpty())) {
 
452
            // try to find an image
 
453
            QStringList imageFormats = imageReadMimeFormats();
 
454
            for (int i = 0; i < imageFormats.size(); ++i) {
 
455
                data = retrieveData_sys(imageFormats.at(i), type);
 
456
                if (data.isNull() || (data.type() == QVariant::ByteArray && data.toByteArray().isEmpty()))
 
457
                    continue;
 
458
                break;
 
459
            }
 
460
        }
 
461
        // we wanted some image type, but all we got was a byte array. Convert it to an image.
 
462
        if (data.type() == QVariant::ByteArray
 
463
            && (type == QVariant::Image || type == QVariant::Pixmap || type == QVariant::Bitmap))
 
464
            data = QImage::fromData(data.toByteArray());
 
465
 
 
466
    } else if (mimeType == QLatin1String("application/x-color") && data.type() == QVariant::ByteArray) {
 
467
        QColor c;
 
468
        QByteArray ba = data.toByteArray();
 
469
        if (ba.size() == 8) {
 
470
            ushort * colBuf = (ushort *)ba.data();
 
471
            c.setRgbF(qreal(colBuf[0]) / qreal(0xFFFF),
 
472
                      qreal(colBuf[1]) / qreal(0xFFFF),
 
473
                      qreal(colBuf[2]) / qreal(0xFFFF),
 
474
                      qreal(colBuf[3]) / qreal(0xFFFF));
 
475
            data = c;
 
476
        } else {
 
477
            qWarning("Invalid color format");
 
478
        }
 
479
    } else if (data.type() != type && data.type() == QVariant::ByteArray) {
 
480
        // try to use mime data's internal conversion stuf.
 
481
        QInternalMimeData *that = const_cast<QInternalMimeData *>(this);
 
482
        that->setData(mimeType, data.toByteArray());
 
483
        data = QMimeData::retrieveData(mimeType, type);
 
484
        that->clear();
 
485
    }
 
486
    return data;
 
487
}
 
488
 
 
489
bool QInternalMimeData::canReadData(const QString &mimeType)
 
490
{
 
491
    return imageReadMimeFormats().contains(mimeType);
 
492
}
 
493
 
 
494
// helper functions for rendering mimedata to the system, this is needed because QMimeData is in core.
 
495
QStringList QInternalMimeData::formatsHelper(const QMimeData *data)
 
496
{
 
497
    QStringList realFormats = data->formats();
 
498
    if (realFormats.contains(QLatin1String("application/x-qt-image"))) {
 
499
        // add all supported image formats
 
500
        QStringList imageFormats = imageWriteMimeFormats();
 
501
        for (int i = 0; i < imageFormats.size(); ++i) {
 
502
            if (!realFormats.contains(imageFormats.at(i)))
 
503
                realFormats.append(imageFormats.at(i));
 
504
        }
 
505
    }
 
506
    return realFormats;
 
507
}
 
508
 
 
509
bool QInternalMimeData::hasFormatHelper(const QString &mimeType, const QMimeData *data)
 
510
{
 
511
 
 
512
    bool foundFormat = data->hasFormat(mimeType);
 
513
    if (!foundFormat) {
 
514
        if (mimeType == QLatin1String("application/x-qt-image")) {
 
515
            // check all supported image formats
 
516
            QStringList imageFormats = imageWriteMimeFormats();
 
517
            for (int i = 0; i < imageFormats.size(); ++i) {
 
518
                if ((foundFormat = data->hasFormat(imageFormats.at(i))))
 
519
                    break;
 
520
            }
 
521
        } else if (mimeType.startsWith(QLatin1String("image/"))) {
 
522
            return data->hasImage() && imageWriteMimeFormats().contains(mimeType);
 
523
        }
 
524
    }
 
525
    return foundFormat;
 
526
}
 
527
 
 
528
QByteArray QInternalMimeData::renderDataHelper(const QString &mimeType, const QMimeData *data)
 
529
{
 
530
    QByteArray ba;
 
531
    if (mimeType == QLatin1String("application/x-color")) {
 
532
        /* QMimeData can only provide colors as QColor or the name
 
533
           of a color as a QByteArray or a QString. So we need to do
 
534
           the conversion to application/x-color here.
 
535
           The application/x-color format is :
 
536
           type: application/x-color
 
537
           format: 16
 
538
           data[0]: red
 
539
           data[1]: green
 
540
           data[2]: blue
 
541
           data[3]: opacity
 
542
        */
 
543
        ba.resize(8);
 
544
        ushort * colBuf = (ushort *)ba.data();
 
545
        QColor c = qvariant_cast<QColor>(data->colorData());
 
546
        colBuf[0] = ushort(c.redF() * 0xFFFF);
 
547
        colBuf[1] = ushort(c.greenF() * 0xFFFF);
 
548
        colBuf[2] = ushort(c.blueF() * 0xFFFF);
 
549
        colBuf[3] = ushort(c.alphaF() * 0xFFFF);
 
550
    } else {
 
551
        ba = data->data(mimeType);
 
552
        if (ba.isEmpty()) {
 
553
            if (mimeType == QLatin1String("application/x-qt-image") && data->hasImage()) {
 
554
                QImage image = qvariant_cast<QImage>(data->imageData());
 
555
                QBuffer buf(&ba);
 
556
                buf.open(QBuffer::WriteOnly);
 
557
                // would there not be PNG ??
 
558
                image.save(&buf, "PNG");
 
559
            } else if (mimeType.startsWith(QLatin1String("image/")) && data->hasImage()) {
 
560
                QImage image = qvariant_cast<QImage>(data->imageData());
 
561
                QBuffer buf(&ba);
 
562
                buf.open(QBuffer::WriteOnly);
 
563
                image.save(&buf, mimeType.mid(mimeType.indexOf('/') + 1).toLatin1().toUpper());
 
564
            }
 
565
        }
 
566
    }
 
567
    return ba;
 
568
}
 
569
 
 
570
QDropData::QDropData()
 
571
    : QInternalMimeData()
 
572
{
 
573
}
 
574
 
 
575
QDropData::~QDropData()
 
576
{
 
577
}