LibreOffice Module vcl (master) 1
transfer2.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <config_vclplug.h>
21
22#include <osl/mutex.hxx>
23#include <sot/exchange.hxx>
24#include <tools/debug.hxx>
25#include <vcl/svapp.hxx>
26#include <vcl/window.hxx>
28#include <com/sun/star/datatransfer/clipboard/SystemClipboard.hpp>
29#include <com/sun/star/datatransfer/dnd/XDropTargetDragContext.hpp>
30#include <com/sun/star/datatransfer/dnd/XDragGestureRecognizer.hpp>
31#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
32#include <com/sun/star/uno/DeploymentException.hpp>
33#include <svl/urlbmk.hxx>
34#include <vcl/transfer.hxx>
35
36#include <svdata.hxx>
37
38using namespace ::com::sun::star::uno;
39using namespace ::com::sun::star::lang;
40using namespace ::com::sun::star::io;
41using namespace ::com::sun::star::datatransfer;
43using namespace ::com::sun::star::datatransfer::dnd;
44
45
46DragSourceHelper::DragGestureListener::DragGestureListener( DragSourceHelper& rDragSourceHelper ) :
47 mrParent( rDragSourceHelper )
48{
49}
50
51
52DragSourceHelper::DragGestureListener::~DragGestureListener()
53{
54}
55
56
57void SAL_CALL DragSourceHelper::DragGestureListener::disposing( const EventObject& )
58{
59}
60
61
62void SAL_CALL DragSourceHelper::DragGestureListener::dragGestureRecognized( const DragGestureEvent& rDGE )
63{
64 const SolarMutexGuard aGuard;
65
66 const Point aPtPixel( rDGE.DragOriginX, rDGE.DragOriginY );
67 mrParent.StartDrag( rDGE.DragAction, aPtPixel );
68}
69
70
71DragSourceHelper::DragSourceHelper( vcl::Window* pWindow ) :
72 mxDragGestureRecognizer( pWindow->GetDragGestureRecognizer() )
73{
74 if( mxDragGestureRecognizer.is() )
75 {
76 mxDragGestureListener = new DragSourceHelper::DragGestureListener( *this );
77 mxDragGestureRecognizer->addDragGestureListener( mxDragGestureListener );
78 }
79}
80
81
82void DragSourceHelper::dispose()
83{
84 Reference<XDragGestureRecognizer> xTmp;
85 {
86 std::scoped_lock aGuard( maMutex );
87 xTmp = std::move(mxDragGestureRecognizer);
88 }
89 if( xTmp.is() )
90 xTmp->removeDragGestureListener( mxDragGestureListener );
91}
92
93DragSourceHelper::~DragSourceHelper()
94{
95 dispose();
96}
97
98
99void DragSourceHelper::StartDrag( sal_Int8, const Point& )
100{
101}
102
103
104DropTargetHelper::DropTargetListener::DropTargetListener( DropTargetHelper& rDropTargetHelper ) :
105 mrParent( rDropTargetHelper )
106{
107}
108
109
110DropTargetHelper::DropTargetListener::~DropTargetListener()
111{
112}
113
114
115void SAL_CALL DropTargetHelper::DropTargetListener::disposing( const EventObject& )
116{
117}
118
119
120void SAL_CALL DropTargetHelper::DropTargetListener::drop( const DropTargetDropEvent& rDTDE )
121{
122 const SolarMutexGuard aGuard;
123
124 try
125 {
126 AcceptDropEvent aAcceptEvent;
127 ExecuteDropEvent aExecuteEvt( rDTDE.DropAction & ~DNDConstants::ACTION_DEFAULT, Point( rDTDE.LocationX, rDTDE.LocationY ), rDTDE );
128
129 aExecuteEvt.mbDefault = ( ( rDTDE.DropAction & DNDConstants::ACTION_DEFAULT ) != 0 );
130
131 // in case of a default action, call ::AcceptDrop first and use the returned
132 // accepted action as the execute action in the call to ::ExecuteDrop
133 aAcceptEvent.mnAction = aExecuteEvt.mnAction;
134 aAcceptEvent.maPosPixel = aExecuteEvt.maPosPixel;
135 static_cast<DropTargetEvent&>(const_cast<DropTargetDragEvent&>( aAcceptEvent.maDragEvent )) = rDTDE;
136 const_cast<DropTargetDragEvent&>( aAcceptEvent.maDragEvent ).DropAction = rDTDE.DropAction;
137 const_cast<DropTargetDragEvent&>( aAcceptEvent.maDragEvent ).LocationX = rDTDE.LocationX;
138 const_cast<DropTargetDragEvent&>( aAcceptEvent.maDragEvent ).LocationY = rDTDE.LocationY;
139 const_cast<DropTargetDragEvent&>( aAcceptEvent.maDragEvent ).SourceActions = rDTDE.SourceActions;
140 aAcceptEvent.mbLeaving = false;
141 aAcceptEvent.mbDefault = aExecuteEvt.mbDefault;
142
143 sal_Int8 nRet = mrParent.AcceptDrop( aAcceptEvent );
144
145 if( DNDConstants::ACTION_NONE != nRet )
146 {
147 rDTDE.Context->acceptDrop( nRet );
148
149 if( aExecuteEvt.mbDefault )
150 aExecuteEvt.mnAction = nRet;
151
152 nRet = mrParent.ExecuteDrop( aExecuteEvt );
153 }
154
155 rDTDE.Context->dropComplete( DNDConstants::ACTION_NONE != nRet );
156
157 mpLastDragOverEvent.reset();
158 }
159 catch( const css::uno::Exception& )
160 {
161 }
162}
163
164
165void SAL_CALL DropTargetHelper::DropTargetListener::dragEnter( const DropTargetDragEnterEvent& rDTDEE )
166{
167 const SolarMutexGuard aGuard;
168
169 try
170 {
171 mrParent.ImplBeginDrag( rDTDEE.SupportedDataFlavors );
172 }
173 catch( const css::uno::Exception& )
174 {
175 }
176
177 dragOver( rDTDEE );
178}
179
180
181void SAL_CALL DropTargetHelper::DropTargetListener::dragOver( const DropTargetDragEvent& rDTDE )
182{
183 const SolarMutexGuard aGuard;
184
185 try
186 {
187 mpLastDragOverEvent.reset( new AcceptDropEvent( rDTDE.DropAction & ~DNDConstants::ACTION_DEFAULT, Point( rDTDE.LocationX, rDTDE.LocationY ), rDTDE ) );
188 mpLastDragOverEvent->mbDefault = ( ( rDTDE.DropAction & DNDConstants::ACTION_DEFAULT ) != 0 );
189
190 const sal_Int8 nRet = mrParent.AcceptDrop( *mpLastDragOverEvent );
191
192 if( DNDConstants::ACTION_NONE == nRet )
193 rDTDE.Context->rejectDrag();
194 else
195 rDTDE.Context->acceptDrag( nRet );
196 }
197 catch( const css::uno::Exception& )
198 {
199 }
200}
201
202
203void SAL_CALL DropTargetHelper::DropTargetListener::dragExit( const DropTargetEvent& )
204{
205 const SolarMutexGuard aGuard;
206
207 try
208 {
209 if( mpLastDragOverEvent )
210 {
211 mpLastDragOverEvent->mbLeaving = true;
212 mrParent.AcceptDrop( *mpLastDragOverEvent );
213 mpLastDragOverEvent.reset();
214 }
215
216 mrParent.ImplEndDrag();
217 }
218 catch( const css::uno::Exception& )
219 {
220 }
221}
222
223
224void SAL_CALL DropTargetHelper::DropTargetListener::dropActionChanged( const DropTargetDragEvent& )
225{
226}
227
228
229DropTargetHelper::DropTargetHelper( vcl::Window* pWindow ) :
230 mxDropTarget( pWindow->GetDropTarget() )
231{
232 ImplConstruct();
233}
234
235
236DropTargetHelper::DropTargetHelper( const Reference< XDropTarget >& rxDropTarget ) :
237 mxDropTarget( rxDropTarget )
238{
239 ImplConstruct();
240}
241
242
243void DropTargetHelper::dispose()
244{
245 Reference< XDropTarget > xTmp;
246 {
247 std::scoped_lock aGuard( maMutex );
248 xTmp = std::move(mxDropTarget);
249 }
250 if( xTmp.is() )
251 xTmp->removeDropTargetListener( mxDropTargetListener );
252}
253
254DropTargetHelper::~DropTargetHelper()
255{
256 dispose();
257}
258
259
260void DropTargetHelper::ImplConstruct()
261{
262 if( mxDropTarget.is() )
263 {
264 mxDropTargetListener = new DropTargetHelper::DropTargetListener( *this );
265 mxDropTarget->addDropTargetListener( mxDropTargetListener );
266 mxDropTarget->setActive( true );
267 }
268}
269
270
271void DropTargetHelper::ImplBeginDrag( const Sequence< DataFlavor >& rSupportedDataFlavors )
272{
273 maFormats.clear();
274 TransferableDataHelper::FillDataFlavorExVector( rSupportedDataFlavors, maFormats );
275}
276
277
278void DropTargetHelper::ImplEndDrag()
279{
280 maFormats.clear();
281}
282
283
284sal_Int8 DropTargetHelper::AcceptDrop( const AcceptDropEvent& )
285{
286 return DNDConstants::ACTION_NONE;
287}
288
289
290sal_Int8 DropTargetHelper::ExecuteDrop( const ExecuteDropEvent& )
291{
292 return DNDConstants::ACTION_NONE;
293}
294
295
296bool DropTargetHelper::IsDropFormatSupported(SotClipboardFormatId nFormat) const
297{
298 return std::any_of(maFormats.begin(), maFormats.end(),
299 [&](const DataFlavorEx& data) { return data.mnSotId == nFormat; });
300}
301
302
303// TransferDataContainer
304
305namespace {
306
307struct TDataCntnrEntry_Impl
308{
309 css::uno::Any aAny;
311};
312
313}
314
316{
317 std::vector< TDataCntnrEntry_Impl > aFmtList;
319 std::unique_ptr<INetBookmark> pBookmk;
320
322 {
323 }
324};
325
326
328 : pImpl( new TransferDataContainer_Impl )
329{
330}
331
332
334{
335}
336
337
339{
340}
341
342
344 const css::datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ )
345{
346 bool bFnd = false;
348
349 // test first the list
350 for (auto const& format : pImpl->aFmtList)
351 {
352 if( nFmtId == format.nId )
353 {
354 bFnd = SetAny( format.aAny );
355 break;
356 }
357 }
358
359 // test second the bookmark pointer
360 if( !bFnd )
361 switch( nFmtId )
362 {
363 case SotClipboardFormatId::STRING:
364 case SotClipboardFormatId::SOLK:
365 case SotClipboardFormatId::NETSCAPE_BOOKMARK:
366 case SotClipboardFormatId::FILECONTENT:
367 case SotClipboardFormatId::FILEGRPDESCRIPTOR:
368 case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
369 if( pImpl->pBookmk )
370 bFnd = SetINetBookmark( *pImpl->pBookmk, rFlavor );
371 break;
372
373 default: break;
374 }
375
376 return bFnd;
377}
378
379
381{
382 if( !pImpl->pBookmk )
383 pImpl->pBookmk.reset( new INetBookmark( rBkmk ) );
384 else
385 *pImpl->pBookmk = rBkmk;
386
387 AddFormat( SotClipboardFormatId::STRING );
388 AddFormat( SotClipboardFormatId::SOLK );
389 AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK );
390 AddFormat( SotClipboardFormatId::FILECONTENT );
391 AddFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR );
392 AddFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR );
393}
394
395
397 const char* pData, sal_uLong nLen )
398{
399 if( nLen )
400 {
401 TDataCntnrEntry_Impl aEntry;
402 aEntry.nId = nFormatId;
403
405 memcpy( aSeq.getArray(), pData, nLen );
406 aEntry.aAny <<= aSeq;
407 pImpl->aFmtList.push_back( aEntry );
408 AddFormat( nFormatId );
409 }
410}
411
412
414 const OString& rStr )
415{
416 CopyAnyData( nFormatId, rStr.getStr(), rStr.getLength() );
417}
418
419
421{
422 if( !rStr.isEmpty() )
423 {
424 TDataCntnrEntry_Impl aEntry;
425 aEntry.nId = nFmt;
426 aEntry.aAny <<= rStr;
427 pImpl->aFmtList.push_back( aEntry );
428 AddFormat( aEntry.nId );
429 }
430}
431
432
433void TransferDataContainer::CopyString( const OUString& rStr )
434{
435 CopyString( SotClipboardFormatId::STRING, rStr );
436}
437
438
440{
441 return !pImpl->aFmtList.empty() ||
442 nullptr != pImpl->pBookmk;
443}
444
445
447 vcl::Window* pWindow, sal_Int8 nDragSourceActions,
448 const Link<sal_Int8,void>& rLnk )
449{
450 pImpl->aFinishedLnk = rLnk;
451 TransferableHelper::StartDrag( pWindow, nDragSourceActions );
452}
453
454
456{
457 pImpl->aFinishedLnk.Call( nDropAction );
458}
459
460Reference<XClipboard> GetSystemClipboard()
461{
462 // On Windows, the css.datatransfer.clipboard.SystemClipboard UNO service is implemented as a
463 // single-instance service (dtrans_CWinClipboard_get_implementation in
464 // vcl/win/dtrans/WinClipboard.cxx) that needs timely disposing to join a spawned thread
465 // (done in DeInitVCL, vcl/source/app/svmain.cxx), while on other platforms it is implemented as
466 // a multi-instance service (ClipboardFactory, vcl/source/components/dtranscomp.cxx) so we
467 // should not hold on to a single instance here:
468#if defined _WIN32
470 auto const data = ImplGetSVData();
471 if (!data->m_xSystemClipboard.is())
472 {
473 try
474 {
475 data->m_xSystemClipboard = css::datatransfer::clipboard::SystemClipboard::create(
477 }
478 catch (DeploymentException const &) {}
479 }
480 return data->m_xSystemClipboard;
481#else
482 Reference<XClipboard> xClipboard;
483 try
484 {
485 xClipboard = css::datatransfer::clipboard::SystemClipboard::create(
487 }
488 catch (DeploymentException const &) {}
489 return xClipboard;
490#endif
491}
492
493Reference<XClipboard> GetSystemPrimarySelection()
494{
495 Reference<XClipboard> xSelection;
496 try
497 {
498 Reference<XComponentContext> xContext(comphelper::getProcessComponentContext());
499#if USING_X11
500 // A hack, making the primary selection available as an instance
501 // of the SystemClipboard service on X11:
502 Sequence< Any > args{ Any(OUString("PRIMARY")) };
503 xSelection.set(xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
504 "com.sun.star.datatransfer.clipboard.SystemClipboard", args, xContext), UNO_QUERY_THROW);
505#else
506 static Reference< XClipboard > s_xSelection(
507 xContext->getServiceManager()->createInstanceWithContext(
508 "com.sun.star.datatransfer.clipboard.GenericClipboard", xContext), UNO_QUERY);
509 xSelection = s_xSelection;
510#endif
511 }
512 catch (RuntimeException const &) {}
513 return xSelection;
514}
515
516/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
BaseContainerNodeSharedPtr & mrParent
static SotClipboardFormatId GetFormat(const css::datatransfer::DataFlavor &rFlavor)
void StartDrag(vcl::Window *pWindow, sal_Int8 nDragSourceActions, const Link< sal_Int8, void > &rCallback)
Definition: transfer2.cxx:446
virtual ~TransferDataContainer() override
Definition: transfer2.cxx:333
bool HasAnyData() const
Definition: transfer2.cxx:439
void CopyAnyData(SotClipboardFormatId nFormatId, const char *pData, sal_uLong nLen)
Definition: transfer2.cxx:396
void CopyINetBookmark(const INetBookmark &rBkmk)
Definition: transfer2.cxx:380
virtual void DragFinished(sal_Int8 nDropAction) override
Definition: transfer2.cxx:455
virtual bool GetData(const css::datatransfer::DataFlavor &rFlavor, const OUString &rDestDoc) override
Definition: transfer2.cxx:343
std::unique_ptr< TransferDataContainer_Impl > pImpl
Definition: transfer.hxx:484
virtual void AddSupportedFormats() override
Definition: transfer2.cxx:338
void CopyString(const OUString &rStr)
Definition: transfer2.cxx:433
void CopyByteString(SotClipboardFormatId nFormatId, const OString &rStr)
Definition: transfer2.cxx:413
static void FillDataFlavorExVector(const css::uno::Sequence< css::datatransfer::DataFlavor > &rDataFlavorSeq, DataFlavorExVector &rDataFlavorExVector)
Definition: transfer.cxx:1168
void StartDrag(vcl::Window *pWindow, sal_Int8 nDragSourceActions)
Definition: transfer.cxx:946
bool SetAny(const css::uno::Any &rAny)
Definition: transfer.cxx:626
bool SetINetBookmark(const INetBookmark &rBmk, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:741
void AddFormat(SotClipboardFormatId nFormat)
Definition: transfer.cxx:529
#define DBG_TESTSOLARMUTEX()
SotClipboardFormatId
Sequence< sal_Int8 > aSeq
std::unique_ptr< sal_Int32[]> pData
Reference< XComponentContext > getProcessComponentContext()
args
void dispose()
sal_Int16 nId
sal_uIntPtr sal_uLong
sal_Int8 mnAction
Definition: transfer.hxx:95
const css::datatransfer::dnd::DropTargetDragEvent maDragEvent
Definition: transfer.hxx:94
Point maPosPixel
Definition: transfer.hxx:93
std::vector< TDataCntnrEntry_Impl > aFmtList
Definition: transfer2.cxx:317
std::unique_ptr< INetBookmark > pBookmk
Definition: transfer2.cxx:319
Link< sal_Int8, void > aFinishedLnk
Definition: transfer2.cxx:318
ImplSVData * ImplGetSVData()
Definition: svdata.cxx:76
Reference< XClipboard > GetSystemPrimarySelection()
Definition: transfer2.cxx:493
Reference< XClipboard > GetSystemClipboard()
Definition: transfer2.cxx:460
signed char sal_Int8