Resolves: tdf#108788 update references for deletions at end of sheet
ie. when the last column or row is included in the deletion. This seems to have
never worked.
Change-Id: Ic1bd1944298fe248367597177ca01e109585fcd2
diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx
index 677eef6..a2d0682 100644
--- a/sc/source/core/data/documen3.cxx
+++ b/sc/source/core/data/documen3.cxx
@@ -983,7 +983,11 @@ void ScDocument::AddUnoRefChange( sal_Int64 nId, const ScRangeList& rOldRanges )
void ScDocument::UpdateReference(
sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, bool bIncludeDraw, bool bUpdateNoteCaptionPos )
{
if (!ValidRange(rCxt.maRange))
if (!ValidRange(rCxt.maRange) && !(rCxt.meMode == URM_INSDEL &&
((rCxt.mnColDelta < 0 && // convention from ScDocument::DeleteCol()
rCxt.maRange.aStart.Col() == MAXCOLCOUNT && rCxt.maRange.aEnd.Col() == MAXCOLCOUNT) ||
(rCxt.mnRowDelta < 0 && // convention from ScDocument::DeleteRow()
rCxt.maRange.aStart.Row() == MAXROWCOUNT && rCxt.maRange.aEnd.Row() == MAXROWCOUNT))))
return;
std::unique_ptr<sc::ExpandRefsSwitch> pExpandRefsSwitch;
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index b0a9538..2627a0c 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -1416,12 +1416,21 @@ void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab,
while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
sc::RefUpdateContext aCxt(*this);
if ( ValidRow(nStartRow+nSize) )
const bool bLastRowIncluded = (nStartRow + nSize == MAXROWCOUNT && ValidRow(nStartRow));
if ( ValidRow(nStartRow+nSize) || bLastRowIncluded )
{
lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
aCxt.meMode = URM_INSDEL;
aCxt.maRange = ScRange(nStartCol, nStartRow+nSize, nTabRangeStart, nEndCol, MAXROW, nTabRangeEnd);
aCxt.mnRowDelta = -(static_cast<SCROW>(nSize));
if (bLastRowIncluded)
{
// Last row is included, shift a virtually non-existent row in.
aCxt.maRange = ScRange( nStartCol, MAXROWCOUNT, nTabRangeStart, nEndCol, MAXROWCOUNT, nTabRangeEnd);
}
else
{
aCxt.maRange = ScRange( nStartCol, nStartRow+nSize, nTabRangeStart, nEndCol, MAXROW, nTabRangeEnd);
}
do
{
UpdateReference(aCxt, pRefUndoDoc, true, false);
@@ -1447,7 +1456,7 @@ void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab,
// Mark all joined groups for group listening.
SetNeedsListeningGroups(aGroupPos);
if ( ValidRow(nStartRow+nSize) )
if ( ValidRow(nStartRow+nSize) || bLastRowIncluded )
{
// Listeners have been removed in UpdateReference
StartNeededListeners();
@@ -1616,12 +1625,22 @@ void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTA
while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
sc::RefUpdateContext aCxt(*this);
if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
const bool bLastColIncluded = (nStartCol + nSize == MAXCOLCOUNT && ValidCol(nStartCol));
if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) || bLastColIncluded )
{
lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
aCxt.meMode = URM_INSDEL;
aCxt.maRange = ScRange(sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart, MAXCOL, nEndRow, nTabRangeEnd);
aCxt.mnColDelta = -(static_cast<SCCOL>(nSize));
if (bLastColIncluded)
{
// Last column is included, shift a virtually non-existent column in.
aCxt.maRange = ScRange( MAXCOLCOUNT, nStartRow, nTabRangeStart, MAXCOLCOUNT, nEndRow, nTabRangeEnd);
}
else
{
aCxt.maRange = ScRange( sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart,
MAXCOL, nEndRow, nTabRangeEnd);
}
do
{
UpdateReference(aCxt, pRefUndoDoc, true, false);
@@ -1638,7 +1657,7 @@ void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTA
maTabs[i]->DeleteCol(aCxt.maRegroupCols, nStartCol, nStartRow, nEndRow, nSize, pUndoOutline);
}
if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) || bLastColIncluded )
{
// Listeners have been removed in UpdateReference
StartNeededListeners();
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index 2e05497..0538a10 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -2650,22 +2650,29 @@ void restoreDeletedRef( ScComplexRefData& rRef, const sc::RefUpdateContext& rCxt
restoreDeletedRef(rRef.Ref2, rCxt);
}
bool shrinkRange( const sc::RefUpdateContext& rCxt, ScRange& rRefRange, const ScRange& rDeletedRange,
enum ShrinkResult
{
UNMODIFIED,
SHRUNK,
STICKY
};
ShrinkResult shrinkRange( const sc::RefUpdateContext& rCxt, ScRange& rRefRange, const ScRange& rDeletedRange,
const ScComplexRefData& rRef )
{
if (!rDeletedRange.Intersects(rRefRange))
return false;
return UNMODIFIED;
if (rCxt.mnColDelta < 0)
{
if (rRef.IsEntireRow())
// Entire rows are not affected, columns are anchored.
return false;
return STICKY;
// Shifting left.
if (rRefRange.aStart.Row() < rDeletedRange.aStart.Row() || rDeletedRange.aEnd.Row() < rRefRange.aEnd.Row())
// Deleted range is only partially overlapping in vertical direction. Bail out.
return false;
return UNMODIFIED;
if (rDeletedRange.aStart.Col() <= rRefRange.aStart.Col())
{
@@ -2687,7 +2694,7 @@ bool shrinkRange( const sc::RefUpdateContext& rCxt, ScRange& rRefRange, const Sc
{
if (rRefRange.IsEndColSticky())
// Sticky end not affected.
return false;
return STICKY;
// Reference is deleted in the middle. Move the last column
// position to the left.
@@ -2698,25 +2705,25 @@ bool shrinkRange( const sc::RefUpdateContext& rCxt, ScRange& rRefRange, const Sc
{
if (rRefRange.IsEndColSticky())
// Sticky end not affected.
return false;
return STICKY;
// The reference range is truncated on the right.
SCCOL nDelta = rDeletedRange.aStart.Col() - rRefRange.aEnd.Col() - 1;
rRefRange.IncEndColSticky(nDelta);
}
return true;
return SHRUNK;
}
else if (rCxt.mnRowDelta < 0)
{
if (rRef.IsEntireCol())
// Entire columns are not affected, rows are anchored.
return false;
return STICKY;
// Shifting up.
if (rRefRange.aStart.Col() < rDeletedRange.aStart.Col() || rDeletedRange.aEnd.Col() < rRefRange.aEnd.Col())
// Deleted range is only partially overlapping in horizontal direction. Bail out.
return false;
return UNMODIFIED;
if (rDeletedRange.aStart.Row() <= rRefRange.aStart.Row())
{
@@ -2738,7 +2745,7 @@ bool shrinkRange( const sc::RefUpdateContext& rCxt, ScRange& rRefRange, const Sc
{
if (rRefRange.IsEndRowSticky())
// Sticky end not affected.
return false;
return STICKY;
// Reference is deleted in the middle. Move the last row
// position upward.
@@ -2749,16 +2756,16 @@ bool shrinkRange( const sc::RefUpdateContext& rCxt, ScRange& rRefRange, const Sc
{
if (rRefRange.IsEndRowSticky())
// Sticky end not affected.
return false;
return STICKY;
// The reference range is truncated on the bottom.
SCCOL nDelta = rDeletedRange.aStart.Row() - rRefRange.aEnd.Row() - 1;
rRefRange.IncEndRowSticky(nDelta);
}
return true;
return SHRUNK;
}
return false;
return UNMODIFIED;
}
bool expandRange( const sc::RefUpdateContext& rCxt, ScRange& rRefRange, const ScRange& rSelectedRange,
@@ -3014,7 +3021,8 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnShift( const sc::RefUpdateCon
}
else if (aSelectedRange.Intersects(aAbs))
{
if (shrinkRange(rCxt, aAbs, aSelectedRange, rRef))
const ShrinkResult eSR = shrinkRange(rCxt, aAbs, aSelectedRange, rRef);
if (eSR == SHRUNK)
{
// The reference range has been shrunk.
rRef.SetRange(aAbs, aNewPos);
@@ -3022,6 +3030,13 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnShift( const sc::RefUpdateCon
aRes.mbReferenceModified = true;
break;
}
else if (eSR == STICKY)
{
// The reference range stays the same but a
// new (empty) cell range is shifted in and
// may change the calculation result.
aRes.mbValueChanged = true;
}
}
}