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 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> 31 #include <com/sun/star/datatransfer/XTransferable.hpp> 32 #include <com/sun/star/datatransfer/dnd/DropTargetDragEnterEvent.hpp> 33 #include <rtl/unload.h> 34 35 #ifndef COMPHELPER_MAKESEQUENCE_HXX_INCLUDED 36 #include "comphelper/makesequence.hxx" 37 #endif 38 #include <cppuhelper/interfacecontainer.hxx> 39 40 #include "aqua_clipboard.hxx" 41 #include "DropTarget.hxx" 42 #include "DragActionConversion.hxx" 43 44 #include "DragSource.hxx" 45 46 #include <rtl/ustring.h> 47 #include <stdio.h> 48 49 #include <premac.h> 50 #include <Carbon/Carbon.h> 51 #include <postmac.h> 52 53 #include <aqua/salframe.h> 54 #include <aqua/salframeview.h> 55 56 using namespace rtl; 57 using namespace cppu; 58 using namespace osl; 59 using namespace com::sun::star::datatransfer; 60 using namespace com::sun::star::datatransfer::dnd; 61 using namespace com::sun::star::datatransfer::dnd::DNDConstants; 62 using namespace com::sun::star::datatransfer::clipboard; 63 using namespace com::sun::star::lang; 64 using namespace com::sun::star::uno; 65 using namespace com::sun::star; 66 using namespace comphelper; 67 68 OUString dropTarget_getImplementationName() 69 { 70 return OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.datatransfer.dnd.OleDropTarget_V1")); 71 } 72 73 74 Sequence<OUString> dropTarget_getSupportedServiceNames() 75 { 76 return makeSequence(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDropTarget"))); 77 } 78 79 80 namespace /* private */ 81 { 82 // Cocoa's coordinate system has its origin lower-left, VCL's 83 // coordinate system upper-left hence we need to transform 84 // coordinates 85 86 inline void CocoaToVCL(NSPoint& rPoint, const NSRect& bounds) 87 { 88 rPoint.y = bounds.size.height - rPoint.y; 89 } 90 91 inline void CocoaToVCL(NSRect& rRect, const NSRect& bounds) 92 { 93 rRect.origin.y = bounds.size.height - (rRect.origin.y + rRect.size.height); 94 } 95 } 96 97 98 @implementation DropTargetHelper 99 100 101 -(DropTargetHelper*)initWithDropTarget:(DropTarget*)pdt 102 { 103 self = [super init]; 104 105 if (self) 106 { 107 mDropTarget = pdt; 108 } 109 110 return self; 111 } 112 113 114 -(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender 115 { 116 return mDropTarget->draggingEntered(sender); 117 } 118 119 120 -(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender 121 { 122 return mDropTarget->draggingUpdated(sender); 123 } 124 125 126 -(void)draggingExited:(id <NSDraggingInfo>)sender 127 { 128 mDropTarget->draggingExited(sender); 129 } 130 131 132 -(BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender 133 { 134 return mDropTarget->prepareForDragOperation(sender); 135 } 136 137 138 -(BOOL)performDragOperation:(id <NSDraggingInfo>)sender 139 { 140 return mDropTarget->performDragOperation(sender); 141 } 142 143 144 -(void)concludeDragOperation:(id <NSDraggingInfo>)sender 145 { 146 mDropTarget->concludeDragOperation(sender); 147 } 148 149 150 @end 151 152 153 DropTarget::DropTarget() : 154 WeakComponentImplHelper5<XInitialization, XDropTarget, XDropTargetDragContext, XDropTargetDropContext, XServiceInfo>(m_aMutex), 155 mView(nil), 156 mpFrame(NULL), 157 mDropTargetHelper(nil), 158 mbActive(false), 159 mDragSourceSupportedActions(DNDConstants::ACTION_NONE), 160 mSelectedDropAction(DNDConstants::ACTION_NONE), 161 mDefaultActions(DNDConstants::ACTION_COPY_OR_MOVE | DNDConstants::ACTION_LINK | DNDConstants::ACTION_DEFAULT) 162 { 163 mDataFlavorMapper = DataFlavorMapperPtr_t(new DataFlavorMapper()); 164 } 165 166 167 DropTarget::~DropTarget() 168 { 169 if( AquaSalFrame::isAlive( mpFrame ) ) 170 [(id <DraggingDestinationHandler>)mView unregisterDraggingDestinationHandler:mDropTargetHelper]; 171 [mDropTargetHelper release]; 172 } 173 174 175 sal_Int8 DropTarget::determineDropAction(sal_Int8 dropActions, id sender) const 176 { 177 sal_Int8 dropAct = dropActions; 178 bool srcAndDestEqual = false; 179 180 if ([sender draggingSource] != nil) 181 { 182 // Internal DnD 183 NSView* destView = [[sender draggingDestinationWindow] contentView]; 184 srcAndDestEqual = (DragSource::g_DragSourceView == destView); 185 } 186 187 // If ACTION_DEFAULT is set this means NSDragOperationGeneric 188 // has been set and we map this to ACTION_MOVE or ACTION_COPY 189 // depending on whether or not source and dest are equal, 190 // this hopefully satisfies all parties 191 if( (dropActions == DNDConstants::ACTION_DEFAULT) 192 || ((dropActions == mDragSourceSupportedActions) 193 && !(~mDragSourceSupportedActions & DNDConstants::ACTION_COPY_OR_MOVE ) ) ) 194 { 195 dropAct = srcAndDestEqual ? DNDConstants::ACTION_MOVE : 196 DNDConstants::ACTION_COPY; 197 } 198 // if more than one drop actions have been specified 199 // set ACTION_DEFAULT in order to let the drop target 200 // decide which one to use 201 else if (dropActions != DNDConstants::ACTION_NONE && 202 dropActions != DNDConstants::ACTION_MOVE && 203 dropActions != DNDConstants::ACTION_COPY && 204 dropActions != DNDConstants::ACTION_LINK) 205 { 206 if (srcAndDestEqual) 207 { 208 dropAct = dropActions; 209 } 210 else // source and destination are different 211 { 212 if (dropActions & DNDConstants::ACTION_COPY) 213 dropAct = DNDConstants::ACTION_COPY; 214 else if (dropActions & DNDConstants::ACTION_MOVE) 215 dropAct = DNDConstants::ACTION_MOVE; 216 else if (dropActions & DNDConstants::ACTION_LINK) 217 dropAct = DNDConstants::ACTION_LINK; 218 } 219 220 dropAct |= DNDConstants::ACTION_DEFAULT; 221 } 222 223 return dropAct; 224 } 225 226 227 NSDragOperation DropTarget::draggingEntered(id sender) 228 { 229 // Initially when DnD will be started no modifier key can be pressed yet 230 // thus we are getting all actions that the drag source supports, we save 231 // this value because later the system masks the drag source actions if 232 // a modifier key will be pressed 233 mDragSourceSupportedActions = SystemToOfficeDragActions([sender draggingSourceOperationMask]); 234 235 // Only if the drop target is really interessted in the drag actions 236 // supported by the source 237 if (mDragSourceSupportedActions & mDefaultActions) 238 { 239 sal_Int8 currentAction = determineDropAction(mDragSourceSupportedActions, sender); 240 241 NSRect bounds = [mView bounds]; 242 NSPoint dragLocation = [sender draggedImageLocation]; 243 244 CocoaToVCL(dragLocation, bounds); 245 246 sal_Int32 posX = static_cast<sal_Int32>(dragLocation.x); 247 sal_Int32 posY = static_cast<sal_Int32>(dragLocation.y); 248 249 NSPasteboard* dragPboard = [sender draggingPasteboard]; 250 mXCurrentDragClipboard = new AquaClipboard(dragPboard, false); 251 252 uno::Reference<XTransferable> xTransferable = DragSource::g_XTransferable.is() ? 253 DragSource::g_XTransferable : mXCurrentDragClipboard->getContents(); 254 255 DropTargetDragEnterEvent dtdee(static_cast<OWeakObject*>(this), 256 0, 257 this, 258 currentAction, 259 posX, 260 posY, 261 mDragSourceSupportedActions, 262 xTransferable->getTransferDataFlavors()); 263 264 fire_dragEnter(dtdee); 265 } 266 267 return OfficeToSystemDragActions(mSelectedDropAction); 268 } 269 270 271 NSDragOperation DropTarget::draggingUpdated(id sender) 272 { 273 sal_Int8 currentDragSourceActions = 274 SystemToOfficeDragActions([sender draggingSourceOperationMask]); 275 NSDragOperation dragOp = NSDragOperationNone; 276 277 if (currentDragSourceActions & mDefaultActions) 278 { 279 sal_Int8 currentAction = determineDropAction(currentDragSourceActions, sender); 280 NSRect bounds = [mView bounds]; 281 NSPoint dragLocation = [sender draggedImageLocation]; 282 283 CocoaToVCL(dragLocation, bounds); 284 285 sal_Int32 posX = static_cast<sal_Int32>(dragLocation.x); 286 sal_Int32 posY = static_cast<sal_Int32>(dragLocation.y); 287 288 DropTargetDragEvent dtde(static_cast<OWeakObject*>(this), 289 0, 290 this, 291 currentAction, 292 posX, 293 posY, 294 mDragSourceSupportedActions); 295 296 fire_dragOver(dtde); 297 298 // drag over callbacks likely have rendered something 299 [mView setNeedsDisplay: TRUE]; 300 301 dragOp = OfficeToSystemDragActions(mSelectedDropAction); 302 303 //NSLog(@"Drag update: Source actions: %x proposed action %x selected action %x", mDragSourceSupportedActions, currentAction, mSelectedDropAction); 304 } 305 306 // Weird but it appears as if there is no method in Cocoa 307 // to create a kThemeCopyArrowCursor hence we have to use 308 // Carbon to do it 309 if (dragOp == NSDragOperationNone) 310 SetThemeCursor(kThemeNotAllowedCursor); 311 else if (dragOp == NSDragOperationCopy) 312 SetThemeCursor(kThemeCopyArrowCursor); 313 else 314 SetThemeCursor(kThemeArrowCursor); 315 316 return dragOp; 317 } 318 319 320 void DropTarget::draggingExited(id /*sender*/) 321 { 322 DropTargetEvent dte(static_cast<OWeakObject*>(this), 0); 323 fire_dragExit(dte); 324 mDragSourceSupportedActions = DNDConstants::ACTION_NONE; 325 mSelectedDropAction = DNDConstants::ACTION_NONE; 326 SetThemeCursor(kThemeArrowCursor); 327 } 328 329 330 BOOL DropTarget::prepareForDragOperation(id /*sender*/) 331 { 332 return 1; 333 } 334 335 336 BOOL DropTarget::performDragOperation(id sender) 337 { 338 bool bSuccess = false; 339 340 if (mSelectedDropAction != DNDConstants::ACTION_NONE) 341 { 342 uno::Reference<XTransferable> xTransferable = DragSource::g_XTransferable; 343 344 if (!DragSource::g_XTransferable.is()) 345 { 346 xTransferable = mXCurrentDragClipboard->getContents(); 347 } 348 349 NSRect bounds = [mView bounds]; 350 NSPoint dragLocation = [sender draggedImageLocation]; 351 352 CocoaToVCL(dragLocation, bounds); 353 354 sal_Int32 posX = static_cast<sal_Int32>(dragLocation.x); 355 sal_Int32 posY = static_cast<sal_Int32>(dragLocation.y); 356 357 DropTargetDropEvent dtde(static_cast<OWeakObject*>(this), 358 0, 359 this, 360 mSelectedDropAction, 361 posX, 362 posY, 363 mDragSourceSupportedActions, 364 xTransferable); 365 366 fire_drop(dtde); 367 368 bSuccess = true; 369 } 370 371 return bSuccess; 372 } 373 374 375 void DropTarget::concludeDragOperation(id /*sender*/) 376 { 377 mDragSourceSupportedActions = DNDConstants::ACTION_NONE; 378 mSelectedDropAction = DNDConstants::ACTION_NONE; 379 mXCurrentDragClipboard = uno::Reference<XClipboard>(); 380 SetThemeCursor(kThemeArrowCursor); 381 } 382 383 384 // called from WeakComponentImplHelperX::dispose 385 // WeakComponentImplHelper calls disposing before it destroys 386 // itself. 387 void SAL_CALL DropTarget::disposing() 388 { 389 } 390 391 392 void SAL_CALL DropTarget::initialize(const Sequence< Any >& aArguments) 393 throw(Exception) 394 { 395 if (aArguments.getLength() < 2) 396 { 397 throw RuntimeException(OUString(RTL_CONSTASCII_USTRINGPARAM("DropTarget::initialize: Cannot install window event handler")), 398 static_cast<OWeakObject*>(this)); 399 } 400 401 Any pNSView = aArguments[0]; 402 sal_uInt64 tmp = 0; 403 pNSView >>= tmp; 404 mView = (id)tmp; 405 mpFrame = [(SalFrameView*)mView getSalFrame]; 406 407 mDropTargetHelper = [[DropTargetHelper alloc] initWithDropTarget: this]; 408 409 [(id <DraggingDestinationHandler>)mView registerDraggingDestinationHandler:mDropTargetHelper]; 410 [mView registerForDraggedTypes: mDataFlavorMapper->getAllSupportedPboardTypes()]; 411 412 id wnd = [mView window]; 413 NSWindow* parentWnd = [wnd parentWindow]; 414 unsigned int topWndStyle = (NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask); 415 unsigned int wndStyles = [wnd styleMask] & topWndStyle; 416 417 if (parentWnd == nil && (wndStyles == topWndStyle)) 418 { 419 [wnd registerDraggingDestinationHandler:mDropTargetHelper]; 420 [wnd registerForDraggedTypes: [NSArray arrayWithObjects: NSFilenamesPboardType, nil]]; 421 } 422 } 423 424 425 void SAL_CALL DropTarget::addDropTargetListener(const uno::Reference<XDropTargetListener>& dtl) 426 throw(RuntimeException) 427 { 428 rBHelper.addListener(::getCppuType(&dtl), dtl); 429 } 430 431 432 void SAL_CALL DropTarget::removeDropTargetListener(const uno::Reference<XDropTargetListener>& dtl) 433 throw(RuntimeException) 434 { 435 rBHelper.removeListener(::getCppuType(&dtl), dtl); 436 } 437 438 439 sal_Bool SAL_CALL DropTarget::isActive( ) throw(RuntimeException) 440 { 441 return mbActive; 442 } 443 444 445 void SAL_CALL DropTarget::setActive(sal_Bool active) throw(RuntimeException) 446 { 447 mbActive = active; 448 } 449 450 451 sal_Int8 SAL_CALL DropTarget::getDefaultActions() throw(RuntimeException) 452 { 453 return mDefaultActions; 454 } 455 456 457 void SAL_CALL DropTarget::setDefaultActions(sal_Int8 actions) throw(RuntimeException) 458 { 459 OSL_ENSURE( actions < 8, "No valid default actions"); 460 mDefaultActions= actions; 461 } 462 463 464 // XDropTargetDragContext 465 466 void SAL_CALL DropTarget::acceptDrag(sal_Int8 dragOperation) throw (RuntimeException) 467 { 468 mSelectedDropAction = dragOperation; 469 } 470 471 472 void SAL_CALL DropTarget::rejectDrag() throw (RuntimeException) 473 { 474 mSelectedDropAction = DNDConstants::ACTION_NONE; 475 } 476 477 478 //XDropTargetDropContext 479 480 void SAL_CALL DropTarget::acceptDrop(sal_Int8 dropOperation) throw( RuntimeException) 481 { 482 mSelectedDropAction = dropOperation; 483 } 484 485 486 void SAL_CALL DropTarget::rejectDrop() throw (RuntimeException) 487 { 488 mSelectedDropAction = DNDConstants::ACTION_NONE; 489 } 490 491 492 void SAL_CALL DropTarget::dropComplete(sal_Bool success) throw (RuntimeException) 493 { 494 // Reset the internal transferable used as shortcut in case this is 495 // an internal D&D operation 496 DragSource::g_XTransferable = uno::Reference<XTransferable>(); 497 DragSource::g_DropSuccessSet = true; 498 DragSource::g_DropSuccess = success; 499 } 500 501 502 void DropTarget::fire_drop( const DropTargetDropEvent& dte) 503 { 504 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) ); 505 if( pContainer) 506 { 507 OInterfaceIteratorHelper iter( *pContainer); 508 while( iter.hasMoreElements()) 509 { 510 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); 511 512 try { listener->drop( dte); } 513 catch(RuntimeException&) {} 514 } 515 } 516 } 517 518 519 void DropTarget::fire_dragEnter(const DropTargetDragEnterEvent& e) 520 { 521 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) ); 522 if( pContainer) 523 { 524 OInterfaceIteratorHelper iter( *pContainer); 525 while( iter.hasMoreElements()) 526 { 527 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); 528 529 try { listener->dragEnter( e); } 530 catch (RuntimeException&) {} 531 } 532 } 533 } 534 535 536 void DropTarget::fire_dragExit(const DropTargetEvent& dte) 537 { 538 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) ); 539 540 if( pContainer) 541 { 542 OInterfaceIteratorHelper iter( *pContainer); 543 while( iter.hasMoreElements()) 544 { 545 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); 546 547 try { listener->dragExit( dte); } 548 catch (RuntimeException&) {} 549 } 550 } 551 } 552 553 554 void DropTarget::fire_dragOver(const DropTargetDragEvent& dtde) 555 { 556 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) ); 557 if( pContainer) 558 { 559 OInterfaceIteratorHelper iter( *pContainer ); 560 while( iter.hasMoreElements()) 561 { 562 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); 563 564 try { listener->dragOver( dtde); } 565 catch (RuntimeException&) {} 566 } 567 } 568 } 569 570 571 void DropTarget::fire_dropActionChanged(const DropTargetDragEvent& dtde) 572 { 573 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) ); 574 if( pContainer) 575 { 576 OInterfaceIteratorHelper iter( *pContainer); 577 while( iter.hasMoreElements()) 578 { 579 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); 580 581 try { listener->dropActionChanged( dtde); } 582 catch (RuntimeException&) {} 583 } 584 } 585 } 586 587 588 // XServiceInfo 589 590 OUString SAL_CALL DropTarget::getImplementationName() throw (RuntimeException) 591 { 592 return dropTarget_getImplementationName(); 593 } 594 595 596 sal_Bool SAL_CALL DropTarget::supportsService( const OUString& ServiceName ) throw (RuntimeException) 597 { 598 return ServiceName.equals(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDropTarget"))); 599 } 600 601 602 Sequence< OUString > SAL_CALL DropTarget::getSupportedServiceNames( ) throw (RuntimeException) 603 { 604 return dropTarget_getSupportedServiceNames(); 605 } 606 607