sc/inc/clipcontext.hxx | 7 +++++ sc/inc/column.hxx | 2 - sc/source/core/data/column2.cxx | 7 +++-- sc/source/core/data/column3.cxx | 21 ++++++++++++--- sc/source/core/data/column4.cxx | 54 +++++++++++++++++++++++++++++++++------ sc/source/core/data/document.cxx | 10 +------ 6 files changed, 79 insertions(+), 22 deletions(-)
New commits: commit 703fb7739a5e604d90e147db6f67917b8d141150 Author: Kohei Yoshida <ko...@libreoffice.org> AuthorDate: Mon Jan 31 22:45:21 2022 -0500 Commit: Kohei Yoshida <ko...@libreoffice.org> CommitDate: Fri Feb 4 02:40:49 2022 +0100 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. Change-Id: I21054cccdd9f60e073695091740b9415dfef2985 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129267 Tested-by: Jenkins Reviewed-by: Kohei Yoshida <ko...@libreoffice.org> diff --git a/sc/inc/clipcontext.hxx b/sc/inc/clipcontext.hxx index 5754feaaac59..32e2dd97767a 100644 --- a/sc/inc/clipcontext.hxx +++ b/sc/inc/clipcontext.hxx @@ -126,6 +126,13 @@ public: bool isTableProtected() const; bool isAsLink() 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 384c12d52248..480e691366c2 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/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx index 905fc0c3373c..ef20c848e622 100644 --- a/sc/source/core/data/column2.cxx +++ b/sc/source/core/data/column2.cxx @@ -1228,10 +1228,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 68eb921fd354..74b2e1ac7fad 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); } @@ -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,6 +1401,10 @@ 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.isSkipEmptyCells()) @@ -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 e3bcfe169941..980ceb5ac3a2 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) diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index b8239e95fc8b..3592eb4a3ee1 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -2914,14 +2914,8 @@ void ScDocument::CopyFromClip( SCCOL nCol2 = rRange.aEnd.Col(); SCROW nRow2 = rRange.aEnd.Row(); - if (bSkipEmptyCells) - { - // 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;