[Libreoffice-commits] core.git: Branch 'feature/formula-core-rework' - sc/inc sc/qa sc/source

Kohei Yoshida kohei.yoshida at gmail.com
Mon Jul 29 11:47:03 PDT 2013


 sc/inc/rangenam.hxx              |   15 +++---
 sc/inc/tokenarray.hxx            |   12 +++++
 sc/qa/unit/ucalc.hxx             |    2 
 sc/qa/unit/ucalc_formula.cxx     |   56 +++++++++++++++++++++++++
 sc/source/core/data/documen3.cxx |    2 
 sc/source/core/data/table1.cxx   |    2 
 sc/source/core/tool/rangenam.cxx |   39 ++++-------------
 sc/source/core/tool/token.cxx    |   85 +++++++++++++++++++++++++++++++++++++--
 8 files changed, 171 insertions(+), 42 deletions(-)

New commits:
commit f908a4ad8e7399cc4fd47c6403dbfa8336f0098b
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Mon Jul 29 14:47:07 2013 -0400

    First cut on re-working reference update in named expressions.
    
    It's not perfect yet.
    
    Change-Id: Iebe7a88e419365b053765685bb769427f569070d

diff --git a/sc/inc/rangenam.hxx b/sc/inc/rangenam.hxx
index 4a5944f..e3b507e 100644
--- a/sc/inc/rangenam.hxx
+++ b/sc/inc/rangenam.hxx
@@ -33,6 +33,10 @@
 class ScDocument;
 class ScTokenArray;
 
+namespace sc {
+    struct RefUpdateContext;
+}
+
 typedef sal_uInt16 RangeType;
 
 #define RT_NAME             ((RangeType)0x0000)
@@ -65,7 +69,7 @@ private:
     SCROW           mnMaxRow;
     SCCOL           mnMaxCol;
 
-    void CompileRangeData( const String& rSymbol, bool bSetError );
+    void CompileRangeData( const OUString& rSymbol, bool bSetError );
     void InitCode();
 public:
 
@@ -75,7 +79,7 @@ public:
 
     SC_DLLPUBLIC                ScRangeData( ScDocument* pDoc,
                                  const OUString& rName,
-                                 const String& rSymbol,
+                                 const OUString& rSymbol,
                                  const ScAddress& rAdr = ScAddress(),
                                  RangeType nType = RT_NAME,
                                  const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_DEFAULT );
@@ -118,9 +122,7 @@ public:
     SC_DLLPUBLIC void GetSymbol( OUString& rSymbol, const ScAddress& rPos, const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_DEFAULT ) const;
     void            UpdateSymbol( OUStringBuffer& rBuffer, const ScAddress&,
                                     const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_DEFAULT );
-    void            UpdateReference( UpdateRefMode eUpdateRefMode,
-                             const ScRange& r,
-                             SCsCOL nDx, SCsROW nDy, SCsTAB nDz, bool bLocal = false );
+    void UpdateReference( const sc::RefUpdateContext& rCxt, bool bLocal = false );
     bool            IsModified() const              { return bModified; }
 
     SC_DLLPUBLIC void           GuessPosition();
@@ -181,8 +183,7 @@ public:
     SC_DLLPUBLIC ScRangeData* findByUpperName(const OUString& rName);
     SC_DLLPUBLIC const ScRangeData* findByUpperName(const OUString& rName) const;
     SC_DLLPUBLIC ScRangeData* findByIndex(sal_uInt16 i) const;
-    void UpdateReference(UpdateRefMode eUpdateRefMode, const ScRange& rRange,
-                         SCsCOL nDx, SCsROW nDy, SCsTAB nDz, bool bLocal = false);
+    void UpdateReference(const sc::RefUpdateContext& rCxt, bool bLocal = false);
     void UpdateTabRef(SCTAB nTable, ScRangeData::TabRefUpdateMode eMode, SCTAB nNewTable = 0, SCTAB nNewSheets = 1);
     void UpdateTranspose(const ScRange& rSource, const ScAddress& rDest);
     void UpdateGrow(const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY);
diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx
index b3fb5ef..71d8c7a 100644
--- a/sc/inc/tokenarray.hxx
+++ b/sc/inc/tokenarray.hxx
@@ -133,6 +133,18 @@ public:
         const sc::RefUpdateContext& rCxt, const ScAddress& rOldPos, const ScAddress& rNewPos );
 
     /**
+     * Adjust all references in named expression. In named expression, we only
+     * update absolute positions, and leave relative positions intact.
+     *
+     * Also, there is no such thing as the base position in named expressions.
+     *
+     * @param rCxt context that stores details of shifted region
+     *
+     * @return update result.
+     */
+    sc::RefUpdateResult AdjustReferenceInName( const sc::RefUpdateContext& rCxt );
+
+    /**
      * Adjust all references on sheet deletion.
      *
      * @param nDelPos position of sheet being deleted.
diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index 5a1d0ae..2413317 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -90,6 +90,7 @@ public:
     void testFormulaRefUpdateRange();
     void testFormulaRefUpdateSheets();
     void testFormulaRefUpdateMove();
+    void testFormulaRefUpdateNamedExpression();
     void testFuncCOLUMN();
     void testFuncROW();
     void testFuncSUM();
@@ -282,6 +283,7 @@ public:
     CPPUNIT_TEST(testFormulaRefUpdateRange);
     CPPUNIT_TEST(testFormulaRefUpdateSheets);
     CPPUNIT_TEST(testFormulaRefUpdateMove);
+    CPPUNIT_TEST(testFormulaRefUpdateNamedExpression);
     CPPUNIT_TEST(testFuncCOLUMN);
     CPPUNIT_TEST(testFuncROW);
     CPPUNIT_TEST(testFuncSUM);
diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx
index def3902..68c0f07 100644
--- a/sc/qa/unit/ucalc_formula.cxx
+++ b/sc/qa/unit/ucalc_formula.cxx
@@ -964,6 +964,62 @@ void Test::testFormulaRefUpdateMove()
     m_pDoc->DeleteTab(0);
 }
 
+void Test::testFormulaRefUpdateNamedExpression()
+{
+    m_pDoc->InsertTab(0, "Formula");
+
+    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
+
+    // Fill C2:C5 with values.
+    m_pDoc->SetValue(ScAddress(2,1,0), 1);
+    m_pDoc->SetValue(ScAddress(2,2,0), 2);
+    m_pDoc->SetValue(ScAddress(2,3,0), 3);
+    m_pDoc->SetValue(ScAddress(2,4,0), 4);
+
+    // Add a named expression that references the immediate left cell.
+    ScRangeName* pGlobalNames = m_pDoc->GetRangeName();
+    CPPUNIT_ASSERT_MESSAGE("Failed to obtain global named expression object.", pGlobalNames);
+    ScRangeData* pName = new ScRangeData(
+        m_pDoc, "ToLeft", "RC[-1]", ScAddress(2,1,0), RT_NAME, formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1);
+
+    bool bInserted = pGlobalNames->insert(pName);
+    CPPUNIT_ASSERT_MESSAGE("Failed to insert a new name.", bInserted);
+
+    // Insert formulas in D2:D5 using the named expression.
+    m_pDoc->SetString(ScAddress(3,1,0), "=ToLeft");
+    m_pDoc->SetString(ScAddress(3,2,0), "=ToLeft");
+    m_pDoc->SetString(ScAddress(3,3,0), "=ToLeft");
+    m_pDoc->SetString(ScAddress(3,4,0), "=ToLeft");
+
+    // Make sure the results are correct.
+    CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(3,1,0));
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(3,2,0));
+    CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(3,3,0));
+    CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(3,4,0));
+
+    // Push cells in column C down by one cell.
+    m_pDoc->InsertRow(ScRange(2,0,0,2,0,0));
+
+    // Make sure the results change accordingly.
+    CPPUNIT_ASSERT_EQUAL(0.0, m_pDoc->GetValue(3,1,0));
+    CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(3,2,0));
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(3,3,0));
+    CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(3,4,0));
+
+    // Move cells back.
+    m_pDoc->DeleteRow(ScRange(2,0,0,2,0,0));
+
+    // Make sure the results are back as well.
+    CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(3,1,0));
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(3,2,0));
+    CPPUNIT_ASSERT_EQUAL(3.0, m_pDoc->GetValue(3,3,0));
+    CPPUNIT_ASSERT_EQUAL(4.0, m_pDoc->GetValue(3,4,0));
+
+
+
+    m_pDoc->DeleteTab(0);
+}
+
 void Test::testFuncCOLUMN()
 {
     m_pDoc->InsertTab(0, "Formula");
diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx
index 04973f4..c9254bc 100644
--- a/sc/source/core/data/documen3.cxx
+++ b/sc/source/core/data/documen3.cxx
@@ -1006,7 +1006,7 @@ void ScDocument::UpdateReference(
         xRowNameRanges->UpdateReference( eUpdateRefMode, this, aRange, nDx, nDy, nDz );
         pDBCollection->UpdateReference( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz );
         if (pRangeName)
-            pRangeName->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz );
+            pRangeName->UpdateReference(rCxt, false);
         if ( pDPCollection )
             pDPCollection->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz );
         UpdateChartRef( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz );
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index f4bb6b9..86e8d1b 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -1475,7 +1475,7 @@ void ScTable::UpdateReference(
 
     // Named expressions need to be updated before formulas acessing them.
     if (mpRangeName)
-        mpRangeName->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz, true );
+        mpRangeName->UpdateReference(rCxt, true);
 
     for ( ; i<=iMax; i++)
         bUpdated |= aCol[i].UpdateReference(rCxt, pUndoDoc);
diff --git a/sc/source/core/tool/rangenam.cxx b/sc/source/core/tool/rangenam.cxx
index e838b49..0f99769 100644
--- a/sc/source/core/tool/rangenam.cxx
+++ b/sc/source/core/tool/rangenam.cxx
@@ -33,6 +33,7 @@
 #include "rechead.hxx"
 #include "refupdat.hxx"
 #include "document.hxx"
+#include "refupdatecontext.hxx"
 
 #include "formula/errorcodes.hxx"
 
@@ -46,7 +47,7 @@ using ::std::unary_function;
 
 ScRangeData::ScRangeData( ScDocument* pDok,
                           const OUString& rName,
-                          const String& rSymbol,
+                          const OUString& rSymbol,
                           const ScAddress& rAddress,
                           RangeType nType,
                           const FormulaGrammar::Grammar eGrammar ) :
@@ -62,7 +63,7 @@ ScRangeData::ScRangeData( ScDocument* pDok,
                 mnMaxRow    (-1),
                 mnMaxCol    (-1)
 {
-    if (rSymbol.Len() > 0)
+    if (!rSymbol.isEmpty())
         CompileRangeData( rSymbol, pDoc->IsImportingXML());
         // Let the compiler set an error on unknown names for a subsequent
         // CompileUnresolvedXML().
@@ -141,7 +142,7 @@ ScRangeData::~ScRangeData()
     delete pCode;
 }
 
-void ScRangeData::CompileRangeData( const String& rSymbol, bool bSetError )
+void ScRangeData::CompileRangeData( const OUString& rSymbol, bool bSetError )
 {
     if (eTempGrammar == FormulaGrammar::GRAM_UNSPECIFIED)
     {
@@ -270,34 +271,13 @@ void ScRangeData::UpdateSymbol( OUStringBuffer& rBuffer, const ScAddress& rPos,
     aComp.CreateStringFromTokenArray( rBuffer );
 }
 
-void ScRangeData::UpdateReference(  UpdateRefMode eUpdateRefMode,
-                                    const ScRange& r,
-                                    SCsCOL nDx, SCsROW nDy, SCsTAB nDz, bool bLocal )
+void ScRangeData::UpdateReference( const sc::RefUpdateContext& rCxt, bool /*bLocal*/ )
 {
     bool bChanged = false;
-
-    pCode->Reset();
-    if( pCode->GetNextReference() )
-    {
-        bool bSharedFormula = ((eType & RT_SHARED) == RT_SHARED);
-        ScCompiler aComp( pDoc, aPos, *pCode );
-        aComp.SetGrammar(pDoc->GetGrammar());
-        const bool bRelRef = aComp.UpdateNameReference( eUpdateRefMode, r,
-                                                    nDx, nDy, nDz,
-                                                    bChanged, bSharedFormula, bLocal);
-        if (bSharedFormula)
-        {
-            if (bRelRef)
-                eType = eType | RT_SHAREDMOD;
-            else
-                eType = eType & ~RT_SHAREDMOD;
-        }
-    }
-
-    bModified = bChanged;
+    sc::RefUpdateResult aRes = pCode->AdjustReferenceInName(rCxt);
+    bModified = aRes.mbReferenceModified;
 }
 
