1 /****************************************************************************
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtGui module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
42 #include "qplatformdefs.h"
49 #include "qtextcodec.h"
50 #include "qapplication.h"
58 #include "qimagereader.h"
59 #include "qimagewriter.h"
63 #include <private/qapplication_p.h>
65 #ifndef QT_NO_DRAGANDDROP
69 #ifndef QT_NO_DRAGANDDROP
74 QString dragActionsToString(Qt::DropActions actions)
77 if (actions == Qt::IgnoreAction) {
80 str += "IgnoreAction";
82 if (actions & Qt::LinkAction) {
87 if (actions & Qt::CopyAction) {
92 if (actions & Qt::MoveAction) {
97 if ((actions & Qt::TargetMoveAction) == Qt::TargetMoveAction ) {
100 str += "TargetMoveAction";
105 QString KeyboardModifiersToString(Qt::KeyboardModifiers moderfies)
108 if (moderfies & Qt::ControlModifier) {
111 str += Qt::ControlModifier;
113 if (moderfies & Qt::AltModifier) {
116 str += Qt::AltModifier;
118 if (moderfies & Qt::ShiftModifier) {
121 str += Qt::ShiftModifier;
128 // the universe's only drag manager
129 QDragManager *QDragManager::instance = 0;
132 QDragManager::QDragManager()
138 currentActionForOverrideCursor = Qt::IgnoreAction;
141 beingCancelled = false;
142 restoreCursor = false;
145 dropData = new QDropData();
146 currentDropTarget = 0;
148 xdndMimeTransferedPixmapIndex = 0;
153 QDragManager::~QDragManager()
157 QApplication::restoreOverrideCursor();
163 QDragManager *QDragManager::self()
165 if (!instance && !QApplication::closingDown())
166 instance = new QDragManager;
170 QPixmap QDragManager::dragCursor(Qt::DropAction action) const
172 QDragPrivate * d = dragPrivate();
173 if (d && d->customCursors.contains(action))
174 return d->customCursors[action];
175 else if (action == Qt::MoveAction)
176 return QApplicationPrivate::instance()->getPixmapCursor(Qt::DragMoveCursor);
177 else if (action == Qt::CopyAction)
178 return QApplicationPrivate::instance()->getPixmapCursor(Qt::DragCopyCursor);
179 else if (action == Qt::LinkAction)
180 return QApplicationPrivate::instance()->getPixmapCursor(Qt::DragLinkCursor);
182 else if (action == Qt::IgnoreAction)
183 return QApplicationPrivate::instance()->getPixmapCursor(Qt::ForbiddenCursor);
188 bool QDragManager::hasCustomDragCursors() const
190 QDragPrivate * d = dragPrivate();
191 return d && !d->customCursors.isEmpty();
194 Qt::DropAction QDragManager::defaultAction(Qt::DropActions possibleActions,
195 Qt::KeyboardModifiers modifiers) const
198 qDebug("QDragManager::defaultAction(Qt::DropActions possibleActions)");
199 qDebug("keyboard modifiers : %s", qPrintable(KeyboardModifiersToString(modifiers)));
202 QDragPrivate *d = dragPrivate();
203 Qt::DropAction defaultAction = d ? d->defaultDropAction : Qt::IgnoreAction;
205 if (defaultAction == Qt::IgnoreAction) {
206 //This means that the drag was initiated by QDrag::start and we need to
207 //preserve the old behavior
209 defaultAction = Qt::MoveAction;
211 defaultAction = Qt::CopyAction;
216 if (modifiers & Qt::ControlModifier && modifiers & Qt::AltModifier)
217 defaultAction = Qt::LinkAction;
218 else if (modifiers & Qt::AltModifier)
219 defaultAction = Qt::CopyAction;
220 else if (modifiers & Qt::ControlModifier)
221 defaultAction = Qt::MoveAction;
223 if (modifiers & Qt::ControlModifier && modifiers & Qt::ShiftModifier)
224 defaultAction = Qt::LinkAction;
225 else if (modifiers & Qt::ControlModifier)
226 defaultAction = Qt::CopyAction;
227 else if (modifiers & Qt::ShiftModifier)
228 defaultAction = Qt::MoveAction;
229 else if (modifiers & Qt::AltModifier)
230 defaultAction = Qt::LinkAction;
233 // if the object is set take the list of possibles from it
235 possibleActions = object->d_func()->possible_actions;
238 qDebug("possible actions : %s", qPrintable(dragActionsToString(possibleActions)));
241 // Check if the action determined is allowed
242 if (!(possibleActions & defaultAction)) {
243 if (possibleActions & Qt::CopyAction)
244 defaultAction = Qt::CopyAction;
245 else if (possibleActions & Qt::MoveAction)
246 defaultAction = Qt::MoveAction;
247 else if (possibleActions & Qt::LinkAction)
248 defaultAction = Qt::LinkAction;
250 defaultAction = Qt::IgnoreAction;
254 qDebug("default action : %s", qPrintable(dragActionsToString(defaultAction)));
257 return defaultAction;
260 void QDragManager::setCurrentTarget(QWidget *target, bool dropped)
262 if (currentDropTarget == target)
265 currentDropTarget = target;
266 if (!dropped && object) {
267 object->d_func()->target = target;
268 emit object->targetChanged(target);
273 QWidget *QDragManager::currentTarget()
275 return currentDropTarget;
280 QDropData::QDropData()
281 : QInternalMimeData()
285 QDropData::~QDropData()
288 #endif // QT_NO_DRAGANDDROP
290 #if !(defined(QT_NO_DRAGANDDROP) && defined(QT_NO_CLIPBOARD))
292 static QStringList imageReadMimeFormats()
295 QList<QByteArray> imageFormats = QImageReader::supportedImageFormats();
296 for (int i = 0; i < imageFormats.size(); ++i) {
297 QString format = QLatin1String("image/");
298 format += QString::fromLatin1(imageFormats.at(i).toLower());
299 formats.append(format);
302 //put png at the front because it is best
303 int pngIndex = formats.indexOf(QLatin1String("image/png"));
304 if (pngIndex != -1 && pngIndex != 0)
305 formats.move(pngIndex, 0);
311 static QStringList imageWriteMimeFormats()
314 QList<QByteArray> imageFormats = QImageWriter::supportedImageFormats();
315 for (int i = 0; i < imageFormats.size(); ++i) {
316 QString format = QLatin1String("image/");
317 format += QString::fromLatin1(imageFormats.at(i).toLower());
318 formats.append(format);
321 //put png at the front because it is best
322 int pngIndex = formats.indexOf(QLatin1String("image/png"));
323 if (pngIndex != -1 && pngIndex != 0)
324 formats.move(pngIndex, 0);
329 QInternalMimeData::QInternalMimeData()
334 QInternalMimeData::~QInternalMimeData()
338 bool QInternalMimeData::hasFormat(const QString &mimeType) const
340 bool foundFormat = hasFormat_sys(mimeType);
341 if (!foundFormat && mimeType == QLatin1String("application/x-qt-image")) {
342 QStringList imageFormats = imageReadMimeFormats();
343 for (int i = 0; i < imageFormats.size(); ++i) {
344 if ((foundFormat = hasFormat_sys(imageFormats.at(i))))
351 QStringList QInternalMimeData::formats() const
353 QStringList realFormats = formats_sys();
354 if (!realFormats.contains(QLatin1String("application/x-qt-image"))) {
355 QStringList imageFormats = imageReadMimeFormats();
356 for (int i = 0; i < imageFormats.size(); ++i) {
357 if (realFormats.contains(imageFormats.at(i))) {
358 realFormats += QLatin1String("application/x-qt-image");
366 QVariant QInternalMimeData::retrieveData(const QString &mimeType, QVariant::Type type) const
368 QVariant data = retrieveData_sys(mimeType, type);
369 if (mimeType == QLatin1String("application/x-qt-image")) {
370 if (data.isNull() || (data.type() == QVariant::ByteArray && data.toByteArray().isEmpty())) {
371 // try to find an image
372 QStringList imageFormats = imageReadMimeFormats();
373 for (int i = 0; i < imageFormats.size(); ++i) {
374 data = retrieveData_sys(imageFormats.at(i), type);
375 if (data.isNull() || (data.type() == QVariant::ByteArray && data.toByteArray().isEmpty()))
380 // we wanted some image type, but all we got was a byte array. Convert it to an image.
381 if (data.type() == QVariant::ByteArray
382 && (type == QVariant::Image || type == QVariant::Pixmap || type == QVariant::Bitmap))
383 data = QImage::fromData(data.toByteArray());
385 } else if (mimeType == QLatin1String("application/x-color") && data.type() == QVariant::ByteArray) {
387 QByteArray ba = data.toByteArray();
388 if (ba.size() == 8) {
389 ushort * colBuf = (ushort *)ba.data();
390 c.setRgbF(qreal(colBuf[0]) / qreal(0xFFFF),
391 qreal(colBuf[1]) / qreal(0xFFFF),
392 qreal(colBuf[2]) / qreal(0xFFFF),
393 qreal(colBuf[3]) / qreal(0xFFFF));
396 qWarning("Qt: Invalid color format");
398 } else if (data.type() != type && data.type() == QVariant::ByteArray) {
399 // try to use mime data's internal conversion stuf.
400 QInternalMimeData *that = const_cast<QInternalMimeData *>(this);
401 that->setData(mimeType, data.toByteArray());
402 data = QMimeData::retrieveData(mimeType, type);
408 bool QInternalMimeData::canReadData(const QString &mimeType)
410 return imageReadMimeFormats().contains(mimeType);
413 // helper functions for rendering mimedata to the system, this is needed because QMimeData is in core.
414 QStringList QInternalMimeData::formatsHelper(const QMimeData *data)
416 QStringList realFormats = data->formats();
417 if (realFormats.contains(QLatin1String("application/x-qt-image"))) {
418 // add all supported image formats
419 QStringList imageFormats = imageWriteMimeFormats();
420 for (int i = 0; i < imageFormats.size(); ++i) {
421 if (!realFormats.contains(imageFormats.at(i)))
422 realFormats.append(imageFormats.at(i));
428 bool QInternalMimeData::hasFormatHelper(const QString &mimeType, const QMimeData *data)
431 bool foundFormat = data->hasFormat(mimeType);
433 if (mimeType == QLatin1String("application/x-qt-image")) {
434 // check all supported image formats
435 QStringList imageFormats = imageWriteMimeFormats();
436 for (int i = 0; i < imageFormats.size(); ++i) {
437 if ((foundFormat = data->hasFormat(imageFormats.at(i))))
440 } else if (mimeType.startsWith(QLatin1String("image/"))) {
441 return data->hasImage() && imageWriteMimeFormats().contains(mimeType);
447 QByteArray QInternalMimeData::renderDataHelper(const QString &mimeType, const QMimeData *data)
450 if (mimeType == QLatin1String("application/x-color")) {
451 /* QMimeData can only provide colors as QColor or the name
452 of a color as a QByteArray or a QString. So we need to do
453 the conversion to application/x-color here.
454 The application/x-color format is :
455 type: application/x-color
463 ushort * colBuf = (ushort *)ba.data();
464 QColor c = qvariant_cast<QColor>(data->colorData());
465 colBuf[0] = ushort(c.redF() * 0xFFFF);
466 colBuf[1] = ushort(c.greenF() * 0xFFFF);
467 colBuf[2] = ushort(c.blueF() * 0xFFFF);
468 colBuf[3] = ushort(c.alphaF() * 0xFFFF);
470 ba = data->data(mimeType);
472 if (mimeType == QLatin1String("application/x-qt-image") && data->hasImage()) {
473 QImage image = qvariant_cast<QImage>(data->imageData());
475 buf.open(QBuffer::WriteOnly);
476 // would there not be PNG ??
477 image.save(&buf, "PNG");
478 } else if (mimeType.startsWith(QLatin1String("image/")) && data->hasImage()) {
479 QImage image = qvariant_cast<QImage>(data->imageData());
481 buf.open(QBuffer::WriteOnly);
482 image.save(&buf, mimeType.mid(mimeType.indexOf(QLatin1Char('/')) + 1).toLatin1().toUpper());
489 #endif // QT_NO_DRAGANDDROP && QT_NO_CLIPBOARD