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

Kohei Yoshida kohei.yoshida at gmail.com
Sat Aug 10 21:05:24 PDT 2013


 sc/inc/formulacell.hxx                |    1 
 sc/inc/sharedformula.hxx              |    4 +
 sc/inc/tokenarray.hxx                 |    3 +
 sc/source/core/data/column.cxx        |   63 +++++++++++++++++++++++---
 sc/source/core/data/formulacell.cxx   |    8 +++
 sc/source/core/tool/sharedformula.cxx |    5 ++
 sc/source/core/tool/token.cxx         |   82 ++++++++++++++++++++++++++++++++++
 7 files changed, 160 insertions(+), 6 deletions(-)

New commits:
commit beb1881c4b82680a63add95dcf6697b38b978c12
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Sat Aug 10 23:31:38 2013 -0400

    Collect all boundaries at which to split the formula group.
    
    Change-Id: Ic78d7a06991b983e625b161f11fbbabce02334f3

diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index 0d258a0..3318dd2 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -336,6 +336,7 @@ public:
 
     bool IsShared() const;
     bool IsSharedInvariant() const;
+    bool IsSharedTop() const;
     SCROW GetSharedTopRow() const;
     SCROW GetSharedLength() const;
     ScTokenArray* GetSharedCode();
diff --git a/sc/inc/sharedformula.hxx b/sc/inc/sharedformula.hxx
index 232c4bc..9423384 100644
--- a/sc/inc/sharedformula.hxx
+++ b/sc/inc/sharedformula.hxx
@@ -13,6 +13,8 @@
 #include "formulacell.hxx"
 #include "mtvelements.hxx"
 
