1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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"
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
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
100 DragSourceDragEvent
dsde(static_cast<OWeakObject
*>(mDragSource
),
101 new DragSourceContext
,
103 DNDConstants::ACTION_COPY
,
104 DNDConstants::ACTION_COPY
);
106 mDragSource
->mXDragSrcListener
->dragEnter(dsde
);
109 -(void)draggedImage
:(NSImage
*)anImage endedAt
:(NSPoint
)aPoint operation
:(NSDragOperation
)operation
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
),
125 mDragSource
->mXDragSrcListener
->dragDropEnd(dsde
);
126 mDragSource
->mXDragSrcListener
.clear();
129 -(void)draggedImage
:(NSImage
*)draggedImage movedTo
:(NSPoint
)screenPoint
133 DragSourceDragEvent
dsde(static_cast<OWeakObject
*>(mDragSource
),
134 new DragSourceContext
,
136 DNDConstants::ACTION_COPY
,
137 DNDConstants::ACTION_COPY
);
139 mDragSource
->mXDragSrcListener
->dragOver(dsde
);
144 DragSource::DragSource():
145 WeakComponentImplHelper
<XDragSource
, XInitialization
, XServiceInfo
>(m_aMutex
),
148 mLastMouseEventBeforeStartDrag(nil
),
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];
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( )
209 sal_Int32 SAL_CALL
DragSource::getDefaultCursor( sal_Int8
/*dragAction*/ )
214 void SAL_CALL
DragSource::startDrag(const DragGestureEvent
& trigger
,
215 sal_Int8 sourceActions
,
216 sal_Int32
/*cursor*/,
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
;
241 dragImage
= [[NSImage alloc
] initWithSize
: sz
];
244 bounds
.origin
= NSMakePoint(0,0);
247 [dragImage lockFocus
];
248 [[NSColor blackColor
] set
];
249 [NSBezierPath fillRect
: bounds
];
250 [dragImage unlockFocus
];
252 NSPoint pInWnd
= [mLastMouseEventBeforeStartDrag locationInWindow
];
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
266 offset
: NSMakeSize(0,0)
267 event
: mLastMouseEventBeforeStartDrag
268 pasteboard
: clipb
->getPasteboard()
269 source
: mDragSourceHelper
271 SAL_WNODEPRECATED_DECLARATIONS_POP
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
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
300 unsigned int DragSource::getSupportedDragOperations(bool isLocal
) const
302 unsigned int srcActions
= OfficeToSystemDragActions(mDragSourceActions
);
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
;
315 // Mask out link and move operations on external DnD
316 srcActions
&= ~(NSDragOperationMove
| NSDragOperationLink
);
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: */