LibreOffice Module vcl (master) 1
transfer.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#ifdef _WIN32
21#include <prewin.h>
22#include <postwin.h>
23#include <shlobj.h>
24#endif
26#include <osl/mutex.hxx>
27#include <rtl/uri.hxx>
28#include <sal/log.hxx>
29#include <tools/debug.hxx>
30#include <tools/urlobj.hxx>
32#include <sot/exchange.hxx>
33#include <sot/storage.hxx>
34#include <vcl/bitmap.hxx>
37#include <vcl/gdimtf.hxx>
38#include <vcl/graph.hxx>
39#include <vcl/cvtgrf.hxx>
40#include <vcl/svapp.hxx>
41#include <vcl/window.hxx>
46#include <sot/filelist.hxx>
48
50#include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
51#include <com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp>
52#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
53#include <com/sun/star/datatransfer/MimeContentTypeFactory.hpp>
54#include <com/sun/star/datatransfer/XMimeContentType.hpp>
55#include <com/sun/star/datatransfer/XTransferable2.hpp>
56#include <com/sun/star/frame/Desktop.hpp>
57
58#include <svl/urlbmk.hxx>
59#include <vcl/inetimg.hxx>
60#include <vcl/wmf.hxx>
61#include <vcl/imap.hxx>
62#include <vcl/transfer.hxx>
63#include <rtl/strbuf.hxx>
64#include <cstdio>
65#include <vcl/dibtools.hxx>
68#include <vcl/graphicfilter.hxx>
69#include <memory>
70#include <utility>
72
73using namespace ::com::sun::star::uno;
74using namespace ::com::sun::star::lang;
75using namespace ::com::sun::star::frame;
76using namespace ::com::sun::star::io;
77using namespace ::com::sun::star::datatransfer;
79using namespace ::com::sun::star::datatransfer::dnd;
80using namespace std::literals::string_view_literals;
81
82
83#define TOD_SIG1 0x01234567
84#define TOD_SIG2 0x89abcdef
85
87{
88 const sal_uInt32 nFirstPos = rOStm.Tell(), nViewAspect = rObjDesc.mnViewAspect;
89 const sal_uInt32 nSig1 = TOD_SIG1, nSig2 = TOD_SIG2;
90
91 rOStm.SeekRel( 4 );
92 WriteSvGlobalName( rOStm, rObjDesc.maClassName );
93 rOStm.WriteUInt32( nViewAspect );
94 rOStm.WriteInt32( rObjDesc.maSize.Width() );
95 rOStm.WriteInt32( rObjDesc.maSize.Height() );
96 rOStm.WriteInt32( rObjDesc.maDragStartPos.X() );
97 rOStm.WriteInt32( rObjDesc.maDragStartPos.Y() );
98 rOStm.WriteUniOrByteString( rObjDesc.maTypeName, osl_getThreadTextEncoding() );
99 rOStm.WriteUniOrByteString( rObjDesc.maDisplayName, osl_getThreadTextEncoding() );
100 rOStm.WriteUInt32( nSig1 ).WriteUInt32( nSig2 );
101
102 const sal_uInt32 nLastPos = rOStm.Tell();
103
104 rOStm.Seek( nFirstPos );
105 rOStm.WriteUInt32( nLastPos - nFirstPos );
106 rOStm.Seek( nLastPos );
107
108 return rOStm;
109}
110
111
112// the reading of the parameter is done using the special service css::datatransfer::MimeContentType,
113// a similar approach should be implemented for creation of the mimetype string;
114// for now the set of acceptable characters has to be hardcoded, in future it should be part of the service that creates the mimetype
115
116static OUString ImplGetParameterString( const TransferableObjectDescriptor& rObjDesc )
117{
118 const OUString aClassName( rObjDesc.maClassName.GetHexName() );
119 OUString aParams;
120
121 if( !aClassName.isEmpty() )
122 {
123 aParams += ";classname=\"" + aClassName + "\"";
124 }
125
126 if( !rObjDesc.maTypeName.isEmpty() )
127 {
128 aParams += ";typename=\"" + rObjDesc.maTypeName + "\"";
129 }
130
131 if( !rObjDesc.maDisplayName.isEmpty() )
132 {
133 // the display name might contain unacceptable characters, encode all of them
134 // this seems to be the only parameter currently that might contain such characters
135 static constexpr auto pToAccept = rtl::createUriCharClass(
136 u8"()<>@,;:/[]?=!#$&'*+-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz{|}~. ");
137
138 aParams += ";displayname=\""
139 + rtl::Uri::encode(
140 rObjDesc.maDisplayName, pToAccept.data(), rtl_UriEncodeIgnoreEscapes,
141 RTL_TEXTENCODING_UTF8)
142 + "\"";
143 }
144
145 aParams += ";viewaspect=\"" + OUString::number(rObjDesc.mnViewAspect)
146 + "\";width=\"" + OUString::number(rObjDesc.maSize.Width())
147 + "\";height=\"" + OUString::number(rObjDesc.maSize.Height())
148 + "\";posx=\"" + OUString::number(rObjDesc.maDragStartPos.X())
149 + "\";posy=\"" + OUString::number(rObjDesc.maDragStartPos.X()) + "\"";
150
151 return aParams;
152}
153
154
155static void ImplSetParameterString( TransferableObjectDescriptor& rObjDesc, const DataFlavorEx& rFlavorEx )
156{
157 Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
158
159 try
160 {
161 Reference< XMimeContentTypeFactory > xMimeFact = MimeContentTypeFactory::create( xContext );
162
163 Reference< XMimeContentType > xMimeType( xMimeFact->createMimeContentType( rFlavorEx.MimeType ) );
164
165 if( xMimeType.is() )
166 {
167 static const OUStringLiteral aClassNameString( u"classname" );
168 static const OUStringLiteral aTypeNameString( u"typename" );
169 static const OUStringLiteral aDisplayNameString( u"displayname" );
170 static const OUStringLiteral aViewAspectString( u"viewaspect" );
171 static const OUStringLiteral aWidthString( u"width" );
172 static const OUStringLiteral aHeightString( u"height" );
173 static const OUStringLiteral aPosXString( u"posx" );
174 static const OUStringLiteral aPosYString( u"posy" );
175
176 if( xMimeType->hasParameter( aClassNameString ) )
177 {
178 rObjDesc.maClassName.MakeId( xMimeType->getParameterValue( aClassNameString ) );
179 }
180
181 if( xMimeType->hasParameter( aTypeNameString ) )
182 {
183 rObjDesc.maTypeName = xMimeType->getParameterValue( aTypeNameString );
184 }
185
186 if( xMimeType->hasParameter( aDisplayNameString ) )
187 {
188 // the display name might contain unacceptable characters, in this case they should be encoded
189 // this seems to be the only parameter currently that might contain such characters
190 rObjDesc.maDisplayName = ::rtl::Uri::decode( xMimeType->getParameterValue( aDisplayNameString ), rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 );
191 }
192
193 if( xMimeType->hasParameter( aViewAspectString ) )
194 {
195 rObjDesc.mnViewAspect = static_cast< sal_uInt16 >( xMimeType->getParameterValue( aViewAspectString ).toInt32() );
196 }
197
198 if( xMimeType->hasParameter( aWidthString ) )
199 {
200 rObjDesc.maSize.setWidth( xMimeType->getParameterValue( aWidthString ).toInt32() );
201 }
202
203 if( xMimeType->hasParameter( aHeightString ) )
204 {
205 rObjDesc.maSize.setHeight( xMimeType->getParameterValue( aHeightString ).toInt32() );
206 }
207
208 if( xMimeType->hasParameter( aPosXString ) )
209 {
210 rObjDesc.maDragStartPos.setX( xMimeType->getParameterValue( aPosXString ).toInt32() );
211 }
212
213 if( xMimeType->hasParameter( aPosYString ) )
214 {
215 rObjDesc.maDragStartPos.setY( xMimeType->getParameterValue( aPosYString ).toInt32() );
216 }
217 }
218 }
219 catch( const css::uno::Exception& )
220 {
221 }
222}
223
224
226 mrParent( rTransferableHelper )
227{
228}
229
230
232{
233}
234
235
236void SAL_CALL TransferableHelper::TerminateListener::disposing( const EventObject& )
237{
238}
239
240
242{
243}
244
245
247{
248 mrParent.ImplFlush();
249}
250
252{
253 return "com.sun.star.comp.svt.TransferableHelperTerminateListener";
254}
255
256sal_Bool SAL_CALL TransferableHelper::TerminateListener::supportsService(const OUString& /*rServiceName*/)
257{
258 return false;
259}
260
262{
263 return {};
264}
267{
268 css::uno::Reference<css::frame::XTerminateListener> listener;
269 {
270 const SolarMutexGuard aGuard;
271 std::swap(listener, mxTerminateListener);
272 }
273 if (listener.is()) {
274 Desktop::create(comphelper::getProcessComponentContext())->removeTerminateListener(
275 listener);
276 }
277}
278
279Any SAL_CALL TransferableHelper::getTransferData( const DataFlavor& rFlavor )
280{
281 return getTransferData2(rFlavor, OUString());
282}
283
284Any SAL_CALL TransferableHelper::getTransferData2( const DataFlavor& rFlavor, const OUString& rDestDoc )
285{
286 if( !maAny.hasValue() || maFormats.empty() || ( maLastFormat != rFlavor.MimeType ) )
287 {
288 const SolarMutexGuard aGuard;
289
290 maLastFormat = rFlavor.MimeType;
291 maAny = Any();
292
293 try
294 {
295 DataFlavor aSubstFlavor;
296 bool bDone = false;
297
298 // add formats if not already done
299 if (maFormats.empty())
301
302 // check alien formats first and try to get a substitution format
303 if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING, aSubstFlavor ) &&
304 TransferableDataHelper::IsEqual( aSubstFlavor, rFlavor ) )
305 {
306 GetData(aSubstFlavor, rDestDoc);
307 bDone = maAny.hasValue();
308 }
309 else if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::BMP, aSubstFlavor )
310 && TransferableDataHelper::IsEqual( aSubstFlavor, rFlavor )
311 && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::BITMAP, aSubstFlavor))
312 {
313 GetData(aSubstFlavor, rDestDoc);
314 bDone = true;
315 }
316 else if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::EMF, aSubstFlavor ) &&
317 TransferableDataHelper::IsEqual( aSubstFlavor, rFlavor ) &&
318 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aSubstFlavor ) )
319 {
320 GetData(aSubstFlavor, rDestDoc);
321
322 if( maAny.hasValue() )
323 {
325
326 if( maAny >>= aSeq )
327 {
328 GDIMetaFile aMtf;
329 {
330 SvMemoryStream aSrcStm( aSeq.getArray(), aSeq.getLength(), StreamMode::WRITE | StreamMode::TRUNC );
331 SvmReader aReader( aSrcStm );
332 aReader.Read( aMtf );
333 }
334
335 Graphic aGraphic( aMtf );
336 SvMemoryStream aDstStm( 65535, 65535 );
337
339 {
340 maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aDstStm.GetData() ),
341 aDstStm.TellEnd() );
342 bDone = true;
343 }
344 }
345 }
346 }
347 else if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::WMF, aSubstFlavor ) &&
348 TransferableDataHelper::IsEqual( aSubstFlavor, rFlavor ) &&
349 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aSubstFlavor ) )
350 {
351 GetData(aSubstFlavor, rDestDoc);
352
353 if( maAny.hasValue() )
354 {
356
357 if( maAny >>= aSeq )
358 {
359 GDIMetaFile aMtf;
360 {
361 SvMemoryStream aSrcStm( aSeq.getArray(), aSeq.getLength(), StreamMode::WRITE | StreamMode::TRUNC );
362 SvmReader aReader( aSrcStm );
363 aReader.Read( aMtf );
364 }
365
366 SvMemoryStream aDstStm( 65535, 65535 );
367
368 // taking wmf without file header
369 if ( ConvertGDIMetaFileToWMF( aMtf, aDstStm, nullptr, false ) )
370 {
371 maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aDstStm.GetData() ),
372 aDstStm.TellEnd() );
373 bDone = true;
374 }
375 }
376 }
377 }
378
379 // reset Any if substitute doesn't work
380 if( !bDone && maAny.hasValue() )
381 maAny = Any();
382
383 // if any is not yet filled, use standard format
384 if( !maAny.hasValue() )
385 GetData(rFlavor, rDestDoc);
386 }
387 catch( const css::uno::Exception& )
388 {
389 }
390
391 if( !maAny.hasValue() )
392 throw UnsupportedFlavorException();
393 }
394
395 return maAny;
396}
397
399{
400 // By default everything is complex, until proven otherwise
401 // in the respective document type transferable handler.
402 return true;
403}
404
405Sequence< DataFlavor > SAL_CALL TransferableHelper::getTransferDataFlavors()
406{
407 const SolarMutexGuard aGuard;
408
409 try
410 {
411 if(maFormats.empty())
413 }
414 catch( const css::uno::Exception& )
415 {
416 }
417
418 return comphelper::containerToSequence<DataFlavor>(maFormats);
419}
420
421
422sal_Bool SAL_CALL TransferableHelper::isDataFlavorSupported( const DataFlavor& rFlavor )
423{
424 const SolarMutexGuard aGuard;
425
426 try
427 {
428 if (maFormats.empty())
430 }
431 catch( const css::uno::Exception& )
432 {
433 }
434
435 for (auto const& format : maFormats)
436 {
437 if( TransferableDataHelper::IsEqual( format, rFlavor ) )
438 {
439 return true;
440 }
441 }
442
443 return false;
444}
445
446
447void SAL_CALL TransferableHelper::lostOwnership( const Reference< XClipboard >&, const Reference< XTransferable >& )
448{
449 const SolarMutexGuard aGuard;
450
451 try
452 {
453 if( mxTerminateListener.is() )
454 {
455 Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
456 xDesktop->removeTerminateListener( mxTerminateListener );
457
458 mxTerminateListener.clear();
459 }
460
462 }
463 catch( const css::uno::Exception& )
464 {
465 }
466}
467
468
469void SAL_CALL TransferableHelper::disposing( const EventObject& )
470{
471}
472
473
474void SAL_CALL TransferableHelper::dragDropEnd( const DragSourceDropEvent& rDSDE )
475{
476 const SolarMutexGuard aGuard;
477
478 try
479 {
480 DragFinished( rDSDE.DropSuccess ? ( rDSDE.DropAction & ~DNDConstants::ACTION_DEFAULT ) : DNDConstants::ACTION_NONE );
482 }
483 catch( const css::uno::Exception& )
484 {
485 }
486}
487
488
489void SAL_CALL TransferableHelper::dragEnter( const DragSourceDragEvent& )
490{
491}
492
493
494void SAL_CALL TransferableHelper::dragExit( const DragSourceEvent& )
495{
496}
497
498
499void SAL_CALL TransferableHelper::dragOver( const DragSourceDragEvent& )
500{
501}
502
503
504void SAL_CALL TransferableHelper::dropActionChanged( const DragSourceDragEvent& )
505{
506}
507
508
510{
511 return comphelper::getSomethingImpl(rId, this);
512}
513
514
516{
517 if( !mxClipboard.is() )
518 return;
519
520 Reference< XFlushableClipboard > xFlushableClipboard( mxClipboard, UNO_QUERY );
521 SolarMutexReleaser aReleaser;
522
523 try
524 {
525 if( xFlushableClipboard.is() )
526 xFlushableClipboard->flushClipboard();
527 }
528 catch( const css::uno::Exception& )
529 {
530 OSL_FAIL( "Could not flush clipboard" );
531 }
532}
533
534
536{
537 DataFlavor aFlavor;
538
539 if( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) )
540 AddFormat( aFlavor );
541}
542
543
544void TransferableHelper::AddFormat( const DataFlavor& rFlavor )
545{
546 bool bAdd = true;
547
548 for (auto & format : maFormats)
549 {
550 if( TransferableDataHelper::IsEqual( format, rFlavor ) )
551 {
552 // update MimeType for SotClipboardFormatId::OBJECTDESCRIPTOR in every case
553 if ((SotClipboardFormatId::OBJECTDESCRIPTOR == format.mnSotId) && mxObjDesc)
554 {
555 DataFlavor aObjDescFlavor;
556
557 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDescFlavor );
558 format.MimeType = aObjDescFlavor.MimeType;
559 format.MimeType += ::ImplGetParameterString(*mxObjDesc);
560 }
561
562 bAdd = false;
563 break;
564 }
565 }
566
567 if( !bAdd )
568 return;
569
570 DataFlavorEx aFlavorEx;
571
572 aFlavorEx.MimeType = rFlavor.MimeType;
573 aFlavorEx.HumanPresentableName = rFlavor.HumanPresentableName;
574 aFlavorEx.DataType = rFlavor.DataType;
575 aFlavorEx.mnSotId = SotExchange::RegisterFormat( rFlavor );
576
577 if ((SotClipboardFormatId::OBJECTDESCRIPTOR == aFlavorEx.mnSotId) && mxObjDesc)
578 aFlavorEx.MimeType += ::ImplGetParameterString(*mxObjDesc);
579
580 maFormats.push_back(aFlavorEx);
581
582 if( SotClipboardFormatId::BITMAP == aFlavorEx.mnSotId )
583 {
584 AddFormat( SotClipboardFormatId::PNG );
585 AddFormat( SotClipboardFormatId::BMP );
586 }
587 else if( SotClipboardFormatId::GDIMETAFILE == aFlavorEx.mnSotId )
588 {
589 AddFormat( SotClipboardFormatId::EMF );
590 AddFormat( SotClipboardFormatId::WMF );
591 }
592}
593
594
596{
597 DataFlavor aFlavor;
598
599 if( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) )
600 RemoveFormat( aFlavor );
601}
602
603
604void TransferableHelper::RemoveFormat( const DataFlavor& rFlavor )
605{
606 DataFlavorExVector::iterator aIter(maFormats.begin());
607
608 while (aIter != maFormats.end())
609 {
610 if( TransferableDataHelper::IsEqual( *aIter, rFlavor ) )
611 aIter = maFormats.erase(aIter);
612 else
613 ++aIter;
614 }
615}
616
617
619{
620 return std::any_of(maFormats.begin(), maFormats.end(),
621 [&](const DataFlavorEx& data) { return data.mnSotId == nFormat; });
622}
623
624
626{
627 maFormats.clear();
628 maAny.clear();
629}
630
631
632bool TransferableHelper::SetAny( const Any& rAny )
633{
634 maAny = rAny;
635 return maAny.hasValue();
636}
637
638
639bool TransferableHelper::SetString( const OUString& rString )
640{
641 maAny <<= rString;
642 return maAny.hasValue();
643}
644
645
646bool TransferableHelper::SetBitmapEx( const BitmapEx& rBitmapEx, const DataFlavor& rFlavor )
647{
648 if( !rBitmapEx.IsEmpty() )
649 {
650 SvMemoryStream aMemStm( 65535, 65535 );
651
652 if(rFlavor.MimeType.equalsIgnoreAsciiCase("image/png"))
653 {
654 // write a PNG
655 css::uno::Sequence<css::beans::PropertyValue> aFilterData;
656
657#ifdef IOS
658 // Use faster compression on slow devices
659 aFilterData.realloc(aFilterData.getLength() + 1);
660 aFilterData.getArray()[aFilterData.getLength() - 1].Name = "Compression";
661
662 // We "know" that this gets passed to zlib's deflateInit2_(). 1 means best speed. For a
663 // typical 15 megapixel image from a DSLR, we are talking about a difference of 17 s for
664 // the default compression level vs 4 s for best speed, on an iPad Pro from 2017.
665 //
666 // Sure, the best would be to not have to re-encode the image at all, but have access to
667 // the original JPEG or PNG when there is a such.
668
669 aFilterData.getArray()[aFilterData.getLength() - 1].Value <<= 1;
670#endif
671 vcl::PngImageWriter aPNGWriter(aMemStm);
672 aPNGWriter.setParameters(aFilterData);
673 aPNGWriter.write(rBitmapEx);
674 }
675 else
676 {
677 // explicitly use Bitmap::Write with bCompressed = sal_False and bFileHeader = sal_True
678 WriteDIB(rBitmapEx.GetBitmap(), aMemStm, false, true);
679 }
680
681 maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() );
682 }
683
684 return maAny.hasValue();
685}
686
687
689{
690 if( rMtf.GetActionSize() )
691 {
692 SvMemoryStream aMemStm( 65535, 65535 );
693
694 SvmWriter aWriter( aMemStm );
695 aWriter.Write( rMtf );
696 maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() );
697 }
698
699 return maAny.hasValue();
700}
701
702
704{
705 if( rGraphic.GetType() != GraphicType::NONE )
706 {
707 SvMemoryStream aMemStm( 65535, 65535 );
708
710 aMemStm.SetCompressMode( SvStreamCompressFlags::NATIVE );
711
712 TypeSerializer aSerializer(aMemStm);
713 aSerializer.writeGraphic(rGraphic);
714
715 maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() );
716 }
717
718 return maAny.hasValue();
719}
720
721
723{
724 SvMemoryStream aMemStm( 8192, 8192 );
725
727 rIMap.Write( aMemStm );
728 maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() );
729
730 return maAny.hasValue();
731}
732
733
735{
736 PrepareOLE( rDesc );
737
738 SvMemoryStream aMemStm( 1024, 1024 );
739
740 WriteTransferableObjectDescriptor( aMemStm, rDesc );
741 maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Tell() );
742
743 return maAny.hasValue();
744 }
745
746
748 const css::datatransfer::DataFlavor& rFlavor )
749{
750 rtl_TextEncoding eSysCSet = osl_getThreadTextEncoding();
751
752 switch( SotExchange::GetFormat( rFlavor ) )
753 {
754 case SotClipboardFormatId::SOLK:
755 {
756 OString sURL(OUStringToOString(rBmk.GetURL(), eSysCSet));
757 OString sDesc(OUStringToOString(rBmk.GetDescription(), eSysCSet));
758 OStringBuffer sOut;
759 sOut.append(sURL.getLength());
760 sOut.append("@" + sURL);
761 sOut.append(sDesc.getLength());
762 sOut.append("@" + sDesc);
763
764 Sequence< sal_Int8 > aSeq(sOut.getLength());
765 memcpy(aSeq.getArray(), sOut.getStr(), sOut.getLength());
766 maAny <<= aSeq;
767 }
768 break;
769
770 case SotClipboardFormatId::STRING:
771 case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
772 maAny <<= rBmk.GetURL();
773 break;
774
775 case SotClipboardFormatId::NETSCAPE_BOOKMARK:
776 {
778 char* pSeq = reinterpret_cast< char* >( aSeq.getArray() );
779
780 // strncpy fills the rest with nulls, as we need
781 strncpy( pSeq, OUStringToOString(rBmk.GetURL(), eSysCSet).getStr(), 1024 );
782 strncpy( pSeq + 1024, OUStringToOString(rBmk.GetDescription(), eSysCSet).getStr(), 1024 );
783
784 maAny <<= aSeq;
785 }
786 break;
787
788#ifdef _WIN32
789 case SotClipboardFormatId::FILEGRPDESCRIPTOR:
790 {
791 Sequence< sal_Int8 > aSeq( sizeof( FILEGROUPDESCRIPTORW ) );
792 FILEGROUPDESCRIPTORW* pFDesc = reinterpret_cast<FILEGROUPDESCRIPTORW*>(aSeq.getArray());
793 FILEDESCRIPTORW& rFDesc1 = pFDesc->fgd[ 0 ];
794
795 pFDesc->cItems = 1;
796 memset( &rFDesc1, 0, sizeof( rFDesc1 ) );
797 rFDesc1.dwFlags = FD_LINKUI;
798
799 OUStringBuffer aStr(rBmk.GetDescription());
800 for( size_t nChar = 0; (nChar = std::u16string_view(aStr).find_first_of(u"\\/:*?\"<>|"sv, nChar)) != std::u16string_view::npos; )
801 aStr.remove(nChar, 1);
802
803 aStr.insert(0, "Shortcut to ");
804 aStr.append(".URL");
805 wcscpy( rFDesc1.cFileName, o3tl::toW(aStr.getStr()) );
806
807 maAny <<= aSeq;
808 }
809 break;
810
811 case SotClipboardFormatId::FILECONTENT:
812 {
813 maAny <<= "[InternetShortcut]\x0aURL=" + rBmk.GetURL();
814 }
815 break;
816#endif
817
818 default:
819 break;
820 }
821
822 return maAny.hasValue();
823}
824
825
827 const css::datatransfer::DataFlavor& rFlavor )
828{
829 SvMemoryStream aMemStm( 1024, 1024 );
830
832 rINtImg.Write( aMemStm, SotExchange::GetFormat( rFlavor ) );
833
834 maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() );
835
836 return maAny.hasValue();
837}
838
839
840bool TransferableHelper::SetObject( void* pUserObject, sal_uInt32 nUserObjectId, const DataFlavor& rFlavor )
841{
842 tools::SvRef<SotTempStream> xStm( new SotTempStream( OUString() ) );
843
844 xStm->SetVersion( SOFFICE_FILEFORMAT_50 );
845
846 if( pUserObject && WriteObject( xStm, pUserObject, nUserObjectId, rFlavor ) )
847 {
848 const sal_uInt32 nLen = xStm->TellEnd();
850
851 xStm->Seek( STREAM_SEEK_TO_BEGIN );
852 xStm->ReadBytes(aSeq.getArray(), nLen);
853
854 if( nLen && ( SotExchange::GetFormat( rFlavor ) == SotClipboardFormatId::STRING ) )
855 {
856 //JP 24.7.2001: as I know was this only for the writer application and this
857 // writes now UTF16 format into the stream
858 //JP 6.8.2001: and now it writes UTF8 because then exist no problem with
859 // little / big endians! - Bug 88121
860 maAny <<= OUString( reinterpret_cast< const char* >( aSeq.getConstArray() ), nLen - 1, RTL_TEXTENCODING_UTF8 );
861 }
862 else
863 maAny <<= aSeq;
864 }
865
866 return maAny.hasValue();
867}
868
869
870bool TransferableHelper::WriteObject( tools::SvRef<SotTempStream>&, void*, sal_uInt32, const DataFlavor& )
871{
872 OSL_FAIL( "TransferableHelper::WriteObject( ... ) not implemented" );
873 return false;
874}
875
876
878{
879}
880
881
883{
884}
885
886
888{
889 mxObjDesc.reset(new TransferableObjectDescriptor(rObjDesc));
890
891 if( HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ) )
892 AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
893}
894
895void TransferableHelper::CopyToClipboard(const Reference<XClipboard>& rClipboard) const
896{
897 if( rClipboard.is() )
898 mxClipboard = rClipboard;
899
900 if( !mxClipboard.is() || mxTerminateListener.is() )
901 return;
902
903 try
904 {
905 TransferableHelper* pThis = const_cast< TransferableHelper* >( this );
906 pThis->mxTerminateListener = new TerminateListener( *pThis );
907 Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
908 xDesktop->addTerminateListener( pThis->mxTerminateListener );
909
910 mxClipboard->setContents( pThis, pThis );
911 }
912 catch( const css::uno::Exception& )
913 {
914 }
915}
916
918{
919 DBG_ASSERT( pWindow, "Window pointer is NULL" );
920 Reference< XClipboard > xClipboard;
921
922 if( pWindow )
923 xClipboard = pWindow->GetClipboard();
924
925 CopyToClipboard(xClipboard);
926}
927
928void TransferableHelper::CopyToSelection(const Reference<XClipboard>& rSelection) const
929{
930 if( !rSelection.is() || mxTerminateListener.is() )
931 return;
932
933 try
934 {
935 TransferableHelper* pThis = const_cast< TransferableHelper* >( this );
936 pThis->mxTerminateListener = new TerminateListener( *pThis );
937 Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
938 xDesktop->addTerminateListener( pThis->mxTerminateListener );
939
940 rSelection->setContents( pThis, pThis );
941 }
942 catch( const css::uno::Exception& )
943 {
944 }
945}
946
948{
950}
951
952void TransferableHelper::StartDrag( vcl::Window* pWindow, sal_Int8 nDnDSourceActions )
953
954{
955 DBG_ASSERT( pWindow, "Window pointer is NULL" );
956 Reference< XDragSource > xDragSource( pWindow->GetDragSource() );
957
958 if( !xDragSource.is() )
959 return;
960
961 /*
962 * #96792# release mouse before actually starting DnD.
963 * This is necessary for the X11 DnD implementation to work.
964 */
965 if( pWindow->IsMouseCaptured() )
966 pWindow->ReleaseMouse();
967
968 const Point aPt( pWindow->GetPointerPosPixel() );
969
970 // On macOS we are forced to execute 'startDrag' synchronously
971 // contrary to the XDragSource interface specification because
972 // we can receive drag events from the system only in the main
973 // thread
974#if !defined(MACOSX)
975 SolarMutexReleaser aReleaser;
976#endif
977
978 try
979 {
980 DragGestureEvent aEvt;
981 aEvt.DragAction = DNDConstants::ACTION_COPY;
982 aEvt.DragOriginX = aPt.X();
983 aEvt.DragOriginY = aPt.Y();
984 aEvt.DragSource = xDragSource;
985
986 xDragSource->startDrag( aEvt, nDnDSourceActions, DND_POINTER_NONE, DND_IMAGE_NONE, this, this );
987 }
988 catch( const css::uno::Exception& )
989 {
990 }
991}
992
994{
995 Reference< XClipboard > xSelection(GetSystemPrimarySelection());
996
997 if( xSelection.is() )
998 xSelection->setContents( nullptr, nullptr );
999}
1000
1002{
1003 static const comphelper::UnoIdInit theTransferableHelperUnoTunnelId;
1004 return theTransferableHelperUnoTunnelId.getSeq();
1005}
1006
1007namespace {
1008
1009class TransferableClipboardNotifier : public ::cppu::WeakImplHelper< XClipboardListener >
1010{
1011private:
1012 ::osl::Mutex& mrMutex;
1013 Reference< XClipboardNotifier > mxNotifier;
1015
1016protected:
1017 // XClipboardListener
1018 virtual void SAL_CALL changedContents( const clipboard::ClipboardEvent& event ) override;
1019
1020 // XEventListener
1021 virtual void SAL_CALL disposing( const EventObject& Source ) override;
1022
1023public:
1024 TransferableClipboardNotifier( const Reference< XClipboard >& _rxClipboard, TransferableDataHelper& _rListener, ::osl::Mutex& _rMutex );
1025
1027 bool isListening() const { return mpListener != nullptr; }
1028
1030 void dispose();
1031};
1032
1033}
1034
1035TransferableClipboardNotifier::TransferableClipboardNotifier( const Reference< XClipboard >& _rxClipboard, TransferableDataHelper& _rListener, ::osl::Mutex& _rMutex )
1036 :mrMutex( _rMutex )
1037 ,mxNotifier( _rxClipboard, UNO_QUERY )
1038 ,mpListener( &_rListener )
1039{
1040 osl_atomic_increment( &m_refCount );
1041 {
1042 if ( mxNotifier.is() )
1043 mxNotifier->addClipboardListener( this );
1044 else
1045 // born dead
1046 mpListener = nullptr;
1047 }
1048 osl_atomic_decrement( &m_refCount );
1049}
1050
1051
1052void SAL_CALL TransferableClipboardNotifier::changedContents( const clipboard::ClipboardEvent& event )
1053{
1054 SolarMutexGuard aSolarGuard;
1055 // the SolarMutex here is necessary, since
1056 // - we cannot call mpListener without our own mutex locked
1057 // - Rebind respectively InitFormats (called by Rebind) will
1058 // try to lock the SolarMutex, too
1059 ::osl::MutexGuard aGuard( mrMutex );
1060 if( mpListener )
1061 mpListener->Rebind( event.Contents );
1062}
1063
1064
1065void SAL_CALL TransferableClipboardNotifier::disposing( const EventObject& )
1066{
1067 // clipboard is being disposed. Hmm. Okay, become disfunctional myself.
1068 dispose();
1069}
1070
1071
1072void TransferableClipboardNotifier::dispose()
1073{
1074 ::osl::MutexGuard aGuard( mrMutex );
1075
1076 Reference< XClipboardListener > xKeepMeAlive( this );
1077
1078 if ( mxNotifier.is() )
1079 mxNotifier->removeClipboardListener( this );
1080 mxNotifier.clear();
1081
1082 mpListener = nullptr;
1083}
1084
1086{
1087 ::osl::Mutex maMutex;
1089
1091 {
1092 }
1093};
1094
1096 : mxObjDesc(new TransferableObjectDescriptor)
1097 , mxImpl(new TransferableDataHelper_Impl)
1098{
1099}
1100
1101TransferableDataHelper::TransferableDataHelper(const Reference< css::datatransfer::XTransferable >& rxTransferable)
1102 : mxTransfer(rxTransferable)
1103 , mxObjDesc(new TransferableObjectDescriptor)
1104 , mxImpl(new TransferableDataHelper_Impl)
1105{
1106 InitFormats();
1107}
1108
1110 : mxTransfer(rDataHelper.mxTransfer)
1111 , mxClipboard(rDataHelper.mxClipboard)
1112 , maFormats(rDataHelper.maFormats)
1113 , mxObjDesc(new TransferableObjectDescriptor(*rDataHelper.mxObjDesc))
1114 , mxImpl(new TransferableDataHelper_Impl)
1115{
1116}
1117
1119 : mxTransfer(std::move(rDataHelper.mxTransfer))
1120 , mxClipboard(std::move(rDataHelper.mxClipboard))
1121 , maFormats(std::move(rDataHelper.maFormats))
1122 , mxObjDesc(std::move(rDataHelper.mxObjDesc))
1123 , mxImpl(new TransferableDataHelper_Impl)
1124{
1125}
1126
1128{
1129 if ( this != &rDataHelper )
1130 {
1131 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1132
1133 const bool bWasClipboardListening = mxImpl->mxClipboardListener.is();
1134
1135 if (bWasClipboardListening)
1137
1138 mxTransfer = rDataHelper.mxTransfer;
1139 maFormats = rDataHelper.maFormats;
1140 mxObjDesc.reset(new TransferableObjectDescriptor(*rDataHelper.mxObjDesc));
1141 mxClipboard = rDataHelper.mxClipboard;
1142
1143 if (bWasClipboardListening)
1145 }
1146
1147 return *this;
1148}
1149
1151{
1152 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1153
1154 const bool bWasClipboardListening = mxImpl->mxClipboardListener.is();
1155
1156 if (bWasClipboardListening)
1158
1159 mxTransfer = std::move(rDataHelper.mxTransfer);
1160 maFormats = std::move(rDataHelper.maFormats);
1161 mxObjDesc = std::move(rDataHelper.mxObjDesc);
1162 mxClipboard = std::move(rDataHelper.mxClipboard);
1163
1164 if (bWasClipboardListening)
1166
1167 return *this;
1168}
1169
1171{
1173 {
1174 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1175 maFormats.clear();
1176 mxObjDesc.reset();
1177 }
1178}
1179
1180void TransferableDataHelper::FillDataFlavorExVector( const Sequence< DataFlavor >& rDataFlavorSeq,
1181 DataFlavorExVector& rDataFlavorExVector )
1182{
1183 try
1184 {
1185 Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
1186 Reference< XMimeContentTypeFactory > xMimeFact = MimeContentTypeFactory::create( xContext );
1187 DataFlavorEx aFlavorEx;
1188 static const OUStringLiteral aCharsetStr( u"charset" );
1189
1190
1191 for (auto const& rFlavor : rDataFlavorSeq)
1192 {
1193 Reference< XMimeContentType > xMimeType;
1194
1195 try
1196 {
1197 if( !rFlavor.MimeType.isEmpty() )
1198 xMimeType = xMimeFact->createMimeContentType( rFlavor.MimeType );
1199 }
1200 catch( const css::uno::Exception& )
1201 {
1202 }
1203
1204 aFlavorEx.MimeType = rFlavor.MimeType;
1205 aFlavorEx.HumanPresentableName = rFlavor.HumanPresentableName;
1206 aFlavorEx.DataType = rFlavor.DataType;
1207 aFlavorEx.mnSotId = SotExchange::RegisterFormat( rFlavor );
1208
1209 rDataFlavorExVector.push_back( aFlavorEx );
1210
1211 // add additional formats for special mime types
1212 if(SotClipboardFormatId::BMP == aFlavorEx.mnSotId || SotClipboardFormatId::PNG == aFlavorEx.mnSotId || SotClipboardFormatId::JPEG == aFlavorEx.mnSotId)
1213 {
1214 if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::BITMAP, aFlavorEx ) )
1215 {
1216 aFlavorEx.mnSotId = SotClipboardFormatId::BITMAP;
1217 rDataFlavorExVector.push_back( aFlavorEx );
1218 }
1219 }
1220 else if( SotClipboardFormatId::WMF == aFlavorEx.mnSotId || SotClipboardFormatId::EMF == aFlavorEx.mnSotId )
1221 {
1222 if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aFlavorEx ) )
1223 {
1224 aFlavorEx.mnSotId = SotClipboardFormatId::GDIMETAFILE;
1225 rDataFlavorExVector.push_back( aFlavorEx );
1226 }
1227 }
1228 else if ( SotClipboardFormatId::HTML_SIMPLE == aFlavorEx.mnSotId )
1229 {
1230 // #104735# HTML_SIMPLE may also be inserted without comments
1231 aFlavorEx.mnSotId = SotClipboardFormatId::HTML_NO_COMMENT;
1232 rDataFlavorExVector.push_back( aFlavorEx );
1233 }
1234 else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/plain" ) )
1235 {
1236 // add, if it is a UTF-8 byte buffer
1237 if( xMimeType->hasParameter( aCharsetStr ) )
1238 {
1239 if( xMimeType->getParameterValue( aCharsetStr ).equalsIgnoreAsciiCase( "unicode" ) ||
1240 xMimeType->getParameterValue( aCharsetStr ).equalsIgnoreAsciiCase( "utf-16" ) )
1241 {
1242 rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::STRING;
1243
1244 }
1245 }
1246 }
1247 else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/rtf" ) )
1248 {
1249 rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::RTF;
1250 }
1251 else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/richtext" ) )
1252 {
1253 rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::RICHTEXT;
1254 }
1255 else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/html" ) )
1256
1257 {
1258 rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::HTML;
1259 }
1260 else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/uri-list" ) )
1261 {
1262 rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::FILE_LIST;
1263 }
1264 else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "application/x-openoffice-objectdescriptor-xml" ) )
1265 {
1266 rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::OBJECTDESCRIPTOR;
1267 }
1268 }
1269 }
1270 catch( const css::uno::Exception& )
1271 {
1272 }
1273}
1274
1276{
1277 SolarMutexGuard aSolarGuard;
1278 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1279
1280 maFormats.clear();
1282
1283 if( !mxTransfer.is() )
1284 return;
1285
1287
1288 for (auto const& format : maFormats)
1289 {
1290 if( SotClipboardFormatId::OBJECTDESCRIPTOR == format.mnSotId )
1291 {
1293 break;
1294 }
1295 }
1296}
1297
1298
1300{
1301 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1302 return std::any_of(maFormats.begin(), maFormats.end(),
1303 [&](const DataFlavorEx& data) { return data.mnSotId == nFormat; });
1304}
1305
1306bool TransferableDataHelper::HasFormat( const DataFlavor& rFlavor ) const
1307{
1308 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1309 for (auto const& format : maFormats)
1310 {
1311 if( TransferableDataHelper::IsEqual( rFlavor, format ) )
1312 return true;
1313 }
1314
1315 return false;
1316}
1317
1319{
1320 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1321 return maFormats.size();
1322}
1323
1325{
1326 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1327 DBG_ASSERT(nFormat < maFormats.size(), "TransferableDataHelper::GetFormat: invalid format index");
1328 return( ( nFormat < maFormats.size() ) ? maFormats[ nFormat ].mnSotId : SotClipboardFormatId::NONE );
1329}
1330
1331DataFlavor TransferableDataHelper::GetFormatDataFlavor( sal_uInt32 nFormat ) const
1332{
1333 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1334 DBG_ASSERT(nFormat < maFormats.size(), "TransferableDataHelper::GetFormat: invalid format index");
1335
1336 DataFlavor aRet;
1337
1338 if (nFormat < maFormats.size())
1339 aRet = maFormats[nFormat];
1340
1341 return aRet;
1342}
1343
1344
1345Reference< XTransferable > TransferableDataHelper::GetXTransferable() const
1346{
1347 Reference< XTransferable > xRet;
1348
1349 if( mxTransfer.is() )
1350 {
1351 try
1352 {
1353 xRet = mxTransfer;
1354
1355 // do a dummy call to check, if this interface is valid (nasty)
1356 xRet->getTransferDataFlavors();
1357
1358 }
1359 catch( const css::uno::Exception& )
1360 {
1361 xRet.clear();
1362 }
1363 }
1364
1365 return xRet;
1366}
1367
1368
1369Any TransferableDataHelper::GetAny( SotClipboardFormatId nFormat, const OUString& rDestDoc ) const
1370{
1371 Any aReturn;
1372
1373 DataFlavor aFlavor;
1374 if ( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) )
1375 aReturn = GetAny(aFlavor, rDestDoc);
1376
1377 return aReturn;
1378}
1379
1380Any TransferableDataHelper::GetAny( const DataFlavor& rFlavor, const OUString& rDestDoc ) const
1381{
1382 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1383 Any aRet;
1384
1385 try
1386 {
1387 if( mxTransfer.is() )
1388 {
1389 const SotClipboardFormatId nRequestFormat = SotExchange::GetFormat( rFlavor );
1390
1391 Reference<css::datatransfer::XTransferable2> xTransfer2(mxTransfer, UNO_QUERY);
1392
1393 if( nRequestFormat != SotClipboardFormatId::NONE )
1394 {
1395 // try to get alien format first
1396 for (auto const& format : maFormats)
1397 {
1398 if( ( nRequestFormat == format.mnSotId ) && !rFlavor.MimeType.equalsIgnoreAsciiCase( format.MimeType ) )
1399 {
1400// tdf#133365: only release solar mutex on Windows
1401#ifdef _WIN32
1402 // tdf#133527: first, make sure that we actually hold the mutex
1404 // Our own thread may handle the nested IDataObject::GetData call,
1405 // and try to acquire solar mutex
1407#endif // _WIN32
1408
1409 if (xTransfer2.is())
1410 aRet = xTransfer2->getTransferData2(format, rDestDoc);
1411 else
1412 aRet = mxTransfer->getTransferData(format);
1413 }
1414
1415 if( aRet.hasValue() )
1416 break;
1417 }
1418 }
1419
1420 if( !aRet.hasValue() )
1421 {
1422// tdf#133365: only release solar mutex on Windows
1423#ifdef _WIN32
1424 // tdf#133527: first, make sure that we actually hold the mutex
1426 // Our own thread may handle the nested IDataObject::GetData call,
1427 // and try to acquire solar mutex
1429#endif // _WIN32
1430
1431 if (xTransfer2.is())
1432 aRet = xTransfer2->getTransferData2(rFlavor, rDestDoc);
1433 else
1434 aRet = mxTransfer->getTransferData(rFlavor);
1435 }
1436 }
1437 }
1438 catch( const css::uno::Exception& )
1439 {
1440 }
1441
1442 return aRet;
1443}
1444
1445
1446bool TransferableDataHelper::GetString( SotClipboardFormatId nFormat, OUString& rStr ) const
1447{
1448 DataFlavor aFlavor;
1449 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetString( aFlavor, rStr ) );
1450}
1451
1452
1453bool TransferableDataHelper::GetString( const DataFlavor& rFlavor, OUString& rStr ) const
1454{
1455 Any aAny = GetAny(rFlavor, OUString());
1456 bool bRet = false;
1457
1458 if( aAny.hasValue() )
1459 {
1460 OUString aOUString;
1462
1463 if( aAny >>= aOUString )
1464 {
1465 rStr = aOUString;
1466 bRet = true;
1467 }
1468 else if( aAny >>= aSeq )
1469 {
1470
1471 const char* pChars = reinterpret_cast< const char* >( aSeq.getConstArray() );
1472 sal_Int32 nLen = aSeq.getLength();
1473
1474 //JP 10.10.2001: 92930 - don't copy the last zero character into the string.
1475 //DVO 2002-05-27: strip _all_ trailing zeros
1476 while( nLen && ( 0 == *( pChars + nLen - 1 ) ) )
1477 --nLen;
1478
1479 rStr = OUString( pChars, nLen, osl_getThreadTextEncoding() );
1480 bRet = true;
1481 }
1482 }
1483
1484 return bRet;
1485}
1486
1487
1489{
1490 if(SotClipboardFormatId::BITMAP == nFormat)
1491 {
1492 // try to get PNG first
1493 DataFlavor aFlavor;
1494
1495 if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor))
1496 {
1497 if(GetBitmapEx(aFlavor, rBmpEx))
1498 {
1499 return true;
1500 }
1501 }
1502
1503 // then JPEG
1504 if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG, aFlavor))
1505 {
1506 if(GetBitmapEx(aFlavor, rBmpEx))
1507 {
1508 return true;
1509 }
1510 }
1511 }
1512
1513 DataFlavor aFlavor;
1514 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetBitmapEx( aFlavor, rBmpEx ) );
1515}
1516
1517
1518bool TransferableDataHelper::GetBitmapEx( const DataFlavor& rFlavor, BitmapEx& rBmpEx ) const
1519{
1521 DataFlavor aSubstFlavor;
1522 bool bRet(GetSotStorageStream(rFlavor, xStm));
1523 bool bSuppressPNG(false); // #122982# If PNG stream not accessed, but BMP one, suppress trying to load PNG
1524 bool bSuppressJPEG(false);
1525
1526 if(!bRet && HasFormat(SotClipboardFormatId::PNG) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aSubstFlavor))
1527 {
1528 // when no direct success, try if PNG is available
1529 bRet = GetSotStorageStream(aSubstFlavor, xStm);
1530 bSuppressJPEG = bRet;
1531 }
1532
1533 if(!bRet && HasFormat(SotClipboardFormatId::JPEG) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG, aSubstFlavor))
1534 {
1535 bRet = GetSotStorageStream(aSubstFlavor, xStm);
1536 bSuppressPNG = bRet;
1537 }
1538
1539 if(!bRet && HasFormat(SotClipboardFormatId::BMP) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::BMP, aSubstFlavor))
1540 {
1541 // when no direct success, try if BMP is available
1542 bRet = GetSotStorageStream(aSubstFlavor, xStm);
1543 bSuppressPNG = bRet;
1544 bSuppressJPEG = bRet;
1545 }
1546
1547 if(bRet)
1548 {
1549 if(!bSuppressPNG && rFlavor.MimeType.equalsIgnoreAsciiCase("image/png"))
1550 {
1551 // it's a PNG, import to BitmapEx
1552 vcl::PngImageReader aPNGReader(*xStm);
1553 rBmpEx = aPNGReader.read();
1554 }
1555 else if(!bSuppressJPEG && rFlavor.MimeType.equalsIgnoreAsciiCase("image/jpeg"))
1556 {
1557 // it's a JPEG, import to BitmapEx
1559 Graphic aGraphic;
1560 if (rFilter.ImportGraphic(aGraphic, u"", *xStm) == ERRCODE_NONE)
1561 rBmpEx = aGraphic.GetBitmapEx();
1562 }
1563
1564 if(rBmpEx.IsEmpty())
1565 {
1566 Bitmap aBitmap;
1567 AlphaMask aMask;
1568
1569 // explicitly use Bitmap::Read with bFileHeader = sal_True
1570 // #i124085# keep DIBV5 for read from clipboard, but should not happen
1571 ReadDIBV5(aBitmap, aMask, *xStm);
1572
1573 if(aMask.GetBitmap().IsEmpty())
1574 {
1575 rBmpEx = aBitmap;
1576 }
1577 else
1578 {
1579 rBmpEx = BitmapEx(aBitmap, aMask);
1580 }
1581 }
1582
1583 bRet = (ERRCODE_NONE == xStm->GetError() && !rBmpEx.IsEmpty());
1584
1585 /* SJ: #110748# At the moment we are having problems with DDB inserted as DIB. The
1586 problem is, that some graphics are inserted much too big because the nXPelsPerMeter
1587 and nYPelsPerMeter of the bitmap fileheader isn't including the correct value.
1588 Due to this reason the following code assumes that bitmaps with a logical size
1589 greater than 50 cm aren't having the correct mapmode set.
1590
1591 The following code should be removed if DDBs and DIBs are supported via clipboard
1592 properly.
1593 */
1594 if(bRet)
1595 {
1596 const MapMode aMapMode(rBmpEx.GetPrefMapMode());
1597
1598 if(MapUnit::MapPixel != aMapMode.GetMapUnit())
1599 {
1600 const Size aSize(OutputDevice::LogicToLogic(rBmpEx.GetPrefSize(), aMapMode, MapMode(MapUnit::Map100thMM)));
1601
1602 // #i122388# This wrongly corrects in the given case; changing from 5000 100th mm to
1603 // the described 50 cm (which is 50000 100th mm)
1604 if((aSize.Width() > 50000) || (aSize.Height() > 50000))
1605 {
1606 rBmpEx.SetPrefMapMode(MapMode(MapUnit::MapPixel));
1607
1608 // #i122388# also adapt size by applying the mew MapMode
1609 const Size aNewSize(o3tl::convert(aSize, o3tl::Length::mm100, o3tl::Length::pt));
1610 rBmpEx.SetPrefSize(aNewSize);
1611 }
1612 }
1613 }
1614 }
1615
1616 return bRet;
1617}
1618
1619
1621{
1622 DataFlavor aFlavor;
1623 return SotExchange::GetFormatDataFlavor(nFormat, aFlavor) &&
1624 GetGDIMetaFile(aFlavor, rMtf) &&
1625 (nMaxActions == 0 || rMtf.GetActionSize() < nMaxActions);
1626}
1627
1628
1629bool TransferableDataHelper::GetGDIMetaFile( const DataFlavor& rFlavor, GDIMetaFile& rMtf ) const
1630{
1632 DataFlavor aSubstFlavor;
1633 bool bRet = false;
1634
1635 if( GetSotStorageStream( rFlavor, xStm ) )
1636 {
1637 SvmReader aReader( *xStm );
1638 aReader.Read( rMtf );
1639 bRet = ( xStm->GetError() == ERRCODE_NONE );
1640 }
1641
1642 if( !bRet &&
1643 HasFormat( SotClipboardFormatId::EMF ) &&
1644 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::EMF, aSubstFlavor ) &&
1645 GetSotStorageStream( aSubstFlavor, xStm ) )
1646 {
1647 Graphic aGraphic;
1648
1649 if( GraphicConverter::Import( *xStm, aGraphic ) == ERRCODE_NONE )
1650 {
1651 rMtf = aGraphic.GetGDIMetaFile();
1652 bRet = true;
1653 }
1654 }
1655
1656 if( !bRet &&
1657 HasFormat( SotClipboardFormatId::WMF ) &&
1658 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::WMF, aSubstFlavor ) &&
1659 GetSotStorageStream( aSubstFlavor, xStm ) )
1660 {
1661 Graphic aGraphic;
1662
1663 if( GraphicConverter::Import( *xStm, aGraphic ) == ERRCODE_NONE )
1664 {
1665 rMtf = aGraphic.GetGDIMetaFile();
1666 bRet = true;
1667 }
1668 }
1669
1670 return bRet;
1671}
1672
1673
1675{
1676 if(SotClipboardFormatId::BITMAP == nFormat)
1677 {
1678 // try to get PNG first
1679 DataFlavor aFlavor;
1680
1681 if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor))
1682 {
1683 if(GetGraphic(aFlavor, rGraphic))
1684 {
1685 return true;
1686 }
1687 }
1688 }
1689
1690 DataFlavor aFlavor;
1691 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetGraphic( aFlavor, rGraphic ) );
1692}
1693
1694
1695bool TransferableDataHelper::GetGraphic( const css::datatransfer::DataFlavor& rFlavor, Graphic& rGraphic ) const
1696{
1697 DataFlavor aFlavor;
1698 bool bRet = false;
1699
1700 if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor) &&
1701 TransferableDataHelper::IsEqual(aFlavor, rFlavor))
1702 {
1703 // try to get PNG first
1704 BitmapEx aBmpEx;
1705
1706 bRet = GetBitmapEx( aFlavor, aBmpEx );
1707 if( bRet )
1708 rGraphic = aBmpEx;
1709 }
1710 else if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PDF, aFlavor) &&
1711 TransferableDataHelper::IsEqual(aFlavor, rFlavor))
1712 {
1713 Graphic aGraphic;
1715 if (GetSotStorageStream(rFlavor, xStm))
1716 {
1717 if (GraphicConverter::Import(*xStm, aGraphic) == ERRCODE_NONE)
1718 {
1719 rGraphic = aGraphic;
1720 bRet = true;
1721 }
1722 }
1723 }
1724 else if (SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG, aFlavor) && TransferableDataHelper::IsEqual(aFlavor, rFlavor))
1725 {
1726 BitmapEx aBitmapEx;
1727
1728 bRet = GetBitmapEx(aFlavor, aBitmapEx);
1729 if (bRet)
1730 rGraphic = aBitmapEx;
1731 }
1732 else if(SotExchange::GetFormatDataFlavor( SotClipboardFormatId::BITMAP, aFlavor ) &&
1733 TransferableDataHelper::IsEqual( aFlavor, rFlavor ) )
1734 {
1735 BitmapEx aBmpEx;
1736
1737 bRet = GetBitmapEx( aFlavor, aBmpEx );
1738 if( bRet )
1739 rGraphic = aBmpEx;
1740 }
1741 else if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aFlavor ) &&
1742 TransferableDataHelper::IsEqual( aFlavor, rFlavor ) )
1743 {
1744 GDIMetaFile aMtf;
1745
1746 bRet = GetGDIMetaFile( aFlavor, aMtf );
1747 if( bRet )
1748 rGraphic = aMtf;
1749 }
1750 else
1751 {
1753
1754 if( GetSotStorageStream( rFlavor, xStm ) )
1755 {
1756 TypeSerializer aSerializer(*xStm);
1757 aSerializer.readGraphic(rGraphic);
1758 bRet = ( xStm->GetError() == ERRCODE_NONE );
1759 }
1760 }
1761
1762 return bRet;
1763}
1764
1765
1767{
1768 DataFlavor aFlavor;
1769 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetImageMap( aFlavor, rIMap ) );
1770}
1771
1772
1773bool TransferableDataHelper::GetImageMap( const css::datatransfer::DataFlavor& rFlavor, ImageMap& rIMap ) const
1774{
1776 bool bRet = GetSotStorageStream( rFlavor, xStm );
1777
1778 if( bRet )
1779 {
1780 rIMap.Read( *xStm );
1781 bRet = ( xStm->GetError() == ERRCODE_NONE );
1782 }
1783
1784 return bRet;
1785}
1786
1787
1789{
1790 DataFlavor aFlavor;
1791 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetTransferableObjectDescriptor( rDesc ) );
1792}
1793
1794
1796{
1797 rDesc = *mxObjDesc;
1798 return true;
1799}
1800
1801
1803{
1804 DataFlavor aFlavor;
1805 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetINetBookmark( aFlavor, rBmk ) );
1806}
1807
1808
1809bool TransferableDataHelper::GetINetBookmark( const css::datatransfer::DataFlavor& rFlavor, INetBookmark& rBmk ) const
1810{
1811 if( !HasFormat( rFlavor ))
1812 return false;
1813
1814 bool bRet = false;
1815 const SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
1816 switch( nFormat )
1817 {
1818 case SotClipboardFormatId::SOLK:
1819 case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
1820 {
1821 OUString aString;
1822 if( GetString( rFlavor, aString ) )
1823 {
1824 if( SotClipboardFormatId::UNIFORMRESOURCELOCATOR == nFormat )
1825 {
1826 rBmk = INetBookmark( aString, aString );
1827 bRet = true;
1828 }
1829 else
1830 {
1831 OUString aURL, aDesc;
1832 sal_Int32 nStart = aString.indexOf( '@' ), nLen = aString.toInt32();
1833
1834 if( !nLen && aString[ 0 ] != '0' )
1835 {
1836 SAL_INFO( "svtools", "SOLK: 1. len=0" );
1837 }
1838 if( nStart == -1 || nLen > aString.getLength() - nStart - 3 )
1839 {
1840 SAL_INFO( "svtools", "SOLK: 1. illegal start or wrong len" );
1841 }
1842 aURL = aString.copy( nStart + 1, nLen );
1843
1844 aString = aString.replaceAt( 0, nStart + 1 + nLen, u"" );
1845 nStart = aString.indexOf( '@' );
1846 nLen = aString.toInt32();
1847
1848 if( !nLen && aString[ 0 ] != '0' )
1849 {
1850 SAL_INFO( "svtools", "SOLK: 2. len=0" );
1851 }
1852 if( nStart == -1 || nLen > aString.getLength() - nStart - 1 )
1853 {
1854 SAL_INFO( "svtools", "SOLK: 2. illegal start or wrong len" );
1855 }
1856 aDesc = aString.copy( nStart+1, nLen );
1857
1858 rBmk = INetBookmark( aURL, aDesc );
1859 bRet = true;
1860 }
1861 }
1862 }
1863 break;
1864
1865 case SotClipboardFormatId::NETSCAPE_BOOKMARK:
1866 {
1867 Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
1868
1869 if (2048 == aSeq.getLength())
1870 {
1871 const char* p1 = reinterpret_cast< const char* >( aSeq.getConstArray() );
1872 const char* p2 = reinterpret_cast< const char* >( aSeq.getConstArray() ) + 1024;
1873 rBmk = INetBookmark( OUString( p1, strlen(p1), osl_getThreadTextEncoding() ),
1874 OUString( p2, strlen(p2), osl_getThreadTextEncoding() ) );
1875 bRet = true;
1876 }
1877 }
1878 break;
1879
1880#ifdef _WIN32
1881 case SotClipboardFormatId::FILEGRPDESCRIPTOR:
1882 {
1883 Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
1884
1885 if (aSeq.getLength())
1886 {
1887 FILEGROUPDESCRIPTORW const * pFDesc = reinterpret_cast<FILEGROUPDESCRIPTORW const *>(aSeq.getConstArray());
1888
1889 if( pFDesc->cItems )
1890 {
1891 OUString aDesc( o3tl::toU(pFDesc->fgd[ 0 ].cFileName) );
1892
1893 if( ( aDesc.getLength() > 4 ) && aDesc.endsWithIgnoreAsciiCase(".URL") )
1894 {
1895 std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( INetURLObject( aDesc ).GetMainURL( INetURLObject::DecodeMechanism::NONE ),
1896 StreamMode::STD_READ ));
1897
1898 if( !pStream || pStream->GetError() )
1899 {
1900 DataFlavor aFileContentFlavor;
1901
1902 aSeq.realloc( 0 );
1903 pStream.reset();
1904
1905 if (SotExchange::GetFormatDataFlavor(SotClipboardFormatId::FILECONTENT, aFileContentFlavor))
1906 {
1907 aSeq = GetSequence(aFileContentFlavor, OUString());
1908 if (aSeq.getLength())
1909 pStream.reset(new SvMemoryStream( const_cast<sal_Int8 *>(aSeq.getConstArray()), aSeq.getLength(), StreamMode::STD_READ ));
1910 }
1911 }
1912
1913 if( pStream )
1914 {
1915 OString aLine;
1916 bool bInA = false, bInW = false, bAFound = false;
1917
1918 while( pStream->ReadLine( aLine ) )
1919 {
1920 if (aLine.startsWithIgnoreAsciiCase("[InternetShortcut", &aLine))
1921 {
1922 // May be [InternetShortcut], or [InternetShortcut.A], or
1923 // [InternetShortcut.W] (the latter has UTF-7-encoded URL)
1924 bInW = aLine.equalsIgnoreAsciiCase(".W]");
1925 bInA = !bAFound && !bInW
1926 && (aLine == "]" || aLine.equalsIgnoreAsciiCase(".A]"));
1927 }
1928 else if (aLine.startsWith("["))
1929 {
1930 bInA = bInW = false;
1931 }
1932 else if ((bInA || bInW) && aLine.startsWithIgnoreAsciiCase("URL="))
1933 {
1934 auto eTextEncoding = bInW ? RTL_TEXTENCODING_UTF7
1935 : osl_getThreadTextEncoding();
1936 rBmk = INetBookmark( OStringToOUString(aLine.subView(4), eTextEncoding),
1937 aDesc.copy(0, aDesc.getLength() - 4) );
1938 bRet = true;
1939 if (bInW)
1940 break;
1941 else
1942 bAFound = true; // Keep looking for "W"
1943 }
1944 }
1945 }
1946 }
1947 }
1948 }
1949 }
1950 break;
1951#endif
1952 default: break;
1953 }
1954 return bRet;
1955}
1956
1957
1959 INetImage& rINtImg ) const
1960{
1961 DataFlavor aFlavor;
1962 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetINetImage( aFlavor, rINtImg ) );
1963}
1964
1965
1967 const css::datatransfer::DataFlavor& rFlavor,
1968 INetImage& rINtImg ) const
1969{
1971 bool bRet = GetSotStorageStream( rFlavor, xStm );
1972
1973 if( bRet )
1974 bRet = rINtImg.Read( *xStm, SotExchange::GetFormat( rFlavor ) );
1975 return bRet;
1976}
1977
1978
1980 FileList& rFileList ) const
1981{
1982 DataFlavor aFlavor;
1983 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetFileList( rFileList ) );
1984}
1985
1986
1988{
1990 bool bRet = false;
1991
1992 for( sal_uInt32 i = 0, nFormatCount = GetFormatCount(); ( i < nFormatCount ) && !bRet; ++i )
1993 {
1994 if( SotClipboardFormatId::FILE_LIST == GetFormat( i ) )
1995 {
1996 const DataFlavor aFlavor( GetFormatDataFlavor( i ) );
1997
1998 if( GetSotStorageStream( aFlavor, xStm ) )
1999 {
2000 if( aFlavor.MimeType.indexOf( "text/uri-list" ) > -1 )
2001 {
2002 OStringBuffer aDiskString;
2003
2004 while( xStm->ReadLine( aDiskString ) )
2005 if( !aDiskString.isEmpty() && aDiskString[0] != '#' )
2006 rFileList.AppendFile( OStringToOUString(aDiskString, RTL_TEXTENCODING_UTF8) );
2007
2008 bRet = true;
2009 }
2010 else
2011 bRet = ( ReadFileList( *xStm, rFileList ).GetError() == ERRCODE_NONE );
2012 }
2013 }
2014 }
2015
2016 return bRet;
2017}
2018
2019
2020Sequence<sal_Int8> TransferableDataHelper::GetSequence( SotClipboardFormatId nFormat, const OUString& rDestDoc ) const
2021{
2022 DataFlavor aFlavor;
2023 if (!SotExchange::GetFormatDataFlavor(nFormat, aFlavor))
2024 return Sequence<sal_Int8>();
2025
2026 return GetSequence(aFlavor, rDestDoc);
2027}
2028
2029Sequence<sal_Int8> TransferableDataHelper::GetSequence( const DataFlavor& rFlavor, const OUString& rDestDoc ) const
2030{
2031 const Any aAny = GetAny(rFlavor, rDestDoc);
2032 Sequence<sal_Int8> aSeq;
2033 if (aAny.hasValue())
2034 aAny >>= aSeq;
2035
2036 return aSeq;
2037}
2038
2039
2041{
2042 DataFlavor aFlavor;
2043 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetSotStorageStream( aFlavor, rxStream ) );
2044}
2045
2046
2047bool TransferableDataHelper::GetSotStorageStream( const DataFlavor& rFlavor, tools::SvRef<SotTempStream>& rxStream ) const
2048{
2049 Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
2050
2051 if (aSeq.hasElements())
2052 {
2053 rxStream = new SotTempStream( "" );
2054 rxStream->WriteBytes( aSeq.getConstArray(), aSeq.getLength() );
2055 rxStream->Seek( 0 );
2056 }
2057
2058 return aSeq.hasElements();
2059}
2060
2061Reference<XInputStream> TransferableDataHelper::GetInputStream( SotClipboardFormatId nFormat, const OUString& rDestDoc ) const
2062{
2063 DataFlavor aFlavor;
2064 if (!SotExchange::GetFormatDataFlavor(nFormat, aFlavor))
2065 return Reference<XInputStream>();
2066
2067 return GetInputStream(aFlavor, rDestDoc);
2068}
2069
2070Reference<XInputStream> TransferableDataHelper::GetInputStream( const DataFlavor& rFlavor, const OUString& rDestDoc ) const
2071{
2072 Sequence<sal_Int8> aSeq = GetSequence(rFlavor, rDestDoc);
2073
2074 if (!aSeq.hasElements())
2075 return Reference<XInputStream>();
2076
2077 Reference<XInputStream> xStream(new comphelper::SequenceInputStream(aSeq));
2078 return xStream;
2079}
2080
2081void TransferableDataHelper::Rebind( const Reference< XTransferable >& _rxNewContent )
2082{
2083 mxTransfer = _rxNewContent;
2084 InitFormats();
2085}
2086
2088{
2089 ::osl::MutexGuard aGuard(mxImpl->maMutex);
2090
2092
2093 mxImpl->mxClipboardListener = new TransferableClipboardNotifier(mxClipboard, *this, mxImpl->maMutex);
2094
2095 return mxImpl->mxClipboardListener->isListening();
2096}
2097
2099{
2100 ::osl::MutexGuard aGuard(mxImpl->maMutex);
2101
2102 if (mxImpl->mxClipboardListener.is())
2103 {
2104 mxImpl->mxClipboardListener->dispose();
2105 mxImpl->mxClipboardListener.clear();
2106 }
2107}
2108
2109TransferableDataHelper TransferableDataHelper::CreateFromClipboard(const css::uno::Reference<css::datatransfer::clipboard::XClipboard>& rClipboard)
2110{
2112
2113 if( rClipboard.is() )
2114 {
2115 try
2116 {
2117 Reference< XTransferable > xTransferable( rClipboard->getContents() );
2118
2119 if( xTransferable.is() )
2120 {
2121 aRet = TransferableDataHelper( xTransferable );
2122 // also copy the clipboard
2123 aRet.mxClipboard = rClipboard;
2124 }
2125 }
2126 catch( const css::uno::Exception& )
2127 {
2128 }
2129 }
2130
2131 return aRet;
2132}
2133
2135{
2136 DBG_ASSERT( pWindow, "Window pointer is NULL" );
2137
2138 Reference< XClipboard > xClipboard;
2139
2140 if( pWindow )
2141 xClipboard = pWindow->GetClipboard();
2142
2143 return CreateFromClipboard(xClipboard);
2144}
2145
2147{
2148 Reference< XClipboard > xSelection(GetSystemPrimarySelection());
2150
2151 if( xSelection.is() )
2152 {
2153 SolarMutexReleaser aReleaser;
2154
2155 try
2156 {
2157 Reference< XTransferable > xTransferable( xSelection->getContents() );
2158
2159 if( xTransferable.is() )
2160 {
2161 aRet = TransferableDataHelper( xTransferable );
2162 aRet.mxClipboard = xSelection;
2163 }
2164 }
2165 catch( const css::uno::Exception& )
2166 {
2167 }
2168 }
2169
2170 return aRet;
2171}
2172
2173bool TransferableDataHelper::IsEqual( const css::datatransfer::DataFlavor& rInternalFlavor,
2174 const css::datatransfer::DataFlavor& rRequestFlavor )
2175{
2176 Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
2177 bool bRet = false;
2178
2179 try
2180 {
2181 Reference< XMimeContentTypeFactory > xMimeFact = MimeContentTypeFactory::create( xContext );
2182
2183 Reference< XMimeContentType > xRequestType1( xMimeFact->createMimeContentType( rInternalFlavor.MimeType ) );
2184 Reference< XMimeContentType > xRequestType2( xMimeFact->createMimeContentType( rRequestFlavor.MimeType ) );
2185
2186 if( xRequestType1.is() && xRequestType2.is() )
2187 {
2188 if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( xRequestType2->getFullMediaType() ) )
2189 {
2190 if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( "text/plain" ) )
2191 {
2192 // special handling for text/plain media types
2193 static const OUStringLiteral aCharsetString( u"charset" );
2194
2195 if( !xRequestType2->hasParameter( aCharsetString ) ||
2196 xRequestType2->getParameterValue( aCharsetString ).equalsIgnoreAsciiCase( "utf-16" ) ||
2197 xRequestType2->getParameterValue( aCharsetString ).equalsIgnoreAsciiCase( "unicode" ) )
2198 {
2199 bRet = true;
2200 }
2201 }
2202 else if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( "application/x-openoffice" ) )
2203 {
2204 // special handling for application/x-openoffice media types
2205 static const OUStringLiteral aFormatString( u"windows_formatname" );
2206
2207 if( xRequestType1->hasParameter( aFormatString ) &&
2208 xRequestType2->hasParameter( aFormatString ) &&
2209 xRequestType1->getParameterValue( aFormatString ).equalsIgnoreAsciiCase( xRequestType2->getParameterValue( aFormatString ) ) )
2210 {
2211 bRet = true;
2212 }
2213 }
2214 else
2215 bRet = true;
2216 }
2217 }
2218 }
2219 catch( const css::uno::Exception& )
2220 {
2221 bRet = rInternalFlavor.MimeType.equalsIgnoreAsciiCase( rRequestFlavor.MimeType );
2222 }
2223
2224 return bRet;
2225}
2226
2227/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XInputStream > xStream
BaseContainerNodeSharedPtr & mrParent
Bitmap const & GetBitmap() const
Definition: alpha.cxx:73
void SetPrefMapMode(const MapMode &rPrefMapMode)
Definition: bitmapex.hxx:79
void SetPrefSize(const Size &rPrefSize)
Definition: bitmapex.hxx:76
bool IsEmpty() const
Definition: BitmapEx.cxx:177
Bitmap GetBitmap(Color aTransparentReplaceColor) const
Definition: BitmapEx.cxx:203
const MapMode & GetPrefMapMode() const
Definition: bitmapex.hxx:78
const Size & GetPrefSize() const
Definition: bitmapex.hxx:75
bool IsEmpty() const
void AppendFile(const OUString &rStr)
size_t GetActionSize() const
Definition: gdimtf.cxx:179
static ErrCode Import(SvStream &rIStm, Graphic &rGraphic, ConvertDataFormat nFormat=ConvertDataFormat::Unknown)
Definition: cvtgrf.cxx:30
static ErrCode Export(SvStream &rOStm, const Graphic &rGraphic, ConvertDataFormat nFormat)
Definition: cvtgrf.cxx:51
Class to import and export graphic formats.
static GraphicFilter & GetGraphicFilter()
ErrCode ImportGraphic(Graphic &rGraphic, const INetURLObject &rPath, sal_uInt16 nFormat=GRFILTER_FORMAT_DONTKNOW, sal_uInt16 *pDeterminedFormat=nullptr, GraphicFilterImportFlags nImportFlags=GraphicFilterImportFlags::NONE)
const GDIMetaFile & GetGDIMetaFile() const
Definition: graph.cxx:339
GraphicType GetType() const
Definition: graph.cxx:293
BitmapEx GetBitmapEx(const GraphicConversionParameters &rParameters=GraphicConversionParameters()) const
Definition: graph.cxx:329
const OUString & GetDescription() const
const OUString & GetURL() const
bool Read(SvStream &rIStm, SotClipboardFormatId nFormat)
Definition: inetimg.cxx:59
void Write(SvStream &rOStm, SotClipboardFormatId nFormat) const
Definition: inetimg.cxx:29
void Write(SvStream &rOStm) const
Definition: imap.cxx:920
void Read(SvStream &rIStm)
Definition: imap.cxx:956
SAL_WARN_UNUSED_RESULT Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
Definition: map.cxx:1639
constexpr tools::Long Height() const
void setWidth(tools::Long nWidth)
void setHeight(tools::Long nHeight)
constexpr tools::Long Width() const
A helper class that calls Application::ReleaseSolarMutex() in its constructor and restores the mutex ...
Definition: svapp.hxx:1443
static bool GetFormatDataFlavor(SotClipboardFormatId nFormat, css::datatransfer::DataFlavor &rFlavor)
static SotClipboardFormatId GetFormat(const css::datatransfer::DataFlavor &rFlavor)
static SotClipboardFormatId RegisterFormat(const css::datatransfer::DataFlavor &rFlavor)
OUString GetHexName() const
bool MakeId(std::u16string_view rId)
const void * GetData()
virtual sal_uInt64 TellEnd() override
SvStream & WriteInt32(sal_Int32 nInt32)
sal_uInt64 Tell() const
void SetCompressMode(SvStreamCompressFlags nNewMode)
SvStream & WriteUniOrByteString(std::u16string_view rStr, rtl_TextEncoding eDestCharSet)
SvStream & WriteUInt32(sal_uInt32 nUInt32)
void SetVersion(sal_Int32 n)
sal_uInt64 Seek(sal_uInt64 nPos)
sal_uInt64 SeekRel(sal_Int64 nPos)
ErrCode GetError() const
SvStream & Read(GDIMetaFile &rMetaFile, ImplMetaReadData *pData=nullptr)
Definition: SvmReader.cxx:63
SvStream & Write(const GDIMetaFile &rMetaFile)
Definition: SvmWriter.cxx:38
sal_uInt32 GetFormatCount() const
Definition: transfer.cxx:1318
std::unique_ptr< TransferableObjectDescriptor > mxObjDesc
Definition: transfer.hxx:285
css::uno::Reference< css::datatransfer::XTransferable > mxTransfer
Definition: transfer.hxx:282
static bool IsEqual(const css::datatransfer::DataFlavor &rInternalFlavor, const css::datatransfer::DataFlavor &rRequestFlavor)
Definition: transfer.cxx:2173
css::uno::Sequence< sal_Int8 > GetSequence(SotClipboardFormatId nFormat, const OUString &rDestDoc) const
Definition: transfer.cxx:2020
bool GetTransferableObjectDescriptor(SotClipboardFormatId nFormat, TransferableObjectDescriptor &rDesc)
Definition: transfer.cxx:1788
static TransferableDataHelper CreateFromPrimarySelection()
Definition: transfer.cxx:2146
static TransferableDataHelper CreateFromClipboard(const css::uno::Reference< css::datatransfer::clipboard::XClipboard > &rClipboard)
Definition: transfer.cxx:2109
bool GetString(SotClipboardFormatId nFormat, OUString &rStr) const
Definition: transfer.cxx:1446
TransferableDataHelper & operator=(const TransferableDataHelper &rDataHelper)
Definition: transfer.cxx:1127
SotClipboardFormatId GetFormat(sal_uInt32 nFormat) const
Definition: transfer.cxx:1324
std::unique_ptr< TransferableDataHelper_Impl > mxImpl
Definition: transfer.hxx:286
bool GetImageMap(SotClipboardFormatId nFormat, ImageMap &rIMap) const
Definition: transfer.cxx:1766
css::uno::Any GetAny(SotClipboardFormatId nFormat, const OUString &rDestDoc) const
Definition: transfer.cxx:1369
bool GetFileList(SotClipboardFormatId nFormat, FileList &rFileList) const
Definition: transfer.cxx:1979
css::uno::Reference< css::io::XInputStream > GetInputStream(SotClipboardFormatId nFormat, const OUString &rDestDoc) const
Definition: transfer.cxx:2061
bool GetSotStorageStream(SotClipboardFormatId nFormat, tools::SvRef< SotTempStream > &rStreamRef) const
Definition: transfer.cxx:2040
bool GetGDIMetaFile(SotClipboardFormatId nFormat, GDIMetaFile &rMtf, size_t nMaxActions=0) const
Return as GDI metafile.
Definition: transfer.cxx:1620
void Rebind(const css::uno::Reference< css::datatransfer::XTransferable > &_rxNewData)
Definition: transfer.cxx:2081
static TransferableDataHelper CreateFromSystemClipboard(vcl::Window *pWindow)
Definition: transfer.cxx:2134
bool HasFormat(SotClipboardFormatId nFormat) const
Definition: transfer.cxx:1299
bool GetINetImage(SotClipboardFormatId nFormat, INetImage &rINtImg) const
Definition: transfer.cxx:1958
static void FillDataFlavorExVector(const css::uno::Sequence< css::datatransfer::DataFlavor > &rDataFlavorSeq, DataFlavorExVector &rDataFlavorExVector)
Definition: transfer.cxx:1180
css::uno::Reference< css::datatransfer::clipboard::XClipboard > mxClipboard
Definition: transfer.hxx:283
bool GetBitmapEx(SotClipboardFormatId nFormat, BitmapEx &rBmp) const
Definition: transfer.cxx:1488
DataFlavorExVector maFormats
Definition: transfer.hxx:284
css::datatransfer::DataFlavor GetFormatDataFlavor(sal_uInt32 nFormat) const
Definition: transfer.cxx:1331
bool GetGraphic(SotClipboardFormatId nFormat, Graphic &rGraphic) const
Definition: transfer.cxx:1674
bool GetINetBookmark(SotClipboardFormatId nFormat, INetBookmark &rBmk) const
Definition: transfer.cxx:1802
css::uno::Reference< css::datatransfer::XTransferable > GetXTransferable() const
Definition: transfer.cxx:1345
virtual ~TerminateListener() override
Definition: transfer.cxx:231
virtual OUString SAL_CALL getImplementationName() override
Definition: transfer.cxx:251
virtual sal_Bool SAL_CALL supportsService(const OUString &sServiceName) override
Definition: transfer.cxx:256
TerminateListener(TransferableHelper &rDropTargetHelper)
Definition: transfer.cxx:225
virtual void SAL_CALL queryTermination(const css::lang::EventObject &aEvent) override
Definition: transfer.cxx:241
virtual void SAL_CALL notifyTermination(const css::lang::EventObject &aEvent) override
Definition: transfer.cxx:246
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
Definition: transfer.cxx:261
virtual void SAL_CALL disposing(const css::lang::EventObject &Source) override
Definition: transfer.cxx:236
virtual css::uno::Sequence< css::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors() override
Definition: transfer.cxx:405
void StartDrag(vcl::Window *pWindow, sal_Int8 nDragSourceActions)
Definition: transfer.cxx:952
virtual css::uno::Any SAL_CALL getTransferData(const css::datatransfer::DataFlavor &rFlavor) override
Definition: transfer.cxx:279
bool SetGraphic(const Graphic &rGraphic)
Definition: transfer.cxx:703
virtual void SAL_CALL dragEnter(const css::datatransfer::dnd::DragSourceDragEvent &dsde) override
Definition: transfer.cxx:489
virtual sal_Bool SAL_CALL isDataFlavorSupported(const css::datatransfer::DataFlavor &rFlavor) override
Definition: transfer.cxx:422
void CopyToClipboard(const css::uno::Reference< css::datatransfer::clipboard::XClipboard > &rClipboard) const
virtual sal_Int64 SAL_CALL getSomething(const css::uno::Sequence< sal_Int8 > &rId) override
Definition: transfer.cxx:509
bool SetTransferableObjectDescriptor(const TransferableObjectDescriptor &rDesc)
Definition: transfer.cxx:734
bool SetAny(const css::uno::Any &rAny)
Definition: transfer.cxx:632
virtual void SAL_CALL dragDropEnd(const css::datatransfer::dnd::DragSourceDropEvent &dsde) override
Definition: transfer.cxx:474
void CopyToSelection(const css::uno::Reference< css::datatransfer::clipboard::XClipboard > &rClipboard) const
Definition: transfer.cxx:928
bool SetObject(void *pUserObject, sal_uInt32 nUserObjectId, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:840
void RemoveFormat(SotClipboardFormatId nFormat)
Definition: transfer.cxx:595
bool SetString(const OUString &rString)
Definition: transfer.cxx:639
virtual void SAL_CALL dragOver(const css::datatransfer::dnd::DragSourceDragEvent &dsde) override
Definition: transfer.cxx:499
virtual bool WriteObject(tools::SvRef< SotTempStream > &rxOStm, void *pUserObject, sal_uInt32 nUserObjectId, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:870
static void ClearPrimarySelection()
Definition: transfer.cxx:993
virtual css::uno::Any SAL_CALL getTransferData2(const css::datatransfer::DataFlavor &rFlavor, const OUString &rDestDoc) override
Definition: transfer.cxx:284
virtual void SAL_CALL dropActionChanged(const css::datatransfer::dnd::DragSourceDragEvent &dsde) override
Definition: transfer.cxx:504
virtual void DragFinished(sal_Int8 nDropAction)
Definition: transfer.cxx:877
VCL_DLLPRIVATE void ImplFlush()
Definition: transfer.cxx:515
bool SetINetImage(const INetImage &rINtImg, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:826
void CopyToPrimarySelection() const
Definition: transfer.cxx:947
bool SetBitmapEx(const BitmapEx &rBitmap, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:646
bool SetINetBookmark(const INetBookmark &rBmk, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:747
virtual void SAL_CALL disposing(const css::lang::EventObject &Source) override
Definition: transfer.cxx:469
bool HasFormat(SotClipboardFormatId nFormat)
Definition: transfer.cxx:618
void PrepareOLE(const TransferableObjectDescriptor &rObjDesc)
Definition: transfer.cxx:887
css::uno::Any maAny
Definition: transfer.hxx:169
void AddFormat(SotClipboardFormatId nFormat)
Definition: transfer.cxx:535
virtual bool GetData(const css::datatransfer::DataFlavor &rFlavor, const OUString &rDestDoc)=0
std::unique_ptr< TransferableObjectDescriptor > mxObjDesc
Definition: transfer.hxx:174
virtual void AddSupportedFormats()=0
static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId()
Definition: transfer.cxx:1001
virtual sal_Bool SAL_CALL isComplex() override
Definition: transfer.cxx:398
bool SetImageMap(const ImageMap &rIMap)
Definition: transfer.cxx:722
css::uno::Reference< css::frame::XTerminateListener > mxTerminateListener
Definition: transfer.hxx:172
OUString maLastFormat
Definition: transfer.hxx:170
virtual void SAL_CALL dragExit(const css::datatransfer::dnd::DragSourceEvent &dse) override
Definition: transfer.cxx:494
virtual void ObjectReleased()
Definition: transfer.cxx:882
bool SetGDIMetaFile(const GDIMetaFile &rMtf)
Definition: transfer.cxx:688
css::uno::Reference< css::datatransfer::clipboard::XClipboard > mxClipboard
Definition: transfer.hxx:171
virtual void SAL_CALL lostOwnership(const css::uno::Reference< css::datatransfer::clipboard::XClipboard > &xClipboard, const css::uno::Reference< css::datatransfer::XTransferable > &xTrans) override
Definition: transfer.cxx:447
DataFlavorExVector maFormats
Definition: transfer.hxx:173
void readGraphic(Graphic &rGraphic)
void writeGraphic(const Graphic &rGraphic)
const css::uno::Sequence< sal_Int8 > & getSeq() const
static std::unique_ptr< SvStream > CreateStream(const OUString &rFileName, StreamMode eOpenMode, css::uno::Reference< css::awt::XWindow > xParentWin=nullptr)
void setParameters(css::uno::Sequence< css::beans::PropertyValue > const &rParameters)
bool write(const BitmapEx &rBitmap)
bool IsMouseCaptured() const
Definition: mouse.cxx:481
void ReleaseMouse()
Definition: mouse.cxx:469
Point GetPointerPosPixel()
Definition: mouse.cxx:564
css::uno::Reference< css::datatransfer::dnd::XDragSource > GetDragSource()
Definition: mouse.cxx:733
css::uno::Reference< css::datatransfer::clipboard::XClipboard > GetClipboard()
Definition: window.cxx:3446
#define DBG_ASSERT(sCon, aError)
bool WriteDIB(const Bitmap &rSource, SvStream &rOStm, bool bCompressed, bool bFileHeader)
Definition: dibtools.cxx:1832
bool ReadDIBV5(Bitmap &rTarget, AlphaMask &rTargetAlpha, SvStream &rIStm)
Definition: dibtools.cxx:1808
URL aURL
float u
#define ERRCODE_NONE
::std::vector< DataFlavorEx > DataFlavorExVector
#define SOFFICE_FILEFORMAT_50
SvStream & ReadFileList(SvStream &rIStm, FileList &rFileList)
SotClipboardFormatId
SvStream & WriteSvGlobalName(SvStream &rOStr, const SvGlobalName &rObj)
IntrinsicAnimationEventHandlerSharedPtr mpListener
Sequence< sal_Int8 > aSeq
#define SAL_INFO(area, stream)
aStr
sal_Int64 getSomethingImpl(const css::uno::Sequence< sal_Int8 > &rId, T *pThis, FallbackToGetSomethingOf< Base >={})
Reference< XComponentContext > getProcessComponentContext()
int i
constexpr Point convert(const Point &rPoint, o3tl::Length eFrom, o3tl::Length eTo)
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
void dispose()
#define STREAM_SEEK_TO_BEGIN
SotClipboardFormatId mnSotId
rtl::Reference< TransferableClipboardNotifier > mxClipboardListener
Definition: transfer.cxx:1088
Reference< XClipboard > GetSystemPrimarySelection()
Definition: transfer2.cxx:493
static void ImplSetParameterString(TransferableObjectDescriptor &rObjDesc, const DataFlavorEx &rFlavorEx)
Definition: transfer.cxx:155
#define TOD_SIG1
Definition: transfer.cxx:83
SvStream & WriteTransferableObjectDescriptor(SvStream &rOStm, const TransferableObjectDescriptor &rObjDesc)
Definition: transfer.cxx:86
static OUString ImplGetParameterString(const TransferableObjectDescriptor &rObjDesc)
Definition: transfer.cxx:116
#define TOD_SIG2
Definition: transfer.cxx:84
#define DND_POINTER_NONE
Definition: transfer.hxx:73
#define DND_IMAGE_NONE
Definition: transfer.hxx:74
unsigned char sal_Bool
signed char sal_Int8
bool ConvertGDIMetaFileToWMF(const GDIMetaFile &rMTF, SvStream &rTargetStream, FilterConfigItem const *pConfigItem, bool bPlaceable)
Definition: wmf.cxx:69