1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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>
62 #include <vcl/dibtools.hxx>
63 #include <vcl/pngread.hxx>
64 #include <vcl/pngwrite.hxx>
65 #include <vcl/graphicfilter.hxx>
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
;
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
);
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() );
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
)
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
];
141 pToAccept
[nChar
] = true;
144 aParams
+= ";displayname=\""
146 rObjDesc
.maDisplayName
, pToAccept
, rtl_UriEncodeIgnoreEscapes
,
147 RTL_TEXTENCODING_UTF8
)
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()) + "\"";
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
) );
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*/)
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
);
280 Desktop::create(comphelper::getProcessComponentContext())->removeTerminateListener(
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
;
301 DataFlavor aSubstFlavor
;
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
);
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
;
334 std::unique_ptr
<SvMemoryStream
> pSrcStm(new SvMemoryStream( aSeq
.getArray(), aSeq
.getLength(), StreamMode::WRITE
| StreamMode::TRUNC
));
337 ReadGDIMetaFile( *pSrcStm
, aMtf
);
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() ),
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
;
364 std::unique_ptr
<SvMemoryStream
> pSrcStm(new SvMemoryStream( aSeq
.getArray(), aSeq
.getLength(), StreamMode::WRITE
| StreamMode::TRUNC
));
367 ReadGDIMetaFile( *pSrcStm
, aMtf
);
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() ),
383 // reset Any if substitute doesn't work
384 if( !bDone
&& maAny
.hasValue() )
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();
402 sal_Bool SAL_CALL
TransferableHelper::isComplex()
404 // By default everything is complex, until proven otherwise
405 // in the respective document type transferable handler.
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
) )
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();
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
);
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
)
517 if( isUnoTunnelId
<TransferableHelper
>(rId
) )
519 nRet
= sal::static_int_cast
<sal_Int64
>(reinterpret_cast<sal_IntPtr
>(this));
528 void TransferableHelper::ImplFlush()
530 if( !mxClipboard
.is() )
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
)
552 if( SotExchange::GetFormatDataFlavor( nFormat
, aFlavor
) )
553 AddFormat( aFlavor
);
557 void TransferableHelper::AddFormat( const DataFlavor
& rFlavor
)
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
);
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
)
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
);
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()
645 bool TransferableHelper::SetAny( const Any
& 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;
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"))
683 css::uno::Sequence
<css::beans::PropertyValue
> aFilterData
;
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;
699 vcl::PNGWriter
aPNGWriter(rBitmapEx
, &aFilterData
);
701 aPNGWriter
.Write(aMemStm
);
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
)
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
));
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());
794 case SotClipboardFormatId::STRING
:
795 maAny
<<= rBmk
.GetURL();
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() );
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() );
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 ];
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 ");
838 strcpy( rFDesc1
.cFileName
, aStr
.getStr() );
844 case SotClipboardFormatId::FILECONTENT
:
846 maAny
<<= "[InternetShortcut]\x0aURL=" + rBmk
.GetURL();
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
);
899 return maAny
.hasValue();
903 bool TransferableHelper::WriteObject( tools::SvRef
<SotStorageStream
>&, void*, sal_uInt32
, const DataFlavor
& )
905 OSL_FAIL( "TransferableHelper::WriteObject( ... ) not implemented" );
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() )
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
;
956 xClipboard
= pWindow
->GetClipboard();
958 CopyToClipboard(xClipboard
);
961 void TransferableHelper::CopyToSelection(const Reference
<XClipboard
>& rSelection
) const
963 if( !rSelection
.is() || mxTerminateListener
.is() )
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
;
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() )
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
1013 #if !defined(MACOSX)
1014 SolarMutexReleaser aReleaser
;
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 );
1043 class theTransferableHelperUnoTunnelId
: public rtl::Static
< UnoTunnelIdInit
, theTransferableHelperUnoTunnelId
> {};
1046 const Sequence
< sal_Int8
>& TransferableHelper::getUnoTunnelId()
1048 return theTransferableHelperUnoTunnelId::get().getSeq();
1053 class TransferableClipboardNotifier
: public ::cppu::WeakImplHelper
< XClipboardListener
>
1056 ::osl::Mutex
& mrMutex
;
1057 Reference
< XClipboardNotifier
> mxNotifier
;
1058 TransferableDataHelper
* mpListener
;
1061 // XClipboardListener
1062 virtual void SAL_CALL
changedContents( const clipboard::ClipboardEvent
& event
) override
;
1065 virtual void SAL_CALL
disposing( const EventObject
& Source
) override
;
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
1079 TransferableClipboardNotifier::TransferableClipboardNotifier( const Reference
< XClipboard
>& _rxClipboard
, TransferableDataHelper
& _rListener
, ::osl::Mutex
& _rMutex
)
1081 ,mxNotifier( _rxClipboard
, UNO_QUERY
)
1082 ,mpListener( &_rListener
)
1084 osl_atomic_increment( &m_refCount
);
1086 if ( mxNotifier
.is() )
1087 mxNotifier
->addClipboardListener( this );
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
);
1105 mpListener
->Rebind( event
.Contents
);
1109 void SAL_CALL
TransferableClipboardNotifier::disposing( const EventObject
& )
1111 // clipboard is being disposed. Hmm. Okay, become disfunctional myself.
1116 void TransferableClipboardNotifier::dispose()
1118 ::osl::MutexGuard
aGuard( mrMutex
);
1120 Reference
< XClipboardListener
> xKeepMeAlive( this );
1122 if ( mxNotifier
.is() )
1123 mxNotifier
->removeClipboardListener( this );
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
)
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();
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();
1214 TransferableDataHelper::~TransferableDataHelper()
1216 StopClipboardListening( );
1218 ::osl::MutexGuard
aGuard(mxImpl
->maMutex
);
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
);
1325 mxObjDesc
.reset(new TransferableObjectDescriptor
);
1327 if( !mxTransfer
.is() )
1330 TransferableDataHelper::FillDataFlavorExVector(mxTransfer
->getTransferDataFlavors(), maFormats
);
1332 for (auto const& format
: maFormats
)
1334 if( SotClipboardFormatId::OBJECTDESCRIPTOR
== format
.mnSotId
)
1336 ImplSetParameterString(*mxObjDesc
, format
);
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
) )
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");
1382 if (nFormat
< maFormats
.size())
1383 aRet
= maFormats
[nFormat
];
1389 Reference
< XTransferable
> TransferableDataHelper::GetXTransferable() const
1391 Reference
< XTransferable
> xRet
;
1393 if( mxTransfer
.is() )
1399 // do a dummy call to check, if this interface is valid (nasty)
1400 xRet
->getTransferDataFlavors();
1403 catch( const css::uno::Exception
& )
1413 Any
TransferableDataHelper::GetAny( SotClipboardFormatId nFormat
, const OUString
& rDestDoc
) const
1418 if ( SotExchange::GetFormatDataFlavor( nFormat
, aFlavor
) )
1419 aReturn
= GetAny(aFlavor
, rDestDoc
);
1424 Any
TransferableDataHelper::GetAny( const DataFlavor
& rFlavor
, const OUString
& rDestDoc
) const
1426 ::osl::MutexGuard
aGuard(mxImpl
->maMutex
);
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
1446 // tdf#133527: first, make sure that we actually hold the mutex
1448 // Our own thread may handle the nested IDataObject::GetData call,
1449 // and try to acquire solar mutex
1450 SolarMutexReleaser r
;
1453 if (xTransfer2
.is())
1454 aRet
= xTransfer2
->getTransferData2(format
, rDestDoc
);
1456 aRet
= mxTransfer
->getTransferData(format
);
1459 if( aRet
.hasValue() )
1464 if( !aRet
.hasValue() )
1466 // tdf#133365: only release solar mutex on Windows
1468 // tdf#133527: first, make sure that we actually hold the mutex
1470 // Our own thread may handle the nested IDataObject::GetData call,
1471 // and try to acquire solar mutex
1472 SolarMutexReleaser r
;
1475 if (xTransfer2
.is())
1476 aRet
= xTransfer2
->getTransferData2(rFlavor
, rDestDoc
);
1478 aRet
= mxTransfer
->getTransferData(rFlavor
);
1482 catch( const css::uno::Exception
& )
1490 bool TransferableDataHelper::GetString( SotClipboardFormatId nFormat
, OUString
& rStr
)
1493 return( SotExchange::GetFormatDataFlavor( nFormat
, aFlavor
) && GetString( aFlavor
, rStr
) );
1497 bool TransferableDataHelper::GetString( const DataFlavor
& rFlavor
, OUString
& rStr
)
1499 Any aAny
= GetAny(rFlavor
, OUString());
1502 if( aAny
.hasValue() )
1505 Sequence
< sal_Int8
> aSeq
;
1507 if( aAny
>>= aOUString
)
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 ) ) )
1523 rStr
= OUString( pChars
, nLen
, osl_getThreadTextEncoding() );
1532 bool TransferableDataHelper::GetBitmapEx( SotClipboardFormatId nFormat
, BitmapEx
& rBmpEx
)
1534 if(SotClipboardFormatId::BITMAP
== nFormat
)
1536 // try to get PNG first
1539 if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG
, aFlavor
))
1541 if(GetBitmapEx(aFlavor
, rBmpEx
))
1548 if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG
, aFlavor
))
1550 if(GetBitmapEx(aFlavor
, rBmpEx
))
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
;
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();
1605 if (rFilter
.ImportGraphic(aGraphic
, "", *xStm
) == ERRCODE_NONE
)
1606 rBmpEx
= aGraphic
.GetBitmapEx();
1609 if(rBmpEx
.IsEmpty())
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())
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
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
);
1665 bool TransferableDataHelper::GetGDIMetaFile(SotClipboardFormatId nFormat
, GDIMetaFile
& rMtf
, size_t nMaxActions
)
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
;
1680 if( GetSotStorageStream( rFlavor
, xStm
) )
1682 ReadGDIMetaFile( *xStm
, rMtf
);
1683 bRet
= ( xStm
->GetError() == ERRCODE_NONE
);
1687 HasFormat( SotClipboardFormatId::EMF
) &&
1688 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::EMF
, aSubstFlavor
) &&
1689 GetSotStorageStream( aSubstFlavor
, xStm
) )
1693 if( GraphicConverter::Import( *xStm
, aGraphic
) == ERRCODE_NONE
)
1695 rMtf
= aGraphic
.GetGDIMetaFile();
1701 HasFormat( SotClipboardFormatId::WMF
) &&
1702 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::WMF
, aSubstFlavor
) &&
1703 GetSotStorageStream( aSubstFlavor
, xStm
) )
1707 if( GraphicConverter::Import( *xStm
, aGraphic
) == ERRCODE_NONE
)
1709 rMtf
= aGraphic
.GetGDIMetaFile();
1718 bool TransferableDataHelper::GetGraphic( SotClipboardFormatId nFormat
, Graphic
& rGraphic
)
1720 if(SotClipboardFormatId::BITMAP
== nFormat
)
1722 // try to get PNG first
1725 if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG
, aFlavor
))
1727 if(GetGraphic(aFlavor
, rGraphic
))
1735 return( SotExchange::GetFormatDataFlavor( nFormat
, aFlavor
) && GetGraphic( aFlavor
, rGraphic
) );
1739 bool TransferableDataHelper::GetGraphic( const css::datatransfer::DataFlavor
& rFlavor
, Graphic
& rGraphic
)
1744 if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG
, aFlavor
) &&
1745 TransferableDataHelper::IsEqual(aFlavor
, rFlavor
))
1747 // try to get PNG first
1750 bRet
= GetBitmapEx( aFlavor
, aBmpEx
);
1754 else if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PDF
, aFlavor
) &&
1755 TransferableDataHelper::IsEqual(aFlavor
, rFlavor
))
1758 tools::SvRef
<SotStorageStream
> xStm
;
1759 if (GetSotStorageStream(rFlavor
, xStm
))
1761 if (GraphicConverter::Import(*xStm
, aGraphic
) == ERRCODE_NONE
)
1763 rGraphic
= aGraphic
;
1768 else if (SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG
, aFlavor
) && TransferableDataHelper::IsEqual(aFlavor
, rFlavor
))
1772 bRet
= GetBitmapEx(aFlavor
, aBitmapEx
);
1774 rGraphic
= aBitmapEx
;
1776 else if(SotExchange::GetFormatDataFlavor( SotClipboardFormatId::BITMAP
, aFlavor
) &&
1777 TransferableDataHelper::IsEqual( aFlavor
, rFlavor
) )
1781 bRet
= GetBitmapEx( aFlavor
, aBmpEx
);
1785 else if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE
, aFlavor
) &&
1786 TransferableDataHelper::IsEqual( aFlavor
, rFlavor
) )
1790 bRet
= GetGDIMetaFile( aFlavor
, aMtf
);
1796 tools::SvRef
<SotStorageStream
> xStm
;
1798 if( GetSotStorageStream( rFlavor
, xStm
) )
1800 ReadGraphic( *xStm
, rGraphic
);
1801 bRet
= ( xStm
->GetError() == ERRCODE_NONE
);
1809 bool TransferableDataHelper::GetImageMap( SotClipboardFormatId nFormat
, ImageMap
& rIMap
)
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
);
1823 rIMap
.Read( *xStm
);
1824 bRet
= ( xStm
->GetError() == ERRCODE_NONE
);
1831 bool TransferableDataHelper::GetTransferableObjectDescriptor( SotClipboardFormatId nFormat
, TransferableObjectDescriptor
& rDesc
)
1834 return( SotExchange::GetFormatDataFlavor( nFormat
, aFlavor
) && GetTransferableObjectDescriptor( rDesc
) );
1838 bool TransferableDataHelper::GetTransferableObjectDescriptor( TransferableObjectDescriptor
& rDesc
)
1845 bool TransferableDataHelper::GetINetBookmark( SotClipboardFormatId nFormat
, INetBookmark
& rBmk
)
1848 return( SotExchange::GetFormatDataFlavor( nFormat
, aFlavor
) && GetINetBookmark( aFlavor
, rBmk
) );
1852 bool TransferableDataHelper::GetINetBookmark( const css::datatransfer::DataFlavor
& rFlavor
, INetBookmark
& rBmk
)
1855 if( HasFormat( rFlavor
))
1857 const SotClipboardFormatId nFormat
= SotExchange::GetFormat( rFlavor
);
1860 case SotClipboardFormatId::SOLK
:
1861 case SotClipboardFormatId::UNIFORMRESOURCELOCATOR
:
1864 if( GetString( rFlavor
, aString
) )
1866 if( SotClipboardFormatId::UNIFORMRESOURCELOCATOR
== nFormat
)
1868 rBmk
= INetBookmark( aString
, aString
);
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
);
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() ) );
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
;
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
));
1959 bool bSttFnd
= false;
1961 while( pStream
->ReadLine( aLine
) )
1963 if (aLine
.equalsIgnoreAsciiCase("[InternetShortcut]"))
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
) );
1987 bool TransferableDataHelper::GetINetImage( SotClipboardFormatId nFormat
,
1988 INetImage
& rINtImg
)
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
);
2003 bRet
= rINtImg
.Read( *xStm
, SotExchange::GetFormat( rFlavor
) );
2008 bool TransferableDataHelper::GetFileList( SotClipboardFormatId nFormat
,
2009 FileList
& rFileList
)
2012 return( SotExchange::GetFormatDataFlavor( nFormat
, aFlavor
) && GetFileList( rFileList
) );
2016 bool TransferableDataHelper::GetFileList( FileList
& rFileList
)
2018 tools::SvRef
<SotStorageStream
> xStm
;
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
) );
2040 bRet
= ( ReadFileList( *xStm
, rFileList
).GetError() == ERRCODE_NONE
);
2049 Sequence
<sal_Int8
> TransferableDataHelper::GetSequence( SotClipboardFormatId nFormat
, const OUString
& rDestDoc
)
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())
2069 bool TransferableDataHelper::GetSotStorageStream( SotClipboardFormatId nFormat
, tools::SvRef
<SotStorageStream
>& rxStream
)
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
)
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
));
2110 void TransferableDataHelper::Rebind( const Reference
< XTransferable
>& _rxNewContent
)
2112 mxTransfer
= _rxNewContent
;
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
& )
2163 TransferableDataHelper
TransferableDataHelper::CreateFromSystemClipboard( vcl::Window
* pWindow
)
2165 DBG_ASSERT( pWindow
, "Window pointer is NULL" );
2167 Reference
< XClipboard
> xClipboard
;
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
;
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
& )
2209 bool TransferableDataHelper::IsEqual( const css::datatransfer::DataFlavor
& rInternalFlavor
,
2210 const css::datatransfer::DataFlavor
& rRequestFlavor
)
2212 Reference
< XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
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" ) )
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
) ) )
2255 catch( const css::uno::Exception
& )
2257 bRet
= rInternalFlavor
.MimeType
.equalsIgnoreAsciiCase( rRequestFlavor
.MimeType
);
2263 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */