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