tdf#146795: Make sure to use valid position hints to avoid crash.

This commit also unifies the code path for both "skip empty cells"
option is selected and when that option is not selected, which
simplifies the code quite a bit.

This commit is a combination of the following two commits cherry-picked
from master:

(cherry picked from commit 703fb7739a5e604d90e147db6f67917b8d141150)
(cherry picked from commit e8032897b4a012d8e236211ee6e5ce89fb90492e)

Change-Id: Ie3b1f471cd80587a3906897cccefda06a83c467c
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129478
Tested-by: Jenkins
Tested-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
diff --git a/sc/inc/clipcontext.hxx b/sc/inc/clipcontext.hxx
index ccce671e..32e2dd9 100644
--- a/sc/inc/clipcontext.hxx
+++ b/sc/inc/clipcontext.hxx
@@ -63,7 +63,7 @@ class SC_DLLPUBLIC CopyFromClipContext final : public ClipContextBase

    ScConditionalFormatList* mpCondFormatList;
    bool mbAsLink:1;
    bool mbSkipAttrForEmptyCells:1;
    bool mbSkipEmptyCells:1;
    bool mbCloneNotes:1;
    bool mbTableProtected:1;

@@ -126,7 +126,14 @@ public:
    bool isTableProtected() const;

    bool isAsLink() const;
    bool isSkipAttrForEmptyCells() const;

    /**
     * Get the flag that indicates whether the "skip empty cells" paste option
     * is selected. When this option is selected, empty cells in the clipboard
     * document will not overwrite the corresponding non-empty cells in the
     * destination range.
     */
    bool isSkipEmptyCells() const;
    bool isCloneNotes() const;
    bool isDateCell( const ScColumn& rCol, SCROW nRow ) const;
};
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 384c12d..480e6913 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -281,7 +281,7 @@ public:
    void CopyFromClip(
        sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2, tools::Long nDy, ScColumn& rColumn );

    void        RemoveEditAttribs( SCROW nStartRow, SCROW nEndRow );
    void RemoveEditAttribs( sc::ColumnBlockPosition& rBlockPos, SCROW nStartRow, SCROW nEndRow );

                //  Selection (?) of this document
    void MixMarked(
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 3df5ddc..fec085a 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -1622,17 +1622,23 @@ public:
                           const ScMarkData& rMark,  InsertDeleteFlags nInsFlag,
                           sc::ColumnSpanSet& rBroadcastSpans );

    /** If pDestRanges is given it overrides rDestRange, rDestRange in this
        case is the overall encompassing range. */
    SC_DLLPUBLIC void   CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMark,
                                        InsertDeleteFlags nInsFlag,
                                        ScDocument* pRefUndoDoc,
                                        ScDocument* pClipDoc,
                                        bool bResetCut = true,
                                        bool bAsLink = false,
                                        bool bIncludeFiltered = true,
                                        bool bSkipAttrForEmpty = false,
                                        const ScRangeList * pDestRanges = nullptr );
    /**
     * Paste data from a clipboard document into this document.
     *
     * @param rDestRange destination range.
     * @param pClipDoc pointer to the clipboard document to copy data from.
     * @param bSkipEmptyCells if this flag is set, empty cells in the source
     *                        range in the clipboard document will not overwrite
     *                        the target destination cells.
     * @param pDestRanges If pDestRanges is given it overrides rDestRange, where
     *                    rDestRange becomes the overall encompassing range.
     */
    SC_DLLPUBLIC void CopyFromClip(
        const ScRange& rDestRange, const ScMarkData& rMark, InsertDeleteFlags nInsFlag,
        ScDocument* pRefUndoDoc, ScDocument* pClipDoc,
        bool bResetCut = true, bool bAsLink = false,
        bool bIncludeFiltered = true, bool bSkipEmptyCells = false,
        const ScRangeList* pDestRanges = nullptr );

    void                CopyMultiRangeFromClip(const ScAddress& rDestPos, const ScMarkData& rMark,
                                               InsertDeleteFlags nInsFlag, ScDocument* pClipDoc,
diff --git a/sc/qa/unit/ucalc_copypaste.cxx b/sc/qa/unit/ucalc_copypaste.cxx
index dc3a74f..0782465 100644
--- a/sc/qa/unit/ucalc_copypaste.cxx
+++ b/sc/qa/unit/ucalc_copypaste.cxx
@@ -465,7 +465,7 @@ void TestCopyPaste::prepareUndoAfterPaste(ScDocumentUniquePtr& pPasteUndoDoc,

    ScUndoPasteOptions aOptions; // store options for repeat
    aOptions.nFunction = nFunction;
    aOptions.bSkipEmpty = bSkipEmpty;
    aOptions.bSkipEmptyCells = bSkipEmpty;
    aOptions.bTranspose = bTranspose;
    aOptions.bAsLink = bAsLink;
    aOptions.eMoveMode = eMoveMode;
diff --git a/sc/source/core/data/clipcontext.cxx b/sc/source/core/data/clipcontext.cxx
index 0d33694..02e2bcc 100644
--- a/sc/source/core/data/clipcontext.cxx
+++ b/sc/source/core/data/clipcontext.cxx
@@ -36,7 +36,7 @@ ColumnBlockPosition* ClipContextBase::getBlockPosition(SCTAB nTab, SCCOL nCol)

CopyFromClipContext::CopyFromClipContext(ScDocument& rDoc,
    ScDocument* pRefUndoDoc, ScDocument* pClipDoc, InsertDeleteFlags nInsertFlag,
    bool bAsLink, bool bSkipAttrForEmptyCells) :
    bool bAsLink, bool bSkipEmptyCells) :
    ClipContextBase(rDoc),
    mnDestCol1(-1), mnDestCol2(-1),
    mnDestRow1(-1), mnDestRow2(-1),
@@ -45,7 +45,7 @@ CopyFromClipContext::CopyFromClipContext(ScDocument& rDoc,
    mpRefUndoDoc(pRefUndoDoc), mpClipDoc(pClipDoc),
    mnInsertFlag(nInsertFlag), mnDeleteFlag(InsertDeleteFlags::NONE),
    mpCondFormatList(nullptr),
    mbAsLink(bAsLink), mbSkipAttrForEmptyCells(bSkipAttrForEmptyCells),
    mbAsLink(bAsLink), mbSkipEmptyCells(bSkipEmptyCells),
    mbCloneNotes (mnInsertFlag & (InsertDeleteFlags::NOTE|InsertDeleteFlags::ADDNOTES)),
    mbTableProtected(false)
{
@@ -325,9 +325,9 @@ bool CopyFromClipContext::isAsLink() const
    return mbAsLink;
}

bool CopyFromClipContext::isSkipAttrForEmptyCells() const
bool CopyFromClipContext::isSkipEmptyCells() const
{
    return mbSkipAttrForEmptyCells;
    return mbSkipEmptyCells;
}

bool CopyFromClipContext::isCloneNotes() const
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index 037e346..92f57bc 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1229,10 +1229,13 @@ public:

}

void ScColumn::RemoveEditAttribs( SCROW nStartRow, SCROW nEndRow )
void ScColumn::RemoveEditAttribs( sc::ColumnBlockPosition& rBlockPos, SCROW nStartRow, SCROW nEndRow )
{
    RemoveEditAttribsHandler aFunc(maCells, &GetDoc());
    sc::ProcessEditText(maCells.begin(), maCells, nStartRow, nEndRow, aFunc);

    rBlockPos.miCellPos = sc::ProcessEditText(
        rBlockPos.miCellPos, maCells, nStartRow, nEndRow, aFunc);

    aFunc.commitStrings();
}

diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index dfdd4e5..74b2e1a 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -1023,7 +1023,7 @@ void ScColumn::DeleteArea(
    if ( nDelFlag & InsertDeleteFlags::EDITATTR )
    {
        OSL_ENSURE( nContFlag == InsertDeleteFlags::NONE, "DeleteArea: Wrong Flags" );
        RemoveEditAttribs( nStartRow, nEndRow );
        RemoveEditAttribs(aBlockPos, nStartRow, nEndRow);
    }

    // Delete attributes just now
@@ -1123,7 +1123,16 @@ public:
        mpSharedStringPool(pSharedStringPool)
    {
        if (mpDestBlockPos)
        {
            {
                // Re-initialize the broadcaster position hint, which may have
                // become invalid by the time it gets here...
                sc::ColumnBlockPosition aTempPos;
                mrDestCol.InitBlockPosition(aTempPos);
                mpDestBlockPos->miBroadcasterPos = aTempPos.miBroadcasterPos;
            }
            maDestBlockPos = *mpDestBlockPos;
        }
        else
            mrDestCol.InitBlockPosition(maDestBlockPos);
    }
@@ -1144,7 +1153,7 @@ public:

        if (node.type == sc::element_type_empty)
        {
            if (bCopyCellNotes && !mrCxt.isSkipAttrForEmptyCells())
            if (bCopyCellNotes && !mrCxt.isSkipEmptyCells())
            {
                bool bCloneCaption = (nFlags & InsertDeleteFlags::NOCAPTIONS) == InsertDeleteFlags::NONE;
                duplicateNotes(nSrcRow1, nDataSize, bCloneCaption );
@@ -1357,7 +1366,7 @@ public:
        mpDestBlockPos(rCxt.getBlockPosition(nDestTab, nDestCol))
    {
        if (mpDestBlockPos)
            maDestBlockPos = *mpDestBlockPos;
            maDestBlockPos.miCellTextAttrPos = mpDestBlockPos->miCellTextAttrPos;
        else
            rDestCol.InitBlockPosition(maDestBlockPos);
    }
@@ -1366,7 +1375,7 @@ public:
    {
        if (mpDestBlockPos)
            // Don't forget to save this to the context!
            *mpDestBlockPos = maDestBlockPos;
            mpDestBlockPos->miCellTextAttrPos = maDestBlockPos.miCellTextAttrPos;
    }

    void operator() ( const sc::CellTextAttrStoreType::value_type& aNode, size_t nOffset, size_t nDataSize )
@@ -1392,9 +1401,13 @@ public:
void ScColumn::CopyFromClip(
    sc::CopyFromClipContext& rCxt, SCROW nRow1, SCROW nRow2, tools::Long nDy, ScColumn& rColumn )
{
    sc::ColumnBlockPosition* pBlockPos = rCxt.getBlockPosition(nTab, nCol);
    if (!pBlockPos)
        return;

    if ((rCxt.getInsertFlag() & InsertDeleteFlags::ATTRIB) != InsertDeleteFlags::NONE)
    {
        if (rCxt.isSkipAttrForEmptyCells())
        if (rCxt.isSkipEmptyCells())
        {
            //  copy only attributes for non-empty cells between nRow1-nDy and nRow2-nDy.
            sc::SingleColumnSpanSet aSpanSet(GetDoc().GetSheetLimits());
@@ -1433,7 +1446,7 @@ void ScColumn::CopyFromClip(

            ScTokenArray aArr(GetDoc());
            aArr.AddSingleReference( aRef );
            SetFormulaCell(nDestRow, new ScFormulaCell(rDocument, aDestPos, aArr));
            SetFormulaCell(*pBlockPos, nDestRow, new ScFormulaCell(rDocument, aDestPos, aArr));
        }

        // Don't forget to copy the cell text attributes.
diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx
index fc4c3a5..980ceb5 100644
--- a/sc/source/core/data/column4.cxx
+++ b/sc/source/core/data/column4.cxx
@@ -100,6 +100,50 @@ void ScColumn::DeleteBeforeCopyFromClip(
    if (!rDocument.ValidRow(aRange.mnRow1) || !rDocument.ValidRow(aRange.mnRow2))
        return;

    sc::ColumnBlockPosition* pBlockPos = rCxt.getBlockPosition(nTab, nCol);
    if (!pBlockPos)
        return;

    InsertDeleteFlags nDelFlag = rCxt.getDeleteFlag();

    if (!rCxt.isSkipEmptyCells())
    {
        // Delete the whole destination range.

        if (nDelFlag & InsertDeleteFlags::CONTENTS)
        {
            sc::SingleColumnSpanSet aDeletedRows(GetDoc().GetSheetLimits());
            DeleteCells(*pBlockPos, aRange.mnRow1, aRange.mnRow2, nDelFlag, aDeletedRows);
            rBroadcastSpans.set(GetDoc(), nTab, nCol, aDeletedRows, true);
        }

        if (nDelFlag & InsertDeleteFlags::NOTE)
            DeleteCellNotes(*pBlockPos, aRange.mnRow1, aRange.mnRow2, false);

        if (nDelFlag & InsertDeleteFlags::EDITATTR)
            RemoveEditAttribs(*pBlockPos, aRange.mnRow1, aRange.mnRow2);

        if (nDelFlag & InsertDeleteFlags::ATTRIB)
        {
            pAttrArray->DeleteArea(aRange.mnRow1, aRange.mnRow2);

            if (rCxt.isTableProtected())
            {
                ScPatternAttr aPattern(rDocument.GetPool());
                aPattern.GetItemSet().Put(ScProtectionAttr(false));
                ApplyPatternArea(aRange.mnRow1, aRange.mnRow2, aPattern);
            }

            ScConditionalFormatList* pCondList = rCxt.getCondFormatList();
            if (pCondList)
                pCondList->DeleteArea(nCol, aRange.mnRow1, nCol, aRange.mnRow2);
        }
        else if ((nDelFlag & InsertDeleteFlags::HARDATTR) == InsertDeleteFlags::HARDATTR)
            pAttrArray->DeleteHardAttr(aRange.mnRow1, aRange.mnRow2);

        return;
    }

    ScRange aClipRange = rCxt.getClipDoc()->GetClipParam().getWholeRange();
    SCROW nClipRow1 = aClipRange.aStart.Row();
    SCROW nClipRow2 = aClipRange.aEnd.Row();
@@ -149,10 +193,6 @@ void ScColumn::DeleteBeforeCopyFromClip(
        nDestOffset += nClipRowLen;
    }

    InsertDeleteFlags nDelFlag = rCxt.getDeleteFlag();
    sc::ColumnBlockPosition aBlockPos;
    InitBlockPosition(aBlockPos);

    for (const auto& rDestSpan : aDestSpans)
    {
        SCROW nRow1 = rDestSpan.mnRow1;
@@ -161,15 +201,15 @@ void ScColumn::DeleteBeforeCopyFromClip(
        if (nDelFlag & InsertDeleteFlags::CONTENTS)
        {
            sc::SingleColumnSpanSet aDeletedRows(GetDoc().GetSheetLimits());
            DeleteCells(aBlockPos, nRow1, nRow2, nDelFlag, aDeletedRows);
            DeleteCells(*pBlockPos, nRow1, nRow2, nDelFlag, aDeletedRows);
            rBroadcastSpans.set(GetDoc(), nTab, nCol, aDeletedRows, true);
        }

        if (nDelFlag & InsertDeleteFlags::NOTE)
            DeleteCellNotes(aBlockPos, nRow1, nRow2, false);
            DeleteCellNotes(*pBlockPos, nRow1, nRow2, false);

        if (nDelFlag & InsertDeleteFlags::EDITATTR)
            RemoveEditAttribs(nRow1, nRow2);
            RemoveEditAttribs(*pBlockPos, nRow1, nRow2);

        // Delete attributes just now
        if (nDelFlag & InsertDeleteFlags::ATTRIB)
@@ -211,7 +251,7 @@ void ScColumn::CopyOneCellFromClip( sc::CopyFromClipContext& rCxt, SCROW nRow1, 

    if ((nFlags & InsertDeleteFlags::ATTRIB) != InsertDeleteFlags::NONE)
    {
        if (!rCxt.isSkipAttrForEmptyCells() || rSrcCell.meType != CELLTYPE_NONE)
        if (!rCxt.isSkipEmptyCells() || rSrcCell.meType != CELLTYPE_NONE)
        {
            const ScPatternAttr* pAttr = (bSameDocPool ? rCxt.getSingleCellPattern(nColOffset) :
                    rCxt.getSingleCellPattern(nColOffset)->PutInPool( &rDocument, rCxt.getClipDoc()));
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 9d27705..3592eb4 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -2818,11 +2818,11 @@ public:

}

void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMark,
                                InsertDeleteFlags nInsFlag,
                                ScDocument* pRefUndoDoc, ScDocument* pClipDoc, bool bResetCut,
                                bool bAsLink, bool bIncludeFiltered, bool bSkipAttrForEmpty,
                                const ScRangeList * pDestRanges )
void ScDocument::CopyFromClip(
    const ScRange& rDestRange, const ScMarkData& rMark, InsertDeleteFlags nInsFlag,
    ScDocument* pRefUndoDoc, ScDocument* pClipDoc, bool bResetCut,
    bool bAsLink, bool bIncludeFiltered, bool bSkipEmptyCells,
    const ScRangeList * pDestRanges )
{
    if (bIsClip)
        return;
@@ -2887,7 +2887,7 @@ void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMar
    if (nInsFlag & InsertDeleteFlags::ATTRIB)
        nDelFlag |= InsertDeleteFlags::ATTRIB;

    sc::CopyFromClipContext aCxt(*this, pRefUndoDoc, pClipDoc, nInsFlag, bAsLink, bSkipAttrForEmpty);
    sc::CopyFromClipContext aCxt(*this, pRefUndoDoc, pClipDoc, nInsFlag, bAsLink, bSkipEmptyCells);
    std::pair<SCTAB,SCTAB> aTabRanges = getMarkedTableRange(maTabs, rMark);
    aCxt.setTabRange(aTabRanges.first, aTabRanges.second);
    aCxt.setDeleteFlag(nDelFlag);
@@ -2914,14 +2914,8 @@ void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMar
        SCCOL nCol2 = rRange.aEnd.Col();
        SCROW nRow2 = rRange.aEnd.Row();

        if (bSkipAttrForEmpty)
        {
            // Delete cells in the destination only if their corresponding clip cells are not empty.
            aCxt.setDestRange(nCol1, nRow1, nCol2, nRow2);
            DeleteBeforeCopyFromClip(aCxt, rMark, aBroadcastSpans);
        }
        else
            DeleteArea(nCol1, nRow1, nCol2, nRow2, rMark, nDelFlag, false, &aBroadcastSpans);
        aCxt.setDestRange(nCol1, nRow1, nCol2, nRow2);
        DeleteBeforeCopyFromClip(aCxt, rMark, aBroadcastSpans);

        if (CopyOneCellFromClip(aCxt, nCol1, nRow1, nCol2, nRow2))
            continue;
diff --git a/sc/source/ui/inc/undoblk.hxx b/sc/source/ui/inc/undoblk.hxx
index 39dba0a..a0de06c 100644
--- a/sc/source/ui/inc/undoblk.hxx
+++ b/sc/source/ui/inc/undoblk.hxx
@@ -163,14 +163,14 @@ private:
struct ScUndoPasteOptions
{
    ScPasteFunc  nFunction;
    bool       bSkipEmpty;
    bool       bSkipEmptyCells;
    bool       bTranspose;
    bool       bAsLink;
    InsCellCmd eMoveMode;

    ScUndoPasteOptions() :
        nFunction( ScPasteFunc::NONE ),
        bSkipEmpty( false ),
        bSkipEmptyCells( false ),
        bTranspose( false ),
        bAsLink( false ),
        eMoveMode( INS_NONE )
diff --git a/sc/source/ui/inc/viewfunc.hxx b/sc/source/ui/inc/viewfunc.hxx
index ec037cc..80b9b09 100644
--- a/sc/source/ui/inc/viewfunc.hxx
+++ b/sc/source/ui/inc/viewfunc.hxx
@@ -116,12 +116,14 @@ public:
    bool                        CopyToClipMultiRange( const ScDocument* pClipDoc, const ScRangeList& rRanges, bool bCut,
                                            bool bApi, bool bIncludeObjects );
    rtl::Reference<ScTransferObj> CopyToTransferable();
    SC_DLLPUBLIC bool           PasteFromClip( InsertDeleteFlags nFlags, ScDocument* pClipDoc,
                                    ScPasteFunc nFunction = ScPasteFunc::NONE, bool bSkipEmpty = false,
                                    bool bTranspose = false, bool bAsLink = false,
                                    InsCellCmd eMoveMode = INS_NONE,
                                    InsertDeleteFlags nUndoExtraFlags = InsertDeleteFlags::NONE,
                                    bool bAllowDialogs = false );

    SC_DLLPUBLIC bool PasteFromClip(
        InsertDeleteFlags nFlags, ScDocument* pClipDoc,
        ScPasteFunc nFunction = ScPasteFunc::NONE, bool bSkipEmptyCells = false,
        bool bTranspose = false, bool bAsLink = false,
        InsCellCmd eMoveMode = INS_NONE,
        InsertDeleteFlags nUndoExtraFlags = InsertDeleteFlags::NONE,
        bool bAllowDialogs = false );

    void                        FillTab( InsertDeleteFlags nFlags, ScPasteFunc nFunction, bool bSkipEmpty, bool bAsLink );

@@ -352,14 +354,16 @@ private:
    void            PasteRTF( SCCOL nCol, SCROW nStartRow,
                                const css::uno::Reference< css::datatransfer::XTransferable >& rxTransferable );

    bool PasteMultiRangesFromClip(InsertDeleteFlags nFlags, ScDocument* pClipDoc,
                                  ScPasteFunc nFunction, bool bSkipEmpty, bool bIncludeFiltered,
                                  bool bTranspose, bool bAsLink, bool bAllowDialogs,
                                  InsCellCmd eMoveMode, InsertDeleteFlags nUndoFlags);
    bool PasteMultiRangesFromClip(
        InsertDeleteFlags nFlags, ScDocument* pClipDoc,
        ScPasteFunc nFunction, bool bSkipEmptyCells, bool bIncludeFiltered,
        bool bTranspose, bool bAsLink, bool bAllowDialogs,
        InsCellCmd eMoveMode, InsertDeleteFlags nUndoFlags );

    bool             PasteFromClipToMultiRanges( InsertDeleteFlags nFlags, ScDocument* pClipDoc, ScPasteFunc nFunction,
                                     bool bSkipEmpty, bool bTranspose, bool bAsLink, bool bAllowDialogs,
                                     InsCellCmd eMoveMode, InsertDeleteFlags nUndoFlags );
    bool PasteFromClipToMultiRanges(
        InsertDeleteFlags nFlags, ScDocument* pClipDoc, ScPasteFunc nFunction,
        bool bSkipEmptyCells, bool bTranspose, bool bAsLink, bool bAllowDialogs,
        InsCellCmd eMoveMode, InsertDeleteFlags nUndoFlags );

    void            PostPasteFromClip(const ScRangeList& rPasteRanges, const ScMarkData& rMark);

diff --git a/sc/source/ui/undo/undoblk.cxx b/sc/source/ui/undo/undoblk.cxx
index 26841c0..be93e37 100644
--- a/sc/source/ui/undo/undoblk.cxx
+++ b/sc/source/ui/undo/undoblk.cxx
@@ -1177,7 +1177,7 @@ void ScUndoPaste::Repeat(SfxRepeatTarget& rTarget)
    if (pOwnClip)
    {
        pViewSh->PasteFromClip( nFlags, pOwnClip->GetDocument(),
                                aPasteOptions.nFunction, aPasteOptions.bSkipEmpty, aPasteOptions.bTranspose,
                                aPasteOptions.nFunction, aPasteOptions.bSkipEmptyCells, aPasteOptions.bTranspose,
                                aPasteOptions.bAsLink, aPasteOptions.eMoveMode, InsertDeleteFlags::NONE,
                                true );     // allow warning dialog
    }
diff --git a/sc/source/ui/view/viewfun3.cxx b/sc/source/ui/view/viewfun3.cxx
index 5397d2d..679557d 100644
--- a/sc/source/ui/view/viewfun3.cxx
+++ b/sc/source/ui/view/viewfun3.cxx
@@ -869,7 +869,7 @@ bool checkDestRangeForOverwrite(const ScRangeList& rDestRanges, const ScDocument
}

bool ScViewFunc::PasteFromClip( InsertDeleteFlags nFlags, ScDocument* pClipDoc,
                                ScPasteFunc nFunction, bool bSkipEmpty,
                                ScPasteFunc nFunction, bool bSkipEmptyCells,
                                bool bTranspose, bool bAsLink,
                                InsCellCmd eMoveMode, InsertDeleteFlags nUndoExtraFlags,
                                bool bAllowDialogs )
@@ -900,7 +900,7 @@ bool ScViewFunc::PasteFromClip( InsertDeleteFlags nFlags, ScDocument* pClipDoc,
    if (rClipParam.isMultiRange())
    {
        // Source data is multi-range.
        return PasteMultiRangesFromClip(nFlags, pClipDoc, nFunction, bSkipEmpty, false, bTranspose,
        return PasteMultiRangesFromClip(nFlags, pClipDoc, nFunction, bSkipEmptyCells, false, bTranspose,
                                        bAsLink, bAllowDialogs, eMoveMode, nUndoFlags);
    }

@@ -909,7 +909,7 @@ bool ScViewFunc::PasteFromClip( InsertDeleteFlags nFlags, ScDocument* pClipDoc,
    {
        // Source data is single-range but destination is multi-range.
        return PasteFromClipToMultiRanges(
            nFlags, pClipDoc, nFunction, bSkipEmpty, bTranspose, bAsLink, bAllowDialogs,
            nFlags, pClipDoc, nFunction, bSkipEmptyCells, bTranspose, bAsLink, bAllowDialogs,
            eMoveMode, nUndoFlags);
    }

@@ -1281,7 +1281,7 @@ bool ScViewFunc::PasteFromClip( InsertDeleteFlags nFlags, ScDocument* pClipDoc,
    ScDocumentUniquePtr pMixDoc;
    if (nFunction != ScPasteFunc::NONE)
    {
        bSkipEmpty = false;
        bSkipEmptyCells = false;
        if ( nFlags & InsertDeleteFlags::CONTENTS )
        {
            pMixDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
@@ -1306,7 +1306,7 @@ bool ScViewFunc::PasteFromClip( InsertDeleteFlags nFlags, ScDocument* pClipDoc,
        //  copy normally (original range)
        rDoc.CopyFromClip( aUserRange, aFilteredMark, nNoObjFlags,
                pRefUndoDoc.get(), pClipDoc, true, false, bIncludeFiltered,
                bSkipEmpty, (bMarkIsFiltered ? &aRangeList : nullptr) );
                bSkipEmptyCells, (bMarkIsFiltered ? &aRangeList : nullptr) );

        // adapt refs manually in case of transpose
        if ( bTranspose && bCutMode && (nFlags & InsertDeleteFlags::CONTENTS) )
@@ -1316,7 +1316,7 @@ bool ScViewFunc::PasteFromClip( InsertDeleteFlags nFlags, ScDocument* pClipDoc,
    {
        //  copy with bAsLink=TRUE
        rDoc.CopyFromClip( aUserRange, aFilteredMark, nNoObjFlags, pRefUndoDoc.get(), pClipDoc,
                                true, true, bIncludeFiltered, bSkipEmpty );
                                true, true, bIncludeFiltered, bSkipEmptyCells );
    }
    else
    {
@@ -1333,7 +1333,7 @@ bool ScViewFunc::PasteFromClip( InsertDeleteFlags nFlags, ScDocument* pClipDoc,

    if ( pMixDoc )              // calculate with original data?
    {
        rDoc.MixDocument( aUserRange, nFunction, bSkipEmpty, *pMixDoc );
        rDoc.MixDocument( aUserRange, nFunction, bSkipEmptyCells, *pMixDoc );
    }
    pMixDoc.reset();

@@ -1405,7 +1405,7 @@ bool ScViewFunc::PasteFromClip( InsertDeleteFlags nFlags, ScDocument* pClipDoc,

        ScUndoPasteOptions aOptions;            // store options for repeat
        aOptions.nFunction  = nFunction;
        aOptions.bSkipEmpty = bSkipEmpty;
        aOptions.bSkipEmptyCells = bSkipEmptyCells;
        aOptions.bTranspose = bTranspose;
        aOptions.bAsLink    = bAsLink;
        aOptions.eMoveMode  = eMoveMode;
@@ -1464,7 +1464,7 @@ bool ScViewFunc::PasteFromClip( InsertDeleteFlags nFlags, ScDocument* pClipDoc,
}

bool ScViewFunc::PasteMultiRangesFromClip(InsertDeleteFlags nFlags, ScDocument* pClipDoc,
                                          ScPasteFunc nFunction, bool bSkipEmpty,
                                          ScPasteFunc nFunction, bool bSkipEmptyCells,
                                          bool bIncludeFiltered, bool bTranspose, bool bAsLink,
                                          bool bAllowDialogs, InsCellCmd eMoveMode,
                                          InsertDeleteFlags nUndoFlags)
@@ -1554,7 +1554,7 @@ bool ScViewFunc::PasteMultiRangesFromClip(InsertDeleteFlags nFlags, ScDocument* 
    }

    ScDocumentUniquePtr pMixDoc;
    if ( bSkipEmpty || nFunction != ScPasteFunc::NONE)
    if ( bSkipEmptyCells || nFunction != ScPasteFunc::NONE)
    {
        if ( nFlags & InsertDeleteFlags::CONTENTS )
        {
@@ -1578,10 +1578,10 @@ bool ScViewFunc::PasteMultiRangesFromClip(InsertDeleteFlags nFlags, ScDocument* 
    if (bAsLink && bTranspose)
        nCopyFlags |= InsertDeleteFlags::FORMULA;
    rDoc.CopyMultiRangeFromClip(rCurPos, aMark, nCopyFlags, pClipDoc, true, bAsLink && !bTranspose,
                                bIncludeFiltered, bSkipEmpty);
                                bIncludeFiltered, bSkipEmptyCells);

    if (pMixDoc)
        rDoc.MixDocument(aMarkedRange, nFunction, bSkipEmpty, *pMixDoc);
        rDoc.MixDocument(aMarkedRange, nFunction, bSkipEmptyCells, *pMixDoc);

    AdjustBlockHeight();            // update row heights before pasting objects

@@ -1611,7 +1611,7 @@ bool ScViewFunc::PasteMultiRangesFromClip(InsertDeleteFlags nFlags, ScDocument* 

        ScUndoPasteOptions aOptions;            // store options for repeat
        aOptions.nFunction  = nFunction;
        aOptions.bSkipEmpty = bSkipEmpty;
        aOptions.bSkipEmptyCells = bSkipEmptyCells;
        aOptions.bTranspose = bTranspose;
        aOptions.bAsLink    = bAsLink;
        aOptions.eMoveMode  = eMoveMode;
@@ -1634,7 +1634,7 @@ bool ScViewFunc::PasteMultiRangesFromClip(InsertDeleteFlags nFlags, ScDocument* 

bool ScViewFunc::PasteFromClipToMultiRanges(
    InsertDeleteFlags nFlags, ScDocument* pClipDoc, ScPasteFunc nFunction,
    bool bSkipEmpty, bool bTranspose, bool bAsLink, bool bAllowDialogs,
    bool bSkipEmptyCells, bool bTranspose, bool bAsLink, bool bAllowDialogs,
    InsCellCmd eMoveMode, InsertDeleteFlags nUndoFlags )
{
    if (bTranspose)
@@ -1714,7 +1714,7 @@ bool ScViewFunc::PasteFromClipToMultiRanges(
    }

    ScDocumentUniquePtr pMixDoc;
    if (bSkipEmpty || nFunction != ScPasteFunc::NONE)
    if (bSkipEmptyCells || nFunction != ScPasteFunc::NONE)
    {
        if (nFlags & InsertDeleteFlags::CONTENTS)
        {
@@ -1738,13 +1738,13 @@ bool ScViewFunc::PasteFromClipToMultiRanges(
    {
        rDoc.CopyFromClip(
            aRanges[i], aMark, (nFlags & ~InsertDeleteFlags::OBJECTS), nullptr, pClipDoc,
            false, false, true, bSkipEmpty);
            false, false, true, bSkipEmptyCells);
    }

    if (pMixDoc)
    {
        for (size_t i = 0, n = aRanges.size(); i < n; ++i)
            rDoc.MixDocument(aRanges[i], nFunction, bSkipEmpty, *pMixDoc);
            rDoc.MixDocument(aRanges[i], nFunction, bSkipEmptyCells, *pMixDoc);
    }

    AdjustBlockHeight();            // update row heights before pasting objects
@@ -1756,7 +1756,7 @@ bool ScViewFunc::PasteFromClipToMultiRanges(
        {
            rDoc.CopyFromClip(
                aRanges[i], aMark, InsertDeleteFlags::OBJECTS, nullptr, pClipDoc,
                false, false, true, bSkipEmpty);
                false, false, true, bSkipEmptyCells);
        }
    }

@@ -1777,7 +1777,7 @@ bool ScViewFunc::PasteFromClipToMultiRanges(

        ScUndoPasteOptions aOptions;            // store options for repeat
        aOptions.nFunction  = nFunction;
        aOptions.bSkipEmpty = bSkipEmpty;
        aOptions.bSkipEmptyCells = bSkipEmptyCells;
        aOptions.bTranspose = bTranspose;
        aOptions.bAsLink    = bAsLink;
        aOptions.eMoveMode  = eMoveMode;