Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / vcl / osx / DropTarget.cxx
blob4d99f3c6998249d4c16967f5ee971f9f536bdfb8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
29 #include <premac.h>
30 #include <Carbon/Carbon.h>
31 #include <postmac.h>
32 #include <osx/salframe.h>
33 #include <osx/salframeview.h>
34 #include <cppuhelper/supportsservice.hxx>
36 using namespace cppu;
37 using namespace osl;
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 OUString dropTarget_getImplementationName()
49 return OUString("com.sun.star.comp.datatransfer.dnd.OleDropTarget_V1");
52 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
61 // coordinates
63 inline void CocoaToVCL(NSPoint& rPoint, const NSRect& bounds)
65 rPoint.y = bounds.size.height - rPoint.y;
69 @implementation DropTargetHelper
71 -(DropTargetHelper*)initWithDropTarget:(DropTarget*)pdt
73 self = [super init];
75 if (self)
77 mDropTarget = pdt;
80 return self;
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
100 (void) sender;
101 return DropTarget::prepareForDragOperation();
104 -(BOOL)performDragOperation:(id <NSDraggingInfo>)sender
106 (void) sender;
107 return mDropTarget->performDragOperation();
110 -(void)concludeDragOperation:(id <NSDraggingInfo>)sender
112 mDropTarget->concludeDragOperation(sender);
115 @end
117 DropTarget::DropTarget() :
118 WeakComponentImplHelper<XInitialization, XDropTarget, XDropTargetDragContext, XDropTargetDropContext, XServiceInfo>(m_aMutex),
119 mView(nil),
120 mpFrame(nullptr),
121 mDropTargetHelper(nil),
122 mbActive(false),
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 = DataFlavorMapperPtr_t(new 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)
144 // Internal DnD
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)
168 if (srcAndDestEqual)
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;
185 return dropAct;
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 interessted 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),
221 this,
222 currentAction,
223 posX,
224 posY,
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),
256 this,
257 currentAction,
258 posX,
259 posY,
260 mDragSourceSupportedActions);
262 fire_dragOver(dtde);
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];
276 else
277 [[NSCursor arrowCursor] set];
279 return dragOp;
282 void DropTarget::draggingExited(id /*sender*/)
284 DropTargetEvent dte(static_cast<OWeakObject*>(this), 0);
285 fire_dragExit(dte);
286 mDragSourceSupportedActions = DNDConstants::ACTION_NONE;
287 mSelectedDropAction = DNDConstants::ACTION_NONE;
288 [[NSCursor arrowCursor] set];
291 BOOL DropTarget::prepareForDragOperation()
293 return 1;
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),
322 this,
323 mSelectedDropAction,
324 posX,
325 posY,
326 mDragSourceSupportedActions,
327 xTransferable);
329 fire_drop(dtde);
331 bSuccess = true;
334 return bSuccess;
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
347 // itself.
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];
361 sal_uInt64 tmp = 0;
362 pNSView >>= tmp;
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 SAL_WNODEPRECATED_DECLARATIONS_PUSH
374 // 'NSClosableWindowMask' is deprecated: first deprecated in macOS 10.12
375 // 'NSResizableWindowMask' is deprecated: first deprecated in macOS 10.12
376 // 'NSTitleWindowMask' is deprecated: first deprecated in macOS 10.12
377 unsigned int topWndStyle = (NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask);
378 SAL_WNODEPRECATED_DECLARATIONS_POP
379 unsigned int wndStyles = [wnd styleMask] & topWndStyle;
381 if (parentWnd == nil && (wndStyles == topWndStyle))
383 [wnd registerDraggingDestinationHandler:mDropTargetHelper];
384 [wnd registerForDraggedTypes: [NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
388 void SAL_CALL DropTarget::addDropTargetListener(const uno::Reference<XDropTargetListener>& dtl)
390 rBHelper.addListener(cppu::UnoType<decltype(dtl)>::get(), dtl);
393 void SAL_CALL DropTarget::removeDropTargetListener(const uno::Reference<XDropTargetListener>& dtl)
395 rBHelper.removeListener(cppu::UnoType<decltype(dtl)>::get(), dtl);
398 sal_Bool SAL_CALL DropTarget::isActive( )
400 return mbActive;
403 void SAL_CALL DropTarget::setActive(sal_Bool active)
405 mbActive = active;
408 sal_Int8 SAL_CALL DropTarget::getDefaultActions()
410 return mDefaultActions;
413 void SAL_CALL DropTarget::setDefaultActions(sal_Int8 actions)
415 OSL_ENSURE( actions < 8, "No valid default actions");
416 mDefaultActions= actions;
419 void SAL_CALL DropTarget::acceptDrag(sal_Int8 dragOperation)
421 mSelectedDropAction = dragOperation;
424 void SAL_CALL DropTarget::rejectDrag()
426 mSelectedDropAction = DNDConstants::ACTION_NONE;
429 void SAL_CALL DropTarget::acceptDrop(sal_Int8 dropOperation)
431 mSelectedDropAction = dropOperation;
434 void SAL_CALL DropTarget::rejectDrop()
436 mSelectedDropAction = DNDConstants::ACTION_NONE;
439 void SAL_CALL DropTarget::dropComplete(sal_Bool success)
441 // Reset the internal transferable used as shortcut in case this is
442 // an internal D&D operation
443 DragSource::g_XTransferable.clear();
444 DragSource::g_DropSuccessSet = true;
445 DragSource::g_DropSuccess = success;
448 void DropTarget::fire_drop( const DropTargetDropEvent& dte)
450 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get());
451 if( pContainer)
453 OInterfaceIteratorHelper iter( *pContainer);
454 while( iter.hasMoreElements())
456 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
458 try { listener->drop( dte); }
459 catch(RuntimeException&) {}
464 void DropTarget::fire_dragEnter(const DropTargetDragEnterEvent& e)
466 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get());
467 if( pContainer)
469 OInterfaceIteratorHelper iter( *pContainer);
470 while( iter.hasMoreElements())
472 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
474 try { listener->dragEnter( e); }
475 catch (RuntimeException&) {}
480 void DropTarget::fire_dragExit(const DropTargetEvent& dte)
482 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get());
484 if( pContainer)
486 OInterfaceIteratorHelper iter( *pContainer);
487 while( iter.hasMoreElements())
489 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
491 try { listener->dragExit( dte); }
492 catch (RuntimeException&) {}
497 void DropTarget::fire_dragOver(const DropTargetDragEvent& dtde)
499 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get());
500 if( pContainer)
502 OInterfaceIteratorHelper iter( *pContainer );
503 while( iter.hasMoreElements())
505 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
507 try { listener->dragOver( dtde); }
508 catch (RuntimeException&) {}
513 void DropTarget::fire_dropActionChanged(const DropTargetDragEvent& dtde)
515 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( cppu::UnoType<XDropTargetListener>::get());
516 if( pContainer)
518 OInterfaceIteratorHelper iter( *pContainer);
519 while( iter.hasMoreElements())
521 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
523 try { listener->dropActionChanged( dtde); }
524 catch (RuntimeException&) {}
529 OUString SAL_CALL DropTarget::getImplementationName()
531 return dropTarget_getImplementationName();
534 sal_Bool SAL_CALL DropTarget::supportsService( const OUString& ServiceName )
536 return cppu::supportsService(this, ServiceName);
539 Sequence< OUString > SAL_CALL DropTarget::getSupportedServiceNames( )
541 return dropTarget_getSupportedServiceNames();
544 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */