[Libreoffice-commits] core.git: Branch 'feature/calc-group-interpreter-2' - 4 commits - sc/inc sc/Library_sc.mk sc/qa sc/source

Kohei Yoshida kohei.yoshida at gmail.com
Tue Aug 13 21:04:39 PDT 2013


 sc/Library_sc.mk                   |    1 
 sc/inc/column.hxx                  |    2 
 sc/inc/columnset.hxx               |   40 +++++++++++++
 sc/inc/refupdatecontext.hxx        |    2 
 sc/inc/table.hxx                   |    9 +--
 sc/qa/unit/ucalc.hxx               |    2 
 sc/qa/unit/ucalc_sharedformula.cxx |   94 ++++++++++++++++++++++++++++++++
 sc/source/core/data/column.cxx     |    5 +
 sc/source/core/data/column3.cxx    |  108 ++++++++++++++++++++++++++-----------
 sc/source/core/data/columnset.cxx  |   66 ++++++++++++++++++++++
 sc/source/core/data/document.cxx   |   16 ++---
 sc/source/core/data/table2.cxx     |   35 +++++++++--
 12 files changed, 328 insertions(+), 52 deletions(-)

New commits:
commit 61d01ee9e074cfb8c817c716676d15e92d60f3da
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Aug 13 23:47:58 2013 -0400

    Do the same when deleting rows.
    
    Change-Id: Ib1deab33a8771e196d0520bae872eb0d492c913e

diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index fa6247c..5e3f959 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -384,8 +384,8 @@ public:
 
     bool TestInsertRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize ) const;
     void        InsertRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize );
-    void        DeleteRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize,
-                            bool* pUndoOutline = NULL );
+    void DeleteRow(
+        const sc::ColumnSet& rRegroupCols, SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize, bool* pUndoOutline = NULL );
 
     bool        TestInsertCol( SCROW nStartRow, SCROW nEndRow, SCSIZE nSize ) const;
     void        InsertCol( SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE nSize );
diff --git a/sc/qa/unit/ucalc_sharedformula.cxx b/sc/qa/unit/ucalc_sharedformula.cxx
index 094db8f..4d9ad67 100644
--- a/sc/qa/unit/ucalc_sharedformula.cxx
+++ b/sc/qa/unit/ucalc_sharedformula.cxx
@@ -309,6 +309,37 @@ void Test::testSharedFormulasRefUpdate()
     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
     CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
 
+    // Insert cells over A11:A12 and shift down.
+    m_pDoc->InsertRow(ScRange(0,10,0,0,11,0));
+    if (!checkFormula(*m_pDoc, ScAddress(1,0,0), "A10"))
+        CPPUNIT_FAIL("Wrong formula in B1");
+    if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "A13"))
+        CPPUNIT_FAIL("Wrong formula in B2");
+    if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "A14"))
+        CPPUNIT_FAIL("Wrong formula in B3");
+
+    pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
+    CPPUNIT_ASSERT_MESSAGE("B1 should be a non-shared formula cell.", pFC && !pFC->IsShared());
+    pFC = m_pDoc->GetFormulaCell(ScAddress(1,1,0));
+    CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC && pFC->IsShared());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(1), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
+
+    // Delete A11:A12 to bring it back to the way it was.
+    m_pDoc->DeleteRow(ScRange(0,10,0,0,11,0));
+
+    if (!checkFormula(*m_pDoc, ScAddress(1,0,0), "A10"))
+        CPPUNIT_FAIL("Wrong formula in B1");
+    if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "A11"))
+        CPPUNIT_FAIL("Wrong formula in B2");
+    if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "A12"))
+        CPPUNIT_FAIL("Wrong formula in B3");
+
+    pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
+    CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC && pFC->IsShared());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
+
     m_pDoc->DeleteTab(0);
 }
 
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 9fdf84a..2e3a279 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -1301,10 +1301,10 @@ void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab,
     }
     while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
 
