Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / vcl / osx / DragSource.cxx
blob1a50d4fbc3dbd56086a96ad51e62da6d26593e39
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/datatransfer/dnd/DNDConstants.hpp>
21 #include <com/sun/star/datatransfer/XTransferable.hpp>
22 #include <com/sun/star/awt/MouseButton.hpp>
24 #include "rtl/ustring.hxx"
26 #include <cppuhelper/supportsservice.hxx>
28 #include "DragSource.hxx"
29 #include "DragSourceContext.hxx"
30 #include "clipboard.hxx"
31 #include "DragActionConversion.hxx"
33 #include "osx/salframe.h"
35 #include <cassert>
37 using namespace cppu;
38 using namespace osl;
39 using namespace com::sun::star;
40 using namespace com::sun::star::datatransfer;
41 using namespace com::sun::star::datatransfer::clipboard;
42 using namespace com::sun::star::datatransfer::dnd;
43 using namespace com::sun::star::datatransfer::dnd::DNDConstants;
44 using namespace com::sun::star::uno;
45 using namespace com::sun::star::awt::MouseButton;
46 using namespace com::sun::star::awt;
47 using namespace com::sun::star::lang;
48 using namespace comphelper;
50 // For LibreOffice internal D&D we provide the Transferable without NSDragPboard
51 // interference as a shortcut, see tdf#100097 for how dbaccess depends on this
52 uno::Reference<XTransferable> DragSource::g_XTransferable;
53 NSView* DragSource::g_DragSourceView = nil;
54 bool DragSource::g_DropSuccessSet = false;
55 bool DragSource::g_DropSuccess = false;
57 OUString dragSource_getImplementationName()
59 return OUString("com.sun.star.comp.datatransfer.dnd.OleDragSource_V1");
62 Sequence<OUString> dragSource_getSupportedServiceNames()
64 return { OUString("com.sun.star.datatransfer.dnd.OleDragSource") };
67 @implementation DragSourceHelper;
69 -(DragSourceHelper*)initWithDragSource: (DragSource*) pds
71 self = [super init];
73 if (self)
75 mDragSource = pds;
78 return self;
81 -(void)mouseDown: (NSEvent*)theEvent
83 mDragSource->saveMouseEvent(theEvent);
86 -(void)mouseDragged: (NSEvent*)theEvent
88 mDragSource->saveMouseEvent(theEvent);
91 -(unsigned int)draggingSourceOperationMaskForLocal: (BOOL)isLocal
93 return mDragSource->getSupportedDragOperations(isLocal);
96 -(void)draggedImage:(NSImage*)anImage beganAt:(NSPoint)aPoint
98 (void)anImage;
99 (void)aPoint;
100 DragSourceDragEvent dsde(static_cast<OWeakObject*>(mDragSource),
101 new DragSourceContext,
102 mDragSource,
103 DNDConstants::ACTION_COPY,
104 DNDConstants::ACTION_COPY);
106 mDragSource->mXDragSrcListener->dragEnter(dsde);
109 -(void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation
111 (void)anImage;
112 (void)aPoint;
113 // an internal drop can accept the drop but fail with dropComplete( false )
114 // this is different than the Cocoa API
115 bool bDropSuccess = operation != NSDragOperationNone;
116 if( DragSource::g_DropSuccessSet )
117 bDropSuccess = DragSource::g_DropSuccess;
119 DragSourceDropEvent dsde(static_cast<OWeakObject*>(mDragSource),
120 new DragSourceContext,
121 static_cast< XDragSource* >(mDragSource),
122 SystemToOfficeDragActions(operation),
123 bDropSuccess );
125 mDragSource->mXDragSrcListener->dragDropEnd(dsde);
126 mDragSource->mXDragSrcListener.clear();
129 -(void)draggedImage:(NSImage *)draggedImage movedTo:(NSPoint)screenPoint
131 (void)draggedImage;
132 (void)screenPoint;
133 DragSourceDragEvent dsde(static_cast<OWeakObject*>(mDragSource),
134 new DragSourceContext,
135 mDragSource,
136 DNDConstants::ACTION_COPY,
137 DNDConstants::ACTION_COPY);
139 mDragSource->mXDragSrcListener->dragOver(dsde);
142 @end
144 DragSource::DragSource():
145 WeakComponentImplHelper<XDragSource, XInitialization, XServiceInfo>(m_aMutex),
146 mView(nullptr),
147 mpFrame(nullptr),
148 mLastMouseEventBeforeStartDrag(nil),
149 m_MouseButton(0)
153 DragSource::~DragSource()
155 if( mpFrame && AquaSalFrame::isAlive( mpFrame ) )
156 [(id <MouseEventListener>)mView unregisterMouseEventListener: mDragSourceHelper];
157 [mDragSourceHelper release];
160 void SAL_CALL DragSource::initialize(const Sequence< Any >& aArguments)
162 if (aArguments.getLength() < 2)
164 throw Exception("DragSource::initialize: Not enough parameter.",
165 static_cast<OWeakObject*>(this));
168 Any pNSView = aArguments[1];
169 sal_uInt64 tmp = 0;
170 pNSView >>= tmp;
171 mView = reinterpret_cast<NSView*>(tmp);
173 /* All SalFrameView the base class for all VCL system views inherits from
174 NSView in order to get mouse and other events. This is the only way to
175 get these events. In order to start a drag operation we need to provide
176 the mouse event which was the trigger. SalFrameView therefore implements
177 a hook mechanism so that we can get mouse events for our purpose.
179 if (![mView respondsToSelector: @selector(registerMouseEventListener:)] ||
180 ![mView respondsToSelector: @selector(unregisterMouseEventListener:)])
182 throw Exception("DragSource::initialize: Provided view doesn't support mouse listener",
183 static_cast<OWeakObject*>(this));
185 NSWindow* pWin = [mView window];
186 if( ! pWin || ![pWin respondsToSelector: @selector(getSalFrame)] )
188 throw Exception("DragSource::initialize: Provided view is not attached to a vcl frame",
189 static_cast<OWeakObject*>(this));
191 mpFrame = reinterpret_cast<AquaSalFrame*>([pWin performSelector: @selector(getSalFrame)]);
193 mDragSourceHelper = [[DragSourceHelper alloc] initWithDragSource: this];
195 if (mDragSourceHelper == nil)
197 throw Exception("DragSource::initialize: Cannot initialize DragSource",
198 static_cast<OWeakObject*>(this));
201 [(id <MouseEventListener>)mView registerMouseEventListener: mDragSourceHelper];
204 sal_Bool SAL_CALL DragSource::isDragImageSupported( )
206 return true;
209 sal_Int32 SAL_CALL DragSource::getDefaultCursor( sal_Int8 /*dragAction*/ )
211 return 0;
214 void SAL_CALL DragSource::startDrag(const DragGestureEvent& trigger,
215 sal_Int8 sourceActions,
216 sal_Int32 /*cursor*/,
217 sal_Int32 /*image*/,
218 const uno::Reference<XTransferable >& transferable,
219 const uno::Reference<XDragSourceListener >& listener )
221 MutexGuard guard(m_aMutex);
223 assert(listener.is() && "DragSource::startDrag: No XDragSourceListener provided\n");
224 assert(transferable.is() && "DragSource::startDrag: No transferable provided\n");
226 trigger.Event >>= mMouseEvent;
227 m_MouseButton= mMouseEvent.Buttons;
228 mXDragSrcListener = listener;
229 mXCurrentContext = static_cast<XDragSourceContext*>(new DragSourceContext);
230 rtl::Reference<AquaClipboard> clipb(new AquaClipboard(nullptr, false));
231 g_XTransferable = transferable;
232 clipb->setContents(g_XTransferable, uno::Reference<XClipboardOwner>());
233 mDragSourceActions = sourceActions;
234 g_DragSourceView = mView;
236 NSSize sz;
237 sz.width = 5;
238 sz.height = 5;
240 NSImage* dragImage;
241 dragImage = [[NSImage alloc] initWithSize: sz];
243 NSRect bounds;
244 bounds.origin = NSMakePoint(0,0);
245 bounds.size = sz;
247 [dragImage lockFocus];
248 [[NSColor blackColor] set];
249 [NSBezierPath fillRect: bounds];
250 [dragImage unlockFocus];
252 NSPoint pInWnd = [mLastMouseEventBeforeStartDrag locationInWindow];
253 NSPoint p;
254 p = [mView convertPoint: pInWnd fromView: nil];
255 p.x = p.x - sz.width/2;
256 p.y = p.y - sz.height/2;
258 // reset drop success flags
259 g_DropSuccessSet = false;
260 g_DropSuccess = false;
262 SAL_WNODEPRECATED_DECLARATIONS_PUSH
263 //TODO: 10.7 dragImage:at:offset:event:pasteboard:source:slideBack:
264 [mView dragImage: dragImage
265 at: p
266 offset: NSMakeSize(0,0)
267 event: mLastMouseEventBeforeStartDrag
268 pasteboard: clipb->getPasteboard()
269 source: mDragSourceHelper
270 slideBack: 1];
271 SAL_WNODEPRECATED_DECLARATIONS_POP
273 [dragImage release];
275 g_XTransferable.clear();
276 g_DragSourceView = nil;
278 // reset drop success flags
279 g_DropSuccessSet = false;
280 g_DropSuccess = false;
283 // In order to initiate a D&D operation we need to
284 // provide the triggering mouse event which we get
285 // from the SalFrameView that is associated with
286 // this DragSource
287 void DragSource::saveMouseEvent(NSEvent* theEvent)
289 if (mLastMouseEventBeforeStartDrag != nil)
291 [mLastMouseEventBeforeStartDrag release];
294 mLastMouseEventBeforeStartDrag = theEvent;
297 /* isLocal indicates whether or not the DnD operation is OOo
298 internal.
300 unsigned int DragSource::getSupportedDragOperations(bool isLocal) const
302 unsigned int srcActions = OfficeToSystemDragActions(mDragSourceActions);
304 if (isLocal)
306 // Support NSDragOperation generic which means we can
307 // decide which D&D operation to choose. We map
308 // NSDragOperationGenric to DNDConstants::ACTION_DEFAULT
309 // in SystemToOfficeDragActions to signal this and
310 // use it in DropTarget::determineDropAction
311 srcActions |= NSDragOperationGeneric;
313 else
315 // Mask out link and move operations on external DnD
316 srcActions &= ~(NSDragOperationMove | NSDragOperationLink);
319 return srcActions;
322 OUString SAL_CALL DragSource::getImplementationName( )
324 return dragSource_getImplementationName();
327 sal_Bool SAL_CALL DragSource::supportsService( const OUString& ServiceName )
329 return cppu::supportsService(this, ServiceName);
332 Sequence< OUString > SAL_CALL DragSource::getSupportedServiceNames()
334 return dragSource_getSupportedServiceNames();
337 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */