1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <scitems.hxx>
21 #include <editeng/justifyitem.hxx>
23 #include <com/sun/star/uno/Sequence.hxx>
24 #include <com/sun/star/embed/XTransactedObject.hpp>
26 #include <o3tl/unit_conversion.hxx>
27 #include <osl/diagnose.h>
28 #include <unotools/tempfile.hxx>
29 #include <unotools/ucbstreamhelper.hxx>
30 #include <unotools/streamwrap.hxx>
31 #include <comphelper/fileformat.h>
32 #include <comphelper/lok.hxx>
33 #include <comphelper/storagehelper.hxx>
34 #include <comphelper/servicehelper.hxx>
35 #include <sot/storage.hxx>
37 #include <vcl/gdimtf.hxx>
38 #include <vcl/jobset.hxx>
39 #include <vcl/svapp.hxx>
40 #include <vcl/virdev.hxx>
41 #include <sfx2/docfile.hxx>
43 #include <transobj.hxx>
44 #include <patattr.hxx>
45 #include <cellvalue.hxx>
46 #include <cellform.hxx>
47 #include <document.hxx>
48 #include <viewopti.hxx>
49 #include <editutil.hxx>
51 #include <formulacell.hxx>
52 #include <printfun.hxx>
53 #include <docfunc.hxx>
55 #include <dragdata.hxx>
56 #include <sortparam.hxx>
57 #include <tabvwsh.hxx>
59 #include <editeng/paperinf.hxx>
60 #include <editeng/sizeitem.hxx>
61 #include <formula/errorcodes.hxx>
63 #include <markdata.hxx>
64 #include <stlpool.hxx>
65 #include <viewdata.hxx>
66 #include <dociter.hxx>
67 #include <cellsuno.hxx>
68 #include <stringutil.hxx>
69 #include <formulaiter.hxx>
71 using namespace com::sun::star
;
73 constexpr sal_uInt32 SCTRANS_TYPE_IMPEX
= 1;
74 constexpr sal_uInt32 SCTRANS_TYPE_EDIT_RTF
= 2;
75 constexpr sal_uInt32 SCTRANS_TYPE_EDIT_BIN
= 3;
76 constexpr sal_uInt32 SCTRANS_TYPE_EMBOBJ
= 4;
77 constexpr sal_uInt32 SCTRANS_TYPE_EDIT_ODF_TEXT_FLAT
= 5;
79 void ScTransferObj::GetAreaSize( const ScDocument
& rDoc
, SCTAB nTab1
, SCTAB nTab2
, SCROW
& nRow
, SCCOL
& nCol
)
83 for( SCTAB nTab
= nTab1
; nTab
<= nTab2
; nTab
++ )
87 // GetPrintArea instead of GetCellArea - include drawing objects
88 if( rDoc
.GetPrintArea( nTab
, nLastCol
, nLastRow
) )
90 if( nLastCol
> nMaxCol
)
92 if( nLastRow
> nMaxRow
)
100 void ScTransferObj::PaintToDev( OutputDevice
* pDev
, ScDocument
& rDoc
, double nPrintFactor
,
101 const ScRange
& rBlock
)
103 tools::Rectangle
aBound( Point(), pDev
->GetOutputSize() ); //! use size from clip area?
105 ScViewData
aViewData(rDoc
);
107 aViewData
.SetTabNo( rBlock
.aEnd
.Tab() );
108 aViewData
.SetScreen( rBlock
.aStart
.Col(), rBlock
.aStart
.Row(),
109 rBlock
.aEnd
.Col(), rBlock
.aEnd
.Row() );
111 ScPrintFunc::DrawToDev( rDoc
, pDev
, nPrintFactor
, aBound
, &aViewData
, false/*bMetaFile*/ );
114 ScTransferObj::ScTransferObj( const std::shared_ptr
<ScDocument
>& pClipDoc
, TransferableObjectDescriptor aDesc
) :
117 m_aObjDesc(std::move( aDesc
)),
120 m_nSourceCursorX( m_pDoc
->MaxCol() + 1 ),
121 m_nSourceCursorY( m_pDoc
->MaxRow() + 1 ),
122 m_nDragSourceFlags( ScDragSrc::Undefined
),
123 m_bDragWasInternal( false ),
124 m_bUsedForLink( false ),
127 OSL_ENSURE(m_pDoc
->IsClipboard(), "wrong document");
129 // get aBlock from clipboard doc
135 m_pDoc
->GetClipStart( nCol1
, nRow1
);
136 m_pDoc
->GetClipArea( nCol2
, nRow2
, true ); // real source area - include filtered rows
137 nCol2
= sal::static_int_cast
<SCCOL
>( nCol2
+ nCol1
);
138 nRow2
= sal::static_int_cast
<SCROW
>( nRow2
+ nRow1
);
141 m_pDoc
->GetClipArea( nDummy
, m_nNonFiltered
, false );
142 m_bHasFiltered
= (m_nNonFiltered
< (nRow2
- nRow1
));
143 ++m_nNonFiltered
; // to get count instead of diff
148 for (SCTAB i
=0; i
< m_pDoc
->GetTableCount(); i
++)
149 if (m_pDoc
->HasTable(i
))
156 OSL_ENSURE(!bFirst
, "no sheet selected");
158 // only limit to used cells if whole sheet was marked
159 // (so empty cell areas can be copied)
160 if ( nCol2
>=m_pDoc
->MaxCol() && nRow2
>=m_pDoc
->MaxRow() )
164 GetAreaSize( *m_pDoc
, nTab1
, nTab2
, nMaxRow
, nMaxCol
);
165 if( nMaxRow
< nRow2
)
167 if( nMaxCol
< nCol2
)
171 m_aBlock
= ScRange( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
172 m_nVisibleTab
= nTab1
; // valid table as default
174 tools::Rectangle aMMRect
= m_pDoc
->GetMMRect( nCol1
,nRow1
, nCol2
,nRow2
, nTab1
);
175 m_aObjDesc
.maSize
= aMMRect
.GetSize();
176 PrepareOLE( m_aObjDesc
);
179 ScTransferObj::~ScTransferObj()
181 SolarMutexGuard aSolarGuard
;
183 bool bIsDisposing
= comphelper::LibreOfficeKit::isActive() && !ScTabViewShell::GetActiveViewShell();
184 ScModule
* pScMod
= ScModule::get();
185 if (pScMod
&& !bIsDisposing
&& pScMod
->GetDragData().pCellTransfer
== this)
187 OSL_FAIL("ScTransferObj wasn't released");
188 pScMod
->ResetDragObject();
191 m_pDoc
.reset(); // ScTransferObj is owner of clipboard document
193 m_aDocShellRef
.clear(); // before releasing the mutex
195 m_aDrawPersistRef
.clear(); // after the model
199 ScTransferObj
* ScTransferObj::GetOwnClipboard(const uno::Reference
<datatransfer::XTransferable2
>& xTransferable
)
201 return dynamic_cast<ScTransferObj
*>(xTransferable
.get());
204 void ScTransferObj::AddSupportedFormats()
206 // same formats as in ScSelectionTransferObj::AddSupportedFormats
207 AddFormat( SotClipboardFormatId::EMBED_SOURCE
);
208 AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR
);
209 AddFormat( SotClipboardFormatId::GDIMETAFILE
);
210 AddFormat( SotClipboardFormatId::PNG
);
211 AddFormat( SotClipboardFormatId::BITMAP
);
213 // ScImportExport formats
214 AddFormat( SotClipboardFormatId::HTML
);
215 AddFormat( SotClipboardFormatId::SYLK
);
216 AddFormat( SotClipboardFormatId::LINK
);
217 AddFormat( SotClipboardFormatId::DIF
);
218 AddFormat( SotClipboardFormatId::STRING
);
219 AddFormat( SotClipboardFormatId::STRING_TSVC
);
221 AddFormat( SotClipboardFormatId::RTF
);
222 AddFormat( SotClipboardFormatId::RICHTEXT
);
223 if ( m_aBlock
.aStart
== m_aBlock
.aEnd
)
225 AddFormat( SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT
);
229 static ScRange
lcl_reduceBlock(const ScDocument
& rDoc
, ScRange aReducedBlock
, bool bIncludeVisual
= false)
231 if ((aReducedBlock
.aEnd
.Col() == rDoc
.MaxCol() || aReducedBlock
.aEnd
.Row() == rDoc
.MaxRow()) &&
232 aReducedBlock
.aStart
.Tab() == aReducedBlock
.aEnd
.Tab())
234 // Shrink the block here so we don't waste time creating huge
235 // output when whole columns or rows are selected.
237 SCCOL nPrintAreaEndCol
= 0;
238 SCROW nPrintAreaEndRow
= 0;
240 rDoc
.GetPrintArea( aReducedBlock
.aStart
.Tab(), nPrintAreaEndCol
, nPrintAreaEndRow
, true );
242 // Shrink the area to allow pasting to external applications.
243 // Shrink to real data area for HTML, RTF and RICHTEXT, but include
244 // all objects and top-left area for BITMAP and PNG.
245 SCCOL nStartCol
= aReducedBlock
.aStart
.Col();
246 SCROW nStartRow
= aReducedBlock
.aStart
.Row();
247 SCCOL nEndCol
= aReducedBlock
.aEnd
.Col();
248 SCROW nEndRow
= aReducedBlock
.aEnd
.Row();
252 ScDataAreaExtras aDataAreaExtras
;
253 aDataAreaExtras
.mbCellNotes
= true;
254 aDataAreaExtras
.mbCellDrawObjects
= true;
255 bool bShrunk
= false;
256 rDoc
.ShrinkToUsedDataArea( bShrunk
, aReducedBlock
.aStart
.Tab(), nStartCol
, nStartRow
, nEndCol
, nEndRow
,
257 false, true /*bStickyTopRow*/, true /*bStickyLeftCol*/, &aDataAreaExtras
);
258 aDataAreaExtras
.GetOverallRange( nStartCol
, nStartRow
, nEndCol
, nEndRow
, ScDataAreaExtras::Clip::None
);
262 bool bShrunk
= false;
263 rDoc
.ShrinkToUsedDataArea( bShrunk
, aReducedBlock
.aStart
.Tab(), nStartCol
, nStartRow
, nEndCol
, nEndRow
,
264 false, false /*bStickyTopRow*/, false /*bStickyLeftCol*/);
267 if ( nPrintAreaEndRow
> nEndRow
)
268 nEndRow
= nPrintAreaEndRow
;
270 if ( nPrintAreaEndCol
> nEndCol
)
271 nEndCol
= nPrintAreaEndCol
;
273 aReducedBlock
= ScRange(nStartCol
, nStartRow
, aReducedBlock
.aStart
.Tab(), nEndCol
, nEndRow
, aReducedBlock
.aEnd
.Tab());
275 return aReducedBlock
;
278 bool ScTransferObj::GetData( const datatransfer::DataFlavor
& rFlavor
, const OUString
& /*rDestDoc*/ )
280 SotClipboardFormatId nFormat
= SotExchange::GetFormat( rFlavor
);
283 if( HasFormat( nFormat
) )
285 ScRange aReducedBlock
= m_aBlock
;
287 bool bReduceBlockFormat
=
288 nFormat
== SotClipboardFormatId::HTML
289 || nFormat
== SotClipboardFormatId::RTF
290 || nFormat
== SotClipboardFormatId::RICHTEXT
291 || nFormat
== SotClipboardFormatId::BITMAP
292 || nFormat
== SotClipboardFormatId::PNG
;
294 const bool bIncludeVisual
= (nFormat
== SotClipboardFormatId::BITMAP
||
295 nFormat
== SotClipboardFormatId::PNG
);
297 if (bReduceBlockFormat
)
298 aReducedBlock
= lcl_reduceBlock(*m_pDoc
, m_aBlock
, bIncludeVisual
);
300 if ( nFormat
== SotClipboardFormatId::LINKSRCDESCRIPTOR
|| nFormat
== SotClipboardFormatId::OBJECTDESCRIPTOR
)
302 bOK
= SetTransferableObjectDescriptor( m_aObjDesc
);
304 else if ( ( nFormat
== SotClipboardFormatId::RTF
|| nFormat
== SotClipboardFormatId::RICHTEXT
||
305 nFormat
== SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT
) && m_aBlock
.aStart
== m_aBlock
.aEnd
)
307 // RTF from a single cell is handled by EditEngine
309 SCCOL nCol
= m_aBlock
.aStart
.Col();
310 SCROW nRow
= m_aBlock
.aStart
.Row();
311 SCTAB nTab
= m_aBlock
.aStart
.Tab();
312 ScAddress
aPos(nCol
, nRow
, nTab
);
314 const ScPatternAttr
* pPattern
= m_pDoc
->GetPattern( nCol
, nRow
, nTab
);
317 ScTabEditEngine
aEngine(*pPattern
, m_pDoc
->GetEditPool(), m_pDoc
.get());
318 ScRefCellValue
aCell(*m_pDoc
, aPos
);
319 if (aCell
.getType() == CELLTYPE_EDIT
)
321 const EditTextObject
* pObj
= aCell
.getEditText();
322 aEngine
.SetTextCurrentDefaults(*pObj
);
326 ScInterpreterContext
& rContext
= m_pDoc
->GetNonThreadedContext();
327 sal_uInt32 nNumFmt
= pPattern
->GetNumberFormat(rContext
);
330 = ScCellFormat::GetString(aCell
, nNumFmt
, &pColor
, &rContext
, *m_pDoc
);
331 if (!aText
.isEmpty())
332 aEngine
.SetTextCurrentDefaults(aText
);
335 bOK
= SetObject(&aEngine
,
336 ((nFormat
== SotClipboardFormatId::RTF
)
337 ? SCTRANS_TYPE_EDIT_RTF
338 : ((nFormat
== SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT
)
339 ? SCTRANS_TYPE_EDIT_ODF_TEXT_FLAT
340 : SCTRANS_TYPE_EDIT_BIN
)),
344 else if ( ScImportExport::IsFormatSupported( nFormat
) || nFormat
== SotClipboardFormatId::RTF
345 || nFormat
== SotClipboardFormatId::RICHTEXT
)
347 // if this transfer object was used to create a DDE link, filtered rows
348 // have to be included for subsequent calls (to be consistent with link data)
349 if ( nFormat
== SotClipboardFormatId::LINK
)
350 m_bUsedForLink
= true;
352 bool bIncludeFiltered
= m_pDoc
->IsCutMode() || m_bUsedForLink
;
354 ScImportExport
aObj( *m_pDoc
, aReducedBlock
);
355 // Plain text ("Unformatted text") may contain embedded tabs and
356 // line breaks but is not enclosed in quotes. Which makes it
357 // unsuitable for multiple cells, especially if one of them is
358 // multi-line, but otherwise is expected behavior for plain text.
359 // For multiple cells replace embedded line breaks (and tabs) with
360 // space character, otherwise pasting would yield odd results.
361 /* XXX: it's debatable whether this is actually expected, but
362 * there's no way to satisfy all possible requirements when
363 * copy/pasting unformatted text. */
364 const bool bPlainMulti
= (nFormat
== SotClipboardFormatId::STRING
&&
365 aReducedBlock
.aStart
!= aReducedBlock
.aEnd
);
366 // Add quotes only for STRING_TSVC.
367 /* TODO: a possible future STRING_TSV should not contain embedded
368 * line breaks nor tab (separator) characters and not be quoted.
369 * A possible STRING_CSV should. */
370 ScExportTextOptions
aTextOptions( ScExportTextOptions::None
, 0,
371 (nFormat
== SotClipboardFormatId::STRING_TSVC
));
372 if ( bPlainMulti
|| m_bUsedForLink
)
374 // For a DDE link or plain text multiple cells, convert line
375 // breaks and separators to space.
376 aTextOptions
.meNewlineConversion
= ScExportTextOptions::ToSpace
;
377 aTextOptions
.mcSeparatorConvertTo
= ' ';
378 aTextOptions
.mbAddQuotes
= false;
380 aObj
.SetExportTextOptions(aTextOptions
);
381 aObj
.SetFormulas( m_pDoc
->GetViewOptions().GetOption( VOPT_FORMULAS
) );
382 aObj
.SetIncludeFiltered( bIncludeFiltered
);
384 // DataType depends on format type:
386 if ( rFlavor
.DataType
.equals( ::cppu::UnoType
<OUString
>::get() ) )
389 if ( aObj
.ExportString( aString
, nFormat
) )
390 bOK
= SetString( aString
);
392 else if ( rFlavor
.DataType
.equals( cppu::UnoType
<uno::Sequence
< sal_Int8
>>::get() ) )
394 // SetObject converts a stream into an Int8-Sequence
395 bOK
= SetObject( &aObj
, SCTRANS_TYPE_IMPEX
, rFlavor
);
399 OSL_FAIL("unknown DataType");
402 else if ( nFormat
== SotClipboardFormatId::BITMAP
|| nFormat
== SotClipboardFormatId::PNG
)
404 tools::Rectangle aMMRect
= m_pDoc
->GetMMRect( aReducedBlock
.aStart
.Col(), aReducedBlock
.aStart
.Row(),
405 aReducedBlock
.aEnd
.Col(), aReducedBlock
.aEnd
.Row(),
406 aReducedBlock
.aStart
.Tab() );
407 ScopedVclPtrInstance
< VirtualDevice
> pVirtDev
;
409 // tdf#160855 fix crash due to Skia's internal maximum pixel limit
410 // Somewhere in the tens of thousands of selected fill cells,
411 // the size of the VirtualDevice exceeds 1 GB of pixels. But
412 // Skia, at least on macOS, will fail to create a surface.
413 // Even if there is ample free memory, Skia/Raster will fail.
414 // The second problem is that even if you disable Skia, the
415 // crash is just delayed when a BitmapEx is created from the
416 // VirtualDevice and malloc() fails.
417 // Since this data flavor really triggers one or more system
418 // memory limits, lower the resolution of the bitmap by keeping
419 // the VirtualDevice pixel size within an arbitrary number of
421 // Note: the arbitrary "maximum number of pixels" limit that
422 // that Skia can handle may need to be raised or lowered for
423 // platforms other than macOS.
424 static constexpr tools::Long nCopyToImageMaxPixels
= 8192 * 8192;
425 Fraction
aScale(1.0);
426 Size aPixelSize
= pVirtDev
->LogicToPixel(aMMRect
.GetSize(), MapMode(MapUnit::Map100thMM
));
427 tools::Long
nPixels(aPixelSize
.Width() * aPixelSize
.Height());
428 if (nPixels
< 0 || nPixels
> nCopyToImageMaxPixels
)
430 aScale
= Fraction(nCopyToImageMaxPixels
, nPixels
);
431 aPixelSize
= pVirtDev
->LogicToPixel(aMMRect
.GetSize(), MapMode(MapUnit::Map100thMM
, Point(), aScale
, aScale
));
432 nPixels
= aPixelSize
.Width() * aPixelSize
.Height();
435 pVirtDev
->SetOutputSizePixel(aPixelSize
);
437 PaintToDev( pVirtDev
, *m_pDoc
, 1.0, aReducedBlock
);
439 pVirtDev
->SetMapMode( MapMode( MapUnit::MapPixel
, Point(), aScale
, aScale
) );
440 BitmapEx aBmp
= pVirtDev
->GetBitmapEx( Point(), pVirtDev
->GetOutputSize() );
441 bOK
= SetBitmapEx( aBmp
, rFlavor
);
443 else if ( nFormat
== SotClipboardFormatId::GDIMETAFILE
)
445 // #i123405# Do not limit visual size calculation for metafile creation.
446 // It seems unlikely that removing the limitation causes problems since
447 // metafile creation means that no real pixel device in the needed size is
451 SfxObjectShell
* pEmbObj
= m_aDocShellRef
.get();
453 // like SvEmbeddedTransfer::GetData:
455 ScopedVclPtrInstance
< VirtualDevice
> pVDev
;
456 MapMode
aMapMode( pEmbObj
->GetMapUnit() );
457 tools::Rectangle
aVisArea( pEmbObj
->GetVisArea( ASPECT_CONTENT
) );
459 pVDev
->EnableOutput( false );
460 pVDev
->SetMapMode( aMapMode
);
461 aMtf
.SetPrefSize( aVisArea
.GetSize() );
462 aMtf
.SetPrefMapMode( aMapMode
);
463 aMtf
.Record( pVDev
);
465 pEmbObj
->DoDraw( pVDev
, Point(), aVisArea
.GetSize(), JobSetup() );
470 bOK
= SetGDIMetaFile( aMtf
);
472 else if ( nFormat
== SotClipboardFormatId::EMBED_SOURCE
)
474 //TODO/LATER: differentiate between formats?!
475 // #i123405# Do limit visual size calculation to PageSize
476 InitDocShell(true); // set aDocShellRef
478 SfxObjectShell
* pEmbObj
= m_aDocShellRef
.get();
479 bOK
= SetObject( pEmbObj
, SCTRANS_TYPE_EMBOBJ
, rFlavor
);
485 bool ScTransferObj::WriteObject( SvStream
& rOStm
, void* pUserObject
, sal_uInt32 nUserObjectId
,
486 const datatransfer::DataFlavor
& rFlavor
)
488 // called from SetObject, put data into stream
491 switch (nUserObjectId
)
493 case SCTRANS_TYPE_IMPEX
:
495 ScImportExport
* pImpEx
= static_cast<ScImportExport
*>(pUserObject
);
497 SotClipboardFormatId nFormat
= SotExchange::GetFormat( rFlavor
);
498 // mba: no BaseURL for data exchange
499 if ( pImpEx
->ExportStream( rOStm
, OUString(), nFormat
) )
500 bRet
= ( rOStm
.GetError() == ERRCODE_NONE
);
504 case SCTRANS_TYPE_EDIT_RTF
:
505 case SCTRANS_TYPE_EDIT_BIN
:
507 ScTabEditEngine
* pEngine
= static_cast<ScTabEditEngine
*>(pUserObject
);
508 if ( nUserObjectId
== SCTRANS_TYPE_EDIT_RTF
)
510 pEngine
->Write( rOStm
, EETextFormat::Rtf
);
511 bRet
= ( rOStm
.GetError() == ERRCODE_NONE
);
515 // can't use Write for EditEngine format because that would
516 // write old format without support for unicode characters.
517 // Get the data from the EditEngine's transferable instead.
519 sal_Int32 nParCnt
= pEngine
->GetParagraphCount();
522 ESelection
aSel( 0, 0, nParCnt
-1, pEngine
->GetTextLen(nParCnt
-1) );
524 uno::Reference
<datatransfer::XTransferable
> xEditTrans
= pEngine
->CreateTransferable( aSel
);
525 TransferableDataHelper
aEditHelper( xEditTrans
);
527 std::unique_ptr
<SvStream
> xStrm
= aEditHelper
.GetSotStorageStream( rFlavor
);
530 rOStm
.WriteStream(*xStrm
);
535 case SCTRANS_TYPE_EDIT_ODF_TEXT_FLAT
:
537 ScTabEditEngine
* pEngine
= static_cast<ScTabEditEngine
*>(pUserObject
);
538 pEngine
->Write(rOStm
, EETextFormat::Xml
);
539 bRet
= (rOStm
.GetError() == ERRCODE_NONE
);
543 case SCTRANS_TYPE_EMBOBJ
:
546 SfxObjectShell
* pEmbObj
= static_cast<SfxObjectShell
*>(pUserObject
);
547 ::utl::TempFileFast aTempFile
;
548 SvStream
* pTempStream
= aTempFile
.GetStream(StreamMode::READWRITE
);
549 uno::Reference
< embed::XStorage
> xWorkStore
=
550 ::comphelper::OStorageHelper::GetStorageFromStream( new utl::OStreamWrapper(*pTempStream
) );
552 // write document storage
553 pEmbObj
->SetupStorage( xWorkStore
, SOFFICE_FILEFORMAT_CURRENT
, false );
555 // mba: no relative URLs for clipboard!
556 SfxMedium
aMedium( xWorkStore
, OUString() );
557 pEmbObj
->DoSaveObjectAs( aMedium
, false );
558 pEmbObj
->DoSaveCompleted();
560 uno::Reference
< embed::XTransactedObject
> xTransact( xWorkStore
, uno::UNO_QUERY
);
561 if ( xTransact
.is() )
564 rOStm
.SetBufferSize( 0xff00 );
565 rOStm
.WriteStream( *pTempStream
);
569 xWorkStore
->dispose();
575 OSL_FAIL("unknown object id");
580 sal_Bool SAL_CALL
ScTransferObj::isComplex()
582 ScRange aReduced
= lcl_reduceBlock(*m_pDoc
, m_aBlock
);
583 size_t nCells
= (aReduced
.aEnd
.Col() - aReduced
.aStart
.Col() + 1) *
584 (aReduced
.aEnd
.Row() - aReduced
.aStart
.Row() + 1) *
585 (aReduced
.aEnd
.Tab() - aReduced
.aStart
.Tab() + 1);
586 return nCells
> 1000;
589 void ScTransferObj::DragFinished( sal_Int8 nDropAction
)
591 if ( nDropAction
== DND_ACTION_MOVE
&& !m_bDragWasInternal
&& !(m_nDragSourceFlags
& ScDragSrc::Navigator
) )
593 // move: delete source data
594 ScDocShell
* pSourceSh
= GetSourceDocShell();
597 ScMarkData aMarkData
= GetSourceMarkData();
598 // external drag&drop doesn't copy objects, so they also aren't deleted:
599 // bApi=TRUE, don't show error messages from drag&drop
600 pSourceSh
->GetDocFunc().DeleteContents( aMarkData
, InsertDeleteFlags::ALL
& ~InsertDeleteFlags::OBJECTS
, true, true );
604 ScModule
* pScMod
= ScModule::get();
605 if ( pScMod
&& pScMod
->GetDragData().pCellTransfer
== this )
606 pScMod
->ResetDragObject();
608 m_xDragSourceRanges
= nullptr; // don't keep source after dropping
610 TransferDataContainer::DragFinished( nDropAction
);
613 void ScTransferObj::SetDragHandlePos( SCCOL nX
, SCROW nY
)
619 void ScTransferObj::SetSourceCursorPos( SCCOL nX
, SCROW nY
)
621 m_nSourceCursorX
= nX
;
622 m_nSourceCursorY
= nY
;
625 bool ScTransferObj::WasSourceCursorInSelection() const
628 m_nSourceCursorX
>= m_aBlock
.aStart
.Col() && m_nSourceCursorX
<= m_aBlock
.aEnd
.Col() &&
629 m_nSourceCursorY
>= m_aBlock
.aStart
.Row() && m_nSourceCursorY
<= m_aBlock
.aEnd
.Row();
632 void ScTransferObj::SetVisibleTab( SCTAB nNew
)
634 m_nVisibleTab
= nNew
;
637 void ScTransferObj::SetDrawPersist( const SfxObjectShellRef
& rRef
)
639 m_aDrawPersistRef
= rRef
;
642 void ScTransferObj::SetDragSource( ScDocShell
* pSourceShell
, const ScMarkData
& rMark
)
645 rMark
.FillRangeListWithMarks( &aRanges
, false );
646 m_xDragSourceRanges
= new ScCellRangesObj( pSourceShell
, aRanges
);
649 void ScTransferObj::SetDragSourceFlags(ScDragSrc nFlags
)
651 m_nDragSourceFlags
= nFlags
;
654 void ScTransferObj::SetDragWasInternal()
656 m_bDragWasInternal
= true;
659 void ScTransferObj::SetUseInApi( bool bSet
)
664 ScDocument
* ScTransferObj::GetSourceDocument()
666 ScDocShell
* pSourceDocSh
= GetSourceDocShell();
668 return &pSourceDocSh
->GetDocument();
672 ScDocShell
* ScTransferObj::GetSourceDocShell()
674 if (m_xDragSourceRanges
)
675 return m_xDragSourceRanges
->GetDocShell();
677 return nullptr; // none set
680 ScMarkData
ScTransferObj::GetSourceMarkData() const
682 ScMarkData
aMarkData(m_pDoc
->GetSheetLimits());
683 if (m_xDragSourceRanges
)
685 const ScRangeList
& rRanges
= m_xDragSourceRanges
->GetRangeList();
686 aMarkData
.MarkFromRangeList( rRanges
, false );
691 // initialize aDocShellRef with a live document from the ClipDoc
693 // #i123405# added parameter to allow size calculation without limitation
694 // to PageSize, e.g. used for Metafile creation for clipboard.
696 void ScTransferObj::InitDocShell(bool bLimitToPageSize
)
698 if ( m_aDocShellRef
.is() )
701 m_aDocShellRef
= new ScDocShell
; // ref must be there before InitNew
703 m_aDocShellRef
->DoInitNew();
705 ScDocument
& rDestDoc
= m_aDocShellRef
->GetDocument();
706 ScMarkData
aDestMark(rDestDoc
.GetSheetLimits());
707 aDestMark
.SelectTable( 0, true );
709 rDestDoc
.SetDocOptions( m_pDoc
->GetDocOptions() ); // #i42666#
712 m_pDoc
->GetName( m_aBlock
.aStart
.Tab(), aTabName
);
713 rDestDoc
.RenameTab( 0, aTabName
);
715 m_aDocShellRef
->MakeDrawLayer();
717 rDestDoc
.CopyStdStylesFrom(*m_pDoc
);
719 SCCOL nStartX
= m_aBlock
.aStart
.Col();
720 SCROW nStartY
= m_aBlock
.aStart
.Row();
721 SCCOL nEndX
= m_aBlock
.aEnd
.Col();
722 SCROW nEndY
= m_aBlock
.aEnd
.Row();
725 // (must be copied before CopyFromClip, for drawing objects)
728 SCTAB nSrcTab
= m_aBlock
.aStart
.Tab();
729 rDestDoc
.SetLayoutRTL(0, m_pDoc
->IsLayoutRTL(nSrcTab
));
730 for (nCol
=nStartX
; nCol
<=nEndX
; nCol
++)
731 if ( m_pDoc
->ColHidden(nCol
, nSrcTab
) )
732 rDestDoc
.ShowCol( nCol
, 0, false );
734 rDestDoc
.SetColWidth( nCol
, 0, m_pDoc
->GetColWidth( nCol
, nSrcTab
) );
738 // Set manual height for all previous rows so we can ensure
739 // that visible area will not change due to autoheight
740 rDestDoc
.SetManualHeight(0, nStartY
- 1, 0, true);
742 for (SCROW nRow
= nStartY
; nRow
<= nEndY
; ++nRow
)
744 if ( m_pDoc
->RowHidden(nRow
, nSrcTab
) )
745 rDestDoc
.ShowRow( nRow
, 0, false );
748 rDestDoc
.SetRowHeight( nRow
, 0, m_pDoc
->GetOriginalHeight( nRow
, nSrcTab
) );
750 // if height was set manually, that flag has to be copied, too
751 bool bManual
= m_pDoc
->IsManualRowHeight(nRow
, nSrcTab
);
752 rDestDoc
.SetManualHeight(nRow
, nRow
, 0, bManual
);
756 // cell range is copied to the original position, but on the first sheet
757 // -> bCutMode must be set
758 // pDoc is always a Clipboard-document
760 ScRange
aDestRange( nStartX
,nStartY
,0, nEndX
,nEndY
,0 );
761 bool bWasCut
= m_pDoc
->IsCutMode();
763 m_pDoc
->SetClipArea( aDestRange
, true ); // Cut
764 rDestDoc
.CopyFromClip( aDestRange
, aDestMark
, InsertDeleteFlags::ALL
, nullptr, m_pDoc
.get(), false );
765 m_pDoc
->SetClipArea( aDestRange
, bWasCut
);
767 StripRefs(*m_pDoc
, nStartX
,nStartY
, nEndX
,nEndY
, rDestDoc
);
769 ScRange aMergeRange
= aDestRange
;
770 rDestDoc
.ExtendMerge( aMergeRange
, true );
772 m_pDoc
->CopyDdeLinks( rDestDoc
); // copy values of DDE Links
774 // page format (grid etc) and page size (maximum size for ole object)
776 Size aPaperSize
= SvxPaperInfo::GetPaperSize( PAPER_A4
); // Twips
777 ScStyleSheetPool
* pStylePool
= m_pDoc
->GetStyleSheetPool();
778 OUString aStyleName
= m_pDoc
->GetPageStyle( m_aBlock
.aStart
.Tab() );
779 SfxStyleSheetBase
* pStyleSheet
= pStylePool
->Find( aStyleName
, SfxStyleFamily::Page
);
782 const SfxItemSet
& rSourceSet
= pStyleSheet
->GetItemSet();
783 aPaperSize
= rSourceSet
.Get(ATTR_PAGE_SIZE
).GetSize();
785 // CopyStyleFrom copies SetItems with correct pool
786 ScStyleSheetPool
* pDestPool
= rDestDoc
.GetStyleSheetPool();
787 pDestPool
->CopyStyleFrom( pStylePool
, aStyleName
, SfxStyleFamily::Page
);
790 ScViewData
aViewData(*m_aDocShellRef
, nullptr);
791 aViewData
.SetScreen( nStartX
,nStartY
, nEndX
,nEndY
);
792 aViewData
.SetCurX( nStartX
);
793 aViewData
.SetCurY( nStartY
);
795 rDestDoc
.SetViewOptions( m_pDoc
->GetViewOptions() );
798 //! get while copying sizes
800 tools::Long nPosX
= 0;
801 tools::Long nPosY
= 0;
803 for (nCol
=0; nCol
<nStartX
; nCol
++)
804 nPosX
+= rDestDoc
.GetColWidth( nCol
, 0 );
805 nPosY
+= rDestDoc
.GetRowHeight( 0, nStartY
-1, 0 );
806 nPosX
= o3tl::convert(nPosX
, o3tl::Length::twip
, o3tl::Length::mm100
);
807 nPosY
= o3tl::convert(nPosY
, o3tl::Length::twip
, o3tl::Length::mm100
);
809 aPaperSize
.setWidth( aPaperSize
.Width() * 2 ); // limit OLE object to double of page size
810 aPaperSize
.setHeight( aPaperSize
.Height() * 2 );
812 tools::Long nSizeX
= 0;
813 tools::Long nSizeY
= 0;
814 for (nCol
=nStartX
; nCol
<=nEndX
; nCol
++)
816 tools::Long nAdd
= rDestDoc
.GetColWidth( nCol
, 0 );
817 if ( bLimitToPageSize
&& nSizeX
+nAdd
> aPaperSize
.Width() && nSizeX
) // above limit?
821 for (SCROW nRow
=nStartY
; nRow
<=nEndY
; nRow
++)
823 tools::Long nAdd
= rDestDoc
.GetRowHeight( nRow
, 0 );
824 if ( bLimitToPageSize
&& nSizeY
+nAdd
> aPaperSize
.Height() && nSizeY
) // above limit?
828 nSizeX
= o3tl::convert(nSizeX
, o3tl::Length::twip
, o3tl::Length::mm100
);
829 nSizeY
= o3tl::convert(nSizeY
, o3tl::Length::twip
, o3tl::Length::mm100
);
831 // m_aDocShellRef->SetVisAreaSize( Size(nSizeX,nSizeY) );
833 tools::Rectangle
aNewArea( Point(nPosX
,nPosY
), Size(nSizeX
,nSizeY
) );
834 //TODO/LATER: why twice?!
835 //m_aDocShellRef->SvInPlaceObject::SetVisArea( aNewArea );
836 m_aDocShellRef
->SetVisArea(aNewArea
);
838 m_aDocShellRef
->UpdateOle(aViewData
, true);
840 //! SetDocumentModified?
841 if ( rDestDoc
.IsChartListenerCollectionNeedsUpdate() )
842 rDestDoc
.UpdateChartListenerCollection();
845 SfxObjectShell
* ScTransferObj::SetDrawClipDoc( bool bAnyOle
, const std::shared_ptr
<ScDocument
>& pDoc
)
847 // update ScGlobal::xDrawClipDocShellRef
849 ScGlobal::xDrawClipDocShellRef
.clear();
852 ScGlobal::xDrawClipDocShellRef
= new ScDocShell(SfxModelFlags::EMBEDDED_OBJECT
| SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS
, pDoc
); // there must be a ref
853 ScGlobal::xDrawClipDocShellRef
->DoInitNew();
856 return ScGlobal::xDrawClipDocShellRef
.get();
859 void ScTransferObj::StripRefs( ScDocument
& rDoc
,
860 SCCOL nStartX
, SCROW nStartY
, SCCOL nEndX
, SCROW nEndY
,
861 ScDocument
& rDestDoc
)
863 // In a clipboard doc the data don't have to be on the first sheet
866 while (nSrcTab
< rDoc
.GetTableCount() && !rDoc
.HasTable(nSrcTab
))
869 while (nDestTab
< rDestDoc
.GetTableCount() && !rDestDoc
.HasTable(nDestTab
))
872 if (!rDoc
.HasTable(nSrcTab
) || !rDestDoc
.HasTable(nDestTab
))
874 OSL_FAIL("Sheet not found in ScTransferObj::StripRefs");
880 ScCellIterator
aIter( rDoc
, ScRange(nStartX
, nStartY
, nSrcTab
, nEndX
, nEndY
, nSrcTab
) );
881 for (bool bHas
= aIter
.first(); bHas
; bHas
= aIter
.next())
883 if (aIter
.getType() != CELLTYPE_FORMULA
)
886 ScFormulaCell
* pFCell
= aIter
.getFormulaCell();
888 ScDetectiveRefIter
aRefIter( rDoc
, pFCell
);
889 while ( !bOut
&& aRefIter
.GetNextRef( aRef
) )
891 if ( aRef
.aStart
.Tab() != nSrcTab
|| aRef
.aEnd
.Tab() != nSrcTab
||
892 aRef
.aStart
.Col() < nStartX
|| aRef
.aEnd
.Col() > nEndX
||
893 aRef
.aStart
.Row() < nStartY
|| aRef
.aEnd
.Row() > nEndY
)
898 SCCOL nCol
= aIter
.GetPos().Col();
899 SCROW nRow
= aIter
.GetPos().Row();
901 FormulaError nErrCode
= pFCell
->GetErrCode();
902 ScAddress
aPos(nCol
, nRow
, nDestTab
);
903 if (nErrCode
!= FormulaError::NONE
)
905 if ( rDestDoc
.GetAttr( nCol
,nRow
,nDestTab
, ATTR_HOR_JUSTIFY
)->GetValue() ==
906 SvxCellHorJustify::Standard
)
907 rDestDoc
.ApplyAttr( nCol
,nRow
,nDestTab
,
908 SvxHorJustifyItem(SvxCellHorJustify::Right
, ATTR_HOR_JUSTIFY
) );
910 ScSetStringParam aParam
;
911 aParam
.setTextInput();
912 rDestDoc
.SetString(aPos
, ScGlobal::GetErrorString(nErrCode
), &aParam
);
914 else if (pFCell
->IsValue())
916 rDestDoc
.SetValue(aPos
, pFCell
->GetValue());
920 OUString aStr
= pFCell
->GetString().getString();
921 if ( pFCell
->IsMultilineResult() )
923 ScFieldEditEngine
& rEngine
= rDestDoc
.GetEditEngine();
924 rEngine
.SetTextCurrentDefaults(aStr
);
925 rDestDoc
.SetEditText(ScAddress(nCol
,nRow
,nDestTab
), rEngine
.CreateTextObject());
929 ScSetStringParam aParam
;
930 aParam
.setTextInput();
931 rDestDoc
.SetString(aPos
, aStr
, &aParam
);
938 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */