tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / app / transobj.cxx
blob16a93d55746172ca45d92a4cb4131b19cd8e9865
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #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>
36 #include <utility>
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>
50 #include <impex.hxx>
51 #include <formulacell.hxx>
52 #include <printfun.hxx>
53 #include <docfunc.hxx>
54 #include <scmod.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>
62 #include <docsh.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 )
81 SCCOL nMaxCol = 0;
82 SCROW nMaxRow = 0;
83 for( SCTAB nTab = nTab1; nTab <= nTab2; nTab++ )
85 SCCOL nLastCol = 0;
86 SCROW nLastRow = 0;
87 // GetPrintArea instead of GetCellArea - include drawing objects
88 if( rDoc.GetPrintArea( nTab, nLastCol, nLastRow ) )
90 if( nLastCol > nMaxCol )
91 nMaxCol = nLastCol;
92 if( nLastRow > nMaxRow )
93 nMaxRow = nLastRow;
96 nRow = nMaxRow;
97 nCol = nMaxCol;
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 ) :
115 m_pDoc( pClipDoc ),
116 m_nNonFiltered(0),
117 m_aObjDesc(std::move( aDesc )),
118 m_nDragHandleX( 0 ),
119 m_nDragHandleY( 0 ),
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 ),
125 m_bUseInApi( false )
127 OSL_ENSURE(m_pDoc->IsClipboard(), "wrong document");
129 // get aBlock from clipboard doc
131 SCCOL nCol1;
132 SCROW nRow1;
133 SCCOL nCol2;
134 SCROW nRow2;
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 );
140 SCCOL nDummy;
141 m_pDoc->GetClipArea( nDummy, m_nNonFiltered, false );
142 m_bHasFiltered = (m_nNonFiltered < (nRow2 - nRow1));
143 ++m_nNonFiltered; // to get count instead of diff
145 SCTAB nTab1=0;
146 SCTAB nTab2=0;
147 bool bFirst = true;
148 for (SCTAB i=0; i< m_pDoc->GetTableCount(); i++)
149 if (m_pDoc->HasTable(i))
151 if (bFirst)
152 nTab1 = i;
153 nTab2 = i;
154 bFirst = false;
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() )
162 SCROW nMaxRow;
163 SCCOL nMaxCol;
164 GetAreaSize( *m_pDoc, nTab1, nTab2, nMaxRow, nMaxCol );
165 if( nMaxRow < nRow2 )
166 nRow2 = nMaxRow;
167 if( nMaxCol < nCol2 )
168 nCol2 = nMaxCol;
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;
239 if (bIncludeVisual)
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();
250 if (bIncludeVisual)
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);
260 else
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 );
281 bool bOK = false;
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 );
315 if (pPattern)
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);
324 else
326 ScInterpreterContext& rContext = m_pDoc->GetNonThreadedContext();
327 sal_uInt32 nNumFmt = pPattern->GetNumberFormat(rContext);
328 const Color* pColor;
329 OUString aText
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)),
341 rFlavor);
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() ) )
388 OUString aString;
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 );
397 else
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
420 // pixels.
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
448 // created.
449 InitDocShell(false);
451 SfxObjectShell* pEmbObj = m_aDocShellRef.get();
453 // like SvEmbeddedTransfer::GetData:
454 GDIMetaFile aMtf;
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() );
467 aMtf.Stop();
468 aMtf.WindStart();
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 );
482 return bOK;
485 bool ScTransferObj::WriteObject( SvStream& rOStm, void* pUserObject, sal_uInt32 nUserObjectId,
486 const datatransfer::DataFlavor& rFlavor )
488 // called from SetObject, put data into stream
490 bool bRet = false;
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 );
502 break;
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 );
513 else
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();
520 if ( nParCnt == 0 )
521 nParCnt = 1;
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 );
528 bRet = bool(xStrm);
529 if (bRet)
530 rOStm.WriteStream(*xStrm);
533 break;
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);
541 break;
543 case SCTRANS_TYPE_EMBOBJ:
545 // TODO/MBA: testing
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() )
562 xTransact->commit();
564 rOStm.SetBufferSize( 0xff00 );
565 rOStm.WriteStream( *pTempStream );
567 bRet = true;
569 xWorkStore->dispose();
570 xWorkStore.clear();
572 break;
574 default:
575 OSL_FAIL("unknown object id");
577 return bRet;
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();
595 if (pSourceSh)
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 )
615 m_nDragHandleX = nX;
616 m_nDragHandleY = nY;
619 void ScTransferObj::SetSourceCursorPos( SCCOL nX, SCROW nY )
621 m_nSourceCursorX = nX;
622 m_nSourceCursorY = nY;
625 bool ScTransferObj::WasSourceCursorInSelection() const
627 return
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 )
644 ScRangeList aRanges;
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 )
661 m_bUseInApi = bSet;
664 ScDocument* ScTransferObj::GetSourceDocument()
666 ScDocShell* pSourceDocSh = GetSourceDocShell();
667 if (pSourceDocSh)
668 return &pSourceDocSh->GetDocument();
669 return nullptr;
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 );
688 return aMarkData;
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() )
699 return;
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#
711 OUString aTabName;
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();
724 // widths / heights
725 // (must be copied before CopyFromClip, for drawing objects)
727 SCCOL nCol;
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 );
733 else
734 rDestDoc.SetColWidth( nCol, 0, m_pDoc->GetColWidth( nCol, nSrcTab ) );
736 if (nStartY > 0)
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 );
746 else
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();
762 if (!bWasCut)
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 );
780 if (pStyleSheet)
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() );
797 // Size
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?
818 break;
819 nSizeX += nAdd;
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?
825 break;
826 nSizeY += nAdd;
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();
850 if (bAnyOle)
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
865 SCTAB nSrcTab = 0;
866 while (nSrcTab < rDoc.GetTableCount() && !rDoc.HasTable(nSrcTab))
867 ++nSrcTab;
868 SCTAB nDestTab = 0;
869 while (nDestTab < rDestDoc.GetTableCount() && !rDestDoc.HasTable(nDestTab))
870 ++nDestTab;
872 if (!rDoc.HasTable(nSrcTab) || !rDestDoc.HasTable(nDestTab))
874 OSL_FAIL("Sheet not found in ScTransferObj::StripRefs");
875 return;
878 ScRange aRef;
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)
884 continue;
886 ScFormulaCell* pFCell = aIter.getFormulaCell();
887 bool bOut = false;
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 )
894 bOut = true;
896 if (bOut)
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());
918 else
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());
927 else
929 ScSetStringParam aParam;
930 aParam.setTextInput();
931 rDestDoc.SetString(aPos, aStr, &aParam);
938 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */