Kaydet (Commit) b35bfb9f authored tarafından Eike Rathke's avatar Eike Rathke

sticky end col/row anchor for range references, tdf#92779

In range references referring more than one column/row where the end
col/row points to the maximum column or row number that col/row is not
decremented when the range is shrunken. Incrementing an end col/row is
not done past the maximum column or row number, so such references do
not yield #REF! errors anymore. This is also done in named expressions
if the end col/row is an absolute reference.

Change-Id: Iafa2d62abd3e816a1c56c3166af92807e55b75ce
(cherry picked from commit cfecdd61)
üst 6158def6
......@@ -542,6 +542,21 @@ public:
ScRange Intersection( const ScRange& rOther ) const;
/// If maximum end column should not be adapted during reference update.
inline bool IsEndColSticky() const;
/// If maximum end row should not be adapted during reference update.
inline bool IsEndRowSticky() const;
/** Increment or decrement end column unless sticky or until it becomes
sticky. Checks if the range encompasses at least two columns so should
be called before adjusting the start column. */
void IncEndColSticky( SCsCOL nDelta );
/** Increment or decrement end row unless sticky or until it becomes
sticky. Checks if the range encompasses at least two rows so should
be called before adjusting the start row. */
void IncEndRowSticky( SCsROW nDelta );
inline bool operator==( const ScRange& rRange ) const;
inline bool operator!=( const ScRange& rRange ) const;
inline bool operator<( const ScRange& rRange ) const;
......@@ -562,6 +577,18 @@ inline void ScRange::GetVars( SCCOL& nCol1, SCROW& nRow1, SCTAB& nTab1,
aEnd.GetVars( nCol2, nRow2, nTab2 );
}
inline bool ScRange::IsEndColSticky() const
{
// Only in an actual column range, i.e. not if both columns are MAXCOL.
return aEnd.Col() == MAXCOL && aStart.Col() < aEnd.Col();
}
inline bool ScRange::IsEndRowSticky() const
{
// Only in an actual row range, i.e. not if both rows are MAXROW.
return aEnd.Row() == MAXROW && aStart.Row() < aEnd.Row();
}
inline bool ScRange::operator==( const ScRange& rRange ) const
{
return ( (aStart == rRange.aStart) && (aEnd == rRange.aEnd) );
......
......@@ -180,6 +180,16 @@ struct ScComplexRefData
ScComplexRefData& Extend( const ScSingleRefData & rRef, const ScAddress & rPos );
ScComplexRefData& Extend( const ScComplexRefData & rRef, const ScAddress & rPos );
/** Increment or decrement end column unless or until sticky.
@see ScRange::IncEndColSticky()
@return TRUE if changed. */
bool IncEndColSticky( SCCOL nDelta, const ScAddress& rPos );
/** Increment or decrement end row unless or until sticky.
@see ScRange::IncEndRowSticky()
@return TRUE if changed. */
bool IncEndRowSticky( SCROW nDelta, const ScAddress& rPos );
#if DEBUG_FORMULA_COMPILER
void Dump( int nIndent = 0 ) const;
#endif
......
......@@ -2125,13 +2125,67 @@ bool ScAddress::Move( SCsCOL dx, SCsROW dy, SCsTAB dz, ScDocument* pDoc )
bool ScRange::Move( SCsCOL dx, SCsROW dy, SCsTAB dz, ScDocument* pDoc )
{
bool bColRange = (aStart.Col() < aEnd.Col());
bool bRowRange = (aStart.Row() < aEnd.Row());
if (dy && aStart.Row() == 0 && aEnd.Row() == MAXROW)
dy = 0; // Entire column not to be moved.
if (dx && aStart.Col() == 0 && aEnd.Col() == MAXCOL)
dx = 0; // Entire row not to be moved.
bool b = aStart.Move( dx, dy, dz, pDoc );
b &= aEnd.Move( dx, dy, dz, pDoc );
return b;
bool b1 = aStart.Move( dx, dy, dz, pDoc );
if (dx && aEnd.Col() == MAXCOL)
dx = 0; // End column sticky.
if (dy && aEnd.Row() == MAXROW)
dy = 0; // End row sticky.
SCTAB nOldTab = aEnd.Tab();
bool b2 = aEnd.Move( dx, dy, dz, pDoc );
if (!b2)
{
// End column or row of a range may have become sticky.
bColRange = (!dx || (bColRange && aEnd.Col() == MAXCOL));
bRowRange = (!dy || (bRowRange && aEnd.Row() == MAXROW));
b2 = bColRange && bRowRange && (aEnd.Tab() - nOldTab == dz);
}
return b1 && b2;
}
void ScRange::IncEndColSticky( SCsCOL nDelta )
{
SCCOL nCol = aEnd.Col();
if (aStart.Col() >= nCol)
{
// Less than two columns => not sticky.
aEnd.IncCol( nDelta);
return;
}
if (nCol == MAXCOL)
// already sticky
return;
if (nCol < MAXCOL)
aEnd.SetCol( ::std::min( static_cast<SCCOL>(nCol + nDelta), MAXCOL));
else
aEnd.IncCol( nDelta); // was greater than MAXCOL, caller should know..
}
void ScRange::IncEndRowSticky( SCsROW nDelta )
{
SCROW nRow = aEnd.Row();
if (aStart.Row() >= nRow)
{
// Less than two rows => not sticky.
aEnd.IncRow( nDelta);
return;
}
if (nRow == MAXROW)
// already sticky
return;
if (nRow < MAXROW)
aEnd.SetRow( ::std::min( static_cast<SCROW>(nRow + nDelta), MAXROW));
else
aEnd.IncRow( nDelta); // was greater than MAXROW, caller should know..
}
OUString ScAddress::GetColRowString( bool bAbsolute,
......
......@@ -478,6 +478,64 @@ void ScComplexRefData::PutInOrder( const ScAddress& rPos )
ScSingleRefData::PutInOrder( Ref1, Ref2, rPos);
}
bool ScComplexRefData::IncEndColSticky( SCCOL nDelta, const ScAddress& rPos )
{
SCCOL nCol1 = Ref1.IsColRel() ? Ref1.Col() + rPos.Col() : Ref1.Col();
SCCOL nCol2 = Ref2.IsColRel() ? Ref2.Col() + rPos.Col() : Ref2.Col();
if (nCol1 >= nCol2)
{
// Less than two columns => not sticky.
Ref2.IncCol( nDelta);
return true;
}
if (nCol2 == MAXCOL)
// already sticky
return false;
if (nCol2 < MAXCOL)
{
SCCOL nCol = ::std::min( static_cast<SCCOL>(nCol2 + nDelta), MAXCOL);
if (Ref2.IsColRel())
Ref2.SetRelCol( nCol - rPos.Col());
else
Ref2.SetAbsCol( nCol);
}
else
Ref2.IncCol( nDelta); // was greater than MAXCOL, caller should know..
return true;
}
bool ScComplexRefData::IncEndRowSticky( SCROW nDelta, const ScAddress& rPos )
{
SCROW nRow1 = Ref1.IsRowRel() ? Ref1.Row() + rPos.Row() : Ref1.Row();
SCROW nRow2 = Ref2.IsRowRel() ? Ref2.Row() + rPos.Row() : Ref2.Row();
if (nRow1 >= nRow2)
{
// Less than two rows => not sticky.
Ref2.IncRow( nDelta);
return true;
}
if (nRow2 == MAXROW)
// already sticky
return false;
if (nRow2 < MAXROW)
{
SCROW nRow = ::std::min( static_cast<SCROW>(nRow2 + nDelta), MAXROW);
if (Ref2.IsRowRel())
Ref2.SetRelRow( nRow - rPos.Row());
else
Ref2.SetAbsRow( nRow);
}
else
Ref2.IncRow( nDelta); // was greater than MAXROW, caller should know..
return true;
}
#if DEBUG_FORMULA_COMPILER
void ScComplexRefData::Dump( int nIndent ) const
{
......
......@@ -231,6 +231,13 @@ ScRefUpdateRes ScRefUpdate::Update( ScDocument* pDoc, UpdateRefMode eUpdateRefMo
theCol1 = oldCol1;
theCol2 = oldCol2;
}
else if (oldCol2 == MAXCOL && oldCol1 < MAXCOL)
{
// End was sticky, but start may have been moved. Only on range.
theCol2 = oldCol2;
}
// Else, if (bCut2 && theCol2 == MAXCOL) then end becomes sticky,
// but currently there's nothing to do.
}
if ( nDy && (theCol1 >= nCol1) && (theCol2 <= nCol2) &&
(theTab1 >= nTab1) && (theTab2 <= nTab2))
......@@ -256,6 +263,13 @@ ScRefUpdateRes ScRefUpdate::Update( ScDocument* pDoc, UpdateRefMode eUpdateRefMo
theRow1 = oldRow1;
theRow2 = oldRow2;
}
else if (oldRow2 == MAXROW && oldRow1 < MAXROW)
{
// End was sticky, but start may have been moved. Only on range.
theRow2 = oldRow2;
}
// Else, if (bCut2 && theRow2 == MAXROW) then end becomes sticky,
// but currently there's nothing to do.
}
if ( nDz && (theCol1 >= nCol1) && (theCol2 <= nCol2) &&
(theRow1 >= nRow1) && (theRow2 <= nRow2) )
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment