[Libreoffice-commits] core.git: 2 commits - sc/inc sc/qa sc/source

Kohei Yoshida kohei.yoshida at collabora.com
Fri Feb 28 18:30:51 PST 2014


 sc/inc/formulacell.hxx              |   22 ++++---
 sc/qa/unit/ucalc.hxx                |    2 
 sc/qa/unit/ucalc_sharedformula.cxx  |   90 +++++++++++++++++++++++++++++
 sc/source/core/data/column.cxx      |  109 ++++++++++++++++++++++++++++++------
 sc/source/core/data/formulacell.cxx |    6 +
 sc/source/core/tool/compiler.cxx    |    4 -
 sc/source/core/tool/token.cxx       |   31 ++++++++++
 7 files changed, 236 insertions(+), 28 deletions(-)

New commits:
commit f32df2d590d0ee14f09664934457ba9e8de8cbe6
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Feb 28 21:25:01 2014 -0500

    fdo#75053: Adjust reference update on shift for formula groups.
    
    This is similar to my earlier fix for reference update on moving of
    cells.
    
    Change-Id: I592599507bfcab12f611eeae7b56c99da6c31919

diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index 42e00a9..f75895b 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -132,14 +132,6 @@ private:
                     };
     void            InterpretTail( ScInterpretTailParameter );
 
-    bool UpdatePosOnShift( const sc::RefUpdateContext& rCxt );
-
-    /**
-     * Update reference in response to cell insertion or deletion.
-     */
-    bool UpdateReferenceOnShift(
-        const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, const ScAddress* pUndoCellPos );
-
     /**
      * Update reference in response to cell copy-n-paste.
      */
@@ -213,6 +205,7 @@ public:
     void ResetDirty();
     bool NeedsListening() const;
     void SetNeedsListening( bool bVar );
+    void SetNeedsDirty( bool bVar );
     void SetNeedNumberFormat( bool bVal );
     short GetFormatType() const;
     void            Compile(const OUString& rFormula,
@@ -246,6 +239,19 @@ public:
         const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc = NULL, const ScAddress* pUndoCellPos = NULL );
 
     /**
+     * Shift the position of formula cell as part of reference update.
+     *
+     * @return true if the position has shifted, false otherwise.
+     */
+    bool UpdatePosOnShift( const sc::RefUpdateContext& rCxt );
+
+    /**
+     * Update reference in response to cell insertion or deletion.
+     */
+    bool UpdateReferenceOnShift(
+        const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, const ScAddress* pUndoCellPos );
+
+    /**
      * Update reference in response to cell move.
      */
     bool UpdateReferenceOnMove(
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 4b8d38c..b7fd479 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -2428,6 +2428,68 @@ class UpdateRefOnNonCopy : std::unary_function<FormulaGroup, void>
     ScDocument* mpUndoDoc;
     bool mbUpdated;
 
+    void updateRefOnShift( FormulaGroup& rGroup )
+    {
+        if (!rGroup.mbShared)
+        {
+            ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab);
+            mbUpdated |= rGroup.mpCell->UpdateReferenceOnShift(*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 aOldPos = pTop->aPos;
+
+        // Run this before the position gets updated.
+        sc::RefUpdateResult aRes = pCode->AdjustReferenceOnShift(*mpCxt, aOldPos);
+
+        if (pTop->UpdatePosOnShift(*mpCxt))
+        {
+            // Update the positions of all formula cells.
+            for (++pp; pp != ppEnd; ++pp) // skip the top cell.
+            {
+                ScFormulaCell* pFC = *pp;
+                pFC->aPos.Move(mpCxt->mnColDelta, mpCxt->mnRowDelta, mpCxt->mnTabDelta);
+            }
+
+            if (pCode->IsRecalcModeOnRefMove())
+                aRes.mbValueChanged = true;
+        }
+
+        if (aRes.mbReferenceModified)
+        {
+            sc::StartListeningContext aStartCxt(mpCxt->mrDoc);
+            sc::EndListeningContext aEndCxt(mpCxt->mrDoc, pOldCode.get());
+            aEndCxt.setPositionDelta(
+                ScAddress(-mpCxt->mnColDelta, -mpCxt->mnRowDelta, -mpCxt->mnTabDelta));
+
+            for (pp = rGroup.mpCells; pp != ppEnd; ++pp)
+            {
+                ScFormulaCell* p = *pp;
+                p->EndListeningTo(aEndCxt);
+                p->SetNeedsListening(true);
+            }
+
+            mbUpdated = true;
+
+            fillUndoDoc(aOldPos, rGroup.mnLength, *pOldCode);
+        }
+
+        if (aRes.mbValueChanged)
+        {
+            for (pp = rGroup.mpCells; pp != ppEnd; ++pp)
+            {
+                ScFormulaCell* p = *pp;
+                p->SetNeedsDirty(true);
+            }
+        }
+    }
+
     void updateRefOnMove( FormulaGroup& rGroup )
     {
         if (!rGroup.mbShared)
@@ -2484,21 +2546,26 @@ class UpdateRefOnNonCopy : std::unary_function<FormulaGroup, void>
                 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);
-                }
-            }
+            fillUndoDoc(aOldPos, rGroup.mnLength, *pOldCode);
+        }
+    }
+
+    void fillUndoDoc( const ScAddress& rOldPos, SCROW nLength, const ScTokenArray& rOldCode )
+    {
+        if (!mpUndoDoc)
+            return;
+
+        // Insert the old formula group into the undo document.
+        ScAddress aUndoPos = rOldPos;
+        ScFormulaCell* pFC = new ScFormulaCell(mpUndoDoc, aUndoPos, rOldCode.Clone());
+        ScFormulaCellGroupRef xGroup = pFC->CreateCellGroup(nLength, false);
+
+        mpUndoDoc->SetFormulaCell(aUndoPos, pFC);
+        aUndoPos.IncRow();
+        for (SCROW i = 1; i < nLength; ++i, aUndoPos.IncRow())
+        {
+            pFC = new ScFormulaCell(mpUndoDoc, aUndoPos, xGroup);
+            mpUndoDoc->SetFormulaCell(aUndoPos, pFC);
         }
     }
 
@@ -2511,10 +2578,16 @@ public:
 
     void operator() ( FormulaGroup& rGroup )
     {
-        if (mpCxt->meMode == URM_MOVE)
+        switch (mpCxt->meMode)
         {
-            updateRefOnMove(rGroup);
-            return;
+            case URM_INSDEL:
+                updateRefOnShift(rGroup);
+                return;
+            case URM_MOVE:
+                updateRefOnMove(rGroup);
+                return;
+            default:
+                ;
         }
 
         if (rGroup.mbShared)
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index a872e91..d0ebd2f 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -957,6 +957,12 @@ bool ScFormulaCell::GetDirty() const { return bDirty; }
 void ScFormulaCell::ResetDirty() { bDirty = bTableOpDirty = mbPostponedDirty = false; }
 bool ScFormulaCell::NeedsListening() const { return bNeedListening; }
 void ScFormulaCell::SetNeedsListening( bool bVar ) { bNeedListening = bVar; }
+
+void ScFormulaCell::SetNeedsDirty( bool bVar )
+{
+    mbPostponedDirty = bVar;
+}
+
 void ScFormulaCell::SetNeedNumberFormat( bool bVal ) { mbNeedsNumberFormat = bVal; }
 short ScFormulaCell::GetFormatType() const { return nFormatType; }
 
diff --git a/sc/source/core/tool/compiler.cxx b/sc/source/core/tool/compiler.cxx
index afb8f5f..68f2ba5 100644
--- a/sc/source/core/tool/compiler.cxx
+++ b/sc/source/core/tool/compiler.cxx
@@ -769,13 +769,13 @@ struct ConventionOOO_A1 : public Convention_A1
             rBuffer.append('.');
         if (!rRef.IsColRel())
             rBuffer.append('$');
-        if (!ValidCol(rAbsRef.Col()))
+        if (!ValidCol(rAbsRef.Col()) || rRef.IsColDeleted())
             rBuffer.append(rErrRef);
         else
             MakeColStr(rBuffer, rAbsRef.Col());
         if (!rRef.IsRowRel())
             rBuffer.append('$');
-        if (!ValidRow(rAbsRef.Row()))
+        if (!ValidRow(rAbsRef.Row()) || rRef.IsRowDeleted())
             rBuffer.append(rErrRef);
         else
             MakeRowStr(rBuffer, rAbsRef.Row());
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index 7052049..c7c8e42 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -2480,6 +2480,25 @@ void setRefDeleted( ScSingleRefData& rRef, const sc::RefUpdateContext& rCxt )
         rRef.SetTabDeleted(true);
 }
 
