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 "comphelper/makesequence.hxx"
24 #include <cppuhelper/interfacecontainer.hxx>
25 #include "clipboard.hxx"
26 #include "DropTarget.hxx"
27 #include "DragActionConversion.hxx"
28 #include "DragSource.hxx"
29 #include <rtl/ustring.h>
32 #include <Carbon/Carbon.h>
34 #include <osx/salframe.h>
35 #include <osx/salframeview.h>
36 #include <cppuhelper/supportsservice.hxx>
40 using namespace com::sun::star::datatransfer
;
41 using namespace com::sun::star::datatransfer::dnd
;
42 using namespace com::sun::star::datatransfer::dnd::DNDConstants
;
43 using namespace com::sun::star::datatransfer::clipboard
;
44 using namespace com::sun::star::lang
;
45 using namespace com::sun::star::uno
;
46 using namespace com::sun::star
;
47 using namespace comphelper
;
49 OUString
dropTarget_getImplementationName()
51 return OUString("com.sun.star.comp.datatransfer.dnd.OleDropTarget_V1");
54 Sequence
<OUString
> dropTarget_getSupportedServiceNames()
56 return makeSequence(OUString("com.sun.star.datatransfer.dnd.OleDropTarget"));
59 namespace /* private */
61 // Cocoa's coordinate system has its origin lower-left, VCL's
62 // coordinate system upper-left hence we need to transform
65 inline void CocoaToVCL(NSPoint
& rPoint
, const NSRect
& bounds
)
67 rPoint
.y
= bounds
.size
.height
- rPoint
.y
;
71 @implementation DropTargetHelper
73 -(DropTargetHelper
*)initWithDropTarget
:(DropTarget
*)pdt
85 -(NSDragOperation
)draggingEntered
:(id
<NSDraggingInfo
>)sender
87 return mDropTarget
->draggingEntered(sender
);
90 -(NSDragOperation
)draggingUpdated
:(id
<NSDraggingInfo
>)sender
92 return mDropTarget
->draggingUpdated(sender
);
95 -(void)draggingExited
:(id
<NSDraggingInfo
>)sender
97 mDropTarget
->draggingExited(sender
);
100 -(BOOL
)prepareForDragOperation
:(id
<NSDraggingInfo
>)sender
103 return DropTarget::prepareForDragOperation();
106 -(BOOL
)performDragOperation
:(id
<NSDraggingInfo
>)sender
109 return mDropTarget
->performDragOperation();
112 -(void)concludeDragOperation
:(id
<NSDraggingInfo
>)sender
114 mDropTarget
->concludeDragOperation(sender
);
119 DropTarget::DropTarget() :
120 WeakComponentImplHelper5
<XInitialization
, XDropTarget
, XDropTargetDragContext
, XDropTargetDropContext
, XServiceInfo
>(m_aMutex
),
123 mDropTargetHelper(nil
),
125 mDragSourceSupportedActions(DNDConstants::ACTION_NONE
),
126 mSelectedDropAction(DNDConstants::ACTION_NONE
),
127 mDefaultActions(DNDConstants::ACTION_COPY_OR_MOVE
| DNDConstants::ACTION_LINK
| DNDConstants::ACTION_DEFAULT
)
129 mDataFlavorMapper
= DataFlavorMapperPtr_t(new DataFlavorMapper());
132 DropTarget::~DropTarget()
134 if( AquaSalFrame::isAlive( mpFrame
) )
135 [(id
<DraggingDestinationHandler
>)mView unregisterDraggingDestinationHandler
:mDropTargetHelper
];
136 [mDropTargetHelper release
];
139 sal_Int8
DropTarget::determineDropAction(sal_Int8 dropActions
, id sender
) const
141 sal_Int8 dropAct
= dropActions
;
142 bool srcAndDestEqual
= false;
144 if ([sender draggingSource
] != nil
)
147 NSView
* destView
= [[sender draggingDestinationWindow
] contentView
];
148 srcAndDestEqual
= (DragSource::g_DragSourceView
== destView
);
151 // If ACTION_DEFAULT is set this means NSDragOperationGeneric
152 // has been set and we map this to ACTION_MOVE or ACTION_COPY
153 // depending on whether or not source and dest are equal,
154 // this hopefully satisfies all parties
155 if( (dropActions
== DNDConstants::ACTION_DEFAULT
)
156 || ((dropActions
== mDragSourceSupportedActions
)
157 && !(~mDragSourceSupportedActions
& DNDConstants::ACTION_COPY_OR_MOVE
) ) )
159 dropAct
= srcAndDestEqual
? DNDConstants::ACTION_MOVE
:
160 DNDConstants::ACTION_COPY
;
162 // if more than one drop actions have been specified
163 // set ACTION_DEFAULT in order to let the drop target
164 // decide which one to use
165 else if (dropActions
!= DNDConstants::ACTION_NONE
&&
166 dropActions
!= DNDConstants::ACTION_MOVE
&&
167 dropActions
!= DNDConstants::ACTION_COPY
&&
168 dropActions
!= DNDConstants::ACTION_LINK
)
172 dropAct
= dropActions
;
174 else // source and destination are different
176 if (dropActions
& DNDConstants::ACTION_COPY
)
177 dropAct
= DNDConstants::ACTION_COPY
;
178 else if (dropActions
& DNDConstants::ACTION_MOVE
)
179 dropAct
= DNDConstants::ACTION_MOVE
;
180 else if (dropActions
& DNDConstants::ACTION_LINK
)
181 dropAct
= DNDConstants::ACTION_LINK
;
184 dropAct
|= DNDConstants::ACTION_DEFAULT
;
190 NSDragOperation
DropTarget::draggingEntered(id sender
)
192 // Initially when DnD will be started no modifier key can be pressed yet
193 // thus we are getting all actions that the drag source supports, we save
194 // this value because later the system masks the drag source actions if
195 // a modifier key will be pressed
196 mDragSourceSupportedActions
= SystemToOfficeDragActions([sender draggingSourceOperationMask
]);
198 // Only if the drop target is really interessted in the drag actions
199 // supported by the source
200 if (mDragSourceSupportedActions
& mDefaultActions
)
202 sal_Int8 currentAction
= determineDropAction(mDragSourceSupportedActions
, sender
);
204 NSRect bounds
= [mView bounds
];
205 NSPoint mouseLoc
= [NSEvent mouseLocation
];
207 id wnd
= [mView window
];
208 NSPoint dragLocation
= [mView convertPoint
:[wnd convertScreenToBase
:mouseLoc
] fromView
:nil
];
210 CocoaToVCL(dragLocation
, bounds
);
212 sal_Int32 posX
= static_cast<sal_Int32
>(dragLocation
.x
);
213 sal_Int32 posY
= static_cast<sal_Int32
>(dragLocation
.y
);
215 NSPasteboard
* dragPboard
= [sender draggingPasteboard
];
216 mXCurrentDragClipboard
= new AquaClipboard(dragPboard
, false);
218 uno::Reference
<XTransferable
> xTransferable
= DragSource::g_XTransferable
.is() ?
219 DragSource::g_XTransferable
: mXCurrentDragClipboard
->getContents();
221 DropTargetDragEnterEvent
dtdee(static_cast<OWeakObject
*>(this),
227 mDragSourceSupportedActions
,
228 xTransferable
->getTransferDataFlavors());
230 fire_dragEnter(dtdee
);
233 return OfficeToSystemDragActions(mSelectedDropAction
);
236 NSDragOperation
DropTarget::draggingUpdated(id sender
)
238 sal_Int8 currentDragSourceActions
=
239 SystemToOfficeDragActions([sender draggingSourceOperationMask
]);
240 NSDragOperation dragOp
= NSDragOperationNone
;
242 if (currentDragSourceActions
& mDefaultActions
)
244 sal_Int8 currentAction
= determineDropAction(currentDragSourceActions
, sender
);
245 NSRect bounds
= [mView bounds
];
246 NSPoint mouseLoc
= [NSEvent mouseLocation
];
248 id wnd
= [mView window
];
249 NSPoint dragLocation
= [mView convertPoint
:[wnd convertScreenToBase
:mouseLoc
] fromView
:nil
];
251 CocoaToVCL(dragLocation
, bounds
);
253 sal_Int32 posX
= static_cast<sal_Int32
>(dragLocation
.x
);
254 sal_Int32 posY
= static_cast<sal_Int32
>(dragLocation
.y
);
256 DropTargetDragEvent
dtde(static_cast<OWeakObject
*>(this),
262 mDragSourceSupportedActions
);
266 // drag over callbacks likely have rendered something
267 [mView setNeedsDisplay
: TRUE
];
269 dragOp
= OfficeToSystemDragActions(mSelectedDropAction
);
271 //NSLog(@"Drag update: Source actions: %x proposed action %x selected action %x", mDragSourceSupportedActions, currentAction, mSelectedDropAction);
274 if (dragOp
== NSDragOperationNone
)
275 [[NSCursor operationNotAllowedCursor
] set
];
276 else if (dragOp
== NSDragOperationCopy
)
277 [[NSCursor dragCopyCursor
] set
];
279 [[NSCursor arrowCursor
] set
];
284 void DropTarget::draggingExited(id
/*sender*/)
286 DropTargetEvent
dte(static_cast<OWeakObject
*>(this), 0);
288 mDragSourceSupportedActions
= DNDConstants::ACTION_NONE
;
289 mSelectedDropAction
= DNDConstants::ACTION_NONE
;
290 [[NSCursor arrowCursor
] set
];
293 BOOL
DropTarget::prepareForDragOperation()
298 BOOL
DropTarget::performDragOperation()
300 bool bSuccess
= false;
302 if (mSelectedDropAction
!= DNDConstants::ACTION_NONE
)
304 uno::Reference
<XTransferable
> xTransferable
= DragSource::g_XTransferable
;
306 if (!DragSource::g_XTransferable
.is())
308 xTransferable
= mXCurrentDragClipboard
->getContents();
311 NSRect bounds
= [mView bounds
];
312 NSPoint mouseLoc
= [NSEvent mouseLocation
];
314 id wnd
= [mView window
];
315 NSPoint dragLocation
= [mView convertPoint
:[wnd convertScreenToBase
:mouseLoc
] fromView
:nil
];
317 CocoaToVCL(dragLocation
, bounds
);
319 sal_Int32 posX
= static_cast<sal_Int32
>(dragLocation
.x
);
320 sal_Int32 posY
= static_cast<sal_Int32
>(dragLocation
.y
);
322 DropTargetDropEvent
dtde(static_cast<OWeakObject
*>(this),
328 mDragSourceSupportedActions
,
339 void DropTarget::concludeDragOperation(id
/*sender*/)
341 mDragSourceSupportedActions
= DNDConstants::ACTION_NONE
;
342 mSelectedDropAction
= DNDConstants::ACTION_NONE
;
343 mXCurrentDragClipboard
= uno::Reference
<XClipboard
>();
344 [[NSCursor arrowCursor
] set
];
347 // called from WeakComponentImplHelperX::dispose
348 // WeakComponentImplHelper calls disposing before it destroys
350 void SAL_CALL
DropTarget::disposing()
354 void SAL_CALL
DropTarget::initialize(const Sequence
< Any
>& aArguments
)
355 throw(Exception
, std::exception
)
357 if (aArguments
.getLength() < 2)
359 throw RuntimeException("DropTarget::initialize: Cannot install window event handler",
360 static_cast<OWeakObject
*>(this));
363 Any pNSView
= aArguments
[0];
366 mView
= reinterpret_cast<id
>(tmp
);
367 mpFrame
= [(SalFrameView
*)mView getSalFrame
];
369 mDropTargetHelper
= [[DropTargetHelper alloc
] initWithDropTarget
: this];
371 [(id
<DraggingDestinationHandler
>)mView registerDraggingDestinationHandler
:mDropTargetHelper
];
372 [mView registerForDraggedTypes
: DataFlavorMapper::getAllSupportedPboardTypes()];
374 id wnd
= [mView window
];
375 NSWindow
* parentWnd
= [wnd parentWindow
];
376 unsigned int topWndStyle
= (NSTitledWindowMask
| NSClosableWindowMask
| NSResizableWindowMask
);
377 unsigned int wndStyles
= [wnd styleMask
] & topWndStyle
;
379 if (parentWnd
== nil
&& (wndStyles
== topWndStyle
))
381 [wnd registerDraggingDestinationHandler
:mDropTargetHelper
];
382 [wnd registerForDraggedTypes
: [NSArray arrayWithObjects
: NSFilenamesPboardType
, nil
]];
386 void SAL_CALL
DropTarget::addDropTargetListener(const uno::Reference
<XDropTargetListener
>& dtl
)
387 throw(RuntimeException
, std::exception
)
389 rBHelper
.addListener(cppu::UnoType
<decltype(dtl
)>::get(), dtl
);
392 void SAL_CALL
DropTarget::removeDropTargetListener(const uno::Reference
<XDropTargetListener
>& dtl
)
393 throw(RuntimeException
, std::exception
)
395 rBHelper
.removeListener(cppu::UnoType
<decltype(dtl
)>::get(), dtl
);
398 sal_Bool SAL_CALL
DropTarget::isActive( ) throw(RuntimeException
, std::exception
)
403 void SAL_CALL
DropTarget::setActive(sal_Bool active
) throw(RuntimeException
, std::exception
)
408 sal_Int8 SAL_CALL
DropTarget::getDefaultActions() throw(RuntimeException
, std::exception
)
410 return mDefaultActions
;
413 void SAL_CALL
DropTarget::setDefaultActions(sal_Int8 actions
) throw(RuntimeException
, std::exception
)
415 OSL_ENSURE( actions
< 8, "No valid default actions");
416 mDefaultActions
= actions
;
419 void SAL_CALL
DropTarget::acceptDrag(sal_Int8 dragOperation
) throw (RuntimeException
, std::exception
)
421 mSelectedDropAction
= dragOperation
;
424 void SAL_CALL
DropTarget::rejectDrag() throw (RuntimeException
, std::exception
)
426 mSelectedDropAction
= DNDConstants::ACTION_NONE
;
429 void SAL_CALL
DropTarget::acceptDrop(sal_Int8 dropOperation
) throw( RuntimeException
, std::exception
)
431 mSelectedDropAction
= dropOperation
;
434 void SAL_CALL
DropTarget::rejectDrop() throw (RuntimeException
, std::exception
)
436 mSelectedDropAction
= DNDConstants::ACTION_NONE
;
439 void SAL_CALL
DropTarget::dropComplete(sal_Bool success
) throw (RuntimeException
, std::exception
)
441 // Reset the internal transferable used as shortcut in case this is
442 // an internal D&D operation
443 DragSource::g_XTransferable
= uno::Reference
<XTransferable
>();
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());
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());
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());
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());
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());
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() throw (RuntimeException
, std::exception
)
531 return dropTarget_getImplementationName();
534 sal_Bool SAL_CALL
DropTarget::supportsService( const OUString
& ServiceName
) throw (RuntimeException
, std::exception
)
536 return cppu::supportsService(this, ServiceName
);
539 Sequence
< OUString
> SAL_CALL
DropTarget::getSupportedServiceNames( ) throw (RuntimeException
, std::exception
)
541 return dropTarget_getSupportedServiceNames();
544 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */