| /************************************************************** |
| * |
| * 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 <com/sun/star/datatransfer/dnd/DNDConstants.hpp> |
| #include <com/sun/star/datatransfer/XTransferable.hpp> |
| #include <com/sun/star/datatransfer/dnd/DropTargetDragEnterEvent.hpp> |
| #include <rtl/unload.h> |
| |
| #ifndef COMPHELPER_MAKESEQUENCE_HXX_INCLUDED |
| #include "comphelper/makesequence.hxx" |
| #endif |
| #include <cppuhelper/interfacecontainer.hxx> |
| |
| #include "aqua_clipboard.hxx" |
| #include "DropTarget.hxx" |
| #include "DragActionConversion.hxx" |
| |
| #include "DragSource.hxx" |
| |
| #include <rtl/ustring.h> |
| #include <stdio.h> |
| |
| #include <premac.h> |
| #include <Carbon/Carbon.h> |
| #include <postmac.h> |
| |
| #include <aqua/salframe.h> |
| #include <aqua/salframeview.h> |
| |
| 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<OUString> 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 <NSDraggingInfo>)sender |
| { |
| return mDropTarget->draggingEntered(sender); |
| } |
| |
| |
| -(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender |
| { |
| return mDropTarget->draggingUpdated(sender); |
| } |
| |
| |
| -(void)draggingExited:(id <NSDraggingInfo>)sender |
| { |
| mDropTarget->draggingExited(sender); |
| } |
| |
| |
| -(BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender |
| { |
| return mDropTarget->prepareForDragOperation(sender); |
| } |
| |
| |
| -(BOOL)performDragOperation:(id <NSDraggingInfo>)sender |
| { |
| return mDropTarget->performDragOperation(sender); |
| } |
| |
| |
| -(void)concludeDragOperation:(id <NSDraggingInfo>)sender |
| { |
| mDropTarget->concludeDragOperation(sender); |
| } |
| |
| |
| @end |
| |
| |
| DropTarget::DropTarget() : |
| WeakComponentImplHelper5<XInitialization, XDropTarget, XDropTargetDragContext, XDropTargetDropContext, XServiceInfo>(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 <DraggingDestinationHandler>)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<sal_Int32>(dragLocation.x); |
| sal_Int32 posY = static_cast<sal_Int32>(dragLocation.y); |
| |
| NSPasteboard* dragPboard = [sender draggingPasteboard]; |
| mXCurrentDragClipboard = new AquaClipboard(dragPboard, false); |
| |
| uno::Reference<XTransferable> xTransferable = DragSource::g_XTransferable.is() ? |
| DragSource::g_XTransferable : mXCurrentDragClipboard->getContents(); |
| |
| DropTargetDragEnterEvent dtdee(static_cast<OWeakObject*>(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<sal_Int32>(dragLocation.x); |
| sal_Int32 posY = static_cast<sal_Int32>(dragLocation.y); |
| |
| DropTargetDragEvent dtde(static_cast<OWeakObject*>(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<OWeakObject*>(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> 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<sal_Int32>(dragLocation.x); |
| sal_Int32 posY = static_cast<sal_Int32>(dragLocation.y); |
| |
| DropTargetDropEvent dtde(static_cast<OWeakObject*>(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<XClipboard>(); |
| [[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<OWeakObject*>(this)); |
| } |
| |
| Any pNSView = aArguments[0]; |
| sal_uInt64 tmp = 0; |
| pNSView >>= tmp; |
| mView = (id)tmp; |
| mpFrame = [(SalFrameView*)mView getSalFrame]; |
| |
| mDropTargetHelper = [[DropTargetHelper alloc] initWithDropTarget: this]; |
| |
| [(id <DraggingDestinationHandler>)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<XDropTargetListener>& dtl) |
| throw(RuntimeException) |
| { |
| rBHelper.addListener(::getCppuType(&dtl), dtl); |
| } |
| |
| |
| void SAL_CALL DropTarget::removeDropTargetListener(const uno::Reference<XDropTargetListener>& 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<XTransferable>(); |
| DragSource::g_DropSuccessSet = true; |
| DragSource::g_DropSuccess = success; |
| } |
| |
| |
| void DropTarget::fire_drop( const DropTargetDropEvent& dte) |
| { |
| OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) ); |
| if( pContainer) |
| { |
| OInterfaceIteratorHelper iter( *pContainer); |
| while( iter.hasMoreElements()) |
| { |
| uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); |
| |
| try { listener->drop( dte); } |
| catch(RuntimeException&) {} |
| } |
| } |
| } |
| |
| |
| void DropTarget::fire_dragEnter(const DropTargetDragEnterEvent& e) |
| { |
| OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) ); |
| if( pContainer) |
| { |
| OInterfaceIteratorHelper iter( *pContainer); |
| while( iter.hasMoreElements()) |
| { |
| uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); |
| |
| try { listener->dragEnter( e); } |
| catch (RuntimeException&) {} |
| } |
| } |
| } |
| |
| |
| void DropTarget::fire_dragExit(const DropTargetEvent& dte) |
| { |
| OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) ); |
| |
| if( pContainer) |
| { |
| OInterfaceIteratorHelper iter( *pContainer); |
| while( iter.hasMoreElements()) |
| { |
| uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); |
| |
| try { listener->dragExit( dte); } |
| catch (RuntimeException&) {} |
| } |
| } |
| } |
| |
| |
| void DropTarget::fire_dragOver(const DropTargetDragEvent& dtde) |
| { |
| OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) ); |
| if( pContainer) |
| { |
| OInterfaceIteratorHelper iter( *pContainer ); |
| while( iter.hasMoreElements()) |
| { |
| uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next())); |
| |
| try { listener->dragOver( dtde); } |
| catch (RuntimeException&) {} |
| } |
| } |
| } |
| |
| |
| void DropTarget::fire_dropActionChanged(const DropTargetDragEvent& dtde) |
| { |
| OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) ); |
| if( pContainer) |
| { |
| OInterfaceIteratorHelper iter( *pContainer); |
| while( iter.hasMoreElements()) |
| { |
| uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( 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(); |
| } |
| |