+void restoreDeletedRef( ScSingleRefData& rRef, const sc::RefUpdateContext& rCxt )
+{
+    if (rCxt.mnColDelta)
+    {
+        if (rRef.IsColDeleted())
+            rRef.SetColDeleted(false);
+    }
+    else if (rCxt.mnRowDelta)
+    {
+        if (rRef.IsRowDeleted())
+            rRef.SetRowDeleted(false);
+    }
+    else if (rCxt.mnTabDelta)
+    {
+        if (rRef.IsTabDeleted())
+            rRef.SetTabDeleted(false);
+    }
+}
+
 void setRefDeleted( ScComplexRefData& rRef, const sc::RefUpdateContext& rCxt )
 {
     if (rCxt.mnColDelta < 0)
@@ -2647,6 +2666,18 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnShift( const sc::RefUpdateCon
                     break;
                 }
 
+                if (!rCxt.isDeleted() && rRef.IsDeleted())
+                {
+                    // Check if the token has reference to previously deleted region.
+                    ScAddress aCheckPos = rRef.toAbs(aNewPos);
+                    if (rCxt.maRange.In(aCheckPos))
+                    {
+                        restoreDeletedRef(rRef, rCxt);
+                        aRes.mbValueChanged = true;
+                        break;
+                    }
+                }
+
                 if (rCxt.maRange.In(aAbs))
                 {
                     aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
commit aa6c5b7faecdb57cbdeac051e304531c1a1cf63b
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Feb 28 09:58:05 2014 -0500

    fdo#75053: Write test for this.
    
    Change-Id: I51c552c23af5d1669e35817e4f54f75be6b54180

diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index 4f8810a..f51556f 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -267,6 +267,7 @@ public:
     void testSharedFormulasRefUpdate();
     void testSharedFormulasRefUpdateRange();
     void testSharedFormulasDeleteRows();
+    void testSharedFormulasDeleteColumns();
     void testSharedFormulasRefUpdateMoveSheets();
     void testSharedFormulasRefUpdateCopySheets();
     void testSharedFormulasCopyPaste();
@@ -439,6 +440,7 @@ public:
     CPPUNIT_TEST(testSharedFormulasRefUpdate);
     CPPUNIT_TEST(testSharedFormulasRefUpdateRange);
     CPPUNIT_TEST(testSharedFormulasDeleteRows);
+    CPPUNIT_TEST(testSharedFormulasDeleteColumns);
     CPPUNIT_TEST(testSharedFormulasRefUpdateMoveSheets);
     CPPUNIT_TEST(testSharedFormulasRefUpdateCopySheets);
     CPPUNIT_TEST(testSharedFormulasCopyPaste);
diff --git a/sc/qa/unit/ucalc_sharedformula.cxx b/sc/qa/unit/ucalc_sharedformula.cxx
index d8974ae..677b0e2 100644
--- a/sc/qa/unit/ucalc_sharedformula.cxx
+++ b/sc/qa/unit/ucalc_sharedformula.cxx
@@ -16,6 +16,8 @@
 #include "undoblk.hxx"
 #include "scopetools.hxx"
 #include <docfunc.hxx>
+#include <tokenarray.hxx>
+#include <tokenstringcontext.hxx>
 #include "svl/sharedstring.hxx"
 
 #include "formula/grammar.hxx"
@@ -519,6 +521,94 @@ void Test::testSharedFormulasDeleteRows()
     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(8), pFC->GetSharedLength());
 }
 