+    sc::RefUpdateContext aCxt(*this);
     if ( ValidRow(nStartRow+nSize) )
     {
         lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
-        sc::RefUpdateContext aCxt(*this);
         aCxt.meMode = URM_INSDEL;
         aCxt.maRange = ScRange(nStartCol, nStartRow+nSize, nTabRangeStart, nEndCol, MAXROW, nTabRangeEnd);
         aCxt.mnRowDelta = -(static_cast<SCROW>(nSize));
@@ -1320,7 +1320,7 @@ void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab,
 
     for ( i = nStartTab; i <= nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
         if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
-            maTabs[i]->DeleteRow( nStartCol, nEndCol, nStartRow, nSize, pUndoOutline );
+            maTabs[i]->DeleteRow(aCxt.maRegroupCols, nStartCol, nEndCol, nStartRow, nSize, pUndoOutline);
 
     if ( ValidRow(nStartRow+nSize) )
     {   // Listeners have been removed in UpdateReference
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index f900f62..d2174de 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -227,8 +227,9 @@ void ScTable::InsertRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE
 }
 
 
-void ScTable::DeleteRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize,
-                            bool* pUndoOutline )
+void ScTable::DeleteRow(
+    const sc::ColumnSet& rRegroupCols, SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize,
+    bool* pUndoOutline )
 {
     if (nStartCol==0 && nEndCol==MAXCOL)
     {
@@ -266,6 +267,10 @@ void ScTable::DeleteRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE
         }
     }
 
+    std::vector<SCCOL> aRegroupCols;
+    rRegroupCols.getColumns(nTab, aRegroupCols);
+    std::for_each(aRegroupCols.begin(), aRegroupCols.end(), ColumnRegroupFormulaCells(aCol));
+
     // Transfer those notes that will get shifted into another container.
     ScNotes aNotes(pDocument);
     ScNotes::iterator itr = maNotes.begin();
commit 99ae3a94dfc0e955710959b01a0e0a1a77aafd1e
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Aug 13 22:53:14 2013 -0400

    Regroup formula cells later in columns where references are updated.
    
    Change-Id: I4dd6ade18e72d8f57583180463f9dda3603be4c2

diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index 6f559f5..83e3358 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -108,6 +108,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
 	sc/source/core/data/column2 \
 	sc/source/core/data/column3 \
 	sc/source/core/data/columniterator \
+	sc/source/core/data/columnset \
 	sc/source/core/data/columnspanset \
 	sc/source/core/data/compressedarray \
 	sc/source/core/data/colorscale \
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 22bb9bd..14d0bfe 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -329,7 +329,7 @@ public:
      * @return true if reference of at least one formula cell has been
      *         updated, false otherwise.
      */
-    bool UpdateReference( const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc = NULL );
+    bool UpdateReference( sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc = NULL );
 
     void UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt );
     void UpdateInsertTabOnlyCells( sc::RefUpdateInsertTabContext& rCxt );
diff --git a/sc/inc/columnset.hxx b/sc/inc/columnset.hxx
new file mode 100644
index 0000000..fb56303
--- /dev/null
+++ b/sc/inc/columnset.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef SC_COLUMNSET_HXX
+#define SC_COLUMNSET_HXX
+
+#include "address.hxx"
+
+#include <vector>
+#include <boost/unordered_set.hpp>
+#include <boost/unordered_map.hpp>
+
+namespace sc {
+
+/**
+ * Simple container to keep track of sheet - column pair.
+ */
+class ColumnSet
+{
+    typedef boost::unordered_set<SCCOL> ColsType;
+    typedef boost::unordered_map<SCTAB, ColsType> TabsType;
+    TabsType maTabs;
+
+public:
+    void set(SCTAB nTab, SCCOL nCol);
+    bool has(SCTAB nTab, SCCOL nCol) const;
+    void getColumns(SCTAB nTab, std::vector<SCCOL>& rCols) const;
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/refupdatecontext.hxx b/sc/inc/refupdatecontext.hxx
index f5ca4d0..ba0beed 100644
--- a/sc/inc/refupdatecontext.hxx
+++ b/sc/inc/refupdatecontext.hxx
@@ -12,6 +12,7 @@
 
 #include "global.hxx"
 #include "address.hxx"
+#include "columnset.hxx"
 
 #include <boost/unordered_map.hpp>
 #include <boost/unordered_set.hpp>
@@ -66,6 +67,7 @@ struct RefUpdateContext
     SCTAB mnTabDelta;
 
     UpdatedRangeNames maUpdatedNames;
+    ColumnSet maRegroupCols;
 
     RefUpdateContext(ScDocument& rDoc);
 
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index a95f2bc..fa6247c 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -58,6 +58,7 @@ namespace sc {
     class CopyToDocContext;
     class MixDocContext;
     class ColumnSpanSet;
+    class ColumnSet;
     struct ColumnBlockPosition;
     struct RefUpdateContext;
     struct RefUpdateInsertTabContext;
@@ -388,8 +389,8 @@ public:
 
     bool        TestInsertCol( SCROW nStartRow, SCROW nEndRow, SCSIZE nSize ) const;
     void        InsertCol( SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE nSize );
-    void        DeleteCol( SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE nSize,
-                            bool* pUndoOutline = NULL );
+    void DeleteCol(
+        const sc::ColumnSet& rRegroupCols, SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE nSize, bool* pUndoOutline = NULL );
 
     void        DeleteArea(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, sal_uInt16 nDelFlag);
     void CopyToClip( sc::CopyToClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScTable* pTable );
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index e4ad8c7..d8c3e60 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -2359,7 +2359,7 @@ bool ScColumn::UpdateReferenceOnCopy( const sc::RefUpdateContext& rCxt, ScDocume
     return aHandler.isUpdated();
 }
 
-bool ScColumn::UpdateReference( const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc )
+bool ScColumn::UpdateReference( sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc )
 {
     if (rCxt.meMode == URM_COPY)
         return UpdateReferenceOnCopy(rCxt, pUndoDoc);
@@ -2396,6 +2396,9 @@ bool ScColumn::UpdateReference( const sc::RefUpdateContext& rCxt, ScDocument* pU
 
     UpdateRefOnNonCopy aHandler(nCol, nTab, rCxt, pUndoDoc);
     sc::ProcessFormula(maCells, aHandler);
+    if (aHandler.isUpdated())
+        rCxt.maRegroupCols.set(nTab, nCol);
+
     return aHandler.isUpdated();
 }
 
diff --git a/sc/source/core/data/columnset.cxx b/sc/source/core/data/columnset.cxx
new file mode 100644
index 0000000..2e1f3aa
--- /dev/null
+++ b/sc/source/core/data/columnset.cxx
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "columnset.hxx"
+
+namespace sc {
+
+void ColumnSet::set(SCTAB nTab, SCCOL nCol)
+{
+    TabsType::iterator itTab = maTabs.find(nTab);
+    if (itTab == maTabs.end())
+    {
+        std::pair<TabsType::iterator,bool> r =
+            maTabs.insert(TabsType::value_type(nTab, ColsType()));
+
+        if (!r.second)
+            // insertion failed.
+            return;
+
+        itTab = r.first;
+    }
+
+    ColsType& rCols = itTab->second;
+    rCols.insert(nCol);
+}
+
+bool ColumnSet::has(SCTAB nTab, SCCOL nCol) const
+{
+    TabsType::const_iterator itTab = maTabs.find(nTab);
+    if (itTab == maTabs.end())
+        return false;
+
+    const ColsType& rCols = itTab->second;
+    return rCols.count(nCol) > 0;
+}
+
+void ColumnSet::getColumns(SCTAB nTab, std::vector<SCCOL>& rCols) const
+{
+    std::vector<SCCOL> aCols;
+    TabsType::const_iterator itTab = maTabs.find(nTab);
+    if (itTab == maTabs.end())
+    {
+        rCols.swap(aCols); // empty it.
+        return;
+    }
+
+    const ColsType& rTabCols = itTab->second;
+    aCols.assign(rTabCols.begin(), rTabCols.end());
+
+    // Sort and remove duplicates.
+    std::sort(aCols.begin(), aCols.end());
+    std::vector<SCCOL>::iterator itCol = std::unique(aCols.begin(), aCols.end());
+    aCols.erase(itCol, aCols.end());
+
+    rCols.swap(aCols);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index a6eb5ef..9fdf84a 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -1474,8 +1474,7 @@ void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTA
         nEndTab = static_cast<SCTAB>(maTabs.size())-1;
     }
 
-    bool bOldAutoCalc = GetAutoCalc();
-    SetAutoCalc( false );   // avoid multiple calculations
+    sc::AutoCalcSwitch aACSwitch(*this, false); // avoid multiple calculations
 
     // handle chunks of consecutive selected sheets together
     SCTAB nTabRangeStart = nStartTab;
@@ -1499,10 +1498,10 @@ void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTA
     }
     while ( lcl_GetNextTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) ) );
 
+    sc::RefUpdateContext aCxt(*this);
     if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
     {
         lcl_GetFirstTabRange( nTabRangeStart, nTabRangeEnd, pTabMark, static_cast<SCTAB>(maTabs.size()) );
-        sc::RefUpdateContext aCxt(*this);
         aCxt.meMode = URM_INSDEL;
         aCxt.maRange = ScRange(sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nTabRangeStart, MAXCOL, nEndRow, nTabRangeEnd);
         aCxt.mnColDelta = -(static_cast<SCCOL>(nSize));
@@ -1516,9 +1515,11 @@ void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTA
     if (pUndoOutline)
         *pUndoOutline = false;
 
-    for ( i = nStartTab; i <= nEndTab && i < static_cast<SCTAB>(maTabs.size()); i++)
+    for (i = nStartTab; i <= nEndTab && i < static_cast<SCTAB>(maTabs.size()); ++i)
+    {
         if (maTabs[i] && (!pTabMark || pTabMark->GetTableSelect(i)))
-            maTabs[i]->DeleteCol( nStartCol, nStartRow, nEndRow, nSize, pUndoOutline );
+            maTabs[i]->DeleteCol(aCxt.maRegroupCols, nStartCol, nStartRow, nEndRow, nSize, pUndoOutline);
+    }
 
     if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
     {// Listeners have been removed in UpdateReference
@@ -1536,7 +1537,6 @@ void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTA
         std::for_each(maTabs.begin(), maTabs.end(), BroadcastRecalcOnRefMoveHandler());
     }
 
-    SetAutoCalc( bOldAutoCalc );
     pChartListenerCollection->UpdateDirtyCharts();
 }
 
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index 537f856..f900f62 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -59,7 +59,21 @@
 #include <svl/PasswordHelper.hxx>
 #include <unotools/transliterationwrapper.hxx>
 
-// STATIC DATA -----------------------------------------------------------
+namespace {
+
+class ColumnRegroupFormulaCells
+{
+    ScColumn* mpCols;
+public:
+    ColumnRegroupFormulaCells(ScColumn* pCols) : mpCols(pCols) {}
+
+    void operator() (SCCOL nCol)
+    {
+        mpCols[nCol].RegroupFormulaCells();
+    }
+};
+
+}
 
 sal_uInt16 ScTable::GetTextWidth(SCCOL nCol, SCROW nRow) const
 {
@@ -425,9 +439,8 @@ void ScTable::InsertCol( SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE
         SetStreamValid(false);
 }
 
-
-void ScTable::DeleteCol( SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE nSize,
-                            bool* pUndoOutline )
+void ScTable::DeleteCol(
+    const sc::ColumnSet& rRegroupCols, SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE nSize, bool* pUndoOutline )
 {
     if (nStartRow==0 && nEndRow==MAXROW)
     {
@@ -460,7 +473,6 @@ void ScTable::DeleteCol( SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE
         }
     }
 
-
     {   // scope for bulk broadcast
         ScBulkBroadcast aBulkBroadcast( pDocument->GetBASM());
         for (SCSIZE i = 0; i < nSize; i++)
@@ -479,6 +491,10 @@ void ScTable::DeleteCol( SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE
             aCol[nStartCol + nSize + i].MoveTo(nStartRow, nEndRow, aCol[nStartCol + i]);
     }
 
+    std::vector<SCCOL> aRegroupCols;
+    rRegroupCols.getColumns(nTab, aRegroupCols);
+    std::for_each(aRegroupCols.begin(), aRegroupCols.end(), ColumnRegroupFormulaCells(aCol));
+
     // Transfer those notes that will get shifted into another container.
     ScNotes aNotes(pDocument);
     ScNotes::iterator itr = maNotes.begin();
commit b93841f70abdd894d1bd17b455577541bc6948a4
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Aug 13 19:47:04 2013 -0400

    Try to re-group without ungrouping all cells.
    
    Change-Id: I8e5c4e240e64a1d70e599c4a8791133dddc0b75b

diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index c4276d9..4f87988 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -2628,18 +2628,6 @@ xub_StrLen ScColumn::GetMaxNumberStringLen(
 
 namespace {
 
-class CellGroupSetter
-{
-    ScFormulaCellGroupRef mxGroup;
-public:
-    CellGroupSetter(const ScFormulaCellGroupRef& xGroup) : mxGroup(xGroup) {}
-
-    void operator() (size_t, ScFormulaCell* pCell)
-    {
-        pCell->SetCellGroup(mxGroup);
-    }
-};
-
 class GroupFormulaCells
 {
     ScFormulaCellGroupRef mxNone;
@@ -2652,40 +2640,103 @@ public:
             // We are only interested in formula cells.
             return;
 
-        ScFormulaCell* pPrev = NULL;
-        ScFormulaCell* pCur = NULL;
         size_t nRow = node.position; // start row position.
 
         sc::formula_block::iterator it = sc::formula_block::begin(*node.data);
         sc::formula_block::iterator itEnd = sc::formula_block::end(*node.data);
-        for (; it != itEnd; ++it, ++nRow, pPrev = pCur)
+
+        // This block should never be empty.
+
+        ScFormulaCell* pPrev = *it;
+        ScFormulaCellGroupRef xPrevGrp = pPrev->GetCellGroup();
+        if (xPrevGrp)
+        {
+            // Move to the cell after the last cell of the current group.
+            std::advance(it, xPrevGrp->mnLength);
+            nRow += xPrevGrp->mnLength;
+        }
+        else
+        {
+            ++it;
+            ++nRow;
+        }
+
+        ScFormulaCell* pCur = NULL;
+        ScFormulaCellGroupRef xCurGrp;
+        for (; it != itEnd; pPrev = pCur, xPrevGrp = xCurGrp)
         {
             pCur = *it;
-            if (!pPrev)
-                continue;
+            xCurGrp = pCur->GetCellGroup();
 
             ScFormulaCell::CompareState eCompState = pPrev->CompareByTokenArray(*pCur);
             if (eCompState == ScFormulaCell::NotEqual)
             {
                 // different formula tokens.
                 pCur->SetCellGroup(mxNone);
+                if (xCurGrp)
+                {
+                    // Move to the cell after the last cell of the current group.
+                    std::advance(it, xCurGrp->mnLength);
+                    nRow += xCurGrp->mnLength;
+                }
+                else
+                {
+                    ++it;
+                    ++nRow;
+                }
+
                 continue;
             }
 
-            // Formula tokens equal those of the previous formula cell.
-            ScFormulaCellGroupRef xGroup = pPrev->GetCellGroup();
-            if (!xGroup)
+            // Formula tokens equal those of the previous formula cell or cell group.
+            if (xPrevGrp)
+            {
+                // Previous cell is a group.
+                if (xCurGrp)
+                {
+                    // The current cell is a group.  Merge these two groups.
+                    xPrevGrp->mnLength += xCurGrp->mnLength;
+                    pCur->SetCellGroup(xPrevGrp);
+                    sc::formula_block::iterator itGrpEnd = it;
+                    std::advance(itGrpEnd, xCurGrp->mnLength);
+                    for (++it; it != itGrpEnd; ++it)
+                    {
+                        ScFormulaCell* pCell = *it;
+                        pCell->SetCellGroup(xPrevGrp);
+                    }
+                    nRow += xCurGrp->mnLength;
+                }
+                else
+                {
+                    // Add this cell to the previous group.
+                    pCur->SetCellGroup(xPrevGrp);
+                    ++xPrevGrp->mnLength;
+                    ++nRow;
+                    ++it;
+                }
+
+            }
+            else if (xCurGrp)
             {
-                // create a new group ...
-                xGroup = pPrev->CreateCellGroup(nRow - 1, 2, eCompState == ScFormulaCell::EqualInvariant);
-                pCur->SetCellGroup(xGroup);
+                // Previous cell is a regular cell and current cell is a group.
+                nRow += xCurGrp->mnLength;
+                std::advance(it, xCurGrp->mnLength);
+                pPrev->SetCellGroup(xCurGrp);
+                --xCurGrp->mnStart;
+                ++xCurGrp->mnLength;
+                xPrevGrp = xCurGrp;
             }
             else
             {
-                // existing group. extend its length.
-                pCur->SetCellGroup(xGroup);
-                ++xGroup->mnLength;
+                // Both previous and current cells are regular cells.
+                xPrevGrp = pPrev->CreateCellGroup(nRow - 1, 2, eCompState == ScFormulaCell::EqualInvariant);
+                pCur->SetCellGroup(xPrevGrp);
+                ++nRow;
+                ++it;
             }
+
+            pCur = pPrev;
+            xCurGrp = xPrevGrp;
         }
     }
 };
@@ -2705,11 +2756,6 @@ void ScColumn::RebuildFormulaGroups()
 
 void ScColumn::RegroupFormulaCells()
 {
-    // clear previous formula groups (if any)
-    ScFormulaCellGroupRef xNone;
-    CellGroupSetter aFunc(xNone);
-    sc::ProcessFormula(maCells, aFunc);
-
     // re-build formula groups.
     std::for_each(maCells.begin(), maCells.end(), GroupFormulaCells());
 }
commit 0e2fc9fce175199a021d0ac10431efbbb9d8c40a
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Tue Aug 13 18:28:11 2013 -0400

    Add test for reference update on shared formulas.
    
    This currently (rightfully) fails.
    
    Change-Id: I254dc7042e93b257765c8ed8cdb9904966afd77e

diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index ebc3221..5e8933c 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -219,6 +219,7 @@ public:
     void testUpdateReference();
     void testSearchCells();
     void testSharedFormulas();
+    void testSharedFormulasRefUpdate();
     void testSharedFormulasCopyPaste();
     void testFormulaPosition();
 
@@ -345,6 +346,7 @@ public:
     CPPUNIT_TEST(testUpdateReference);
     CPPUNIT_TEST(testSearchCells);
     CPPUNIT_TEST(testSharedFormulas);
+    CPPUNIT_TEST(testSharedFormulasRefUpdate);
     CPPUNIT_TEST(testSharedFormulasCopyPaste);
     CPPUNIT_TEST(testFormulaPosition);
     CPPUNIT_TEST(testJumpToPrecedentsDependents);
diff --git a/sc/qa/unit/ucalc_sharedformula.cxx b/sc/qa/unit/ucalc_sharedformula.cxx
index 1eba457..094db8f 100644
--- a/sc/qa/unit/ucalc_sharedformula.cxx
+++ b/sc/qa/unit/ucalc_sharedformula.cxx
@@ -14,6 +14,7 @@
 #include "docsh.hxx"
 #include "clipparam.hxx"
 #include "undoblk.hxx"
+#include "scopetools.hxx"
 
 #include "formula/grammar.hxx"
 
@@ -249,6 +250,68 @@ void Test::testSharedFormulas()
     m_pDoc->DeleteTab(0);
 }
 
+void Test::testSharedFormulasRefUpdate()
+{
+    m_pDoc->InsertTab(0, "Test");
+
+    sc::AutoCalcSwitch aACSwitch(*m_pDoc, false); // turn off auto calculation.
+
+    // Set values to A10:A12.
+    m_pDoc->SetValue(ScAddress(0,9,0), 1);
+    m_pDoc->SetValue(ScAddress(0,10,0), 2);
+    m_pDoc->SetValue(ScAddress(0,11,0), 3);
+
+    // Insert formulas that reference A10:A12 in B1:B3.
+    m_pDoc->SetString(ScAddress(1,0,0), "=A10");
+    m_pDoc->SetString(ScAddress(1,1,0), "=A11");
+    m_pDoc->SetString(ScAddress(1,2,0), "=A12");
+
+    if (!checkFormula(*m_pDoc, ScAddress(1,0,0), "A10"))
+        CPPUNIT_FAIL("Wrong formula in B1");
+    if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "A11"))
+        CPPUNIT_FAIL("Wrong formula in B2");
+    if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "A12"))
+        CPPUNIT_FAIL("Wrong formula in B3");
+
+    const ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
+    CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC && pFC->IsShared());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
+
+    // Insert cells over A11:B11 to shift to right. This should split the B1:B3 grouping into 3.
+    m_pDoc->InsertCol(ScRange(0,10,0,1,10,0));
+    if (!checkFormula(*m_pDoc, ScAddress(1,0,0), "A10"))
+        CPPUNIT_FAIL("Wrong formula in B1");
+    if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "C11"))
+        CPPUNIT_FAIL("Wrong formula in B2");
+    if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "A12"))
+        CPPUNIT_FAIL("Wrong formula in B3");
+
+    pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
+    CPPUNIT_ASSERT_MESSAGE("B1 should be a non-shared formula cell.", pFC && !pFC->IsShared());
+    pFC = m_pDoc->GetFormulaCell(ScAddress(1,1,0));
+    CPPUNIT_ASSERT_MESSAGE("B2 should be a non-shared formula cell.", pFC && !pFC->IsShared());
+    pFC = m_pDoc->GetFormulaCell(ScAddress(1,2,0));
+    CPPUNIT_ASSERT_MESSAGE("B3 should be a non-shared formula cell.", pFC && !pFC->IsShared());
+
+    // Delelte cells over A11:B11 to bring it back to the previous state.
+    m_pDoc->DeleteCol(ScRange(0,10,0,1,10,0));
+
+    if (!checkFormula(*m_pDoc, ScAddress(1,0,0), "A10"))
+        CPPUNIT_FAIL("Wrong formula in B1");
+    if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "A11"))
+        CPPUNIT_FAIL("Wrong formula in B2");
+    if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "A12"))
+        CPPUNIT_FAIL("Wrong formula in B3");
+
+    pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
+    CPPUNIT_ASSERT_MESSAGE("This must be a shared formula cell.", pFC && pFC->IsShared());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
+
+    m_pDoc->DeleteTab(0);
+}
+
 void Test::testSharedFormulasCopyPaste()
 {
     m_pDoc->InsertTab(0, "Test");


More information about the Libreoffice-commits mailing list