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>
24 #include "comphelper/makesequence.hxx"
25 #include <cppuhelper/interfacecontainer.hxx>
27 #include "aqua_clipboard.hxx"
28 #include "DropTarget.hxx"
29 #include "DragActionConversion.hxx"
31 #include "DragSource.hxx"
33 #include <rtl/ustring.h>
37 #include <Carbon/Carbon.h>
40 #include <aqua/salframe.h>
41 #include <aqua/salframeview.h>
45 using namespace com::sun::star::datatransfer
;
46 using namespace com::sun::star::datatransfer::dnd
;
47 using namespace com::sun::star::datatransfer::dnd::DNDConstants
;
48 using namespace com::sun::star::datatransfer::clipboard
;
49 using namespace com::sun::star::lang
;
50 using namespace com::sun::star::uno
;
51 using namespace com::sun::star
;
52 using namespace comphelper
;
55 OUString
dropTarget_getImplementationName()
57 return OUString("com.sun.star.comp.datatransfer.dnd.OleDropTarget_V1");
61 Sequence
<OUString
> dropTarget_getSupportedServiceNames()
63 return makeSequence(OUString("com.sun.star.datatransfer.dnd.OleDropTarget"));
67 namespace /* private */
69 // Cocoa's coordinate system has its origin lower-left, VCL's
70 // coordinate system upper-left hence we need to transform
73 inline void CocoaToVCL(NSPoint
& rPoint
, const NSRect
& bounds
)
75 rPoint
.y
= bounds
.size
.height
- rPoint
.y
;
80 @implementation DropTargetHelper
83 -(DropTargetHelper
*)initWithDropTarget
:(DropTarget
*)pdt
96 -(NSDragOperation
)draggingEntered
:(id
<NSDraggingInfo
>)sender
98 return mDropTarget
->draggingEntered(sender
);
102 -(NSDragOperation
)draggingUpdated
:(id
<NSDraggingInfo
>)sender
104 return mDropTarget
->draggingUpdated(sender
);
108 -(void)draggingExited
:(id
<NSDraggingInfo
>)sender
110 mDropTarget
->draggingExited(sender
);
114 -(BOOL
)prepareForDragOperation
:(id
<NSDraggingInfo
>)sender
116 return mDropTarget
->prepareForDragOperation(sender
);
120 -(BOOL
)performDragOperation
:(id
<NSDraggingInfo
>)sender
122 return mDropTarget
->performDragOperation(sender
);
126 -(void)concludeDragOperation
:(id
<NSDraggingInfo
>)sender
128 mDropTarget
->concludeDragOperation(sender
);
135 DropTarget::DropTarget() :
136 WeakComponentImplHelper5
<XInitialization
, XDropTarget
, XDropTargetDragContext
, XDropTargetDropContext
, XServiceInfo
>(m_aMutex
),
139 mDropTargetHelper(nil
),
141 mDragSourceSupportedActions(DNDConstants::ACTION_NONE
),
142 mSelectedDropAction(DNDConstants::ACTION_NONE
),
143 mDefaultActions(DNDConstants::ACTION_COPY_OR_MOVE
| DNDConstants::ACTION_LINK
| DNDConstants::ACTION_DEFAULT
)
145 mDataFlavorMapper
= DataFlavorMapperPtr_t(new DataFlavorMapper());
149 DropTarget::~DropTarget()
151 if( AquaSalFrame::isAlive( mpFrame
) )
152 [(id
<DraggingDestinationHandler
>)mView unregisterDraggingDestinationHandler
:mDropTargetHelper
];
153 [mDropTargetHelper release
];
157 sal_Int8
DropTarget::determineDropAction(sal_Int8 dropActions
, id sender
) const
159 sal_Int8 dropAct
= dropActions
;
160 bool srcAndDestEqual
= false;
162 if ([sender draggingSource
] != nil
)
165 NSView
* destView
= [[sender draggingDestinationWindow
] contentView
];
166 srcAndDestEqual
= (DragSource::g_DragSourceView
== destView
);
169 // If ACTION_DEFAULT is set this means NSDragOperationGeneric
170 // has been set and we map this to ACTION_MOVE or ACTION_COPY
171 // depending on whether or not source and dest are equal,
172 // this hopefully satisfies all parties
173 if( (dropActions
== DNDConstants::ACTION_DEFAULT
)
174 || ((dropActions
== mDragSourceSupportedActions
)
175 && !(~mDragSourceSupportedActions
& DNDConstants::ACTION_COPY_OR_MOVE
) ) )
177 dropAct
= srcAndDestEqual
? DNDConstants::ACTION_MOVE
:
178 DNDConstants::ACTION_COPY
;
180 // if more than one drop actions have been specified
181 // set ACTION_DEFAULT in order to let the drop target
182 // decide which one to use
183 else if (dropActions
!= DNDConstants::ACTION_NONE
&&
184 dropActions
!= DNDConstants::ACTION_MOVE
&&
185 dropActions
!= DNDConstants::ACTION_COPY
&&
186 dropActions
!= DNDConstants::ACTION_LINK
)
190 dropAct
= dropActions
;
192 else // source and destination are different
194 if (dropActions
& DNDConstants::ACTION_COPY
)
195 dropAct
= DNDConstants::ACTION_COPY
;
196 else if (dropActions
& DNDConstants::ACTION_MOVE
)
197 dropAct
= DNDConstants::ACTION_MOVE
;
198 else if (dropActions
& DNDConstants::ACTION_LINK
)
199 dropAct
= DNDConstants::ACTION_LINK
;
202 dropAct
|= DNDConstants::ACTION_DEFAULT
;
209 NSDragOperation
DropTarget::draggingEntered(id sender
)
211 // Initially when DnD will be started no modifier key can be pressed yet
212 // thus we are getting all actions that the drag source supports, we save
213 // this value because later the system masks the drag source actions if
214 // a modifier key will be pressed
215 mDragSourceSupportedActions
= SystemToOfficeDragActions([sender draggingSourceOperationMask
]);
217 // Only if the drop target is really interessted in the drag actions
218 // supported by the source
219 if (mDragSourceSupportedActions
& mDefaultActions
)
221 sal_Int8 currentAction
= determineDropAction(mDragSourceSupportedActions
, sender
);
223 NSRect bounds
= [mView bounds
];
224 NSPoint dragLocation
= [sender draggedImageLocation
];
226 CocoaToVCL(dragLocation
, bounds
);
228 sal_Int32 posX
= static_cast<sal_Int32
>(dragLocation
.x
);
229 sal_Int32 posY
= static_cast<sal_Int32
>(dragLocation
.y
);
231 NSPasteboard
* dragPboard
= [sender draggingPasteboard
];
232 mXCurrentDragClipboard
= new AquaClipboard(dragPboard
, false);
234 uno::Reference
<XTransferable
> xTransferable
= DragSource::g_XTransferable
.is() ?
235 DragSource::g_XTransferable
: mXCurrentDragClipboard
->getContents();
237 DropTargetDragEnterEvent
dtdee(static_cast<OWeakObject
*>(this),
243 mDragSourceSupportedActions
,
244 xTransferable
->getTransferDataFlavors());
246 fire_dragEnter(dtdee
);
249 return OfficeToSystemDragActions(mSelectedDropAction
);
253 NSDragOperation
DropTarget::draggingUpdated(id sender
)
255 sal_Int8 currentDragSourceActions
=
256 SystemToOfficeDragActions([sender draggingSourceOperationMask
]);
257 NSDragOperation dragOp
= NSDragOperationNone
;
259 if (currentDragSourceActions
& mDefaultActions
)
261 sal_Int8 currentAction
= determineDropAction(currentDragSourceActions
, sender
);
262 NSRect bounds
= [mView bounds
];
263 NSPoint dragLocation
= [sender draggedImageLocation
];
265 CocoaToVCL(dragLocation
, bounds
);
267 sal_Int32 posX
= static_cast<sal_Int32
>(dragLocation
.x
);
268 sal_Int32 posY
= static_cast<sal_Int32
>(dragLocation
.y
);
270 DropTargetDragEvent
dtde(static_cast<OWeakObject
*>(this),
276 mDragSourceSupportedActions
);
280 // drag over callbacks likely have rendered something
281 [mView setNeedsDisplay
: TRUE
];
283 dragOp
= OfficeToSystemDragActions(mSelectedDropAction
);
285 //NSLog(@"Drag update: Source actions: %x proposed action %x selected action %x", mDragSourceSupportedActions, currentAction, mSelectedDropAction);
289 // Weird but it appears as if there is no method in Cocoa
290 // to create a kThemeCopyArrowCursor hence we have to use
292 if (dragOp
== NSDragOperationNone
)
293 SetThemeCursor(kThemeNotAllowedCursor
);
294 else if (dragOp
== NSDragOperationCopy
)
295 SetThemeCursor(kThemeCopyArrowCursor
);
297 SetThemeCursor(kThemeArrowCursor
);
299 // FIXME: SetThemeCursor replacement?
305 void DropTarget::draggingExited(id
/*sender*/)
307 DropTargetEvent
dte(static_cast<OWeakObject
*>(this), 0);
309 mDragSourceSupportedActions
= DNDConstants::ACTION_NONE
;
310 mSelectedDropAction
= DNDConstants::ACTION_NONE
;
312 SetThemeCursor(kThemeArrowCursor
);
317 BOOL
DropTarget::prepareForDragOperation(id
/*sender*/)
323 BOOL
DropTarget::performDragOperation(id sender
)
325 bool bSuccess
= false;
327 if (mSelectedDropAction
!= DNDConstants::ACTION_NONE
)
329 uno::Reference
<XTransferable
> xTransferable
= DragSource::g_XTransferable
;
331 if (!DragSource::g_XTransferable
.is())
333 xTransferable
= mXCurrentDragClipboard
->getContents();
336 NSRect bounds
= [mView bounds
];
337 NSPoint dragLocation
= [sender draggedImageLocation
];
339 CocoaToVCL(dragLocation
, bounds
);
341 sal_Int32 posX
= static_cast<sal_Int32
>(dragLocation
.x
);
342 sal_Int32 posY
= static_cast<sal_Int32
>(dragLocation
.y
);
344 DropTargetDropEvent
dtde(static_cast<OWeakObject
*>(this),
350 mDragSourceSupportedActions
,
362 void DropTarget::concludeDragOperation(id
/*sender*/)
364 mDragSourceSupportedActions
= DNDConstants::ACTION_NONE
;
365 mSelectedDropAction
= DNDConstants::ACTION_NONE
;
366 mXCurrentDragClipboard
= uno::Reference
<XClipboard
>();
368 SetThemeCursor(kThemeArrowCursor
);
373 // called from WeakComponentImplHelperX::dispose
374 // WeakComponentImplHelper calls disposing before it destroys
376 void SAL_CALL
DropTarget::disposing()
381 void SAL_CALL
DropTarget::initialize(const Sequence
< Any
>& aArguments
)
384 if (aArguments
.getLength() < 2)
386 throw RuntimeException("DropTarget::initialize: Cannot install window event handler",
387 static_cast<OWeakObject
*>(this));
390 Any pNSView
= aArguments
[0];
394 mpFrame
= [(SalFrameView
*)mView getSalFrame
];
396 mDropTargetHelper
= [[DropTargetHelper alloc
] initWithDropTarget
: this];
398 [(id
<DraggingDestinationHandler
>)mView registerDraggingDestinationHandler
:mDropTargetHelper
];
399 [mView registerForDraggedTypes
: mDataFlavorMapper
->getAllSupportedPboardTypes()];
401 id wnd
= [mView window
];
402 NSWindow
* parentWnd
= [wnd parentWindow
];
403 unsigned int topWndStyle
= (NSTitledWindowMask
| NSClosableWindowMask
| NSResizableWindowMask
);
404 unsigned int wndStyles
= [wnd styleMask
] & topWndStyle
;
406 if (parentWnd
== nil
&& (wndStyles
== topWndStyle
))
408 [wnd registerDraggingDestinationHandler
:mDropTargetHelper
];
409 [wnd registerForDraggedTypes
: [NSArray arrayWithObjects
: NSFilenamesPboardType
, nil
]];
414 void SAL_CALL
DropTarget::addDropTargetListener(const uno::Reference
<XDropTargetListener
>& dtl
)
415 throw(RuntimeException
)
417 rBHelper
.addListener(::getCppuType(&dtl
), dtl
);
421 void SAL_CALL
DropTarget::removeDropTargetListener(const uno::Reference
<XDropTargetListener
>& dtl
)
422 throw(RuntimeException
)
424 rBHelper
.removeListener(::getCppuType(&dtl
), dtl
);
428 sal_Bool SAL_CALL
DropTarget::isActive( ) throw(RuntimeException
)
434 void SAL_CALL
DropTarget::setActive(sal_Bool active
) throw(RuntimeException
)
440 sal_Int8 SAL_CALL
DropTarget::getDefaultActions() throw(RuntimeException
)
442 return mDefaultActions
;
446 void SAL_CALL
DropTarget::setDefaultActions(sal_Int8 actions
) throw(RuntimeException
)
448 OSL_ENSURE( actions
< 8, "No valid default actions");
449 mDefaultActions
= actions
;
453 // XDropTargetDragContext
455 void SAL_CALL
DropTarget::acceptDrag(sal_Int8 dragOperation
) throw (RuntimeException
)
457 mSelectedDropAction
= dragOperation
;
461 void SAL_CALL
DropTarget::rejectDrag() throw (RuntimeException
)
463 mSelectedDropAction
= DNDConstants::ACTION_NONE
;
467 //XDropTargetDropContext
469 void SAL_CALL
DropTarget::acceptDrop(sal_Int8 dropOperation
) throw( RuntimeException
)
471 mSelectedDropAction
= dropOperation
;
475 void SAL_CALL
DropTarget::rejectDrop() throw (RuntimeException
)
477 mSelectedDropAction
= DNDConstants::ACTION_NONE
;
481 void SAL_CALL
DropTarget::dropComplete(sal_Bool success
) throw (RuntimeException
)
483 // Reset the internal transferable used as shortcut in case this is
484 // an internal D&D operation
485 DragSource::g_XTransferable
= uno::Reference
<XTransferable
>();
486 DragSource::g_DropSuccessSet
= true;
487 DragSource::g_DropSuccess
= success
;
491 void DropTarget::fire_drop( const DropTargetDropEvent
& dte
)
493 OInterfaceContainerHelper
* pContainer
= rBHelper
.getContainer( getCppuType( (uno::Reference
<XDropTargetListener
>* )0 ) );
496 OInterfaceIteratorHelper
iter( *pContainer
);
497 while( iter
.hasMoreElements())
499 uno::Reference
<XDropTargetListener
> listener( static_cast<XDropTargetListener
*>( iter
.next()));
501 try { listener
->drop( dte
); }
502 catch(RuntimeException
&) {}
508 void DropTarget::fire_dragEnter(const DropTargetDragEnterEvent
& e
)
510 OInterfaceContainerHelper
* pContainer
= rBHelper
.getContainer( getCppuType( (uno::Reference
<XDropTargetListener
>* )0 ) );
513 OInterfaceIteratorHelper
iter( *pContainer
);
514 while( iter
.hasMoreElements())
516 uno::Reference
<XDropTargetListener
> listener( static_cast<XDropTargetListener
*>( iter
.next()));
518 try { listener
->dragEnter( e
); }
519 catch (RuntimeException
&) {}
525 void DropTarget::fire_dragExit(const DropTargetEvent
& dte
)
527 OInterfaceContainerHelper
* pContainer
= rBHelper
.getContainer( getCppuType( (uno::Reference
<XDropTargetListener
>* )0 ) );
531 OInterfaceIteratorHelper
iter( *pContainer
);
532 while( iter
.hasMoreElements())
534 uno::Reference
<XDropTargetListener
> listener( static_cast<XDropTargetListener
*>( iter
.next()));
536 try { listener
->dragExit( dte
); }
537 catch (RuntimeException
&) {}
543 void DropTarget::fire_dragOver(const DropTargetDragEvent
& dtde
)
545 OInterfaceContainerHelper
* pContainer
= rBHelper
.getContainer( getCppuType( (uno::Reference
<XDropTargetListener
>* )0 ) );
548 OInterfaceIteratorHelper
iter( *pContainer
);
549 while( iter
.hasMoreElements())
551 uno::Reference
<XDropTargetListener
> listener( static_cast<XDropTargetListener
*>( iter
.next()));
553 try { listener
->dragOver( dtde
); }
554 catch (RuntimeException
&) {}
560 void DropTarget::fire_dropActionChanged(const DropTargetDragEvent
& dtde
)
562 OInterfaceContainerHelper
* pContainer
= rBHelper
.getContainer( getCppuType( (uno::Reference
<XDropTargetListener
>* )0 ) );
565 OInterfaceIteratorHelper
iter( *pContainer
);
566 while( iter
.hasMoreElements())
568 uno::Reference
<XDropTargetListener
> listener( static_cast<XDropTargetListener
*>( iter
.next()));
570 try { listener
->dropActionChanged( dtde
); }
571 catch (RuntimeException
&) {}
579 OUString SAL_CALL
DropTarget::getImplementationName() throw (RuntimeException
)
581 return dropTarget_getImplementationName();
585 sal_Bool SAL_CALL
DropTarget::supportsService( const OUString
& ServiceName
) throw (RuntimeException
)
587 return ServiceName
== "com.sun.star.datatransfer.dnd.OleDropTarget";
591 Sequence
< OUString
> SAL_CALL
DropTarget::getSupportedServiceNames( ) throw (RuntimeException
)
593 return dropTarget_getSupportedServiceNames();
596 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */