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 // Weird but it appears as if there is no method in Cocoa 303 // to create a kThemeCopyArrowCursor hence we have to use 304 // Carbon to do it 305 if (dragOp == NSDragOperationNone) 306 SetThemeCursor(kThemeNotAllowedCursor); 307 else if (dragOp == NSDragOperationCopy) 308 SetThemeCursor(kThemeCopyArrowCursor); 309 else 310 SetThemeCursor(kThemeArrowCursor); 311 312 return dragOp; 313 } 314 315 316 void DropTarget::draggingExited(id /*sender*/) 317 { 318 DropTargetEvent dte(static_cast<OWeakObject*>(this), 0); 319 fire_dragExit(dte); 320 mDragSourceSupportedActions = DNDConstants::ACTION_NONE; 321 mSelectedDropAction = DNDConstants::ACTION_NONE; 322 SetThemeCursor(kThemeArrowCursor); 323 } 324 325 326 BOOL DropTarget::prepareForDragOperation(id /*sender*/) 327 { 328 return 1; 329 } 330 331 332 BOOL DropTarget::performDragOperation(id sender) 333 { 334 bool bSuccess = false; 335 336 if (mSelectedDropAction != DNDConstants::ACTION_NONE) 337 { 338 uno::Reference<XTransferable> xTransferable = DragSource::g_XTransferable; 339 340 if (!DragSource::g_XTransferable.is()) 341 { 342 xTransferable = mXCurrentDragClipboard->getContents(); 343 } 344 345 NSRect bounds = [mView bounds]; 346 NSPoint dragLocation = [sender draggedImageLocation]; 347 348 CocoaToVCL(dragLocation, bounds); 349 350 sal_Int32 posX = static_cast<sal_Int32>(dragLocation.x); 351 sal_Int32 posY = static_cast<sal_Int32>(dragLocation.y); 352 353 DropTargetDropEvent dtde(static_cast<OWeakObject*>(this), 354 0, 355 this, 356 mSelectedDropAction, 357 posX, 358 posY, 359 mDragSourceSupportedActions, 360 xTransferable); 361 362 fire_drop(dtde); 363 364 bSuccess = true; 365 } 366 367 return bSuccess; 368 } 369 370 371 void DropTarget::concludeDragOperation(id /*sender*/) 372 { 373 mDragSourceSupportedActions = DNDConstants::ACTION_NONE; 374 mSelectedDropAction = DNDConstants::ACTION_NONE; 375 mXCurrentDragClipboard = uno::Reference<XClipboard>(); 376 SetThemeCursor(kThemeArrowCursor); 377 } 378 379 380 // called from WeakComponentImplHelperX::dispose 381 // WeakComponentImplHelper calls disposing before it destroys 382 // itself. 383 void SAL_CALL DropTarget::disposing() 384 { 385 } 386 387 388 void SAL_CALL DropTarget::initialize(const Sequence< Any >& aArguments) 389 throw(Exception) 390 { 391 if (aArguments.getLength() < 2) 392 { 393 throw RuntimeException(OUString(RTL_CONSTASCII_USTRINGPARAM("DropTarget::initialize: Cannot install window event handler")), 394 static_cast<OWeakObject*>(this)); 395 } 396 397 Any pNSView = aArguments[0]; 398 sal_uInt64 tmp = 0; 399 pNSView >>= tmp; 400 mView = (id)tmp; 401 mpFrame = [(SalFrameView*)mView getSalFrame]; 402 403 mDropTargetHelper = [[DropTargetHelper alloc] initWithDropTarget: this]; 404 405 [(id <DraggingDestinationHandler>)mView registerDraggingDestinationHandler:mDropTargetHelper]; 406 [mView registerForDraggedTypes: mDataFlavorMapper->getAllSupportedPboardTypes()]; 407 408 id wnd = [mView window]; 409 NSWindow* parentWnd = [wnd parentWindow]; 410 unsigned int topWndStyle = (NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask); 411 unsigned int wndStyles = [wnd styleMask] & topWndStyle; 412 413 if (parentWnd == nil && (wndStyles == topWndStyle)) 414 { 415 [wnd registerDraggingDestinationHandler:mDropTargetHelper]; 416 [wnd registerForDraggedTypes: [NSArray arrayWithObjects: NSFilenamesPboardType, nil]]; 417 } 418 } 419 420 421 void SAL_CALL DropTarget::addDropTargetListener(const uno::Reference<XDropTargetListener>& dtl) 422 throw(RuntimeException) 423 { 424 rBHelper.addListener(::getCppuType(&dtl), dtl); 425 } 426 427 428 void SAL_CALL DropTarget::removeDropTargetListener(const uno::Reference<XDropTargetListener>& dtl) 429 throw(RuntimeException) 430 { 431 rBHelper.removeListener(::getCppuType(&dtl), dtl); 432 } 433 434 435 sal_Bool SAL_CALL DropTarget::isActive( ) throw(RuntimeException) 436 { 437 return mbActive; 438 } 439 440 441 void SAL_CALL DropTarget::setActive(sal_Bool active) throw(RuntimeException) 442 { 443 mbActive = active; 444 } 445 446 447 sal_Int8 SAL_CALL DropTarget::getDefaultActions() throw(RuntimeException) 448 { 449 return mDefaultActions; 450 } 451 452 453 void SAL_CALL DropTarget::setDefaultActions(sal_Int8 actions) throw(RuntimeException) 454 { 455 OSL_ENSURE( actions < 8, "No valid default actions"); 456 mDefaultActions= actions; 457 } 458 459 460 // XDropTargetDragContext 461 462 void SAL_CALL DropTarget::acceptDrag(sal_Int8 dragOperation) throw (RuntimeException) 463 { 464 mSelectedDropAction = dragOperation; 465 } 466 467 468 void SAL_CALL DropTarget::rejectDrag() throw (RuntimeException) 469 { 470 mSelectedDropAction = DNDConstants::ACTION_NONE; 471 } 472 473 474 //XDropTargetDropContext 475 476 void SAL_CALL DropTarget::acceptDrop(sal_Int8 dropOperation) throw( RuntimeException) 477 { 478 mSelectedDropAction = dropOperation; 479 } 480 481 482 void SAL_CALL DropTarget::rejectDrop() throw (RuntimeException) 483 { 484 mSelectedDropAction = DNDConstants::ACTION_NONE; 485 } 486 487 488 void SAL_CALL DropTarget::dropComplete(sal_Bool success) throw (RuntimeException) 489 { 490 // Reset the internal transferable used as shortcut in case this is 491 // an internal D&D operation 492 DragSource::g_XTransferable = uno::Reference<XTransferable>(); 493 DragSource::g_DropSuccessSet = true; 494 DragSource::g_DropSuccess = success; 495 } 496 497 498 void DropTarget::fire_drop( const DropTargetDropEvent& dte) 499 { 500 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) ); 501 if( pContainer) 502 { 503 OInterfaceIteratorHelper iter( *pContainer); 504 while( iter.hasMoreElements()) 505 { 506 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); 507 508 try { listener->drop( dte); } 509 catch(RuntimeException&) {} 510 } 511 } 512 } 513 514 515 void DropTarget::fire_dragEnter(const DropTargetDragEnterEvent& e) 516 { 517 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) ); 518 if( pContainer) 519 { 520 OInterfaceIteratorHelper iter( *pContainer); 521 while( iter.hasMoreElements()) 522 { 523 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); 524 525 try { listener->dragEnter( e); } 526 catch (RuntimeException&) {} 527 } 528 } 529 } 530 531 532 void DropTarget::fire_dragExit(const DropTargetEvent& dte) 533 { 534 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) ); 535 536 if( pContainer) 537 { 538 OInterfaceIteratorHelper iter( *pContainer); 539 while( iter.hasMoreElements()) 540 { 541 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); 542 543 try { listener->dragExit( dte); } 544 catch (RuntimeException&) {} 545 } 546 } 547 } 548 549 550 void DropTarget::fire_dragOver(const DropTargetDragEvent& dtde) 551 { 552 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) ); 553 if( pContainer) 554 { 555 OInterfaceIteratorHelper iter( *pContainer ); 556 while( iter.hasMoreElements()) 557 { 558 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); 559 560 try { listener->dragOver( dtde); } 561 catch (RuntimeException&) {} 562 } 563 } 564 } 565 566 567 void DropTarget::fire_dropActionChanged(const DropTargetDragEvent& dtde) 568 { 569 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) ); 570 if( pContainer) 571 { 572 OInterfaceIteratorHelper iter( *pContainer); 573 while( iter.hasMoreElements()) 574 { 575 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); 576 577 try { listener->dropActionChanged( dtde); } 578 catch (RuntimeException&) {} 579 } 580 } 581 } 582 583 584 // XServiceInfo 585 586 OUString SAL_CALL DropTarget::getImplementationName() throw (RuntimeException) 587 { 588 return dropTarget_getImplementationName(); 589 } 590 591 592 sal_Bool SAL_CALL DropTarget::supportsService( const OUString& ServiceName ) throw (RuntimeException) 593 { 594 return ServiceName.equals(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDropTarget"))); 595 } 596 597 598 Sequence< OUString > SAL_CALL DropTarget::getSupportedServiceNames( ) throw (RuntimeException) 599 { 600 return dropTarget_getSupportedServiceNames(); 601 } 602 603