+#include <vector>
+
 namespace sc {
 
 class SharedFormulaUtil
@@ -61,6 +63,8 @@ public:
      */
     static void splitFormulaCellGroup(const CellStoreType::position_type& aPos);
 
+    static void splitFormulaCellGroups(CellStoreType& rCells, const std::vector<SCROW>& rBounds);
+
     /**
      * See if two specified adjacent formula cells can be merged, and if they
      * can, merge them into the same group.
diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx
index 09a9798..00f192d 100644
--- a/sc/inc/tokenarray.hxx
+++ b/sc/inc/tokenarray.hxx
@@ -166,6 +166,9 @@ public:
 
     sc::RefUpdateResult AdjustReferenceOnMovedTab( sc::RefUpdateMoveTabContext& rCxt, const ScAddress& rOldPos );
 
+    void CheckRelativeReferenceBounds(
+        const sc::RefUpdateContext& rCxt, const ScAddress& rPos, SCROW nGroupLen, std::vector<SCROW>& rBounds ) const;
+
 #if DEBUG_FORMULA_COMPILER
     void Dump() const;
 #endif
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 0171fab..a395c78 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -2295,6 +2295,46 @@ public:
     bool isUpdated() const { return mbUpdated; }
 };
 
+class UpdateRefGroupBoundChecker : std::unary_function<sc::CellStoreType::value_type, void>
+{
+    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)
+    {
+        if (node.type != sc::element_type_formula)
+            return;
+
+        sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
+        sc::formula_block::const_iterator itEnd = sc::formula_block::end(*node.data);
+
+        // 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;
+
+            if (rCell.IsSharedTop())
+            {
+                // Check its tokens and record its reference boundaries.
+                const ScTokenArray& rCode = *rCell.GetCode();
+                rCode.CheckRelativeReferenceBounds(
+                    mrCxt, rCell.aPos, rCell.GetSharedLength(), mrBounds);
+
+                // 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);
+            }
+        }
+    }
+};
+
 }
 
 bool ScColumn::UpdateReferenceOnCopy( const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc )
@@ -2324,6 +2364,8 @@ bool ScColumn::UpdateReference( const sc::RefUpdateContext& rCxt, ScDocument* pU
     if (rCxt.meMode == URM_COPY)
         return UpdateReferenceOnCopy(rCxt, pUndoDoc);
 
+    std::vector<SCROW> aBounds;
+
     bool bThisColShifted = (rCxt.maRange.aStart.Tab() <= nTab && nTab <= rCxt.maRange.aEnd.Tab() &&
                             rCxt.maRange.aStart.Col() <= nCol && nCol <= rCxt.maRange.aEnd.Col());
     if (bThisColShifted)
@@ -2333,17 +2375,26 @@ bool ScColumn::UpdateReference( const sc::RefUpdateContext& rCxt, ScDocument* pU
         SCROW nSplitPos = rCxt.maRange.aStart.Row();
         if (ValidRow(nSplitPos))
         {
-            sc::CellStoreType::position_type aPos = maCells.position(nSplitPos);
-            sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
+            aBounds.push_back(nSplitPos);
             nSplitPos = rCxt.maRange.aEnd.Row() + 1;
             if (ValidRow(nSplitPos))
-            {
-                aPos = maCells.position(aPos.first, nSplitPos);
-                sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
-            }
+                aBounds.push_back(nSplitPos);
         }
     }
 
+    // Check the row positions at which the group must be split per relative
+    // references.
+    UpdateRefGroupBoundChecker aBoundChecker(rCxt, aBounds);
+    std::for_each(maCells.begin(), maCells.end(), aBoundChecker);
+
+    // Sort and remove duplicates.
+    std::sort(aBounds.begin(), aBounds.end());
+    std::vector<SCROW>::iterator it = std::unique(aBounds.begin(), aBounds.end());
+    aBounds.erase(it, aBounds.end());
+
+    // Do the actual splitting.
+    sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds);
+
     UpdateRefOnNonCopy aHandler(nCol, nTab, rCxt, pUndoDoc);
     sc::ProcessFormula(maCells, aHandler);
     return aHandler.isUpdated();
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 06fb6dc..1753153 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -3824,6 +3824,14 @@ bool ScFormulaCell::IsSharedInvariant() const
     return mxGroup ? mxGroup->mbInvariant : false;
 }
 
+bool ScFormulaCell::IsSharedTop() const
+{
+    if (!mxGroup)
+        return false;
+
+    return mxGroup->mnStart == aPos.Row();
+}
+
 SCROW ScFormulaCell::GetSharedTopRow() const
 {
     return mxGroup ? mxGroup->mnStart : -1;
diff --git a/sc/source/core/tool/sharedformula.cxx b/sc/source/core/tool/sharedformula.cxx
index 3e77934..d9f3a25 100644
--- a/sc/source/core/tool/sharedformula.cxx
+++ b/sc/source/core/tool/sharedformula.cxx
@@ -64,6 +64,11 @@ void SharedFormulaUtil::splitFormulaCellGroup(const CellStoreType::position_type
     }
 }
 
+void SharedFormulaUtil::splitFormulaCellGroups(CellStoreType& rCells, const std::vector<SCROW>& rBounds)
+{
+    // TODO: Implement this.
+}
+
 void SharedFormulaUtil::joinFormulaCells(const CellStoreType::position_type& rPos, ScFormulaCell& rCell1, ScFormulaCell& rCell2)
 {
     ScFormulaCell::CompareState eState = rCell1.CompareByTokenArray(rCell2);
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index d74182d..1fbf325 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -2934,6 +2934,88 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnMovedTab( sc::RefUpdateMoveTa
     return aRes;
 }
 
+namespace {
+
+void checkBounds(
+    const sc::RefUpdateContext& rCxt, const ScAddress& rPos, SCROW nGroupLen,
+    const ScSingleRefData& rRef, std::vector<SCROW>& rBounds)
+{
+    if (!rRef.IsRowRel())
+        return;
+
+    ScRange aAbs(rRef.toAbs(rPos));
+    aAbs.aEnd.IncRow(nGroupLen-1);
+    if (!rCxt.maRange.Intersects(aAbs))
+        return;
+
+    // Get the boundary row positions.
+    if (aAbs.aEnd.Row() < rCxt.maRange.aStart.Row())
+        // No intersections.
+        return;
+
+    if (aAbs.aEnd.Row() <= rCxt.maRange.aEnd.Row())
+    {
+        //    +-+ <---- top
+        //    | |
+        // +--+-+--+ <---- boundary row position
+        // |  | |  |
+        // |  +-+  |
+        // +-------+
+
+        // Add offset from the reference top to the cell position.
+        SCROW nOffset = rCxt.maRange.aStart.Row() - aAbs.aStart.Row();
+        rBounds.push_back(rPos.Row()+nOffset);
+        return;
+    }
+
+    //    +-+ <---- top
+    //    | |
+    // +--+-+--+ <---- boundary row position
+    // |  | |  |
+    // |  | |  |
+    // +--+-+--+ <---- boundary row position
+    //    | |
+    //    +-+
+
+    // Add offset from the reference top to the cell position.
+    SCROW nOffset = rCxt.maRange.aStart.Row() - aAbs.aStart.Row();
+    rBounds.push_back(rPos.Row()+nOffset);
+    // Ditto.
+    nOffset = rCxt.maRange.aEnd.Row() - aAbs.aStart.Row();
+    rBounds.push_back(rPos.Row()+nOffset);
+}
+
+}
+
+void ScTokenArray::CheckRelativeReferenceBounds(
+    const sc::RefUpdateContext& rCxt, const ScAddress& rPos, SCROW nGroupLen, std::vector<SCROW>& rBounds ) const
+{
+    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);
+                checkBounds(rCxt, rPos, nGroupLen, pToken->GetSingleRef(), rBounds);
+            }
+            break;
+            case svDoubleRef:
+            {
+                ScToken* pToken = static_cast<ScToken*>(*p);
+                const ScComplexRefData& rRef = pToken->GetDoubleRef();
+                checkBounds(rCxt, rPos, nGroupLen, rRef.Ref1, rBounds);
+                checkBounds(rCxt, rPos, nGroupLen, rRef.Ref2, rBounds);
+            }
+            break;
+            default:
+                ;
+        }
+    }
+}
+
 #if DEBUG_FORMULA_COMPILER
 void ScTokenArray::Dump() const
 {


More information about the Libreoffice-commits mailing list