-
 void ScRangeData::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest )
 {
     bool bChanged = false;
@@ -733,12 +713,11 @@ ScRangeData* ScRangeName::findByIndex(sal_uInt16 i) const
     return nPos < maIndexToData.size() ? maIndexToData[nPos] : NULL;
 }
 
-void ScRangeName::UpdateReference(
-    UpdateRefMode eUpdateRefMode, const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz, bool bLocal)
+void ScRangeName::UpdateReference(const sc::RefUpdateContext& rCxt, bool bLocal)
 {
     DataType::iterator itr = maData.begin(), itrEnd = maData.end();
     for (; itr != itrEnd; ++itr)
-        itr->second->UpdateReference(eUpdateRefMode, rRange, nDx, nDy, nDz, bLocal);
+        itr->second->UpdateReference(rCxt, bLocal);
 }
 
 void ScRangeName::UpdateTabRef(SCTAB nTable, ScRangeData::TabRefUpdateMode eMode, SCTAB nNewTable, SCTAB nNewSheets)
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index df54e8f..c524692 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -2156,7 +2156,6 @@ void ScTokenArray::AdjustAbsoluteRefs( const ScDocument* pOldDoc, const ScAddres
                     AdjustSingleRefData( rRef1, rOldPos, rNewPos );
                 if (!bRangeName || !(rRef2.IsColRel() || rRef2.IsRowRel() || rRef2.IsTabRel()))
                     AdjustSingleRefData( rRef2, rOldPos, rNewPos );
-
             }
             break;
             case svSingleRef :
