nss: upgrade to release 3.73
[LibreOffice.git] / vcl / source / treelist / transfer.cxx
bloba14da846739bcadc9da4a380b77fe014c540939b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 #ifdef _WIN32
21 #include <prewin.h>
22 #include <postwin.h>
23 #include <shlobj.h>
24 #endif
25 #include <osl/mutex.hxx>
26 #include <rtl/uri.hxx>
27 #include <sal/log.hxx>
28 #include <tools/debug.hxx>
29 #include <tools/urlobj.hxx>
30 #include <unotools/ucbstreamhelper.hxx>
31 #include <sot/exchange.hxx>
32 #include <sot/storage.hxx>
33 #include <vcl/bitmap.hxx>
34 #include <vcl/gdimtf.hxx>
35 #include <vcl/graph.hxx>
36 #include <vcl/cvtgrf.hxx>
37 #include <vcl/svapp.hxx>
38 #include <vcl/window.hxx>
39 #include <comphelper/fileformat.h>
40 #include <comphelper/processfactory.hxx>
41 #include <comphelper/servicehelper.hxx>
42 #include <comphelper/sequence.hxx>
43 #include <sot/filelist.hxx>
44 #include <cppuhelper/implbase.hxx>
46 #include <comphelper/seqstream.hxx>
47 #include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
48 #include <com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp>
49 #include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
50 #include <com/sun/star/datatransfer/MimeContentTypeFactory.hpp>
51 #include <com/sun/star/datatransfer/XMimeContentType.hpp>
52 #include <com/sun/star/datatransfer/XTransferable2.hpp>
53 #include <com/sun/star/frame/Desktop.hpp>
55 #include <svl/urlbmk.hxx>
56 #include <vcl/inetimg.hxx>
57 #include <vcl/wmf.hxx>
58 #include <vcl/imap.hxx>
59 #include <vcl/transfer.hxx>
60 #include <rtl/strbuf.hxx>
61 #include <cstdio>
62 #include <vcl/dibtools.hxx>
63 #include <vcl/pngread.hxx>
64 #include <vcl/pngwrite.hxx>
65 #include <vcl/graphicfilter.hxx>
66 #include <memory>
67 #include <utility>
69 using namespace ::com::sun::star::uno;
70 using namespace ::com::sun::star::lang;
71 using namespace ::com::sun::star::frame;
72 using namespace ::com::sun::star::io;
73 using namespace ::com::sun::star::datatransfer;
74 using namespace ::com::sun::star::datatransfer::clipboard;
75 using namespace ::com::sun::star::datatransfer::dnd;
78 #define TOD_SIG1 0x01234567
79 #define TOD_SIG2 0x89abcdef
81 SvStream& WriteTransferableObjectDescriptor( SvStream& rOStm, const TransferableObjectDescriptor& rObjDesc )
83 const sal_uInt32 nFirstPos = rOStm.Tell(), nViewAspect = rObjDesc.mnViewAspect;
84 const sal_uInt32 nSig1 = TOD_SIG1, nSig2 = TOD_SIG2;
86 rOStm.SeekRel( 4 );
87 WriteSvGlobalName( rOStm, rObjDesc.maClassName );
88 rOStm.WriteUInt32( nViewAspect );
89 rOStm.WriteInt32( rObjDesc.maSize.Width() );
90 rOStm.WriteInt32( rObjDesc.maSize.Height() );
91 rOStm.WriteInt32( rObjDesc.maDragStartPos.X() );
92 rOStm.WriteInt32( rObjDesc.maDragStartPos.Y() );
93 rOStm.WriteUniOrByteString( rObjDesc.maTypeName, osl_getThreadTextEncoding() );
94 rOStm.WriteUniOrByteString( rObjDesc.maDisplayName, osl_getThreadTextEncoding() );
95 rOStm.WriteUInt32( nSig1 ).WriteUInt32( nSig2 );
97 const sal_uInt32 nLastPos = rOStm.Tell();
99 rOStm.Seek( nFirstPos );
100 rOStm.WriteUInt32( nLastPos - nFirstPos );
101 rOStm.Seek( nLastPos );
103 return rOStm;
107 // the reading of the parameter is done using the special service css::datatransfer::MimeContentType,
108 // a similar approach should be implemented for creation of the mimetype string;
109 // for now the set of acceptable characters has to be hardcoded, in future it should be part of the service that creates the mimetype
111 static OUString ImplGetParameterString( const TransferableObjectDescriptor& rObjDesc )
113 const OUString aClassName( rObjDesc.maClassName.GetHexName() );
114 OUString aParams;
116 if( !aClassName.isEmpty() )
118 aParams += ";classname=\"" + aClassName + "\"";
121 if( !rObjDesc.maTypeName.isEmpty() )
123 aParams += ";typename=\"" + rObjDesc.maTypeName + "\"";
126 if( !rObjDesc.maDisplayName.isEmpty() )
128 // the display name might contain unacceptable characters, encode all of them
129 // this seems to be the only parameter currently that might contain such characters
130 sal_Bool pToAccept[128];
131 for (sal_Bool & rb : pToAccept)
132 rb = false;
134 const char aQuotedParamChars[] =
135 "()<>@,;:/[]?=!#$&'*+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz{|}~. ";
137 for ( sal_Int32 nInd = 0; nInd < RTL_CONSTASCII_LENGTH(aQuotedParamChars); ++nInd )
139 sal_Unicode nChar = aQuotedParamChars[nInd];
140 if ( nChar < 128 )
141 pToAccept[nChar] = true;
144 aParams += ";displayname=\""
145 + rtl::Uri::encode(
146 rObjDesc.maDisplayName, pToAccept, rtl_UriEncodeIgnoreEscapes,
147 RTL_TEXTENCODING_UTF8)
148 + "\"";
151 aParams += ";viewaspect=\"" + OUString::number(rObjDesc.mnViewAspect)
152 + "\";width=\"" + OUString::number(rObjDesc.maSize.Width())
153 + "\";height=\"" + OUString::number(rObjDesc.maSize.Height())
154 + "\";posx=\"" + OUString::number(rObjDesc.maDragStartPos.X())
155 + "\";posy=\"" + OUString::number(rObjDesc.maDragStartPos.X()) + "\"";
157 return aParams;
161 static void ImplSetParameterString( TransferableObjectDescriptor& rObjDesc, const DataFlavorEx& rFlavorEx )
163 Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
167 Reference< XMimeContentTypeFactory > xMimeFact = MimeContentTypeFactory::create( xContext );
169 Reference< XMimeContentType > xMimeType( xMimeFact->createMimeContentType( rFlavorEx.MimeType ) );
171 if( xMimeType.is() )
173 const OUString aClassNameString( "classname" );
174 const OUString aTypeNameString( "typename" );
175 const OUString aDisplayNameString( "displayname" );
176 const OUString aViewAspectString( "viewaspect" );
177 const OUString aWidthString( "width" );
178 const OUString aHeightString( "height" );
179 const OUString aPosXString( "posx" );
180 const OUString aPosYString( "posy" );
182 if( xMimeType->hasParameter( aClassNameString ) )
184 rObjDesc.maClassName.MakeId( xMimeType->getParameterValue( aClassNameString ) );
187 if( xMimeType->hasParameter( aTypeNameString ) )
189 rObjDesc.maTypeName = xMimeType->getParameterValue( aTypeNameString );
192 if( xMimeType->hasParameter( aDisplayNameString ) )
194 // the display name might contain unacceptable characters, in this case they should be encoded
195 // this seems to be the only parameter currently that might contain such characters
196 rObjDesc.maDisplayName = ::rtl::Uri::decode( xMimeType->getParameterValue( aDisplayNameString ), rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 );
199 if( xMimeType->hasParameter( aViewAspectString ) )
201 rObjDesc.mnViewAspect = static_cast< sal_uInt16 >( xMimeType->getParameterValue( aViewAspectString ).toInt32() );
204 if( xMimeType->hasParameter( aWidthString ) )
206 rObjDesc.maSize.setWidth( xMimeType->getParameterValue( aWidthString ).toInt32() );
209 if( xMimeType->hasParameter( aHeightString ) )
211 rObjDesc.maSize.setHeight( xMimeType->getParameterValue( aHeightString ).toInt32() );
214 if( xMimeType->hasParameter( aPosXString ) )
216 rObjDesc.maDragStartPos.setX( xMimeType->getParameterValue( aPosXString ).toInt32() );
219 if( xMimeType->hasParameter( aPosYString ) )
221 rObjDesc.maDragStartPos.setY( xMimeType->getParameterValue( aPosYString ).toInt32() );
225 catch( const css::uno::Exception& )
231 TransferableHelper::TerminateListener::TerminateListener( TransferableHelper& rTransferableHelper ) :
232 mrParent( rTransferableHelper )
237 TransferableHelper::TerminateListener::~TerminateListener()
242 void SAL_CALL TransferableHelper::TerminateListener::disposing( const EventObject& )
247 void SAL_CALL TransferableHelper::TerminateListener::queryTermination( const EventObject& )
252 void SAL_CALL TransferableHelper::TerminateListener::notifyTermination( const EventObject& )
254 mrParent.ImplFlush();
257 OUString SAL_CALL TransferableHelper::TerminateListener::getImplementationName()
259 return "com.sun.star.comp.svt.TransferableHelperTerminateListener";
262 sal_Bool SAL_CALL TransferableHelper::TerminateListener::supportsService(const OUString& /*rServiceName*/)
264 return false;
267 css::uno::Sequence<OUString> TransferableHelper::TerminateListener::getSupportedServiceNames()
269 return css::uno::Sequence<OUString>();
272 TransferableHelper::~TransferableHelper()
274 css::uno::Reference<css::frame::XTerminateListener> listener;
276 const SolarMutexGuard aGuard;
277 std::swap(listener, mxTerminateListener);
279 if (listener.is()) {
280 Desktop::create(comphelper::getProcessComponentContext())->removeTerminateListener(
281 listener);
285 Any SAL_CALL TransferableHelper::getTransferData( const DataFlavor& rFlavor )
287 return getTransferData2(rFlavor, OUString());
290 Any SAL_CALL TransferableHelper::getTransferData2( const DataFlavor& rFlavor, const OUString& rDestDoc )
292 if( !maAny.hasValue() || maFormats.empty() || ( maLastFormat != rFlavor.MimeType ) )
294 const SolarMutexGuard aGuard;
296 maLastFormat = rFlavor.MimeType;
297 maAny = Any();
301 DataFlavor aSubstFlavor;
302 bool bDone = false;
304 // add formats if not already done
305 if (maFormats.empty())
306 AddSupportedFormats();
308 // check alien formats first and try to get a substitution format
309 if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING, aSubstFlavor ) &&
310 TransferableDataHelper::IsEqual( aSubstFlavor, rFlavor ) )
312 GetData(aSubstFlavor, rDestDoc);
313 bDone = maAny.hasValue();
315 else if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::BMP, aSubstFlavor )
316 && TransferableDataHelper::IsEqual( aSubstFlavor, rFlavor )
317 && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::BITMAP, aSubstFlavor))
319 GetData(aSubstFlavor, rDestDoc);
320 bDone = true;
322 else if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::EMF, aSubstFlavor ) &&
323 TransferableDataHelper::IsEqual( aSubstFlavor, rFlavor ) &&
324 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aSubstFlavor ) )
326 GetData(aSubstFlavor, rDestDoc);
328 if( maAny.hasValue() )
330 Sequence< sal_Int8 > aSeq;
332 if( maAny >>= aSeq )
334 std::unique_ptr<SvMemoryStream> pSrcStm(new SvMemoryStream( aSeq.getArray(), aSeq.getLength(), StreamMode::WRITE | StreamMode::TRUNC ));
335 GDIMetaFile aMtf;
337 ReadGDIMetaFile( *pSrcStm, aMtf );
338 pSrcStm.reset();
340 Graphic aGraphic( aMtf );
341 SvMemoryStream aDstStm( 65535, 65535 );
343 if( GraphicConverter::Export( aDstStm, aGraphic, ConvertDataFormat::EMF ) == ERRCODE_NONE )
345 maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aDstStm.GetData() ),
346 aDstStm.TellEnd() );
347 bDone = true;
352 else if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::WMF, aSubstFlavor ) &&
353 TransferableDataHelper::IsEqual( aSubstFlavor, rFlavor ) &&
354 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aSubstFlavor ) )
356 GetData(aSubstFlavor, rDestDoc);
358 if( maAny.hasValue() )
360 Sequence< sal_Int8 > aSeq;
362 if( maAny >>= aSeq )
364 std::unique_ptr<SvMemoryStream> pSrcStm(new SvMemoryStream( aSeq.getArray(), aSeq.getLength(), StreamMode::WRITE | StreamMode::TRUNC ));
365 GDIMetaFile aMtf;
367 ReadGDIMetaFile( *pSrcStm, aMtf );
368 pSrcStm.reset();
370 SvMemoryStream aDstStm( 65535, 65535 );
372 // taking wmf without file header
373 if ( ConvertGDIMetaFileToWMF( aMtf, aDstStm, nullptr, false ) )
375 maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aDstStm.GetData() ),
376 aDstStm.TellEnd() );
377 bDone = true;
383 // reset Any if substitute doesn't work
384 if( !bDone && maAny.hasValue() )
385 maAny = Any();
387 // if any is not yet filled, use standard format
388 if( !maAny.hasValue() )
389 GetData(rFlavor, rDestDoc);
391 catch( const css::uno::Exception& )
395 if( !maAny.hasValue() )
396 throw UnsupportedFlavorException();
399 return maAny;
402 sal_Bool SAL_CALL TransferableHelper::isComplex()
404 // By default everything is complex, until proven otherwise
405 // in the respective document type transferable handler.
406 return true;
409 Sequence< DataFlavor > SAL_CALL TransferableHelper::getTransferDataFlavors()
411 const SolarMutexGuard aGuard;
415 if(maFormats.empty())
416 AddSupportedFormats();
418 catch( const css::uno::Exception& )
422 return comphelper::containerToSequence<DataFlavor>(maFormats);
426 sal_Bool SAL_CALL TransferableHelper::isDataFlavorSupported( const DataFlavor& rFlavor )
428 const SolarMutexGuard aGuard;
432 if (maFormats.empty())
433 AddSupportedFormats();
435 catch( const css::uno::Exception& )
439 for (auto const& format : maFormats)
441 if( TransferableDataHelper::IsEqual( format, rFlavor ) )
443 return true;
447 return false;
451 void SAL_CALL TransferableHelper::lostOwnership( const Reference< XClipboard >&, const Reference< XTransferable >& )
453 const SolarMutexGuard aGuard;
457 if( mxTerminateListener.is() )
459 Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
460 xDesktop->removeTerminateListener( mxTerminateListener );
462 mxTerminateListener.clear();
465 ObjectReleased();
467 catch( const css::uno::Exception& )
473 void SAL_CALL TransferableHelper::disposing( const EventObject& )
478 void SAL_CALL TransferableHelper::dragDropEnd( const DragSourceDropEvent& rDSDE )
480 const SolarMutexGuard aGuard;
484 DragFinished( rDSDE.DropSuccess ? ( rDSDE.DropAction & ~DNDConstants::ACTION_DEFAULT ) : DNDConstants::ACTION_NONE );
485 ObjectReleased();
487 catch( const css::uno::Exception& )
493 void SAL_CALL TransferableHelper::dragEnter( const DragSourceDragEvent& )
498 void SAL_CALL TransferableHelper::dragExit( const DragSourceEvent& )
503 void SAL_CALL TransferableHelper::dragOver( const DragSourceDragEvent& )
508 void SAL_CALL TransferableHelper::dropActionChanged( const DragSourceDragEvent& )
513 sal_Int64 SAL_CALL TransferableHelper::getSomething( const Sequence< sal_Int8 >& rId )
515 sal_Int64 nRet;
517 if( isUnoTunnelId<TransferableHelper>(rId) )
519 nRet = sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_IntPtr>(this));
521 else
522 nRet = 0;
524 return nRet;
528 void TransferableHelper::ImplFlush()
530 if( !mxClipboard.is() )
531 return;
533 Reference< XFlushableClipboard > xFlushableClipboard( mxClipboard, UNO_QUERY );
534 SolarMutexReleaser aReleaser;
538 if( xFlushableClipboard.is() )
539 xFlushableClipboard->flushClipboard();
541 catch( const css::uno::Exception& )
543 OSL_FAIL( "Could not flush clipboard" );
548 void TransferableHelper::AddFormat( SotClipboardFormatId nFormat )
550 DataFlavor aFlavor;
552 if( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) )
553 AddFormat( aFlavor );
557 void TransferableHelper::AddFormat( const DataFlavor& rFlavor )
559 bool bAdd = true;
561 for (auto & format : maFormats)
563 if( TransferableDataHelper::IsEqual( format, rFlavor ) )
565 // update MimeType for SotClipboardFormatId::OBJECTDESCRIPTOR in every case
566 if ((SotClipboardFormatId::OBJECTDESCRIPTOR == format.mnSotId) && mxObjDesc)
568 DataFlavor aObjDescFlavor;
570 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDescFlavor );
571 format.MimeType = aObjDescFlavor.MimeType;
572 format.MimeType += ::ImplGetParameterString(*mxObjDesc);
575 bAdd = false;
576 break;
580 if( !bAdd )
581 return;
583 DataFlavorEx aFlavorEx;
585 aFlavorEx.MimeType = rFlavor.MimeType;
586 aFlavorEx.HumanPresentableName = rFlavor.HumanPresentableName;
587 aFlavorEx.DataType = rFlavor.DataType;
588 aFlavorEx.mnSotId = SotExchange::RegisterFormat( rFlavor );
590 if ((SotClipboardFormatId::OBJECTDESCRIPTOR == aFlavorEx.mnSotId) && mxObjDesc)
591 aFlavorEx.MimeType += ::ImplGetParameterString(*mxObjDesc);
593 maFormats.push_back(aFlavorEx);
595 if( SotClipboardFormatId::BITMAP == aFlavorEx.mnSotId )
597 AddFormat( SotClipboardFormatId::PNG );
598 AddFormat( SotClipboardFormatId::BMP );
600 else if( SotClipboardFormatId::GDIMETAFILE == aFlavorEx.mnSotId )
602 AddFormat( SotClipboardFormatId::EMF );
603 AddFormat( SotClipboardFormatId::WMF );
608 void TransferableHelper::RemoveFormat( SotClipboardFormatId nFormat )
610 DataFlavor aFlavor;
612 if( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) )
613 RemoveFormat( aFlavor );
617 void TransferableHelper::RemoveFormat( const DataFlavor& rFlavor )
619 DataFlavorExVector::iterator aIter(maFormats.begin());
621 while (aIter != maFormats.end())
623 if( TransferableDataHelper::IsEqual( *aIter, rFlavor ) )
624 aIter = maFormats.erase(aIter);
625 else
626 ++aIter;
631 bool TransferableHelper::HasFormat( SotClipboardFormatId nFormat )
633 return std::any_of(maFormats.begin(), maFormats.end(),
634 [&](const DataFlavorEx& data) { return data.mnSotId == nFormat; });
638 void TransferableHelper::ClearFormats()
640 maFormats.clear();
641 maAny.clear();
645 bool TransferableHelper::SetAny( const Any& rAny )
647 maAny = rAny;
648 return maAny.hasValue();
652 bool TransferableHelper::SetString( const OUString& rString, const DataFlavor& rFlavor )
654 DataFlavor aFileFlavor;
656 if( !rString.isEmpty() &&
657 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::SIMPLE_FILE, aFileFlavor ) &&
658 TransferableDataHelper::IsEqual( aFileFlavor, rFlavor ) )
660 const OString aByteStr(OUStringToOString(rString, osl_getThreadTextEncoding()));
661 Sequence< sal_Int8 > aSeq( aByteStr.getLength() + 1 );
663 memcpy( aSeq.getArray(), aByteStr.getStr(), aByteStr.getLength() );
664 aSeq[ aByteStr.getLength() ] = 0;
665 maAny <<= aSeq;
667 else
668 maAny <<= rString;
670 return maAny.hasValue();
674 bool TransferableHelper::SetBitmapEx( const BitmapEx& rBitmapEx, const DataFlavor& rFlavor )
676 if( !rBitmapEx.IsEmpty() )
678 SvMemoryStream aMemStm( 65535, 65535 );
680 if(rFlavor.MimeType.equalsIgnoreAsciiCase("image/png"))
682 // write a PNG
683 css::uno::Sequence<css::beans::PropertyValue> aFilterData;
685 #ifdef IOS
686 // Use faster compression on slow devices
687 aFilterData.realloc(aFilterData.getLength() + 1);
688 aFilterData[aFilterData.getLength() - 1].Name = "Compression";
690 // We "know" that this gets passed to zlib's deflateInit2_(). 1 means best speed. For a
691 // typical 15 megapixel image from a DSLR, we are talking about a difference of 17 s for
692 // the default compression level vs 4 s for best speed, on an iPad Pro from 2017.
694 // Sure, the best would be to not have to re-encode the image at all, but have access to
695 // the original JPEG or PNG when there is a such.
697 aFilterData[aFilterData.getLength() - 1].Value <<= 1;
698 #endif
699 vcl::PNGWriter aPNGWriter(rBitmapEx, &aFilterData);
701 aPNGWriter.Write(aMemStm);
703 else
705 // explicitly use Bitmap::Write with bCompressed = sal_False and bFileHeader = sal_True
706 WriteDIB(rBitmapEx.GetBitmap(), aMemStm, false, true);
709 maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() );
712 return maAny.hasValue();
716 bool TransferableHelper::SetGDIMetaFile( const GDIMetaFile& rMtf )
718 if( rMtf.GetActionSize() )
720 SvMemoryStream aMemStm( 65535, 65535 );
722 const_cast<GDIMetaFile&>(rMtf).Write( aMemStm );
723 maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() );
726 return maAny.hasValue();
730 bool TransferableHelper::SetGraphic( const Graphic& rGraphic )
732 if( rGraphic.GetType() != GraphicType::NONE )
734 SvMemoryStream aMemStm( 65535, 65535 );
736 aMemStm.SetVersion( SOFFICE_FILEFORMAT_50 );
737 aMemStm.SetCompressMode( SvStreamCompressFlags::NATIVE );
738 WriteGraphic( aMemStm, rGraphic );
739 maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Seek( STREAM_SEEK_TO_END ) );
742 return maAny.hasValue();
746 bool TransferableHelper::SetImageMap( const ImageMap& rIMap )
748 SvMemoryStream aMemStm( 8192, 8192 );
750 aMemStm.SetVersion( SOFFICE_FILEFORMAT_50 );
751 rIMap.Write( aMemStm );
752 maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Seek( STREAM_SEEK_TO_END ) );
754 return maAny.hasValue();
758 bool TransferableHelper::SetTransferableObjectDescriptor( const TransferableObjectDescriptor& rDesc )
760 PrepareOLE( rDesc );
762 SvMemoryStream aMemStm( 1024, 1024 );
764 WriteTransferableObjectDescriptor( aMemStm, rDesc );
765 maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Tell() );
767 return maAny.hasValue();
771 bool TransferableHelper::SetINetBookmark( const INetBookmark& rBmk,
772 const css::datatransfer::DataFlavor& rFlavor )
774 rtl_TextEncoding eSysCSet = osl_getThreadTextEncoding();
776 switch( SotExchange::GetFormat( rFlavor ) )
778 case SotClipboardFormatId::SOLK:
780 OString sURL(OUStringToOString(rBmk.GetURL(), eSysCSet));
781 OString sDesc(OUStringToOString(rBmk.GetDescription(), eSysCSet));
782 OStringBuffer sOut;
783 sOut.append(sURL.getLength());
784 sOut.append('@').append(sURL);
785 sOut.append(sDesc.getLength());
786 sOut.append('@').append(sDesc);
788 Sequence< sal_Int8 > aSeq(sOut.getLength());
789 memcpy(aSeq.getArray(), sOut.getStr(), sOut.getLength());
790 maAny <<= aSeq;
792 break;
794 case SotClipboardFormatId::STRING:
795 maAny <<= rBmk.GetURL();
796 break;
798 case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
800 OString sURL(OUStringToOString(rBmk.GetURL(), eSysCSet));
801 Sequence< sal_Int8 > aSeq( sURL.getLength() );
802 memcpy( aSeq.getArray(), sURL.getStr(), sURL.getLength() );
803 maAny <<= aSeq;
805 break;
807 case SotClipboardFormatId::NETSCAPE_BOOKMARK:
809 Sequence< sal_Int8 > aSeq( 2048 );
811 memset( aSeq.getArray(), 0, 2048 );
812 strcpy( reinterpret_cast< char* >( aSeq.getArray() ), OUStringToOString(rBmk.GetURL(), eSysCSet).getStr() );
813 strcpy( reinterpret_cast< char* >( aSeq.getArray() ) + 1024, OUStringToOString(rBmk.GetDescription(), eSysCSet).getStr() );
815 maAny <<= aSeq;
817 break;
819 #ifdef _WIN32
820 case SotClipboardFormatId::FILEGRPDESCRIPTOR:
822 Sequence< sal_Int8 > aSeq( sizeof( FILEGROUPDESCRIPTOR ) );
823 FILEGROUPDESCRIPTOR* pFDesc = reinterpret_cast<FILEGROUPDESCRIPTOR*>(aSeq.getArray());
824 FILEDESCRIPTOR& rFDesc1 = pFDesc->fgd[ 0 ];
826 pFDesc->cItems = 1;
827 memset( &rFDesc1, 0, sizeof( FILEDESCRIPTOR ) );
828 rFDesc1.dwFlags = FD_LINKUI;
830 OStringBuffer aStr(OUStringToOString(
831 rBmk.GetDescription(), eSysCSet));
832 for( sal_Int32 nChar = 0; nChar < aStr.getLength(); ++nChar )
833 if( strchr( "\\/:*?\"<>|", aStr[nChar] ) )
834 aStr.remove(nChar--, 1);
836 aStr.insert(0, "Shortcut to ");
837 aStr.append(".URL");
838 strcpy( rFDesc1.cFileName, aStr.getStr() );
840 maAny <<= aSeq;
842 break;
844 case SotClipboardFormatId::FILECONTENT:
846 maAny <<= "[InternetShortcut]\x0aURL=" + rBmk.GetURL();
848 break;
849 #endif
851 default:
852 break;
855 return maAny.hasValue();
859 bool TransferableHelper::SetINetImage( const INetImage& rINtImg,
860 const css::datatransfer::DataFlavor& rFlavor )
862 SvMemoryStream aMemStm( 1024, 1024 );
864 aMemStm.SetVersion( SOFFICE_FILEFORMAT_50 );
865 rINtImg.Write( aMemStm, SotExchange::GetFormat( rFlavor ) );
867 maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Seek( STREAM_SEEK_TO_END ) );
869 return maAny.hasValue();
873 bool TransferableHelper::SetObject( void* pUserObject, sal_uInt32 nUserObjectId, const DataFlavor& rFlavor )
875 tools::SvRef<SotStorageStream> xStm( new SotStorageStream( OUString() ) );
877 xStm->SetVersion( SOFFICE_FILEFORMAT_50 );
879 if( pUserObject && WriteObject( xStm, pUserObject, nUserObjectId, rFlavor ) )
881 const sal_uInt32 nLen = xStm->TellEnd();
882 Sequence< sal_Int8 > aSeq( nLen );
884 xStm->Seek( STREAM_SEEK_TO_BEGIN );
885 xStm->ReadBytes(aSeq.getArray(), nLen);
887 if( nLen && ( SotExchange::GetFormat( rFlavor ) == SotClipboardFormatId::STRING ) )
889 //JP 24.7.2001: as I know was this only for the writer application and this
890 // writes now UTF16 format into the stream
891 //JP 6.8.2001: and now it writes UTF8 because then exist no problem with
892 // little / big endians! - Bug 88121
893 maAny <<= OUString( reinterpret_cast< const char* >( aSeq.getConstArray() ), nLen - 1, RTL_TEXTENCODING_UTF8 );
895 else
896 maAny <<= aSeq;
899 return maAny.hasValue();
903 bool TransferableHelper::WriteObject( tools::SvRef<SotStorageStream>&, void*, sal_uInt32, const DataFlavor& )
905 OSL_FAIL( "TransferableHelper::WriteObject( ... ) not implemented" );
906 return false;
910 void TransferableHelper::DragFinished( sal_Int8 )
915 void TransferableHelper::ObjectReleased()
920 void TransferableHelper::PrepareOLE( const TransferableObjectDescriptor& rObjDesc )
922 mxObjDesc.reset(new TransferableObjectDescriptor(rObjDesc));
924 if( HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ) )
925 AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
928 void TransferableHelper::CopyToClipboard(const Reference<XClipboard>& rClipboard) const
930 if( rClipboard.is() )
931 mxClipboard = rClipboard;
933 if( !mxClipboard.is() || mxTerminateListener.is() )
934 return;
938 TransferableHelper* pThis = const_cast< TransferableHelper* >( this );
939 pThis->mxTerminateListener = new TerminateListener( *pThis );
940 Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
941 xDesktop->addTerminateListener( pThis->mxTerminateListener );
943 mxClipboard->setContents( pThis, pThis );
945 catch( const css::uno::Exception& )
950 void TransferableHelper::CopyToClipboard( vcl::Window *pWindow ) const
952 DBG_ASSERT( pWindow, "Window pointer is NULL" );
953 Reference< XClipboard > xClipboard;
955 if( pWindow )
956 xClipboard = pWindow->GetClipboard();
958 CopyToClipboard(xClipboard);
961 void TransferableHelper::CopyToSelection(const Reference<XClipboard>& rSelection) const
963 if( !rSelection.is() || mxTerminateListener.is() )
964 return;
968 TransferableHelper* pThis = const_cast< TransferableHelper* >( this );
969 pThis->mxTerminateListener = new TerminateListener( *pThis );
970 Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
971 xDesktop->addTerminateListener( pThis->mxTerminateListener );
973 rSelection->setContents( pThis, pThis );
975 catch( const css::uno::Exception& )
980 void TransferableHelper::CopyToSelection( vcl::Window *pWindow ) const
982 DBG_ASSERT( pWindow, "Window pointer is NULL" );
983 Reference< XClipboard > xSelection;
985 if( pWindow )
986 xSelection = pWindow->GetPrimarySelection();
988 CopyToSelection(xSelection);
991 void TransferableHelper::StartDrag( vcl::Window* pWindow, sal_Int8 nDnDSourceActions )
994 DBG_ASSERT( pWindow, "Window pointer is NULL" );
995 Reference< XDragSource > xDragSource( pWindow->GetDragSource() );
997 if( !xDragSource.is() )
998 return;
1001 * #96792# release mouse before actually starting DnD.
1002 * This is necessary for the X11 DnD implementation to work.
1004 if( pWindow->IsMouseCaptured() )
1005 pWindow->ReleaseMouse();
1007 const Point aPt( pWindow->GetPointerPosPixel() );
1009 // On macOS we are forced to execute 'startDrag' synchronously
1010 // contrary to the XDragSource interface specification because
1011 // we can receive drag events from the system only in the main
1012 // thread
1013 #if !defined(MACOSX)
1014 SolarMutexReleaser aReleaser;
1015 #endif
1019 DragGestureEvent aEvt;
1020 aEvt.DragAction = DNDConstants::ACTION_COPY;
1021 aEvt.DragOriginX = aPt.X();
1022 aEvt.DragOriginY = aPt.Y();
1023 aEvt.DragSource = xDragSource;
1025 xDragSource->startDrag( aEvt, nDnDSourceActions, DND_POINTER_NONE, DND_IMAGE_NONE, this, this );
1027 catch( const css::uno::Exception& )
1032 void TransferableHelper::ClearSelection( vcl::Window *pWindow )
1034 DBG_ASSERT( pWindow, "Window pointer is NULL" );
1035 Reference< XClipboard > xSelection( pWindow->GetPrimarySelection() );
1037 if( xSelection.is() )
1038 xSelection->setContents( nullptr, nullptr );
1041 namespace
1043 class theTransferableHelperUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theTransferableHelperUnoTunnelId > {};
1046 const Sequence< sal_Int8 >& TransferableHelper::getUnoTunnelId()
1048 return theTransferableHelperUnoTunnelId::get().getSeq();
1051 namespace {
1053 class TransferableClipboardNotifier : public ::cppu::WeakImplHelper< XClipboardListener >
1055 private:
1056 ::osl::Mutex& mrMutex;
1057 Reference< XClipboardNotifier > mxNotifier;
1058 TransferableDataHelper* mpListener;
1060 protected:
1061 // XClipboardListener
1062 virtual void SAL_CALL changedContents( const clipboard::ClipboardEvent& event ) override;
1064 // XEventListener
1065 virtual void SAL_CALL disposing( const EventObject& Source ) override;
1067 public:
1068 TransferableClipboardNotifier( const Reference< XClipboard >& _rxClipboard, TransferableDataHelper& _rListener, ::osl::Mutex& _rMutex );
1070 /// determines whether we're currently listening
1071 bool isListening() const { return mpListener != nullptr; }
1073 /// makes the instance non-functional
1074 void dispose();
1079 TransferableClipboardNotifier::TransferableClipboardNotifier( const Reference< XClipboard >& _rxClipboard, TransferableDataHelper& _rListener, ::osl::Mutex& _rMutex )
1080 :mrMutex( _rMutex )
1081 ,mxNotifier( _rxClipboard, UNO_QUERY )
1082 ,mpListener( &_rListener )
1084 osl_atomic_increment( &m_refCount );
1086 if ( mxNotifier.is() )
1087 mxNotifier->addClipboardListener( this );
1088 else
1089 // born dead
1090 mpListener = nullptr;
1092 osl_atomic_decrement( &m_refCount );
1096 void SAL_CALL TransferableClipboardNotifier::changedContents( const clipboard::ClipboardEvent& event )
1098 SolarMutexGuard aSolarGuard;
1099 // the SolarMutex here is necessary, since
1100 // - we cannot call mpListener without our own mutex locked
1101 // - Rebind respectively InitFormats (called by Rebind) will
1102 // try to lock the SolarMutex, too
1103 ::osl::MutexGuard aGuard( mrMutex );
1104 if( mpListener )
1105 mpListener->Rebind( event.Contents );
1109 void SAL_CALL TransferableClipboardNotifier::disposing( const EventObject& )
1111 // clipboard is being disposed. Hmm. Okay, become disfunctional myself.
1112 dispose();
1116 void TransferableClipboardNotifier::dispose()
1118 ::osl::MutexGuard aGuard( mrMutex );
1120 Reference< XClipboardListener > xKeepMeAlive( this );
1122 if ( mxNotifier.is() )
1123 mxNotifier->removeClipboardListener( this );
1124 mxNotifier.clear();
1126 mpListener = nullptr;
1129 struct TransferableDataHelper_Impl
1131 ::osl::Mutex maMutex;
1132 rtl::Reference<TransferableClipboardNotifier> mxClipboardListener;
1134 TransferableDataHelper_Impl()
1139 TransferableDataHelper::TransferableDataHelper()
1140 : mxObjDesc(new TransferableObjectDescriptor)
1141 , mxImpl(new TransferableDataHelper_Impl)
1145 TransferableDataHelper::TransferableDataHelper(const Reference< css::datatransfer::XTransferable >& rxTransferable)
1146 : mxTransfer(rxTransferable)
1147 , mxObjDesc(new TransferableObjectDescriptor)
1148 , mxImpl(new TransferableDataHelper_Impl)
1150 InitFormats();
1153 TransferableDataHelper::TransferableDataHelper(const TransferableDataHelper& rDataHelper)
1154 : mxTransfer(rDataHelper.mxTransfer)
1155 , mxClipboard(rDataHelper.mxClipboard)
1156 , maFormats(rDataHelper.maFormats)
1157 , mxObjDesc(new TransferableObjectDescriptor(*rDataHelper.mxObjDesc))
1158 , mxImpl(new TransferableDataHelper_Impl)
1162 TransferableDataHelper::TransferableDataHelper(TransferableDataHelper&& rDataHelper) noexcept
1163 : mxTransfer(std::move(rDataHelper.mxTransfer))
1164 , mxClipboard(std::move(rDataHelper.mxClipboard))
1165 , maFormats(std::move(rDataHelper.maFormats))
1166 , mxObjDesc(std::move(rDataHelper.mxObjDesc))
1167 , mxImpl(new TransferableDataHelper_Impl)
1171 TransferableDataHelper& TransferableDataHelper::operator=( const TransferableDataHelper& rDataHelper )
1173 if ( this != &rDataHelper )
1175 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1177 const bool bWasClipboardListening = mxImpl->mxClipboardListener.is();
1179 if (bWasClipboardListening)
1180 StopClipboardListening();
1182 mxTransfer = rDataHelper.mxTransfer;
1183 maFormats = rDataHelper.maFormats;
1184 mxObjDesc.reset(new TransferableObjectDescriptor(*rDataHelper.mxObjDesc));
1185 mxClipboard = rDataHelper.mxClipboard;
1187 if (bWasClipboardListening)
1188 StartClipboardListening();
1191 return *this;
1194 TransferableDataHelper& TransferableDataHelper::operator=(TransferableDataHelper&& rDataHelper)
1196 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1198 const bool bWasClipboardListening = mxImpl->mxClipboardListener.is();
1200 if (bWasClipboardListening)
1201 StopClipboardListening();
1203 mxTransfer = std::move(rDataHelper.mxTransfer);
1204 maFormats = std::move(rDataHelper.maFormats);
1205 mxObjDesc = std::move(rDataHelper.mxObjDesc);
1206 mxClipboard = std::move(rDataHelper.mxClipboard);
1208 if (bWasClipboardListening)
1209 StartClipboardListening();
1211 return *this;
1214 TransferableDataHelper::~TransferableDataHelper()
1216 StopClipboardListening( );
1218 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1219 maFormats.clear();
1220 mxObjDesc.reset();
1224 void TransferableDataHelper::FillDataFlavorExVector( const Sequence< DataFlavor >& rDataFlavorSeq,
1225 DataFlavorExVector& rDataFlavorExVector )
1229 Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
1230 Reference< XMimeContentTypeFactory > xMimeFact = MimeContentTypeFactory::create( xContext );
1231 DataFlavorEx aFlavorEx;
1232 const OUString aCharsetStr( "charset" );
1235 for (auto const& rFlavor : rDataFlavorSeq)
1237 Reference< XMimeContentType > xMimeType;
1241 if( !rFlavor.MimeType.isEmpty() )
1242 xMimeType = xMimeFact->createMimeContentType( rFlavor.MimeType );
1244 catch( const css::uno::Exception& )
1248 aFlavorEx.MimeType = rFlavor.MimeType;
1249 aFlavorEx.HumanPresentableName = rFlavor.HumanPresentableName;
1250 aFlavorEx.DataType = rFlavor.DataType;
1251 aFlavorEx.mnSotId = SotExchange::RegisterFormat( rFlavor );
1253 rDataFlavorExVector.push_back( aFlavorEx );
1255 // add additional formats for special mime types
1256 if(SotClipboardFormatId::BMP == aFlavorEx.mnSotId || SotClipboardFormatId::PNG == aFlavorEx.mnSotId || SotClipboardFormatId::JPEG == aFlavorEx.mnSotId)
1258 if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::BITMAP, aFlavorEx ) )
1260 aFlavorEx.mnSotId = SotClipboardFormatId::BITMAP;
1261 rDataFlavorExVector.push_back( aFlavorEx );
1264 else if( SotClipboardFormatId::WMF == aFlavorEx.mnSotId || SotClipboardFormatId::EMF == aFlavorEx.mnSotId )
1266 if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aFlavorEx ) )
1268 aFlavorEx.mnSotId = SotClipboardFormatId::GDIMETAFILE;
1269 rDataFlavorExVector.push_back( aFlavorEx );
1272 else if ( SotClipboardFormatId::HTML_SIMPLE == aFlavorEx.mnSotId )
1274 // #104735# HTML_SIMPLE may also be inserted without comments
1275 aFlavorEx.mnSotId = SotClipboardFormatId::HTML_NO_COMMENT;
1276 rDataFlavorExVector.push_back( aFlavorEx );
1278 else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/plain" ) )
1280 // add, if it is a UTF-8 byte buffer
1281 if( xMimeType->hasParameter( aCharsetStr ) )
1283 if( xMimeType->getParameterValue( aCharsetStr ).equalsIgnoreAsciiCase( "unicode" ) ||
1284 xMimeType->getParameterValue( aCharsetStr ).equalsIgnoreAsciiCase( "utf-16" ) )
1286 rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::STRING;
1291 else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/rtf" ) )
1293 rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::RTF;
1295 else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/richtext" ) )
1297 rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::RICHTEXT;
1299 else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/html" ) )
1302 rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::HTML;
1304 else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/uri-list" ) )
1306 rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::FILE_LIST;
1308 else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "application/x-openoffice-objectdescriptor-xml" ) )
1310 rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::OBJECTDESCRIPTOR;
1314 catch( const css::uno::Exception& )
1319 void TransferableDataHelper::InitFormats()
1321 SolarMutexGuard aSolarGuard;
1322 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1324 maFormats.clear();
1325 mxObjDesc.reset(new TransferableObjectDescriptor);
1327 if( !mxTransfer.is() )
1328 return;
1330 TransferableDataHelper::FillDataFlavorExVector(mxTransfer->getTransferDataFlavors(), maFormats);
1332 for (auto const& format : maFormats)
1334 if( SotClipboardFormatId::OBJECTDESCRIPTOR == format.mnSotId )
1336 ImplSetParameterString(*mxObjDesc, format);
1337 break;
1343 bool TransferableDataHelper::HasFormat( SotClipboardFormatId nFormat ) const
1345 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1346 return std::any_of(maFormats.begin(), maFormats.end(),
1347 [&](const DataFlavorEx& data) { return data.mnSotId == nFormat; });
1350 bool TransferableDataHelper::HasFormat( const DataFlavor& rFlavor ) const
1352 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1353 for (auto const& format : maFormats)
1355 if( TransferableDataHelper::IsEqual( rFlavor, format ) )
1356 return true;
1359 return false;
1362 sal_uInt32 TransferableDataHelper::GetFormatCount() const
1364 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1365 return maFormats.size();
1368 SotClipboardFormatId TransferableDataHelper::GetFormat( sal_uInt32 nFormat ) const
1370 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1371 DBG_ASSERT(nFormat < maFormats.size(), "TransferableDataHelper::GetFormat: invalid format index");
1372 return( ( nFormat < maFormats.size() ) ? maFormats[ nFormat ].mnSotId : SotClipboardFormatId::NONE );
1375 DataFlavor TransferableDataHelper::GetFormatDataFlavor( sal_uInt32 nFormat ) const
1377 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1378 DBG_ASSERT(nFormat < maFormats.size(), "TransferableDataHelper::GetFormat: invalid format index");
1380 DataFlavor aRet;
1382 if (nFormat < maFormats.size())
1383 aRet = maFormats[nFormat];
1385 return aRet;
1389 Reference< XTransferable > TransferableDataHelper::GetXTransferable() const
1391 Reference< XTransferable > xRet;
1393 if( mxTransfer.is() )
1397 xRet = mxTransfer;
1399 // do a dummy call to check, if this interface is valid (nasty)
1400 xRet->getTransferDataFlavors();
1403 catch( const css::uno::Exception& )
1405 xRet.clear();
1409 return xRet;
1413 Any TransferableDataHelper::GetAny( SotClipboardFormatId nFormat, const OUString& rDestDoc ) const
1415 Any aReturn;
1417 DataFlavor aFlavor;
1418 if ( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) )
1419 aReturn = GetAny(aFlavor, rDestDoc);
1421 return aReturn;
1424 Any TransferableDataHelper::GetAny( const DataFlavor& rFlavor, const OUString& rDestDoc ) const
1426 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1427 Any aRet;
1431 if( mxTransfer.is() )
1433 const SotClipboardFormatId nRequestFormat = SotExchange::GetFormat( rFlavor );
1435 Reference<css::datatransfer::XTransferable2> xTransfer2(mxTransfer, UNO_QUERY);
1437 if( nRequestFormat != SotClipboardFormatId::NONE )
1439 // try to get alien format first
1440 for (auto const& format : maFormats)
1442 if( ( nRequestFormat == format.mnSotId ) && !rFlavor.MimeType.equalsIgnoreAsciiCase( format.MimeType ) )
1444 // tdf#133365: only release solar mutex on Windows
1445 #ifdef _WIN32
1446 // tdf#133527: first, make sure that we actually hold the mutex
1447 SolarMutexGuard g;
1448 // Our own thread may handle the nested IDataObject::GetData call,
1449 // and try to acquire solar mutex
1450 SolarMutexReleaser r;
1451 #endif // _WIN32
1453 if (xTransfer2.is())
1454 aRet = xTransfer2->getTransferData2(format, rDestDoc);
1455 else
1456 aRet = mxTransfer->getTransferData(format);
1459 if( aRet.hasValue() )
1460 break;
1464 if( !aRet.hasValue() )
1466 // tdf#133365: only release solar mutex on Windows
1467 #ifdef _WIN32
1468 // tdf#133527: first, make sure that we actually hold the mutex
1469 SolarMutexGuard g;
1470 // Our own thread may handle the nested IDataObject::GetData call,
1471 // and try to acquire solar mutex
1472 SolarMutexReleaser r;
1473 #endif // _WIN32
1475 if (xTransfer2.is())
1476 aRet = xTransfer2->getTransferData2(rFlavor, rDestDoc);
1477 else
1478 aRet = mxTransfer->getTransferData(rFlavor);
1482 catch( const css::uno::Exception& )
1486 return aRet;
1490 bool TransferableDataHelper::GetString( SotClipboardFormatId nFormat, OUString& rStr )
1492 DataFlavor aFlavor;
1493 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetString( aFlavor, rStr ) );
1497 bool TransferableDataHelper::GetString( const DataFlavor& rFlavor, OUString& rStr )
1499 Any aAny = GetAny(rFlavor, OUString());
1500 bool bRet = false;
1502 if( aAny.hasValue() )
1504 OUString aOUString;
1505 Sequence< sal_Int8 > aSeq;
1507 if( aAny >>= aOUString )
1509 rStr = aOUString;
1510 bRet = true;
1512 else if( aAny >>= aSeq )
1515 const char* pChars = reinterpret_cast< const char* >( aSeq.getConstArray() );
1516 sal_Int32 nLen = aSeq.getLength();
1518 //JP 10.10.2001: 92930 - don't copy the last zero character into the string.
1519 //DVO 2002-05-27: strip _all_ trailing zeros
1520 while( nLen && ( 0 == *( pChars + nLen - 1 ) ) )
1521 --nLen;
1523 rStr = OUString( pChars, nLen, osl_getThreadTextEncoding() );
1524 bRet = true;
1528 return bRet;
1532 bool TransferableDataHelper::GetBitmapEx( SotClipboardFormatId nFormat, BitmapEx& rBmpEx )
1534 if(SotClipboardFormatId::BITMAP == nFormat)
1536 // try to get PNG first
1537 DataFlavor aFlavor;
1539 if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor))
1541 if(GetBitmapEx(aFlavor, rBmpEx))
1543 return true;
1547 // then JPEG
1548 if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG, aFlavor))
1550 if(GetBitmapEx(aFlavor, rBmpEx))
1552 return true;
1557 DataFlavor aFlavor;
1558 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetBitmapEx( aFlavor, rBmpEx ) );
1562 bool TransferableDataHelper::GetBitmapEx( const DataFlavor& rFlavor, BitmapEx& rBmpEx )
1564 tools::SvRef<SotStorageStream> xStm;
1565 DataFlavor aSubstFlavor;
1566 bool bRet(GetSotStorageStream(rFlavor, xStm));
1567 bool bSuppressPNG(false); // #122982# If PNG stream not accessed, but BMP one, suppress trying to load PNG
1568 bool bSuppressJPEG(false);
1570 if(!bRet && HasFormat(SotClipboardFormatId::PNG) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aSubstFlavor))
1572 // when no direct success, try if PNG is available
1573 bRet = GetSotStorageStream(aSubstFlavor, xStm);
1574 bSuppressJPEG = bRet;
1577 if(!bRet && HasFormat(SotClipboardFormatId::JPEG) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG, aSubstFlavor))
1579 bRet = GetSotStorageStream(aSubstFlavor, xStm);
1580 bSuppressPNG = bRet;
1583 if(!bRet && HasFormat(SotClipboardFormatId::BMP) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::BMP, aSubstFlavor))
1585 // when no direct success, try if BMP is available
1586 bRet = GetSotStorageStream(aSubstFlavor, xStm);
1587 bSuppressPNG = bRet;
1588 bSuppressJPEG = bRet;
1591 if(bRet)
1593 if(!bSuppressPNG && rFlavor.MimeType.equalsIgnoreAsciiCase("image/png"))
1595 // it's a PNG, import to BitmapEx
1596 vcl::PNGReader aPNGReader(*xStm);
1598 rBmpEx = aPNGReader.Read();
1600 else if(!bSuppressJPEG && rFlavor.MimeType.equalsIgnoreAsciiCase("image/jpeg"))
1602 // it's a JPEG, import to BitmapEx
1603 GraphicFilter& rFilter = GraphicFilter::GetGraphicFilter();
1604 Graphic aGraphic;
1605 if (rFilter.ImportGraphic(aGraphic, "", *xStm) == ERRCODE_NONE)
1606 rBmpEx = aGraphic.GetBitmapEx();
1609 if(rBmpEx.IsEmpty())
1611 Bitmap aBitmap;
1612 AlphaMask aMask;
1614 // explicitly use Bitmap::Read with bFileHeader = sal_True
1615 // #i124085# keep DIBV5 for read from clipboard, but should not happen
1616 ReadDIBV5(aBitmap, aMask, *xStm);
1618 if(aMask.GetBitmap().IsEmpty())
1620 rBmpEx = aBitmap;
1622 else
1624 rBmpEx = BitmapEx(aBitmap, aMask);
1628 bRet = (ERRCODE_NONE == xStm->GetError() && !rBmpEx.IsEmpty());
1630 /* SJ: #110748# At the moment we are having problems with DDB inserted as DIB. The
1631 problem is, that some graphics are inserted much too big because the nXPelsPerMeter
1632 and nYPelsPerMeter of the bitmap fileheader isn't including the correct value.
1633 Due to this reason the following code assumes that bitmaps with a logical size
1634 greater than 50 cm aren't having the correct mapmode set.
1636 The following code should be removed if DDBs and DIBs are supported via clipboard
1637 properly.
1639 if(bRet)
1641 const MapMode aMapMode(rBmpEx.GetPrefMapMode());
1643 if(MapUnit::MapPixel != aMapMode.GetMapUnit())
1645 const Size aSize(OutputDevice::LogicToLogic(rBmpEx.GetPrefSize(), aMapMode, MapMode(MapUnit::Map100thMM)));
1647 // #i122388# This wrongly corrects in the given case; changing from 5000 100th mm to
1648 // the described 50 cm (which is 50000 100th mm)
1649 if((aSize.Width() > 50000) || (aSize.Height() > 50000))
1651 rBmpEx.SetPrefMapMode(MapMode(MapUnit::MapPixel));
1653 // #i122388# also adapt size by applying the mew MapMode
1654 const Size aNewSize(OutputDevice::LogicToLogic(aSize, MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapPixel)));
1655 rBmpEx.SetPrefSize(aNewSize);
1661 return bRet;
1665 bool TransferableDataHelper::GetGDIMetaFile(SotClipboardFormatId nFormat, GDIMetaFile& rMtf, size_t nMaxActions)
1667 DataFlavor aFlavor;
1668 return SotExchange::GetFormatDataFlavor(nFormat, aFlavor) &&
1669 GetGDIMetaFile(aFlavor, rMtf) &&
1670 (nMaxActions == 0 || rMtf.GetActionSize() < nMaxActions);
1674 bool TransferableDataHelper::GetGDIMetaFile( const DataFlavor& rFlavor, GDIMetaFile& rMtf )
1676 tools::SvRef<SotStorageStream> xStm;
1677 DataFlavor aSubstFlavor;
1678 bool bRet = false;
1680 if( GetSotStorageStream( rFlavor, xStm ) )
1682 ReadGDIMetaFile( *xStm, rMtf );
1683 bRet = ( xStm->GetError() == ERRCODE_NONE );
1686 if( !bRet &&
1687 HasFormat( SotClipboardFormatId::EMF ) &&
1688 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::EMF, aSubstFlavor ) &&
1689 GetSotStorageStream( aSubstFlavor, xStm ) )
1691 Graphic aGraphic;
1693 if( GraphicConverter::Import( *xStm, aGraphic ) == ERRCODE_NONE )
1695 rMtf = aGraphic.GetGDIMetaFile();
1696 bRet = true;
1700 if( !bRet &&
1701 HasFormat( SotClipboardFormatId::WMF ) &&
1702 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::WMF, aSubstFlavor ) &&
1703 GetSotStorageStream( aSubstFlavor, xStm ) )
1705 Graphic aGraphic;
1707 if( GraphicConverter::Import( *xStm, aGraphic ) == ERRCODE_NONE )
1709 rMtf = aGraphic.GetGDIMetaFile();
1710 bRet = true;
1714 return bRet;
1718 bool TransferableDataHelper::GetGraphic( SotClipboardFormatId nFormat, Graphic& rGraphic )
1720 if(SotClipboardFormatId::BITMAP == nFormat)
1722 // try to get PNG first
1723 DataFlavor aFlavor;
1725 if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor))
1727 if(GetGraphic(aFlavor, rGraphic))
1729 return true;
1734 DataFlavor aFlavor;
1735 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetGraphic( aFlavor, rGraphic ) );
1739 bool TransferableDataHelper::GetGraphic( const css::datatransfer::DataFlavor& rFlavor, Graphic& rGraphic )
1741 DataFlavor aFlavor;
1742 bool bRet = false;
1744 if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor) &&
1745 TransferableDataHelper::IsEqual(aFlavor, rFlavor))
1747 // try to get PNG first
1748 BitmapEx aBmpEx;
1750 bRet = GetBitmapEx( aFlavor, aBmpEx );
1751 if( bRet )
1752 rGraphic = aBmpEx;
1754 else if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PDF, aFlavor) &&
1755 TransferableDataHelper::IsEqual(aFlavor, rFlavor))
1757 Graphic aGraphic;
1758 tools::SvRef<SotStorageStream> xStm;
1759 if (GetSotStorageStream(rFlavor, xStm))
1761 if (GraphicConverter::Import(*xStm, aGraphic) == ERRCODE_NONE)
1763 rGraphic = aGraphic;
1764 bRet = true;
1768 else if (SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG, aFlavor) && TransferableDataHelper::IsEqual(aFlavor, rFlavor))
1770 BitmapEx aBitmapEx;
1772 bRet = GetBitmapEx(aFlavor, aBitmapEx);
1773 if (bRet)
1774 rGraphic = aBitmapEx;
1776 else if(SotExchange::GetFormatDataFlavor( SotClipboardFormatId::BITMAP, aFlavor ) &&
1777 TransferableDataHelper::IsEqual( aFlavor, rFlavor ) )
1779 BitmapEx aBmpEx;
1781 bRet = GetBitmapEx( aFlavor, aBmpEx );
1782 if( bRet )
1783 rGraphic = aBmpEx;
1785 else if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aFlavor ) &&
1786 TransferableDataHelper::IsEqual( aFlavor, rFlavor ) )
1788 GDIMetaFile aMtf;
1790 bRet = GetGDIMetaFile( aFlavor, aMtf );
1791 if( bRet )
1792 rGraphic = aMtf;
1794 else
1796 tools::SvRef<SotStorageStream> xStm;
1798 if( GetSotStorageStream( rFlavor, xStm ) )
1800 ReadGraphic( *xStm, rGraphic );
1801 bRet = ( xStm->GetError() == ERRCODE_NONE );
1805 return bRet;
1809 bool TransferableDataHelper::GetImageMap( SotClipboardFormatId nFormat, ImageMap& rIMap )
1811 DataFlavor aFlavor;
1812 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetImageMap( aFlavor, rIMap ) );
1816 bool TransferableDataHelper::GetImageMap( const css::datatransfer::DataFlavor& rFlavor, ImageMap& rIMap )
1818 tools::SvRef<SotStorageStream> xStm;
1819 bool bRet = GetSotStorageStream( rFlavor, xStm );
1821 if( bRet )
1823 rIMap.Read( *xStm );
1824 bRet = ( xStm->GetError() == ERRCODE_NONE );
1827 return bRet;
1831 bool TransferableDataHelper::GetTransferableObjectDescriptor( SotClipboardFormatId nFormat, TransferableObjectDescriptor& rDesc )
1833 DataFlavor aFlavor;
1834 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetTransferableObjectDescriptor( rDesc ) );
1838 bool TransferableDataHelper::GetTransferableObjectDescriptor( TransferableObjectDescriptor& rDesc )
1840 rDesc = *mxObjDesc;
1841 return true;
1845 bool TransferableDataHelper::GetINetBookmark( SotClipboardFormatId nFormat, INetBookmark& rBmk )
1847 DataFlavor aFlavor;
1848 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetINetBookmark( aFlavor, rBmk ) );
1852 bool TransferableDataHelper::GetINetBookmark( const css::datatransfer::DataFlavor& rFlavor, INetBookmark& rBmk )
1854 bool bRet = false;
1855 if( HasFormat( rFlavor ))
1857 const SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
1858 switch( nFormat )
1860 case SotClipboardFormatId::SOLK:
1861 case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
1863 OUString aString;
1864 if( GetString( rFlavor, aString ) )
1866 if( SotClipboardFormatId::UNIFORMRESOURCELOCATOR == nFormat )
1868 rBmk = INetBookmark( aString, aString );
1869 bRet = true;
1871 else
1873 OUString aURL, aDesc;
1874 sal_Int32 nStart = aString.indexOf( '@' ), nLen = aString.toInt32();
1876 if( !nLen && aString[ 0 ] != '0' )
1878 SAL_INFO( "svtools", "SOLK: 1. len=0" );
1880 if( nStart == -1 || nLen > aString.getLength() - nStart - 3 )
1882 SAL_INFO( "svtools", "SOLK: 1. illegal start or wrong len" );
1884 aURL = aString.copy( nStart + 1, nLen );
1886 aString = aString.replaceAt( 0, nStart + 1 + nLen, "" );
1887 nStart = aString.indexOf( '@' );
1888 nLen = aString.toInt32();
1890 if( !nLen && aString[ 0 ] != '0' )
1892 SAL_INFO( "svtools", "SOLK: 2. len=0" );
1894 if( nStart == -1 || nLen > aString.getLength() - nStart - 1 )
1896 SAL_INFO( "svtools", "SOLK: 2. illegal start or wrong len" );
1898 aDesc = aString.copy( nStart+1, nLen );
1900 rBmk = INetBookmark( aURL, aDesc );
1901 bRet = true;
1905 break;
1907 case SotClipboardFormatId::NETSCAPE_BOOKMARK:
1909 Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
1911 if (2048 == aSeq.getLength())
1913 const char* p1 = reinterpret_cast< const char* >( aSeq.getConstArray() );
1914 const char* p2 = reinterpret_cast< const char* >( aSeq.getConstArray() ) + 1024;
1915 rBmk = INetBookmark( OUString( p1, strlen(p1), osl_getThreadTextEncoding() ),
1916 OUString( p2, strlen(p2), osl_getThreadTextEncoding() ) );
1917 bRet = true;
1920 break;
1922 #ifdef _WIN32
1923 case SotClipboardFormatId::FILEGRPDESCRIPTOR:
1925 Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
1927 if (aSeq.getLength())
1929 FILEGROUPDESCRIPTOR const * pFDesc = reinterpret_cast<FILEGROUPDESCRIPTOR const *>(aSeq.getConstArray());
1931 if( pFDesc->cItems )
1933 OString aDesc( pFDesc->fgd[ 0 ].cFileName );
1934 rtl_TextEncoding eTextEncoding = osl_getThreadTextEncoding();
1936 if( ( aDesc.getLength() > 4 ) && aDesc.copy(aDesc.getLength() - 4).equalsIgnoreAsciiCase(".URL") )
1938 std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( INetURLObject( OStringToOUString(aDesc, eTextEncoding) ).GetMainURL( INetURLObject::DecodeMechanism::NONE ),
1939 StreamMode::STD_READ ));
1941 if( !pStream || pStream->GetError() )
1943 DataFlavor aFileContentFlavor;
1945 aSeq.realloc( 0 );
1946 pStream.reset();
1948 if (SotExchange::GetFormatDataFlavor(SotClipboardFormatId::FILECONTENT, aFileContentFlavor))
1950 aSeq = GetSequence(aFileContentFlavor, OUString());
1951 if (aSeq.getLength())
1952 pStream.reset(new SvMemoryStream( const_cast<sal_Int8 *>(aSeq.getConstArray()), aSeq.getLength(), StreamMode::STD_READ ));
1956 if( pStream )
1958 OString aLine;
1959 bool bSttFnd = false;
1961 while( pStream->ReadLine( aLine ) )
1963 if (aLine.equalsIgnoreAsciiCase("[InternetShortcut]"))
1964 bSttFnd = true;
1965 else if (bSttFnd && aLine.copy(0, 4).equalsIgnoreAsciiCase("URL="))
1967 rBmk = INetBookmark( OStringToOUString(aLine.copy(4), eTextEncoding),
1968 OStringToOUString(aDesc.copy(0, aDesc.getLength() - 4), eTextEncoding) );
1969 bRet = true;
1970 break;
1978 break;
1979 #endif
1980 default: break;
1983 return bRet;
1987 bool TransferableDataHelper::GetINetImage( SotClipboardFormatId nFormat,
1988 INetImage& rINtImg )
1990 DataFlavor aFlavor;
1991 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetINetImage( aFlavor, rINtImg ) );
1995 bool TransferableDataHelper::GetINetImage(
1996 const css::datatransfer::DataFlavor& rFlavor,
1997 INetImage& rINtImg )
1999 tools::SvRef<SotStorageStream> xStm;
2000 bool bRet = GetSotStorageStream( rFlavor, xStm );
2002 if( bRet )
2003 bRet = rINtImg.Read( *xStm, SotExchange::GetFormat( rFlavor ) );
2004 return bRet;
2008 bool TransferableDataHelper::GetFileList( SotClipboardFormatId nFormat,
2009 FileList& rFileList )
2011 DataFlavor aFlavor;
2012 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetFileList( rFileList ) );
2016 bool TransferableDataHelper::GetFileList( FileList& rFileList )
2018 tools::SvRef<SotStorageStream> xStm;
2019 bool bRet = false;
2021 for( sal_uInt32 i = 0, nFormatCount = GetFormatCount(); ( i < nFormatCount ) && !bRet; ++i )
2023 if( SotClipboardFormatId::FILE_LIST == GetFormat( i ) )
2025 const DataFlavor aFlavor( GetFormatDataFlavor( i ) );
2027 if( GetSotStorageStream( aFlavor, xStm ) )
2029 if( aFlavor.MimeType.indexOf( "text/uri-list" ) > -1 )
2031 OString aDiskString;
2033 while( xStm->ReadLine( aDiskString ) )
2034 if( !aDiskString.isEmpty() && aDiskString[0] != '#' )
2035 rFileList.AppendFile( OStringToOUString(aDiskString, RTL_TEXTENCODING_UTF8) );
2037 bRet = true;
2039 else
2040 bRet = ( ReadFileList( *xStm, rFileList ).GetError() == ERRCODE_NONE );
2045 return bRet;
2049 Sequence<sal_Int8> TransferableDataHelper::GetSequence( SotClipboardFormatId nFormat, const OUString& rDestDoc )
2051 DataFlavor aFlavor;
2052 if (!SotExchange::GetFormatDataFlavor(nFormat, aFlavor))
2053 return Sequence<sal_Int8>();
2055 return GetSequence(aFlavor, rDestDoc);
2058 Sequence<sal_Int8> TransferableDataHelper::GetSequence( const DataFlavor& rFlavor, const OUString& rDestDoc )
2060 const Any aAny = GetAny(rFlavor, rDestDoc);
2061 Sequence<sal_Int8> aSeq;
2062 if (aAny.hasValue())
2063 aAny >>= aSeq;
2065 return aSeq;
2069 bool TransferableDataHelper::GetSotStorageStream( SotClipboardFormatId nFormat, tools::SvRef<SotStorageStream>& rxStream )
2071 DataFlavor aFlavor;
2072 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetSotStorageStream( aFlavor, rxStream ) );
2076 bool TransferableDataHelper::GetSotStorageStream( const DataFlavor& rFlavor, tools::SvRef<SotStorageStream>& rxStream )
2078 Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
2080 if (aSeq.hasElements())
2082 rxStream = new SotStorageStream( "" );
2083 rxStream->WriteBytes( aSeq.getConstArray(), aSeq.getLength() );
2084 rxStream->Seek( 0 );
2087 return aSeq.hasElements();
2090 Reference<XInputStream> TransferableDataHelper::GetInputStream( SotClipboardFormatId nFormat, const OUString& rDestDoc )
2092 DataFlavor aFlavor;
2093 if (!SotExchange::GetFormatDataFlavor(nFormat, aFlavor))
2094 return Reference<XInputStream>();
2096 return GetInputStream(aFlavor, rDestDoc);
2099 Reference<XInputStream> TransferableDataHelper::GetInputStream( const DataFlavor& rFlavor, const OUString& rDestDoc )
2101 Sequence<sal_Int8> aSeq = GetSequence(rFlavor, rDestDoc);
2103 if (!aSeq.hasElements())
2104 return Reference<XInputStream>();
2106 Reference<XInputStream> xStream(new comphelper::SequenceInputStream(aSeq));
2107 return xStream;
2110 void TransferableDataHelper::Rebind( const Reference< XTransferable >& _rxNewContent )
2112 mxTransfer = _rxNewContent;
2113 InitFormats();
2116 bool TransferableDataHelper::StartClipboardListening( )
2118 ::osl::MutexGuard aGuard(mxImpl->maMutex);
2120 StopClipboardListening( );
2122 mxImpl->mxClipboardListener = new TransferableClipboardNotifier(mxClipboard, *this, mxImpl->maMutex);
2124 return mxImpl->mxClipboardListener->isListening();
2127 void TransferableDataHelper::StopClipboardListening( )
2129 ::osl::MutexGuard aGuard(mxImpl->maMutex);
2131 if (mxImpl->mxClipboardListener.is())
2133 mxImpl->mxClipboardListener->dispose();
2134 mxImpl->mxClipboardListener.clear();
2138 TransferableDataHelper TransferableDataHelper::CreateFromClipboard(const css::uno::Reference<css::datatransfer::clipboard::XClipboard>& rClipboard)
2140 TransferableDataHelper aRet;
2142 if( rClipboard.is() )
2146 Reference< XTransferable > xTransferable( rClipboard->getContents() );
2148 if( xTransferable.is() )
2150 aRet = TransferableDataHelper( xTransferable );
2151 // also copy the clipboard
2152 aRet.mxClipboard = rClipboard;
2155 catch( const css::uno::Exception& )
2160 return aRet;
2163 TransferableDataHelper TransferableDataHelper::CreateFromSystemClipboard( vcl::Window * pWindow )
2165 DBG_ASSERT( pWindow, "Window pointer is NULL" );
2167 Reference< XClipboard > xClipboard;
2169 if( pWindow )
2170 xClipboard = pWindow->GetClipboard();
2172 return CreateFromClipboard(xClipboard);
2176 TransferableDataHelper TransferableDataHelper::CreateFromSelection( vcl::Window* pWindow )
2178 DBG_ASSERT( pWindow, "Window pointer is NULL" );
2180 Reference< XClipboard > xSelection;
2181 TransferableDataHelper aRet;
2183 if( pWindow )
2184 xSelection = pWindow->GetPrimarySelection();
2186 if( xSelection.is() )
2188 SolarMutexReleaser aReleaser;
2192 Reference< XTransferable > xTransferable( xSelection->getContents() );
2194 if( xTransferable.is() )
2196 aRet = TransferableDataHelper( xTransferable );
2197 aRet.mxClipboard = xSelection;
2200 catch( const css::uno::Exception& )
2205 return aRet;
2209 bool TransferableDataHelper::IsEqual( const css::datatransfer::DataFlavor& rInternalFlavor,
2210 const css::datatransfer::DataFlavor& rRequestFlavor )
2212 Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
2213 bool bRet = false;
2217 Reference< XMimeContentTypeFactory > xMimeFact = MimeContentTypeFactory::create( xContext );
2219 Reference< XMimeContentType > xRequestType1( xMimeFact->createMimeContentType( rInternalFlavor.MimeType ) );
2220 Reference< XMimeContentType > xRequestType2( xMimeFact->createMimeContentType( rRequestFlavor.MimeType ) );
2222 if( xRequestType1.is() && xRequestType2.is() )
2224 if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( xRequestType2->getFullMediaType() ) )
2226 if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( "text/plain" ) )
2228 // special handling for text/plain media types
2229 const OUString aCharsetString( "charset" );
2231 if( !xRequestType2->hasParameter( aCharsetString ) ||
2232 xRequestType2->getParameterValue( aCharsetString ).equalsIgnoreAsciiCase( "utf-16" ) ||
2233 xRequestType2->getParameterValue( aCharsetString ).equalsIgnoreAsciiCase( "unicode" ) )
2235 bRet = true;
2238 else if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( "application/x-openoffice" ) )
2240 // special handling for application/x-openoffice media types
2241 const OUString aFormatString( "windows_formatname" );
2243 if( xRequestType1->hasParameter( aFormatString ) &&
2244 xRequestType2->hasParameter( aFormatString ) &&
2245 xRequestType1->getParameterValue( aFormatString ).equalsIgnoreAsciiCase( xRequestType2->getParameterValue( aFormatString ) ) )
2247 bRet = true;
2250 else
2251 bRet = true;
2255 catch( const css::uno::Exception& )
2257 bRet = rInternalFlavor.MimeType.equalsIgnoreAsciiCase( rRequestFlavor.MimeType );
2260 return bRet;
2263 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */