[Libreoffice-commits] core.git: Branch 'feature/formula-core-rework' - 4 commits - sc/inc sc/qa sc/source
Kohei Yoshida
kohei.yoshida at gmail.com
Thu Jul 18 17:49:17 PDT 2013
sc/inc/refupdatecontext.hxx | 1
sc/qa/unit/ucalc_formula.cxx | 46 +++++++++++++++++
sc/source/core/data/formulacell.cxx | 12 ----
sc/source/core/data/refupdatecontext.cxx | 2
sc/source/core/tool/token.cxx | 81 +++++++++++++++++++++++++++++++
5 files changed, 132 insertions(+), 10 deletions(-)
New commits:
commit c7db01d4010d82fc29d47aab137ba6e978455607
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date: Thu Jul 18 20:51:28 2013 -0400
Add test for no reference error on reference deletion.
Change-Id: I3e6fd2b41c3bbf0ee12769a507fbf484f9ba833b
diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx
index e04c741..a57c6cf 100644
--- a/sc/qa/unit/ucalc_formula.cxx
+++ b/sc/qa/unit/ucalc_formula.cxx
@@ -306,9 +306,25 @@ void Test::testFormulaRefUpdate()
if (!checkFormula(*m_pDoc, aPos, "$A$1"))
CPPUNIT_FAIL("Wrong formula in C4.");
+ // Delete row 1 which will delete the value cell (A1).
+ m_pDoc->DeleteRow(ScRange(0,0,0,MAXCOL,0,0));
+
+ aPos = ScAddress(2,1,0);
+ ScFormulaCell* pFC = m_pDoc->GetFormulaCell(aPos);
+ CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pFC);
+ CPPUNIT_ASSERT_EQUAL(ScErrorCodes::errNoRef, pFC->GetErrCode());
+ aPos = ScAddress(2,2,0);
+ pFC = m_pDoc->GetFormulaCell(aPos);
+ CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pFC);
+ CPPUNIT_ASSERT_EQUAL(ScErrorCodes::errNoRef, pFC->GetErrCode());
+
// Clear all and start over.
clearRange(m_pDoc, ScRange(0,0,0,10,10,0));
+ // ------------------------------------------
+ // Test range updates
+ // ------------------------------------------
+
// Fill B2:C3 with values.
m_pDoc->SetValue(ScAddress(1,1,0), 1);
m_pDoc->SetValue(ScAddress(1,2,0), 2);
@@ -410,6 +426,18 @@ void Test::testFormulaRefUpdate()
CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(0,5,0)));
CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(0,6,0)));
+ // Delete rows 2:3 to completely remove the referenced range.
+ m_pDoc->DeleteRow(ScRange(0,1,0,MAXCOL,2,0));
+
+ // Both A4 and A5 should show #REF! errors.
+ pFC = m_pDoc->GetFormulaCell(ScAddress(0,3,0));
+ CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pFC);
+ CPPUNIT_ASSERT_EQUAL(ScErrorCodes::errNoRef, pFC->GetErrCode());
+
+ pFC = m_pDoc->GetFormulaCell(ScAddress(0,4,0));
+ CPPUNIT_ASSERT_MESSAGE("This should be a formula cell.", pFC);
+ CPPUNIT_ASSERT_EQUAL(ScErrorCodes::errNoRef, pFC->GetErrCode());
+
m_pDoc->DeleteTab(0);
}
commit 886716bddd0ac18f3c122d6ebd6def6dedf7448e
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date: Thu Jul 18 20:25:12 2013 -0400
Handle deleted references.
Change-Id: Ic99d8f154cf487983aa5fce59cde053a9b9d3fb3
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index 7e444b0..04a161a 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -2217,8 +2217,67 @@ void ScTokenArray::AdjustAbsoluteRefs( const ScDocument* pOldDoc, const ScAddres
}
}
+namespace {
+
+ScRange getDeletedRange( const sc::RefUpdateContext& rCxt )
+{
+ ScRange aDeletedRange(ScAddress::INITIALIZE_INVALID);
+ if (rCxt.mnColDelta < 0)
+ {
+ // Delete and shift to left.
+ aDeletedRange.aStart = ScAddress(rCxt.maRange.aStart.Col()+rCxt.mnColDelta, rCxt.maRange.aStart.Row(), rCxt.maRange.aStart.Tab());
+ aDeletedRange.aEnd = ScAddress(rCxt.maRange.aStart.Col()-1, rCxt.maRange.aEnd.Row(), rCxt.maRange.aEnd.Tab());
+ }
+ else if (rCxt.mnRowDelta < 0)
+ {
+ // Delete and shift up.
+ aDeletedRange.aStart = ScAddress(rCxt.maRange.aStart.Col(), rCxt.maRange.aStart.Row()+rCxt.mnRowDelta, rCxt.maRange.aStart.Tab());
+ aDeletedRange.aEnd = ScAddress(rCxt.maRange.aEnd.Col(), rCxt.maRange.aStart.Row()-1, rCxt.maRange.aEnd.Tab());
+ }
+ else if (rCxt.mnTabDelta < 0)
+ {
+ // Deleting sheets.
+ // TODO : Figure out what to do here.
+ }
+
+ return aDeletedRange;
+}
+
+void setRefDeleted( ScSingleRefData& rRef, const sc::RefUpdateContext& rCxt )
+{
+ if (rCxt.mnColDelta < 0)
+ rRef.SetColDeleted(true);
+ else if (rCxt.mnRowDelta < 0)
+ rRef.SetRowDeleted(true);
+ else if (rCxt.mnTabDelta < 0)
+ rRef.SetTabDeleted(true);
+}
+
+void setRefDeleted( ScComplexRefData& rRef, const sc::RefUpdateContext& rCxt )
+{
+ if (rCxt.mnColDelta < 0)
+ {
+ rRef.Ref1.SetColDeleted(true);
+ rRef.Ref2.SetColDeleted(true);
+ }
+ else if (rCxt.mnRowDelta < 0)
+ {
+ rRef.Ref1.SetRowDeleted(true);
+ rRef.Ref2.SetRowDeleted(true);
+ }
+ else if (rCxt.mnTabDelta < 0)
+ {
+ rRef.Ref1.SetTabDeleted(true);
+ rRef.Ref2.SetTabDeleted(true);
+ }
+}
+
+}
+
sc::RefUpdateResult ScTokenArray::AdjustReferenceOnShift( const sc::RefUpdateContext& rCxt, const ScAddress& rOldPos )
{
+ ScRange aDeletedRange = getDeletedRange(rCxt);
+
sc::RefUpdateResult aRes;
ScAddress aNewPos = rOldPos;
bool bCellShifted = rCxt.maRange.In(rOldPos);
@@ -2237,6 +2296,14 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnShift( const sc::RefUpdateCon
ScSingleRefData& rRef = pToken->GetSingleRef();
ScAddress aAbs = rRef.toAbs(rOldPos);
+ if (aDeletedRange.In(aAbs))
+ {
+ // This reference is in the deleted region.
+ setRefDeleted(rRef, rCxt);
+ aRes.mbValueChanged = true;
+ break;
+ }
+
if (rCxt.maRange.In(aAbs))
aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
@@ -2248,6 +2315,14 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnShift( const sc::RefUpdateCon
ScComplexRefData& rRef = pToken->GetDoubleRef();
ScRange aAbs = rRef.toAbs(rOldPos);
+ if (aDeletedRange.In(aAbs))
+ {
+ // This reference is in the deleted region.
+ setRefDeleted(rRef, rCxt);
+ aRes.mbValueChanged = true;
+ break;
+ }
+
if (rCxt.maRange.In(aAbs))
aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
else if (rCxt.maRange.Intersects(aAbs))
commit 390497d548536a65d0f3a5bae32567e97d2e171b
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date: Thu Jul 18 17:30:10 2013 -0400
Mark formula cells dirty when a referenced range gets partially shifted.
Change-Id: I5d97cb0e325c0168fdae57f8ec39f62c85bec524
diff --git a/sc/inc/refupdatecontext.hxx b/sc/inc/refupdatecontext.hxx
index 7192ec7..2f33767 100644
--- a/sc/inc/refupdatecontext.hxx
+++ b/sc/inc/refupdatecontext.hxx
@@ -49,6 +49,7 @@ struct RefUpdateResult
bool mbRangeSizeModified;
RefUpdateResult();
+ RefUpdateResult(const RefUpdateResult& r);
};
}
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index e17d4c6..4defffd 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -2310,18 +2310,13 @@ bool ScFormulaCell::UpdateReferenceOnShift(
EndListeningTo(pDocument, pOldCode.get(), aOldPos);
}
- bool bNeedDirty = false;
// NeedDirty for changes except for Copy and Move/Insert without RelNames
- if (bRangeModified || bColRowNameCompile ||
- (bValChanged && (bHasRelName || bInDeleteUndo || bRefSizeChanged)) || bOnRefMove)
- bNeedDirty = true;
+ bool bNeedDirty = (bRangeModified || bValChanged || bColRowNameCompile || bOnRefMove);
if (pUndoDoc && (bValChanged || bOnRefMove))
setOldCodeToUndo(pUndoDoc, aUndoPos, pOldCode.get(), eTempGrammar, cMatrixFlag);
- bValChanged = false;
-
- if ( ( bCompile = (bCompile || bValChanged || bRangeModified || bColRowNameCompile) ) != 0 )
+ if ( ( bCompile = (bCompile || bRangeModified || bColRowNameCompile) ) != 0 )
{
CompileTokenArray( bNewListening ); // no Listening
bNeedDirty = true;
@@ -2539,7 +2534,6 @@ bool ScFormulaCell::UpdateReferenceOnCopy(
bOnRefMove = (bValChanged || (aPos != aOldPos));
bool bColRowNameCompile = false;
- bool bHasRelName = false;
bool bNewListening = false;
bool bInDeleteUndo = false;
@@ -2553,8 +2547,6 @@ bool ScFormulaCell::UpdateReferenceOnCopy(
ScChangeTrack* pChangeTrack = pDocument->GetChangeTrack();
bInDeleteUndo = (pChangeTrack && pChangeTrack->IsInDeleteUndo());
- // RelNameRefs are always moved
- bHasRelName = HasRelNameReference();
// Reference changed and new listening needed?
// Except in Insert/Delete without specialties.
bNewListening =
diff --git a/sc/source/core/data/refupdatecontext.cxx b/sc/source/core/data/refupdatecontext.cxx
index 72dadf0..9f39f44 100644
--- a/sc/source/core/data/refupdatecontext.cxx
+++ b/sc/source/core/data/refupdatecontext.cxx
@@ -20,6 +20,8 @@ bool RefUpdateContext::hasDelta() const
}
RefUpdateResult::RefUpdateResult() : mbValueChanged(false), mbRangeSizeModified(false) {}
+RefUpdateResult::RefUpdateResult(const RefUpdateResult& r) :
+ mbValueChanged(r.mbValueChanged), mbRangeSizeModified(r.mbRangeSizeModified) {}
}
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index 56d4ddc..7e444b0 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -2250,6 +2250,12 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnShift( const sc::RefUpdateCon
if (rCxt.maRange.In(aAbs))
aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
+ else if (rCxt.maRange.Intersects(aAbs))
+ {
+ // Part of the referenced range is being shifted. This
+ // will change the values of the range.
+ aRes.mbValueChanged = true;
+ }
rRef.SetRange(aAbs, aNewPos);
}
commit d2c49aafcc7e6282d7f3f8cf4b27ddf6b60eb4e7
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date: Thu Jul 18 17:28:43 2013 -0400
Test for recalculating formula cells on partial shifting of ref range.
Change-Id: I63807a0368551c6a38cf98865a877e92810b2a22
diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx
index 134d23c..e04c741 100644
--- a/sc/qa/unit/ucalc_formula.cxx
+++ b/sc/qa/unit/ucalc_formula.cxx
@@ -392,6 +392,24 @@ void Test::testFormulaRefUpdate()
if (!checkFormula(*m_pDoc, aPos, "SUM($B$2:$C$3)"))
CPPUNIT_FAIL("Wrong formula in A7.");
+ // Check the values of the formula cells in A6:A7.
+ CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(0,5,0)));
+ CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(0,6,0)));
+
+ // Insert cells over B1:B2 to partially shift value range.
+ m_pDoc->InsertRow(ScRange(1,0,0,1,1,0));
+
+ // Check the values of the formula cells in A6:A7 again.
+ CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc->GetValue(ScAddress(0,5,0)));
+ CPPUNIT_ASSERT_EQUAL(7.0, m_pDoc->GetValue(ScAddress(0,6,0)));
+
+ // ... and shift them back.
+ m_pDoc->DeleteRow(ScRange(1,0,0,1,1,0));
+
+ // The formula cell results should be back too.
+ CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(0,5,0)));
+ CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(0,6,0)));
+
m_pDoc->DeleteTab(0);
}
More information about the Libreoffice-commits
mailing list