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