1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
21 #include <com/sun/star/datatransfer/XTransferable.hpp>
22 #include <com/sun/star/datatransfer/dnd/DropTargetDragEnterEvent.hpp>
23 #include <cppuhelper/interfacecontainer.hxx>
24 #include "clipboard.hxx"
25 #include "DropTarget.hxx"
26 #include "DragActionConversion.hxx"
27 #include "DragSource.hxx"
28 #include <rtl/ustring.h>
30 #include <Carbon/Carbon.h>
32 #include <osx/salframe.h>
33 #include <osx/salframeview.h>
34 #include <cppuhelper/supportsservice.hxx>
38 using namespace com::sun::star::datatransfer
;
39 using namespace com::sun::star::datatransfer::dnd
;
40 using namespace com::sun::star::datatransfer::dnd::DNDConstants
;
41 using namespace com::sun::star::datatransfer::clipboard
;
42 using namespace com::sun::star::lang
;
43 using namespace com::sun::star::uno
;
44 using namespace com::sun::star
;
45 using namespace comphelper
;
47 static OUString
dropTarget_getImplementationName()
49 return "com.sun.star.comp.datatransfer.dnd.OleDropTarget_V1";
52 static Sequence
<OUString
> dropTarget_getSupportedServiceNames()
54 return { OUString("com.sun.star.datatransfer.dnd.OleDropTarget") };
57 namespace /* private */
59 // Cocoa's coordinate system has its origin lower-left, VCL's
60 // coordinate system upper-left hence we need to transform
63 void CocoaToVCL(NSPoint
& rPoint
, const NSRect
& bounds
)
65 rPoint
.y
= bounds
.size
.height
- rPoint
.y
;
69 @implementation DropTargetHelper
71 -(DropTargetHelper
*)initWithDropTarget
:(DropTarget
*)pdt
83 -(NSDragOperation
)draggingEntered
:(id
<NSDraggingInfo
>)sender
85 return mDropTarget
->draggingEntered(sender
);
88 -(NSDragOperation
)draggingUpdated
:(id
<NSDraggingInfo
>)sender
90 return mDropTarget
->draggingUpdated(sender
);
93 -(void)draggingExited
:(id
<NSDraggingInfo
>)sender
95 mDropTarget
->draggingExited(sender
);
98 -(BOOL
)prepareForDragOperation
:(id
<NSDraggingInfo
>)sender
101 return DropTarget::prepareForDragOperation();
104 -(BOOL
)performDragOperation
:(id
<NSDraggingInfo
>)sender
107 return mDropTarget
->performDragOperation();
110 -(void)concludeDragOperation
:(id
<NSDraggingInfo
>)sender
112 mDropTarget
->concludeDragOperation(sender
);
117 DropTarget::DropTarget() :
118 WeakComponentImplHelper
<XInitialization
, XDropTarget
, XDropTargetDragContext
, XDropTargetDropContext
, XServiceInfo
>(m_aMutex
),
121 mDropTargetHelper(nil
),
123 mDragSourceSupportedActions(DNDConstants::ACTION_NONE
),
124 mSelectedDropAction(DNDConstants::ACTION_NONE
),
125 mDefaultActions(DNDConstants::ACTION_COPY_OR_MOVE
| DNDConstants::ACTION_LINK
| DNDConstants::ACTION_DEFAULT
)
127 mDataFlavorMapper
= std::make_shared
<DataFlavorMapper
>();
130 DropTarget::~DropTarget()
132 if( AquaSalFrame::isAlive( mpFrame
) )
133 [static_cast<id
<DraggingDestinationHandler
>>(mView
) unregisterDraggingDestinationHandler
:mDropTargetHelper
];
134 [mDropTargetHelper release
];
137 sal_Int8
DropTarget::determineDropAction(sal_Int8 dropActions
, id sender
) const
139 sal_Int8 dropAct
= dropActions
;
140 bool srcAndDestEqual
= false;
142 if ([sender draggingSource
] != nil
)
145 NSView
* destView
= [[sender draggingDestinationWindow
] contentView
];
146 srcAndDestEqual
= (DragSource::g_DragSourceView
== destView
);
149 // If ACTION_DEFAULT is set this means NSDragOperationGeneric
150 // has been set and we map this to ACTION_MOVE or ACTION_COPY
151 // depending on whether or not source and dest are equal,
152 // this hopefully satisfies all parties
153 if( (dropActions
== DNDConstants::ACTION_DEFAULT
)
154 || ((dropActions
== mDragSourceSupportedActions
)
155 && !(~mDragSourceSupportedActions
& DNDConstants::ACTION_COPY_OR_MOVE
) ) )
157 dropAct
= srcAndDestEqual
? DNDConstants::ACTION_MOVE
:
158 DNDConstants::ACTION_COPY
;
160 // if more than one drop actions have been specified
161 // set ACTION_DEFAULT in order to let the drop target
162 // decide which one to use
163 else if (dropActions
!= DNDConstants::ACTION_NONE
&&
164 dropActions
!= DNDConstants::ACTION_MOVE
&&
165 dropActions
!= DNDConstants::ACTION_COPY
&&
166 dropActions
!= DNDConstants::ACTION_LINK
)
170 dropAct
= dropActions
;
172 else // source and destination are different
174 if (dropActions
& DNDConstants::ACTION_COPY
)
175 dropAct
= DNDConstants::ACTION_COPY
;
176 else if (dropActions
& DNDConstants::ACTION_MOVE
)
177 dropAct
= DNDConstants::ACTION_MOVE
;
178 else if (dropActions
& DNDConstants::ACTION_LINK
)
179 dropAct
= DNDConstants::ACTION_LINK
;
182 dropAct
|= DNDConstants::ACTION_DEFAULT
;
188 NSDragOperation
DropTarget::draggingEntered(id sender
)
190 // Initially when DnD will be started no modifier key can be pressed yet
191 // thus we are getting all actions that the drag source supports, we save
192 // this value because later the system masks the drag source actions if
193 // a modifier key will be pressed
194 mDragSourceSupportedActions
= SystemToOfficeDragActions([sender draggingSourceOperationMask
]);
196 // Only if the drop target is really interested in the drag actions
197 // supported by the source
198 if (mDragSourceSupportedActions
& mDefaultActions
)
200 sal_Int8 currentAction
= determineDropAction(mDragSourceSupportedActions
, sender
);
202 NSRect bounds
= [mView bounds
];
203 NSPoint mouseLoc
= [NSEvent mouseLocation
];
205 id wnd
= [mView window
];
206 NSPoint dragLocation
= [mView convertPoint
:[wnd convertRectFromScreen
:NSMakeRect(mouseLoc
.x
, mouseLoc
.y
, 1, 1)].origin fromView
:nil
];
208 CocoaToVCL(dragLocation
, bounds
);
210 sal_Int32 posX
= static_cast<sal_Int32
>(dragLocation
.x
);
211 sal_Int32 posY
= static_cast<sal_Int32
>(dragLocation
.y
);
213 NSPasteboard
* dragPboard
= [sender draggingPasteboard
];
214 mXCurrentDragClipboard
= new AquaClipboard(dragPboard
, false);
216 uno::Reference
<XTransferable
> xTransferable
= DragSource::g_XTransferable
.is() ?
217 DragSource::g_XTransferable
: mXCurrentDragClipboard
->getContents();
219 DropTargetDragEnterEvent
dtdee(static_cast<OWeakObject
*>(this),
225 mDragSourceSupportedActions
,
226 xTransferable
->getTransferDataFlavors());
228 fire_dragEnter(dtdee
);
231 return OfficeToSystemDragActions(mSelectedDropAction
);
234 NSDragOperation
DropTarget::draggingUpdated(id sender
)
236 sal_Int8 currentDragSourceActions
=
237 SystemToOfficeDragActions([sender draggingSourceOperationMask
]);
238 NSDragOperation dragOp
= NSDragOperationNone
;
240 if (currentDragSourceActions
& mDefaultActions
)
242 sal_Int8 currentAction
= determineDropAction(currentDragSourceActions
, sender
);
243 NSRect bounds
= [mView bounds
];
244 NSPoint mouseLoc
= [NSEvent mouseLocation
];
246 id wnd
= [mView window
];
247 NSPoint dragLocation
= [mView convertPoint
:[wnd convertRectFromScreen
:NSMakeRect(mouseLoc
.x
, mouseLoc
.y
, 1, 1)].origin fromView
:nil
];
249 CocoaToVCL(dragLocation
, bounds
);
251 sal_Int32 posX
= static_cast<sal_Int32
>(dragLocation
.x
);
252 sal_Int32 posY
= static_cast<sal_Int32
>(dragLocation
.y
);
254 DropTargetDragEvent
dtde(static_cast<OWeakObject
*>(this),
260 mDragSourceSupportedActions
);
264 // drag over callbacks likely have rendered something
265 [mView setNeedsDisplay
: true];
267 dragOp
= OfficeToSystemDragActions(mSelectedDropAction
);
269 //NSLog(@"Drag update: Source actions: %x proposed action %x selected action %x", mDragSourceSupportedActions, currentAction, mSelectedDropAction);
272 if (dragOp
== NSDragOperationNone
)
273 [[NSCursor operationNotAllowedCursor
] set
];
274 else if (dragOp
== NSDragOperationCopy
)
275 [[NSCursor dragCopyCursor
] set
];
277 [[NSCursor arrowCursor
] set
];
282 void DropTarget::draggingExited(id
/*sender*/)
284 DropTargetEvent
dte(static_cast<OWeakObject
*>(this), 0);
286 mDragSourceSupportedActions
= DNDConstants::ACTION_NONE
;
287 mSelectedDropAction
= DNDConstants::ACTION_NONE
;
288 [[NSCursor arrowCursor
] set
];
291 BOOL
DropTarget::prepareForDragOperation()
296 BOOL
DropTarget::performDragOperation()
298 bool bSuccess
= false;
300 if (mSelectedDropAction
!= DNDConstants::ACTION_NONE
)
302 uno::Reference
<XTransferable
> xTransferable
= DragSource::g_XTransferable
;
304 if (!DragSource::g_XTransferable
.is())
306 xTransferable
= mXCurrentDragClipboard
->getContents();
309 NSRect bounds
= [mView bounds
];
310 NSPoint mouseLoc
= [NSEvent mouseLocation
];
312 id wnd
= [mView window
];
313 NSPoint dragLocation
= [mView convertPoint
:[wnd convertRectFromScreen
:NSMakeRect(mouseLoc
.x
, mouseLoc
.y
, 1, 1)].origin fromView
:nil
];
315 CocoaToVCL(dragLocation
, bounds
);
317 sal_Int32 posX
= static_cast<sal_Int32
>(dragLocation
.x
);
318 sal_Int32 posY
= static_cast<sal_Int32
>(dragLocation
.y
);
320 DropTargetDropEvent
dtde(static_cast<OWeakObject
*>(this),
326 mDragSourceSupportedActions
,
337 void DropTarget::concludeDragOperation(id
/*sender*/)
339 mDragSourceSupportedActions
= DNDConstants::ACTION_NONE
;
340 mSelectedDropAction
= DNDConstants::ACTION_NONE
;
341 mXCurrentDragClipboard
.clear();
342 [[NSCursor arrowCursor
] set
];
345 // called from WeakComponentImplHelperX::dispose
346 // WeakComponentImplHelper calls disposing before it destroys
348 void SAL_CALL
DropTarget::disposing()
352 void SAL_CALL
DropTarget::initialize(const Sequence
< Any
>& aArguments
)
354 if (aArguments
.getLength() < 2)
356 throw RuntimeException("DropTarget::initialize: Cannot install window event handler",
357 static_cast<OWeakObject
*>(this));
360 Any pNSView
= aArguments
[0];
363 mView
= reinterpret_cast<id
>(tmp
);
364 mpFrame
= [static_cast<SalFrameView
*>(mView
) getSalFrame
];
366 mDropTargetHelper
= [[DropTargetHelper alloc
] initWithDropTarget
: this];
368 [static_cast<id
<DraggingDestinationHandler
>>(mView
) registerDraggingDestinationHandler
:mDropTargetHelper
];
369 [mView registerForDraggedTypes
: DataFlavorMapper::getAllSupportedPboardTypes()];
371 id wnd
= [mView window
];
372 NSWindow
* parentWnd
= [wnd parentWindow
];
373 unsigned int topWndStyle
= (NSWindowStyleMaskTitled
| NSWindowStyleMaskClosable
| NSWindowStyleMaskResizable
);
374 unsigned int wndStyles
= [wnd styleMask
] & topWndStyle
;
376 if (parentWnd
== nil
&& (wndStyles
== topWndStyle
))
378 [wnd registerDraggingDestinationHandler
:mDropTargetHelper
];
379 SAL_WNODEPRECATED_DECLARATIONS_PUSH
380 // "'NSFilenamesPboardType' is deprecated: first deprecated in macOS 10.14 - Create
381 // multiple pasteboard items with NSPasteboardTypeFileURL or kUTTypeFileURL instead"
382 [wnd registerForDraggedTypes
: [NSArray arrayWithObjects
: NSFilenamesPboardType
, nil
]];
383 SAL_WNODEPRECATED_DECLARATIONS_POP
387 void SAL_CALL
DropTarget::addDropTargetListener(const uno::Reference
<XDropTargetListener
>& dtl
)
389 rBHelper
.addListener(cppu::UnoType
<decltype(dtl
)>::get(), dtl
);
392 void SAL_CALL
DropTarget::removeDropTargetListener(const uno::Reference
<XDropTargetListener
>& dtl
)
394 rBHelper
.removeListener(cppu::UnoType
<decltype(dtl
)>::get(), dtl
);
397 sal_Bool SAL_CALL
DropTarget::isActive( )
402 void SAL_CALL
DropTarget::setActive(sal_Bool active
)
407 sal_Int8 SAL_CALL
DropTarget::getDefaultActions()
409 return mDefaultActions
;
412 void SAL_CALL
DropTarget::setDefaultActions(sal_Int8 actions
)
414 OSL_ENSURE( actions
< 8, "No valid default actions");
415 mDefaultActions
= actions
;
418 void SAL_CALL
DropTarget::acceptDrag(sal_Int8 dragOperation
)
420 mSelectedDropAction
= dragOperation
;
423 void SAL_CALL
DropTarget::rejectDrag()
425 mSelectedDropAction
= DNDConstants::ACTION_NONE
;
428 void SAL_CALL
DropTarget::acceptDrop(sal_Int8 dropOperation
)
430 mSelectedDropAction
= dropOperation
;
433 void SAL_CALL
DropTarget::rejectDrop()
435 mSelectedDropAction
= DNDConstants::ACTION_NONE
;
438 void SAL_CALL
DropTarget::dropComplete(sal_Bool success
)
440 // Reset the internal transferable used as shortcut in case this is
441 // an internal D&D operation
442 DragSource::g_XTransferable
.clear();
443 DragSource::g_DropSuccessSet
= true;
444 DragSource::g_DropSuccess
= success
;
447 void DropTarget::fire_drop( const DropTargetDropEvent
& dte
)
449 OInterfaceContainerHelper
* pContainer
= rBHelper
.getContainer( cppu::UnoType
<XDropTargetListener
>::get());
452 OInterfaceIteratorHelper
iter( *pContainer
);
453 while( iter
.hasMoreElements())
455 uno::Reference
<XDropTargetListener
> listener( static_cast<XDropTargetListener
*>( iter
.next()));
457 try { listener
->drop( dte
); }
458 catch(RuntimeException
&) {}
463 void DropTarget::fire_dragEnter(const DropTargetDragEnterEvent
& e
)
465 OInterfaceContainerHelper
* pContainer
= rBHelper
.getContainer( cppu::UnoType
<XDropTargetListener
>::get());
468 OInterfaceIteratorHelper
iter( *pContainer
);
469 while( iter
.hasMoreElements())
471 uno::Reference
<XDropTargetListener
> listener( static_cast<XDropTargetListener
*>( iter
.next()));
473 try { listener
->dragEnter( e
); }
474 catch (RuntimeException
&) {}
479 void DropTarget::fire_dragExit(const DropTargetEvent
& dte
)
481 OInterfaceContainerHelper
* pContainer
= rBHelper
.getContainer( cppu::UnoType
<XDropTargetListener
>::get());
485 OInterfaceIteratorHelper
iter( *pContainer
);
486 while( iter
.hasMoreElements())
488 uno::Reference
<XDropTargetListener
> listener( static_cast<XDropTargetListener
*>( iter
.next()));
490 try { listener
->dragExit( dte
); }
491 catch (RuntimeException
&) {}
496 void DropTarget::fire_dragOver(const DropTargetDragEvent
& dtde
)
498 OInterfaceContainerHelper
* pContainer
= rBHelper
.getContainer( cppu::UnoType
<XDropTargetListener
>::get());
501 OInterfaceIteratorHelper
iter( *pContainer
);
502 while( iter
.hasMoreElements())
504 uno::Reference
<XDropTargetListener
> listener( static_cast<XDropTargetListener
*>( iter
.next()));
506 try { listener
->dragOver( dtde
); }
507 catch (RuntimeException
&) {}
512 void DropTarget::fire_dropActionChanged(const DropTargetDragEvent
& dtde
)
514 OInterfaceContainerHelper
* pContainer
= rBHelper
.getContainer( cppu::UnoType
<XDropTargetListener
>::get());
517 OInterfaceIteratorHelper
iter( *pContainer
);
518 while( iter
.hasMoreElements())
520 uno::Reference
<XDropTargetListener
> listener( static_cast<XDropTargetListener
*>( iter
.next()));
522 try { listener
->dropActionChanged( dtde
); }
523 catch (RuntimeException
&) {}
528 OUString SAL_CALL
DropTarget::getImplementationName()
530 return dropTarget_getImplementationName();
533 sal_Bool SAL_CALL
DropTarget::supportsService( const OUString
& ServiceName
)
535 return cppu::supportsService(this, ServiceName
);
538 Sequence
< OUString
> SAL_CALL
DropTarget::getSupportedServiceNames( )
540 return dropTarget_getSupportedServiceNames();
543 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */