summaryrefslogtreecommitdiffstats
path: root/sc/source/ui/app/transobj.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--sc/source/ui/app/transobj.cxx921
1 files changed, 921 insertions, 0 deletions
diff --git a/sc/source/ui/app/transobj.cxx b/sc/source/ui/app/transobj.cxx
new file mode 100644
index 000000000..d0be7e0ae
--- /dev/null
+++ b/sc/source/ui/app/transobj.cxx
@@ -0,0 +1,921 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <editeng/justifyitem.hxx>
+
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+
+#include <o3tl/unit_conversion.hxx>
+#include <osl/diagnose.h>
+#include <unotools/tempfile.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <comphelper/fileformat.h>
+#include <comphelper/lok.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <sot/storage.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/jobset.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/virdev.hxx>
+#include <sfx2/docfile.hxx>
+
+#include <transobj.hxx>
+#include <patattr.hxx>
+#include <cellvalue.hxx>
+#include <cellform.hxx>
+#include <document.hxx>
+#include <viewopti.hxx>
+#include <editutil.hxx>
+#include <impex.hxx>
+#include <formulacell.hxx>
+#include <printfun.hxx>
+#include <docfunc.hxx>
+#include <scmod.hxx>
+#include <dragdata.hxx>
+#include <sortparam.hxx>
+#include <tabvwsh.hxx>
+
+#include <editeng/paperinf.hxx>
+#include <editeng/sizeitem.hxx>
+#include <formula/errorcodes.hxx>
+#include <docsh.hxx>
+#include <markdata.hxx>
+#include <stlpool.hxx>
+#include <viewdata.hxx>
+#include <dociter.hxx>
+#include <cellsuno.hxx>
+#include <stringutil.hxx>
+#include <formulaiter.hxx>
+
+using namespace com::sun::star;
+
+constexpr sal_uInt32 SCTRANS_TYPE_IMPEX = 1;
+constexpr sal_uInt32 SCTRANS_TYPE_EDIT_RTF = 2;
+constexpr sal_uInt32 SCTRANS_TYPE_EDIT_BIN = 3;
+constexpr sal_uInt32 SCTRANS_TYPE_EMBOBJ = 4;
+constexpr sal_uInt32 SCTRANS_TYPE_EDIT_ODF_TEXT_FLAT = 5;
+
+void ScTransferObj::GetAreaSize( const ScDocument& rDoc, SCTAB nTab1, SCTAB nTab2, SCROW& nRow, SCCOL& nCol )
+{
+ SCCOL nMaxCol = 0;
+ SCROW nMaxRow = 0;
+ for( SCTAB nTab = nTab1; nTab <= nTab2; nTab++ )
+ {
+ SCCOL nLastCol = 0;
+ SCROW nLastRow = 0;
+ // GetPrintArea instead of GetCellArea - include drawing objects
+ if( rDoc.GetPrintArea( nTab, nLastCol, nLastRow ) )
+ {
+ if( nLastCol > nMaxCol )
+ nMaxCol = nLastCol;
+ if( nLastRow > nMaxRow )
+ nMaxRow = nLastRow;
+ }
+ }
+ nRow = nMaxRow;
+ nCol = nMaxCol;
+}
+
+void ScTransferObj::PaintToDev( OutputDevice* pDev, ScDocument& rDoc, double nPrintFactor,
+ const ScRange& rBlock )
+{
+ tools::Rectangle aBound( Point(), pDev->GetOutputSize() ); //! use size from clip area?
+
+ ScViewData aViewData(rDoc);
+
+ aViewData.SetTabNo( rBlock.aEnd.Tab() );
+ aViewData.SetScreen( rBlock.aStart.Col(), rBlock.aStart.Row(),
+ rBlock.aEnd.Col(), rBlock.aEnd.Row() );
+
+ ScPrintFunc::DrawToDev( rDoc, pDev, nPrintFactor, aBound, &aViewData, false/*bMetaFile*/ );
+}
+
+ScTransferObj::ScTransferObj( const std::shared_ptr<ScDocument>& pClipDoc, const TransferableObjectDescriptor& rDesc ) :
+ m_pDoc( pClipDoc ),
+ m_nNonFiltered(0),
+ m_aObjDesc( rDesc ),
+ m_nDragHandleX( 0 ),
+ m_nDragHandleY( 0 ),
+ m_nSourceCursorX( m_pDoc->MaxCol() + 1 ),
+ m_nSourceCursorY( m_pDoc->MaxRow() + 1 ),
+ m_nDragSourceFlags( ScDragSrc::Undefined ),
+ m_bDragWasInternal( false ),
+ m_bUsedForLink( false ),
+ m_bUseInApi( false )
+{
+ OSL_ENSURE(m_pDoc->IsClipboard(), "wrong document");
+
+ // get aBlock from clipboard doc
+
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ m_pDoc->GetClipStart( nCol1, nRow1 );
+ m_pDoc->GetClipArea( nCol2, nRow2, true ); // real source area - include filtered rows
+ nCol2 = sal::static_int_cast<SCCOL>( nCol2 + nCol1 );
+ nRow2 = sal::static_int_cast<SCROW>( nRow2 + nRow1 );
+
+ SCCOL nDummy;
+ m_pDoc->GetClipArea( nDummy, m_nNonFiltered, false );
+ m_bHasFiltered = (m_nNonFiltered < (nRow2 - nRow1));
+ ++m_nNonFiltered; // to get count instead of diff
+
+ SCTAB nTab1=0;
+ SCTAB nTab2=0;
+ bool bFirst = true;
+ for (SCTAB i=0; i< m_pDoc->GetTableCount(); i++)
+ if (m_pDoc->HasTable(i))
+ {
+ if (bFirst)
+ nTab1 = i;
+ nTab2 = i;
+ bFirst = false;
+ }
+ OSL_ENSURE(!bFirst, "no sheet selected");
+
+ // only limit to used cells if whole sheet was marked
+ // (so empty cell areas can be copied)
+ if ( nCol2>=m_pDoc->MaxCol() && nRow2>=m_pDoc->MaxRow() )
+ {
+ SCROW nMaxRow;
+ SCCOL nMaxCol;
+ GetAreaSize( *m_pDoc, nTab1, nTab2, nMaxRow, nMaxCol );
+ if( nMaxRow < nRow2 )
+ nRow2 = nMaxRow;
+ if( nMaxCol < nCol2 )
+ nCol2 = nMaxCol;
+ }
+
+ m_aBlock = ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ m_nVisibleTab = nTab1; // valid table as default
+
+ tools::Rectangle aMMRect = m_pDoc->GetMMRect( nCol1,nRow1, nCol2,nRow2, nTab1 );
+ m_aObjDesc.maSize = aMMRect.GetSize();
+ PrepareOLE( m_aObjDesc );
+}
+
+ScTransferObj::~ScTransferObj()
+{
+ SolarMutexGuard aSolarGuard;
+
+ bool bIsDisposing = comphelper::LibreOfficeKit::isActive() && !ScTabViewShell::GetActiveViewShell();
+ ScModule* pScMod = SC_MOD();
+ if (pScMod && !bIsDisposing && pScMod->GetDragData().pCellTransfer == this)
+ {
+ OSL_FAIL("ScTransferObj wasn't released");
+ pScMod->ResetDragObject();
+ }
+
+ m_pDoc.reset(); // ScTransferObj is owner of clipboard document
+
+ m_aDocShellRef.clear(); // before releasing the mutex
+
+ m_aDrawPersistRef.clear(); // after the model
+
+}
+
+ScTransferObj* ScTransferObj::GetOwnClipboard(const uno::Reference<datatransfer::XTransferable2>& xTransferable)
+{
+ return comphelper::getFromUnoTunnel<ScTransferObj>(xTransferable);
+}
+
+void ScTransferObj::AddSupportedFormats()
+{
+ // same formats as in ScSelectionTransferObj::AddSupportedFormats
+ AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BITMAP );
+
+ // ScImportExport formats
+ AddFormat( SotClipboardFormatId::HTML );
+ AddFormat( SotClipboardFormatId::SYLK );
+ AddFormat( SotClipboardFormatId::LINK );
+ AddFormat( SotClipboardFormatId::DIF );
+ AddFormat( SotClipboardFormatId::STRING );
+ AddFormat( SotClipboardFormatId::STRING_TSVC );
+
+ AddFormat( SotClipboardFormatId::RTF );
+ AddFormat( SotClipboardFormatId::RICHTEXT );
+ if ( m_aBlock.aStart == m_aBlock.aEnd )
+ {
+ AddFormat( SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT );
+ }
+}
+
+static ScRange lcl_reduceBlock(const ScDocument& rDoc, ScRange aReducedBlock, bool bIncludeVisual = false)
+{
+ if ((aReducedBlock.aEnd.Col() == rDoc.MaxCol() || aReducedBlock.aEnd.Row() == rDoc.MaxRow()) &&
+ aReducedBlock.aStart.Tab() == aReducedBlock.aEnd.Tab())
+ {
+ // Shrink the block here so we don't waste time creating huge
+ // output when whole columns or rows are selected.
+
+ SCCOL nPrintAreaEndCol = 0;
+ SCROW nPrintAreaEndRow = 0;
+ if (bIncludeVisual)
+ rDoc.GetPrintArea( aReducedBlock.aStart.Tab(), nPrintAreaEndCol, nPrintAreaEndRow, true );
+
+ // Shrink the area to allow pasting to external applications.
+ // Shrink to real data area for HTML, RTF and RICHTEXT, but include
+ // all objects and top-left area for BITMAP and PNG.
+ SCCOL nStartCol = aReducedBlock.aStart.Col();
+ SCROW nStartRow = aReducedBlock.aStart.Row();
+ SCCOL nEndCol = aReducedBlock.aEnd.Col();
+ SCROW nEndRow = aReducedBlock.aEnd.Row();
+
+ if (bIncludeVisual)
+ {
+ ScDataAreaExtras aDataAreaExtras;
+ aDataAreaExtras.mbCellNotes = true;
+ aDataAreaExtras.mbCellDrawObjects = true;
+ bool bShrunk = false;
+ rDoc.ShrinkToUsedDataArea( bShrunk, aReducedBlock.aStart.Tab(), nStartCol, nStartRow, nEndCol, nEndRow,
+ false, true /*bStickyTopRow*/, true /*bStickyLeftCol*/, &aDataAreaExtras);
+ aDataAreaExtras.GetOverallRange( nStartCol, nStartRow, nEndCol, nEndRow, ScDataAreaExtras::Clip::None);
+ }
+ else
+ {
+ bool bShrunk = false;
+ rDoc.ShrinkToUsedDataArea( bShrunk, aReducedBlock.aStart.Tab(), nStartCol, nStartRow, nEndCol, nEndRow,
+ false, false /*bStickyTopRow*/, false /*bStickyLeftCol*/);
+ }
+
+ if ( nPrintAreaEndRow > nEndRow )
+ nEndRow = nPrintAreaEndRow;
+
+ if ( nPrintAreaEndCol > nEndCol )
+ nEndCol = nPrintAreaEndCol;
+
+ aReducedBlock = ScRange(nStartCol, nStartRow, aReducedBlock.aStart.Tab(), nEndCol, nEndRow, aReducedBlock.aEnd.Tab());
+ }
+ return aReducedBlock;
+}
+
+bool ScTransferObj::GetData( const datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ )
+{
+ SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
+ bool bOK = false;
+
+ if( HasFormat( nFormat ) )
+ {
+ ScRange aReducedBlock = m_aBlock;
+
+ bool bReduceBlockFormat =
+ nFormat == SotClipboardFormatId::HTML
+ || nFormat == SotClipboardFormatId::RTF
+ || nFormat == SotClipboardFormatId::RICHTEXT
+ || nFormat == SotClipboardFormatId::BITMAP
+ || nFormat == SotClipboardFormatId::PNG;
+
+ const bool bIncludeVisual = (nFormat == SotClipboardFormatId::BITMAP ||
+ nFormat == SotClipboardFormatId::PNG);
+
+ if (bReduceBlockFormat)
+ aReducedBlock = lcl_reduceBlock(*m_pDoc, m_aBlock, bIncludeVisual);
+
+ if ( nFormat == SotClipboardFormatId::LINKSRCDESCRIPTOR || nFormat == SotClipboardFormatId::OBJECTDESCRIPTOR )
+ {
+ bOK = SetTransferableObjectDescriptor( m_aObjDesc );
+ }
+ else if ( ( nFormat == SotClipboardFormatId::RTF || nFormat == SotClipboardFormatId::RICHTEXT ||
+ nFormat == SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT ) && m_aBlock.aStart == m_aBlock.aEnd )
+ {
+ // RTF from a single cell is handled by EditEngine
+
+ SCCOL nCol = m_aBlock.aStart.Col();
+ SCROW nRow = m_aBlock.aStart.Row();
+ SCTAB nTab = m_aBlock.aStart.Tab();
+ ScAddress aPos(nCol, nRow, nTab);
+
+ const ScPatternAttr* pPattern = m_pDoc->GetPattern( nCol, nRow, nTab );
+ ScTabEditEngine aEngine( *pPattern, m_pDoc->GetEditPool(), m_pDoc.get() );
+ ScRefCellValue aCell(*m_pDoc, aPos);
+ if (aCell.meType == CELLTYPE_EDIT)
+ {
+ const EditTextObject* pObj = aCell.mpEditText;
+ aEngine.SetTextCurrentDefaults(*pObj);
+ }
+ else
+ {
+ SvNumberFormatter* pFormatter = m_pDoc->GetFormatTable();
+ sal_uInt32 nNumFmt = pPattern->GetNumberFormat(pFormatter);
+ const Color* pColor;
+ OUString aText = ScCellFormat::GetString(aCell, nNumFmt, &pColor, *pFormatter, *m_pDoc);
+ if (!aText.isEmpty())
+ aEngine.SetTextCurrentDefaults(aText);
+ }
+
+ bOK = SetObject( &aEngine,
+ ((nFormat == SotClipboardFormatId::RTF) ? SCTRANS_TYPE_EDIT_RTF :
+ ((nFormat == SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT) ?
+ SCTRANS_TYPE_EDIT_ODF_TEXT_FLAT : SCTRANS_TYPE_EDIT_BIN)),
+ rFlavor );
+ }
+ else if ( ScImportExport::IsFormatSupported( nFormat ) || nFormat == SotClipboardFormatId::RTF
+ || nFormat == SotClipboardFormatId::RICHTEXT )
+ {
+ // if this transfer object was used to create a DDE link, filtered rows
+ // have to be included for subsequent calls (to be consistent with link data)
+ if ( nFormat == SotClipboardFormatId::LINK )
+ m_bUsedForLink = true;
+
+ bool bIncludeFiltered = m_pDoc->IsCutMode() || m_bUsedForLink;
+
+ ScImportExport aObj( *m_pDoc, aReducedBlock );
+ // Plain text ("Unformatted text") may contain embedded tabs and
+ // line breaks but is not enclosed in quotes. Which makes it
+ // unsuitable for multiple cells, especially if one of them is
+ // multi-line, but otherwise is expected behavior for plain text.
+ // For multiple cells replace embedded line breaks (and tabs) with
+ // space character, otherwise pasting would yield odd results.
+ /* XXX: it's debatable whether this is actually expected, but
+ * there's no way to satisfy all possible requirements when
+ * copy/pasting unformatted text. */
+ const bool bPlainMulti = (nFormat == SotClipboardFormatId::STRING &&
+ aReducedBlock.aStart != aReducedBlock.aEnd);
+ // Add quotes only for STRING_TSVC.
+ /* TODO: a possible future STRING_TSV should not contain embedded
+ * line breaks nor tab (separator) characters and not be quoted.
+ * A possible STRING_CSV should. */
+ ScExportTextOptions aTextOptions( ScExportTextOptions::None, 0,
+ (nFormat == SotClipboardFormatId::STRING_TSVC));
+ if ( bPlainMulti || m_bUsedForLink )
+ {
+ // For a DDE link or plain text multiple cells, convert line
+ // breaks and separators to space.
+ aTextOptions.meNewlineConversion = ScExportTextOptions::ToSpace;
+ aTextOptions.mcSeparatorConvertTo = ' ';
+ aTextOptions.mbAddQuotes = false;
+ }
+ aObj.SetExportTextOptions(aTextOptions);
+ aObj.SetFormulas( m_pDoc->GetViewOptions().GetOption( VOPT_FORMULAS ) );
+ aObj.SetIncludeFiltered( bIncludeFiltered );
+
+ // DataType depends on format type:
+
+ if ( rFlavor.DataType.equals( ::cppu::UnoType<OUString>::get() ) )
+ {
+ OUString aString;
+ if ( aObj.ExportString( aString, nFormat ) )
+ bOK = SetString( aString );
+ }
+ else if ( rFlavor.DataType.equals( cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ) )
+ {
+ // SetObject converts a stream into an Int8-Sequence
+ bOK = SetObject( &aObj, SCTRANS_TYPE_IMPEX, rFlavor );
+ }
+ else
+ {
+ OSL_FAIL("unknown DataType");
+ }
+ }
+ else if ( nFormat == SotClipboardFormatId::BITMAP || nFormat == SotClipboardFormatId::PNG )
+ {
+ tools::Rectangle aMMRect = m_pDoc->GetMMRect( aReducedBlock.aStart.Col(), aReducedBlock.aStart.Row(),
+ aReducedBlock.aEnd.Col(), aReducedBlock.aEnd.Row(),
+ aReducedBlock.aStart.Tab() );
+ ScopedVclPtrInstance< VirtualDevice > pVirtDev;
+ pVirtDev->SetOutputSizePixel(pVirtDev->LogicToPixel(aMMRect.GetSize(), MapMode(MapUnit::Map100thMM)));
+
+ PaintToDev( pVirtDev, *m_pDoc, 1.0, aReducedBlock );
+
+ pVirtDev->SetMapMode( MapMode( MapUnit::MapPixel ) );
+ BitmapEx aBmp = pVirtDev->GetBitmapEx( Point(), pVirtDev->GetOutputSize() );
+ bOK = SetBitmapEx( aBmp, rFlavor );
+ }
+ else if ( nFormat == SotClipboardFormatId::GDIMETAFILE )
+ {
+ // #i123405# Do not limit visual size calculation for metafile creation.
+ // It seems unlikely that removing the limitation causes problems since
+ // metafile creation means that no real pixel device in the needed size is
+ // created.
+ InitDocShell(false);
+
+ SfxObjectShell* pEmbObj = m_aDocShellRef.get();
+
+ // like SvEmbeddedTransfer::GetData:
+ GDIMetaFile aMtf;
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ MapMode aMapMode( pEmbObj->GetMapUnit() );
+ tools::Rectangle aVisArea( pEmbObj->GetVisArea( ASPECT_CONTENT ) );
+
+ pVDev->EnableOutput( false );
+ pVDev->SetMapMode( aMapMode );
+ aMtf.SetPrefSize( aVisArea.GetSize() );
+ aMtf.SetPrefMapMode( aMapMode );
+ aMtf.Record( pVDev );
+
+ pEmbObj->DoDraw( pVDev, Point(), aVisArea.GetSize(), JobSetup() );
+
+ aMtf.Stop();
+ aMtf.WindStart();
+
+ bOK = SetGDIMetaFile( aMtf );
+ }
+ else if ( nFormat == SotClipboardFormatId::EMBED_SOURCE )
+ {
+ //TODO/LATER: differentiate between formats?!
+ // #i123405# Do limit visual size calculation to PageSize
+ InitDocShell(true); // set aDocShellRef
+
+ SfxObjectShell* pEmbObj = m_aDocShellRef.get();
+ bOK = SetObject( pEmbObj, SCTRANS_TYPE_EMBOBJ, rFlavor );
+ }
+ }
+ return bOK;
+}
+
+bool ScTransferObj::WriteObject( tools::SvRef<SotTempStream>& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId,
+ const datatransfer::DataFlavor& rFlavor )
+{
+ // called from SetObject, put data into stream
+
+ bool bRet = false;
+ switch (nUserObjectId)
+ {
+ case SCTRANS_TYPE_IMPEX:
+ {
+ ScImportExport* pImpEx = static_cast<ScImportExport*>(pUserObject);
+
+ SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
+ // mba: no BaseURL for data exchange
+ if ( pImpEx->ExportStream( *rxOStm, OUString(), nFormat ) )
+ bRet = ( rxOStm->GetError() == ERRCODE_NONE );
+ }
+ break;
+
+ case SCTRANS_TYPE_EDIT_RTF:
+ case SCTRANS_TYPE_EDIT_BIN:
+ {
+ ScTabEditEngine* pEngine = static_cast<ScTabEditEngine*>(pUserObject);
+ if ( nUserObjectId == SCTRANS_TYPE_EDIT_RTF )
+ {
+ pEngine->Write( *rxOStm, EETextFormat::Rtf );
+ bRet = ( rxOStm->GetError() == ERRCODE_NONE );
+ }
+ else
+ {
+ // can't use Write for EditEngine format because that would
+ // write old format without support for unicode characters.
+ // Get the data from the EditEngine's transferable instead.
+
+ sal_Int32 nParCnt = pEngine->GetParagraphCount();
+ if ( nParCnt == 0 )
+ nParCnt = 1;
+ ESelection aSel( 0, 0, nParCnt-1, pEngine->GetTextLen(nParCnt-1) );
+
+ uno::Reference<datatransfer::XTransferable> xEditTrans = pEngine->CreateTransferable( aSel );
+ TransferableDataHelper aEditHelper( xEditTrans );
+
+ bRet = aEditHelper.GetSotStorageStream( rFlavor, rxOStm );
+ }
+ }
+ break;
+
+ case SCTRANS_TYPE_EDIT_ODF_TEXT_FLAT:
+ {
+ ScTabEditEngine* pEngine = static_cast<ScTabEditEngine*>(pUserObject);
+ pEngine->Write(*rxOStm, EETextFormat::Xml);
+ bRet = (rxOStm->GetError() == ERRCODE_NONE);
+ }
+ break;
+
+ case SCTRANS_TYPE_EMBOBJ:
+ {
+ // TODO/MBA: testing
+ SfxObjectShell* pEmbObj = static_cast<SfxObjectShell*>(pUserObject);
+ ::utl::TempFile aTempFile;
+ aTempFile.EnableKillingFile();
+ uno::Reference< embed::XStorage > xWorkStore =
+ ::comphelper::OStorageHelper::GetStorageFromURL( aTempFile.GetURL(), embed::ElementModes::READWRITE );
+
+ // write document storage
+ pEmbObj->SetupStorage( xWorkStore, SOFFICE_FILEFORMAT_CURRENT, false );
+
+ // mba: no relative URLs for clipboard!
+ SfxMedium aMedium( xWorkStore, OUString() );
+ pEmbObj->DoSaveObjectAs( aMedium, false );
+ pEmbObj->DoSaveCompleted();
+
+ uno::Reference< embed::XTransactedObject > xTransact( xWorkStore, uno::UNO_QUERY );
+ if ( xTransact.is() )
+ xTransact->commit();
+
+ std::unique_ptr<SvStream> pSrcStm = ::utl::UcbStreamHelper::CreateStream( aTempFile.GetURL(), StreamMode::READ );
+ if( pSrcStm )
+ {
+ rxOStm->SetBufferSize( 0xff00 );
+ rxOStm->WriteStream( *pSrcStm );
+ pSrcStm.reset();
+ }
+
+ bRet = true;
+
+ xWorkStore->dispose();
+ xWorkStore.clear();
+ }
+ break;
+
+ default:
+ OSL_FAIL("unknown object id");
+ }
+ return bRet;
+}
+
+sal_Bool SAL_CALL ScTransferObj::isComplex()
+{
+ ScRange aReduced = lcl_reduceBlock(*m_pDoc, m_aBlock);
+ size_t nCells = (aReduced.aEnd.Col() - aReduced.aStart.Col() + 1) *
+ (aReduced.aEnd.Row() - aReduced.aStart.Row() + 1) *
+ (aReduced.aEnd.Tab() - aReduced.aStart.Tab() + 1);
+ return nCells > 1000;
+}
+
+void ScTransferObj::DragFinished( sal_Int8 nDropAction )
+{
+ if ( nDropAction == DND_ACTION_MOVE && !m_bDragWasInternal && !(m_nDragSourceFlags & ScDragSrc::Navigator) )
+ {
+ // move: delete source data
+ ScDocShell* pSourceSh = GetSourceDocShell();
+ if (pSourceSh)
+ {
+ ScMarkData aMarkData = GetSourceMarkData();
+ // external drag&drop doesn't copy objects, so they also aren't deleted:
+ // bApi=TRUE, don't show error messages from drag&drop
+ pSourceSh->GetDocFunc().DeleteContents( aMarkData, InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS, true, true );
+ }
+ }
+
+ ScModule* pScMod = SC_MOD();
+ if ( pScMod->GetDragData().pCellTransfer == this )
+ pScMod->ResetDragObject();
+
+ m_xDragSourceRanges = nullptr; // don't keep source after dropping
+
+ TransferDataContainer::DragFinished( nDropAction );
+}
+
+void ScTransferObj::SetDragHandlePos( SCCOL nX, SCROW nY )
+{
+ m_nDragHandleX = nX;
+ m_nDragHandleY = nY;
+}
+
+void ScTransferObj::SetSourceCursorPos( SCCOL nX, SCROW nY )
+{
+ m_nSourceCursorX = nX;
+ m_nSourceCursorY = nY;
+}
+
+bool ScTransferObj::WasSourceCursorInSelection() const
+{
+ return
+ m_nSourceCursorX >= m_aBlock.aStart.Col() && m_nSourceCursorX <= m_aBlock.aEnd.Col() &&
+ m_nSourceCursorY >= m_aBlock.aStart.Row() && m_nSourceCursorY <= m_aBlock.aEnd.Row();
+}
+
+void ScTransferObj::SetVisibleTab( SCTAB nNew )
+{
+ m_nVisibleTab = nNew;
+}
+
+void ScTransferObj::SetDrawPersist( const SfxObjectShellRef& rRef )
+{
+ m_aDrawPersistRef = rRef;
+}
+
+void ScTransferObj::SetDragSource( ScDocShell* pSourceShell, const ScMarkData& rMark )
+{
+ ScRangeList aRanges;
+ rMark.FillRangeListWithMarks( &aRanges, false );
+ m_xDragSourceRanges = new ScCellRangesObj( pSourceShell, aRanges );
+}
+
+void ScTransferObj::SetDragSourceFlags(ScDragSrc nFlags)
+{
+ m_nDragSourceFlags = nFlags;
+}
+
+void ScTransferObj::SetDragWasInternal()
+{
+ m_bDragWasInternal = true;
+}
+
+void ScTransferObj::SetUseInApi( bool bSet )
+{
+ m_bUseInApi = bSet;
+}
+
+ScDocument* ScTransferObj::GetSourceDocument()
+{
+ ScDocShell* pSourceDocSh = GetSourceDocShell();
+ if (pSourceDocSh)
+ return &pSourceDocSh->GetDocument();
+ return nullptr;
+}
+
+ScDocShell* ScTransferObj::GetSourceDocShell()
+{
+ ScCellRangesBase* pRangesObj = comphelper::getFromUnoTunnel<ScCellRangesBase>( m_xDragSourceRanges );
+ if (pRangesObj)
+ return pRangesObj->GetDocShell();
+
+ return nullptr; // none set
+}
+
+ScMarkData ScTransferObj::GetSourceMarkData() const
+{
+ ScMarkData aMarkData(m_pDoc->GetSheetLimits());
+ ScCellRangesBase* pRangesObj = comphelper::getFromUnoTunnel<ScCellRangesBase>( m_xDragSourceRanges );
+ if (pRangesObj)
+ {
+ const ScRangeList& rRanges = pRangesObj->GetRangeList();
+ aMarkData.MarkFromRangeList( rRanges, false );
+ }
+ return aMarkData;
+}
+
+// initialize aDocShellRef with a live document from the ClipDoc
+
+// #i123405# added parameter to allow size calculation without limitation
+// to PageSize, e.g. used for Metafile creation for clipboard.
+
+void ScTransferObj::InitDocShell(bool bLimitToPageSize)
+{
+ if ( m_aDocShellRef.is() )
+ return;
+
+ ScDocShell* pDocSh = new ScDocShell;
+ m_aDocShellRef = pDocSh; // ref must be there before InitNew
+
+ pDocSh->DoInitNew();
+
+ ScDocument& rDestDoc = pDocSh->GetDocument();
+ ScMarkData aDestMark(rDestDoc.GetSheetLimits());
+ aDestMark.SelectTable( 0, true );
+
+ rDestDoc.SetDocOptions( m_pDoc->GetDocOptions() ); // #i42666#
+
+ OUString aTabName;
+ m_pDoc->GetName( m_aBlock.aStart.Tab(), aTabName );
+ rDestDoc.RenameTab( 0, aTabName );
+
+ rDestDoc.CopyStdStylesFrom(*m_pDoc);
+
+ SCCOL nStartX = m_aBlock.aStart.Col();
+ SCROW nStartY = m_aBlock.aStart.Row();
+ SCCOL nEndX = m_aBlock.aEnd.Col();
+ SCROW nEndY = m_aBlock.aEnd.Row();
+
+ // widths / heights
+ // (must be copied before CopyFromClip, for drawing objects)
+
+ SCCOL nCol;
+ SCTAB nSrcTab = m_aBlock.aStart.Tab();
+ rDestDoc.SetLayoutRTL(0, m_pDoc->IsLayoutRTL(nSrcTab));
+ for (nCol=nStartX; nCol<=nEndX; nCol++)
+ if ( m_pDoc->ColHidden(nCol, nSrcTab) )
+ rDestDoc.ShowCol( nCol, 0, false );
+ else
+ rDestDoc.SetColWidth( nCol, 0, m_pDoc->GetColWidth( nCol, nSrcTab ) );
+
+ if (nStartY > 0)
+ {
+ // Set manual height for all previous rows so we can ensure
+ // that visible area will not change due to autoheight
+ rDestDoc.SetManualHeight(0, nStartY - 1, 0, true);
+ }
+ for (SCROW nRow = nStartY; nRow <= nEndY; ++nRow)
+ {
+ if ( m_pDoc->RowHidden(nRow, nSrcTab) )
+ rDestDoc.ShowRow( nRow, 0, false );
+ else
+ {
+ rDestDoc.SetRowHeight( nRow, 0, m_pDoc->GetOriginalHeight( nRow, nSrcTab ) );
+
+ // if height was set manually, that flag has to be copied, too
+ bool bManual = m_pDoc->IsManualRowHeight(nRow, nSrcTab);
+ rDestDoc.SetManualHeight(nRow, nRow, 0, bManual);
+ }
+ }
+
+ if (m_pDoc->GetDrawLayer() || m_pDoc->HasNotes())
+ pDocSh->MakeDrawLayer();
+
+ // cell range is copied to the original position, but on the first sheet
+ // -> bCutMode must be set
+ // pDoc is always a Clipboard-document
+
+ ScRange aDestRange( nStartX,nStartY,0, nEndX,nEndY,0 );
+ bool bWasCut = m_pDoc->IsCutMode();
+ if (!bWasCut)
+ m_pDoc->SetClipArea( aDestRange, true ); // Cut
+ rDestDoc.CopyFromClip( aDestRange, aDestMark, InsertDeleteFlags::ALL, nullptr, m_pDoc.get(), false );
+ m_pDoc->SetClipArea( aDestRange, bWasCut );
+
+ StripRefs(*m_pDoc, nStartX,nStartY, nEndX,nEndY, rDestDoc);
+
+ ScRange aMergeRange = aDestRange;
+ rDestDoc.ExtendMerge( aMergeRange, true );
+
+ m_pDoc->CopyDdeLinks( rDestDoc ); // copy values of DDE Links
+
+ // page format (grid etc) and page size (maximum size for ole object)
+
+ Size aPaperSize = SvxPaperInfo::GetPaperSize( PAPER_A4 ); // Twips
+ ScStyleSheetPool* pStylePool = m_pDoc->GetStyleSheetPool();
+ OUString aStyleName = m_pDoc->GetPageStyle( m_aBlock.aStart.Tab() );
+ SfxStyleSheetBase* pStyleSheet = pStylePool->Find( aStyleName, SfxStyleFamily::Page );
+ if (pStyleSheet)
+ {
+ const SfxItemSet& rSourceSet = pStyleSheet->GetItemSet();
+ aPaperSize = rSourceSet.Get(ATTR_PAGE_SIZE).GetSize();
+
+ // CopyStyleFrom copies SetItems with correct pool
+ ScStyleSheetPool* pDestPool = rDestDoc.GetStyleSheetPool();
+ pDestPool->CopyStyleFrom( pStylePool, aStyleName, SfxStyleFamily::Page );
+ }
+
+ ScViewData aViewData( *pDocSh, nullptr );
+ aViewData.SetScreen( nStartX,nStartY, nEndX,nEndY );
+ aViewData.SetCurX( nStartX );
+ aViewData.SetCurY( nStartY );
+
+ rDestDoc.SetViewOptions( m_pDoc->GetViewOptions() );
+
+ // Size
+ //! get while copying sizes
+
+ tools::Long nPosX = 0;
+ tools::Long nPosY = 0;
+
+ for (nCol=0; nCol<nStartX; nCol++)
+ nPosX += rDestDoc.GetColWidth( nCol, 0 );
+ nPosY += rDestDoc.GetRowHeight( 0, nStartY-1, 0 );
+ nPosX = o3tl::convert(nPosX, o3tl::Length::twip, o3tl::Length::mm100);
+ nPosY = o3tl::convert(nPosY, o3tl::Length::twip, o3tl::Length::mm100);
+
+ aPaperSize.setWidth( aPaperSize.Width() * 2 ); // limit OLE object to double of page size
+ aPaperSize.setHeight( aPaperSize.Height() * 2 );
+
+ tools::Long nSizeX = 0;
+ tools::Long nSizeY = 0;
+ for (nCol=nStartX; nCol<=nEndX; nCol++)
+ {
+ tools::Long nAdd = rDestDoc.GetColWidth( nCol, 0 );
+ if ( bLimitToPageSize && nSizeX+nAdd > aPaperSize.Width() && nSizeX ) // above limit?
+ break;
+ nSizeX += nAdd;
+ }
+ for (SCROW nRow=nStartY; nRow<=nEndY; nRow++)
+ {
+ tools::Long nAdd = rDestDoc.GetRowHeight( nRow, 0 );
+ if ( bLimitToPageSize && nSizeY+nAdd > aPaperSize.Height() && nSizeY ) // above limit?
+ break;
+ nSizeY += nAdd;
+ }
+ nSizeX = o3tl::convert(nSizeX, o3tl::Length::twip, o3tl::Length::mm100);
+ nSizeY = o3tl::convert(nSizeY, o3tl::Length::twip, o3tl::Length::mm100);
+
+// pDocSh->SetVisAreaSize( Size(nSizeX,nSizeY) );
+
+ tools::Rectangle aNewArea( Point(nPosX,nPosY), Size(nSizeX,nSizeY) );
+ //TODO/LATER: why twice?!
+ //pDocSh->SvInPlaceObject::SetVisArea( aNewArea );
+ pDocSh->SetVisArea( aNewArea );
+
+ pDocSh->UpdateOle(aViewData, true);
+
+ //! SetDocumentModified?
+ if ( rDestDoc.IsChartListenerCollectionNeedsUpdate() )
+ rDestDoc.UpdateChartListenerCollection();
+}
+
+SfxObjectShell* ScTransferObj::SetDrawClipDoc( bool bAnyOle, const std::shared_ptr<ScDocument>& pDoc )
+{
+ // update ScGlobal::xDrawClipDocShellRef
+
+ ScGlobal::xDrawClipDocShellRef.clear();
+ if (bAnyOle)
+ {
+ ScGlobal::xDrawClipDocShellRef = new ScDocShell(SfxModelFlags::EMBEDDED_OBJECT | SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS, pDoc); // there must be a ref
+ ScGlobal::xDrawClipDocShellRef->DoInitNew();
+ }
+
+ return ScGlobal::xDrawClipDocShellRef.get();
+}
+
+void ScTransferObj::StripRefs( ScDocument& rDoc,
+ SCCOL nStartX, SCROW nStartY, SCCOL nEndX, SCROW nEndY,
+ ScDocument& rDestDoc )
+{
+ // In a clipboard doc the data don't have to be on the first sheet
+
+ SCTAB nSrcTab = 0;
+ while (nSrcTab < rDoc.GetTableCount() && !rDoc.HasTable(nSrcTab))
+ ++nSrcTab;
+ SCTAB nDestTab = 0;
+ while (nDestTab < rDestDoc.GetTableCount() && !rDestDoc.HasTable(nDestTab))
+ ++nDestTab;
+
+ if (!rDoc.HasTable(nSrcTab) || !rDestDoc.HasTable(nDestTab))
+ {
+ OSL_FAIL("Sheet not found in ScTransferObj::StripRefs");
+ return;
+ }
+
+ ScRange aRef;
+
+ ScCellIterator aIter( rDoc, ScRange(nStartX, nStartY, nSrcTab, nEndX, nEndY, nSrcTab) );
+ for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
+ {
+ if (aIter.getType() != CELLTYPE_FORMULA)
+ continue;
+
+ ScFormulaCell* pFCell = aIter.getFormulaCell();
+ bool bOut = false;
+ ScDetectiveRefIter aRefIter( rDoc, pFCell );
+ while ( !bOut && aRefIter.GetNextRef( aRef ) )
+ {
+ if ( aRef.aStart.Tab() != nSrcTab || aRef.aEnd.Tab() != nSrcTab ||
+ aRef.aStart.Col() < nStartX || aRef.aEnd.Col() > nEndX ||
+ aRef.aStart.Row() < nStartY || aRef.aEnd.Row() > nEndY )
+ bOut = true;
+ }
+ if (bOut)
+ {
+ SCCOL nCol = aIter.GetPos().Col();
+ SCROW nRow = aIter.GetPos().Row();
+
+ FormulaError nErrCode = pFCell->GetErrCode();
+ ScAddress aPos(nCol, nRow, nDestTab);
+ if (nErrCode != FormulaError::NONE)
+ {
+ if ( rDestDoc.GetAttr( nCol,nRow,nDestTab, ATTR_HOR_JUSTIFY)->GetValue() ==
+ SvxCellHorJustify::Standard )
+ rDestDoc.ApplyAttr( nCol,nRow,nDestTab,
+ SvxHorJustifyItem(SvxCellHorJustify::Right, ATTR_HOR_JUSTIFY) );
+
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ rDestDoc.SetString(aPos, ScGlobal::GetErrorString(nErrCode), &aParam);
+ }
+ else if (pFCell->IsValue())
+ {
+ rDestDoc.SetValue(aPos, pFCell->GetValue());
+ }
+ else
+ {
+ OUString aStr = pFCell->GetString().getString();
+ if ( pFCell->IsMultilineResult() )
+ {
+ ScFieldEditEngine& rEngine = rDestDoc.GetEditEngine();
+ rEngine.SetTextCurrentDefaults(aStr);
+ rDestDoc.SetEditText(ScAddress(nCol,nRow,nDestTab), rEngine.CreateTextObject());
+ }
+ else
+ {
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ rDestDoc.SetString(aPos, aStr, &aParam);
+ }
+ }
+ }
+ }
+}
+
+const css::uno::Sequence< sal_Int8 >& ScTransferObj::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit theScTransferUnoTunnelId;
+ return theScTransferUnoTunnelId.getSeq();
+}
+
+sal_Int64 SAL_CALL ScTransferObj::getSomething( const css::uno::Sequence< sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(
+ rId, this, comphelper::FallbackToGetSomethingOf<TransferDataContainer>{});
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */