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

Kohei Yoshida kohei.yoshida at collabora.com
Sat Mar 22 06:53:34 PDT 2014


 sc/inc/column.hxx                  |    3 +
 sc/inc/document.hxx                |    2 
 sc/inc/table.hxx                   |    2 
 sc/qa/unit/ucalc.hxx               |    2 
 sc/qa/unit/ucalc_sharedformula.cxx |  106 +++++++++++++++++++++++++++++++++++++
 sc/source/core/data/column.cxx     |   21 +++++--
 sc/source/core/data/column3.cxx    |   69 ++++++++++++++++++++++++
 sc/source/core/data/documen2.cxx   |   12 ++++
 sc/source/core/data/table2.cxx     |    8 ++
 9 files changed, 221 insertions(+), 4 deletions(-)

New commits:
commit 474b2ea601f7fa2f1fbeae0f169ff5b8abc965be
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Sat Mar 22 09:47:11 2014 -0400

    fdo#76470: Avoid joining new formula cells individually.
    
    Instead, insert the formula cells in the group first, then only try to join
    the top and bottom cells afterward. Otherwise the grouping would get messed
    up and a problem would ensue.
    
    Change-Id: I4fdd5326c029032a636d8225b5fb16cbde427c7d

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index c9e9757..a84f836 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -299,6 +299,8 @@ public:
     ScFormulaCell* SetFormulaCell( SCROW nRow, ScFormulaCell* pCell );
     ScFormulaCell* SetFormulaCell( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, ScFormulaCell* pCell );
 
+    bool SetFormulaCells( SCROW nRow, std::vector<ScFormulaCell*>& rCells );
+
     void CloneFormulaCell( const ScFormulaCell& rSrc, const std::vector<sc::RowSpan>& rRanges );
 
     svl::SharedString GetSharedString( SCROW nRow ) const;
@@ -570,6 +572,7 @@ private:
     sc::CellStoreType::iterator GetPositionToInsert( const sc::CellStoreType::iterator& it, SCROW nRow );
     void ActivateNewFormulaCell( const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell, bool bJoin = true );
     void ActivateNewFormulaCell( const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell, bool bJoin = true );
+    void AttachNewFormulaCells( const sc::CellStoreType::position_type& aPos, size_t nLength );
     void BroadcastNewCell( SCROW nRow );
     bool UpdateScriptType( sc::CellTextAttr& rAttr, SCROW nRow, sc::CellStoreType::iterator& itr );
 
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 05afc1c..becca93 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -844,6 +844,8 @@ public:
      */
     SC_DLLPUBLIC ScFormulaCell* SetFormulaCell( const ScAddress& rPos, ScFormulaCell* pCell );
 
+    bool SetFormulaCells( const ScAddress& rPos, std::vector<ScFormulaCell*>& rCells );
+
     SC_DLLPUBLIC void InsertMatrixFormula(SCCOL nCol1, SCROW nRow1,
                                         SCCOL nCol2, SCROW nRow2,
                                         const ScMarkData& rMark,
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index ce58c20..59a8f58 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -347,6 +347,8 @@ public:
      */
     ScFormulaCell* SetFormulaCell( SCCOL nCol, SCROW nRow, ScFormulaCell* pCell );
 
+    bool SetFormulaCells( SCCOL nCol, SCROW nRow, std::vector<ScFormulaCell*>& rCells );
+
     svl::SharedString GetSharedString( SCCOL nCol, SCROW nRow ) const;
 
     void        SetValue( SCCOL nCol, SCROW nRow, const double& rVal );
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 9694790..5c196a0 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -43,6 +43,7 @@
 #include "refupdatecontext.hxx"
 #include <listenercontext.hxx>
 #include <refhint.hxx>
+#include <stlalgorithm.hxx>
 
 #include <svl/poolcach.hxx>
 #include <svl/zforlist.hxx>
@@ -2561,21 +2562,33 @@ class UpdateRefOnNonCopy : std::unary_function<FormulaGroup, void>
 
     void fillUndoDoc( const ScAddress& rOldPos, SCROW nLength, const ScTokenArray& rOldCode )
     {
-        if (!mpUndoDoc)
+        if (!mpUndoDoc || nLength <= 0)
             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);
+        if (nLength == 1)
+        {
+            mpUndoDoc->SetFormulaCell(aUndoPos, pFC);
+            return;
+        }
+
+        std::vector<ScFormulaCell*> aCells;
+        aCells.reserve(nLength);
+        ScFormulaCellGroupRef xGroup = pFC->CreateCellGroup(nLength, false);
+        aCells.push_back(pFC);
         aUndoPos.IncRow();
         for (SCROW i = 1; i < nLength; ++i, aUndoPos.IncRow())
         {
             pFC = new ScFormulaCell(mpUndoDoc, aUndoPos, xGroup);
-            mpUndoDoc->SetFormulaCell(aUndoPos, pFC);
+            aCells.push_back(pFC);
         }
+
+        if (!mpUndoDoc->SetFormulaCells(rOldPos, aCells))
+            // Insertion failed.  Delete all formula cells.
+            std::for_each(aCells.begin(), aCells.end(), ScDeleteObjectByPtr<ScFormulaCell>());
     }
 
 public:
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 40b0729..3016816 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -46,6 +46,7 @@
 #include "scopetools.hxx"
 #include "editutil.hxx"
 #include "sharedformula.hxx"
