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