1
0
Fork 0
libreoffice/vcl/source/treelist/transfer2.cxx
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

528 lines
14 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <config_vclplug.h>
#include <osl/mutex.hxx>
#include <sot/exchange.hxx>
#include <tools/debug.hxx>
#include <vcl/svapp.hxx>
#include <vcl/window.hxx>
#include <comphelper/lok.hxx>
#include <comphelper/processfactory.hxx>
#include <com/sun/star/datatransfer/clipboard/LokClipboard.hpp>
#include <com/sun/star/datatransfer/clipboard/SystemClipboard.hpp>
#include <com/sun/star/datatransfer/dnd/XDropTargetDragContext.hpp>
#include <com/sun/star/datatransfer/dnd/XDragGestureRecognizer.hpp>
#include <com/sun/star/datatransfer/dnd/XDropTarget.hpp>
#include <com/sun/star/uno/DeploymentException.hpp>
#include <svl/urlbmk.hxx>
#include <vcl/transfer.hxx>
#include <svdata.hxx>
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::io;
using namespace ::com::sun::star::datatransfer;
using namespace ::com::sun::star::datatransfer::clipboard;
using namespace ::com::sun::star::datatransfer::dnd;
DragSourceHelper::DragGestureListener::DragGestureListener( DragSourceHelper& rDragSourceHelper ) :
mrParent( rDragSourceHelper )
{
}
DragSourceHelper::DragGestureListener::~DragGestureListener()
{
}
void SAL_CALL DragSourceHelper::DragGestureListener::disposing( const EventObject& )
{
}
void SAL_CALL DragSourceHelper::DragGestureListener::dragGestureRecognized( const DragGestureEvent& rDGE )
{
const SolarMutexGuard aGuard;
const Point aPtPixel( rDGE.DragOriginX, rDGE.DragOriginY );
mrParent.StartDrag( rDGE.DragAction, aPtPixel );
}
DragSourceHelper::DragSourceHelper( vcl::Window* pWindow ) :
mxDragGestureRecognizer( pWindow->GetDragGestureRecognizer() )
{
if( mxDragGestureRecognizer.is() )
{
mxDragGestureListener = new DragSourceHelper::DragGestureListener( *this );
mxDragGestureRecognizer->addDragGestureListener( mxDragGestureListener );
}
}
void DragSourceHelper::dispose()
{
Reference<XDragGestureRecognizer> xTmp;
{
std::scoped_lock aGuard( maMutex );
xTmp = std::move(mxDragGestureRecognizer);
}
if( xTmp.is() )
xTmp->removeDragGestureListener( mxDragGestureListener );
}
DragSourceHelper::~DragSourceHelper()
{
dispose();
}
void DragSourceHelper::StartDrag( sal_Int8, const Point& )
{
}
DropTargetHelper::DropTargetListener::DropTargetListener( DropTargetHelper& rDropTargetHelper ) :
mrParent( rDropTargetHelper )
{
}
DropTargetHelper::DropTargetListener::~DropTargetListener()
{
}
void SAL_CALL DropTargetHelper::DropTargetListener::disposing( const EventObject& )
{
}
void SAL_CALL DropTargetHelper::DropTargetListener::drop( const DropTargetDropEvent& rDTDE )
{
const SolarMutexGuard aGuard;
try
{
AcceptDropEvent aAcceptEvent;
ExecuteDropEvent aExecuteEvt( rDTDE.DropAction & ~DNDConstants::ACTION_DEFAULT, Point( rDTDE.LocationX, rDTDE.LocationY ), rDTDE );
aExecuteEvt.mbDefault = ( ( rDTDE.DropAction & DNDConstants::ACTION_DEFAULT ) != 0 );
// in case of a default action, call ::AcceptDrop first and use the returned
// accepted action as the execute action in the call to ::ExecuteDrop
aAcceptEvent.mnAction = aExecuteEvt.mnAction;
aAcceptEvent.maPosPixel = aExecuteEvt.maPosPixel;
static_cast<DropTargetEvent&>(const_cast<DropTargetDragEvent&>( aAcceptEvent.maDragEvent )) = rDTDE;
const_cast<DropTargetDragEvent&>( aAcceptEvent.maDragEvent ).DropAction = rDTDE.DropAction;
const_cast<DropTargetDragEvent&>( aAcceptEvent.maDragEvent ).LocationX = rDTDE.LocationX;
const_cast<DropTargetDragEvent&>( aAcceptEvent.maDragEvent ).LocationY = rDTDE.LocationY;
const_cast<DropTargetDragEvent&>( aAcceptEvent.maDragEvent ).SourceActions = rDTDE.SourceActions;
aAcceptEvent.mbLeaving = false;
aAcceptEvent.mbDefault = aExecuteEvt.mbDefault;
sal_Int8 nRet = mrParent.AcceptDrop( aAcceptEvent );
if( DNDConstants::ACTION_NONE != nRet )
{
rDTDE.Context->acceptDrop( nRet );
if( aExecuteEvt.mbDefault )
aExecuteEvt.mnAction = nRet;
nRet = mrParent.ExecuteDrop( aExecuteEvt );
}
rDTDE.Context->dropComplete( DNDConstants::ACTION_NONE != nRet );
mpLastDragOverEvent.reset();
}
catch( const css::uno::Exception& )
{
}
}
void SAL_CALL DropTargetHelper::DropTargetListener::dragEnter( const DropTargetDragEnterEvent& rDTDEE )
{
const SolarMutexGuard aGuard;
try
{
mrParent.ImplBeginDrag( rDTDEE.SupportedDataFlavors );
}
catch( const css::uno::Exception& )
{
}
dragOver( rDTDEE );
}
void SAL_CALL DropTargetHelper::DropTargetListener::dragOver( const DropTargetDragEvent& rDTDE )
{
const SolarMutexGuard aGuard;
try
{
mpLastDragOverEvent.reset( new AcceptDropEvent( rDTDE.DropAction & ~DNDConstants::ACTION_DEFAULT, Point( rDTDE.LocationX, rDTDE.LocationY ), rDTDE ) );
mpLastDragOverEvent->mbDefault = ( ( rDTDE.DropAction & DNDConstants::ACTION_DEFAULT ) != 0 );
const sal_Int8 nRet = mrParent.AcceptDrop( *mpLastDragOverEvent );
if( DNDConstants::ACTION_NONE == nRet )
rDTDE.Context->rejectDrag();
else
rDTDE.Context->acceptDrag( nRet );
}
catch( const css::uno::Exception& )
{
}
}
void SAL_CALL DropTargetHelper::DropTargetListener::dragExit( const DropTargetEvent& )
{
const SolarMutexGuard aGuard;
try
{
if( mpLastDragOverEvent )
{
mpLastDragOverEvent->mbLeaving = true;
mrParent.AcceptDrop( *mpLastDragOverEvent );
mpLastDragOverEvent.reset();
}
mrParent.ImplEndDrag();
}
catch( const css::uno::Exception& )
{
}
}
void SAL_CALL DropTargetHelper::DropTargetListener::dropActionChanged( const DropTargetDragEvent& )
{
}
DropTargetHelper::DropTargetHelper( vcl::Window* pWindow ) :
mxDropTarget( pWindow->GetDropTarget() )
{
ImplConstruct();
}
DropTargetHelper::DropTargetHelper( const Reference< XDropTarget >& rxDropTarget ) :
mxDropTarget( rxDropTarget )
{
ImplConstruct();
}
void DropTargetHelper::dispose()
{
Reference< XDropTarget > xTmp;
{
std::scoped_lock aGuard( maMutex );
xTmp = std::move(mxDropTarget);
}
if( xTmp.is() )
xTmp->removeDropTargetListener( mxDropTargetListener );
}
DropTargetHelper::~DropTargetHelper()
{
dispose();
}
void DropTargetHelper::ImplConstruct()
{
if( mxDropTarget.is() )
{
mxDropTargetListener = new DropTargetHelper::DropTargetListener( *this );
mxDropTarget->addDropTargetListener( mxDropTargetListener );
mxDropTarget->setActive( true );
}
}
void DropTargetHelper::ImplBeginDrag( const Sequence< DataFlavor >& rSupportedDataFlavors )
{
maFormats.clear();
TransferableDataHelper::FillDataFlavorExVector( rSupportedDataFlavors, maFormats );
}
void DropTargetHelper::ImplEndDrag()
{
maFormats.clear();
}
sal_Int8 DropTargetHelper::AcceptDrop( const AcceptDropEvent& )
{
return DNDConstants::ACTION_NONE;
}
sal_Int8 DropTargetHelper::ExecuteDrop( const ExecuteDropEvent& )
{
return DNDConstants::ACTION_NONE;
}
bool DropTargetHelper::IsDropFormatSupported(SotClipboardFormatId nFormat) const
{
return std::any_of(maFormats.begin(), maFormats.end(),
[&](const DataFlavorEx& data) { return data.mnSotId == nFormat; });
}
// TransferDataContainer
namespace {
struct TDataCntnrEntry_Impl
{
css::uno::Any aAny;
SotClipboardFormatId nId;
};
}
struct TransferDataContainer_Impl
{
std::vector< TDataCntnrEntry_Impl > aFmtList;
Link<sal_Int8,void> aFinishedLnk;
std::optional<INetBookmark> moBookmk;
TransferDataContainer_Impl()
{
}
};
TransferDataContainer::TransferDataContainer()
: pImpl( new TransferDataContainer_Impl )
{
}
TransferDataContainer::~TransferDataContainer()
{
}
void TransferDataContainer::AddSupportedFormats()
{
}
bool TransferDataContainer::GetData(
const css::datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ )
{
bool bFnd = false;
SotClipboardFormatId nFmtId = SotExchange::GetFormat( rFlavor );
// test first the list
for (auto const& format : pImpl->aFmtList)
{
if( nFmtId == format.nId )
{
bFnd = SetAny( format.aAny );
break;
}
}
// test second the bookmark pointer
if( !bFnd )
switch( nFmtId )
{
case SotClipboardFormatId::STRING:
case SotClipboardFormatId::SOLK:
case SotClipboardFormatId::NETSCAPE_BOOKMARK:
case SotClipboardFormatId::FILECONTENT:
case SotClipboardFormatId::FILEGRPDESCRIPTOR:
case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
if( pImpl->moBookmk )
bFnd = SetINetBookmark( *pImpl->moBookmk, rFlavor );
break;
default: break;
}
return bFnd;
}
void TransferDataContainer::CopyINetBookmark( const INetBookmark& rBkmk )
{
pImpl->moBookmk = rBkmk;
AddFormat( SotClipboardFormatId::STRING );
AddFormat( SotClipboardFormatId::SOLK );
AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK );
AddFormat( SotClipboardFormatId::FILECONTENT );
AddFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR );
AddFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR );
}
void TransferDataContainer::CopyAnyData( SotClipboardFormatId nFormatId,
const char* pData, sal_uLong nLen )
{
if( nLen )
{
TDataCntnrEntry_Impl aEntry;
aEntry.nId = nFormatId;
Sequence< sal_Int8 > aSeq( nLen );
memcpy( aSeq.getArray(), pData, nLen );
aEntry.aAny <<= aSeq;
pImpl->aFmtList.push_back( aEntry );
AddFormat( nFormatId );
}
}
void TransferDataContainer::CopyByteString( SotClipboardFormatId nFormatId,
const OString& rStr )
{
CopyAnyData( nFormatId, rStr.getStr(), rStr.getLength() );
}
void TransferDataContainer::CopyString( SotClipboardFormatId nFmt, const OUString& rStr )
{
if( !rStr.isEmpty() )
{
TDataCntnrEntry_Impl aEntry;
aEntry.nId = nFmt;
aEntry.aAny <<= rStr;
pImpl->aFmtList.push_back( aEntry );
AddFormat( aEntry.nId );
}
}
void TransferDataContainer::CopyString( const OUString& rStr )
{
CopyString( SotClipboardFormatId::STRING, rStr );
}
bool TransferDataContainer::HasAnyData() const
{
return !pImpl->aFmtList.empty() ||
pImpl->moBookmk.has_value();
}
void TransferDataContainer::StartDrag(
vcl::Window* pWindow, sal_Int8 nDragSourceActions,
const Link<sal_Int8,void>& rLnk )
{
pImpl->aFinishedLnk = rLnk;
TransferableHelper::StartDrag( pWindow, nDragSourceActions );
}
void TransferDataContainer::DragFinished( sal_Int8 nDropAction )
{
pImpl->aFinishedLnk.Call( nDropAction );
}
Reference<XClipboard> GetSystemClipboard()
{
// On Windows, the css.datatransfer.clipboard.SystemClipboard UNO service is implemented as a
// single-instance service (dtrans_CWinClipboard_get_implementation in
// vcl/win/dtrans/WinClipboard.cxx) that needs timely disposing to join a spawned thread
// (done in DeInitVCL, vcl/source/app/svmain.cxx), while on other platforms it is implemented as
// a multi-instance service (ClipboardFactory, vcl/source/components/dtranscomp.cxx) so we
// should not hold on to a single instance here:
#if defined _WIN32
DBG_TESTSOLARMUTEX();
auto const data = ImplGetSVData();
if (!data->m_xSystemClipboard.is())
{
try
{
data->m_xSystemClipboard = css::datatransfer::clipboard::SystemClipboard::create(
comphelper::getProcessComponentContext());
}
catch (DeploymentException const &) {}
}
return data->m_xSystemClipboard;
#else
Reference<XClipboard> xClipboard;
try
{
#ifdef IOS
if (false)
;
#else
if (comphelper::LibreOfficeKit::isActive())
{
xClipboard = css::datatransfer::clipboard::LokClipboard::create(
comphelper::getProcessComponentContext());
}
#endif
else
{
xClipboard = css::datatransfer::clipboard::SystemClipboard::create(
comphelper::getProcessComponentContext());
}
}
catch (DeploymentException const &) {}
return xClipboard;
#endif
}
Reference<XClipboard> GetSystemPrimarySelection()
{
Reference<XClipboard> xSelection;
try
{
const Reference<XComponentContext>& xContext(comphelper::getProcessComponentContext());
#if USING_X11
// A hack, making the primary selection available as an instance
// of the SystemClipboard service on X11:
Sequence< Any > args{ Any(u"PRIMARY"_ustr) };
xSelection.set(xContext->getServiceManager()->createInstanceWithArgumentsAndContext(
u"com.sun.star.datatransfer.clipboard.SystemClipboard"_ustr, args, xContext), UNO_QUERY_THROW);
#else
static Reference< XClipboard > s_xSelection(
xContext->getServiceManager()->createInstanceWithContext(
"com.sun.star.datatransfer.clipboard.GenericClipboard", xContext), UNO_QUERY);
xSelection = s_xSelection;
#endif
}
catch (RuntimeException const &) {}
return xSelection;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */