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