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 throw(Exception)
395 {
396 if (aArguments.getLength() < 2)
397 {
398 throw RuntimeException(OUString(RTL_CONSTASCII_USTRINGPARAM("DropTarget::initialize: Cannot install window event handler")),
399 static_cast<OWeakObject*>(this));
400 }
401
402 Any pNSView = aArguments[0];
403 sal_uInt64 tmp = 0;
404 pNSView >>= tmp;
405 mView = (id)tmp;
406 mpFrame = [(SalFrameView*)mView getSalFrame];
407
408 mDropTargetHelper = [[DropTargetHelper alloc] initWithDropTarget: this];
409
410 [(id <DraggingDestinationHandler>)mView registerDraggingDestinationHandler:mDropTargetHelper];
411 [mView registerForDraggedTypes: mDataFlavorMapper->getAllSupportedPboardTypes()];
412
413 id wnd = [mView window];
414 NSWindow* parentWnd = [wnd parentWindow];
415 unsigned int topWndStyle = (NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask);
416 unsigned int wndStyles = [wnd styleMask] & topWndStyle;
417
418 if (parentWnd == nil && (wndStyles == topWndStyle))
419 {
420 [wnd registerDraggingDestinationHandler:mDropTargetHelper];
421 [wnd registerForDraggedTypes: [NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
422 }
423 }
424
425
addDropTargetListener(const uno::Reference<XDropTargetListener> & dtl)426 void SAL_CALL DropTarget::addDropTargetListener(const uno::Reference<XDropTargetListener>& dtl)
427 throw(RuntimeException)
428 {
429 rBHelper.addListener(::getCppuType(&dtl), dtl);
430 }
431
432
removeDropTargetListener(const uno::Reference<XDropTargetListener> & dtl)433 void SAL_CALL DropTarget::removeDropTargetListener(const uno::Reference<XDropTargetListener>& dtl)
434 throw(RuntimeException)
435 {
436 rBHelper.removeListener(::getCppuType(&dtl), dtl);
437 }
438
439
isActive()440 sal_Bool SAL_CALL DropTarget::isActive( ) throw(RuntimeException)
441 {
442 return mbActive;
443 }
444
445
setActive(sal_Bool active)446 void SAL_CALL DropTarget::setActive(sal_Bool active) throw(RuntimeException)
447 {
448 mbActive = active;
449 }
450
451
getDefaultActions()452 sal_Int8 SAL_CALL DropTarget::getDefaultActions() throw(RuntimeException)
453 {
454 return mDefaultActions;
455 }
456
457
setDefaultActions(sal_Int8 actions)458 void SAL_CALL DropTarget::setDefaultActions(sal_Int8 actions) throw(RuntimeException)
459 {
460 OSL_ENSURE( actions < 8, "No valid default actions");
461 mDefaultActions= actions;
462 }
463
464
465 // XDropTargetDragContext
466
acceptDrag(sal_Int8 dragOperation)467 void SAL_CALL DropTarget::acceptDrag(sal_Int8 dragOperation) throw (RuntimeException)
468 {
469 mSelectedDropAction = dragOperation;
470 }
471
472
rejectDrag()473 void SAL_CALL DropTarget::rejectDrag() throw (RuntimeException)
474 {
475 mSelectedDropAction = DNDConstants::ACTION_NONE;
476 }
477
478
479 //XDropTargetDropContext
480
acceptDrop(sal_Int8 dropOperation)481 void SAL_CALL DropTarget::acceptDrop(sal_Int8 dropOperation) throw( RuntimeException)
482 {
483 mSelectedDropAction = dropOperation;
484 }
485
486
rejectDrop()487 void SAL_CALL DropTarget::rejectDrop() throw (RuntimeException)
488 {
489 mSelectedDropAction = DNDConstants::ACTION_NONE;
490 }
491
492
dropComplete(sal_Bool success)493 void SAL_CALL DropTarget::dropComplete(sal_Bool success) throw (RuntimeException)
494 {
495 // Reset the internal transferable used as shortcut in case this is
496 // an internal D&D operation
497 DragSource::g_XTransferable = uno::Reference<XTransferable>();
498 DragSource::g_DropSuccessSet = true;
499 DragSource::g_DropSuccess = success;
500 }
501
502
fire_drop(const DropTargetDropEvent & dte)503 void DropTarget::fire_drop( const DropTargetDropEvent& dte)
504 {
505 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) );
506 if( pContainer)
507 {
508 OInterfaceIteratorHelper iter( *pContainer);
509 while( iter.hasMoreElements())
510 {
511 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
512
513 try { listener->drop( dte); }
514 catch(RuntimeException&) {}
515 }
516 }
517 }
518
519
fire_dragEnter(const DropTargetDragEnterEvent & e)520 void DropTarget::fire_dragEnter(const DropTargetDragEnterEvent& e)
521 {
522 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) );
523 if( pContainer)
524 {
525 OInterfaceIteratorHelper iter( *pContainer);
526 while( iter.hasMoreElements())
527 {
528 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
529
530 try { listener->dragEnter( e); }
531 catch (RuntimeException&) {}
532 }
533 }
534 }
535
536
fire_dragExit(const DropTargetEvent & dte)537 void DropTarget::fire_dragExit(const DropTargetEvent& dte)
538 {
539 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) );
540
541 if( pContainer)
542 {
543 OInterfaceIteratorHelper iter( *pContainer);
544 while( iter.hasMoreElements())
545 {
546 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
547
548 try { listener->dragExit( dte); }
549 catch (RuntimeException&) {}
550 }
551 }
552 }
553
554
fire_dragOver(const DropTargetDragEvent & dtde)555 void DropTarget::fire_dragOver(const DropTargetDragEvent& dtde)
556 {
557 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) );
558 if( pContainer)
559 {
560 OInterfaceIteratorHelper iter( *pContainer );
561 while( iter.hasMoreElements())
562 {
563 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
564
565 try { listener->dragOver( dtde); }
566 catch (RuntimeException&) {}
567 }
568 }
569 }
570
571
fire_dropActionChanged(const DropTargetDragEvent & dtde)572 void DropTarget::fire_dropActionChanged(const DropTargetDragEvent& dtde)
573 {
574 OInterfaceContainerHelper* pContainer= rBHelper.getContainer( getCppuType( (uno::Reference<XDropTargetListener>* )0 ) );
575 if( pContainer)
576 {
577 OInterfaceIteratorHelper iter( *pContainer);
578 while( iter.hasMoreElements())
579 {
580 uno::Reference<XDropTargetListener> listener( static_cast<XDropTargetListener*>( iter.next()));
581
582 try { listener->dropActionChanged( dtde); }
583 catch (RuntimeException&) {}
584 }
585 }
586 }
587
588
589 // XServiceInfo
590
getImplementationName()591 OUString SAL_CALL DropTarget::getImplementationName() throw (RuntimeException)
592 {
593 return dropTarget_getImplementationName();
594 }
595
596
supportsService(const OUString & ServiceName)597 sal_Bool SAL_CALL DropTarget::supportsService( const OUString& ServiceName ) throw (RuntimeException)
598 {
599 return ServiceName.equals(OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.datatransfer.dnd.OleDropTarget")));
600 }
601
602
getSupportedServiceNames()603 Sequence< OUString > SAL_CALL DropTarget::getSupportedServiceNames( ) throw (RuntimeException)
604 {
605 return dropTarget_getSupportedServiceNames();
606 }
607
608 /* vim: set noet sw=4 ts=4: */
609