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