| /**************************************************************************** |
| ** |
| ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). |
| ** All rights reserved. |
| ** Contact: Nokia Corporation (qt-info@nokia.com) |
| ** |
| ** This file is part of the QtGui module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** GNU Lesser General Public License Usage |
| ** This file may be used under the terms of the GNU Lesser General Public |
| ** License version 2.1 as published by the Free Software Foundation and |
| ** appearing in the file LICENSE.LGPL included in the packaging of this |
| ** file. Please review the following information to ensure the GNU Lesser |
| ** General Public License version 2.1 requirements will be met: |
| ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
| ** |
| ** In addition, as a special exception, Nokia gives you certain additional |
| ** rights. These rights are described in the Nokia Qt LGPL Exception |
| ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU General |
| ** Public License version 3.0 as published by the Free Software Foundation |
| ** and appearing in the file LICENSE.GPL included in the packaging of this |
| ** file. Please review the following information to ensure the GNU General |
| ** Public License version 3.0 requirements will be met: |
| ** http://www.gnu.org/copyleft/gpl.html. |
| ** |
| ** Other Usage |
| ** Alternatively, this file may be used in accordance with the terms and |
| ** conditions contained in a signed written agreement between you and Nokia. |
| ** |
| ** |
| ** |
| ** |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qapplication.h" |
| #ifndef QT_NO_DRAGANDDROP |
| #include "qbitmap.h" |
| #include "qcursor.h" |
| #include "qevent.h" |
| #include "qpainter.h" |
| #include "qurl.h" |
| #include "qwidget.h" |
| #include "qfile.h" |
| #include "qfileinfo.h" |
| #include <stdlib.h> |
| #include <string.h> |
| #ifndef QT_NO_ACCESSIBILITY |
| # include "qaccessible.h" |
| #endif |
| |
| #include <private/qapplication_p.h> |
| #include <private/qwidget_p.h> |
| #include <private/qdnd_p.h> |
| #include <private/qt_mac_p.h> |
| |
| QT_BEGIN_NAMESPACE |
| |
| QT_USE_NAMESPACE |
| |
| QMacDndAnswerRecord qt_mac_dnd_answer_rec; |
| |
| /***************************************************************************** |
| QDnD debug facilities |
| *****************************************************************************/ |
| //#define DEBUG_DRAG_EVENTS |
| //#define DEBUG_DRAG_PROMISES |
| |
| /***************************************************************************** |
| QDnD globals |
| *****************************************************************************/ |
| bool qt_mac_in_drag = false; |
| #ifndef QT_MAC_USE_COCOA |
| static DragReference qt_mac_current_dragRef = 0; |
| #endif |
| |
| /***************************************************************************** |
| Externals |
| *****************************************************************************/ |
| extern void qt_mac_send_modifiers_changed(quint32, QObject *); //qapplication_mac.cpp |
| extern uint qGlobalPostedEventsCount(); //qapplication.cpp |
| extern RgnHandle qt_mac_get_rgn(); // qregion_mac.cpp |
| extern void qt_mac_dispose_rgn(RgnHandle); // qregion_mac.cpp |
| /***************************************************************************** |
| QDnD utility functions |
| *****************************************************************************/ |
| |
| //default pixmap |
| static const int default_pm_hotx = -2; |
| static const int default_pm_hoty = -16; |
| #ifndef QT_MAC_USE_COCOA |
| static const char * const default_pm[] = { |
| "13 9 3 1", |
| ". c None", |
| " c #000000", |
| "X c #FFFFFF", |
| "X X X X X X X", |
| " X X X X X X ", |
| "X ......... X", |
| " X.........X ", |
| "X ......... X", |
| " X.........X ", |
| "X ......... X", |
| " X X X X X X ", |
| "X X X X X X X", |
| }; |
| #endif |
| |
| //action management |
| #ifdef DEBUG_DRAG_EVENTS |
| # define MAP_MAC_ENUM(x) x, #x |
| #else |
| # define MAP_MAC_ENUM(x) x |
| #endif |
| struct mac_enum_mapper |
| { |
| int mac_code; |
| int qt_code; |
| #ifdef DEBUG_DRAG_EVENTS |
| char *qt_desc; |
| #endif |
| }; |
| #ifndef QT_MAC_USE_COCOA |
| static mac_enum_mapper dnd_action_symbols[] = { |
| { kDragActionAlias, MAP_MAC_ENUM(Qt::LinkAction) }, |
| { kDragActionMove, MAP_MAC_ENUM(Qt::MoveAction) }, |
| { kDragActionGeneric, MAP_MAC_ENUM(Qt::CopyAction) }, |
| { kDragActionCopy, MAP_MAC_ENUM(Qt::CopyAction) }, |
| { 0, MAP_MAC_ENUM(0) } |
| }; |
| static DragActions qt_mac_dnd_map_qt_actions(Qt::DropActions qActions) |
| { |
| DragActions ret = kDragActionNothing; |
| for(int i = 0; dnd_action_symbols[i].qt_code; ++i) { |
| if(qActions & dnd_action_symbols[i].qt_code) |
| ret |= dnd_action_symbols[i].mac_code; |
| } |
| return ret; |
| } |
| static Qt::DropActions qt_mac_dnd_map_mac_actions(DragActions macActions) |
| { |
| #ifdef DEBUG_DRAG_EVENTS |
| qDebug("Converting DND ActionList: 0x%lx", macActions); |
| #endif |
| Qt::DropActions ret = Qt::IgnoreAction; |
| for(int i = 0; dnd_action_symbols[i].qt_code; ++i) { |
| #ifdef DEBUG_DRAG_EVENTS |
| qDebug(" %d) [%s] : %s", i, dnd_action_symbols[i].qt_desc, |
| (macActions & dnd_action_symbols[i].mac_code) ? "true" : "false"); |
| #endif |
| if(macActions & dnd_action_symbols[i].mac_code) |
| ret |= Qt::DropAction(dnd_action_symbols[i].qt_code); |
| } |
| return ret; |
| } |
| static Qt::DropAction qt_mac_dnd_map_mac_default_action(DragActions macActions) |
| { |
| static Qt::DropAction preferred_actions[] = { Qt::CopyAction, Qt::LinkAction, //in order |
| Qt::MoveAction, Qt::IgnoreAction }; |
| Qt::DropAction ret = Qt::IgnoreAction; |
| const Qt::DropActions qtActions = qt_mac_dnd_map_mac_actions(macActions); |
| for(int i = 0; preferred_actions[i] != Qt::IgnoreAction; ++i) { |
| if(qtActions & preferred_actions[i]) { |
| ret = preferred_actions[i]; |
| break; |
| } |
| } |
| #ifdef DEBUG_DRAG_EVENTS |
| for(int i = 0; dnd_action_symbols[i].qt_code; ++i) { |
| if(dnd_action_symbols[i].qt_code == ret) { |
| qDebug("Got default action: %s [0x%lx]", dnd_action_symbols[i].qt_desc, macActions); |
| break; |
| } |
| } |
| #endif |
| return ret; |
| } |
| static void qt_mac_dnd_update_action(DragReference dragRef) { |
| SInt16 modifiers; |
| GetDragModifiers(dragRef, &modifiers, 0, 0); |
| qt_mac_send_modifiers_changed(modifiers, qApp); |
| |
| Qt::DropAction qtAction = Qt::IgnoreAction; |
| { |
| DragActions macAllowed = kDragActionNothing; |
| GetDragDropAction(dragRef, &macAllowed); |
| Qt::DropActions qtAllowed = qt_mac_dnd_map_mac_actions(macAllowed); |
| qtAction = QDragManager::self()->defaultAction(qtAllowed, QApplication::keyboardModifiers()); |
| #if 1 |
| if(!(qtAllowed & qtAction)) |
| qtAction = qt_mac_dnd_map_mac_default_action(macAllowed); |
| #endif |
| } |
| DragActions macAction = qt_mac_dnd_map_qt_actions(qtAction); |
| |
| DragActions currentActions; |
| GetDragDropAction(dragRef, ¤tActions); |
| if(currentActions != macAction) { |
| SetDragDropAction(dragRef, macAction); |
| QDragManager::self()->emitActionChanged(qtAction); |
| } |
| } |
| #endif // !QT_MAC_USE_COCOA |
| |
| /***************************************************************************** |
| DnD functions |
| *****************************************************************************/ |
| bool QDropData::hasFormat_sys(const QString &mime) const |
| { |
| #ifndef QT_MAC_USE_COCOA |
| OSPasteboardRef board; |
| if(GetDragPasteboard(qt_mac_current_dragRef, &board) != noErr) { |
| qDebug("DnD: Cannot get PasteBoard!"); |
| return false; |
| } |
| return QMacPasteboard(board, QMacPasteboardMime::MIME_DND).hasFormat(mime); |
| #else |
| Q_UNUSED(mime); |
| return false; |
| #endif // !QT_MAC_USE_COCOA |
| } |
| |
| QVariant QDropData::retrieveData_sys(const QString &mime, QVariant::Type type) const |
| { |
| #ifndef QT_MAC_USE_COCOA |
| OSPasteboardRef board; |
| if(GetDragPasteboard(qt_mac_current_dragRef, &board) != noErr) { |
| qDebug("DnD: Cannot get PasteBoard!"); |
| return QVariant(); |
| } |
| return QMacPasteboard(board, QMacPasteboardMime::MIME_DND).retrieveData(mime, type); |
| #else |
| Q_UNUSED(mime); |
| Q_UNUSED(type); |
| return QVariant(); |
| #endif // !QT_MAC_USE_COCOA |
| } |
| |
| QStringList QDropData::formats_sys() const |
| { |
| #ifndef QT_MAC_USE_COCOA |
| OSPasteboardRef board; |
| if(GetDragPasteboard(qt_mac_current_dragRef, &board) != noErr) { |
| qDebug("DnD: Cannot get PasteBoard!"); |
| return QStringList(); |
| } |
| return QMacPasteboard(board, QMacPasteboardMime::MIME_DND).formats(); |
| #else |
| return QStringList(); |
| #endif |
| } |
| |
| void QDragManager::timerEvent(QTimerEvent*) |
| { |
| } |
| |
| bool QDragManager::eventFilter(QObject *, QEvent *) |
| { |
| return false; |
| } |
| |
| void QDragManager::updateCursor() |
| { |
| } |
| |
| void QDragManager::cancel(bool) |
| { |
| if(object) { |
| beingCancelled = true; |
| object = 0; |
| } |
| #ifndef QT_NO_ACCESSIBILITY |
| QAccessible::updateAccessibility(this, 0, QAccessible::DragDropEnd); |
| #endif |
| } |
| |
| void QDragManager::move(const QPoint &) |
| { |
| } |
| |
| void QDragManager::drop() |
| { |
| } |
| |
| /** |
| If a drop action is already set on the carbon event |
| (from e.g. an earlier enter event), we insert the same |
| action on the new Qt event that has yet to be sendt. |
| */ |
| static inline bool qt_mac_set_existing_drop_action(const DragRef &dragRef, QDropEvent &event) |
| { |
| #ifndef QT_MAC_USE_COCOA |
| DragActions currentAction = kDragActionNothing; |
| OSStatus err = GetDragDropAction(dragRef, ¤tAction); |
| if (err == noErr && currentAction != kDragActionNothing) { |
| // This looks a bit evil, but we only ever set one action, so it's OK. |
| event.setDropAction(Qt::DropAction(int(qt_mac_dnd_map_mac_actions(currentAction)))); |
| return true; |
| } |
| #else |
| Q_UNUSED(dragRef); |
| Q_UNUSED(event); |
| #endif |
| return false; |
| } |
| |
| /** |
| If an answer rect has been set on the event (after being sent |
| to the global event processor), we store that rect so we can |
| check if the mouse is in the same area upon next drag move event. |
| */ |
| void qt_mac_copy_answer_rect(const QDragMoveEvent &event) |
| { |
| if (!event.answerRect().isEmpty()) { |
| qt_mac_dnd_answer_rec.rect = event.answerRect(); |
| qt_mac_dnd_answer_rec.buttons = event.mouseButtons(); |
| qt_mac_dnd_answer_rec.modifiers = event.keyboardModifiers(); |
| qt_mac_dnd_answer_rec.lastAction = event.dropAction(); |
| } |
| } |
| |
| bool qt_mac_mouse_inside_answer_rect(QPoint mouse) |
| { |
| if (!qt_mac_dnd_answer_rec.rect.isEmpty() |
| && qt_mac_dnd_answer_rec.rect.contains(mouse) |
| && QApplication::mouseButtons() == qt_mac_dnd_answer_rec.buttons |
| && QApplication::keyboardModifiers() == qt_mac_dnd_answer_rec.modifiers) |
| return true; |
| else |
| return false; |
| } |
| |
| bool QWidgetPrivate::qt_mac_dnd_event(uint kind, DragRef dragRef) |
| { |
| #ifndef QT_MAC_USE_COCOA |
| Q_Q(QWidget); |
| qt_mac_current_dragRef = dragRef; |
| if (kind != kEventControlDragLeave) |
| qt_mac_dnd_update_action(dragRef); |
| |
| Point mouse; |
| GetDragMouse(dragRef, &mouse, 0L); |
| if(!mouse.h && !mouse.v) |
| GetGlobalMouse(&mouse); |
| |
| if(QApplicationPrivate::modalState()) { |
| for(QWidget *modal = q; modal; modal = modal->parentWidget()) { |
| if(modal->isWindow()) { |
| if(modal != QApplication::activeModalWidget()) |
| return noErr; |
| break; |
| } |
| } |
| } |
| |
| //lookup the possible actions |
| DragActions allowed = kDragActionNothing; |
| GetDragAllowableActions(dragRef, &allowed); |
| Qt::DropActions qtAllowed = qt_mac_dnd_map_mac_actions(allowed); |
| |
| //lookup the source dragAccepted |
| QMimeData *dropdata = QDragManager::self()->dropData; |
| if(QDragManager::self()->source()) |
| dropdata = QDragManager::self()->dragPrivate()->data; |
| |
| // 'interrestedInDrag' should end up being 'true' if a later drop |
| // will be accepted by the widget for the current mouse position |
| bool interrestedInDrag = true; |
| |
| //Dispatch events |
| if (kind == kEventControlDragWithin) { |
| if (qt_mac_mouse_inside_answer_rect(q->mapFromGlobal(QPoint(mouse.h, mouse.v)))) |
| return qt_mac_dnd_answer_rec.lastAction == Qt::IgnoreAction; |
| else |
| qt_mac_dnd_answer_rec.clear(); |
| |
| QDragMoveEvent qDMEvent(q->mapFromGlobal(QPoint(mouse.h, mouse.v)), qtAllowed, dropdata, |
| QApplication::mouseButtons(), QApplication::keyboardModifiers()); |
| |
| // Accept the event by default if a |
| // drag action exists on the carbon event |
| if (qt_mac_set_existing_drop_action(dragRef, qDMEvent)) |
| qDMEvent.accept(); |
| |
| QApplication::sendEvent(q, &qDMEvent); |
| if (!qDMEvent.isAccepted() || qDMEvent.dropAction() == Qt::IgnoreAction) |
| interrestedInDrag = false; |
| |
| qt_mac_copy_answer_rect(qDMEvent); |
| SetDragDropAction(dragRef, qt_mac_dnd_map_qt_actions(qDMEvent.dropAction())); |
| |
| } else if (kind == kEventControlDragEnter) { |
| qt_mac_dnd_answer_rec.clear(); |
| |
| QDragEnterEvent qDEEvent(q->mapFromGlobal(QPoint(mouse.h, mouse.v)), qtAllowed, dropdata, |
| QApplication::mouseButtons(), QApplication::keyboardModifiers()); |
| qt_mac_set_existing_drop_action(dragRef, qDEEvent); |
| QApplication::sendEvent(q, &qDEEvent); |
| SetDragDropAction(dragRef, qt_mac_dnd_map_qt_actions(qDEEvent.dropAction())); |
| |
| if (!qDEEvent.isAccepted()) |
| // The widget is simply not interested in this |
| // drag. So tell carbon this by returning 'false'. We will then |
| // not receive any further move, drop or leave events for this widget. |
| return false; |
| else { |
| // Documentation states that a drag move event is sent immediately after |
| // a drag enter event. So we do that. This will honor widgets overriding |
| // 'dragMoveEvent' only, and not 'dragEnterEvent' |
| QDragMoveEvent qDMEvent(q->mapFromGlobal(QPoint(mouse.h, mouse.v)), qtAllowed, dropdata, |
| QApplication::mouseButtons(), QApplication::keyboardModifiers()); |
| qDMEvent.accept(); // accept by default, since enter event was accepted. |
| qDMEvent.setDropAction(qDEEvent.dropAction()); |
| QApplication::sendEvent(q, &qDMEvent); |
| if (!qDMEvent.isAccepted() || qDMEvent.dropAction() == Qt::IgnoreAction) |
| interrestedInDrag = false; |
| |
| qt_mac_copy_answer_rect(qDMEvent); |
| SetDragDropAction(dragRef, qt_mac_dnd_map_qt_actions(qDMEvent.dropAction())); |
| } |
| |
| } else if(kind == kEventControlDragLeave) { |
| QDragLeaveEvent de; |
| QApplication::sendEvent(q, &de); |
| } else if(kind == kEventControlDragReceive) { |
| QDropEvent de(q->mapFromGlobal(QPoint(mouse.h, mouse.v)), qtAllowed, dropdata, |
| QApplication::mouseButtons(), QApplication::keyboardModifiers()); |
| if(QDragManager::self()->object) |
| QDragManager::self()->dragPrivate()->target = q; |
| QApplication::sendEvent(q, &de); |
| if(!de.isAccepted()) { |
| interrestedInDrag = false; |
| SetDragDropAction(dragRef, kDragActionNothing); |
| } else { |
| if(QDragManager::self()->object) |
| QDragManager::self()->dragPrivate()->executed_action = de.dropAction(); |
| SetDragDropAction(dragRef, qt_mac_dnd_map_qt_actions(de.dropAction())); |
| } |
| } |
| |
| #ifdef DEBUG_DRAG_EVENTS |
| { |
| const char *desc = 0; |
| switch(kind) { |
| case kEventControlDragWithin: desc = "DragMove"; break; |
| case kEventControlDragEnter: desc = "DragEnter"; break; |
| case kEventControlDragLeave: desc = "DragLeave"; break; |
| case kEventControlDragReceive: desc = "DragDrop"; break; |
| } |
| if(desc) { |
| QPoint pos(q->mapFromGlobal(QPoint(mouse.h, mouse.v))); |
| qDebug("Sending <%s>(%d, %d) event to %p(%s::%s) [%d] (%p)", |
| desc, pos.x(), pos.y(), q, q->metaObject()->className(), |
| q->objectName().toLocal8Bit().constData(), ret, dragRef); |
| } |
| } |
| #endif |
| |
| //set the cursor |
| bool found_cursor = false; |
| if(kind == kEventControlDragWithin || kind == kEventControlDragEnter) { |
| ThemeCursor cursor = kThemeNotAllowedCursor; |
| found_cursor = true; |
| if (interrestedInDrag) { |
| DragActions action = kDragActionNothing; |
| GetDragDropAction(dragRef, &action); |
| switch(qt_mac_dnd_map_mac_default_action(action)) { |
| case Qt::IgnoreAction: |
| cursor = kThemeNotAllowedCursor; |
| break; |
| case Qt::MoveAction: |
| cursor = kThemeArrowCursor; |
| break; |
| case Qt::CopyAction: |
| cursor = kThemeCopyArrowCursor; |
| break; |
| case Qt::LinkAction: |
| cursor = kThemeAliasArrowCursor; |
| break; |
| default: |
| cursor = kThemeNotAllowedCursor; |
| break; |
| } |
| } |
| SetThemeCursor(cursor); |
| } |
| if(found_cursor) { |
| qt_mac_set_cursor(0, QPoint()); //just use our's |
| } else { |
| QCursor cursor(Qt::ArrowCursor); |
| if(qApp && qApp->overrideCursor()) { |
| cursor = *qApp->overrideCursor(); |
| } else if(q) { |
| for(QWidget *p = q; p; p = p->parentWidget()) { |
| if(p->isEnabled() && p->testAttribute(Qt::WA_SetCursor)) { |
| cursor = p->cursor(); |
| break; |
| } |
| } |
| } |
| qt_mac_set_cursor(&cursor, QPoint(mouse.h, mouse.v)); |
| } |
| |
| //idle things |
| if(qGlobalPostedEventsCount()) { |
| QApplication::sendPostedEvents(); |
| QApplication::flush(); |
| } |
| |
| // If this was not a drop, tell carbon that we will be interresed in receiving more |
| // events for the current drag. We do that by returning true. |
| if (kind == kEventControlDragReceive) |
| return interrestedInDrag; |
| else |
| return true; |
| #else |
| Q_UNUSED(kind); |
| Q_UNUSED(dragRef); |
| return false; |
| #endif // !QT_MAC_USE_COCOA |
| } |
| |
| #ifndef QT_MAC_USE_COCOA |
| Qt::DropAction QDragManager::drag(QDrag *o) |
| { |
| |
| if(qt_mac_in_drag) { //just make sure.. |
| qWarning("Qt: Internal error: WH0A, unexpected condition reached"); |
| return Qt::IgnoreAction; |
| } |
| if(object == o) |
| return Qt::IgnoreAction; |
| /* At the moment it seems clear that Mac OS X does not want to drag with a non-left button |
| so we just bail early to prevent it */ |
| if(!(GetCurrentEventButtonState() & kEventMouseButtonPrimary)) |
| return Qt::IgnoreAction; |
| |
| if(object) { |
| dragPrivate()->source->removeEventFilter(this); |
| cancel(); |
| beingCancelled = false; |
| } |
| |
| object = o; |
| dragPrivate()->target = 0; |
| |
| #ifndef QT_NO_ACCESSIBILITY |
| QAccessible::updateAccessibility(this, 0, QAccessible::DragDropStart); |
| #endif |
| |
| //setup the data |
| QMacPasteboard dragBoard(QMacPasteboardMime::MIME_DND); |
| dragBoard.setMimeData(dragPrivate()->data); |
| |
| //create the drag |
| OSErr result; |
| DragRef dragRef; |
| if((result = NewDragWithPasteboard(dragBoard.pasteBoard(), &dragRef))) |
| return Qt::IgnoreAction; |
| //setup the actions |
| DragActions possibleActions = qt_mac_dnd_map_qt_actions(dragPrivate()->possible_actions); |
| SetDragAllowableActions(dragRef, //local |
| possibleActions, |
| true); |
| SetDragAllowableActions(dragRef, //remote (same as local) |
| possibleActions, |
| false); |
| |
| |
| QPoint hotspot; |
| QPixmap pix = dragPrivate()->pixmap; |
| if(pix.isNull()) { |
| if(dragPrivate()->data->hasText() || dragPrivate()->data->hasUrls()) { |
| //get the string |
| QString s = dragPrivate()->data->hasText() ? dragPrivate()->data->text() |
| : dragPrivate()->data->urls().first().toString(); |
| if(s.length() > 26) |
| s = s.left(23) + QChar(0x2026); |
| if(!s.isEmpty()) { |
| //draw it |
| QFont f(qApp->font()); |
| f.setPointSize(12); |
| QFontMetrics fm(f); |
| const int width = fm.width(s); |
| const int height = fm.height(); |
| if(width > 0 && height > 0) { |
| QPixmap tmp(width, height); |
| QPainter p(&tmp); |
| p.fillRect(0, 0, tmp.width(), tmp.height(), Qt::color0); |
| p.setPen(Qt::color1); |
| p.setFont(f); |
| p.drawText(0, fm.ascent(), s); |
| p.end(); |
| //save it |
| pix = tmp; |
| hotspot = QPoint(tmp.width() / 2, tmp.height() / 2); |
| } |
| } |
| } else { |
| pix = QPixmap(default_pm); |
| hotspot = QPoint(default_pm_hotx, default_pm_hoty); |
| } |
| } else { |
| hotspot = dragPrivate()->hotspot; |
| } |
| |
| //so we must fake an event |
| EventRecord fakeEvent; |
| GetGlobalMouse(&(fakeEvent.where)); |
| fakeEvent.message = 0; |
| fakeEvent.what = mouseDown; |
| fakeEvent.when = EventTimeToTicks(GetCurrentEventTime()); |
| fakeEvent.modifiers = GetCurrentKeyModifiers(); |
| if(GetCurrentEventButtonState() & 2) |
| fakeEvent.modifiers |= controlKey; |
| |
| //find the hotspot in relation to the pixmap |
| Point boundsPoint; |
| boundsPoint.h = fakeEvent.where.h - hotspot.x(); |
| boundsPoint.v = fakeEvent.where.v - hotspot.y(); |
| Rect boundsRect; |
| SetRect(&boundsRect, boundsPoint.h, boundsPoint.v, boundsPoint.h + pix.width(), boundsPoint.v + pix.height()); |
| |
| //set the drag image |
| QRegion dragRegion(boundsPoint.h, boundsPoint.v, pix.width(), pix.height()), pixRegion; |
| if(!pix.isNull()) { |
| HIPoint hipoint = { -hotspot.x(), -hotspot.y() }; |
| CGImageRef img = (CGImageRef)pix.macCGHandle(); |
| SetDragImageWithCGImage(dragRef, img, &hipoint, 0); |
| CGImageRelease(img); |
| } |
| |
| SetDragItemBounds(dragRef, (ItemReference)1 , &boundsRect); |
| { //do the drag |
| qt_mac_in_drag = true; |
| qt_mac_dnd_update_action(dragRef); |
| result = TrackDrag(dragRef, &fakeEvent, QMacSmartQuickDrawRegion(dragRegion.toQDRgn())); |
| qt_mac_in_drag = false; |
| } |
| object = 0; |
| if(result == noErr) { |
| // Check if the receiver points us to |
| // a file location. If so, we need to do |
| // the file copy/move ourselves: |
| QCFType<CFURLRef> pasteLocation = 0; |
| PasteboardCopyPasteLocation(dragBoard.pasteBoard(), &pasteLocation); |
| if (pasteLocation){ |
| Qt::DropAction action = o->d_func()->defaultDropAction; |
| if (action == Qt::IgnoreAction){ |
| if (o->d_func()->possible_actions & Qt::MoveAction) |
| action = Qt::MoveAction; |
| else if (o->d_func()->possible_actions & Qt::CopyAction) |
| action = Qt::CopyAction; |
| |
| } |
| bool atleastOne = false; |
| QList<QUrl> urls = o->mimeData()->urls(); |
| for (int i = 0; i < urls.size(); ++i){ |
| QUrl fromUrl = urls.at(i); |
| QString filename = QFileInfo(fromUrl.path()).fileName(); |
| QUrl toUrl(QCFString::toQString(CFURLGetString(pasteLocation)) + filename); |
| if (action == Qt::MoveAction){ |
| if (QFile::rename(fromUrl.path(), toUrl.path())) |
| atleastOne = true; |
| } else if (action == Qt::CopyAction){ |
| if (QFile::copy(fromUrl.path(), toUrl.path())) |
| atleastOne = true; |
| } |
| } |
| if (atleastOne){ |
| DisposeDrag(dragRef); |
| o->setMimeData(0); |
| o->deleteLater(); |
| return action; |
| } |
| } |
| |
| DragActions ret = kDragActionNothing; |
| GetDragDropAction(dragRef, &ret); |
| DisposeDrag(dragRef); //cleanup |
| o->setMimeData(0); |
| o->deleteLater(); |
| return qt_mac_dnd_map_mac_default_action(ret); |
| } |
| DisposeDrag(dragRef); //cleanup |
| return Qt::IgnoreAction; |
| } |
| #endif |
| |
| void QDragManager::updatePixmap() |
| { |
| } |
| |
| QCocoaDropData::QCocoaDropData(CFStringRef pasteboard) |
| : QInternalMimeData() |
| { |
| NSString* pasteboardName = (NSString*)pasteboard; |
| [pasteboardName retain]; |
| dropPasteboard = pasteboard; |
| } |
| |
| QCocoaDropData::~QCocoaDropData() |
| { |
| NSString* pasteboardName = (NSString*)dropPasteboard; |
| [pasteboardName release]; |
| } |
| |
| QStringList QCocoaDropData::formats_sys() const |
| { |
| QStringList formats; |
| OSPasteboardRef board; |
| if (PasteboardCreate(dropPasteboard, &board) != noErr) { |
| qDebug("DnD: Cannot get PasteBoard!"); |
| return formats; |
| } |
| formats = QMacPasteboard(board, QMacPasteboardMime::MIME_DND).formats(); |
| return formats; |
| } |
| |
| QVariant QCocoaDropData::retrieveData_sys(const QString &mimeType, QVariant::Type type) const |
| { |
| QVariant data; |
| OSPasteboardRef board; |
| if (PasteboardCreate(dropPasteboard, &board) != noErr) { |
| qDebug("DnD: Cannot get PasteBoard!"); |
| return data; |
| } |
| data = QMacPasteboard(board, QMacPasteboardMime::MIME_DND).retrieveData(mimeType, type); |
| CFRelease(board); |
| return data; |
| } |
| |
| bool QCocoaDropData::hasFormat_sys(const QString &mimeType) const |
| { |
| bool has = false; |
| OSPasteboardRef board; |
| if (PasteboardCreate(dropPasteboard, &board) != noErr) { |
| qDebug("DnD: Cannot get PasteBoard!"); |
| return has; |
| } |
| has = QMacPasteboard(board, QMacPasteboardMime::MIME_DND).hasFormat(mimeType); |
| CFRelease(board); |
| return has; |
| } |
| |
| #endif // QT_NO_DRAGANDDROP |
| QT_END_NAMESPACE |