/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_vcl.hxx" #include #include #include #include #ifndef COMPHELPER_MAKESEQUENCE_HXX_INCLUDED #include "comphelper/makesequence.hxx" #endif #include #include "aqua_clipboard.hxx" #include "DropTarget.hxx" #include "DragActionConversion.hxx" #include "DragSource.hxx" #include #include #include #include #include #include #include using namespace rtl; using namespace cppu; using namespace osl; using namespace com::sun::star::datatransfer; using namespace com::sun::star::datatransfer::dnd; using namespace com::sun::star::datatransfer::dnd::DNDConstants; using namespace com::sun::star::datatransfer::clipboard; using namespace com::sun::star::lang; using namespace com::sun::star::uno; using namespace com::sun::star; using namespace comphelper; OUString dropTarget_getImplementationName() { return OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.datatransfer.dnd.OleDropTarget_V1")); } Sequence dropTarget_getSupportedServiceNames() { return makeSequence(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDropTarget"))); } namespace /* private */ { // Cocoa's coordinate system has its origin lower-left, VCL's // coordinate system upper-left hence we need to transform // coordinates inline void CocoaToVCL(NSPoint& rPoint, const NSRect& bounds) { rPoint.y = bounds.size.height - rPoint.y; } inline void CocoaToVCL(NSRect& rRect, const NSRect& bounds) { rRect.origin.y = bounds.size.height - (rRect.origin.y + rRect.size.height); } } @implementation DropTargetHelper -(DropTargetHelper*)initWithDropTarget:(DropTarget*)pdt { self = [super init]; if (self) { mDropTarget = pdt; } return self; } -(NSDragOperation)draggingEntered:(id )sender { return mDropTarget->draggingEntered(sender); } -(NSDragOperation)draggingUpdated:(id )sender { return mDropTarget->draggingUpdated(sender); } -(void)draggingExited:(id )sender { mDropTarget->draggingExited(sender); } -(BOOL)prepareForDragOperation:(id )sender { return mDropTarget->prepareForDragOperation(sender); } -(BOOL)performDragOperation:(id )sender { return mDropTarget->performDragOperation(sender); } -(void)concludeDragOperation:(id )sender { mDropTarget->concludeDragOperation(sender); } @end DropTarget::DropTarget() : WeakComponentImplHelper5(m_aMutex), mView(nil), mpFrame(NULL), mDropTargetHelper(nil), mbActive(false), mDragSourceSupportedActions(DNDConstants::ACTION_NONE), mSelectedDropAction(DNDConstants::ACTION_NONE), mDefaultActions(DNDConstants::ACTION_COPY_OR_MOVE | DNDConstants::ACTION_LINK | DNDConstants::ACTION_DEFAULT) { mDataFlavorMapper = DataFlavorMapperPtr_t(new DataFlavorMapper()); } DropTarget::~DropTarget() { if( AquaSalFrame::isAlive( mpFrame ) ) [(id )mView unregisterDraggingDestinationHandler:mDropTargetHelper]; [mDropTargetHelper release]; } sal_Int8 DropTarget::determineDropAction(sal_Int8 dropActions, id sender) const { sal_Int8 dropAct = dropActions; bool srcAndDestEqual = false; if ([sender draggingSource] != nil) { // Internal DnD NSView* destView = [[sender draggingDestinationWindow] contentView]; srcAndDestEqual = (DragSource::g_DragSourceView == destView); } // If ACTION_DEFAULT is set this means NSDragOperationGeneric // has been set and we map this to ACTION_MOVE or ACTION_COPY // depending on whether or not source and dest are equal, // this hopefully satisfies all parties if( (dropActions == DNDConstants::ACTION_DEFAULT) || ((dropActions == mDragSourceSupportedActions) && !(~mDragSourceSupportedActions & DNDConstants::ACTION_COPY_OR_MOVE ) ) ) { dropAct = srcAndDestEqual ? DNDConstants::ACTION_MOVE : DNDConstants::ACTION_COPY; } // if more than one drop actions have been specified // set ACTION_DEFAULT in order to let the drop target // decide which one to use else if (dropActions != DNDConstants::ACTION_NONE && dropActions != DNDConstants::ACTION_MOVE && dropActions != DNDConstants::ACTION_COPY && dropActions != DNDConstants::ACTION_LINK) { if (srcAndDestEqual) { dropAct = dropActions; } else // source and destination are different { if (dropActions & DNDConstants::ACTION_COPY) dropAct = DNDConstants::ACTION_COPY; else if (dropActions & DNDConstants::ACTION_MOVE) dropAct = DNDConstants::ACTION_MOVE; else if (dropActions & DNDConstants::ACTION_LINK) dropAct = DNDConstants::ACTION_LINK; } dropAct |= DNDConstants::ACTION_DEFAULT; } return dropAct; } NSDragOperation DropTarget::draggingEntered(id sender) { // Initially when DnD will be started no modifier key can be pressed yet // thus we are getting all actions that the drag source supports, we save // this value because later the system masks the drag source actions if // a modifier key will be pressed mDragSourceSupportedActions = SystemToOfficeDragActions([sender draggingSourceOperationMask]); // Only if the drop target is really interessted in the drag actions // supported by the source if (mDragSourceSupportedActions & mDefaultActions) { sal_Int8 currentAction = determineDropAction(mDragSourceSupportedActions, sender); NSRect bounds = [mView bounds]; NSPoint dragLocation = [sender draggedImageLocation]; CocoaToVCL(dragLocation, bounds); sal_Int32 posX = static_cast(dragLocation.x); sal_Int32 posY = static_cast(dragLocation.y); NSPasteboard* dragPboard = [sender draggingPasteboard]; mXCurrentDragClipboard = new AquaClipboard(dragPboard, false); uno::Reference xTransferable = DragSource::g_XTransferable.is() ? DragSource::g_XTransferable : mXCurrentDragClipboard->getContents(); DropTargetDragEnterEvent dtdee(static_cast(this), 0, this, currentAction, posX, posY, mDragSourceSupportedActions, xTransferable->getTransferDataFlavors()); fire_dragEnter(dtdee); } return OfficeToSystemDragActions(mSelectedDropAction); } NSDragOperation DropTarget::draggingUpdated(id sender) { sal_Int8 currentDragSourceActions = SystemToOfficeDragActions([sender draggingSourceOperationMask]); NSDragOperation dragOp = NSDragOperationNone; if (currentDragSourceActions & mDefaultActions) { sal_Int8 currentAction = determineDropAction(currentDragSourceActions, sender); NSRect bounds = [mView bounds]; NSPoint dragLocation = [sender draggedImageLocation]; CocoaToVCL(dragLocation, bounds); sal_Int32 posX = static_cast(dragLocation.x); sal_Int32 posY = static_cast(dragLocation.y); DropTargetDragEvent dtde(static_cast(this), 0, this, currentAction, posX, posY, mDragSourceSupportedActions); fire_dragOver(dtde); // drag over callbacks likely have rendered something [mView setNeedsDisplay: TRUE]; dragOp = OfficeToSystemDragActions(mSelectedDropAction); //NSLog(@"Drag update: Source actions: %x proposed action %x selected action %x", mDragSourceSupportedActions, currentAction, mSelectedDropAction); } if (dragOp == NSDragOperationNone) [[NSCursor operationNotAllowedCursor] set]; else if (dragOp == NSDragOperationCopy) [[NSCursor dragCopyCursor] set]; else [[NSCursor arrowCursor] set]; return dragOp; } void DropTarget::draggingExited(id /*sender*/) { DropTargetEvent dte(static_cast(this), 0); fire_dragExit(dte); mDragSourceSupportedActions = DNDConstants::ACTION_NONE; mSelectedDropAction = DNDConstants::ACTION_NONE; [[NSCursor arrowCursor] set]; } BOOL DropTarget::prepareForDragOperation(id /*sender*/) { return 1; } BOOL DropTarget::performDragOperation(id sender) { bool bSuccess = false; if (mSelectedDropAction != DNDConstants::ACTION_NONE) { uno::Reference xTransferable = DragSource::g_XTransferable; if (!DragSource::g_XTransferable.is()) { xTransferable = mXCurrentDragClipboard->getContents(); } NSRect bounds = [mView bounds]; NSPoint dragLocation = [sender draggedImageLocation]; CocoaToVCL(dragLocation, bounds); sal_Int32 posX = static_cast(dragLocation.x); sal_Int32 posY = static_cast(dragLocation.y); DropTargetDropEvent dtde(static_cast(this), 0, this, mSelectedDropAction, posX, posY, mDragSourceSupportedActions, xTransferable); fire_drop(dtde); bSuccess = true; } return bSuccess; } void DropTarget::concludeDragOperation(id /*sender*/) { mDragSourceSupportedActions = DNDConstants::ACTION_NONE; mSelectedDropAction = DNDConstants::ACTION_NONE; mXCurrentDragClipboard = uno::Reference(); [[NSCursor arrowCursor] set]; } // called from WeakComponentImplHelperX::dispose // WeakComponentImplHelper calls disposing before it destroys // itself. void SAL_CALL DropTarget::disposing() { } void SAL_CALL DropTarget::initialize(const Sequence< Any >& aArguments) throw(Exception) { if (aArguments.getLength() < 2) { throw RuntimeException(OUString(RTL_CONSTASCII_USTRINGPARAM("DropTarget::initialize: Cannot install window event handler")), static_cast(this)); } Any pNSView = aArguments[0]; sal_uInt64 tmp = 0; pNSView >>= tmp; mView = (id)tmp; mpFrame = [(SalFrameView*)mView getSalFrame]; mDropTargetHelper = [[DropTargetHelper alloc] initWithDropTarget: this]; [(id )mView registerDraggingDestinationHandler:mDropTargetHelper]; [mView registerForDraggedTypes: mDataFlavorMapper->getAllSupportedPboardTypes()]; id wnd = [mView window]; NSWindow* parentWnd = [wnd parentWindow]; unsigned int topWndStyle = (NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask); unsigned int wndStyles = [wnd styleMask] & topWndStyle; if (parentWnd == nil && (wndStyles == topWndStyle)) { [wnd registerDraggingDestinationHandler:mDropTargetHelper]; [wnd registerForDraggedTypes: [NSArray arrayWithObjects: NSFilenamesPboardType, nil]]; } } void SAL_CALL DropTarget::addDropTargetListener(const uno::Reference& dtl) throw(RuntimeException) { rBHelper.addListener(::getCppuType(&dtl), dtl); } void SAL_CALL DropTarget::removeDropTargetListener(const uno::Reference& dtl) throw(RuntimeException) { rBHelper.removeListener(::getCppuType(&dtl), dtl); } sal_Bool SAL_CALL DropTarget::isActive( ) throw(RuntimeException) { return mbActive; } void SAL_CALL DropTarget::setActive(sal_Bool active) throw(RuntimeException) { mbActive = active; } sal_Int8 SAL_CALL DropTarget::getDefaultActions() throw(RuntimeException) { return mDefaultActions; } void SAL_CALL DropTarget::setDefaultActions(sal_Int8 actions) throw(RuntimeException) { OSL_ENSURE( actions < 8, "No valid default actions"); mDefaultActions= actions; } // XDropTargetDragContext void SAL_CALL DropTarget::acceptDrag(sal_Int8 dragOperation) throw (RuntimeException) { mSelectedDropAction = dragOperation; } void SAL_CALL DropTarget::rejectDrag() throw (RuntimeException) { mSelectedDropAction = DNDConstants::ACTION_NONE; } //XDropTargetDropContext void SAL_CALL DropTarget::acceptDrop(sal_Int8 dropOperation) throw( RuntimeException) { mSelectedDropAction = dropOperation; } void SAL_CALL DropTarget::rejectDrop() throw (RuntimeException) { mSelectedDropAction = DNDConstants::ACTION_NONE; } void SAL_CALL DropTarget::dropComplete(sal_Bool success) throw (RuntimeException) { // Reset the internal transferable used as shortcut in case this is // an internal D&D operation DragSource::g_XTransferable = uno::Reference(); DragSource::g_DropSuccessSet = true; DragSource::g_DropSuccess = success; } void DropTarget::fire_drop( const DropTargetDropEvent& dte) { OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference* )0 ) ); if( pContainer) { OInterfaceIteratorHelper iter( *pContainer); while( iter.hasMoreElements()) { uno::Reference listener( static_cast( iter.next())); try { listener->drop( dte); } catch(RuntimeException&) {} } } } void DropTarget::fire_dragEnter(const DropTargetDragEnterEvent& e) { OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference* )0 ) ); if( pContainer) { OInterfaceIteratorHelper iter( *pContainer); while( iter.hasMoreElements()) { uno::Reference listener( static_cast( iter.next())); try { listener->dragEnter( e); } catch (RuntimeException&) {} } } } void DropTarget::fire_dragExit(const DropTargetEvent& dte) { OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference* )0 ) ); if( pContainer) { OInterfaceIteratorHelper iter( *pContainer); while( iter.hasMoreElements()) { uno::Reference listener( static_cast( iter.next())); try { listener->dragExit( dte); } catch (RuntimeException&) {} } } } void DropTarget::fire_dragOver(const DropTargetDragEvent& dtde) { OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference* )0 ) ); if( pContainer) { OInterfaceIteratorHelper iter( *pContainer ); while( iter.hasMoreElements()) { uno::Reference listener( static_cast( iter.next())); try { listener->dragOver( dtde); } catch (RuntimeException&) {} } } } void DropTarget::fire_dropActionChanged(const DropTargetDragEvent& dtde) { OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference* )0 ) ); if( pContainer) { OInterfaceIteratorHelper iter( *pContainer); while( iter.hasMoreElements()) { uno::Reference listener( static_cast( iter.next())); try { listener->dropActionChanged( dtde); } catch (RuntimeException&) {} } } } // XServiceInfo OUString SAL_CALL DropTarget::getImplementationName() throw (RuntimeException) { return dropTarget_getImplementationName(); } sal_Bool SAL_CALL DropTarget::supportsService( const OUString& ServiceName ) throw (RuntimeException) { return ServiceName.equals(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDropTarget"))); } Sequence< OUString > SAL_CALL DropTarget::getSupportedServiceNames( ) throw (RuntimeException) { return dropTarget_getSupportedServiceNames(); }