src/gui/kernel/qdnd_mac.mm
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     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 QtGui 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 "qapplication.h"
       
    43 #ifndef QT_NO_DRAGANDDROP
       
    44 #include "qbitmap.h"
       
    45 #include "qcursor.h"
       
    46 #include "qevent.h"
       
    47 #include "qpainter.h"
       
    48 #include "qurl.h"
       
    49 #include "qwidget.h"
       
    50 #include "qfile.h"
       
    51 #include "qfileinfo.h"
       
    52 #include <stdlib.h>
       
    53 #include <string.h>
       
    54 #ifndef QT_NO_ACCESSIBILITY
       
    55 # include "qaccessible.h"
       
    56 #endif
       
    57 
       
    58 #include <private/qapplication_p.h>
       
    59 #include <private/qwidget_p.h>
       
    60 #include <private/qdnd_p.h>
       
    61 #include <private/qt_mac_p.h>
       
    62 
       
    63 QT_BEGIN_NAMESPACE
       
    64 
       
    65 QT_USE_NAMESPACE
       
    66 
       
    67 QMacDndAnswerRecord qt_mac_dnd_answer_rec; 
       
    68 
       
    69 /*****************************************************************************
       
    70   QDnD debug facilities
       
    71  *****************************************************************************/
       
    72 //#define DEBUG_DRAG_EVENTS
       
    73 //#define DEBUG_DRAG_PROMISES
       
    74 
       
    75 /*****************************************************************************
       
    76   QDnD globals
       
    77  *****************************************************************************/
       
    78 bool qt_mac_in_drag = false;
       
    79 #ifndef QT_MAC_USE_COCOA
       
    80 static DragReference qt_mac_current_dragRef = 0;
       
    81 #endif
       
    82 
       
    83 /*****************************************************************************
       
    84   Externals
       
    85  *****************************************************************************/
       
    86 extern void qt_mac_send_modifiers_changed(quint32, QObject *); //qapplication_mac.cpp
       
    87 extern uint qGlobalPostedEventsCount(); //qapplication.cpp
       
    88 extern RgnHandle qt_mac_get_rgn(); // qregion_mac.cpp
       
    89 extern void qt_mac_dispose_rgn(RgnHandle); // qregion_mac.cpp
       
    90 /*****************************************************************************
       
    91   QDnD utility functions
       
    92  *****************************************************************************/
       
    93 
       
    94 //default pixmap
       
    95 static const int default_pm_hotx = -2;
       
    96 static const int default_pm_hoty = -16;
       
    97 #ifndef QT_MAC_USE_COCOA
       
    98 static const char * const default_pm[] = {
       
    99     "13 9 3 1",
       
   100     ".      c None",
       
   101     "       c #000000",
       
   102     "X      c #FFFFFF",
       
   103     "X X X X X X X",
       
   104     " X X X X X X ",
       
   105     "X ......... X",
       
   106     " X.........X ",
       
   107     "X ......... X",
       
   108     " X.........X ",
       
   109     "X ......... X",
       
   110     " X X X X X X ",
       
   111     "X X X X X X X",
       
   112 };
       
   113 #endif
       
   114 
       
   115 //action management
       
   116 #ifdef DEBUG_DRAG_EVENTS
       
   117 # define MAP_MAC_ENUM(x) x, #x
       
   118 #else
       
   119 # define MAP_MAC_ENUM(x) x
       
   120 #endif
       
   121 struct mac_enum_mapper
       
   122 {
       
   123     int mac_code;
       
   124     int qt_code;
       
   125 #ifdef DEBUG_DRAG_EVENTS
       
   126     char *qt_desc;
       
   127 #endif
       
   128 };
       
   129 #ifndef QT_MAC_USE_COCOA
       
   130 static mac_enum_mapper dnd_action_symbols[] = {
       
   131     { kDragActionAlias, MAP_MAC_ENUM(Qt::LinkAction) },
       
   132     { kDragActionMove, MAP_MAC_ENUM(Qt::MoveAction) },
       
   133     { kDragActionGeneric, MAP_MAC_ENUM(Qt::CopyAction) },
       
   134     { kDragActionCopy, MAP_MAC_ENUM(Qt::CopyAction) },
       
   135     { 0, MAP_MAC_ENUM(0) }
       
   136 };
       
   137 static DragActions qt_mac_dnd_map_qt_actions(Qt::DropActions qActions)
       
   138 {
       
   139     DragActions ret = kDragActionNothing;
       
   140     for(int i = 0; dnd_action_symbols[i].qt_code; ++i) {
       
   141         if(qActions & dnd_action_symbols[i].qt_code)
       
   142             ret |= dnd_action_symbols[i].mac_code;
       
   143     }
       
   144     return ret;
       
   145 }
       
   146 static Qt::DropActions qt_mac_dnd_map_mac_actions(DragActions macActions)
       
   147 {
       
   148 #ifdef DEBUG_DRAG_EVENTS
       
   149     qDebug("Converting DND ActionList: 0x%lx", macActions);
       
   150 #endif
       
   151     Qt::DropActions ret = Qt::IgnoreAction;
       
   152     for(int i = 0; dnd_action_symbols[i].qt_code; ++i) {
       
   153 #ifdef DEBUG_DRAG_EVENTS
       
   154         qDebug(" %d) [%s] : %s", i, dnd_action_symbols[i].qt_desc,
       
   155                 (macActions & dnd_action_symbols[i].mac_code) ? "true" : "false");
       
   156 #endif
       
   157         if(macActions & dnd_action_symbols[i].mac_code)
       
   158             ret |= Qt::DropAction(dnd_action_symbols[i].qt_code);
       
   159     }
       
   160     return ret;
       
   161 }
       
   162 static Qt::DropAction qt_mac_dnd_map_mac_default_action(DragActions macActions)
       
   163 {
       
   164     static Qt::DropAction preferred_actions[] = { Qt::CopyAction, Qt::LinkAction, //in order
       
   165         Qt::MoveAction, Qt::IgnoreAction };
       
   166     Qt::DropAction ret = Qt::IgnoreAction;
       
   167     const Qt::DropActions qtActions = qt_mac_dnd_map_mac_actions(macActions);
       
   168     for(int i = 0; preferred_actions[i] != Qt::IgnoreAction; ++i) {
       
   169         if(qtActions & preferred_actions[i]) {
       
   170             ret = preferred_actions[i];
       
   171             break;
       
   172         }
       
   173     }
       
   174 #ifdef DEBUG_DRAG_EVENTS
       
   175     for(int i = 0; dnd_action_symbols[i].qt_code; ++i) {
       
   176         if(dnd_action_symbols[i].qt_code == ret) {
       
   177             qDebug("Got default action: %s [0x%lx]", dnd_action_symbols[i].qt_desc, macActions);
       
   178             break;
       
   179         }
       
   180     }
       
   181 #endif
       
   182     return ret;
       
   183 }
       
   184 static void qt_mac_dnd_update_action(DragReference dragRef) {
       
   185     SInt16 modifiers;
       
   186     GetDragModifiers(dragRef, &modifiers, 0, 0);
       
   187     qt_mac_send_modifiers_changed(modifiers, qApp);
       
   188 
       
   189     Qt::DropAction qtAction = Qt::IgnoreAction;
       
   190     {
       
   191         DragActions macAllowed = kDragActionNothing;
       
   192         GetDragDropAction(dragRef, &macAllowed);
       
   193         Qt::DropActions qtAllowed = qt_mac_dnd_map_mac_actions(macAllowed);
       
   194         qtAction = QDragManager::self()->defaultAction(qtAllowed, QApplication::keyboardModifiers());
       
   195 #if 1
       
   196         if(!(qtAllowed & qtAction))
       
   197             qtAction = qt_mac_dnd_map_mac_default_action(macAllowed);
       
   198 #endif
       
   199     }
       
   200     DragActions macAction = qt_mac_dnd_map_qt_actions(qtAction);
       
   201 
       
   202     DragActions currentActions;
       
   203     GetDragDropAction(dragRef, &currentActions);
       
   204     if(currentActions != macAction) {
       
   205         SetDragDropAction(dragRef, macAction);
       
   206         QDragManager::self()->emitActionChanged(qtAction);
       
   207     }
       
   208 }
       
   209 #endif // !QT_MAC_USE_COCOA
       
   210 
       
   211 /*****************************************************************************
       
   212   DnD functions
       
   213  *****************************************************************************/
       
   214 bool QDropData::hasFormat_sys(const QString &mime) const
       
   215 {
       
   216 #ifndef QT_MAC_USE_COCOA
       
   217     OSPasteboardRef board;
       
   218     if(GetDragPasteboard(qt_mac_current_dragRef, &board) != noErr) {
       
   219         qDebug("DnD: Cannot get PasteBoard!");
       
   220         return false;
       
   221     }
       
   222     return QMacPasteboard(board, QMacPasteboardMime::MIME_DND).hasFormat(mime);
       
   223 #else
       
   224     Q_UNUSED(mime);
       
   225     return false;
       
   226 #endif // !QT_MAC_USE_COCOA
       
   227 }
       
   228 
       
   229 QVariant QDropData::retrieveData_sys(const QString &mime, QVariant::Type type) const
       
   230 {
       
   231 #ifndef QT_MAC_USE_COCOA
       
   232     OSPasteboardRef board;
       
   233     if(GetDragPasteboard(qt_mac_current_dragRef, &board) != noErr) {
       
   234         qDebug("DnD: Cannot get PasteBoard!");
       
   235         return QVariant();
       
   236     }
       
   237     return QMacPasteboard(board, QMacPasteboardMime::MIME_DND).retrieveData(mime, type);
       
   238 #else
       
   239     Q_UNUSED(mime);
       
   240     Q_UNUSED(type);
       
   241     return QVariant();
       
   242 #endif // !QT_MAC_USE_COCOA
       
   243 }
       
   244 
       
   245 QStringList QDropData::formats_sys() const
       
   246 {
       
   247 #ifndef QT_MAC_USE_COCOA
       
   248     OSPasteboardRef board;
       
   249     if(GetDragPasteboard(qt_mac_current_dragRef, &board) != noErr) {
       
   250         qDebug("DnD: Cannot get PasteBoard!");
       
   251         return QStringList();
       
   252     }
       
   253     return QMacPasteboard(board, QMacPasteboardMime::MIME_DND).formats();
       
   254 #else
       
   255     return QStringList();
       
   256 #endif
       
   257 }
       
   258 
       
   259 void QDragManager::timerEvent(QTimerEvent*)
       
   260 {
       
   261 }
       
   262 
       
   263 bool QDragManager::eventFilter(QObject *, QEvent *)
       
   264 {
       
   265     return false;
       
   266 }
       
   267 
       
   268 void QDragManager::updateCursor()
       
   269 {
       
   270 }
       
   271 
       
   272 void QDragManager::cancel(bool)
       
   273 {
       
   274     if(object) {
       
   275         beingCancelled = true;
       
   276         object = 0;
       
   277     }
       
   278 #ifndef QT_NO_ACCESSIBILITY
       
   279     QAccessible::updateAccessibility(this, 0, QAccessible::DragDropEnd);
       
   280 #endif
       
   281 }
       
   282 
       
   283 void QDragManager::move(const QPoint &)
       
   284 {
       
   285 }
       
   286 
       
   287 void QDragManager::drop()
       
   288 {
       
   289 }
       
   290 
       
   291 /**
       
   292     If a drop action is already set on the carbon event
       
   293     (from e.g. an earlier enter event), we insert the same
       
   294     action on the new Qt event that has yet to be sendt.
       
   295 */
       
   296 static inline bool qt_mac_set_existing_drop_action(const DragRef &dragRef, QDropEvent &event)
       
   297 {
       
   298 #ifndef QT_MAC_USE_COCOA
       
   299     DragActions currentAction = kDragActionNothing;        
       
   300     OSStatus err = GetDragDropAction(dragRef, &currentAction);
       
   301     if (err == noErr && currentAction != kDragActionNothing) {
       
   302         // This looks a bit evil, but we only ever set one action, so it's OK.
       
   303         event.setDropAction(Qt::DropAction(int(qt_mac_dnd_map_mac_actions(currentAction))));
       
   304         return true;
       
   305     }
       
   306 #else
       
   307     Q_UNUSED(dragRef);
       
   308     Q_UNUSED(event);
       
   309 #endif
       
   310     return false;
       
   311 }
       
   312 
       
   313 /**
       
   314     If an answer rect has been set on the event (after being sent
       
   315     to the global event processor), we store that rect so we can
       
   316     check if the mouse is in the same area upon next drag move event. 
       
   317 */
       
   318 void qt_mac_copy_answer_rect(const QDragMoveEvent &event)
       
   319 {
       
   320     if (!event.answerRect().isEmpty()) {
       
   321         qt_mac_dnd_answer_rec.rect = event.answerRect();
       
   322         qt_mac_dnd_answer_rec.buttons = event.mouseButtons();
       
   323         qt_mac_dnd_answer_rec.modifiers = event.keyboardModifiers();
       
   324         qt_mac_dnd_answer_rec.lastAction = event.dropAction();
       
   325     }    
       
   326 }
       
   327 
       
   328 bool qt_mac_mouse_inside_answer_rect(QPoint mouse)
       
   329 {
       
   330     if (!qt_mac_dnd_answer_rec.rect.isEmpty()
       
   331             && qt_mac_dnd_answer_rec.rect.contains(mouse)
       
   332             && QApplication::mouseButtons() == qt_mac_dnd_answer_rec.buttons
       
   333             && QApplication::keyboardModifiers() == qt_mac_dnd_answer_rec.modifiers)
       
   334         return true;
       
   335     else
       
   336         return false;
       
   337 }
       
   338 
       
   339 bool QWidgetPrivate::qt_mac_dnd_event(uint kind, DragRef dragRef)
       
   340 {
       
   341 #ifndef QT_MAC_USE_COCOA
       
   342     Q_Q(QWidget);
       
   343     qt_mac_current_dragRef = dragRef;
       
   344     if (kind != kEventControlDragLeave)
       
   345         qt_mac_dnd_update_action(dragRef);
       
   346 
       
   347     Point mouse;
       
   348     GetDragMouse(dragRef, &mouse, 0L);
       
   349     if(!mouse.h && !mouse.v)
       
   350         GetGlobalMouse(&mouse);
       
   351 
       
   352     if(QApplicationPrivate::modalState()) {
       
   353         for(QWidget *modal = q; modal; modal = modal->parentWidget()) {
       
   354             if(modal->isWindow()) {
       
   355                 if(modal != QApplication::activeModalWidget())
       
   356                     return noErr;
       
   357                 break;
       
   358             }
       
   359         }
       
   360     }
       
   361 
       
   362     //lookup the possible actions
       
   363     DragActions allowed = kDragActionNothing;
       
   364     GetDragAllowableActions(dragRef, &allowed);
       
   365     Qt::DropActions qtAllowed = qt_mac_dnd_map_mac_actions(allowed);
       
   366 
       
   367     //lookup the source dragAccepted 
       
   368     QMimeData *dropdata = QDragManager::self()->dropData;
       
   369     if(QDragManager::self()->source())
       
   370         dropdata = QDragManager::self()->dragPrivate()->data;
       
   371 
       
   372     // 'interrestedInDrag' should end up being 'true' if a later drop
       
   373     // will be accepted by the widget for the current mouse position 
       
   374     bool interrestedInDrag = true;
       
   375 
       
   376     //Dispatch events
       
   377     if (kind == kEventControlDragWithin) {
       
   378         if (qt_mac_mouse_inside_answer_rect(q->mapFromGlobal(QPoint(mouse.h, mouse.v))))
       
   379             return qt_mac_dnd_answer_rec.lastAction == Qt::IgnoreAction;
       
   380         else
       
   381             qt_mac_dnd_answer_rec.clear();
       
   382         
       
   383         QDragMoveEvent qDMEvent(q->mapFromGlobal(QPoint(mouse.h, mouse.v)), qtAllowed, dropdata,
       
   384                 QApplication::mouseButtons(), QApplication::keyboardModifiers());
       
   385                 
       
   386         // Accept the event by default if a
       
   387         // drag action exists on the carbon event
       
   388         if (qt_mac_set_existing_drop_action(dragRef, qDMEvent))
       
   389             qDMEvent.accept();
       
   390             
       
   391         QApplication::sendEvent(q, &qDMEvent);
       
   392         if (!qDMEvent.isAccepted() || qDMEvent.dropAction() == Qt::IgnoreAction)
       
   393             interrestedInDrag = false;
       
   394 
       
   395         qt_mac_copy_answer_rect(qDMEvent);
       
   396         SetDragDropAction(dragRef, qt_mac_dnd_map_qt_actions(qDMEvent.dropAction()));
       
   397         
       
   398     } else if (kind == kEventControlDragEnter) {
       
   399         qt_mac_dnd_answer_rec.clear();
       
   400         
       
   401         QDragEnterEvent qDEEvent(q->mapFromGlobal(QPoint(mouse.h, mouse.v)), qtAllowed, dropdata,
       
   402                 QApplication::mouseButtons(), QApplication::keyboardModifiers());
       
   403         qt_mac_set_existing_drop_action(dragRef, qDEEvent);                         
       
   404         QApplication::sendEvent(q, &qDEEvent);
       
   405         SetDragDropAction(dragRef, qt_mac_dnd_map_qt_actions(qDEEvent.dropAction()));
       
   406         
       
   407         if (!qDEEvent.isAccepted())
       
   408             // The widget is simply not interested in this
       
   409             // drag. So tell carbon this by returning 'false'. We will then
       
   410             // not receive any further move, drop or leave events for this widget.
       
   411             return false;
       
   412         else {
       
   413             // Documentation states that a drag move event is sent immediately after
       
   414             // a drag enter event. So we do that. This will honor widgets overriding
       
   415             // 'dragMoveEvent' only, and not 'dragEnterEvent' 
       
   416             QDragMoveEvent qDMEvent(q->mapFromGlobal(QPoint(mouse.h, mouse.v)), qtAllowed, dropdata,
       
   417                     QApplication::mouseButtons(), QApplication::keyboardModifiers());
       
   418             qDMEvent.accept(); // accept by default, since enter event was accepted.
       
   419             qDMEvent.setDropAction(qDEEvent.dropAction());         
       
   420             QApplication::sendEvent(q, &qDMEvent);
       
   421             if (!qDMEvent.isAccepted() || qDMEvent.dropAction() == Qt::IgnoreAction)
       
   422                 interrestedInDrag = false;
       
   423             
       
   424             qt_mac_copy_answer_rect(qDMEvent);           
       
   425             SetDragDropAction(dragRef, qt_mac_dnd_map_qt_actions(qDMEvent.dropAction()));
       
   426         }
       
   427         
       
   428     } else if(kind == kEventControlDragLeave) {
       
   429         QDragLeaveEvent de;
       
   430         QApplication::sendEvent(q, &de);
       
   431     } else if(kind == kEventControlDragReceive) {
       
   432         QDropEvent de(q->mapFromGlobal(QPoint(mouse.h, mouse.v)), qtAllowed, dropdata,
       
   433                       QApplication::mouseButtons(), QApplication::keyboardModifiers());
       
   434         if(QDragManager::self()->object)
       
   435             QDragManager::self()->dragPrivate()->target = q;
       
   436         QApplication::sendEvent(q, &de);
       
   437         if(!de.isAccepted()) {
       
   438             interrestedInDrag = false;
       
   439             SetDragDropAction(dragRef, kDragActionNothing);
       
   440         } else {
       
   441             if(QDragManager::self()->object)
       
   442                 QDragManager::self()->dragPrivate()->executed_action = de.dropAction();
       
   443             SetDragDropAction(dragRef, qt_mac_dnd_map_qt_actions(de.dropAction()));
       
   444         }
       
   445     }
       
   446 
       
   447 #ifdef DEBUG_DRAG_EVENTS
       
   448     {
       
   449         const char *desc = 0;
       
   450         switch(kind) {
       
   451         case kEventControlDragWithin: desc = "DragMove"; break;
       
   452         case kEventControlDragEnter: desc = "DragEnter"; break;
       
   453         case kEventControlDragLeave: desc = "DragLeave"; break;
       
   454         case kEventControlDragReceive: desc = "DragDrop"; break;
       
   455         }
       
   456         if(desc) {
       
   457             QPoint pos(q->mapFromGlobal(QPoint(mouse.h, mouse.v)));
       
   458             qDebug("Sending <%s>(%d, %d) event to %p(%s::%s) [%d] (%p)",
       
   459                    desc, pos.x(), pos.y(), q, q->metaObject()->className(),
       
   460                    q->objectName().toLocal8Bit().constData(), ret, dragRef);
       
   461         }
       
   462     }
       
   463 #endif
       
   464 
       
   465     //set the cursor
       
   466     bool found_cursor = false;
       
   467     if(kind == kEventControlDragWithin || kind == kEventControlDragEnter) {
       
   468         ThemeCursor cursor = kThemeNotAllowedCursor;
       
   469         found_cursor = true;
       
   470         if (interrestedInDrag) {
       
   471             DragActions action = kDragActionNothing;
       
   472             GetDragDropAction(dragRef, &action);
       
   473             switch(qt_mac_dnd_map_mac_default_action(action)) {
       
   474             case Qt::IgnoreAction:
       
   475                 cursor = kThemeNotAllowedCursor;
       
   476                 break;
       
   477             case Qt::MoveAction:
       
   478                 cursor = kThemeArrowCursor;
       
   479                 break;
       
   480             case Qt::CopyAction:
       
   481                 cursor = kThemeCopyArrowCursor;
       
   482                 break;
       
   483             case Qt::LinkAction:
       
   484                 cursor = kThemeAliasArrowCursor;
       
   485                 break;
       
   486             default:
       
   487                 cursor = kThemeNotAllowedCursor;
       
   488                 break;
       
   489             }
       
   490         }
       
   491         SetThemeCursor(cursor);
       
   492     }
       
   493     if(found_cursor) {
       
   494         qt_mac_set_cursor(0, QPoint()); //just use our's
       
   495     } else {
       
   496         QCursor cursor(Qt::ArrowCursor);
       
   497         if(qApp && qApp->overrideCursor()) {
       
   498             cursor = *qApp->overrideCursor();
       
   499         } else if(q) {
       
   500             for(QWidget *p = q; p; p = p->parentWidget()) {
       
   501                 if(p->isEnabled() && p->testAttribute(Qt::WA_SetCursor)) {
       
   502                     cursor = p->cursor();
       
   503                     break;
       
   504                 }
       
   505             }
       
   506         }
       
   507         qt_mac_set_cursor(&cursor, QPoint(mouse.h, mouse.v));
       
   508     }
       
   509 
       
   510     //idle things
       
   511     if(qGlobalPostedEventsCount()) {
       
   512         QApplication::sendPostedEvents();
       
   513         QApplication::flush();
       
   514     }
       
   515     
       
   516     // If this was not a drop, tell carbon that we will be interresed in receiving more
       
   517     // events for the current drag. We do that by returning true. 
       
   518     if (kind == kEventControlDragReceive)
       
   519         return interrestedInDrag;
       
   520     else
       
   521         return true;
       
   522 #else
       
   523     Q_UNUSED(kind);
       
   524     Q_UNUSED(dragRef);
       
   525     return false;
       
   526 #endif // !QT_MAC_USE_COCOA
       
   527 }
       
   528 
       
   529 #ifndef QT_MAC_USE_COCOA
       
   530 Qt::DropAction QDragManager::drag(QDrag *o)
       
   531 {
       
   532   
       
   533     if(qt_mac_in_drag) {     //just make sure..
       
   534         qWarning("Qt: Internal error: WH0A, unexpected condition reached");
       
   535         return Qt::IgnoreAction;
       
   536     }
       
   537     if(object == o)
       
   538         return Qt::IgnoreAction;
       
   539     /* At the moment it seems clear that Mac OS X does not want to drag with a non-left button
       
   540        so we just bail early to prevent it */
       
   541     if(!(GetCurrentEventButtonState() & kEventMouseButtonPrimary))
       
   542         return Qt::IgnoreAction;
       
   543 
       
   544     if(object) {
       
   545         dragPrivate()->source->removeEventFilter(this);
       
   546         cancel();
       
   547         beingCancelled = false;
       
   548     }
       
   549 
       
   550     object = o;
       
   551     dragPrivate()->target = 0;
       
   552 
       
   553 #ifndef QT_NO_ACCESSIBILITY
       
   554     QAccessible::updateAccessibility(this, 0, QAccessible::DragDropStart);
       
   555 #endif
       
   556 
       
   557     //setup the data
       
   558     QMacPasteboard dragBoard(QMacPasteboardMime::MIME_DND);
       
   559     dragBoard.setMimeData(dragPrivate()->data);
       
   560 
       
   561     //create the drag
       
   562     OSErr result;
       
   563     DragRef dragRef;
       
   564     if((result = NewDragWithPasteboard(dragBoard.pasteBoard(), &dragRef)))
       
   565         return Qt::IgnoreAction;
       
   566     //setup the actions
       
   567     DragActions possibleActions = qt_mac_dnd_map_qt_actions(dragPrivate()->possible_actions);
       
   568     SetDragAllowableActions(dragRef, //local
       
   569                             possibleActions,
       
   570                             true);
       
   571     SetDragAllowableActions(dragRef, //remote (same as local)
       
   572                             possibleActions,
       
   573                             false);
       
   574 
       
   575 
       
   576     QPoint hotspot;
       
   577     QPixmap pix = dragPrivate()->pixmap;
       
   578     if(pix.isNull()) {
       
   579         if(dragPrivate()->data->hasText() || dragPrivate()->data->hasUrls()) {
       
   580             //get the string
       
   581             QString s = dragPrivate()->data->hasText() ? dragPrivate()->data->text()
       
   582                                                 : dragPrivate()->data->urls().first().toString();
       
   583             if(s.length() > 26)
       
   584                 s = s.left(23) + QChar(0x2026);
       
   585             if(!s.isEmpty()) {
       
   586                 //draw it
       
   587                 QFont f(qApp->font());
       
   588                 f.setPointSize(12);
       
   589                 QFontMetrics fm(f);
       
   590                 const int width = fm.width(s);
       
   591                 const int height = fm.height();
       
   592                 if(width > 0 && height > 0) {
       
   593                     QPixmap tmp(width, height);
       
   594                     QPainter p(&tmp);
       
   595                     p.fillRect(0, 0, tmp.width(), tmp.height(), Qt::color0);
       
   596                     p.setPen(Qt::color1);
       
   597                     p.setFont(f);
       
   598                     p.drawText(0, fm.ascent(), s);
       
   599                     p.end();
       
   600                     //save it
       
   601                     pix = tmp;
       
   602                     hotspot = QPoint(tmp.width() / 2, tmp.height() / 2);
       
   603                 }
       
   604             }
       
   605         } else {
       
   606             pix = QPixmap(default_pm);
       
   607             hotspot = QPoint(default_pm_hotx, default_pm_hoty);
       
   608         }
       
   609     } else {
       
   610         hotspot = dragPrivate()->hotspot;
       
   611     }
       
   612 
       
   613     //so we must fake an event
       
   614     EventRecord fakeEvent;
       
   615     GetGlobalMouse(&(fakeEvent.where));
       
   616     fakeEvent.message = 0;
       
   617     fakeEvent.what = mouseDown;
       
   618     fakeEvent.when = EventTimeToTicks(GetCurrentEventTime());
       
   619     fakeEvent.modifiers = GetCurrentKeyModifiers();
       
   620     if(GetCurrentEventButtonState() & 2)
       
   621         fakeEvent.modifiers |= controlKey;
       
   622 
       
   623     //find the hotspot in relation to the pixmap
       
   624     Point boundsPoint;
       
   625     boundsPoint.h = fakeEvent.where.h - hotspot.x();
       
   626     boundsPoint.v = fakeEvent.where.v - hotspot.y();
       
   627     Rect boundsRect;
       
   628     SetRect(&boundsRect, boundsPoint.h, boundsPoint.v, boundsPoint.h + pix.width(), boundsPoint.v + pix.height());
       
   629 
       
   630     //set the drag image
       
   631     QRegion dragRegion(boundsPoint.h, boundsPoint.v, pix.width(), pix.height()), pixRegion;
       
   632     if(!pix.isNull()) {
       
   633         HIPoint hipoint = { -hotspot.x(), -hotspot.y() };
       
   634         CGImageRef img = (CGImageRef)pix.macCGHandle();
       
   635         SetDragImageWithCGImage(dragRef, img, &hipoint, 0);
       
   636         CGImageRelease(img);
       
   637     }
       
   638 
       
   639     SetDragItemBounds(dragRef, (ItemReference)1 , &boundsRect);
       
   640     { //do the drag
       
   641         qt_mac_in_drag = true;
       
   642         qt_mac_dnd_update_action(dragRef);
       
   643         result = TrackDrag(dragRef, &fakeEvent, QMacSmartQuickDrawRegion(dragRegion.toQDRgn()));
       
   644         qt_mac_in_drag = false;
       
   645     }
       
   646     object = 0;
       
   647     if(result == noErr) {
       
   648         // Check if the receiver points us to
       
   649         // a file location. If so, we need to do
       
   650         // the file copy/move ourselves:
       
   651         QCFType<CFURLRef> pasteLocation = 0;
       
   652         PasteboardCopyPasteLocation(dragBoard.pasteBoard(), &pasteLocation);
       
   653         if (pasteLocation){
       
   654             Qt::DropAction action = o->d_func()->defaultDropAction;
       
   655             if (action == Qt::IgnoreAction){
       
   656                 if (o->d_func()->possible_actions & Qt::MoveAction)
       
   657                     action = Qt::MoveAction;
       
   658                 else if (o->d_func()->possible_actions & Qt::CopyAction)
       
   659                     action = Qt::CopyAction;
       
   660                 
       
   661             }
       
   662             bool atleastOne = false;
       
   663             QList<QUrl> urls = o->mimeData()->urls();
       
   664             for (int i = 0; i < urls.size(); ++i){
       
   665                 QUrl fromUrl = urls.at(i);
       
   666                 QString filename = QFileInfo(fromUrl.path()).fileName();
       
   667                 QUrl toUrl(QCFString::toQString(CFURLGetString(pasteLocation)) + filename);
       
   668                 if (action == Qt::MoveAction){
       
   669                     if (QFile::rename(fromUrl.path(), toUrl.path()))
       
   670                         atleastOne = true;
       
   671                 } else if (action == Qt::CopyAction){
       
   672                     if (QFile::copy(fromUrl.path(), toUrl.path()))
       
   673                         atleastOne = true;
       
   674                 }
       
   675             }
       
   676             if (atleastOne){
       
   677                 DisposeDrag(dragRef);
       
   678                 return action;
       
   679             }
       
   680         }
       
   681 
       
   682         DragActions ret = kDragActionNothing;
       
   683         GetDragDropAction(dragRef, &ret);
       
   684         DisposeDrag(dragRef); //cleanup
       
   685         return qt_mac_dnd_map_mac_default_action(ret);
       
   686     }
       
   687     DisposeDrag(dragRef); //cleanup
       
   688     return Qt::IgnoreAction;
       
   689 }
       
   690 #endif
       
   691 
       
   692 void QDragManager::updatePixmap()
       
   693 {
       
   694 }
       
   695 
       
   696 QCocoaDropData::QCocoaDropData(CFStringRef pasteboard)
       
   697     : QInternalMimeData()
       
   698 {
       
   699     NSString* pasteboardName = (NSString*)pasteboard;
       
   700     [pasteboardName retain];
       
   701     dropPasteboard = pasteboard;
       
   702 }
       
   703 
       
   704 QCocoaDropData::~QCocoaDropData()
       
   705 {
       
   706     NSString* pasteboardName = (NSString*)dropPasteboard;
       
   707     [pasteboardName release];
       
   708 }
       
   709 
       
   710 QStringList QCocoaDropData::formats_sys() const
       
   711 {
       
   712     QStringList formats; 
       
   713     OSPasteboardRef board;
       
   714     if (PasteboardCreate(dropPasteboard, &board) != noErr) {
       
   715         qDebug("DnD: Cannot get PasteBoard!");
       
   716         return formats;
       
   717     }
       
   718     formats = QMacPasteboard(board, QMacPasteboardMime::MIME_DND).formats();
       
   719     return formats;
       
   720 }
       
   721 
       
   722 QVariant QCocoaDropData::retrieveData_sys(const QString &mimeType, QVariant::Type type) const
       
   723 {
       
   724     QVariant data;
       
   725     OSPasteboardRef board;
       
   726     if (PasteboardCreate(dropPasteboard, &board) != noErr) {
       
   727         qDebug("DnD: Cannot get PasteBoard!");
       
   728         return data;
       
   729     }
       
   730     data = QMacPasteboard(board, QMacPasteboardMime::MIME_DND).retrieveData(mimeType, type);
       
   731     CFRelease(board);
       
   732     return data;
       
   733 }
       
   734 
       
   735 bool QCocoaDropData::hasFormat_sys(const QString &mimeType) const
       
   736 {
       
   737     bool has = false;
       
   738     OSPasteboardRef board;
       
   739     if (PasteboardCreate(dropPasteboard, &board) != noErr) {
       
   740         qDebug("DnD: Cannot get PasteBoard!");
       
   741         return has;
       
   742     }
       
   743     has = QMacPasteboard(board, QMacPasteboardMime::MIME_DND).hasFormat(mimeType);
       
   744     CFRelease(board);
       
   745     return has;
       
   746 }
       
   747 
       
   748 #endif // QT_NO_DRAGANDDROP
       
   749 QT_END_NAMESPACE