source: trunk/src/gui/kernel/qcocoaview_mac.mm@ 134

Last change on this file since 134 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 45.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#import <private/qcocoaview_mac_p.h>
43#ifdef QT_MAC_USE_COCOA
44
45#include <private/qwidget_p.h>
46#include <private/qt_mac_p.h>
47#include <private/qapplication_p.h>
48#include <private/qabstractscrollarea_p.h>
49#include <private/qt_cocoa_helpers_mac_p.h>
50#include <private/qdnd_p.h>
51#include <private/qmacinputcontext_p.h>
52
53#include <qscrollarea.h>
54#include <qhash.h>
55#include <qtextformat.h>
56#include <qpaintengine.h>
57#include <QUrl>
58#include <QAccessible>
59#include <QFileInfo>
60#include <QFile>
61
62#include <qdebug.h>
63
64
65QT_BEGIN_NAMESPACE
66
67Q_GLOBAL_STATIC(DnDParams, qMacDnDParams);
68
69extern void qt_mac_update_cursor_at_global_pos(const QPoint &globalPos); // qcursor_mac.mm
70extern bool qt_sendSpontaneousEvent(QObject *, QEvent *); // qapplication.cpp
71extern OSViewRef qt_mac_nativeview_for(const QWidget *w); // qwidget_mac.mm
72extern const QStringList& qEnabledDraggedTypes(); // qmime_mac.cpp
73extern QPointer<QWidget> qt_mouseover; //qapplication_mac.mm
74
75Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum)
76{
77 if (buttonNum == 0)
78 return Qt::LeftButton;
79 if (buttonNum == 1)
80 return Qt::RightButton;
81 if (buttonNum == 2)
82 return Qt::MidButton;
83 if (buttonNum == 3)
84 return Qt::XButton1;
85 if (buttonNum == 4)
86 return Qt::XButton2;
87 return Qt::NoButton;
88}
89
90struct dndenum_mapper
91{
92 NSDragOperation mac_code;
93 Qt::DropAction qt_code;
94 bool Qt2Mac;
95};
96
97static dndenum_mapper dnd_enums[] = {
98 { NSDragOperationLink, Qt::LinkAction, true },
99 { NSDragOperationMove, Qt::MoveAction, true },
100 { NSDragOperationCopy, Qt::CopyAction, true },
101 { NSDragOperationGeneric, Qt::CopyAction, false },
102 { NSDragOperationEvery, Qt::ActionMask, false },
103 { NSDragOperationNone, Qt::IgnoreAction, false }
104};
105
106static NSDragOperation qt_mac_mapDropAction(Qt::DropAction action)
107{
108 for (int i=0; dnd_enums[i].qt_code; i++) {
109 if (dnd_enums[i].Qt2Mac && (action & dnd_enums[i].qt_code)) {
110 return dnd_enums[i].mac_code;
111 }
112 }
113 return NSDragOperationNone;
114}
115
116static NSDragOperation qt_mac_mapDropActions(Qt::DropActions actions)
117{
118 NSDragOperation nsActions = NSDragOperationNone;
119 for (int i=0; dnd_enums[i].qt_code; i++) {
120 if (dnd_enums[i].Qt2Mac && (actions & dnd_enums[i].qt_code))
121 nsActions |= dnd_enums[i].mac_code;
122 }
123 return nsActions;
124}
125
126static Qt::DropAction qt_mac_mapNSDragOperation(NSDragOperation nsActions)
127{
128 Qt::DropAction action = Qt::IgnoreAction;
129 for (int i=0; dnd_enums[i].mac_code; i++) {
130 if (nsActions & dnd_enums[i].mac_code)
131 return dnd_enums[i].qt_code;
132 }
133 return action;
134}
135
136static Qt::DropActions qt_mac_mapNSDragOperations(NSDragOperation nsActions)
137{
138 Qt::DropActions actions = Qt::IgnoreAction;
139 for (int i=0; dnd_enums[i].mac_code; i++) {
140 if (nsActions & dnd_enums[i].mac_code)
141 actions |= dnd_enums[i].qt_code;
142 }
143 return actions;
144}
145
146static QColor colorFrom(NSColor *color)
147{
148 QColor qtColor;
149 NSString *colorSpace = [color colorSpaceName];
150 if (colorSpace == NSDeviceCMYKColorSpace) {
151 CGFloat cyan, magenta, yellow, black, alpha;
152 [color getCyan:&cyan magenta:&magenta yellow:&yellow black:&black alpha:&alpha];
153 qtColor.setCmykF(cyan, magenta, yellow, black, alpha);
154 } else {
155 NSColor *tmpColor;
156 tmpColor = [color colorUsingColorSpaceName:NSDeviceRGBColorSpace];
157 CGFloat red, green, blue, alpha;
158 [tmpColor getRed:&red green:&green blue:&blue alpha:&alpha];
159 qtColor.setRgbF(red, green, blue, alpha);
160 }
161 return qtColor;
162}
163
164QT_END_NAMESPACE
165
166QT_FORWARD_DECLARE_CLASS(QMacCocoaAutoReleasePool)
167QT_FORWARD_DECLARE_CLASS(QCFString)
168QT_FORWARD_DECLARE_CLASS(QDragManager)
169QT_FORWARD_DECLARE_CLASS(QMimeData)
170QT_FORWARD_DECLARE_CLASS(QPoint)
171QT_FORWARD_DECLARE_CLASS(QApplication)
172QT_FORWARD_DECLARE_CLASS(QApplicationPrivate)
173QT_FORWARD_DECLARE_CLASS(QDragEnterEvent)
174QT_FORWARD_DECLARE_CLASS(QDragMoveEvent)
175QT_FORWARD_DECLARE_CLASS(QStringList)
176QT_FORWARD_DECLARE_CLASS(QString)
177QT_FORWARD_DECLARE_CLASS(QRect)
178QT_FORWARD_DECLARE_CLASS(QRegion)
179QT_FORWARD_DECLARE_CLASS(QAbstractScrollArea)
180QT_FORWARD_DECLARE_CLASS(QAbstractScrollAreaPrivate)
181QT_FORWARD_DECLARE_CLASS(QPaintEvent)
182QT_FORWARD_DECLARE_CLASS(QPainter)
183QT_FORWARD_DECLARE_CLASS(QHoverEvent)
184QT_USE_NAMESPACE
185extern "C" {
186 extern NSString *NSTextInputReplacementRangeAttributeName;
187}
188
189
190@implementation QT_MANGLE_NAMESPACE(QCocoaView)
191
192- (id)initWithQWidget:(QWidget *)widget widgetPrivate:(QWidgetPrivate *)widgetprivate
193{
194 self = [super init];
195 if (self) {
196 [self finishInitWithQWidget:widget widgetPrivate:widgetprivate];
197 }
198 composing = false;
199 sendKeyEvents = true;
200 [self setHidden:YES];
201 return self;
202}
203
204- (void) finishInitWithQWidget:(QWidget *)widget widgetPrivate:(QWidgetPrivate *)widgetprivate
205{
206 qwidget = widget;
207 qwidgetprivate = widgetprivate;
208 [[NSNotificationCenter defaultCenter] addObserver:self
209 selector:@selector(frameDidChange:)
210 name:@"NSViewFrameDidChangeNotification"
211 object:self];
212}
213
214-(void)registerDragTypes:(bool)accept
215{
216 QMacCocoaAutoReleasePool pool;
217 if (accept) {
218 const NSString* mimeTypeGeneric = @"com.trolltech.qt.MimeTypeName";
219 NSMutableArray *supportedTypes = [NSMutableArray arrayWithObjects:NSColorPboardType,
220 NSFilenamesPboardType, NSStringPboardType,
221 NSFilenamesPboardType, NSPostScriptPboardType, NSTIFFPboardType,
222 NSRTFPboardType, NSTabularTextPboardType, NSFontPboardType,
223 NSRulerPboardType, NSFileContentsPboardType, NSColorPboardType,
224 NSRTFDPboardType, NSHTMLPboardType, NSPICTPboardType,
225 NSURLPboardType, NSPDFPboardType, NSVCardPboardType,
226 NSFilesPromisePboardType, NSInkTextPboardType,
227 NSMultipleTextSelectionPboardType, mimeTypeGeneric, nil];
228 // Add custom types supported by the application.
229 const QStringList& customTypes = qEnabledDraggedTypes();
230 for (int i = 0; i < customTypes.size(); i++) {
231 [supportedTypes addObject:reinterpret_cast<const NSString *>(QCFString::toCFStringRef(customTypes[i]))];
232 }
233 [self registerForDraggedTypes:supportedTypes];
234 } else {
235 [self unregisterDraggedTypes];
236 }
237}
238
239- (void)removeDropData
240{
241 if (dropData) {
242 delete dropData;
243 dropData = 0;
244 }
245}
246
247- (void)addDropData:(id <NSDraggingInfo>)sender
248{
249 [self removeDropData];
250 CFStringRef dropPasteboard = (CFStringRef) [[sender draggingPasteboard] name];
251 dropData = new QCocoaDropData(dropPasteboard);
252}
253
254- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
255{
256 [self addDropData:sender];
257 QMimeData *mimeData = dropData;
258 if (QDragManager::self()->source())
259 mimeData = QDragManager::self()->dragPrivate()->data;
260 NSPoint windowPoint = [sender draggingLocation];
261 NSPoint globalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:windowPoint];
262 NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
263 QPoint posDrag(localPoint.x, localPoint.y);
264 NSDragOperation nsActions = [sender draggingSourceOperationMask];
265 Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations(nsActions);
266 // send the drag enter event to the widget.
267 QDragEnterEvent qDEEvent(posDrag, qtAllowed, mimeData,
268 QApplication::mouseButtons(), QApplication::keyboardModifiers());
269 QApplication::sendEvent(qwidget, &qDEEvent);
270 if (!qDEEvent.isAccepted()) {
271 // widget is not interested in this drag, so ignore this drop data.
272 [self removeDropData];
273 return NSDragOperationNone;
274 } else {
275 // send a drag move event immediately after a drag enter event (as per documentation).
276 QDragMoveEvent qDMEvent(posDrag, qtAllowed, mimeData,
277 QApplication::mouseButtons(), QApplication::keyboardModifiers());
278 qDMEvent.setDropAction(qDEEvent.dropAction());
279 qDMEvent.accept(); // accept by default, since enter event was accepted.
280 QApplication::sendEvent(qwidget, &qDMEvent);
281 if (!qDMEvent.isAccepted() || qDMEvent.dropAction() == Qt::IgnoreAction) {
282 // since we accepted the drag enter event, the widget expects
283 // future drage move events.
284 // ### check if we need to treat this like the drag enter event.
285 nsActions = QT_PREPEND_NAMESPACE(qt_mac_mapDropAction)(qDEEvent.dropAction());
286 } else {
287 nsActions = QT_PREPEND_NAMESPACE(qt_mac_mapDropAction)(qDMEvent.dropAction());
288 }
289 QT_PREPEND_NAMESPACE(qt_mac_copy_answer_rect)(qDMEvent);
290 return nsActions;
291 }
292 }
293
294- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender
295{
296 // drag enter event was rejected, so ignore the move event.
297 if (dropData == 0)
298 return NSDragOperationNone;
299 // return last value, if we are still in the answerRect.
300 NSPoint windowPoint = [sender draggingLocation];
301 NSPoint globalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:windowPoint];
302 NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
303 NSDragOperation nsActions = [sender draggingSourceOperationMask];
304 QPoint posDrag(localPoint.x, localPoint.y);
305 if (qt_mac_mouse_inside_answer_rect(posDrag)
306 && QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) == nsActions)
307 return QT_PREPEND_NAMESPACE(qt_mac_mapDropActions)(QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastAction));
308 // send drag move event to the widget
309 QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) = nsActions;
310 Qt::DropActions qtAllowed = QT_PREPEND_NAMESPACE(qt_mac_mapNSDragOperations)(nsActions);
311 QMimeData *mimeData = dropData;
312 if (QDragManager::self()->source())
313 mimeData = QDragManager::self()->dragPrivate()->data;
314 QDragMoveEvent qDMEvent(posDrag, qtAllowed, mimeData,
315 QApplication::mouseButtons(), QApplication::keyboardModifiers());
316 qDMEvent.setDropAction(QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec).lastAction);
317 qDMEvent.accept();
318 QApplication::sendEvent(qwidget, &qDMEvent);
319 qt_mac_copy_answer_rect(qDMEvent);
320
321 NSDragOperation operation = qt_mac_mapDropAction(qDMEvent.dropAction());
322 if (!qDMEvent.isAccepted() || qDMEvent.dropAction() == Qt::IgnoreAction) {
323 // ignore this event (we will still receive further notifications)
324 operation = NSDragOperationNone;
325 }
326 return operation;
327}
328
329- (void)draggingExited:(id < NSDraggingInfo >)sender
330{
331 Q_UNUSED(sender)
332 // drag enter event was rejected, so ignore the move event.
333 if (dropData) {
334 QDragLeaveEvent de;
335 QApplication::sendEvent(qwidget, &de);
336 [self removeDropData];
337 }
338
339}
340
341- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
342{
343 [self addDropData:sender];
344
345 NSPoint windowPoint = [sender draggingLocation];
346 NSPoint globalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:windowPoint];
347 NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
348 QPoint posDrop(localPoint.x, localPoint.y);
349
350 NSDragOperation nsActions = [sender draggingSourceOperationMask];
351 Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations(nsActions);
352 QMimeData *mimeData = dropData;
353 if (QDragManager::self()->source())
354 mimeData = QDragManager::self()->dragPrivate()->data;
355 // send the drop event to the widget.
356 QDropEvent de(posDrop, qtAllowed, mimeData,
357 QApplication::mouseButtons(), QApplication::keyboardModifiers());
358 if (QDragManager::self()->object)
359 QDragManager::self()->dragPrivate()->target = qwidget;
360 QApplication::sendEvent(qwidget, &de);
361 if (!de.isAccepted())
362 return NO;
363 else
364 return YES;
365}
366
367- (void)dealloc
368{
369 [[NSNotificationCenter defaultCenter] removeObserver:self];
370 [super dealloc];
371}
372
373- (BOOL)isOpaque;
374{
375 return qwidgetprivate->isOpaque;
376}
377
378- (BOOL)isFlipped;
379{
380 return YES;
381}
382
383- (BOOL) preservesContentDuringLiveResize;
384{
385 return qwidget->testAttribute(Qt::WA_StaticContents);
386}
387
388- (void) setFrameSize:(NSSize)newSize
389{
390 [super setFrameSize:newSize];
391
392 // A change in size has required the view to be invalidated.
393 if ([self inLiveResize])
394 {
395 NSRect rects[4];
396 NSInteger count;
397 [self getRectsExposedDuringLiveResize:rects count:&count];
398 while (count-- > 0)
399 {
400 [self setNeedsDisplayInRect:rects[count]];
401 }
402 }
403 else
404 {
405 [self setNeedsDisplay:YES];
406 }
407}
408
409- (void)drawRect:(NSRect)aRect
410{
411 CGContextRef cg = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
412 qwidgetprivate->hd = cg;
413 CGContextSaveGState(cg);
414
415 if (qwidget->isVisible() && qwidget->updatesEnabled()) { //process the actual paint event.
416 if (qwidget->testAttribute(Qt::WA_WState_InPaintEvent))
417 qWarning("QWidget::repaint: Recursive repaint detected");
418
419 const QRect qrect = QRect(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height);
420 QRegion qrgn(qrect);
421
422 if (!qwidget->isWindow() && !qobject_cast<QAbstractScrollArea *>(qwidget->parent())) {
423 const QRegion &parentMask = qwidget->window()->mask();
424 if (!parentMask.isEmpty()) {
425 const QPoint mappedPoint = qwidget->mapTo(qwidget->window(), qrect.topLeft());
426 qrgn.translate(mappedPoint);
427 qrgn &= parentMask;
428 qrgn.translate(-mappedPoint.x(), -mappedPoint.y());
429 }
430 }
431
432 QPoint redirectionOffset(0, 0);
433 //setup the context
434 qwidget->setAttribute(Qt::WA_WState_InPaintEvent);
435 QPaintEngine *engine = qwidget->paintEngine();
436 if (engine)
437 engine->setSystemClip(qrgn);
438 if (qwidgetprivate->extra && qwidgetprivate->extra->hasMask) {
439 CGRect widgetRect = CGRectMake(0, 0, qwidget->width(), qwidget->height());
440 CGContextTranslateCTM (cg, 0, widgetRect.size.height);
441 CGContextScaleCTM(cg, 1, -1);
442 if (qwidget->isWindow())
443 CGContextClearRect(cg, widgetRect);
444 CGContextClipToMask(cg, widgetRect, qwidgetprivate->extra->imageMask);
445 CGContextScaleCTM(cg, 1, -1);
446 CGContextTranslateCTM (cg, 0, -widgetRect.size.height);
447 }
448
449 if (qwidget->isWindow() && !qwidgetprivate->isOpaque
450 && !qwidget->testAttribute(Qt::WA_MacBrushedMetal)) {
451 CGContextClearRect(cg, NSRectToCGRect(aRect));
452 }
453
454 if (engine && !qwidget->testAttribute(Qt::WA_NoSystemBackground)
455 && (qwidget->isWindow() || qwidget->autoFillBackground())
456 || qwidget->testAttribute(Qt::WA_TintedBackground)
457 || qwidget->testAttribute(Qt::WA_StyledBackground)) {
458#ifdef DEBUG_WIDGET_PAINT
459 if(doDebug)
460 qDebug(" Handling erase for [%s::%s]", qwidget->metaObject()->className(),
461 qwidget->objectName().local8Bit().data());
462#endif
463 QPainter p(qwidget);
464 QAbstractScrollArea *scrollArea = qobject_cast<QAbstractScrollArea *>(qwidget->parent());
465 QPoint scrollAreaOffset;
466 if (scrollArea && scrollArea->viewport() == qwidget) {
467 QAbstractScrollAreaPrivate *priv
468 = static_cast<QAbstractScrollAreaPrivate *>(qt_widget_private(scrollArea));
469 scrollAreaOffset = priv->contentsOffset();
470 p.translate(-scrollAreaOffset);
471 }
472 qwidgetprivate->paintBackground(&p, qrgn, scrollAreaOffset,
473 qwidget->isWindow() ? QWidgetPrivate::DrawAsRoot : 0);
474 p.end();
475 }
476 QPaintEvent e(qrgn);
477#ifdef QT3_SUPPORT
478 e.setErased(true);
479#endif
480 qt_sendSpontaneousEvent(qwidget, &e);
481 if (!redirectionOffset.isNull())
482 QPainter::restoreRedirected(qwidget);
483#ifdef QT_RASTER_PAINTENGINE
484 if(engine && engine->type() == QPaintEngine::Raster)
485 static_cast<QRasterPaintEngine*>(engine)->flush(qwidget,
486 qrgn.boundingRect().topLeft());
487#endif
488 if (engine)
489 engine->setSystemClip(QRegion());
490 qwidget->setAttribute(Qt::WA_WState_InPaintEvent, false);
491 if(!qwidget->testAttribute(Qt::WA_PaintOutsidePaintEvent) && qwidget->paintingActive())
492 qWarning("QWidget: It is dangerous to leave painters active on a"
493 " widget outside of the PaintEvent");
494 }
495 qwidgetprivate->hd = 0;
496 CGContextRestoreGState(cg);
497}
498
499- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
500{
501 Q_UNUSED(theEvent);
502 return !qwidget->testAttribute(Qt::WA_MacNoClickThrough);
503}
504
505- (void)updateTrackingAreas
506{
507 QMacCocoaAutoReleasePool pool;
508 if (NSArray *trackingArray = [self trackingAreas]) {
509 NSUInteger size = [trackingArray count];
510 for (NSUInteger i = 0; i < size; ++i) {
511 NSTrackingArea *t = [trackingArray objectAtIndex:i];
512 [self removeTrackingArea:t];
513 }
514 }
515 NSUInteger trackingOptions = NSTrackingMouseEnteredAndExited | NSTrackingActiveInActiveApp
516 | NSTrackingInVisibleRect;
517 if (qwidget->hasMouseTracking() || !qwidgetprivate->toolTip.isEmpty()
518 || qwidget->testAttribute(Qt::WA_Hover))
519 trackingOptions |= NSTrackingMouseMoved;
520 NSTrackingArea *ta = [[NSTrackingArea alloc] initWithRect:NSMakeRect(0, 0,
521 qwidget->width(),
522 qwidget->height())
523 options:trackingOptions
524 owner:self
525 userInfo:nil];
526 [self addTrackingArea:ta];
527 [ta release];
528}
529
530- (void)mouseEntered:(NSEvent *)event
531{
532 QEvent enterEvent(QEvent::Enter);
533 NSPoint windowPoint = [event locationInWindow];
534 NSPoint globalPoint = [[event window] convertBaseToScreen:windowPoint];
535 NSPoint viewPoint = [self convertPoint:windowPoint fromView:nil];
536 if (!qAppInstance()->activeModalWidget() || QApplicationPrivate::tryModalHelper(qwidget, 0)) {
537 QApplication::sendEvent(qwidget, &enterEvent);
538 qt_mouseover = qwidget;
539
540 // Update cursor and dispatch hover events.
541 qt_mac_update_cursor_at_global_pos(flipPoint(globalPoint).toPoint());
542 if (qwidget->testAttribute(Qt::WA_Hover) &&
543 (!qAppInstance()->activePopupWidget() || qAppInstance()->activePopupWidget() == qwidget->window())) {
544 QHoverEvent he(QEvent::HoverEnter, QPoint(viewPoint.x, viewPoint.y), QPoint(-1, -1));
545 QApplicationPrivate::instance()->notify_helper(qwidget, &he);
546 }
547 }
548}
549
550- (void)mouseExited:(NSEvent *)event
551{
552 QEvent leaveEvent(QEvent::Leave);
553 NSPoint globalPoint = [[event window] convertBaseToScreen:[event locationInWindow]];
554 if (!qAppInstance()->activeModalWidget() || QApplicationPrivate::tryModalHelper(qwidget, 0)) {
555 QApplication::sendEvent(qwidget, &leaveEvent);
556
557 // ### Think about if it is necessary to update the cursor, should only be for a few cases.
558 qt_mac_update_cursor_at_global_pos(flipPoint(globalPoint).toPoint());
559 if (qwidget->testAttribute(Qt::WA_Hover)
560 && (!qAppInstance()->activePopupWidget() || qAppInstance()->activePopupWidget() == qwidget->window())) {
561 QHoverEvent he(QEvent::HoverLeave, QPoint(-1, -1),
562 qwidget->mapFromGlobal(QApplicationPrivate::instance()->hoverGlobalPos));
563 QApplicationPrivate::instance()->notify_helper(qwidget, &he);
564 }
565 }
566}
567
568- (void)flagsChanged:(NSEvent *)theEvent
569{
570 QWidget *widgetToGetKey = qwidget;
571
572 QWidget *popup = qAppInstance()->activePopupWidget();
573 if (popup && popup != qwidget->window())
574 widgetToGetKey = popup->focusWidget() ? popup->focusWidget() : popup;
575 qt_dispatchModifiersChanged(theEvent, widgetToGetKey);
576 [super flagsChanged:theEvent];
577}
578
579- (void)mouseMoved:(NSEvent *)theEvent
580{
581 qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, Qt::NoButton);
582}
583
584- (NSView *)viewUnderTransparentForMouseView:(NSView *)mouseView widget:(QWidget *)widgetToGetMouse
585 withWindowPoint:(NSPoint)windowPoint
586{
587 NSMutableArray *viewsToLookAt = [NSMutableArray arrayWithCapacity:5];
588 [viewsToLookAt addObject:mouseView];
589 QWidget *parentWidget = widgetToGetMouse->parentWidget();
590 while (parentWidget) {
591 [viewsToLookAt addObject:qt_mac_nativeview_for(parentWidget)];
592 parentWidget = parentWidget->parentWidget();
593 }
594
595 // Now walk through the subviews of each view and determine which subview should
596 // get the event. We look through all the subviews at a given level with
597 // the assumption that the last item to be found the candidate has a higher z-order.
598 // Unfortunately, fast enumeration doesn't go backwards in 10.5, so assume go fast
599 // forward is quicker than the slow normal way backwards.
600 NSView *candidateView = nil;
601 for (NSView *lookView in viewsToLookAt) {
602 NSPoint tmpPoint = [lookView convertPoint:windowPoint fromView:nil];
603 for (NSView *view in [lookView subviews]) {
604 if (view == mouseView)
605 continue;
606 NSRect frameRect = [view frame];
607 if (NSMouseInRect(tmpPoint, [view frame], [view isFlipped]))
608 candidateView = view;
609 }
610 if (candidateView)
611 break;
612 }
613
614
615 if (candidateView != nil) {
616 // Now that we've got a candidate, we have to dig into it's tree and see where it is.
617 NSView *lowerView = nil;
618 NSView *viewForDescent = candidateView;
619 while (viewForDescent) {
620 NSPoint tmpPoint = [viewForDescent convertPoint:windowPoint fromView:nil];
621 // Apply same rule as above wrt z-order.
622 for (NSView *view in [viewForDescent subviews]) {
623 if (NSMouseInRect(tmpPoint, [view frame], [view isFlipped]))
624 lowerView = view;
625 }
626 if (!lowerView) // Low as we can be at this point.
627 candidateView = viewForDescent;
628
629 // Try to go deeper, will also exit out of the loop, if we found the point.
630 viewForDescent = lowerView;
631 lowerView = nil;
632 }
633 }
634 // I am transparent, so I can't be a candidate.
635 if (candidateView == mouseView)
636 candidateView = nil;
637 return candidateView;
638}
639
640- (void)mouseDown:(NSEvent *)theEvent
641{
642 qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonPress, Qt::LeftButton);
643 // Don't call super here. This prevents us from getting the mouseUp event,
644 // which we need to send even if the mouseDown event was not accepted.
645 // (this is standard Qt behavior.)
646}
647
648
649- (void)mouseUp:(NSEvent *)theEvent
650{
651 bool mouseOK = qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonRelease, Qt::LeftButton);
652
653 if (!mouseOK)
654 [super mouseUp:theEvent];
655}
656
657- (void)rightMouseDown:(NSEvent *)theEvent
658{
659 bool mouseOK = qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonPress, Qt::RightButton);
660
661 if (!mouseOK)
662 [super rightMouseDown:theEvent];
663}
664
665- (void)rightMouseUp:(NSEvent *)theEvent
666{
667 bool mouseOK = qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonRelease, Qt::RightButton);
668
669 if (!mouseOK)
670 [super rightMouseUp:theEvent];
671}
672
673- (void)otherMouseDown:(NSEvent *)theEvent
674{
675 Qt::MouseButton mouseButton = cocoaButton2QtButton([theEvent buttonNumber]);
676 bool mouseOK = qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonPress, mouseButton);
677
678 if (!mouseOK)
679 [super otherMouseDown:theEvent];
680}
681
682- (void)otherMouseUp:(NSEvent *)theEvent
683{
684 Qt::MouseButton mouseButton = cocoaButton2QtButton([theEvent buttonNumber]);
685 bool mouseOK = qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonRelease, mouseButton);
686
687 if (!mouseOK)
688 [super otherMouseUp:theEvent];
689
690}
691
692- (void)mouseDragged:(NSEvent *)theEvent
693{
694 qMacDnDParams()->view = self;
695 qMacDnDParams()->theEvent = theEvent;
696 bool mouseOK = qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, Qt::LeftButton);
697
698 if (!mouseOK)
699 [super mouseDragged:theEvent];
700}
701
702- (void)rightMouseDragged:(NSEvent *)theEvent
703{
704 qMacDnDParams()->view = self;
705 qMacDnDParams()->theEvent = theEvent;
706 bool mouseOK = qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, Qt::RightButton);
707
708 if (!mouseOK)
709 [super rightMouseDragged:theEvent];
710}
711
712- (void)otherMouseDragged:(NSEvent *)theEvent
713{
714 qMacDnDParams()->view = self;
715 qMacDnDParams()->theEvent = theEvent;
716 Qt::MouseButton mouseButton = cocoaButton2QtButton([theEvent buttonNumber]);
717 bool mouseOK = qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, mouseButton);
718
719 if (!mouseOK)
720 [super otherMouseDragged:theEvent];
721}
722
723- (void)scrollWheel:(NSEvent *)theEvent
724{
725 // Give the Input Manager a chance to process the wheel event.
726 NSInputManager *currentIManager = [NSInputManager currentInputManager];
727 if (currentIManager && [currentIManager wantsToHandleMouseEvents]) {
728 [currentIManager handleMouseEvent:theEvent];
729 }
730
731 NSPoint windowPoint = [theEvent locationInWindow];
732 NSPoint globalPoint = [[theEvent window] convertBaseToScreen:windowPoint];
733 NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
734 QPoint qlocal = QPoint(localPoint.x, localPoint.y);
735 QPoint qglobal = QPoint(globalPoint.x, globalPoint.y);
736 Qt::MouseButton buttons = cocoaButton2QtButton([theEvent buttonNumber]);
737 bool wheelOK = false;
738 Qt::KeyboardModifiers keyMods = qt_cocoaModifiers2QtModifiers([theEvent modifierFlags]);
739
740 // Mouse wheel deltas seem to tick in at increments of 0.1. Qt widgets
741 // expect the delta to be a multiple of 120.
742 const int ScrollFactor = 10 * 120;
743 // The qMax(...) factor reduces the
744 // acceleration for large wheel deltas.
745 int deltaX = [theEvent deltaX] * ScrollFactor * qMax(0.6, 1.1 - qAbs([theEvent deltaX]));
746 int deltaY = [theEvent deltaY] * ScrollFactor * qMax(0.6, 1.1 - qAbs([theEvent deltaY]));
747 int deltaZ = [theEvent deltaZ] * ScrollFactor * qMax(0.6, 1.1 - qAbs([theEvent deltaZ]));
748
749 if (deltaX != 0) {
750 QWheelEvent qwe(qlocal, qglobal, deltaX, buttons, keyMods, Qt::Horizontal);
751 qt_sendSpontaneousEvent(qwidget, &qwe);
752 wheelOK = qwe.isAccepted();
753 if (!wheelOK && QApplicationPrivate::focus_widget
754 && QApplicationPrivate::focus_widget != qwidget) {
755 QWheelEvent qwe2(QApplicationPrivate::focus_widget->mapFromGlobal(qglobal), qglobal,
756 deltaX, buttons, keyMods, Qt::Horizontal);
757 qt_sendSpontaneousEvent(QApplicationPrivate::focus_widget, &qwe2);
758 wheelOK = qwe2.isAccepted();
759 }
760 }
761
762 if (deltaY) {
763 QWheelEvent qwe(qlocal, qglobal, deltaY, buttons, keyMods, Qt::Vertical);
764 qt_sendSpontaneousEvent(qwidget, &qwe);
765 wheelOK = qwe.isAccepted();
766 if (wheelOK && QApplicationPrivate::focus_widget
767 && QApplicationPrivate::focus_widget != qwidget) {
768 QWheelEvent qwe2(QApplicationPrivate::focus_widget->mapFromGlobal(qglobal), qglobal,
769 deltaZ, buttons, keyMods, Qt::Vertical);
770 qt_sendSpontaneousEvent(QApplicationPrivate::focus_widget, &qwe2);
771 wheelOK = qwe2.isAccepted();
772 }
773 }
774
775 if (deltaZ) {
776 // Qt doesn't explicitly support wheels with a Z component. In a misguided attempt to
777 // try to be ahead of the pack, I'm adding this extra value.
778 QWheelEvent qwe(qlocal, qglobal, deltaZ, buttons, keyMods, (Qt::Orientation)3);
779 qt_sendSpontaneousEvent(qwidget, &qwe);
780 wheelOK = qwe.isAccepted();
781 if (!wheelOK && QApplicationPrivate::focus_widget
782 && QApplicationPrivate::focus_widget != qwidget) {
783 QWheelEvent qwe2(QApplicationPrivate::focus_widget->mapFromGlobal(qglobal), qglobal,
784 deltaZ, buttons, keyMods, (Qt::Orientation)3);
785 qt_sendSpontaneousEvent(QApplicationPrivate::focus_widget, &qwe2);
786 wheelOK = qwe2.isAccepted();
787 }
788 }
789 if (!wheelOK) {
790 return [super scrollWheel:theEvent];
791 }
792}
793
794- (void)tabletProximity:(NSEvent *)tabletEvent
795{
796 qt_dispatchTabletProximityEvent(tabletEvent);
797}
798
799- (void)tabletPoint:(NSEvent *)tabletEvent
800{
801 if (!qt_mac_handleTabletEvent(self, tabletEvent))
802 [super tabletPoint:tabletEvent];
803}
804
805- (void)frameDidChange:(NSNotification *)note
806{
807 Q_UNUSED(note);
808 if (qwidget->isWindow())
809 return;
810 NSRect newFrame = [self frame];
811 QRect newGeo(newFrame.origin.x, newFrame.origin.y, newFrame.size.width, newFrame.size.height);
812 bool moved = qwidget->testAttribute(Qt::WA_Moved);
813 bool resized = qwidget->testAttribute(Qt::WA_Resized);
814 qwidget->setGeometry(newGeo);
815 qwidget->setAttribute(Qt::WA_Moved, moved);
816 qwidget->setAttribute(Qt::WA_Resized, resized);
817 qwidgetprivate->syncCocoaMask();
818}
819
820- (BOOL)isEnabled
821{
822 if (!qwidget)
823 return [super isEnabled];
824 return [super isEnabled] && qwidget->isEnabled();
825}
826
827- (void)setEnabled:(BOOL)flag
828{
829 QMacCocoaAutoReleasePool pool;
830 [super setEnabled:flag];
831 if (qwidget->isEnabled() != flag)
832 qwidget->setEnabled(flag);
833}
834
835+ (Class)cellClass
836{
837 return [NSActionCell class];
838}
839
840- (BOOL)acceptsFirstResponder
841{
842 if (qwidget->isWindow())
843 return YES; // Always do it, so that windows can accept key press events.
844 return qwidget->focusPolicy() != Qt::NoFocus;
845}
846
847- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal
848{
849 Q_UNUSED(isLocal);
850 return supportedActions;
851}
852
853- (void)setSupportedActions:(NSDragOperation)actions
854{
855 supportedActions = actions;
856}
857
858- (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation
859{
860 Q_UNUSED(anImage);
861 Q_UNUSED(aPoint);
862 qMacDnDParams()->performedAction = operation;
863}
864
865- (QWidget *)qt_qwidget
866{
867 return qwidget;
868}
869
870- (BOOL)qt_leftButtonIsRightButton
871{
872 return leftButtonIsRightButton;
873}
874
875- (void)qt_setLeftButtonIsRightButton:(BOOL)isSwapped
876{
877 leftButtonIsRightButton = isSwapped;
878}
879
880+ (DnDParams*)currentMouseEvent
881{
882 return qMacDnDParams();
883}
884
885- (void)keyDown:(NSEvent *)theEvent
886{
887 sendKeyEvents = true;
888
889 QWidget *widgetToGetKey = qwidget;
890
891 QWidget *popup = qAppInstance()->activePopupWidget();
892 bool sendToPopup = false;
893 if (popup && popup != qwidget->window()) {
894 widgetToGetKey = popup->focusWidget() ? popup->focusWidget() : popup;
895 sendToPopup = true;
896 }
897
898 if (widgetToGetKey->testAttribute(Qt::WA_InputMethodEnabled)) {
899 [qt_mac_nativeview_for(widgetToGetKey) interpretKeyEvents:[NSArray arrayWithObject: theEvent]];
900 }
901 if (sendKeyEvents && !composing) {
902 bool keyOK = qt_dispatchKeyEvent(theEvent, widgetToGetKey);
903 if (!keyOK && !sendToPopup)
904 [super keyDown:theEvent];
905 }
906}
907
908
909- (void)keyUp:(NSEvent *)theEvent
910{
911 if (sendKeyEvents) {
912 bool keyOK = qt_dispatchKeyEvent(theEvent, qwidget);
913 if (!keyOK)
914 [super keyUp:theEvent];
915 }
916}
917
918- (void)viewWillMoveToWindow:(NSWindow *)window
919{
920 if (qwidget->windowFlags() & Qt::MSWindowsOwnDC
921 && (window != [self window])) { // OpenGL Widget
922 // Create a stupid ClearDrawable Event
923 QEvent event(QEvent::MacGLClearDrawable);
924 qApp->sendEvent(qwidget, &event);
925 }
926}
927
928- (void)viewDidMoveToWindow
929{
930 if (qwidget->windowFlags() & Qt::MSWindowsOwnDC && [self window]) {
931 // call update paint event
932 qwidgetprivate->needWindowChange = true;
933 QEvent event(QEvent::MacGLWindowChange);
934 qApp->sendEvent(qwidget, &event);
935 }
936}
937
938
939// NSTextInput Protocol implementation
940
941- (void) insertText:(id)aString
942{
943 if (composing) {
944 // Send the commit string to the widget.
945 QString commitText;
946 if ([aString isKindOfClass:[NSAttributedString class]]) {
947 commitText = QCFString::toQString(reinterpret_cast<CFStringRef>([aString string]));
948 } else {
949 commitText = QCFString::toQString(reinterpret_cast<CFStringRef>(aString));
950 };
951 composing = false;
952 sendKeyEvents = false;
953 QInputMethodEvent e;
954 e.setCommitString(commitText);
955 qt_sendSpontaneousEvent(qwidget, &e);
956 }
957}
958
959- (void) setMarkedText:(id)aString selectedRange:(NSRange)selRange
960{
961 // Generate the QInputMethodEvent with preedit string and the attributes
962 // for rendering it. The attributes handled here are 'underline',
963 // 'underline color' and 'cursor position'.
964 sendKeyEvents = false;
965 composing = true;
966 QString qtText;
967 // Cursor position is retrived from the range.
968 QList<QInputMethodEvent::Attribute> attrs;
969 attrs<<QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, selRange.location, 1, QVariant());
970 if ([aString isKindOfClass:[NSAttributedString class]]) {
971 qtText = QCFString::toQString(reinterpret_cast<CFStringRef>([aString string]));
972 composingLength = qtText.length();
973 int index = 0;
974 // Create attributes for individual sections of preedit text
975 while (index < composingLength) {
976 NSRange effectiveRange;
977 NSRange range = NSMakeRange(index, composingLength-index);
978 NSDictionary *attributes = [aString attributesAtIndex:index
979 longestEffectiveRange:&effectiveRange
980 inRange:range];
981 NSNumber *underlineStyle = [attributes objectForKey:NSUnderlineStyleAttributeName];
982 if (underlineStyle) {
983 QColor clr (Qt::black);
984 NSColor *color = [attributes objectForKey:NSUnderlineColorAttributeName];
985 if (color) {
986 clr = colorFrom(color);
987 }
988 QTextCharFormat format;
989 format.setFontUnderline(true);
990 format.setUnderlineColor(clr);
991 attrs<<QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
992 effectiveRange.location,
993 effectiveRange.length,
994 format);
995 }
996 index = effectiveRange.location + effectiveRange.length;
997 }
998 } else {
999 // No attributes specified, take only the preedit text.
1000 qtText = QCFString::toQString(reinterpret_cast<CFStringRef>(aString));
1001 composingLength = qtText.length();
1002 }
1003 // Make sure that we have at least one text format.
1004 if (attrs.size() <= 1) {
1005 QTextCharFormat format;
1006 format.setFontUnderline(true);
1007 attrs<<QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
1008 0, composingLength, format);
1009 }
1010 QInputMethodEvent e(qtText, attrs);
1011 qt_sendSpontaneousEvent(qwidget, &e);
1012}
1013
1014- (void) unmarkText
1015{
1016 composing = false;
1017}
1018
1019- (BOOL) hasMarkedText
1020{
1021 return (composing ? YES: NO);
1022}
1023
1024- (void) doCommandBySelector:(SEL)aSelector
1025{
1026 Q_UNUSED(aSelector);
1027}
1028
1029- (BOOL)isComposing
1030{
1031 return composing;
1032}
1033
1034- (NSInteger) conversationIdentifier
1035{
1036 // Return a unique identifier fot this ime conversation
1037 return (NSInteger)self;
1038}
1039
1040- (NSAttributedString *) attributedSubstringFromRange:(NSRange)theRange
1041{
1042 QString selectedText(qwidget->inputMethodQuery(Qt::ImCurrentSelection).toString());
1043 if (!selectedText.isEmpty()) {
1044 QCFString string(selectedText.mid(theRange.location, theRange.length));
1045 const NSString *tmpString = reinterpret_cast<const NSString *>((CFStringRef)string);
1046 return [[[NSAttributedString alloc] initWithString:tmpString] autorelease];
1047 } else {
1048 return nil;
1049 }
1050}
1051
1052- (NSRange) markedRange
1053{
1054 NSRange range;
1055 if (composing) {
1056 range.location = 0;
1057 range.length = composingLength;
1058 } else {
1059 range.location = NSNotFound;
1060 range.length = 0;
1061 }
1062 return range;
1063}
1064
1065- (NSRange) selectedRange
1066{
1067 NSRange selRange;
1068 QString selectedText(qwidget->inputMethodQuery(Qt::ImCurrentSelection).toString());
1069 if (!selectedText.isEmpty()) {
1070 // Consider only the selected text.
1071 selRange.location = 0;
1072 selRange.length = selectedText.length();
1073 } else {
1074 // No selected text.
1075 selRange.location = NSNotFound;
1076 selRange.length = 0;
1077 }
1078 return selRange;
1079
1080}
1081
1082- (NSRect) firstRectForCharacterRange:(NSRange)theRange
1083{
1084 Q_UNUSED(theRange);
1085 // The returned rect is always based on the internal cursor.
1086 QRect mr(qwidget->inputMethodQuery(Qt::ImMicroFocus).toRect());
1087 QPoint mp(qwidget->mapToGlobal(QPoint(mr.bottomLeft())));
1088 NSRect rect ;
1089 rect.origin.x = mp.x();
1090 rect.origin.y = flipYCoordinate(mp.y());
1091 rect.size.width = mr.width();
1092 rect.size.height = mr.height();
1093 return rect;
1094}
1095
1096- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
1097{
1098 // We dont support cursor movements using mouse while composing.
1099 Q_UNUSED(thePoint);
1100 return NSNotFound;
1101}
1102
1103- (NSArray*) validAttributesForMarkedText
1104{
1105 if (!qwidget->testAttribute(Qt::WA_InputMethodEnabled))
1106 return nil; // Not sure if that's correct, but it's saves a malloc.
1107
1108 // Support only underline color/style.
1109 return [NSArray arrayWithObjects:NSUnderlineColorAttributeName,
1110 NSUnderlineStyleAttributeName, nil];
1111}
1112@end
1113
1114QT_BEGIN_NAMESPACE
1115void QMacInputContext::reset()
1116{
1117 QWidget *w = QInputContext::focusWidget();
1118 if (w) {
1119 NSView *view = qt_mac_nativeview_for(w);
1120 if ([view isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaView) class]]) {
1121 QMacCocoaAutoReleasePool pool;
1122 QT_MANGLE_NAMESPACE(QCocoaView) *qc = static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(view);
1123 NSInputManager *currentIManager = [NSInputManager currentInputManager];
1124 if (currentIManager) {
1125 [currentIManager markedTextAbandoned:view];
1126 [qc unmarkText];
1127 }
1128 }
1129 }
1130}
1131
1132bool QMacInputContext::isComposing() const
1133{
1134 QWidget *w = QInputContext::focusWidget();
1135 if (w) {
1136 NSView *view = qt_mac_nativeview_for(w);
1137 if ([view isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaView) class]]) {
1138 return [static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(view) isComposing];
1139 }
1140 }
1141 return false;
1142}
1143
1144extern bool qt_mac_in_drag;
1145void * /*NSImage */qt_mac_create_nsimage(const QPixmap &pm);
1146static const int default_pm_hotx = -2;
1147static const int default_pm_hoty = -16;
1148static const char* default_pm[] = {
1149 "13 9 3 1",
1150 ". c None",
1151 " c #000000",
1152 "X c #FFFFFF",
1153 "X X X X X X X",
1154 " X X X X X X ",
1155 "X ......... X",
1156 " X.........X ",
1157 "X ......... X",
1158 " X.........X ",
1159 "X ......... X",
1160 " X X X X X X ",
1161 "X X X X X X X",
1162};
1163
1164Qt::DropAction QDragManager::drag(QDrag *o)
1165{
1166 if(qt_mac_in_drag) { //just make sure..
1167 qWarning("Qt: Internal error: WH0A, unexpected condition reached");
1168 return Qt::IgnoreAction;
1169 }
1170 if(object == o)
1171 return Qt::IgnoreAction;
1172 /* At the moment it seems clear that Mac OS X does not want to drag with a non-left button
1173 so we just bail early to prevent it */
1174 if(!(GetCurrentEventButtonState() & kEventMouseButtonPrimary))
1175 return Qt::IgnoreAction;
1176
1177 if(object) {
1178 dragPrivate()->source->removeEventFilter(this);
1179 cancel();
1180 beingCancelled = false;
1181 }
1182
1183 object = o;
1184 dragPrivate()->target = 0;
1185
1186#ifndef QT_NO_ACCESSIBILITY
1187 QAccessible::updateAccessibility(this, 0, QAccessible::DragDropStart);
1188#endif
1189
1190 // setup the data
1191 QMacPasteboard dragBoard((CFStringRef) NSDragPboard, QMacPasteboardMime::MIME_DND);
1192 dragPrivate()->data->setData(QLatin1String("application/x-qt-mime-type-name"), QByteArray());
1193 dragBoard.setMimeData(dragPrivate()->data);
1194
1195 // create the image
1196 QPoint hotspot;
1197 QPixmap pix = dragPrivate()->pixmap;
1198 if(pix.isNull()) {
1199 if(dragPrivate()->data->hasText() || dragPrivate()->data->hasUrls()) {
1200 // get the string
1201 QString s = dragPrivate()->data->hasText() ? dragPrivate()->data->text()
1202 : dragPrivate()->data->urls().first().toString();
1203 if(s.length() > 26)
1204 s = s.left(23) + QChar(0x2026);
1205 if(!s.isEmpty()) {
1206 // draw it
1207 QFont f(qApp->font());
1208 f.setPointSize(12);
1209 QFontMetrics fm(f);
1210 QPixmap tmp(fm.width(s), fm.height());
1211 if(!tmp.isNull()) {
1212 QPainter p(&tmp);
1213 p.fillRect(0, 0, tmp.width(), tmp.height(), Qt::color0);
1214 p.setPen(Qt::color1);
1215 p.setFont(f);
1216 p.drawText(0, fm.ascent(), s);
1217 // save it
1218 pix = tmp;
1219 hotspot = QPoint(tmp.width() / 2, tmp.height() / 2);
1220 }
1221 }
1222 } else {
1223 pix = QPixmap(default_pm);
1224 hotspot = QPoint(default_pm_hotx, default_pm_hoty);
1225 }
1226 } else {
1227 hotspot = dragPrivate()->hotspot;
1228 }
1229 // convert the image to NSImage.
1230 NSImage *image = (NSImage *)qt_mac_create_nsimage(pix);
1231 [image retain];
1232 DnDParams *dndParams = [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent];
1233 // save supported actions
1234 [dndParams->view setSupportedActions: qt_mac_mapDropActions(dragPrivate()->possible_actions)];
1235 NSPoint imageLoc = {dndParams->localPoint.x - hotspot.x(),
1236 dndParams->localPoint.y + pix.height() - hotspot.y()};
1237 NSSize mouseOffset = {0.0, 0.0};
1238 NSPasteboard *pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
1239 NSPoint windowPoint = [dndParams->theEvent locationInWindow];
1240 // do the drag
1241 [dndParams->view retain];
1242 [dndParams->view dragImage:image
1243 at:imageLoc
1244 offset:mouseOffset
1245 event:dndParams->theEvent
1246 pasteboard:pboard
1247 source:dndParams->view
1248 slideBack:YES];
1249 [dndParams->view release];
1250 [image release];
1251 object = 0;
1252 Qt::DropAction performedAction(qt_mac_mapNSDragOperation(dndParams->performedAction));
1253 // do post drag processing, if required.
1254 if(performedAction != Qt::IgnoreAction) {
1255 // check if the receiver points us to a file location.
1256 // if so, we need to do the file copy/move ourselves.
1257 QCFType<CFURLRef> pasteLocation = 0;
1258 PasteboardCopyPasteLocation(dragBoard.pasteBoard(), &pasteLocation);
1259 if (pasteLocation) {
1260 QList<QUrl> urls = o->mimeData()->urls();
1261 for (int i = 0; i < urls.size(); ++i) {
1262 QUrl fromUrl = urls.at(i);
1263 QString filename = QFileInfo(fromUrl.path()).fileName();
1264 QUrl toUrl(QCFString::toQString(CFURLGetString(pasteLocation)) + filename);
1265 if (performedAction == Qt::MoveAction)
1266 QFile::rename(fromUrl.path(), toUrl.path());
1267 else if (performedAction == Qt::CopyAction)
1268 QFile::copy(fromUrl.path(), toUrl.path());
1269 }
1270 }
1271 }
1272 return performedAction;
1273}
1274
1275QT_END_NAMESPACE
1276
1277#endif // QT_MAC_USE_COCOA
Note: See TracBrowser for help on using the repository browser.