@@ -2169,8 +2168,6 @@ void ScTokenArray::AdjustAbsoluteRefs( const ScDocument* pOldDoc, const ScAddres
                 // for range names only adjust if all parts are absolute
                 if (!bRangeName || !(rRef.IsColRel() || rRef.IsRowRel() || rRef.IsTabRel()))
                     AdjustSingleRefData( rRef, rOldPos, rNewPos );
-
-
             }
             break;
             default:
@@ -2536,6 +2533,88 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnMove(
 
 namespace {
 
+bool adjustSingleRefInName( ScSingleRefData& rRef, const sc::RefUpdateContext& rCxt )
+{
+    if (rRef.IsTabRel())
+        // Ignore reference with relative sheet position for now.
+        return false;
+
+    if (rRef.Tab() < rCxt.maRange.aStart.Tab() || rCxt.maRange.aEnd.Tab() < rRef.Tab())
+        // References sheet that has not shifted. Don't change it.
+        return false;
+
+    bool bChanged = false;
+
+    if (!rRef.IsColRel() && rCxt.mnColDelta)
+    {
+        // Adjust absolute column reference.
+        if (rCxt.maRange.aStart.Col() <= rRef.Col() && rRef.Col() <= rCxt.maRange.aEnd.Col())
+        {
+            rRef.IncCol(rCxt.mnColDelta);
+            bChanged = true;
+        }
+    }
+
+    if (!rRef.IsRowRel() && rCxt.mnRowDelta)
+    {
+        // Adjust absolute row reference.
+        if (rCxt.maRange.aStart.Row() <= rRef.Row() && rRef.Row() <= rCxt.maRange.aEnd.Row())
+        {
+            rRef.IncRow(rCxt.mnRowDelta);
+            bChanged = true;
+        }
+    }
+
+    if (!rRef.IsTabRel() && rCxt.mnTabDelta)
+    {
+        // Sheet range has already been checked above.
+        rRef.IncTab(rCxt.mnTabDelta);
+        bChanged = true;
+    }
+
+    return bChanged;
+}
+
+}
+
+sc::RefUpdateResult ScTokenArray::AdjustReferenceInName( const sc::RefUpdateContext& rCxt )
+{
+    sc::RefUpdateResult aRes;
+
+    FormulaToken** p = pCode;
+    FormulaToken** pEnd = p + static_cast<size_t>(nLen);
+    for (; p != pEnd; ++p)
+    {
+        switch ((*p)->GetType())
+        {
+            case svSingleRef:
+            {
+                ScToken* pToken = static_cast<ScToken*>(*p);
+                ScSingleRefData& rRef = pToken->GetSingleRef();
+                if (adjustSingleRefInName(rRef, rCxt))
+                    aRes.mbReferenceModified = true;
+            }
+            break;
+            case svDoubleRef:
+            {
+                ScToken* pToken = static_cast<ScToken*>(*p);
+                ScComplexRefData& rRef = pToken->GetDoubleRef();
+                if (adjustSingleRefInName(rRef.Ref1, rCxt))
+                    aRes.mbReferenceModified = true;
+                if (adjustSingleRefInName(rRef.Ref2, rCxt))
+                    aRes.mbReferenceModified = true;
+            }
+            break;
+            default:
+                ;
+        }
+    }
+
+    return aRes;
+}
+
+namespace {
+
 bool adjustSingleRefOnDeletedTab( ScSingleRefData& rRef, SCTAB nDelPos, SCTAB nSheets, const ScAddress& rOldPos, const ScAddress& rNewPos )
 {
     ScAddress aAbs = rRef.toAbs(rOldPos);


More information about the Libreoffice-commits mailing list