1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: DropTarget.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
33 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
34 #include <com/sun/star/datatransfer/XTransferable.hpp>
35 #include <com/sun/star/datatransfer/dnd/DropTargetDragEnterEvent.hpp>
36 #include <rtl/unload.h>
38 #ifndef COMPHELPER_MAKESEQUENCE_HXX_INCLUDED
39 #include "comphelper/makesequence.hxx"
41 #include <cppuhelper/interfacecontainer.hxx>
43 #include "aqua_clipboard.hxx"
44 #include "DropTarget.hxx"
45 #include "DragActionConversion.hxx"
47 #include "DragSource.hxx"
49 #include <rtl/ustring.h>
53 #include <Carbon/Carbon.h>
60 using namespace com::sun::star::datatransfer
;
61 using namespace com::sun::star::datatransfer::dnd
;
62 using namespace com::sun::star::datatransfer::dnd::DNDConstants
;
63 using namespace com::sun::star::datatransfer::clipboard
;
64 using namespace com::sun::star::lang
;
65 using namespace com::sun::star::uno
;
66 using namespace comphelper
;
68 OUString
dropTarget_getImplementationName()
70 return OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.datatransfer.dnd.OleDropTarget_V1"));
74 Sequence
<OUString
> dropTarget_getSupportedServiceNames()
76 return makeSequence(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDropTarget")));
80 namespace /* private */
82 // Cocoa's coordinate system has its origin lower-left, VCL's
83 // coordinate system upper-left hence we need to transform
86 inline void CocoaToVCL(NSPoint
& rPoint
, const NSRect
& bounds
)
88 rPoint
.y
= bounds
.size
.height
- rPoint
.y
;
91 inline void CocoaToVCL(NSRect
& rRect
, const NSRect
& bounds
)
93 rRect
.origin
.y
= bounds
.size
.height
- (rRect
.origin
.y
+ rRect
.size
.height
);
98 @implementation DropTargetHelper
101 -(DropTargetHelper
*)initWithDropTarget
:(DropTarget
*)pdt
114 -(NSDragOperation
)draggingEntered
:(id
<NSDraggingInfo
>)sender
116 return mDropTarget
->draggingEntered(sender
);
120 -(NSDragOperation
)draggingUpdated
:(id
<NSDraggingInfo
>)sender
122 return mDropTarget
->draggingUpdated(sender
);
126 -(void)draggingExited
:(id
<NSDraggingInfo
>)sender
128 mDropTarget
->draggingExited(sender
);
132 -(MacOSBOOL
)prepareForDragOperation
:(id
<NSDraggingInfo
>)sender
134 return mDropTarget
->prepareForDragOperation(sender
);
138 -(MacOSBOOL
)performDragOperation
:(id
<NSDraggingInfo
>)sender
140 return mDropTarget
->performDragOperation(sender
);
144 -(void)concludeDragOperation
:(id
<NSDraggingInfo
>)sender
146 mDropTarget
->concludeDragOperation(sender
);
153 DropTarget::DropTarget() :
154 WeakComponentImplHelper5
<XInitialization
, XDropTarget
, XDropTargetDragContext
, XDropTargetDropContext
, XServiceInfo
>(m_aMutex
),
155 mDropTargetHelper(nil
),
157 mDragSourceSupportedActions(DNDConstants::ACTION_NONE
),
158 mSelectedDropAction(DNDConstants::ACTION_NONE
),
159 mDefaultActions(DNDConstants::ACTION_COPY_OR_MOVE
| DNDConstants::ACTION_LINK
| DNDConstants::ACTION_DEFAULT
)
161 mDataFlavorMapper
= DataFlavorMapperPtr_t(new DataFlavorMapper());
165 DropTarget::~DropTarget()
167 [(id
<DraggingDestinationHandler
>)mView unregisterDraggingDestinationHandler
:mDropTargetHelper
];
168 [mDropTargetHelper release
];
172 sal_Int8
DropTarget::determineDropAction(sal_Int8 dropActions
, id sender
) const
174 sal_Int8 dropAct
= dropActions
;
175 bool srcAndDestEqual
= false;
177 if ([sender draggingSource
] != nil
)
180 NSView
* destView
= [[sender draggingDestinationWindow
] contentView
];
181 srcAndDestEqual
= (DragSource::g_DragSourceView
== destView
);
184 // If ACTION_DEFAULT is set this means NSDragOperationGeneric
185 // has been set and we map this to ACTION_MOVE or ACTION_COPY
186 // depending on whether or not source and dest are equal,
187 // this hopefully satisfies all parties
188 if( (dropActions
== DNDConstants::ACTION_DEFAULT
)
189 || ((dropActions
== mDragSourceSupportedActions
)
190 && !(~mDragSourceSupportedActions
& DNDConstants::ACTION_COPY_OR_MOVE
) ) )
192 dropAct
= srcAndDestEqual
? DNDConstants::ACTION_MOVE
:
193 DNDConstants::ACTION_COPY
;
195 // if more than one drop actions have been specified
196 // set ACTION_DEFAULT in order to let the drop target
197 // decide which one to use
198 else if (dropActions
!= DNDConstants::ACTION_NONE
&&
199 dropActions
!= DNDConstants::ACTION_MOVE
&&
200 dropActions
!= DNDConstants::ACTION_COPY
&&
201 dropActions
!= DNDConstants::ACTION_LINK
)
205 dropAct
= dropActions
;
207 else // source and destination are different
209 if (dropActions
& DNDConstants::ACTION_COPY
)
210 dropAct
= DNDConstants::ACTION_COPY
;
211 else if (dropActions
& DNDConstants::ACTION_MOVE
)
212 dropAct
= DNDConstants::ACTION_MOVE
;
213 else if (dropActions
& DNDConstants::ACTION_LINK
)
214 dropAct
= DNDConstants::ACTION_LINK
;
217 dropAct
|= DNDConstants::ACTION_DEFAULT
;
224 NSDragOperation
DropTarget::draggingEntered(id sender
)
226 // Initially when DnD will be started no modifier key can be pressed yet
227 // thus we are getting all actions that the drag source supports, we save
228 // this value because later the system masks the drag source actions if
229 // a modifier key will be pressed
230 mDragSourceSupportedActions
= SystemToOfficeDragActions([sender draggingSourceOperationMask
]);
232 // Only if the drop target is really interessted in the drag actions
233 // supported by the source
234 if (mDragSourceSupportedActions
& mDefaultActions
)
236 sal_Int8 currentAction
= determineDropAction(mDragSourceSupportedActions
, sender
);
238 NSRect bounds
= [mView bounds
];
239 NSPoint dragLocation
= [sender draggedImageLocation
];
241 CocoaToVCL(dragLocation
, bounds
);
243 sal_Int32 posX
= static_cast<sal_Int32
>(dragLocation
.x
);
244 sal_Int32 posY
= static_cast<sal_Int32
>(dragLocation
.y
);
246 NSPasteboard
* dragPboard
= [sender draggingPasteboard
];
247 mXCurrentDragClipboard
= new AquaClipboard(dragPboard
, false);
249 Reference
<XTransferable
> xTransferable
= DragSource::g_XTransferable
.is() ?
250 DragSource::g_XTransferable
: mXCurrentDragClipboard
->getContents();
252 DropTargetDragEnterEvent
dtdee(static_cast<OWeakObject
*>(this),
258 mDragSourceSupportedActions
,
259 xTransferable
->getTransferDataFlavors());
261 fire_dragEnter(dtdee
);
264 return OfficeToSystemDragActions(mSelectedDropAction
);
268 NSDragOperation
DropTarget::draggingUpdated(id sender
)
270 sal_Int8 currentDragSourceActions
=
271 SystemToOfficeDragActions([sender draggingSourceOperationMask
]);
272 NSDragOperation dragOp
= NSDragOperationNone
;
274 if (currentDragSourceActions
& mDefaultActions
)
276 sal_Int8 currentAction
= determineDropAction(currentDragSourceActions
, sender
);
277 NSRect bounds
= [mView bounds
];
278 NSPoint dragLocation
= [sender draggedImageLocation
];
280 CocoaToVCL(dragLocation
, bounds
);
282 sal_Int32 posX
= static_cast<sal_Int32
>(dragLocation
.x
);
283 sal_Int32 posY
= static_cast<sal_Int32
>(dragLocation
.y
);
285 DropTargetDragEvent
dtde(static_cast<OWeakObject
*>(this),
291 mDragSourceSupportedActions
);
295 // drag over callbacks likely have rendered something
296 [mView setNeedsDisplay
: TRUE
];
298 dragOp
= OfficeToSystemDragActions(mSelectedDropAction
);
300 //NSLog(@"Drag update: Source actions: %x proposed action %x selected action %x", mDragSourceSupportedActions, currentAction, mSelectedDropAction);
303 // Weird but it appears as if there is no method in Cocoa
304 // to create a kThemeCopyArrowCursor hence we have to use
306 if (dragOp
== NSDragOperationNone
)
307 SetThemeCursor(kThemeNotAllowedCursor
);
308 else if (dragOp
== NSDragOperationCopy
)
309 SetThemeCursor(kThemeCopyArrowCursor
);
311 SetThemeCursor(kThemeArrowCursor
);
317 void DropTarget::draggingExited(id sender
)
319 DropTargetEvent
dte(static_cast<OWeakObject
*>(this), 0);
321 mDragSourceSupportedActions
= DNDConstants::ACTION_NONE
;
322 mSelectedDropAction
= DNDConstants::ACTION_NONE
;
323 SetThemeCursor(kThemeArrowCursor
);
327 MacOSBOOL
DropTarget::prepareForDragOperation(id sender
)
333 MacOSBOOL
DropTarget::performDragOperation(id sender
)
335 bool bSuccess
= false;
337 if (mSelectedDropAction
!= DNDConstants::ACTION_NONE
)
339 Reference
<XTransferable
> xTransferable
= DragSource::g_XTransferable
;
341 if (!DragSource::g_XTransferable
.is())
343 xTransferable
= mXCurrentDragClipboard
->getContents();
346 NSRect bounds
= [mView bounds
];
347 NSPoint dragLocation
= [sender draggedImageLocation
];
349 CocoaToVCL(dragLocation
, bounds
);
351 sal_Int32 posX
= static_cast<sal_Int32
>(dragLocation
.x
);
352 sal_Int32 posY
= static_cast<sal_Int32
>(dragLocation
.y
);
354 DropTargetDropEvent
dtde(static_cast<OWeakObject
*>(this),
360 mDragSourceSupportedActions
,
372 void DropTarget::concludeDragOperation(id sender
)
374 mDragSourceSupportedActions
= DNDConstants::ACTION_NONE
;
375 mSelectedDropAction
= DNDConstants::ACTION_NONE
;
376 mXCurrentDragClipboard
= Reference
<XClipboard
>();
377 SetThemeCursor(kThemeArrowCursor
);
381 // called from WeakComponentImplHelperX::dispose
382 // WeakComponentImplHelper calls disposing before it destroys
384 void SAL_CALL
DropTarget::disposing()
389 void SAL_CALL
DropTarget::initialize(const Sequence
< Any
>& aArguments
)
392 if (aArguments
.getLength() < 2)
394 throw RuntimeException(OUString(RTL_CONSTASCII_USTRINGPARAM("DropTarget::initialize: Cannot install window event handler")),
395 static_cast<OWeakObject
*>(this));
398 Any pNSView
= aArguments
[0];
403 mDropTargetHelper
= [[DropTargetHelper alloc
] initWithDropTarget
: this];
405 [(id
<DraggingDestinationHandler
>)mView registerDraggingDestinationHandler
:mDropTargetHelper
];
406 [mView registerForDraggedTypes
: mDataFlavorMapper
->getAllSupportedPboardTypes()];
408 id wnd
= [mView window
];
409 NSWindow
* parentWnd
= [wnd parentWindow
];
410 unsigned int topWndStyle
= (NSTitledWindowMask
| NSClosableWindowMask
| NSResizableWindowMask
);
411 unsigned int wndStyles
= [wnd styleMask
] & topWndStyle
;
413 if (parentWnd
== nil
&& (wndStyles
== topWndStyle
))
415 [wnd registerDraggingDestinationHandler
:mDropTargetHelper
];
416 [wnd registerForDraggedTypes
: [NSArray arrayWithObjects
: NSFilenamesPboardType
, nil
]];
421 void SAL_CALL
DropTarget::addDropTargetListener(const Reference
<XDropTargetListener
>& dtl
)
422 throw(RuntimeException
)
424 rBHelper
.addListener(::getCppuType(&dtl
), dtl
);
428 void SAL_CALL
DropTarget::removeDropTargetListener(const Reference
<XDropTargetListener
>& dtl
)
429 throw(RuntimeException
)
431 rBHelper
.removeListener(::getCppuType(&dtl
), dtl
);
435 sal_Bool SAL_CALL
DropTarget::isActive( ) throw(RuntimeException
)
441 void SAL_CALL
DropTarget::setActive(sal_Bool active
) throw(RuntimeException
)
447 sal_Int8 SAL_CALL
DropTarget::getDefaultActions() throw(RuntimeException
)
449 return mDefaultActions
;
453 void SAL_CALL
DropTarget::setDefaultActions(sal_Int8 actions
) throw(RuntimeException
)
455 OSL_ENSURE( actions
< 8, "No valid default actions");
456 mDefaultActions
= actions
;
460 // XDropTargetDragContext
462 void SAL_CALL
DropTarget::acceptDrag(sal_Int8 dragOperation
) throw (RuntimeException
)
464 mSelectedDropAction
= dragOperation
;
468 void SAL_CALL
DropTarget::rejectDrag() throw (RuntimeException
)
470 mSelectedDropAction
= DNDConstants::ACTION_NONE
;
474 //XDropTargetDropContext
476 void SAL_CALL
DropTarget::acceptDrop(sal_Int8 dropOperation
) throw( RuntimeException
)
478 mSelectedDropAction
= dropOperation
;
482 void SAL_CALL
DropTarget::rejectDrop() throw (RuntimeException
)
484 mSelectedDropAction
= DNDConstants::ACTION_NONE
;
488 void SAL_CALL
DropTarget::dropComplete(sal_Bool success
) throw (RuntimeException
)
490 // Reset the internal transferable used as shortcut in case this is
491 // an internal D&D operation
492 DragSource::g_XTransferable
= Reference
<XTransferable
>();
493 DragSource::g_DropSuccessSet
= true;
494 DragSource::g_DropSuccess
= success
;
498 void DropTarget::fire_drop( const DropTargetDropEvent
& dte
)
500 OInterfaceContainerHelper
* pContainer
= rBHelper
.getContainer( getCppuType( (Reference
<XDropTargetListener
>* )0 ) );
503 OInterfaceIteratorHelper
iter( *pContainer
);
504 while( iter
.hasMoreElements())
506 Reference
<XDropTargetListener
> listener( static_cast<XDropTargetListener
*>( iter
.next()));
508 try { listener
->drop( dte
); }
509 catch(RuntimeException
&) {}
515 void DropTarget::fire_dragEnter(const DropTargetDragEnterEvent
& e
)
517 OInterfaceContainerHelper
* pContainer
= rBHelper
.getContainer( getCppuType( (Reference
<XDropTargetListener
>* )0 ) );
520 OInterfaceIteratorHelper
iter( *pContainer
);
521 while( iter
.hasMoreElements())
523 Reference
<XDropTargetListener
> listener( static_cast<XDropTargetListener
*>( iter
.next()));
525 try { listener
->dragEnter( e
); }
526 catch (RuntimeException
&) {}
532 void DropTarget::fire_dragExit(const DropTargetEvent
& dte
)
534 OInterfaceContainerHelper
* pContainer
= rBHelper
.getContainer( getCppuType( (Reference
<XDropTargetListener
>* )0 ) );
538 OInterfaceIteratorHelper
iter( *pContainer
);
539 while( iter
.hasMoreElements())
541 Reference
<XDropTargetListener
> listener( static_cast<XDropTargetListener
*>( iter
.next()));
543 try { listener
->dragExit( dte
); }
544 catch (RuntimeException
&) {}
550 void DropTarget::fire_dragOver(const DropTargetDragEvent
& dtde
)
552 OInterfaceContainerHelper
* pContainer
= rBHelper
.getContainer( getCppuType( (Reference
<XDropTargetListener
>* )0 ) );
555 OInterfaceIteratorHelper
iter( *pContainer
);
556 while( iter
.hasMoreElements())
558 Reference
<XDropTargetListener
> listener( static_cast<XDropTargetListener
*>( iter
.next()));
560 try { listener
->dragOver( dtde
); }
561 catch (RuntimeException
&) {}
567 void DropTarget::fire_dropActionChanged(const DropTargetDragEvent
& dtde
)
569 OInterfaceContainerHelper
* pContainer
= rBHelper
.getContainer( getCppuType( (Reference
<XDropTargetListener
>* )0 ) );
572 OInterfaceIteratorHelper
iter( *pContainer
);
573 while( iter
.hasMoreElements())
575 Reference
<XDropTargetListener
> listener( static_cast<XDropTargetListener
*>( iter
.next()));
577 try { listener
->dropActionChanged( dtde
); }
578 catch (RuntimeException
&) {}
586 OUString SAL_CALL
DropTarget::getImplementationName() throw (RuntimeException
)
588 return dropTarget_getImplementationName();
592 sal_Bool SAL_CALL
DropTarget::supportsService( const OUString
& ServiceName
) throw (RuntimeException
)
594 return ServiceName
.equals(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDropTarget")));
598 Sequence
< OUString
> SAL_CALL
DropTarget::getSupportedServiceNames( ) throw (RuntimeException
)
600 return dropTarget_getSupportedServiceNames();