+#include <listenercontext.hxx>
 
 #include <com/sun/star/i18n/LocaleDataItem.hpp>
 
@@ -413,6 +414,40 @@ void ScColumn::ActivateNewFormulaCell(
     }
 }
 
+void ScColumn::AttachNewFormulaCells( const sc::CellStoreType::position_type& aPos, size_t nLength )
+{
+    // Make sure the whole length consists of formula cells.
+    if (aPos.first->type != sc::element_type_formula)
+        return;
+
+    if (aPos.first->size < aPos.second + nLength)
+        // Block is shorter than specified length.
+        return;
+
+    // Join the top and bottom cells only.
+    ScFormulaCell* pCell = sc::formula_block::at(*aPos.first->data, aPos.second);
+    JoinNewFormulaCell(aPos, *pCell);
+
+    sc::CellStoreType::position_type aPosLast = aPos;
+    aPosLast.second += nLength - 1;
+    pCell = sc::formula_block::at(*aPosLast.first->data, aPosLast.second);
+    JoinNewFormulaCell(aPosLast, *pCell);
+
+    if (!pDocument->IsClipOrUndo() && !pDocument->IsInsertingFromOtherDoc())
+    {
+        sc::StartListeningContext aCxt(*pDocument);
+        ScFormulaCell** pp = &sc::formula_block::at(*aPos.first->data, aPos.second);
+        ScFormulaCell** ppEnd = pp + nLength;
+        for (; pp != ppEnd; ++pp)
+        {
+            pCell = *pp;
+            pCell->StartListeningTo(aCxt);
+            if (!pDocument->IsCalcingAfterLoad())
+                pCell->SetDirty();
+        }
+    }
+}
+
 void ScColumn::BroadcastNewCell( SCROW nRow )
 {
     // When we insert from the Clipboard we still have wrong (old) References!
@@ -1797,6 +1832,40 @@ ScFormulaCell* ScColumn::SetFormulaCell( sc::ColumnBlockPosition& rBlockPos, SCR
     return pCell;
 }
 
+bool ScColumn::SetFormulaCells( SCROW nRow, std::vector<ScFormulaCell*>& rCells )
+{
+    if (!ValidRow(nRow))
+        return false;
+
+    SCROW nEndRow = nRow + rCells.size() - 1;
+    if (!ValidRow(nEndRow))
+        return false;
+
+    sc::CellStoreType::position_type aPos = maCells.position(nRow);
+
+    // Detach all formula cells that will be overwritten.
+    DetachFormulaCells(aPos, rCells.size());
+
+    for (size_t i = 0, n = rCells.size(); i < n; ++i)
+    {
+        SCROW nThisRow = nRow + i;
+        sal_uInt32 nFmt = GetNumberFormat(nThisRow);
+        if ((nFmt % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
+            rCells[i]->SetNeedNumberFormat(true);
+    }
+
+    std::vector<sc::CellTextAttr> aDefaults(rCells.size(), sc::CellTextAttr());
+    maCellTextAttrs.set(nRow, aDefaults.begin(), aDefaults.end());
+
+    sc::CellStoreType::iterator it = maCells.set(aPos.first, nRow, rCells.begin(), rCells.end());
+
+    CellStorageModified();
+
+    AttachNewFormulaCells(aPos, rCells.size());
+
+    return true;
+}
+
 svl::SharedString ScColumn::GetSharedString( SCROW nRow ) const
 {
     sc::CellStoreType::const_position_type aPos = maCells.position(nRow);
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index 88775f8..745bc24 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -1104,6 +1104,18 @@ ScFormulaCell* ScDocument::SetFormulaCell( const ScAddress& rPos, ScFormulaCell*
     return maTabs[rPos.Tab()]->SetFormulaCell(rPos.Col(), rPos.Row(), pCell);
 }
 
+bool ScDocument::SetFormulaCells( const ScAddress& rPos, std::vector<ScFormulaCell*>& rCells )
+{
+    if (rCells.empty())
+        return false;
+
+    ScTable* pTab = FetchTable(rPos.Tab());
+    if (!pTab)
+        return false;
+
+    return pTab->SetFormulaCells(rPos.Col(), rPos.Row(), rCells);
+}
+
 void ScDocument::SetConsolidateDlgData( const ScConsolidateParam* pData )
 {
     delete pConsolidateDlgData;
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index b4d6656..c4ceabc 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -1412,6 +1412,14 @@ ScFormulaCell* ScTable::SetFormulaCell( SCCOL nCol, SCROW nRow, ScFormulaCell* p
     return aCol[nCol].SetFormulaCell(nRow, pCell);
 }
 
+bool ScTable::SetFormulaCells( SCCOL nCol, SCROW nRow, std::vector<ScFormulaCell*>& rCells )
+{
+    if (!ValidCol(nCol))
+        return false;
+
+    return aCol[nCol].SetFormulaCells(nRow, rCells);
+}
+
 svl::SharedString ScTable::GetSharedString( SCCOL nCol, SCROW nRow ) const
 {
     if (!ValidColRow(nCol, nRow))
commit c78d1bb2cd98aeac64402caf7baa40cbe4cca6f9
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Fri Mar 21 20:42:47 2014 -0400

    fdo#76470: Write unit test for this first.
    
    Change-Id: Iaf609b509165405c1a471dd8556c30dc019922da

diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index 81e915f..39b40d1 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -265,6 +265,7 @@ public:
     void testSharedFormulasRefUpdate();
     void testSharedFormulasRefUpdateRange();
     void testSharedFormulasRefUpdateExternal();
+    void testSharedFormulasInsertRow();
     void testSharedFormulasDeleteRows();
     void testSharedFormulasDeleteColumns();
     void testSharedFormulasRefUpdateMoveSheets();
@@ -442,6 +443,7 @@ public:
     CPPUNIT_TEST(testSharedFormulasRefUpdate);
     CPPUNIT_TEST(testSharedFormulasRefUpdateRange);
     CPPUNIT_TEST(testSharedFormulasRefUpdateExternal);
+    CPPUNIT_TEST(testSharedFormulasInsertRow);
     CPPUNIT_TEST(testSharedFormulasDeleteRows);
     CPPUNIT_TEST(testSharedFormulasDeleteColumns);
     CPPUNIT_TEST(testSharedFormulasRefUpdateMoveSheets);
diff --git a/sc/qa/unit/ucalc_sharedformula.cxx b/sc/qa/unit/ucalc_sharedformula.cxx
index eb7b598..b95a673 100644
--- a/sc/qa/unit/ucalc_sharedformula.cxx
+++ b/sc/qa/unit/ucalc_sharedformula.cxx
@@ -536,6 +536,112 @@ void Test::testSharedFormulasRefUpdateExternal()
     m_pDoc->DeleteTab(0);
 }
 
+void Test::testSharedFormulasInsertRow()
+{
+    struct
+    {
+        bool checkContent( ScDocument* pDoc )
+        {
+            // B1:B2 and B4:B5 should point to $A$5.
+            SCROW pRows[] = { 0, 1, 3, 4 };
+            for (size_t i = 0, n = SAL_N_ELEMENTS(pRows); i < n; ++i)
+            {
+                ScAddress aPos(1, pRows[i], 0);
+                if (!checkFormula(*pDoc, aPos, "$A$5"))
+                {
+                    cerr << "Wrong formula!" << endl;
+                    return false;
+                }
+            }
+
+            // B1:B2 should be grouped.
+            ScFormulaCell* pFC = pDoc->GetFormulaCell(ScAddress(1,0,0));
+            if (!pFC || pFC->GetSharedTopRow() != 0 || pFC->GetSharedLength() != 2)
+            {
+                cerr << "B1:B2 should be grouped." << endl;
+                return false;
+            }
+
+            // B4:B5 should be grouped.
+            pFC = pDoc->GetFormulaCell(ScAddress(1,3,0));
+            if (!pFC || pFC->GetSharedTopRow() != 3 || pFC->GetSharedLength() != 2)
+            {
+                cerr << "B4:B5 should be grouped." << endl;
+                return false;
+            }
+
+            return true;
+        }
+
+        bool checkContentUndo( ScDocument* pDoc )
+        {
+            for (SCROW i = 0; i <= 3; ++i)
+            {
+                ScAddress aPos(1,i,0);
+                if (!checkFormula(*pDoc, aPos, "$A$4"))
+                {
+                    cerr << "Wrong formula!" << endl;
+                    return false;
+                }
+            }
+
+            // Ensure that B5 is empty.
+            if (pDoc->GetCellType(ScAddress(1,4,0)) != CELLTYPE_NONE)
+            {
+                cerr << "B5 should be empty." << endl;
+                return false;
+            }
+
+            // B1:B4 should be grouped.
+            ScFormulaCell* pFC = pDoc->GetFormulaCell(ScAddress(1,0,0));
+            if (!pFC || pFC->GetSharedTopRow() != 0 || pFC->GetSharedLength() != 4)
+            {
+                cerr << "B1:B4 should be grouped." << endl;
+                return false;
+            }
+
+            return true;
+        }
+
+    } aCheck;
+
+    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
+    m_pDoc->InsertTab(0, "Test");
+
+    // Scenario inspired by fdo#76470.
+
+    // Set value to A4.
+    m_pDoc->SetValue(ScAddress(0,3,0), 4.0);
+
+    // Set formula cells in B1:B4 all referencing A4 as absolute reference.
+    for (SCROW i = 0; i <= 3; ++i)
+        m_pDoc->SetString(ScAddress(1,i,0), "=$A$4");
+
+    // Insert a new row at row 3.
+    ScDocFunc& rFunc = getDocShell().GetDocFunc();
+    ScMarkData aMark;
+    aMark.SelectOneTable(0);
+    rFunc.InsertCells(ScRange(0,2,0,MAXCOL,2,0), &aMark, INS_INSROWS, true, true, false);
+
+    bool bResult = aCheck.checkContent(m_pDoc);
+    CPPUNIT_ASSERT_MESSAGE("Failed on the initial content check.", bResult);
+
+    // Undo and check its result.
+    SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
+    CPPUNIT_ASSERT(pUndoMgr);
+    pUndoMgr->Undo();
+
+    bResult = aCheck.checkContentUndo(m_pDoc);
+    CPPUNIT_ASSERT_MESSAGE("Failed on the content check after undo.", bResult);
+
+    // Redo and check its result.
+    pUndoMgr->Redo();
+    bResult = aCheck.checkContent(m_pDoc);
+    CPPUNIT_ASSERT_MESSAGE("Failed on the content check after redo.", bResult);
+
+    m_pDoc->DeleteTab(0);
+}
+
 void Test::testSharedFormulasDeleteRows()
 {
     m_pDoc->InsertTab(0, "Test");


More information about the Libreoffice-commits mailing list