Coverage Report

Created: 2026-05-16 09:25

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