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}
265
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 if( !mxClipboard.is() )
512 return;
513
514 Reference< XFlushableClipboard > xFlushableClipboard( mxClipboard, UNO_QUERY );
515 SolarMutexReleaser aReleaser;
516
517 try
518 {
519 if( xFlushableClipboard.is() )
520 xFlushableClipboard->flushClipboard();
521 }
522 catch( const css::uno::Exception& )
523 {
524 OSL_FAIL( "Could not flush clipboard" );
525 }
526}
527
528
530{
531 DataFlavor aFlavor;
532
533 if( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) )
534 AddFormat( aFlavor );
535}
536
537
538void TransferableHelper::AddFormat( const DataFlavor& rFlavor )
539{
540 bool bAdd = true;
541
542 for (auto & format : maFormats)
543 {
544 if( TransferableDataHelper::IsEqual( format, rFlavor ) )
545 {
546 // update MimeType for SotClipboardFormatId::OBJECTDESCRIPTOR in every case
547 if ((SotClipboardFormatId::OBJECTDESCRIPTOR == format.mnSotId) && mxObjDesc)
548 {
549 DataFlavor aObjDescFlavor;
550
551 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDescFlavor );
552 format.MimeType = aObjDescFlavor.MimeType;
553 format.MimeType += ::ImplGetParameterString(*mxObjDesc);
554 }
555
556 bAdd = false;
557 break;
558 }
559 }
560
561 if( !bAdd )
562 return;
563
564 DataFlavorEx aFlavorEx;
565
566 aFlavorEx.MimeType = rFlavor.MimeType;
567 aFlavorEx.HumanPresentableName = rFlavor.HumanPresentableName;
568 aFlavorEx.DataType = rFlavor.DataType;
569 aFlavorEx.mnSotId = SotExchange::RegisterFormat( rFlavor );
570
571 if ((SotClipboardFormatId::OBJECTDESCRIPTOR == aFlavorEx.mnSotId) && mxObjDesc)
572 aFlavorEx.MimeType += ::ImplGetParameterString(*mxObjDesc);
573
574 maFormats.push_back(aFlavorEx);
575
576 if( SotClipboardFormatId::BITMAP == aFlavorEx.mnSotId )
577 {
578 AddFormat( SotClipboardFormatId::PNG );
579 AddFormat( SotClipboardFormatId::BMP );
580 }
581 else if( SotClipboardFormatId::GDIMETAFILE == aFlavorEx.mnSotId )
582 {
583 AddFormat( SotClipboardFormatId::EMF );
584 AddFormat( SotClipboardFormatId::WMF );
585 }
586}
587
588
590{
591 DataFlavor aFlavor;
592
593 if( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) )
594 RemoveFormat( aFlavor );
595}
596
597
598void TransferableHelper::RemoveFormat( const DataFlavor& rFlavor )
599{
600 DataFlavorExVector::iterator aIter(maFormats.begin());
601
602 while (aIter != maFormats.end())
603 {
604 if( TransferableDataHelper::IsEqual( *aIter, rFlavor ) )
605 aIter = maFormats.erase(aIter);
606 else
607 ++aIter;
608 }
609}
610
611
613{
614 return std::any_of(maFormats.begin(), maFormats.end(),
615 [&](const DataFlavorEx& data) { return data.mnSotId == nFormat; });
616}
617
618
620{
621 maFormats.clear();
622 maAny.clear();
623}
624
625
626bool TransferableHelper::SetAny( const Any& rAny )
627{
628 maAny = rAny;
629 return maAny.hasValue();
630}
631
632
633bool TransferableHelper::SetString( const OUString& rString )
634{
635 maAny <<= rString;
636 return maAny.hasValue();
637}
638
639
640bool TransferableHelper::SetBitmapEx( const BitmapEx& rBitmapEx, const DataFlavor& rFlavor )
641{
642 if( !rBitmapEx.IsEmpty() )
643 {
644 SvMemoryStream aMemStm( 65535, 65535 );
645
646 if(rFlavor.MimeType.equalsIgnoreAsciiCase("image/png"))
647 {
648 // write a PNG
649 css::uno::Sequence<css::beans::PropertyValue> aFilterData;
650
651#ifdef IOS
652 // Use faster compression on slow devices
653 aFilterData.realloc(aFilterData.getLength() + 1);
654 aFilterData.getArray()[aFilterData.getLength() - 1].Name = "Compression";
655
656 // We "know" that this gets passed to zlib's deflateInit2_(). 1 means best speed. For a
657 // typical 15 megapixel image from a DSLR, we are talking about a difference of 17 s for
658 // the default compression level vs 4 s for best speed, on an iPad Pro from 2017.
659 //
660 // Sure, the best would be to not have to re-encode the image at all, but have access to
661 // the original JPEG or PNG when there is a such.
662
663 aFilterData.getArray()[aFilterData.getLength() - 1].Value <<= 1;
664#endif
665 vcl::PngImageWriter aPNGWriter(aMemStm);
666 aPNGWriter.setParameters(aFilterData);
667 aPNGWriter.write(rBitmapEx);
668 }
669 else
670 {
671 // explicitly use Bitmap::Write with bCompressed = sal_False and bFileHeader = sal_True
672 WriteDIB(rBitmapEx.GetBitmap(), aMemStm, false, true);
673 }
674
675 maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() );
676 }
677
678 return maAny.hasValue();
679}
680
681
683{
684 if( rMtf.GetActionSize() )
685 {
686 SvMemoryStream aMemStm( 65535, 65535 );
687
688 SvmWriter aWriter( aMemStm );
689 aWriter.Write( rMtf );
690 maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() );
691 }
692
693 return maAny.hasValue();
694}
695
696
698{
699 if( rGraphic.GetType() != GraphicType::NONE )
700 {
701 SvMemoryStream aMemStm( 65535, 65535 );
702
704 aMemStm.SetCompressMode( SvStreamCompressFlags::NATIVE );
705
706 TypeSerializer aSerializer(aMemStm);
707 aSerializer.writeGraphic(rGraphic);
708
709 maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() );
710 }
711
712 return maAny.hasValue();
713}
714
715
717{
718 SvMemoryStream aMemStm( 8192, 8192 );
719
721 rIMap.Write( aMemStm );
722 maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() );
723
724 return maAny.hasValue();
725}
726
727
729{
730 PrepareOLE( rDesc );
731
732 SvMemoryStream aMemStm( 1024, 1024 );
733
734 WriteTransferableObjectDescriptor( aMemStm, rDesc );
735 maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.Tell() );
736
737 return maAny.hasValue();
738 }
739
740
742 const css::datatransfer::DataFlavor& rFlavor )
743{
744 rtl_TextEncoding eSysCSet = osl_getThreadTextEncoding();
745
746 switch( SotExchange::GetFormat( rFlavor ) )
747 {
748 case SotClipboardFormatId::SOLK:
749 {
750 OString sURL(OUStringToOString(rBmk.GetURL(), eSysCSet));
751 OString sDesc(OUStringToOString(rBmk.GetDescription(), eSysCSet));
752 OStringBuffer sOut;
753 sOut.append(sURL.getLength());
754 sOut.append("@" + sURL);
755 sOut.append(sDesc.getLength());
756 sOut.append("@" + sDesc);
757
758 Sequence< sal_Int8 > aSeq(sOut.getLength());
759 memcpy(aSeq.getArray(), sOut.getStr(), sOut.getLength());
760 maAny <<= aSeq;
761 }
762 break;
763
764 case SotClipboardFormatId::STRING:
765 case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
766 maAny <<= rBmk.GetURL();
767 break;
768
769 case SotClipboardFormatId::NETSCAPE_BOOKMARK:
770 {
772 char* pSeq = reinterpret_cast< char* >( aSeq.getArray() );
773
774 // strncpy fills the rest with nulls, as we need
775 strncpy( pSeq, OUStringToOString(rBmk.GetURL(), eSysCSet).getStr(), 1024 );
776 strncpy( pSeq + 1024, OUStringToOString(rBmk.GetDescription(), eSysCSet).getStr(), 1024 );
777
778 maAny <<= aSeq;
779 }
780 break;
781
782#ifdef _WIN32
783 case SotClipboardFormatId::FILEGRPDESCRIPTOR:
784 {
785 Sequence< sal_Int8 > aSeq( sizeof( FILEGROUPDESCRIPTORW ) );
786 FILEGROUPDESCRIPTORW* pFDesc = reinterpret_cast<FILEGROUPDESCRIPTORW*>(aSeq.getArray());
787 FILEDESCRIPTORW& rFDesc1 = pFDesc->fgd[ 0 ];
788
789 pFDesc->cItems = 1;
790 memset( &rFDesc1, 0, sizeof( rFDesc1 ) );
791 rFDesc1.dwFlags = FD_LINKUI;
792
793 OUStringBuffer aStr(rBmk.GetDescription());
794 for( size_t nChar = 0; (nChar = std::u16string_view(aStr).find_first_of(u"\\/:*?\"<>|"sv, nChar)) != std::u16string_view::npos; )
795 aStr.remove(nChar, 1);
796
797 aStr.insert(0, "Shortcut to ");
798 aStr.append(".URL");
799 wcscpy( rFDesc1.cFileName, o3tl::toW(aStr.getStr()) );
800
801 maAny <<= aSeq;
802 }
803 break;
804
805 case SotClipboardFormatId::FILECONTENT:
806 {
807 maAny <<= "[InternetShortcut]\x0aURL=" + rBmk.GetURL();
808 }
809 break;
810#endif
811
812 default:
813 break;
814 }
815
816 return maAny.hasValue();
817}
818
819
821 const css::datatransfer::DataFlavor& rFlavor )
822{
823 SvMemoryStream aMemStm( 1024, 1024 );
824
826 rINtImg.Write( aMemStm, SotExchange::GetFormat( rFlavor ) );
827
828 maAny <<= Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aMemStm.GetData() ), aMemStm.TellEnd() );
829
830 return maAny.hasValue();
831}
832
833
834bool TransferableHelper::SetObject( void* pUserObject, sal_uInt32 nUserObjectId, const DataFlavor& rFlavor )
835{
836 tools::SvRef<SotTempStream> xStm( new SotTempStream( OUString() ) );
837
838 xStm->SetVersion( SOFFICE_FILEFORMAT_50 );
839
840 if( pUserObject && WriteObject( xStm, pUserObject, nUserObjectId, rFlavor ) )
841 {
842 const sal_uInt32 nLen = xStm->TellEnd();
844
845 xStm->Seek( STREAM_SEEK_TO_BEGIN );
846 xStm->ReadBytes(aSeq.getArray(), nLen);
847
848 if( nLen && ( SotExchange::GetFormat( rFlavor ) == SotClipboardFormatId::STRING ) )
849 {
850 //JP 24.7.2001: as I know was this only for the writer application and this
851 // writes now UTF16 format into the stream
852 //JP 6.8.2001: and now it writes UTF8 because then exist no problem with
853 // little / big endians! - Bug 88121
854 maAny <<= OUString( reinterpret_cast< const char* >( aSeq.getConstArray() ), nLen - 1, RTL_TEXTENCODING_UTF8 );
855 }
856 else
857 maAny <<= aSeq;
858 }
859
860 return maAny.hasValue();
861}
862
863
864bool TransferableHelper::WriteObject( tools::SvRef<SotTempStream>&, void*, sal_uInt32, const DataFlavor& )
865{
866 OSL_FAIL( "TransferableHelper::WriteObject( ... ) not implemented" );
867 return false;
868}
869
870
872{
873}
874
875
877{
878}
879
880
882{
883 mxObjDesc.reset(new TransferableObjectDescriptor(rObjDesc));
884
885 if( HasFormat( SotClipboardFormatId::OBJECTDESCRIPTOR ) )
886 AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
887}
888
889void TransferableHelper::CopyToClipboard(const Reference<XClipboard>& rClipboard) const
890{
891 if( rClipboard.is() )
892 mxClipboard = rClipboard;
893
894 if( !mxClipboard.is() || mxTerminateListener.is() )
895 return;
896
897 try
898 {
899 TransferableHelper* pThis = const_cast< TransferableHelper* >( this );
900 pThis->mxTerminateListener = new TerminateListener( *pThis );
901 Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
902 xDesktop->addTerminateListener( pThis->mxTerminateListener );
903
904 mxClipboard->setContents( pThis, pThis );
905 }
906 catch( const css::uno::Exception& )
907 {
908 }
909}
910
912{
913 DBG_ASSERT( pWindow, "Window pointer is NULL" );
914 Reference< XClipboard > xClipboard;
915
916 if( pWindow )
917 xClipboard = pWindow->GetClipboard();
918
919 CopyToClipboard(xClipboard);
920}
921
922void TransferableHelper::CopyToSelection(const Reference<XClipboard>& rSelection) const
923{
924 if( !rSelection.is() || mxTerminateListener.is() )
925 return;
926
927 try
928 {
929 TransferableHelper* pThis = const_cast< TransferableHelper* >( this );
930 pThis->mxTerminateListener = new TerminateListener( *pThis );
931 Reference< XDesktop2 > xDesktop = Desktop::create( ::comphelper::getProcessComponentContext() );
932 xDesktop->addTerminateListener( pThis->mxTerminateListener );
933
934 rSelection->setContents( pThis, pThis );
935 }
936 catch( const css::uno::Exception& )
937 {
938 }
939}
940
942{
944}
945
946void TransferableHelper::StartDrag( vcl::Window* pWindow, sal_Int8 nDnDSourceActions )
947
948{
949 DBG_ASSERT( pWindow, "Window pointer is NULL" );
950 Reference< XDragSource > xDragSource( pWindow->GetDragSource() );
951
952 if( !xDragSource.is() )
953 return;
954
955 /*
956 * #96792# release mouse before actually starting DnD.
957 * This is necessary for the X11 DnD implementation to work.
958 */
959 if( pWindow->IsMouseCaptured() )
960 pWindow->ReleaseMouse();
961
962 const Point aPt( pWindow->GetPointerPosPixel() );
963
964 // On macOS we are forced to execute 'startDrag' synchronously
965 // contrary to the XDragSource interface specification because
966 // we can receive drag events from the system only in the main
967 // thread
968#if !defined(MACOSX)
969 SolarMutexReleaser aReleaser;
970#endif
971
972 try
973 {
974 DragGestureEvent aEvt;
975 aEvt.DragAction = DNDConstants::ACTION_COPY;
976 aEvt.DragOriginX = aPt.X();
977 aEvt.DragOriginY = aPt.Y();
978 aEvt.DragSource = xDragSource;
979
980 xDragSource->startDrag( aEvt, nDnDSourceActions, DND_POINTER_NONE, DND_IMAGE_NONE, this, this );
981 }
982 catch( const css::uno::Exception& )
983 {
984 }
985}
986
988{
989 Reference< XClipboard > xSelection(GetSystemPrimarySelection());
990
991 if( xSelection.is() )
992 xSelection->setContents( nullptr, nullptr );
993}
994
995namespace {
996
997class TransferableClipboardNotifier : public ::cppu::WeakImplHelper< XClipboardListener >
998{
999private:
1000 ::osl::Mutex& mrMutex;
1001 Reference< XClipboardNotifier > mxNotifier;
1003
1004protected:
1005 // XClipboardListener
1006 virtual void SAL_CALL changedContents( const clipboard::ClipboardEvent& event ) override;
1007
1008 // XEventListener
1009 virtual void SAL_CALL disposing( const EventObject& Source ) override;
1010
1011public:
1012 TransferableClipboardNotifier( const Reference< XClipboard >& _rxClipboard, TransferableDataHelper& _rListener, ::osl::Mutex& _rMutex );
1013
1015 bool isListening() const { return mpListener != nullptr; }
1016
1018 void dispose();
1019};
1020
1021}
1022
1023TransferableClipboardNotifier::TransferableClipboardNotifier( const Reference< XClipboard >& _rxClipboard, TransferableDataHelper& _rListener, ::osl::Mutex& _rMutex )
1024 :mrMutex( _rMutex )
1025 ,mxNotifier( _rxClipboard, UNO_QUERY )
1026 ,mpListener( &_rListener )
1027{
1028 osl_atomic_increment( &m_refCount );
1029 {
1030 if ( mxNotifier.is() )
1031 mxNotifier->addClipboardListener( this );
1032 else
1033 // born dead
1034 mpListener = nullptr;
1035 }
1036 osl_atomic_decrement( &m_refCount );
1037}
1038
1039
1040void SAL_CALL TransferableClipboardNotifier::changedContents( const clipboard::ClipboardEvent& event )
1041{
1042 SolarMutexGuard aSolarGuard;
1043 // the SolarMutex here is necessary, since
1044 // - we cannot call mpListener without our own mutex locked
1045 // - Rebind respectively InitFormats (called by Rebind) will
1046 // try to lock the SolarMutex, too
1047 ::osl::MutexGuard aGuard( mrMutex );
1048 if( mpListener )
1049 mpListener->Rebind( event.Contents );
1050}
1051
1052
1053void SAL_CALL TransferableClipboardNotifier::disposing( const EventObject& )
1054{
1055 // clipboard is being disposed. Hmm. Okay, become disfunctional myself.
1056 dispose();
1057}
1058
1059
1060void TransferableClipboardNotifier::dispose()
1061{
1062 ::osl::MutexGuard aGuard( mrMutex );
1063
1064 Reference< XClipboardListener > xKeepMeAlive( this );
1065
1066 if ( mxNotifier.is() )
1067 mxNotifier->removeClipboardListener( this );
1068 mxNotifier.clear();
1069
1070 mpListener = nullptr;
1071}
1072
1074{
1075 ::osl::Mutex maMutex;
1077
1079 {
1080 }
1081};
1082
1084 : mxObjDesc(new TransferableObjectDescriptor)
1085 , mxImpl(new TransferableDataHelper_Impl)
1086{
1087}
1088
1089TransferableDataHelper::TransferableDataHelper(const Reference< css::datatransfer::XTransferable >& rxTransferable)
1090 : mxTransfer(rxTransferable)
1091 , mxObjDesc(new TransferableObjectDescriptor)
1092 , mxImpl(new TransferableDataHelper_Impl)
1093{
1094 InitFormats();
1095}
1096
1098 : mxTransfer(rDataHelper.mxTransfer)
1099 , mxClipboard(rDataHelper.mxClipboard)
1100 , maFormats(rDataHelper.maFormats)
1101 , mxObjDesc(new TransferableObjectDescriptor(*rDataHelper.mxObjDesc))
1102 , mxImpl(new TransferableDataHelper_Impl)
1103{
1104}
1105
1107 : mxTransfer(std::move(rDataHelper.mxTransfer))
1108 , mxClipboard(std::move(rDataHelper.mxClipboard))
1109 , maFormats(std::move(rDataHelper.maFormats))
1110 , mxObjDesc(std::move(rDataHelper.mxObjDesc))
1111 , mxImpl(new TransferableDataHelper_Impl)
1112{
1113}
1114
1116{
1117 if ( this != &rDataHelper )
1118 {
1119 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1120
1121 const bool bWasClipboardListening = mxImpl->mxClipboardListener.is();
1122
1123 if (bWasClipboardListening)
1125
1126 mxTransfer = rDataHelper.mxTransfer;
1127 maFormats = rDataHelper.maFormats;
1128 mxObjDesc.reset(new TransferableObjectDescriptor(*rDataHelper.mxObjDesc));
1129 mxClipboard = rDataHelper.mxClipboard;
1130
1131 if (bWasClipboardListening)
1133 }
1134
1135 return *this;
1136}
1137
1139{
1140 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1141
1142 const bool bWasClipboardListening = mxImpl->mxClipboardListener.is();
1143
1144 if (bWasClipboardListening)
1146
1147 mxTransfer = std::move(rDataHelper.mxTransfer);
1148 maFormats = std::move(rDataHelper.maFormats);
1149 mxObjDesc = std::move(rDataHelper.mxObjDesc);
1150 mxClipboard = std::move(rDataHelper.mxClipboard);
1151
1152 if (bWasClipboardListening)
1154
1155 return *this;
1156}
1157
1159{
1161 {
1162 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1163 maFormats.clear();
1164 mxObjDesc.reset();
1165 }
1166}
1167
1168void TransferableDataHelper::FillDataFlavorExVector( const Sequence< DataFlavor >& rDataFlavorSeq,
1169 DataFlavorExVector& rDataFlavorExVector )
1170{
1171 try
1172 {
1173 Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
1174 Reference< XMimeContentTypeFactory > xMimeFact = MimeContentTypeFactory::create( xContext );
1175 DataFlavorEx aFlavorEx;
1176 static const OUStringLiteral aCharsetStr( u"charset" );
1177
1178
1179 for (auto const& rFlavor : rDataFlavorSeq)
1180 {
1181 Reference< XMimeContentType > xMimeType;
1182
1183 try
1184 {
1185 if( !rFlavor.MimeType.isEmpty() )
1186 xMimeType = xMimeFact->createMimeContentType( rFlavor.MimeType );
1187 }
1188 catch( const css::uno::Exception& )
1189 {
1190 }
1191
1192 aFlavorEx.MimeType = rFlavor.MimeType;
1193 aFlavorEx.HumanPresentableName = rFlavor.HumanPresentableName;
1194 aFlavorEx.DataType = rFlavor.DataType;
1195 aFlavorEx.mnSotId = SotExchange::RegisterFormat( rFlavor );
1196
1197 rDataFlavorExVector.push_back( aFlavorEx );
1198
1199 // add additional formats for special mime types
1200 if(SotClipboardFormatId::BMP == aFlavorEx.mnSotId || SotClipboardFormatId::PNG == aFlavorEx.mnSotId || SotClipboardFormatId::JPEG == aFlavorEx.mnSotId)
1201 {
1202 if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::BITMAP, aFlavorEx ) )
1203 {
1204 aFlavorEx.mnSotId = SotClipboardFormatId::BITMAP;
1205 rDataFlavorExVector.push_back( aFlavorEx );
1206 }
1207 }
1208 else if( SotClipboardFormatId::WMF == aFlavorEx.mnSotId || SotClipboardFormatId::EMF == aFlavorEx.mnSotId )
1209 {
1210 if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aFlavorEx ) )
1211 {
1212 aFlavorEx.mnSotId = SotClipboardFormatId::GDIMETAFILE;
1213 rDataFlavorExVector.push_back( aFlavorEx );
1214 }
1215 }
1216 else if ( SotClipboardFormatId::HTML_SIMPLE == aFlavorEx.mnSotId )
1217 {
1218 // #104735# HTML_SIMPLE may also be inserted without comments
1219 aFlavorEx.mnSotId = SotClipboardFormatId::HTML_NO_COMMENT;
1220 rDataFlavorExVector.push_back( aFlavorEx );
1221 }
1222 else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/plain" ) )
1223 {
1224 // add, if it is a UTF-8 byte buffer
1225 if( xMimeType->hasParameter( aCharsetStr ) )
1226 {
1227 if( xMimeType->getParameterValue( aCharsetStr ).equalsIgnoreAsciiCase( "unicode" ) ||
1228 xMimeType->getParameterValue( aCharsetStr ).equalsIgnoreAsciiCase( "utf-16" ) )
1229 {
1230 rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::STRING;
1231
1232 }
1233 }
1234 }
1235 else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/rtf" ) )
1236 {
1237 rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::RTF;
1238 }
1239 else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/richtext" ) )
1240 {
1241 rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::RICHTEXT;
1242 }
1243 else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/html" ) )
1244
1245 {
1246 rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::HTML;
1247 }
1248 else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "text/uri-list" ) )
1249 {
1250 rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::FILE_LIST;
1251 }
1252 else if( xMimeType.is() && xMimeType->getFullMediaType().equalsIgnoreAsciiCase( "application/x-openoffice-objectdescriptor-xml" ) )
1253 {
1254 rDataFlavorExVector[ rDataFlavorExVector.size() - 1 ].mnSotId = SotClipboardFormatId::OBJECTDESCRIPTOR;
1255 }
1256 }
1257 }
1258 catch( const css::uno::Exception& )
1259 {
1260 }
1261}
1262
1264{
1265 SolarMutexGuard aSolarGuard;
1266 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1267
1268 maFormats.clear();
1270
1271 if( !mxTransfer.is() )
1272 return;
1273
1275
1276 for (auto const& format : maFormats)
1277 {
1278 if( SotClipboardFormatId::OBJECTDESCRIPTOR == format.mnSotId )
1279 {
1281 break;
1282 }
1283 }
1284}
1285
1286
1288{
1289 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1290 return std::any_of(maFormats.begin(), maFormats.end(),
1291 [&](const DataFlavorEx& data) { return data.mnSotId == nFormat; });
1292}
1293
1294bool TransferableDataHelper::HasFormat( const DataFlavor& rFlavor ) const
1295{
1296 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1297 for (auto const& format : maFormats)
1298 {
1299 if( TransferableDataHelper::IsEqual( rFlavor, format ) )
1300 return true;
1301 }
1302
1303 return false;
1304}
1305
1307{
1308 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1309 return maFormats.size();
1310}
1311
1313{
1314 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1315 DBG_ASSERT(nFormat < maFormats.size(), "TransferableDataHelper::GetFormat: invalid format index");
1316 return( ( nFormat < maFormats.size() ) ? maFormats[ nFormat ].mnSotId : SotClipboardFormatId::NONE );
1317}
1318
1319DataFlavor TransferableDataHelper::GetFormatDataFlavor( sal_uInt32 nFormat ) const
1320{
1321 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1322 DBG_ASSERT(nFormat < maFormats.size(), "TransferableDataHelper::GetFormat: invalid format index");
1323
1324 DataFlavor aRet;
1325
1326 if (nFormat < maFormats.size())
1327 aRet = maFormats[nFormat];
1328
1329 return aRet;
1330}
1331
1332
1333Reference< XTransferable > TransferableDataHelper::GetXTransferable() const
1334{
1335 Reference< XTransferable > xRet;
1336
1337 if( mxTransfer.is() )
1338 {
1339 try
1340 {
1341 xRet = mxTransfer;
1342
1343 // do a dummy call to check, if this interface is valid (nasty)
1344 xRet->getTransferDataFlavors();
1345
1346 }
1347 catch( const css::uno::Exception& )
1348 {
1349 xRet.clear();
1350 }
1351 }
1352
1353 return xRet;
1354}
1355
1356
1357Any TransferableDataHelper::GetAny( SotClipboardFormatId nFormat, const OUString& rDestDoc ) const
1358{
1359 Any aReturn;
1360
1361 DataFlavor aFlavor;
1362 if ( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) )
1363 aReturn = GetAny(aFlavor, rDestDoc);
1364
1365 return aReturn;
1366}
1367
1368Any TransferableDataHelper::GetAny( const DataFlavor& rFlavor, const OUString& rDestDoc ) const
1369{
1370 ::osl::MutexGuard aGuard(mxImpl->maMutex);
1371 Any aRet;
1372
1373 try
1374 {
1375 if( mxTransfer.is() )
1376 {
1377 const SotClipboardFormatId nRequestFormat = SotExchange::GetFormat( rFlavor );
1378
1379 Reference<css::datatransfer::XTransferable2> xTransfer2(mxTransfer, UNO_QUERY);
1380
1381 if( nRequestFormat != SotClipboardFormatId::NONE )
1382 {
1383 // try to get alien format first
1384 for (auto const& format : maFormats)
1385 {
1386 if( ( nRequestFormat == format.mnSotId ) && !rFlavor.MimeType.equalsIgnoreAsciiCase( format.MimeType ) )
1387 {
1388// tdf#133365: only release solar mutex on Windows
1389#ifdef _WIN32
1390 // tdf#133527: first, make sure that we actually hold the mutex
1392 // Our own thread may handle the nested IDataObject::GetData call,
1393 // and try to acquire solar mutex
1395#endif // _WIN32
1396
1397 if (xTransfer2.is())
1398 aRet = xTransfer2->getTransferData2(format, rDestDoc);
1399 else
1400 aRet = mxTransfer->getTransferData(format);
1401 }
1402
1403 if( aRet.hasValue() )
1404 break;
1405 }
1406 }
1407
1408 if( !aRet.hasValue() )
1409 {
1410// tdf#133365: only release solar mutex on Windows
1411#ifdef _WIN32
1412 // tdf#133527: first, make sure that we actually hold the mutex
1414 // Our own thread may handle the nested IDataObject::GetData call,
1415 // and try to acquire solar mutex
1417#endif // _WIN32
1418
1419 if (xTransfer2.is())
1420 aRet = xTransfer2->getTransferData2(rFlavor, rDestDoc);
1421 else
1422 aRet = mxTransfer->getTransferData(rFlavor);
1423 }
1424 }
1425 }
1426 catch( const css::uno::Exception& )
1427 {
1428 }
1429
1430 return aRet;
1431}
1432
1433
1434bool TransferableDataHelper::GetString( SotClipboardFormatId nFormat, OUString& rStr ) const
1435{
1436 DataFlavor aFlavor;
1437 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetString( aFlavor, rStr ) );
1438}
1439
1440
1441bool TransferableDataHelper::GetString( const DataFlavor& rFlavor, OUString& rStr ) const
1442{
1443 Any aAny = GetAny(rFlavor, OUString());
1444 bool bRet = false;
1445
1446 if( aAny.hasValue() )
1447 {
1448 OUString aOUString;
1450
1451 if( aAny >>= aOUString )
1452 {
1453 rStr = aOUString;
1454 bRet = true;
1455 }
1456 else if( aAny >>= aSeq )
1457 {
1458
1459 const char* pChars = reinterpret_cast< const char* >( aSeq.getConstArray() );
1460 sal_Int32 nLen = aSeq.getLength();
1461
1462 //JP 10.10.2001: 92930 - don't copy the last zero character into the string.
1463 //DVO 2002-05-27: strip _all_ trailing zeros
1464 while( nLen && ( 0 == *( pChars + nLen - 1 ) ) )
1465 --nLen;
1466
1467 rStr = OUString( pChars, nLen, osl_getThreadTextEncoding() );
1468 bRet = true;
1469 }
1470 }
1471
1472 return bRet;
1473}
1474
1475
1477{
1478 if(SotClipboardFormatId::BITMAP == nFormat)
1479 {
1480 // try to get PNG first
1481 DataFlavor aFlavor;
1482
1483 if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor))
1484 {
1485 if(GetBitmapEx(aFlavor, rBmpEx))
1486 {
1487 return true;
1488 }
1489 }
1490
1491 // then JPEG
1492 if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG, aFlavor))
1493 {
1494 if(GetBitmapEx(aFlavor, rBmpEx))
1495 {
1496 return true;
1497 }
1498 }
1499 }
1500
1501 DataFlavor aFlavor;
1502 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetBitmapEx( aFlavor, rBmpEx ) );
1503}
1504
1505
1506bool TransferableDataHelper::GetBitmapEx( const DataFlavor& rFlavor, BitmapEx& rBmpEx ) const
1507{
1509 DataFlavor aSubstFlavor;
1510 bool bRet(GetSotStorageStream(rFlavor, xStm));
1511 bool bSuppressPNG(false); // #122982# If PNG stream not accessed, but BMP one, suppress trying to load PNG
1512 bool bSuppressJPEG(false);
1513
1514 if(!bRet && HasFormat(SotClipboardFormatId::PNG) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aSubstFlavor))
1515 {
1516 // when no direct success, try if PNG is available
1517 bRet = GetSotStorageStream(aSubstFlavor, xStm);
1518 bSuppressJPEG = bRet;
1519 }
1520
1521 if(!bRet && HasFormat(SotClipboardFormatId::JPEG) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG, aSubstFlavor))
1522 {
1523 bRet = GetSotStorageStream(aSubstFlavor, xStm);
1524 bSuppressPNG = bRet;
1525 }
1526
1527 if(!bRet && HasFormat(SotClipboardFormatId::BMP) && SotExchange::GetFormatDataFlavor(SotClipboardFormatId::BMP, aSubstFlavor))
1528 {
1529 // when no direct success, try if BMP is available
1530 bRet = GetSotStorageStream(aSubstFlavor, xStm);
1531 bSuppressPNG = bRet;
1532 bSuppressJPEG = bRet;
1533 }
1534
1535 if(bRet)
1536 {
1537 if(!bSuppressPNG && rFlavor.MimeType.equalsIgnoreAsciiCase("image/png"))
1538 {
1539 // it's a PNG, import to BitmapEx
1540 vcl::PngImageReader aPNGReader(*xStm);
1541 rBmpEx = aPNGReader.read();
1542 }
1543 else if(!bSuppressJPEG && rFlavor.MimeType.equalsIgnoreAsciiCase("image/jpeg"))
1544 {
1545 // it's a JPEG, import to BitmapEx
1547 Graphic aGraphic;
1548 if (rFilter.ImportGraphic(aGraphic, u"", *xStm) == ERRCODE_NONE)
1549 rBmpEx = aGraphic.GetBitmapEx();
1550 }
1551
1552 if(rBmpEx.IsEmpty())
1553 {
1554 Bitmap aBitmap;
1555 AlphaMask aMask;
1556
1557 // explicitly use Bitmap::Read with bFileHeader = sal_True
1558 // #i124085# keep DIBV5 for read from clipboard, but should not happen
1559 ReadDIBV5(aBitmap, aMask, *xStm);
1560
1561 if(aMask.GetBitmap().IsEmpty())
1562 {
1563 rBmpEx = aBitmap;
1564 }
1565 else
1566 {
1567 rBmpEx = BitmapEx(aBitmap, aMask);
1568 }
1569 }
1570
1571 bRet = (ERRCODE_NONE == xStm->GetError() && !rBmpEx.IsEmpty());
1572
1573 /* SJ: #110748# At the moment we are having problems with DDB inserted as DIB. The
1574 problem is, that some graphics are inserted much too big because the nXPelsPerMeter
1575 and nYPelsPerMeter of the bitmap fileheader isn't including the correct value.
1576 Due to this reason the following code assumes that bitmaps with a logical size
1577 greater than 50 cm aren't having the correct mapmode set.
1578
1579 The following code should be removed if DDBs and DIBs are supported via clipboard
1580 properly.
1581 */
1582 if(bRet)
1583 {
1584 const MapMode aMapMode(rBmpEx.GetPrefMapMode());
1585
1586 if(MapUnit::MapPixel != aMapMode.GetMapUnit())
1587 {
1588 const Size aSize(OutputDevice::LogicToLogic(rBmpEx.GetPrefSize(), aMapMode, MapMode(MapUnit::Map100thMM)));
1589
1590 // #i122388# This wrongly corrects in the given case; changing from 5000 100th mm to
1591 // the described 50 cm (which is 50000 100th mm)
1592 if((aSize.Width() > 50000) || (aSize.Height() > 50000))
1593 {
1594 rBmpEx.SetPrefMapMode(MapMode(MapUnit::MapPixel));
1595
1596 // #i122388# also adapt size by applying the mew MapMode
1597 const Size aNewSize(o3tl::convert(aSize, o3tl::Length::mm100, o3tl::Length::pt));
1598 rBmpEx.SetPrefSize(aNewSize);
1599 }
1600 }
1601 }
1602 }
1603
1604 return bRet;
1605}
1606
1607
1609{
1610 DataFlavor aFlavor;
1611 return SotExchange::GetFormatDataFlavor(nFormat, aFlavor) &&
1612 GetGDIMetaFile(aFlavor, rMtf) &&
1613 (nMaxActions == 0 || rMtf.GetActionSize() < nMaxActions);
1614}
1615
1616
1617bool TransferableDataHelper::GetGDIMetaFile( const DataFlavor& rFlavor, GDIMetaFile& rMtf ) const
1618{
1620 DataFlavor aSubstFlavor;
1621 bool bRet = false;
1622
1623 if( GetSotStorageStream( rFlavor, xStm ) )
1624 {
1625 SvmReader aReader( *xStm );
1626 aReader.Read( rMtf );
1627 bRet = ( xStm->GetError() == ERRCODE_NONE );
1628 }
1629
1630 if( !bRet &&
1631 HasFormat( SotClipboardFormatId::EMF ) &&
1632 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::EMF, aSubstFlavor ) &&
1633 GetSotStorageStream( aSubstFlavor, xStm ) )
1634 {
1635 Graphic aGraphic;
1636
1637 if( GraphicConverter::Import( *xStm, aGraphic ) == ERRCODE_NONE )
1638 {
1639 rMtf = aGraphic.GetGDIMetaFile();
1640 bRet = true;
1641 }
1642 }
1643
1644 if( !bRet &&
1645 HasFormat( SotClipboardFormatId::WMF ) &&
1646 SotExchange::GetFormatDataFlavor( SotClipboardFormatId::WMF, aSubstFlavor ) &&
1647 GetSotStorageStream( aSubstFlavor, xStm ) )
1648 {
1649 Graphic aGraphic;
1650
1651 if( GraphicConverter::Import( *xStm, aGraphic ) == ERRCODE_NONE )
1652 {
1653 rMtf = aGraphic.GetGDIMetaFile();
1654 bRet = true;
1655 }
1656 }
1657
1658 return bRet;
1659}
1660
1661
1663{
1664 if(SotClipboardFormatId::BITMAP == nFormat)
1665 {
1666 // try to get PNG first
1667 DataFlavor aFlavor;
1668
1669 if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor))
1670 {
1671 if(GetGraphic(aFlavor, rGraphic))
1672 {
1673 return true;
1674 }
1675 }
1676 }
1677
1678 DataFlavor aFlavor;
1679 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetGraphic( aFlavor, rGraphic ) );
1680}
1681
1682
1683bool TransferableDataHelper::GetGraphic( const css::datatransfer::DataFlavor& rFlavor, Graphic& rGraphic ) const
1684{
1685 DataFlavor aFlavor;
1686 bool bRet = false;
1687
1688 if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PNG, aFlavor) &&
1689 TransferableDataHelper::IsEqual(aFlavor, rFlavor))
1690 {
1691 // try to get PNG first
1692 BitmapEx aBmpEx;
1693
1694 bRet = GetBitmapEx( aFlavor, aBmpEx );
1695 if( bRet )
1696 rGraphic = aBmpEx;
1697 }
1698 else if(SotExchange::GetFormatDataFlavor(SotClipboardFormatId::PDF, aFlavor) &&
1699 TransferableDataHelper::IsEqual(aFlavor, rFlavor))
1700 {
1701 Graphic aGraphic;
1703 if (GetSotStorageStream(rFlavor, xStm))
1704 {
1705 if (GraphicConverter::Import(*xStm, aGraphic) == ERRCODE_NONE)
1706 {
1707 rGraphic = aGraphic;
1708 bRet = true;
1709 }
1710 }
1711 }
1712 else if (SotExchange::GetFormatDataFlavor(SotClipboardFormatId::JPEG, aFlavor) && TransferableDataHelper::IsEqual(aFlavor, rFlavor))
1713 {
1714 BitmapEx aBitmapEx;
1715
1716 bRet = GetBitmapEx(aFlavor, aBitmapEx);
1717 if (bRet)
1718 rGraphic = aBitmapEx;
1719 }
1720 else if(SotExchange::GetFormatDataFlavor( SotClipboardFormatId::BITMAP, aFlavor ) &&
1721 TransferableDataHelper::IsEqual( aFlavor, rFlavor ) )
1722 {
1723 BitmapEx aBmpEx;
1724
1725 bRet = GetBitmapEx( aFlavor, aBmpEx );
1726 if( bRet )
1727 rGraphic = aBmpEx;
1728 }
1729 else if( SotExchange::GetFormatDataFlavor( SotClipboardFormatId::GDIMETAFILE, aFlavor ) &&
1730 TransferableDataHelper::IsEqual( aFlavor, rFlavor ) )
1731 {
1732 GDIMetaFile aMtf;
1733
1734 bRet = GetGDIMetaFile( aFlavor, aMtf );
1735 if( bRet )
1736 rGraphic = aMtf;
1737 }
1738 else
1739 {
1741
1742 if( GetSotStorageStream( rFlavor, xStm ) )
1743 {
1744 TypeSerializer aSerializer(*xStm);
1745 aSerializer.readGraphic(rGraphic);
1746 bRet = ( xStm->GetError() == ERRCODE_NONE );
1747 }
1748 }
1749
1750 return bRet;
1751}
1752
1753
1755{
1756 DataFlavor aFlavor;
1757 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetImageMap( aFlavor, rIMap ) );
1758}
1759
1760
1761bool TransferableDataHelper::GetImageMap( const css::datatransfer::DataFlavor& rFlavor, ImageMap& rIMap ) const
1762{
1764 bool bRet = GetSotStorageStream( rFlavor, xStm );
1765
1766 if( bRet )
1767 {
1768 rIMap.Read( *xStm );
1769 bRet = ( xStm->GetError() == ERRCODE_NONE );
1770 }
1771
1772 return bRet;
1773}
1774
1775
1777{
1778 DataFlavor aFlavor;
1779 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetTransferableObjectDescriptor( rDesc ) );
1780}
1781
1782
1784{
1785 rDesc = *mxObjDesc;
1786 return true;
1787}
1788
1789
1791{
1792 DataFlavor aFlavor;
1793 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetINetBookmark( aFlavor, rBmk ) );
1794}
1795
1796
1797bool TransferableDataHelper::GetINetBookmark( const css::datatransfer::DataFlavor& rFlavor, INetBookmark& rBmk ) const
1798{
1799 if( !HasFormat( rFlavor ))
1800 return false;
1801
1802 bool bRet = false;
1803 const SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
1804 switch( nFormat )
1805 {
1806 case SotClipboardFormatId::SOLK:
1807 case SotClipboardFormatId::UNIFORMRESOURCELOCATOR:
1808 {
1809 OUString aString;
1810 if( GetString( rFlavor, aString ) )
1811 {
1812 if( SotClipboardFormatId::UNIFORMRESOURCELOCATOR == nFormat )
1813 {
1814 rBmk = INetBookmark( aString, aString );
1815 bRet = true;
1816 }
1817 else
1818 {
1819 OUString aURL, aDesc;
1820 sal_Int32 nStart = aString.indexOf( '@' ), nLen = aString.toInt32();
1821
1822 if( !nLen && aString[ 0 ] != '0' )
1823 {
1824 SAL_INFO( "svtools", "SOLK: 1. len=0" );
1825 }
1826 if( nStart == -1 || nLen > aString.getLength() - nStart - 3 )
1827 {
1828 SAL_INFO( "svtools", "SOLK: 1. illegal start or wrong len" );
1829 }
1830 aURL = aString.copy( nStart + 1, nLen );
1831
1832 aString = aString.replaceAt( 0, nStart + 1 + nLen, u"" );
1833 nStart = aString.indexOf( '@' );
1834 nLen = aString.toInt32();
1835
1836 if( !nLen && aString[ 0 ] != '0' )
1837 {
1838 SAL_INFO( "svtools", "SOLK: 2. len=0" );
1839 }
1840 if( nStart == -1 || nLen > aString.getLength() - nStart - 1 )
1841 {
1842 SAL_INFO( "svtools", "SOLK: 2. illegal start or wrong len" );
1843 }
1844 aDesc = aString.copy( nStart+1, nLen );
1845
1846 rBmk = INetBookmark( aURL, aDesc );
1847 bRet = true;
1848 }
1849 }
1850 }
1851 break;
1852
1853 case SotClipboardFormatId::NETSCAPE_BOOKMARK:
1854 {
1855 Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
1856
1857 if (2048 == aSeq.getLength())
1858 {
1859 const char* p1 = reinterpret_cast< const char* >( aSeq.getConstArray() );
1860 const char* p2 = reinterpret_cast< const char* >( aSeq.getConstArray() ) + 1024;
1861 rBmk = INetBookmark( OUString( p1, strlen(p1), osl_getThreadTextEncoding() ),
1862 OUString( p2, strlen(p2), osl_getThreadTextEncoding() ) );
1863 bRet = true;
1864 }
1865 }
1866 break;
1867
1868#ifdef _WIN32
1869 case SotClipboardFormatId::FILEGRPDESCRIPTOR:
1870 {
1871 Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
1872
1873 if (aSeq.getLength())
1874 {
1875 FILEGROUPDESCRIPTORW const * pFDesc = reinterpret_cast<FILEGROUPDESCRIPTORW const *>(aSeq.getConstArray());
1876
1877 if( pFDesc->cItems )
1878 {
1879 OUString aDesc( o3tl::toU(pFDesc->fgd[ 0 ].cFileName) );
1880
1881 if( ( aDesc.getLength() > 4 ) && aDesc.endsWithIgnoreAsciiCase(".URL") )
1882 {
1883 std::unique_ptr<SvStream> pStream(::utl::UcbStreamHelper::CreateStream( INetURLObject( aDesc ).GetMainURL( INetURLObject::DecodeMechanism::NONE ),
1884 StreamMode::STD_READ ));
1885
1886 if( !pStream || pStream->GetError() )
1887 {
1888 DataFlavor aFileContentFlavor;
1889
1890 aSeq.realloc( 0 );
1891 pStream.reset();
1892
1893 if (SotExchange::GetFormatDataFlavor(SotClipboardFormatId::FILECONTENT, aFileContentFlavor))
1894 {
1895 aSeq = GetSequence(aFileContentFlavor, OUString());
1896 if (aSeq.getLength())
1897 pStream.reset(new SvMemoryStream( const_cast<sal_Int8 *>(aSeq.getConstArray()), aSeq.getLength(), StreamMode::STD_READ ));
1898 }
1899 }
1900
1901 if( pStream )
1902 {
1903 OString aLine;
1904 bool bInA = false, bInW = false, bAFound = false;
1905
1906 while( pStream->ReadLine( aLine ) )
1907 {
1908 if (aLine.startsWithIgnoreAsciiCase("[InternetShortcut", &aLine))
1909 {
1910 // May be [InternetShortcut], or [InternetShortcut.A], or
1911 // [InternetShortcut.W] (the latter has UTF-7-encoded URL)
1912 bInW = aLine.equalsIgnoreAsciiCase(".W]");
1913 bInA = !bAFound && !bInW
1914 && (aLine == "]" || aLine.equalsIgnoreAsciiCase(".A]"));
1915 }
1916 else if (aLine.startsWith("["))
1917 {
1918 bInA = bInW = false;
1919 }
1920 else if ((bInA || bInW) && aLine.startsWithIgnoreAsciiCase("URL="))
1921 {
1922 auto eTextEncoding = bInW ? RTL_TEXTENCODING_UTF7
1923 : osl_getThreadTextEncoding();
1924 rBmk = INetBookmark( OStringToOUString(aLine.subView(4), eTextEncoding),
1925 aDesc.copy(0, aDesc.getLength() - 4) );
1926 bRet = true;
1927 if (bInW)
1928 break;
1929 else
1930 bAFound = true; // Keep looking for "W"
1931 }
1932 }
1933 }
1934 }
1935 }
1936 }
1937 }
1938 break;
1939#endif
1940 default: break;
1941 }
1942 return bRet;
1943}
1944
1945
1947 INetImage& rINtImg ) const
1948{
1949 DataFlavor aFlavor;
1950 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetINetImage( aFlavor, rINtImg ) );
1951}
1952
1953
1955 const css::datatransfer::DataFlavor& rFlavor,
1956 INetImage& rINtImg ) const
1957{
1959 bool bRet = GetSotStorageStream( rFlavor, xStm );
1960
1961 if( bRet )
1962 bRet = rINtImg.Read( *xStm, SotExchange::GetFormat( rFlavor ) );
1963 return bRet;
1964}
1965
1966
1968 FileList& rFileList ) const
1969{
1970 DataFlavor aFlavor;
1971 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetFileList( rFileList ) );
1972}
1973
1974
1976{
1978 bool bRet = false;
1979
1980 for( sal_uInt32 i = 0, nFormatCount = GetFormatCount(); ( i < nFormatCount ) && !bRet; ++i )
1981 {
1982 if( SotClipboardFormatId::FILE_LIST == GetFormat( i ) )
1983 {
1984 const DataFlavor aFlavor( GetFormatDataFlavor( i ) );
1985
1986 if( GetSotStorageStream( aFlavor, xStm ) )
1987 {
1988 if( aFlavor.MimeType.indexOf( "text/uri-list" ) > -1 )
1989 {
1990 OStringBuffer aDiskString;
1991
1992 while( xStm->ReadLine( aDiskString ) )
1993 if( !aDiskString.isEmpty() && aDiskString[0] != '#' )
1994 rFileList.AppendFile( OStringToOUString(aDiskString, RTL_TEXTENCODING_UTF8) );
1995
1996 bRet = true;
1997 }
1998 else
1999 bRet = ( ReadFileList( *xStm, rFileList ).GetError() == ERRCODE_NONE );
2000 }
2001 }
2002 }
2003
2004 return bRet;
2005}
2006
2007
2008Sequence<sal_Int8> TransferableDataHelper::GetSequence( SotClipboardFormatId nFormat, const OUString& rDestDoc ) const
2009{
2010 DataFlavor aFlavor;
2011 if (!SotExchange::GetFormatDataFlavor(nFormat, aFlavor))
2012 return Sequence<sal_Int8>();
2013
2014 return GetSequence(aFlavor, rDestDoc);
2015}
2016
2017Sequence<sal_Int8> TransferableDataHelper::GetSequence( const DataFlavor& rFlavor, const OUString& rDestDoc ) const
2018{
2019 const Any aAny = GetAny(rFlavor, rDestDoc);
2020 Sequence<sal_Int8> aSeq;
2021 if (aAny.hasValue())
2022 aAny >>= aSeq;
2023
2024 return aSeq;
2025}
2026
2027
2029{
2030 DataFlavor aFlavor;
2031 return( SotExchange::GetFormatDataFlavor( nFormat, aFlavor ) && GetSotStorageStream( aFlavor, rxStream ) );
2032}
2033
2034
2035bool TransferableDataHelper::GetSotStorageStream( const DataFlavor& rFlavor, tools::SvRef<SotTempStream>& rxStream ) const
2036{
2037 Sequence<sal_Int8> aSeq = GetSequence(rFlavor, OUString());
2038
2039 if (aSeq.hasElements())
2040 {
2041 rxStream = new SotTempStream( "" );
2042 rxStream->WriteBytes( aSeq.getConstArray(), aSeq.getLength() );
2043 rxStream->Seek( 0 );
2044 }
2045
2046 return aSeq.hasElements();
2047}
2048
2049Reference<XInputStream> TransferableDataHelper::GetInputStream( SotClipboardFormatId nFormat, const OUString& rDestDoc ) const
2050{
2051 DataFlavor aFlavor;
2052 if (!SotExchange::GetFormatDataFlavor(nFormat, aFlavor))
2053 return Reference<XInputStream>();
2054
2055 return GetInputStream(aFlavor, rDestDoc);
2056}
2057
2058Reference<XInputStream> TransferableDataHelper::GetInputStream( const DataFlavor& rFlavor, const OUString& rDestDoc ) const
2059{
2060 Sequence<sal_Int8> aSeq = GetSequence(rFlavor, rDestDoc);
2061
2062 if (!aSeq.hasElements())
2063 return Reference<XInputStream>();
2064
2065 Reference<XInputStream> xStream(new comphelper::SequenceInputStream(aSeq));
2066 return xStream;
2067}
2068
2069void TransferableDataHelper::Rebind( const Reference< XTransferable >& _rxNewContent )
2070{
2071 mxTransfer = _rxNewContent;
2072 InitFormats();
2073}
2074
2076{
2077 ::osl::MutexGuard aGuard(mxImpl->maMutex);
2078
2080
2081 mxImpl->mxClipboardListener = new TransferableClipboardNotifier(mxClipboard, *this, mxImpl->maMutex);
2082
2083 return mxImpl->mxClipboardListener->isListening();
2084}
2085
2087{
2088 ::osl::MutexGuard aGuard(mxImpl->maMutex);
2089
2090 if (mxImpl->mxClipboardListener.is())
2091 {
2092 mxImpl->mxClipboardListener->dispose();
2093 mxImpl->mxClipboardListener.clear();
2094 }
2095}
2096
2097TransferableDataHelper TransferableDataHelper::CreateFromClipboard(const css::uno::Reference<css::datatransfer::clipboard::XClipboard>& rClipboard)
2098{
2100
2101 if( rClipboard.is() )
2102 {
2103 try
2104 {
2105 Reference< XTransferable > xTransferable( rClipboard->getContents() );
2106
2107 if( xTransferable.is() )
2108 {
2109 aRet = TransferableDataHelper( xTransferable );
2110 // also copy the clipboard
2111 aRet.mxClipboard = rClipboard;
2112 }
2113 }
2114 catch( const css::uno::Exception& )
2115 {
2116 }
2117 }
2118
2119 return aRet;
2120}
2121
2123{
2124 DBG_ASSERT( pWindow, "Window pointer is NULL" );
2125
2126 Reference< XClipboard > xClipboard;
2127
2128 if( pWindow )
2129 xClipboard = pWindow->GetClipboard();
2130
2131 return CreateFromClipboard(xClipboard);
2132}
2133
2135{
2136 Reference< XClipboard > xSelection(GetSystemPrimarySelection());
2138
2139 if( xSelection.is() )
2140 {
2141 SolarMutexReleaser aReleaser;
2142
2143 try
2144 {
2145 Reference< XTransferable > xTransferable( xSelection->getContents() );
2146
2147 if( xTransferable.is() )
2148 {
2149 aRet = TransferableDataHelper( xTransferable );
2150 aRet.mxClipboard = xSelection;
2151 }
2152 }
2153 catch( const css::uno::Exception& )
2154 {
2155 }
2156 }
2157
2158 return aRet;
2159}
2160
2161bool TransferableDataHelper::IsEqual( const css::datatransfer::DataFlavor& rInternalFlavor,
2162 const css::datatransfer::DataFlavor& rRequestFlavor )
2163{
2164 Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
2165 bool bRet = false;
2166
2167 try
2168 {
2169 Reference< XMimeContentTypeFactory > xMimeFact = MimeContentTypeFactory::create( xContext );
2170
2171 Reference< XMimeContentType > xRequestType1( xMimeFact->createMimeContentType( rInternalFlavor.MimeType ) );
2172 Reference< XMimeContentType > xRequestType2( xMimeFact->createMimeContentType( rRequestFlavor.MimeType ) );
2173
2174 if( xRequestType1.is() && xRequestType2.is() )
2175 {
2176 if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( xRequestType2->getFullMediaType() ) )
2177 {
2178 if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( "text/plain" ) )
2179 {
2180 // special handling for text/plain media types
2181 static const OUStringLiteral aCharsetString( u"charset" );
2182
2183 if( !xRequestType2->hasParameter( aCharsetString ) ||
2184 xRequestType2->getParameterValue( aCharsetString ).equalsIgnoreAsciiCase( "utf-16" ) ||
2185 xRequestType2->getParameterValue( aCharsetString ).equalsIgnoreAsciiCase( "unicode" ) )
2186 {
2187 bRet = true;
2188 }
2189 }
2190 else if( xRequestType1->getFullMediaType().equalsIgnoreAsciiCase( "application/x-openoffice" ) )
2191 {
2192 // special handling for application/x-openoffice media types
2193 static const OUStringLiteral aFormatString( u"windows_formatname" );
2194
2195 if( xRequestType1->hasParameter( aFormatString ) &&
2196 xRequestType2->hasParameter( aFormatString ) &&
2197 xRequestType1->getParameterValue( aFormatString ).equalsIgnoreAsciiCase( xRequestType2->getParameterValue( aFormatString ) ) )
2198 {
2199 bRet = true;
2200 }
2201 }
2202 else
2203 bRet = true;
2204 }
2205 }
2206 }
2207 catch( const css::uno::Exception& )
2208 {
2209 bRet = rInternalFlavor.MimeType.equalsIgnoreAsciiCase( rRequestFlavor.MimeType );
2210 }
2211
2212 return bRet;
2213}
2214
2215/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::shared_ptr< PresenterClockTimer::Listener > mpListener
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:340
GraphicType GetType() const
Definition: graph.cxx:294
BitmapEx GetBitmapEx(const GraphicConversionParameters &rParameters=GraphicConversionParameters()) const
Definition: graph.cxx:330
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:913
void Read(SvStream &rIStm)
Definition: imap.cxx:949
SAL_WARN_UNUSED_RESULT Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
Definition: map.cxx:1593
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:1447
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:65
SvStream & Write(const GDIMetaFile &rMetaFile)
Definition: SvmWriter.cxx:38
sal_uInt32 GetFormatCount() const
Definition: transfer.cxx:1306
std::unique_ptr< TransferableObjectDescriptor > mxObjDesc
Definition: transfer.hxx:277
css::uno::Reference< css::datatransfer::XTransferable > mxTransfer
Definition: transfer.hxx:274
static bool IsEqual(const css::datatransfer::DataFlavor &rInternalFlavor, const css::datatransfer::DataFlavor &rRequestFlavor)
Definition: transfer.cxx:2161
css::uno::Sequence< sal_Int8 > GetSequence(SotClipboardFormatId nFormat, const OUString &rDestDoc) const
Definition: transfer.cxx:2008
bool GetTransferableObjectDescriptor(SotClipboardFormatId nFormat, TransferableObjectDescriptor &rDesc)
Definition: transfer.cxx:1776
static TransferableDataHelper CreateFromPrimarySelection()
Definition: transfer.cxx:2134
static TransferableDataHelper CreateFromClipboard(const css::uno::Reference< css::datatransfer::clipboard::XClipboard > &rClipboard)
Definition: transfer.cxx:2097
bool GetString(SotClipboardFormatId nFormat, OUString &rStr) const
Definition: transfer.cxx:1434
TransferableDataHelper & operator=(const TransferableDataHelper &rDataHelper)
Definition: transfer.cxx:1115
SotClipboardFormatId GetFormat(sal_uInt32 nFormat) const
Definition: transfer.cxx:1312
std::unique_ptr< TransferableDataHelper_Impl > mxImpl
Definition: transfer.hxx:278
bool GetImageMap(SotClipboardFormatId nFormat, ImageMap &rIMap) const
Definition: transfer.cxx:1754
css::uno::Any GetAny(SotClipboardFormatId nFormat, const OUString &rDestDoc) const
Definition: transfer.cxx:1357
bool GetFileList(SotClipboardFormatId nFormat, FileList &rFileList) const
Definition: transfer.cxx:1967
css::uno::Reference< css::io::XInputStream > GetInputStream(SotClipboardFormatId nFormat, const OUString &rDestDoc) const
Definition: transfer.cxx:2049
bool GetSotStorageStream(SotClipboardFormatId nFormat, tools::SvRef< SotTempStream > &rStreamRef) const
Definition: transfer.cxx:2028
bool GetGDIMetaFile(SotClipboardFormatId nFormat, GDIMetaFile &rMtf, size_t nMaxActions=0) const
Return as GDI metafile.
Definition: transfer.cxx:1608
void Rebind(const css::uno::Reference< css::datatransfer::XTransferable > &_rxNewData)
Definition: transfer.cxx:2069
static TransferableDataHelper CreateFromSystemClipboard(vcl::Window *pWindow)
Definition: transfer.cxx:2122
bool HasFormat(SotClipboardFormatId nFormat) const
Definition: transfer.cxx:1287
bool GetINetImage(SotClipboardFormatId nFormat, INetImage &rINtImg) const
Definition: transfer.cxx:1946
static void FillDataFlavorExVector(const css::uno::Sequence< css::datatransfer::DataFlavor > &rDataFlavorSeq, DataFlavorExVector &rDataFlavorExVector)
Definition: transfer.cxx:1168
css::uno::Reference< css::datatransfer::clipboard::XClipboard > mxClipboard
Definition: transfer.hxx:275
bool GetBitmapEx(SotClipboardFormatId nFormat, BitmapEx &rBmp) const
Definition: transfer.cxx:1476
DataFlavorExVector maFormats
Definition: transfer.hxx:276
css::datatransfer::DataFlavor GetFormatDataFlavor(sal_uInt32 nFormat) const
Definition: transfer.cxx:1319
bool GetGraphic(SotClipboardFormatId nFormat, Graphic &rGraphic) const
Definition: transfer.cxx:1662
bool GetINetBookmark(SotClipboardFormatId nFormat, INetBookmark &rBmk) const
Definition: transfer.cxx:1790
css::uno::Reference< css::datatransfer::XTransferable > GetXTransferable() const
Definition: transfer.cxx:1333
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:946
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:697
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
bool SetTransferableObjectDescriptor(const TransferableObjectDescriptor &rDesc)
Definition: transfer.cxx:728
bool SetAny(const css::uno::Any &rAny)
Definition: transfer.cxx:626
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:922
bool SetObject(void *pUserObject, sal_uInt32 nUserObjectId, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:834
void RemoveFormat(SotClipboardFormatId nFormat)
Definition: transfer.cxx:589
bool SetString(const OUString &rString)
Definition: transfer.cxx:633
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:864
static void ClearPrimarySelection()
Definition: transfer.cxx:987
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:871
VCL_DLLPRIVATE void ImplFlush()
Definition: transfer.cxx:509
bool SetINetImage(const INetImage &rINtImg, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:820
void CopyToPrimarySelection() const
Definition: transfer.cxx:941
bool SetBitmapEx(const BitmapEx &rBitmap, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:640
bool SetINetBookmark(const INetBookmark &rBmk, const css::datatransfer::DataFlavor &rFlavor)
Definition: transfer.cxx:741
virtual void SAL_CALL disposing(const css::lang::EventObject &Source) override
Definition: transfer.cxx:469
bool HasFormat(SotClipboardFormatId nFormat)
Definition: transfer.cxx:612
void PrepareOLE(const TransferableObjectDescriptor &rObjDesc)
Definition: transfer.cxx:881
css::uno::Any maAny
Definition: transfer.hxx:167
void AddFormat(SotClipboardFormatId nFormat)
Definition: transfer.cxx:529
virtual bool GetData(const css::datatransfer::DataFlavor &rFlavor, const OUString &rDestDoc)=0
std::unique_ptr< TransferableObjectDescriptor > mxObjDesc
Definition: transfer.hxx:172
virtual void AddSupportedFormats()=0
virtual sal_Bool SAL_CALL isComplex() override
Definition: transfer.cxx:398
bool SetImageMap(const ImageMap &rIMap)
Definition: transfer.cxx:716
css::uno::Reference< css::frame::XTerminateListener > mxTerminateListener
Definition: transfer.hxx:170
OUString maLastFormat
Definition: transfer.hxx:168
virtual void SAL_CALL dragExit(const css::datatransfer::dnd::DragSourceEvent &dse) override
Definition: transfer.cxx:494
virtual void ObjectReleased()
Definition: transfer.cxx:876
bool SetGDIMetaFile(const GDIMetaFile &rMtf)
Definition: transfer.cxx:682
css::uno::Reference< css::datatransfer::clipboard::XClipboard > mxClipboard
Definition: transfer.hxx:169
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:171
void readGraphic(Graphic &rGraphic)
void writeGraphic(const Graphic &rGraphic)
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:735
css::uno::Reference< css::datatransfer::clipboard::XClipboard > GetClipboard()
Definition: window.cxx:3448
#define DBG_ASSERT(sCon, aError)
bool WriteDIB(const Bitmap &rSource, SvStream &rOStm, bool bCompressed, bool bFileHeader)
Definition: dibtools.cxx:1790
bool ReadDIBV5(Bitmap &rTarget, AlphaMask &rTargetAlpha, SvStream &rIStm)
Definition: dibtools.cxx:1766
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)
Sequence< sal_Int8 > aSeq
#define SAL_INFO(area, stream)
aStr
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:1076
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:72
#define DND_IMAGE_NONE
Definition: transfer.hxx:73
unsigned char sal_Bool
signed char sal_Int8
bool ConvertGDIMetaFileToWMF(const GDIMetaFile &rMTF, SvStream &rTargetStream, FilterConfigItem const *pConfigItem, bool bPlaceable)
Definition: wmf.cxx:69