xref: /trunk/main/vcl/aqua/source/dtrans/DropTarget.cxx (revision 963f188bc36ea5a201e277d1528f7a830d23a1db)
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 
62 OUString dropTarget_getImplementationName()
63 {
64   return OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.datatransfer.dnd.OleDropTarget_V1"));
65 }
66 
67 
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 
80   inline void CocoaToVCL(NSPoint& rPoint, const NSRect& bounds)
81   {
82     rPoint.y = bounds.size.height - rPoint.y;
83   }
84 
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 
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 
162 DropTarget::~DropTarget()
163 {
164     if( AquaSalFrame::isAlive( mpFrame ) )
165         [(id <DraggingDestinationHandler>)mView unregisterDraggingDestinationHandler:mDropTargetHelper];
166     [mDropTargetHelper release];
167 }
168 
169 
170 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 
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 
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 
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 
328 BOOL DropTarget::prepareForDragOperation(id /*sender*/)
329 {
330     return 1;
331 }
332 
333 
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 
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.
388   void SAL_CALL DropTarget::disposing()
389   {
390   }
391 
392 
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 
426   void SAL_CALL DropTarget::addDropTargetListener(const uno::Reference<XDropTargetListener>& dtl)
427     throw(RuntimeException)
428   {
429     rBHelper.addListener(::getCppuType(&dtl), dtl);
430   }
431 
432 
433   void SAL_CALL DropTarget::removeDropTargetListener(const uno::Reference<XDropTargetListener>& dtl)
434     throw(RuntimeException)
435   {
436     rBHelper.removeListener(::getCppuType(&dtl), dtl);
437   }
438 
439 
440   sal_Bool SAL_CALL DropTarget::isActive(  ) throw(RuntimeException)
441   {
442     return mbActive;
443   }
444 
445 
446   void SAL_CALL DropTarget::setActive(sal_Bool active) throw(RuntimeException)
447   {
448     mbActive = active;
449   }
450 
451 
452   sal_Int8 SAL_CALL DropTarget::getDefaultActions() throw(RuntimeException)
453   {
454     return mDefaultActions;
455   }
456 
457 
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 
467   void SAL_CALL DropTarget::acceptDrag(sal_Int8 dragOperation) throw (RuntimeException)
468   {
469     mSelectedDropAction = dragOperation;
470   }
471 
472 
473   void SAL_CALL DropTarget::rejectDrag() throw (RuntimeException)
474   {
475     mSelectedDropAction = DNDConstants::ACTION_NONE;
476   }
477 
478 
479   //XDropTargetDropContext
480 
481   void SAL_CALL DropTarget::acceptDrop(sal_Int8 dropOperation) throw( RuntimeException)
482   {
483     mSelectedDropAction = dropOperation;
484   }
485 
486 
487   void SAL_CALL DropTarget::rejectDrop() throw (RuntimeException)
488   {
489     mSelectedDropAction = DNDConstants::ACTION_NONE;
490   }
491 
492 
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 
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 
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 
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 
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 
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 
591   OUString SAL_CALL DropTarget::getImplementationName() throw (RuntimeException)
592   {
593     return dropTarget_getImplementationName();
594   }
595 
596 
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 
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