/* -*- 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 .
*/
if ( !rMark.IsMarked() && !rMark.IsMultiMarked() ) // mark the range if not marked yet
{
DoneBlockMode();
InitOwnBlockMode( aRange );
rMark.SetMarkArea( aRange );
MarkDataChanged();
}
CopyToClip( nullptr, true, false, true/*bIncludeObjects*/ ); // copy to clipboard
ScAddress aOldEnd( aRange.aEnd ); // combined cells in this range?
rDoc.ExtendMerge( aRange, true );
ScDocumentUniquePtr pUndoDoc; if ( bRecord )
{
pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
pUndoDoc->InitUndoSelected( rDoc, rMark ); // all sheets - CopyToDocument skips those that don't exist in pUndoDoc
ScRange aCopyRange = aRange;
aCopyRange.aStart.SetTab(0);
aCopyRange.aEnd.SetTab(rDoc.GetTableCount()-1);
rDoc.CopyToDocument( aCopyRange, (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS, false, *pUndoDoc );
rDoc.BeginDrawUndo();
}
// Copy the content of the Range into clipboard. bool ScViewFunc::CopyToClip( ScDocument* pClipDoc, const ScRangeList& rRanges, boolbCut, bool bApi, bool bIncludeObjects, bool bStopEdit )
{ if ( rRanges.empty() ) returnfalse; if ( bStopEdit )
UpdateInputLine();
// is this necessary?, will setting the doc id upset the // following paste operation with range? would be nicer to just set this always // and lose the 'if' above
aClipParam.setSourceDocID( rDoc.GetDocumentID() );
if (ScDocShell* pObjectShell = rDoc.GetDocumentShell())
{ // Copy document properties from pObjectShell to pClipDoc (to its clip options, as it has no object shell).
uno::Reference<util::XCloneable> xCloneable(pObjectShell->getDocProperties(), uno::UNO_QUERY_THROW);
std::unique_ptr<ScClipOptions> pOptions(new ScClipOptions);
pOptions->m_xDocumentProperties.set(xCloneable->createClone(), uno::UNO_QUERY);
pClipDoc->SetClipOptions(std::move(pOptions));
}
if ( nAction != EXCHG_INOUT_ACTION_NONE )
{ switch( nAction )
{ case EXCHG_OUT_ACTION_INSERT_SVXB: case EXCHG_OUT_ACTION_INSERT_GDIMETAFILE: case EXCHG_OUT_ACTION_INSERT_BITMAP: case EXCHG_OUT_ACTION_INSERT_GRAPH: // SotClipboardFormatId::BITMAP // SotClipboardFormatId::PNG // SotClipboardFormatId::GDIMETAFILE // SotClipboardFormatId::SVXB
PasteFromSystem(nFormat); break; default:
nAction = EXCHG_INOUT_ACTION_NONE;
}
}
if ( nAction == EXCHG_INOUT_ACTION_NONE )
{ // first SvDraw-model, then drawing // (only one drawing is allowed)
if (aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ))
{ // special case for tables from drawing if( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) )
{
PasteFromSystem( SotClipboardFormatId::RTF );
} elseif( aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) )
{
PasteFromSystem( SotClipboardFormatId::RICHTEXT );
} else
{
PasteFromSystem( SotClipboardFormatId::DRAWING );
}
} elseif (aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE ))
{ // If it's a Writer object, insert RTF instead of OLE
// Else, if the class id is all-zero, and SYLK is available, // it probably is spreadsheet cells that have been put // on the clipboard by OOo, so use the SYLK. (fdo#31077)
bool bDoRtf = false;
TransferableObjectDescriptor aObjDesc; if( aDataHelper.GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc ) )
{
bDoRtf = ( ( aObjDesc.maClassName == SvGlobalName( SO3_SW_CLASSID ) ||
aObjDesc.maClassName == SvGlobalName( SO3_SWWEB_CLASSID ) )
&& ( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) || aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) ) );
} if ( bDoRtf )
PasteFromSystem( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) ? SotClipboardFormatId::RTF : SotClipboardFormatId::RICHTEXT ); elseif ( aObjDesc.maClassName == SvGlobalName( 0,0,0,0,0,0,0,0,0,0,0 )
&& aDataHelper.HasFormat( SotClipboardFormatId::SYLK ))
PasteFromSystem( SotClipboardFormatId::SYLK ); else
PasteFromSystem( SotClipboardFormatId::EMBED_SOURCE );
} elseif (aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE ))
PasteFromSystem( SotClipboardFormatId::LINK_SOURCE ); // the following format can not affect scenario from #89579# elseif (aDataHelper.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ_OLE ))
PasteFromSystem( SotClipboardFormatId::EMBEDDED_OBJ_OLE ); // SotClipboardFormatId::PRIVATE no longer here (can't work if pOwnClip is NULL) elseif (aDataHelper.HasFormat(nBiff8)) // before xxx_OLE formats
PasteFromSystem(nBiff8); elseif (aDataHelper.HasFormat(nBiff5))
PasteFromSystem(nBiff5); elseif (aDataHelper.HasFormat(SotClipboardFormatId::RTF))
PasteFromSystem(SotClipboardFormatId::RTF); elseif (aDataHelper.HasFormat(SotClipboardFormatId::RICHTEXT))
PasteFromSystem(SotClipboardFormatId::RICHTEXT); elseif (aDataHelper.HasFormat(SotClipboardFormatId::HTML))
PasteFromSystem(SotClipboardFormatId::HTML, false, useSavedPrefs); elseif (aDataHelper.HasFormat(SotClipboardFormatId::BITMAP))
PasteFromSystem(SotClipboardFormatId::BITMAP); elseif (aDataHelper.HasFormat(SotClipboardFormatId::HTML_SIMPLE))
PasteFromSystem(SotClipboardFormatId::HTML_SIMPLE); elseif (aDataHelper.HasFormat(SotClipboardFormatId::SYLK))
PasteFromSystem(SotClipboardFormatId::SYLK); elseif (aDataHelper.HasFormat(SotClipboardFormatId::STRING_TSVC))
PasteFromSystem(SotClipboardFormatId::STRING_TSVC); elseif (aDataHelper.HasFormat(SotClipboardFormatId::STRING))
PasteFromSystem(SotClipboardFormatId::STRING); // xxx_OLE formats come last, like in SotExchange tables elseif (aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE_OLE ))
PasteFromSystem( SotClipboardFormatId::EMBED_SOURCE_OLE ); elseif (aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE_OLE ))
PasteFromSystem( SotClipboardFormatId::LINK_SOURCE_OLE );
}
}
} // no exception-> SID_PASTE has FastCall-flag from idl // will be called in case of empty clipboard (#42531#)
}
for (constauto& rTab : rMark)
{ for (size_t i = 0; i < nRangeSize && bIsEmpty; ++i)
{ const ScRange& rRange = rDestRanges[i]; // tdf#158110 - check if just the ADDNOTES flag is present without any other content if ((nFlags & InsertDeleteFlags::ADDNOTES) == InsertDeleteFlags::ADDNOTES
&& (nFlags & (InsertDeleteFlags::CONTENTS & ~InsertDeleteFlags::NOTE))
== InsertDeleteFlags::NONE)
bIsEmpty = rDoc.IsNotesBlockEmpty(rRange.aStart.Col(), rRange.aStart.Row(),
rRange.aEnd.Col(), rRange.aEnd.Row(), rTab); else
bIsEmpty = rDoc.IsBlockEmpty(rRange.aStart.Col(), rRange.aStart.Row(),
rRange.aEnd.Col(), rRange.aEnd.Row(), rTab);
} if (!bIsEmpty) break;
}
if (!bIsEmpty)
{
ScReplaceWarnBox aBox(pParentWnd); if (aBox.run() != RET_YES)
{ // changing the configuration is within the ScReplaceWarnBox returnfalse;
}
} returntrue;
}
if (GetViewData().SelectionForbidsPaste(pClipDoc)) returnfalse;
// undo: save all or no content
InsertDeleteFlags nContFlags = InsertDeleteFlags::NONE; if (nFlags & InsertDeleteFlags::CONTENTS)
nContFlags |= InsertDeleteFlags::CONTENTS; if (nFlags & InsertDeleteFlags::ATTRIB)
nContFlags |= InsertDeleteFlags::ATTRIB; // move attributes to undo without copying them from clip to doc
InsertDeleteFlags nUndoFlags = nContFlags; if (nUndoExtraFlags & InsertDeleteFlags::ATTRIB)
nUndoFlags |= InsertDeleteFlags::ATTRIB; // do not copy note captions into undo document
nUndoFlags |= InsertDeleteFlags::NOCAPTIONS;
ScClipParam& rClipParam = pClipDoc->GetClipParam(); if (rClipParam.isMultiRange())
{ // Source data is multi-range. return PasteMultiRangesFromClip(nFlags, pClipDoc, nFunction, bSkipEmptyCells, bTranspose,
bAsLink, bAllowDialogs, eMoveMode, nUndoFlags);
}
ScMarkData& rMark = GetViewData().GetMarkData(); if (rMark.IsMultiMarked())
{ // Source data is single-range but destination is multi-range. return PasteFromClipToMultiRanges(
nFlags, pClipDoc, nFunction, bSkipEmptyCells, bTranspose, bAsLink, bAllowDialogs,
eMoveMode, nUndoFlags);
}
bool bCutMode = pClipDoc->IsCutMode(); // if transposing, take from original clipdoc bool bIncludeFiltered = bCutMode;
// paste drawing: also if InsertDeleteFlags::NOTE is set (to create drawing layer for note captions) bool bPasteDraw = ( pClipDoc->GetDrawLayer() && ( nFlags & (InsertDeleteFlags::OBJECTS|InsertDeleteFlags::NOTE) ) );
ScDocShellRef aTransShellRef; // for objects in xTransClip - must remain valid as long as xTransClip
ScDocument* pOrigClipDoc = nullptr;
ScDocumentUniquePtr xTransClip; if ( bTranspose )
{
SCCOL nX;
SCROW nY; // include filtered rows until TransposeClip can skip them
pClipDoc->GetClipArea( nX, nY, true ); if ( nY > static_cast<sal_Int32>(pClipDoc->MaxCol()) ) // too many lines for transpose
{
ErrorMessage(STR_PASTE_FULL); returnfalse;
}
pOrigClipDoc = pClipDoc; // refs
if ( bPasteDraw )
{
aTransShellRef = new ScDocShell; // DocShell needs a Ref immediately
aTransShellRef->DoInitNew();
}
ScDrawLayer::SetGlobalDrawPersist( aTransShellRef.get() );
// size in target doc: include filtered rows only if CutMode is set
SCCOL nDestSizeX;
SCROW nDestSizeY;
pClipDoc->GetClipArea( nDestSizeX, nDestSizeY, bIncludeFiltered );
if (!bNoPaste)
{ if (!rMark.IsMarked())
{ // Create a selection with clipboard row count and check that for // filtered.
nStartCol = GetViewData().GetCurX();
nStartRow = GetViewData().GetCurY();
nStartTab = GetViewData().GetTabNo();
nEndCol = nStartCol + nDestSizeX;
nEndRow = nStartRow + nDestSizeY;
nEndTab = nStartTab;
aMarkRange = ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab); if (ScViewUtil::HasFiltered(aMarkRange, rDoc))
{
bMarkIsFiltered = true; // Fit to clipboard's row count unfiltered rows. If there is no // fit assume that pasting is not possible. Note that nDestSizeY is // size-1 (difference). if (!ScViewUtil::FitToUnfilteredRows(aMarkRange, rDoc, nDestSizeY+1))
bNoPaste = true;
}
aFilteredMark.SetMarkArea( aMarkRange);
} else
{ // Expand the marked area when the destination area is larger than the // current selection, to get the undo do the right thing. (i#106711)
ScRange aRange = aFilteredMark.GetMarkArea(); if( (aRange.aEnd.Col() - aRange.aStart.Col()) < nDestSizeX )
{
aRange.aEnd.SetCol(aRange.aStart.Col() + nDestSizeX);
aFilteredMark.SetMarkArea(aRange);
}
}
}
if (bNoPaste)
{
ErrorMessage(STR_MSSG_PASTEFROMCLIP_0); returnfalse;
}
SCROW nUnfilteredRows = aMarkRange.aEnd.Row() - aMarkRange.aStart.Row() + 1;
ScRangeList aRangeList; if (bMarkIsFiltered)
{
ScViewUtil::UnmarkFiltered(aFilteredMark, rDoc);
aFilteredMark.FillRangeListWithMarks( &aRangeList, false);
nUnfilteredRows = 0;
size_t ListSize = aRangeList.size(); for ( size_t i = 0; i < ListSize; ++i )
{
ScRange & r = aRangeList[i];
nUnfilteredRows += r.aEnd.Row() - r.aStart.Row() + 1;
} #if 0 /* This isn't needed but could be a desired restriction. */ // For filtered, destination rows have to be an exact multiple of // source rows. Note that nDestSizeY is size-1 (difference), so // nDestSizeY==0 fits always. if ((nUnfilteredRows % (nDestSizeY+1)) != 0)
{ /* FIXME: this should be a more descriptive error message then. */
ErrorMessage(STR_MSSG_PASTEFROMCLIP_0); returnfalse;
} #endif
}
// Also for a filtered selection the area is used, for undo et al. if ( aFilteredMark.IsMarked() || bMarkIsFiltered )
{
aMarkRange.GetVars( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
SCCOL nBlockAddX = nEndCol-nStartCol;
SCROW nBlockAddY = nEndRow-nStartRow;
// request, if the selection is greater than one row/column, but smaller // as the Clipboard (then inserting is done beyond the selection)
if (nBlockAddX <= nDestSizeX)
nEndCol = nStartCol + nDestSizeX;
if (nBlockAddY <= nDestSizeY)
{
nEndRow = nStartRow + nDestSizeY; if (bMarkIsFiltered || nEndRow > aMarkRange.aEnd.Row())
{ // Same as above if nothing was marked: re-fit selection to // unfiltered rows. Extending the selection actually may // introduce filtered rows where there weren't any before, so // we also need to test for that.
aMarkRange = ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab); if (bMarkIsFiltered || ScViewUtil::HasFiltered(aMarkRange, rDoc))
{
bMarkIsFiltered = true; // Worst case: all rows up to the end of the sheet are filtered. if (!ScViewUtil::FitToUnfilteredRows(aMarkRange, rDoc, nDestSizeY+1))
{
ErrorMessage(STR_PASTE_FULL); returnfalse;
}
}
aMarkRange.GetVars( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
aFilteredMark.SetMarkArea( aMarkRange); if (bMarkIsFiltered)
{
ScViewUtil::UnmarkFiltered(aFilteredMark, rDoc);
aFilteredMark.FillRangeListWithMarks( &aRangeList, true);
}
}
}
} else
{
nStartCol = GetViewData().GetCurX();
nStartRow = GetViewData().GetCurY();
nStartTab = GetViewData().GetTabNo();
nEndCol = nStartCol + nDestSizeX;
nEndRow = nStartRow + nDestSizeY;
nEndTab = nStartTab;
}
// should lines be inserted? // ( too large nEndCol/nEndRow are detected below) bool bInsertCells = ( eMoveMode != INS_NONE && !bOffLimits ); if ( bInsertCells )
{ // Instead of EnterListAction, the paste undo action is merged into the // insert action, so Repeat can insert the right cells
MarkRange( aUserRange ); // set through CopyFromClip
// CutMode is reset on insertion of cols/rows but needed again on cell move bool bCut = pClipDoc->IsCutMode(); if (!InsertCells( eMoveMode, bRecord, true )) // is inserting possible?
{ returnfalse; // #i21036# EnterListAction isn't used, and InsertCells doesn't insert // its undo action on failure, so no undo handling is needed here
} if ( bCut )
pClipDoc->SetCutMode( bCut );
} elseif (!bOffLimits)
{ bool bAskIfNotEmpty = bAllowDialogs &&
( nFlags & InsertDeleteFlags::CONTENTS ) &&
nFunction == ScPasteFunc::NONE &&
ScModule::get()->GetInputOptions().GetReplaceCellsWarn(); if ( bAskIfNotEmpty )
{
ScRangeList aTestRanges(aUserRange); if (!checkDestRangeForOverwrite(nFlags, aTestRanges, rDoc, aFilteredMark, GetViewData().GetDialogParent())) returnfalse;
}
}
SCCOL nClipStartX; // enlarge clipboard-range
SCROW nClipStartY;
pClipDoc->GetClipStart( nClipStartX, nClipStartY );
SCCOL nUndoEndCol = nClipStartX + nClipSizeX;
SCROW nUndoEndRow = nClipStartY + nClipSizeY; // end of source area in clipboard document bool bClipOver = false; // #i68690# ExtendMerge for the clip doc must be called with the clipboard's sheet numbers. // The same end column/row can be used for all calls because the clip doc doesn't contain // content outside the clip area. for (SCTAB nClipTab=0; nClipTab < pClipDoc->GetTableCount(); nClipTab++) if ( pClipDoc->HasTable(nClipTab) ) if ( pClipDoc->ExtendMerge( nClipStartX,nClipStartY, nUndoEndCol,nUndoEndRow, nClipTab ) )
bClipOver = true;
nUndoEndCol -= nClipStartX + nClipSizeX;
nUndoEndRow -= nClipStartY + nClipSizeY; // now contains only the difference added by ExtendMerge
nUndoEndCol = sal::static_int_cast<SCCOL>( nUndoEndCol + nEndCol );
nUndoEndRow = sal::static_int_cast<SCROW>( nUndoEndRow + nEndRow ); // destination area, expanded for merged cells
if (nUndoEndCol>pClipDoc->MaxCol() || nUndoEndRow>pClipDoc->MaxRow())
{
ErrorMessage(STR_PASTE_FULL); returnfalse;
}
/* Make draw layer and start drawing undo. - Needed before AdjustBlockHeight to track moved drawing objects. - Needed before rDoc.CopyFromClip to track inserted note caption objects.
*/ if ( bPasteDraw )
rDocSh.MakeDrawLayer(); if ( bRecord )
rDoc.BeginDrawUndo();
if ( bInsertCells )
{ // Merge the paste undo action into the insert action. // Use ScUndoWrapper so the ScUndoPaste pointer can be stored in the insert action.
if (!rDoc.ValidCol(aCurPos.Col()+nColSize-1) || !rDoc.ValidRow(aCurPos.Row()+nRowSize-1))
{
ErrorMessage(STR_PASTE_FULL); returnfalse;
}
// Determine the first and last selected sheet numbers.
SCTAB nTab1 = aMark.GetFirstSelected();
SCTAB nTab2 = aMark.GetLastSelected();
ScDocShellModificator aModificator(rDocSh);
// For multi-selection paste, we don't support cell duplication for larger // destination range. In case the destination is marked, we reset it to // the clip size.
ScRange aMarkedRange(aCurPos.Col(), aCurPos.Row(), nTab1,
aCurPos.Col()+nColSize-1, aCurPos.Row()+nRowSize-1, nTab2);
// Extend the marked range to account for filtered rows in the destination // area. if (ScViewUtil::HasFiltered(aMarkedRange, rDoc))
{ if (!ScViewUtil::FitToUnfilteredRows(aMarkedRange, rDoc, nRowSize)) returnfalse;
}
/* Make draw layer and start drawing undo. - Needed before AdjustBlockHeight to track moved drawing objects. - Needed before rDoc.CopyFromClip to track inserted note caption objects.
*/ if (nFlags & InsertDeleteFlags::OBJECTS)
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.30 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.