1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
27 #include <com/sun/star/datatransfer/XTransferable.hpp>
28 #include <com/sun/star/datatransfer/dnd/DropTargetDragEnterEvent.hpp>
29 #include <rtl/unload.h>
30
31 #ifndef COMPHELPER_MAKESEQUENCE_HXX_INCLUDED
32 #include "comphelper/makesequence.hxx"
33 #endif
34 #include <cppuhelper/interfacecontainer.hxx>
35
36 #include "aqua_clipboard.hxx"
37 #include "DropTarget.hxx"
38 #include "DragActionConversion.hxx"
39
40 #include "DragSource.hxx"
41
42 #include <rtl/ustring.h>
43 #include <stdio.h>
44
45 #include <premac.h>
46 #include <Carbon/Carbon.h>
47 #include <postmac.h>
48
49 #include <aqua/salframe.h>
50 #include <aqua/salframeview.h>
51
52 using namespace rtl;
53 using namespace cppu;
54 using namespace osl;
55 using namespace com::sun::star::datatransfer;
56 using namespace com::sun::star::datatransfer::dnd;
57 using namespace com::sun::star::datatransfer::dnd::DNDConstants;
58 using namespace com::sun::star::datatransfer::clipboard;
59 using namespace com::sun::star::lang;
60 using namespace com::sun::star::uno;
61 using namespace com::sun::star;
62 using namespace comphelper;
63
dropTarget_getImplementationName()64 OUString dropTarget_getImplementationName()
65 {
66 return OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.datatransfer.dnd.OleDropTarget_V1"));
67 }
68
69
dropTarget_getSupportedServiceNames()70 Sequence<OUString> dropTarget_getSupportedServiceNames()
71 {
72 return makeSequence(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDropTarget")));
73 }
74
75
76 namespace /* private */
77 {
78 // Cocoa's coordinate system has its origin lower-left, VCL's
79 // coordinate system upper-left hence we need to transform
80 // coordinates
81
CocoaToVCL(NSPoint & rPoint,const NSRect & bounds)82 inline void CocoaToVCL(NSPoint& rPoint, const NSRect& bounds)
83 {
84 rPoint.y = bounds.size.height - rPoint.y;
85 }
86
CocoaToVCL(NSRect & rRect,const NSRect & bounds)87 inline void CocoaToVCL(NSRect& rRect, const NSRect& bounds)
88 {
89 rRect.origin.y = bounds.size.height - (rRect.origin.y + rRect.size.height);
90 }
91 }
92
93
94 @implementation DropTargetHelper
95
96
97 -(DropTargetHelper*)initWithDropTarget:(DropTarget*)pdt
98 {
99 self = [super init];
100
101 if (self)
102 {
103 mDropTarget = pdt;
104 }
105
106 return self;
107 }
108
109
110 -(NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
111 {
112 return mDropTarget->draggingEntered(sender);
113 }
114
115
116 -(NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
117 {
118 return mDropTarget->draggingUpdated(sender);
119 }
120
121
122 -(void)draggingExited:(id <NSDraggingInfo>)sender
123 {
124 mDropTarget->draggingExited(sender);
125 }
126
127
128 -(BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
129 {
130 return mDropTarget->prepareForDragOperation(sender);
131 }
132
133
134 -(BOOL)performDragOperation:(id <NSDraggingInfo>)sender
135 {
136 (void) sender;
137 return mDropTarget->performDragOperation();
138 }
139
140
141 -(void)concludeDragOperation:(id <NSDraggingInfo>)sender
142 {
143 mDropTarget->concludeDragOperation(sender);
144 }
145
146
147 @end
148
149
DropTarget()150 DropTarget::DropTarget() :
151 WeakComponentImplHelper5<XInitialization, XDropTarget, XDropTargetDragContext, XDropTargetDropContext, XServiceInfo>(m_aMutex),
152 mView(nil),
153 mpFrame(NULL),
154 mDropTargetHelper(nil),
155 mbActive(false),
156 mDragSourceSupportedActions(DNDConstants::ACTION_NONE),
157 mSelectedDropAction(DNDConstants::ACTION_NONE),
158 mDefaultActions(DNDConstants::ACTION_COPY_OR_MOVE | DNDConstants::ACTION_LINK | DNDConstants::ACTION_DEFAULT)
159 {
160 mDataFlavorMapper = DataFlavorMapperPtr_t(new DataFlavorMapper());
161 }
162
163
~DropTarget()164 DropTarget::~DropTarget()
165 {
166 if( AquaSalFrame::isAlive( mpFrame ) )
167 [(id <DraggingDestinationHandler>)mView unregisterDraggingDestinationHandler:mDropTargetHelper];
168 [mDropTargetHelper release];
169 }
170
171
determineDropAction(sal_Int8 dropActions,id sender) const172 sal_Int8 DropTarget::determineDropAction(sal_Int8 dropActions, id sender) const
173 {
174 sal_Int8 dropAct = dropActions;
175 bool srcAndDestEqual = false;
176
177 if ([sender draggingSource] != nil)
178 {
179 // Internal DnD
180 NSView* destView = [[sender draggingDestinationWindow] contentView];
181 srcAndDestEqual = (DragSource::g_DragSourceView == destView);
182 }
183
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 ) ) )
191 {
192 dropAct = srcAndDestEqual ? DNDConstants::ACTION_MOVE :
193 DNDConstants::ACTION_COPY;
194 }
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)
202 {
203 if (srcAndDestEqual)
204 {
205 dropAct = dropActions;
206 }
207 else // source and destination are different
208 {
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;
215 }
216
217 dropAct |= DNDConstants::ACTION_DEFAULT;
218 }
219
220 return dropAct;
221 }
222
223
draggingEntered(id sender)224 NSDragOperation DropTarget::draggingEntered(id sender)
225 {
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]);
231
232 // Only if the drop target is really interessted in the drag actions
233 // supported by the source
234 if (mDragSourceSupportedActions & mDefaultActions)
235 {
236 sal_Int8 currentAction = determineDropAction(mDragSourceSupportedActions, sender);
237
238 NSRect bounds = [mView bounds];
239 NSPoint mouseLoc = [NSEvent mouseLocation];
240
241 id wnd = [mView window];
242 NSPoint dragLocation = [mView convertPoint:[wnd convertScreenToBase:mouseLoc] fromView:nil];
243
244 CocoaToVCL(dragLocation, bounds);
245
246 sal_Int32 posX = static_cast<sal_Int32>(dragLocation.x);
247 sal_Int32 posY = static_cast<sal_Int32>(dragLocation.y);
248
249 NSPasteboard* dragPboard = [sender draggingPasteboard];
250 mXCurrentDragClipboard = new AquaClipboard(dragPboard, false);
251
252 uno::Reference<XTransferable> xTransferable = DragSource::g_XTransferable.is() ?
253 DragSource::g_XTransferable : mXCurrentDragClipboard->getContents();
254
255 DropTargetDragEnterEvent dtdee(static_cast<OWeakObject*>(this),
256 0,
257 this,
258 currentAction,
259 posX,
260 posY,
261 mDragSourceSupportedActions,
262 xTransferable->getTransferDataFlavors());
263
264 fire_dragEnter(dtdee);
265 }
266
267 return OfficeToSystemDragActions(mSelectedDropAction);
268 }
269
270
draggingUpdated(id sender)271 NSDragOperation DropTarget::draggingUpdated(id sender)
272 {
273 sal_Int8 currentDragSourceActions =
274 SystemToOfficeDragActions([sender draggingSourceOperationMask]);
275 NSDragOperation dragOp = NSDragOperationNone;
276
277 if (currentDragSourceActions & mDefaultActions)
278 {
279 sal_Int8 currentAction = determineDropAction(currentDragSourceActions, sender);
280 NSRect bounds = [mView bounds];
281 NSPoint mouseLoc = [NSEvent mouseLocation];
282
283 id wnd = [mView window];
284 NSPoint dragLocation = [mView convertPoint:[wnd convertScreenToBase:mouseLoc] fromView:nil];
285
286 CocoaToVCL(dragLocation, bounds);
287
288 sal_Int32 posX = static_cast<sal_Int32>(dragLocation.x);
289 sal_Int32 posY = static_cast<sal_Int32>(dragLocation.y);
290
291 DropTargetDragEvent dtde(static_cast<OWeakObject*>(this),
292 0,
293 this,
294 currentAction,
295 posX,
296 posY,
297 mDragSourceSupportedActions);
298
299 fire_dragOver(dtde);
300
301 // drag over callbacks likely have rendered something
302 [mView setNeedsDisplay: TRUE];
303
304 dragOp = OfficeToSystemDragActions(mSelectedDropAction);
305
306 //NSLog(@"Drag update: Source actions: %x proposed action %x selected action %x", mDragSourceSupportedActions, currentAction, mSelectedDropAction);
307 }
308
309 if (dragOp == NSDragOperationNone)
310 [[NSCursor operationNotAllowedCursor] set];
311 else if (dragOp == NSDragOperationCopy)
312 [[NSCursor dragCopyCursor] set];
313 else
314 [[NSCursor arrowCursor] set];
315
316 return dragOp;
317 }
318
319
draggingExited(id)320 void DropTarget::draggingExited(id /*sender*/)
321 {
322 DropTargetEvent dte(static_cast<OWeakObject*>(this), 0);
323 fire_dragExit(dte);
324 mDragSourceSupportedActions = DNDConstants::ACTION_NONE;
325 mSelectedDropAction = DNDConstants::ACTION_NONE;
326 [[NSCursor arrowCursor] set];
327 }
328
329
prepareForDragOperation(id)330 BOOL DropTarget::prepareForDragOperation(id /*sender*/)
331 {
332 return 1;
333 }
334
335
performDragOperation()336 BOOL DropTarget::performDragOperation()
337 {
338 bool bSuccess = false;
339
340 if (mSelectedDropAction != DNDConstants::ACTION_NONE)
341 {
342 uno::Reference<XTransferable> xTransferable = DragSource::g_XTransferable;
343
344 if (!DragSource::g_XTransferable.is())
345 {
346 xTransferable = mXCurrentDragClipboard->getContents();
347 }
348
349 NSRect bounds = [mView bounds];
350 NSPoint mouseLoc = [NSEvent mouseLocation];
351
352 id wnd = [mView window];
353 NSPoint dragLocation = [mView convertPoint:[wnd convertScreenToBase:mouseLoc] fromView:nil];
354
355 CocoaToVCL(dragLocation, bounds);
356
357 sal_Int32 posX = static_cast<sal_Int32>(dragLocation.x);
358 sal_Int32 posY = static_cast<sal_Int32>(dragLocation.y);
359
360 DropTargetDropEvent dtde(static_cast<OWeakObject*>(this),
361 0,
362 this,
363 mSelectedDropAction,
364 posX,
365 posY,
366 mDragSourceSupportedActions,
367 xTransferable);
368
369 fire_drop(dtde);
370
371 bSuccess = true;
372 }
373
374 return bSuccess;
375 }
376
377
concludeDragOperation(id)378 void DropTarget::concludeDragOperation(id /*sender*/)
379 {
380 mDragSourceSupportedActions = DNDConstants::ACTION_NONE;
381 mSelectedDropAction = DNDConstants::ACTION_NONE;
382 mXCurrentDragClipboard = uno::Reference<XClipboard>();
383 [[NSCursor arrowCursor] set];
384 }
385
386
387 // called from WeakComponentImplHelperX::dispose
388 // WeakComponentImplHelper calls disposing before it destroys
389 // itself.
disposing()390 void SAL_CALL DropTarget::disposing()
391 {
392 }
393
394
initialize(const Sequence<Any> & aArguments)395 void SAL_CALL DropTarget::initialize(const Sequence< Any >& aArguments)
396 throw(Exception)
397 {
398 if (aArguments.getLength() < 2)
399 {
400 throw RuntimeException(OUString(RTL_CONSTASCII_USTRINGPARAM("DropTarget::initialize: Cannot install window event handler")),
401 static_cast<OWeakObject*>(this));
402 }
403
404 Any pNSView = aArguments[0];
405 sal_uInt64 tmp = 0;
406 pNSView >>= tmp;
407 mView = (id)tmp;
408 mpFrame = [(SalFrameView*)mView getSalFrame];
409
410 mDropTargetHelper = [[DropTargetHelper alloc] initWithDropTarget: this];
411
412 [(id <DraggingDestinationHandler>)mView registerDraggingDestinationHandler:mDropTargetHelper];
413 [mView registerForDraggedTypes: mDataFlavorMapper->getAllSupportedPboardTypes()];
414
415 id wnd = [mView window];
416 NSWindow* parentWnd = [wnd parentWindow];
417 unsigned int topWndStyle = (NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask);
418 unsigned int wndStyles = [wnd styleMask] & topWndStyle;
419
420 if (parentWnd == nil && (wndStyles == topWndStyle))
421 {
422 [wnd registerDraggingDestinationHandler:mDropTargetHelper];
423 [wnd registerForDraggedTypes: [NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
424 }
425 }
426
427
addDropTargetListener(const uno::Reference<XDropTargetListener> & dtl)428 void SAL_CALL DropTarget::addDropTargetListener(const uno::Reference<XDropTargetListener>& dtl)
429 throw(RuntimeException)
430 {
431 rBHelper.addListener(::getCppuType(&dtl), dtl);
432 }
433
434
removeDropTargetListener(const uno::Reference<XDropTargetListener> & dtl)435 void SAL_CALL DropTarget::removeDropTargetListener(const uno::Reference<XDropTargetListener>& dtl)
436 throw(RuntimeException)
437 {
438 rBHelper.removeListener(::getCppuType(&dtl), dtl);
439 }
440
441
isActive()442 sal_Bool SAL_CALL DropTarget::isActive( ) throw(RuntimeException)
443 {
444 return mbActive;
445 }
446
447
setActive(sal_Bool active)448 void SAL_CALL DropTarget::setActive(sal_Bool active) throw(RuntimeException)
449 {
450 mbActive = active;
451 }
452
453
getDefaultActions()454 sal_Int8 SAL_CALL DropTarget::getDefaultActions() throw(RuntimeException)
455 {
456 return mDefaultActions;
457 }
458
459
setDefaultActions(sal_Int8 actions)460 void SAL_CALL DropTarget::setDefaultActions(sal_Int8 actions) throw(RuntimeException)
461 {
462 OSL_ENSURE( actions < 8, "No valid default actions");
463 mDefaultActions= actions;
464 }
465
466
467 // XDropTargetDragContext
468
acceptDrag(sal_Int8 dragOperation)469 void SAL_CALL DropTarget::acceptDrag(sal_Int8 dragOperation) throw (RuntimeException)
470 {
471 mSelectedDropAction = dragOperation;
472 }
473
474
rejectDrag()475 void SAL_CALL DropTarget::rejectDrag() throw (RuntimeException)
476 {
477 mSelectedDropAction = DNDConstants::ACTION_NONE;
478 }
479
480
481 //XDropTargetDropContext
482
acceptDrop(sal_Int8 dropOperation)483 void SAL_CALL DropTarget::acceptDrop(sal_Int8 dropOperation) throw( RuntimeException)
484 {
485 mSelectedDropAction = dropOperation;
486 }
487
488
rejectDrop()489 void SAL_CALL DropTarget::rejectDrop() throw (RuntimeException)
490 {
491 mSelectedDropAction = DNDConstants::ACTION_NONE;
492 }
493
494
dropComplete(sal_Bool success)495 void SAL_CALL DropTarget::dropComplete(sal_Bool success) throw (RuntimeException)
496 {
497 // Reset the internal transferable used as shortcut in case this is
498 // an internal D&D operation
499 DragSource::g_XTransferable = uno::Reference<XTransferable>();
500 DragSource::g_DropSuccessSet = true;
501 DragSource::g_DropSuccess = success;
502 }
503
504
fire_drop(const DropTargetDropEvent & dte)505 void DropTarget::fire_drop( const DropTargetDropEvent& dte)
506 {
507 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) );
508 if( pContainer)
509 {
510 OInterfaceIteratorHelper iter( *pContainer);
511 while( iter.hasMoreElements())
512 {
513 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
514
515 try { listener->drop( dte); }
516 catch(RuntimeException&) {}
517 }
518 }
519 }
520
521
fire_dragEnter(const DropTargetDragEnterEvent & e)522 void DropTarget::fire_dragEnter(const DropTargetDragEnterEvent& e)
523 {
524 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) );
525 if( pContainer)
526 {
527 OInterfaceIteratorHelper iter( *pContainer);
528 while( iter.hasMoreElements())
529 {
530 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
531
532 try { listener->dragEnter( e); }
533 catch (RuntimeException&) {}
534 }
535 }
536 }
537
538
fire_dragExit(const DropTargetEvent & dte)539 void DropTarget::fire_dragExit(const DropTargetEvent& dte)
540 {
541 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) );
542
543 if( pContainer)
544 {
545 OInterfaceIteratorHelper iter( *pContainer);
546 while( iter.hasMoreElements())
547 {
548 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
549
550 try { listener->dragExit( dte); }
551 catch (RuntimeException&) {}
552 }
553 }
554 }
555
556
fire_dragOver(const DropTargetDragEvent & dtde)557 void DropTarget::fire_dragOver(const DropTargetDragEvent& dtde)
558 {
559 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) );
560 if( pContainer)
561 {
562 OInterfaceIteratorHelper iter( *pContainer );
563 while( iter.hasMoreElements())
564 {
565 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
566
567 try { listener->dragOver( dtde); }
568 catch (RuntimeException&) {}
569 }
570 }
571 }
572
573
fire_dropActionChanged(const DropTargetDragEvent & dtde)574 void DropTarget::fire_dropActionChanged(const DropTargetDragEvent& dtde)
575 {
576 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) );
577 if( pContainer)
578 {
579 OInterfaceIteratorHelper iter( *pContainer);
580 while( iter.hasMoreElements())
581 {
582 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
583
584 try { listener->dropActionChanged( dtde); }
585 catch (RuntimeException&) {}
586 }
587 }
588 }
589
590
591 // XServiceInfo
592
getImplementationName()593 OUString SAL_CALL DropTarget::getImplementationName() throw (RuntimeException)
594 {
595 return dropTarget_getImplementationName();
596 }
597
598
supportsService(const OUString & ServiceName)599 sal_Bool SAL_CALL DropTarget::supportsService( const OUString& ServiceName ) throw (RuntimeException)
600 {
601 return ServiceName.equals(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDropTarget")));
602 }
603
604
getSupportedServiceNames()605 Sequence< OUString > SAL_CALL DropTarget::getSupportedServiceNames( ) throw (RuntimeException)
606 {
607 return dropTarget_getSupportedServiceNames();
608 }
609
610