[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