author | Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com> |
Fri, 19 Feb 2010 23:40:16 +0200 | |
branch | RCL_3 |
changeset 4 | 3b1da2848fc7 |
parent 0 | 1918ee327afb |
child 33 | 3e2da88830cd |
permissions | -rw-r--r-- |
0 | 1 |
/**************************************************************************** |
2 |
** |
|
4
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
3 |
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
0 | 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, ¤tActions); |
|
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, ¤tAction); |
|
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 |