summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@collabora.com>2014-02-25 12:53:33 -0500
committerKohei Yoshida <kohei.yoshida@collabora.com>2014-02-25 22:53:39 -0500
commit79d03eb090a5f88863c1004ef8b7f483cbecb69d (patch)
treeadf2ac29093d7a77ddbd2c560ce219c861df91c5
parent3cb186f57d188ad17503d60cf2f8e6a4bbd8523c (diff)
fdo#75386: Totally fix reference update during range move.
It was just not working at all due to multiple reasons. The reference update needed to be reworked for formula groups such that the token array is adjusted only for the top cell but all formula cells still needed to be processed afterwards. The bound check also needed to be done against the old range prior to the move, not the new range after the move. During undo, the paint had to be deferred until after the two calls to DoUndo() else the formula cells would get re-calculated before the values were placed back to their old positions, causing them to mis- calculate wrong values. Change-Id: Iba66f80a413e0539cac5ab619226cd6f7a04f317
-rw-r--r--sc/inc/formulacell.hxx12
-rw-r--r--sc/inc/listenercontext.hxx11
-rw-r--r--sc/inc/refupdatecontext.hxx18
-rw-r--r--sc/source/core/data/column.cxx234
-rw-r--r--sc/source/core/data/formulacell.cxx17
-rw-r--r--sc/source/core/data/listenercontext.cxx24
-rw-r--r--sc/source/core/tool/token.cxx17
-rw-r--r--sc/source/ui/inc/undoblk.hxx5
-rw-r--r--sc/source/ui/undo/undoblk.cxx19
9 files changed, 293 insertions, 64 deletions
diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index d3e88534c9c0..274548b1414c 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -141,12 +141,6 @@ private:
const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, const ScAddress* pUndoCellPos );
/**
- * Update reference in response to cell move.
- */
- bool UpdateReferenceOnMove(
- const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, const ScAddress* pUndoCellPos );
-
- /**
* Update reference in response to cell copy-n-paste.
*/
bool UpdateReferenceOnCopy(
@@ -252,6 +246,12 @@ public:
bool UpdateReference(
const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc = NULL, const ScAddress* pUndoCellPos = NULL );
+ /**
+ * Update reference in response to cell move.
+ */
+ bool UpdateReferenceOnMove(
+ const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, const ScAddress* pUndoCellPos );
+
void TransposeReference();
void UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
ScDocument* pUndoDoc );
diff --git a/sc/inc/listenercontext.hxx b/sc/inc/listenercontext.hxx
index 1e7d067f6f9f..c0260ef8be1a 100644
--- a/sc/inc/listenercontext.hxx
+++ b/sc/inc/listenercontext.hxx
@@ -17,6 +17,7 @@
#include <boost/scoped_ptr.hpp>
class ScDocument;
+class ScTokenArray;
namespace sc {
@@ -39,9 +40,17 @@ class EndListeningContext : boost::noncopyable
ScDocument& mrDoc;
ColumnSpanSet maSet;
boost::scoped_ptr<ColumnBlockPositionSet> mpPosSet;
+ ScTokenArray* mpOldCode;
+ ScAddress maPosDelta; // Add this to get the old position prior to the move.
+
public:
- EndListeningContext(ScDocument& rDoc);
+ EndListeningContext(ScDocument& rDoc, ScTokenArray* pOldCode = NULL);
+
+ void setPositionDelta( const ScAddress& rDelta );
+
ScDocument& getDoc();
+ ScTokenArray* getOldCode();
+ ScAddress getOldPosition( const ScAddress& rPos ) const;
ColumnBlockPosition* getBlockPosition(SCTAB nTab, SCCOL nCol);
diff --git a/sc/inc/refupdatecontext.hxx b/sc/inc/refupdatecontext.hxx
index ba0beedbc161..c8e52d8acdf0 100644
--- a/sc/inc/refupdatecontext.hxx
+++ b/sc/inc/refupdatecontext.hxx
@@ -55,7 +55,8 @@ struct RefUpdateContext
/**
* Range of cells that are about to be moved for insert/delete/move modes.
* For copy mode, it's the destination range of cells that are about to be
- * pasted.
+ * pasted. When moving a range of cells, it's the destination range, not
+ * the source range.
*/
ScRange maRange;
@@ -77,8 +78,23 @@ struct RefUpdateContext
struct RefUpdateResult
{
+ /**
+ * When this flag is true, the result of the formula needs to be
+ * re-calculated either because it contains a reference that's been
+ * deleted, or the size of a range reference has changed.
+ */
bool mbValueChanged;
+
+ /**
+ * This flag indicates whether any reference in the token array has been
+ * modified.
+ */
bool mbReferenceModified;
+
+ /**
+ * When this flag is true, it indicates that the token array contains a
+ * range name that's been updated.
+ */
bool mbNameModified;
RefUpdateResult();
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 3768808a6268..4b8d38cd934b 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -41,6 +41,7 @@
#include "scopetools.hxx"
#include "sharedformula.hxx"
#include "refupdatecontext.hxx"
+#include <listenercontext.hxx>
#include <svl/poolcach.hxx>
#include <svl/zforlist.hxx>
@@ -2328,6 +2329,67 @@ void ScColumn::MarkSubTotalCells( sc::ColumnSpanSet& rSet, SCROW nRow1, SCROW nR
namespace {
+struct FormulaGroup
+{
+ struct {
+ ScFormulaCell* mpCell; // non-shared formula cell
+ ScFormulaCell** mpCells; // pointer to the top formula cell in a shared group.
+ };
+ size_t mnRow;
+ size_t mnLength;
+ bool mbShared;
+
+ FormulaGroup( ScFormulaCell** pCells, size_t nRow, size_t nLength ) :
+ mpCells(pCells), mnRow(nRow), mnLength(nLength), mbShared(true) {}
+
+ FormulaGroup( ScFormulaCell* pCell, size_t nRow ) :
+ mpCell(pCell), mnRow(nRow), mnLength(0), mbShared(false) {}
+};
+
+class SharedTopFormulaCellPicker : std::unary_function<sc::CellStoreType::value_type, void>
+{
+public:
+ virtual ~SharedTopFormulaCellPicker() {}
+
+ void operator() ( sc::CellStoreType::value_type& node )
+ {
+ if (node.type != sc::element_type_formula)
+ return;
+
+ size_t nTopRow = node.position;
+
+ sc::formula_block::iterator itBeg = sc::formula_block::begin(*node.data);
+ sc::formula_block::iterator itEnd = sc::formula_block::end(*node.data);
+
+ // Only pick shared formula cells that are the top cells of their
+ // respective shared ranges.
+ for (sc::formula_block::iterator it = itBeg; it != itEnd; ++it)
+ {
+ ScFormulaCell* pCell = *it;
+ size_t nRow = nTopRow + std::distance(itBeg, it);
+ if (!pCell->IsShared())
+ {
+ processNonShared(pCell, nRow);
+ continue;
+ }
+
+ if (pCell->IsSharedTop())
+ {
+ ScFormulaCell** pp = &(*it);
+ processSharedTop(pp, nRow, pCell->GetSharedLength());
+
+ // Move to the last cell in the group, to get incremented to
+ // the next cell in the next iteration.
+ size_t nOffsetToLast = pCell->GetSharedLength() - 1;
+ std::advance(it, nOffsetToLast);
+ }
+ }
+ }
+
+ virtual void processNonShared( ScFormulaCell* /*pCell*/, size_t /*nRow*/ ) {}
+ virtual void processSharedTop( ScFormulaCell** /*ppCells*/, size_t /*nRow*/, size_t /*nLength*/ ) {}
+};
+
class UpdateRefOnCopy
{
const sc::RefUpdateContext& mrCxt;
@@ -2358,67 +2420,162 @@ public:
}
};
-class UpdateRefOnNonCopy
+class UpdateRefOnNonCopy : std::unary_function<FormulaGroup, void>
{
SCCOL mnCol;
SCROW mnTab;
- const sc::RefUpdateContext& mrCxt;
+ const sc::RefUpdateContext* mpCxt;
ScDocument* mpUndoDoc;
bool mbUpdated;
+ void updateRefOnMove( FormulaGroup& rGroup )
+ {
+ if (!rGroup.mbShared)
+ {
+ ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab);
+ mbUpdated |= rGroup.mpCell->UpdateReferenceOnMove(*mpCxt, mpUndoDoc, &aUndoPos);
+ return;
+ }
+
+ // Update references of a formula group.
+ ScFormulaCell** pp = rGroup.mpCells;
+ ScFormulaCell** ppEnd = pp + rGroup.mnLength;
+ ScFormulaCell* pTop = *pp;
+ ScTokenArray* pCode = pTop->GetCode();
+ boost::scoped_ptr<ScTokenArray> pOldCode(pCode->Clone());
+
+ ScAddress aPos = pTop->aPos;
+ ScAddress aOldPos = aPos;
+
+ if (mpCxt->maRange.In(aPos))
+ {
+ // The cell is being moved or copied to a new position. The
+ // position has already been updated prior to this call.
+ // Determine its original position before the move which will be
+ // used to adjust relative references later.
+
+ aOldPos.Set(
+ aPos.Col() - mpCxt->mnColDelta,
+ aPos.Row() - mpCxt->mnRowDelta,
+ aPos.Tab() - mpCxt->mnTabDelta);
+ }
+
+ bool bRecalcOnMove = pCode->IsRecalcModeOnRefMove();
+ if (bRecalcOnMove)
+ bRecalcOnMove = aPos != aOldPos;
+
+ sc::RefUpdateResult aRes = pCode->AdjustReferenceOnMove(*mpCxt, aOldPos, aPos);
+ if (aRes.mbReferenceModified || bRecalcOnMove)
+ {
+ // Perform end-listening, start-listening, and dirtying on all
+ // formula cells in the group.
+
+ sc::StartListeningContext aStartCxt(mpCxt->mrDoc);
+
+ sc::EndListeningContext aEndCxt(mpCxt->mrDoc, pOldCode.get());
+ aEndCxt.setPositionDelta(
+ ScAddress(-mpCxt->mnColDelta, -mpCxt->mnRowDelta, -mpCxt->mnTabDelta));
+
+ for (; pp != ppEnd; ++pp)
+ {
+ ScFormulaCell* p = *pp;
+ p->EndListeningTo(aEndCxt);
+ p->StartListeningTo(aStartCxt);
+ p->SetDirty();
+ }
+
+ if (mpUndoDoc)
+ {
+ // Insert the old formula group into the undo document.
+ ScAddress aUndoPos = aOldPos;
+ ScFormulaCell* pFC = new ScFormulaCell(mpUndoDoc, aUndoPos, pOldCode->Clone());
+ ScFormulaCellGroupRef xGroup = pFC->CreateCellGroup(rGroup.mnLength, false);
+
+ mpUndoDoc->SetFormulaCell(aUndoPos, pFC);
+ aUndoPos.IncRow();
+ for (size_t i = 1; i < rGroup.mnLength; ++i, aUndoPos.IncRow())
+ {
+ pFC = new ScFormulaCell(mpUndoDoc, aUndoPos, xGroup);
+ mpUndoDoc->SetFormulaCell(aUndoPos, pFC);
+ }
+ }
+ }
+ }
+
public:
UpdateRefOnNonCopy(
- SCCOL nCol, SCTAB nTab, const sc::RefUpdateContext& rCxt,
+ SCCOL nCol, SCTAB nTab, const sc::RefUpdateContext* pCxt,
ScDocument* pUndoDoc) :
- mnCol(nCol), mnTab(nTab), mrCxt(rCxt),
+ mnCol(nCol), mnTab(nTab), mpCxt(pCxt),
mpUndoDoc(pUndoDoc), mbUpdated(false) {}
- void operator() (size_t nRow, ScFormulaCell* pCell)
+ void operator() ( FormulaGroup& rGroup )
{
- ScAddress aUndoPos(mnCol, nRow, mnTab);
- mbUpdated |= pCell->UpdateReference(mrCxt, mpUndoDoc, &aUndoPos);
+ if (mpCxt->meMode == URM_MOVE)
+ {
+ updateRefOnMove(rGroup);
+ return;
+ }
+
+ if (rGroup.mbShared)
+ {
+ ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab);
+ ScFormulaCell** pp = rGroup.mpCells;
+ ScFormulaCell** ppEnd = pp + rGroup.mnLength;
+ for (; pp != ppEnd; ++pp, aUndoPos.IncRow())
+ {
+ ScFormulaCell* p = *pp;
+ mbUpdated |= p->UpdateReference(*mpCxt, mpUndoDoc, &aUndoPos);
+ }
+ }
+ else
+ {
+ ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab);
+ mbUpdated |= rGroup.mpCell->UpdateReference(*mpCxt, mpUndoDoc, &aUndoPos);
+ }
}
bool isUpdated() const { return mbUpdated; }
};
-class UpdateRefGroupBoundChecker : std::unary_function<sc::CellStoreType::value_type, void>
+class UpdateRefGroupBoundChecker : public SharedTopFormulaCellPicker
{
const sc::RefUpdateContext& mrCxt;
std::vector<SCROW>& mrBounds;
+
public:
UpdateRefGroupBoundChecker(const sc::RefUpdateContext& rCxt, std::vector<SCROW>& rBounds) :
mrCxt(rCxt), mrBounds(rBounds) {}
- void operator() (const sc::CellStoreType::value_type& node)
+ virtual ~UpdateRefGroupBoundChecker() {}
+
+ virtual void processSharedTop( ScFormulaCell** ppCells, size_t /*nRow*/, size_t /*nLength*/ )
{
- if (node.type != sc::element_type_formula)
- return;
+ // Check its tokens and record its reference boundaries.
+ ScFormulaCell& rCell = **ppCells;
+ const ScTokenArray& rCode = *rCell.GetCode();
+ rCode.CheckRelativeReferenceBounds(
+ mrCxt, rCell.aPos, rCell.GetSharedLength(), mrBounds);
+ }
+};
- sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
- sc::formula_block::const_iterator itEnd = sc::formula_block::end(*node.data);
+class FormulaGroupPicker : public SharedTopFormulaCellPicker
+{
+ std::vector<FormulaGroup>& mrGroups;
- // Only pick shared formula cells that are the top cells of their
- // respective shared ranges.
- for (; it != itEnd; ++it)
- {
- const ScFormulaCell& rCell = **it;
- if (!rCell.IsShared())
- continue;
+public:
+ FormulaGroupPicker( std::vector<FormulaGroup>& rGroups ) : mrGroups(rGroups) {}
- if (rCell.IsSharedTop())
- {
- // Check its tokens and record its reference boundaries.
- const ScTokenArray& rCode = *rCell.GetCode();
- rCode.CheckRelativeReferenceBounds(
- mrCxt, rCell.aPos, rCell.GetSharedLength(), mrBounds);
+ virtual ~FormulaGroupPicker() {}
- // Move to the last cell in the group, to get incremented to
- // the next cell in the next iteration.
- size_t nOffsetToLast = rCell.GetSharedLength() - 1;
- std::advance(it, nOffsetToLast);
- }
- }
+ virtual void processNonShared( ScFormulaCell* pCell, size_t nRow )
+ {
+ mrGroups.push_back(FormulaGroup(pCell, nRow));
+ }
+
+ virtual void processSharedTop( ScFormulaCell** ppCells, size_t nRow, size_t nLength )
+ {
+ mrGroups.push_back(FormulaGroup(ppCells, nRow, nLength));
}
};
@@ -2451,8 +2608,8 @@ bool ScColumn::UpdateReference( sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc
if (rCxt.meMode == URM_COPY)
return UpdateReferenceOnCopy(rCxt, pUndoDoc);
- if (IsEmptyData())
- // Cells in this column are all empty.
+ if (IsEmptyData() || pDocument->IsClipOrUndo())
+ // Cells in this column are all empty, or clip or undo doc. No update needed.
return false;
std::vector<SCROW> aBounds;
@@ -2490,8 +2647,13 @@ bool ScColumn::UpdateReference( sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc
// Do the actual splitting.
sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds);
- UpdateRefOnNonCopy aHandler(nCol, nTab, rCxt, pUndoDoc);
- sc::ProcessFormula(maCells, aHandler);
+ // Collect all formula groups.
+ std::vector<FormulaGroup> aGroups;
+ std::for_each(maCells.begin(), maCells.end(), FormulaGroupPicker(aGroups));
+
+ // Process all collected formula groups.
+ UpdateRefOnNonCopy aHandler(nCol, nTab, &rCxt, pUndoDoc);
+ aHandler = std::for_each(aGroups.begin(), aGroups.end(), aHandler);
if (aHandler.isUpdated())
rCxt.maRegroupCols.set(nTab, nCol);
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index aa6e8b14e572..0540e88a9c19 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -3932,7 +3932,7 @@ void ScFormulaCell::EndListeningTo( ScDocument* pDoc, ScTokenArray* pArr,
{
case svSingleRef:
{
- ScAddress aCell = t->GetSingleRef().toAbs(aPos);
+ ScAddress aCell = t->GetSingleRef().toAbs(aCellPos);
if (aCell.IsValid())
pDoc->EndListeningCell(aCell, this);
}
@@ -3954,27 +3954,32 @@ void ScFormulaCell::EndListeningTo( sc::EndListeningContext& rCxt )
ScDocument& rDoc = rCxt.getDoc();
rDoc.SetDetectiveDirty(true); // It has changed something
- if (pCode->IsRecalcModeAlways())
+ ScTokenArray* pArr = rCxt.getOldCode();
+ ScAddress aCellPos = rCxt.getOldPosition(aPos);
+ if (!pArr)
+ pArr = pCode;
+
+ if (pArr->IsRecalcModeAlways())
{
rDoc.EndListeningArea(BCA_LISTEN_ALWAYS, this);
return;
}
- pCode->Reset();
+ pArr->Reset();
ScToken* t;
- while ( ( t = static_cast<ScToken*>(pCode->GetNextReferenceRPN()) ) != NULL )
+ while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL )
{
switch (t->GetType())
{
case svSingleRef:
{
- ScAddress aCell = t->GetSingleRef().toAbs(aPos);
+ ScAddress aCell = t->GetSingleRef().toAbs(aCellPos);
if (aCell.IsValid())
rDoc.EndListeningCell(rCxt, aCell, *this);
}
break;
case svDoubleRef:
- endListeningArea(this, rDoc, aPos, *t);
+ endListeningArea(this, rDoc, aCellPos, *t);
break;
default:
; // nothing
diff --git a/sc/source/core/data/listenercontext.cxx b/sc/source/core/data/listenercontext.cxx
index dc9234681acb..3dfe5edb0b37 100644
--- a/sc/source/core/data/listenercontext.cxx
+++ b/sc/source/core/data/listenercontext.cxx
@@ -52,14 +52,34 @@ ColumnBlockPosition* StartListeningContext::getBlockPosition(SCTAB nTab, SCCOL n
return mpSet->getBlockPosition(nTab, nCol);
}
-EndListeningContext::EndListeningContext(ScDocument& rDoc) :
- mrDoc(rDoc), maSet(false), mpPosSet(new ColumnBlockPositionSet(rDoc)) {}
+EndListeningContext::EndListeningContext(ScDocument& rDoc, ScTokenArray* pOldCode) :
+ mrDoc(rDoc), maSet(false), mpPosSet(new ColumnBlockPositionSet(rDoc)),
+ mpOldCode(pOldCode), maPosDelta(0,0,0) {}
+
+void EndListeningContext::setPositionDelta( const ScAddress& rDelta )
+{
+ maPosDelta = rDelta;
+}
ScDocument& EndListeningContext::getDoc()
{
return mrDoc;
}
+ScTokenArray* EndListeningContext::getOldCode()
+{
+ return mpOldCode;
+}
+
+ScAddress EndListeningContext::getOldPosition( const ScAddress& rPos ) const
+{
+ ScAddress aOldPos = rPos;
+ aOldPos.IncCol(maPosDelta.Col());
+ aOldPos.IncRow(maPosDelta.Row());
+ aOldPos.IncTab(maPosDelta.Tab());
+ return aOldPos;
+}
+
ColumnBlockPosition* EndListeningContext::getBlockPosition(SCTAB nTab, SCCOL nCol)
{
return mpPosSet->getBlockPosition(nTab, nCol);
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index 463fd06e29a4..7052049a9f44 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -3155,17 +3155,22 @@ void checkBounds(
if (!rRef.IsRowRel())
return;
+ ScRange aCheckRange = rCxt.maRange;
+ if (rCxt.meMode == URM_MOVE)
+ // Check bounds against the old range prior to the move.
+ aCheckRange.Move(-rCxt.mnColDelta, -rCxt.mnRowDelta, -rCxt.mnTabDelta);
+
ScRange aAbs(rRef.toAbs(rPos));
aAbs.aEnd.IncRow(nGroupLen-1);
- if (!rCxt.maRange.Intersects(aAbs))
+ if (!aCheckRange.Intersects(aAbs))
return;
// Get the boundary row positions.
- if (aAbs.aEnd.Row() < rCxt.maRange.aStart.Row())
+ if (aAbs.aEnd.Row() < aCheckRange.aStart.Row())
// No intersections.
return;
- if (aAbs.aStart.Row() <= rCxt.maRange.aStart.Row())
+ if (aAbs.aStart.Row() <= aCheckRange.aStart.Row())
{
// +-+ <---- top
// | |
@@ -3175,11 +3180,11 @@ void checkBounds(
// +-------+
// Add offset from the reference top to the cell position.
- SCROW nOffset = rCxt.maRange.aStart.Row() - aAbs.aStart.Row();
+ SCROW nOffset = aCheckRange.aStart.Row() - aAbs.aStart.Row();
rBounds.push_back(rPos.Row()+nOffset);
}
- if (aAbs.aEnd.Row() >= rCxt.maRange.aEnd.Row())
+ if (aAbs.aEnd.Row() >= aCheckRange.aEnd.Row())
{
// only check for end range
@@ -3191,7 +3196,7 @@ void checkBounds(
// +-+
// Ditto.
- SCROW nOffset = rCxt.maRange.aEnd.Row() + 1 - aAbs.aStart.Row();
+ SCROW nOffset = aCheckRange.aEnd.Row() + 1 - aAbs.aStart.Row();
rBounds.push_back(rPos.Row()+nOffset);
}
}
diff --git a/sc/source/ui/inc/undoblk.hxx b/sc/source/ui/inc/undoblk.hxx
index d79e32cc234c..29e82ac91330 100644
--- a/sc/source/ui/inc/undoblk.hxx
+++ b/sc/source/ui/inc/undoblk.hxx
@@ -241,6 +241,9 @@ public:
virtual OUString GetComment() const;
private:
+ sal_uInt16 mnPaintExtFlags;
+ ScRangeList maPaintRanges;
+
ScRange aSrcRange;
ScRange aDestRange;
sal_uLong nStartChangeAction;
@@ -249,7 +252,7 @@ private:
bool bKeepScenarioFlags;
void PaintArea( ScRange aRange, sal_uInt16 nExtFlags ) const;
- void DoUndo( ScRange aRange ) const;
+ void DoUndo( ScRange aRange );
void SetChangeTrack();
};
diff --git a/sc/source/ui/undo/undoblk.cxx b/sc/source/ui/undo/undoblk.cxx
index 1fdf7d156c2b..cd0c707d6309 100644
--- a/sc/source/ui/undo/undoblk.cxx
+++ b/sc/source/ui/undo/undoblk.cxx
@@ -1214,7 +1214,7 @@ void ScUndoDragDrop::PaintArea( ScRange aRange, sal_uInt16 nExtFlags ) const
pDocShell->PostPaint( aRange, nPaint, nExtFlags );
}
-void ScUndoDragDrop::DoUndo( ScRange aRange ) const
+void ScUndoDragDrop::DoUndo( ScRange aRange )
{
ScDocument* pDoc = pDocShell->GetDocument();
@@ -1227,8 +1227,7 @@ void ScUndoDragDrop::DoUndo( ScRange aRange ) const
ScRange aPaintRange = aRange;
pDoc->ExtendMerge( aPaintRange ); // before deleting
- sal_uInt16 nExtFlags = 0;
- pDocShell->UpdatePaintExt( nExtFlags, aPaintRange );
+ pDocShell->UpdatePaintExt(mnPaintExtFlags, aPaintRange);
// do not undo objects and note captions, they are handled via drawing undo
sal_uInt16 nUndoFlags = (IDF_ALL & ~IDF_OBJECTS) | IDF_NOCAPTIONS;
@@ -1241,16 +1240,26 @@ void ScUndoDragDrop::DoUndo( ScRange aRange ) const
aPaintRange.aEnd.SetCol( std::max( aPaintRange.aEnd.Col(), aRange.aEnd.Col() ) );
aPaintRange.aEnd.SetRow( std::max( aPaintRange.aEnd.Row(), aRange.aEnd.Row() ) );
- pDocShell->UpdatePaintExt( nExtFlags, aPaintRange );
- PaintArea( aPaintRange, nExtFlags );
+ pDocShell->UpdatePaintExt(mnPaintExtFlags, aPaintRange);
+ maPaintRanges.Join(aPaintRange);
}
void ScUndoDragDrop::Undo()
{
+ mnPaintExtFlags = 0;
+ maPaintRanges.RemoveAll();
+
BeginUndo();
DoUndo(aDestRange);
if (bCut)
DoUndo(aSrcRange);
+
+ for (size_t i = 0; i < maPaintRanges.size(); ++i)
+ {
+ const ScRange* p = maPaintRanges[i];
+ PaintArea(*p, mnPaintExtFlags);
+ }
+
EndUndo();
SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_AREALINKS_CHANGED ) );
}