+void Test::testSharedFormulasDeleteColumns()
+{
+    using namespace formula;
+
+    m_pDoc->InsertTab(0, "Test");
+
+    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
+    FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
+
+    ScDocFunc& rFunc = getDocShell().GetDocFunc();
+    ScMarkData aMark;
+    aMark.SelectOneTable(0);
+
+    // First, test a single cell case.  A value in B1 and formula in C1.
+    m_pDoc->SetValue(ScAddress(1,0,0), 11.0);
+    m_pDoc->SetString(ScAddress(2,0,0), "=RC[-1]");
+    CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc->GetValue(ScAddress(2,0,0)));
+
+    // Delete column B.
+    rFunc.DeleteCells(ScRange(1,0,0,1,MAXROW,0), &aMark, DEL_CELLSLEFT, true, true);
+    CPPUNIT_ASSERT_EQUAL(OUString("#REF!"), m_pDoc->GetString(ScAddress(1,0,0)));
+
+    // The reference should still point to row 1 but the column status should be set to 'deleted'.
+    const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
+    CPPUNIT_ASSERT(pFC);
+    const ScTokenArray* pCode = pFC->GetCode();
+    CPPUNIT_ASSERT(pCode && pCode->GetLen() == 1);
+    const FormulaToken* pToken = pCode->GetArray()[0];
+    CPPUNIT_ASSERT(pToken->GetType() == svSingleRef);
+    const ScSingleRefData* pSRef = &static_cast<const ScToken*>(pToken)->GetSingleRef();
+    CPPUNIT_ASSERT(pSRef->IsColDeleted());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pSRef->toAbs(ScAddress(1,0,0)).Row());
+
+    // The formula string should show #REF! in lieu of the column position (only for Calc A1 syntax).
+    sc::CompileFormulaContext aCFCxt(m_pDoc, FormulaGrammar::GRAM_ENGLISH);
+    CPPUNIT_ASSERT_EQUAL(OUString("=#REF!1"), pFC->GetFormula(aCFCxt));
+
+    SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
+    CPPUNIT_ASSERT(pUndoMgr);
+
+    // Undo and make sure the deleted flag is gone.
+    pUndoMgr->Undo();
+    CPPUNIT_ASSERT_EQUAL(11.0, m_pDoc->GetValue(ScAddress(2,0,0)));
+    pFC = m_pDoc->GetFormulaCell(ScAddress(2,0,0));
+    CPPUNIT_ASSERT_EQUAL(OUString("=B1"), pFC->GetFormula(aCFCxt));
+
+    // Clear row 1 and move over to a formula group case.
+    clearRange(m_pDoc, ScRange(0,0,0,MAXCOL,0,0));
+
+    // Fill A1:B2 with numbers, and C1:C2 with formula that reference those numbers.
+    for (SCROW i = 0; i <= 1; ++i)
+    {
+        m_pDoc->SetValue(ScAddress(0,i,0), (i+1));
+        m_pDoc->SetValue(ScAddress(1,i,0), (i+11));
+        m_pDoc->SetString(ScAddress(2,i,0), "=RC[-2]+RC[-1]");
+        double fCheck = m_pDoc->GetValue(ScAddress(0,i,0));
+        fCheck += m_pDoc->GetValue(ScAddress(1,i,0));
+        CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(2,i,0)));
+    }
+
+    // Delete column B.
+    rFunc.DeleteCells(ScRange(1,0,0,1,MAXROW,0), &aMark, DEL_CELLSLEFT, true, true);
+
+    for (SCROW i = 0; i <= 1; ++i)
+    {
+        ScAddress aPos(1,i,0);
+        CPPUNIT_ASSERT_EQUAL(OUString("#REF!"), m_pDoc->GetString(aPos));
+    }
+
+    pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0)); // B1
+    CPPUNIT_ASSERT(pFC);
+    CPPUNIT_ASSERT_EQUAL(OUString("=A1+#REF!1"), pFC->GetFormula(aCFCxt));
+    pFC = m_pDoc->GetFormulaCell(ScAddress(1,1,0)); // B2
+    CPPUNIT_ASSERT(pFC);
+    CPPUNIT_ASSERT_EQUAL(OUString("=A2+#REF!2"), pFC->GetFormula(aCFCxt));
+
+    // Undo deletion of column B and check the results of C1:C2.
+    pUndoMgr->Undo();
+    for (SCROW i = 0; i <= 1; ++i)
+    {
+        double fCheck = m_pDoc->GetValue(ScAddress(0,i,0));
+        fCheck += m_pDoc->GetValue(ScAddress(1,i,0));
+        CPPUNIT_ASSERT_EQUAL(fCheck, m_pDoc->GetValue(ScAddress(2,i,0)));
+    }
+
+    m_pDoc->DeleteTab(0);
+}
+
 void Test::testSharedFormulasRefUpdateMoveSheets()
 {
     m_pDoc->InsertTab(0, "Sheet1");


More information about the Libreoffice-commits mailing list