1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_vcl.hxx" 30 31 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> 32 #include <com/sun/star/datatransfer/XTransferable.hpp> 33 #include <com/sun/star/awt/MouseButton.hpp> 34 35 #include "rtl/unload.h" 36 #include "rtl/ustring.hxx" 37 38 #include "comphelper/makesequence.hxx" 39 40 #include "DragSource.hxx" 41 #include "DragSourceContext.hxx" 42 #include "aqua_clipboard.hxx" 43 #include "DragActionConversion.hxx" 44 45 #include "aqua/salframe.h" 46 47 #include <memory> 48 49 50 using namespace rtl; 51 using namespace cppu; 52 using namespace osl; 53 using namespace com::sun::star; 54 using namespace com::sun::star::datatransfer; 55 using namespace com::sun::star::datatransfer::clipboard; 56 using namespace com::sun::star::datatransfer::dnd; 57 using namespace com::sun::star::datatransfer::dnd::DNDConstants; 58 using namespace com::sun::star::uno; 59 using namespace com::sun::star::awt::MouseButton; 60 using namespace com::sun::star::awt; 61 using namespace com::sun::star::lang; 62 using namespace comphelper; 63 using namespace std; 64 65 66 // For OOo internal D&D we provide the Transferable without NSDragPboard 67 // interference as a shortcut 68 uno::Reference<XTransferable> DragSource::g_XTransferable; 69 NSView* DragSource::g_DragSourceView = nil; 70 bool DragSource::g_DropSuccessSet = false; 71 bool DragSource::g_DropSuccess = false; 72 73 74 OUString dragSource_getImplementationName() 75 { 76 return OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.datatransfer.dnd.OleDragSource_V1")); 77 } 78 79 Sequence<OUString> dragSource_getSupportedServiceNames() 80 { 81 return makeSequence(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDragSource"))); 82 } 83 84 85 @implementation DragSourceHelper; 86 87 -(DragSourceHelper*)initWithDragSource: (DragSource*) pds 88 { 89 self = [super init]; 90 91 if (self) 92 { 93 mDragSource = pds; 94 } 95 96 return self; 97 } 98 99 100 -(void)mouseDown: (NSEvent*)theEvent 101 { 102 mDragSource->saveMouseEvent(theEvent); 103 } 104 105 106 -(void)mouseDragged: (NSEvent*)theEvent 107 { 108 mDragSource->saveMouseEvent(theEvent); 109 } 110 111 112 -(unsigned int)draggingSourceOperationMaskForLocal: (BOOL)isLocal 113 { 114 return mDragSource->getSupportedDragOperations(isLocal); 115 } 116 117 118 -(void)draggedImage:(NSImage*)anImage beganAt:(NSPoint)aPoint 119 { 120 (void)anImage; 121 (void)aPoint; 122 DragSourceDragEvent dsde(static_cast<OWeakObject*>(mDragSource), 123 new DragSourceContext(mDragSource), 124 mDragSource, 125 DNDConstants::ACTION_COPY, 126 DNDConstants::ACTION_COPY); 127 128 mDragSource->mXDragSrcListener->dragEnter(dsde); 129 } 130 131 132 -(void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation 133 { 134 (void)anImage; 135 (void)aPoint; 136 // an internal drop can accept the drop but fail with dropComplete( false ) 137 // this is different than the Cocoa API 138 bool bDropSuccess = operation != NSDragOperationNone; 139 if( DragSource::g_DropSuccessSet ) 140 bDropSuccess = DragSource::g_DropSuccess; 141 142 DragSourceDropEvent dsde(static_cast<OWeakObject*>(mDragSource), 143 new DragSourceContext(mDragSource), 144 static_cast< XDragSource* >(mDragSource), 145 SystemToOfficeDragActions(operation), 146 bDropSuccess ); 147 148 mDragSource->mXDragSrcListener->dragDropEnd(dsde); 149 mDragSource->mXDragSrcListener = uno::Reference<XDragSourceListener>(); 150 } 151 152 153 -(void)draggedImage:(NSImage *)draggedImage movedTo:(NSPoint)screenPoint 154 { 155 (void)draggedImage; 156 (void)screenPoint; 157 DragSourceDragEvent dsde(static_cast<OWeakObject*>(mDragSource), 158 new DragSourceContext(mDragSource), 159 mDragSource, 160 DNDConstants::ACTION_COPY, 161 DNDConstants::ACTION_COPY); 162 163 mDragSource->mXDragSrcListener->dragOver(dsde); 164 } 165 166 @end 167 168 169 DragSource::DragSource(): 170 WeakComponentImplHelper3<XDragSource, XInitialization, XServiceInfo>(m_aMutex), 171 mView(NULL), 172 mpFrame(NULL), 173 mLastMouseEventBeforeStartDrag(nil), 174 m_MouseButton(0) 175 { 176 } 177 178 179 DragSource::~DragSource() 180 { 181 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) ) 182 [(id <MouseEventListener>)mView unregisterMouseEventListener: mDragSourceHelper]; 183 [mDragSourceHelper release]; 184 } 185 186 187 void SAL_CALL DragSource::initialize(const Sequence< Any >& aArguments) 188 throw(Exception) 189 { 190 if (aArguments.getLength() < 2) 191 { 192 throw Exception(OUString(RTL_CONSTASCII_USTRINGPARAM("DragSource::initialize: Not enough parameter.")), 193 static_cast<OWeakObject*>(this)); 194 } 195 196 Any pNSView = aArguments[1]; 197 sal_uInt64 tmp = 0; 198 pNSView >>= tmp; 199 mView = (NSView*)tmp; 200 201 /* All SalFrameView the base class for all VCL system views inherits from 202 NSView in order to get mouse and other events. This is the only way to 203 get these events. In order to start a drag operation we need to provide 204 the mouse event which was the trigger. SalFrameView therefor implements 205 a hook mechanism so that we can get mouse events for our purpose. 206 */ 207 if (![mView respondsToSelector: @selector(registerMouseEventListener:)] || 208 ![mView respondsToSelector: @selector(unregisterMouseEventListener:)]) 209 { 210 throw Exception(OUString(RTL_CONSTASCII_USTRINGPARAM("DragSource::initialize: Provided view doesn't support mouse listener")), 211 static_cast<OWeakObject*>(this)); 212 } 213 NSWindow* pWin = [mView window]; 214 if( ! pWin || ![pWin respondsToSelector: @selector(getSalFrame)] ) 215 { 216 throw Exception(OUString(RTL_CONSTASCII_USTRINGPARAM("DragSource::initialize: Provided view is not attached to a vcl frame")), 217 static_cast<OWeakObject*>(this)); 218 } 219 mpFrame = (AquaSalFrame*)[pWin performSelector: @selector(getSalFrame)]; 220 221 mDragSourceHelper = [[DragSourceHelper alloc] initWithDragSource: this]; 222 223 if (mDragSourceHelper == nil) 224 { 225 throw Exception(OUString(RTL_CONSTASCII_USTRINGPARAM("DragSource::initialize: Cannot initialize DragSource")), 226 static_cast<OWeakObject*>(this)); 227 } 228 229 [(id <MouseEventListener>)mView registerMouseEventListener: mDragSourceHelper]; 230 } 231 232 233 //---------------------------------------------------- 234 // XDragSource 235 //---------------------------------------------------- 236 237 sal_Bool SAL_CALL DragSource::isDragImageSupported( ) 238 throw(RuntimeException) 239 { 240 return true; 241 } 242 243 244 sal_Int32 SAL_CALL DragSource::getDefaultCursor( sal_Int8 /*dragAction*/ ) 245 throw( IllegalArgumentException, RuntimeException) 246 { 247 return 0; 248 } 249 250 251 void SAL_CALL DragSource::startDrag(const DragGestureEvent& trigger, 252 sal_Int8 sourceActions, 253 sal_Int32 /*cursor*/, 254 sal_Int32 /*image*/, 255 const uno::Reference<XTransferable >& transferable, 256 const uno::Reference<XDragSourceListener >& listener ) 257 throw( RuntimeException) 258 { 259 MutexGuard guard(m_aMutex); 260 261 OSL_ASSERT(listener.is() && "DragSource::startDrag: No XDragSourceListener provided\n"); 262 OSL_ASSERT(transferable.is() && "DragSource::startDrag: No transferable provided\n"); 263 264 trigger.Event >>= mMouseEvent; 265 m_MouseButton= mMouseEvent.Buttons; 266 mXDragSrcListener = listener; 267 mXCurrentContext = static_cast<XDragSourceContext*>(new DragSourceContext(this)); 268 auto_ptr<AquaClipboard> clipb(new AquaClipboard(NULL, false)); 269 g_XTransferable = transferable; 270 clipb->setContents(g_XTransferable, uno::Reference<XClipboardOwner>()); 271 mDragSourceActions = sourceActions; 272 g_DragSourceView = mView; 273 274 NSSize sz; 275 sz.width = 5; 276 sz.height = 5; 277 278 NSImage* dragImage; 279 dragImage = [[NSImage alloc] initWithSize: sz]; 280 281 NSRect bounds; 282 bounds.origin = NSMakePoint(0,0); 283 bounds.size = sz; 284 285 [dragImage lockFocus]; 286 [[NSColor blackColor] set]; 287 [NSBezierPath fillRect: bounds]; 288 [dragImage unlockFocus]; 289 290 NSPoint pInWnd = [mLastMouseEventBeforeStartDrag locationInWindow]; 291 NSPoint p; 292 p = [mView convertPoint: pInWnd fromView: nil]; 293 p.x = p.x - sz.width/2; 294 p.y = p.y - sz.height/2; 295 296 // reset drop success flags 297 g_DropSuccessSet = false; 298 g_DropSuccess = false; 299 300 [mView dragImage: dragImage 301 at: p 302 offset: NSMakeSize(0,0) 303 event: mLastMouseEventBeforeStartDrag 304 pasteboard: clipb->getPasteboard() 305 source: mDragSourceHelper 306 slideBack: 1]; 307 308 [dragImage release]; 309 310 g_XTransferable = uno::Reference<XTransferable>(); 311 g_DragSourceView = nil; 312 313 // reset drop success flags 314 g_DropSuccessSet = false; 315 g_DropSuccess = false; 316 } 317 318 319 // In order to initiate a D&D operation we need to 320 // provide the triggering mouse event which we get 321 // from the SalFrameView that is associated with 322 // this DragSource 323 void DragSource::saveMouseEvent(NSEvent* theEvent) 324 { 325 if (mLastMouseEventBeforeStartDrag != nil) 326 { 327 [mLastMouseEventBeforeStartDrag release]; 328 } 329 330 mLastMouseEventBeforeStartDrag = theEvent; 331 } 332 333 334 /* isLocal indicates whether or not the DnD operation is OOo 335 internal. 336 */ 337 unsigned int DragSource::getSupportedDragOperations(bool isLocal) const 338 { 339 unsigned int srcActions = OfficeToSystemDragActions(mDragSourceActions); 340 341 if (isLocal) 342 { 343 // Support NSDragOperation generic which means we can 344 // decide which D&D operation to choose. We map 345 // NSDragOperationGenric to DNDConstants::ACTION_DEFAULT 346 // in SystemToOfficeDragActions to signal this and 347 // use it in DropTarget::determineDropAction 348 srcActions |= NSDragOperationGeneric; 349 } 350 else 351 { 352 // Mask out link and move operations on external DnD 353 srcActions &= ~(NSDragOperationMove | NSDragOperationLink); 354 } 355 356 return srcActions; 357 } 358 359 360 //################################ 361 // XServiceInfo 362 //################################ 363 364 OUString SAL_CALL DragSource::getImplementationName( ) throw (RuntimeException) 365 { 366 return dragSource_getImplementationName(); 367 } 368 369 370 sal_Bool SAL_CALL DragSource::supportsService( const OUString& ServiceName ) throw (RuntimeException) 371 { 372 return ServiceName.equals(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDragSource"))); 373 } 374 375 376 Sequence< OUString > SAL_CALL DragSource::getSupportedServiceNames() throw (RuntimeException) 377 { 378 return dragSource_getSupportedServiceNames(); 379 } 380 381 382 383 384