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

Eike Rathke erack at redhat.com
Tue Sep 8 14:34:17 PDT 2015


 sc/inc/dbdata.hxx              |    1 
 sc/qa/unit/ucalc_formula.cxx   |  223 +++++++++++++++++++++++++++++++++++++++++
 sc/source/core/tool/dbdata.cxx |   53 ++++-----
 3 files changed, 250 insertions(+), 27 deletions(-)

New commits:
commit 470848093a2687a6d8056629da6b43773ff4cb0c
Author: Eike Rathke <erack at redhat.com>
Date:   Tue Sep 8 23:30:27 2015 +0200

    factor out duplicated code into NamedDBs::initInserted()
    
    Change-Id: Idc95d4b8acae9dcd4ed0092c43986e6687f06c11

diff --git a/sc/inc/dbdata.hxx b/sc/inc/dbdata.hxx
index 85ace9f..1f825e7 100644
--- a/sc/inc/dbdata.hxx
+++ b/sc/inc/dbdata.hxx
@@ -243,6 +243,7 @@ public:
         NamedDBs(const NamedDBs& r);
         virtual ~NamedDBs();
         NamedDBs & operator=(NamedDBs const&) = delete;
+        void initInserted( ScDBData* p );
 
     public:
         typedef DBsType::iterator iterator;
diff --git a/sc/source/core/tool/dbdata.cxx b/sc/source/core/tool/dbdata.cxx
index 19c460b..9edd5d0 100644
--- a/sc/source/core/tool/dbdata.cxx
+++ b/sc/source/core/tool/dbdata.cxx
@@ -1058,27 +1058,7 @@ ScDBCollection::NamedDBs::NamedDBs(const NamedDBs& r)
         ScDBData* p = new ScDBData(*it);
         std::unique_ptr<ScDBData> pData(p);
         if (m_DBs.insert( std::move(pData)).second)
-        {
-            p->SetContainer( this);
-            if (!mrDoc.IsClipOrUndo())
-            {
-                p->StartTableColumnNamesListener(); // needs the container be set already
-                if (p->AreTableColumnNamesDirty())
-                {
-                    if (p->HasHeader())
-                    {
-                        // Refresh table column names in next round.
-                        maDirtyTableColumnNames.Join( p->GetHeaderArea());
-                    }
-                    else
-                    {
-                        // Header-less table can generate its column names
-                        // already without accessing the document.
-                        p->RefreshTableColumnNames( nullptr);
-                    }
-                }
-            }
-        }
+            initInserted(p);
     }
 }
 
@@ -1086,6 +1066,29 @@ ScDBCollection::NamedDBs::~NamedDBs()
 {
 }
 
+void ScDBCollection::NamedDBs::initInserted( ScDBData* p )
+{
+    p->SetContainer( this);
+    if (!mrDoc.IsClipOrUndo())
+    {
+        p->StartTableColumnNamesListener(); // needs the container be set already
+        if (p->AreTableColumnNamesDirty())
+        {
+            if (p->HasHeader())
+            {
+                // Refresh table column names in next round.
+                maDirtyTableColumnNames.Join( p->GetHeaderArea());
+            }
+            else
+            {
+                // Header-less table can generate its column names
+                // already without accessing the document.
+                p->RefreshTableColumnNames( nullptr);
+            }
+        }
+    }
+}
+
 ScDBCollection::NamedDBs::iterator ScDBCollection::NamedDBs::begin()
 {
     return m_DBs.begin();
@@ -1136,25 +1139,7 @@ bool ScDBCollection::NamedDBs::insert(ScDBData* p)
 
     if (r.second)
     {
-        p->SetContainer( this);
-        if (!mrDoc.IsClipOrUndo())
-        {
-            p->StartTableColumnNamesListener(); // needs the container be set already
-            if (p->AreTableColumnNamesDirty())
-            {
-                if (p->HasHeader())
-                {
-                    // Refresh table column names in next round.
-                    maDirtyTableColumnNames.Join( p->GetHeaderArea());
-                }
-                else
-                {
-                    // Header-less table can generate its column names
-                    // already without accessing the document.
-                    p->RefreshTableColumnNames( nullptr);
-                }
-            }
-        }
+        initInserted(p);
 
         /* TODO: shouldn't the import refresh not be setup for
          * clipboard/undo documents? It was already like this before.. */
commit 70a1e658c0d1f111c8c0991fb87561e3be5683f0
Author: Eike Rathke <erack at redhat.com>
Date:   Tue Sep 8 23:03:09 2015 +0200

    TableRef: add unit tests for column names updates and header-less
    
    Change-Id: I244866c91a4f98a55e7ba5f6f87a820cb3de0ead

diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx
index 4aa08b7..675e517 100644
--- a/sc/qa/unit/ucalc_formula.cxx
+++ b/sc/qa/unit/ucalc_formula.cxx
@@ -5434,6 +5434,9 @@ void Test::testFuncTableRef()
     sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
 
     m_pDoc->InsertTab(0, "Sheet1");
+    ScMarkData aMark;
+    aMark.SelectOneTable(0);
+    ScDocFunc& rDocFunc = getDocShell().GetDocFunc();
 
     {
         ScDBCollection* pDBs = m_pDoc->GetDBCollection();
@@ -5552,6 +5555,226 @@ void Test::testFuncTableRef()
                 aPrefix + m_pDoc->GetString( aPos));
     }
 
+    // Insert a column at column B to extend database range from column A,B to
+    // A,B,C. Use ScDocFunc so RefreshDirtyTableColumnNames() is called.
+    rDocFunc.InsertCells(ScRange(1,0,0,1,MAXROW,0), &aMark, INS_INSCOLS_BEFORE, false, true);
+
+    // Re-verify the named expression in SUM() formula, on row 4 that
+    // intersects, now starting at column E, still works.
+    m_pDoc->CalcAll();
+    for (size_t i = 0, n = SAL_N_ELEMENTS(aNames); i < n; ++i)
+    {
+        OUString aFormula( "=SUM(" + OUString::createFromAscii( aNames[i].pName) + ")");
+        ScAddress aPos(4+i,3,0);
+        // For easier "debugability" have position and formula in assertion.
+        OUString aPrefix( aPos.Format(SCA_VALID) + " " + aFormula + " : ");
+        CPPUNIT_ASSERT_EQUAL( aPrefix + OUString::createFromAscii( aNames[i].pSum4),
+                aPrefix + m_pDoc->GetString( aPos));
+    }
+
+    const char* pColumn2Formula = "=SUM(table[[#Data];[Column2]])";
+    {
+        // Populate "table" database range with empty header and data in newly
+        // inserted column, B1:B4 plus a table formula in B6. The empty header
+        // should result in the internal table column name "Column2" that is
+        // used in the formula.
+        const char* aData[][1] = {
+            { "" },
+            { "64" },
+            { "128" },
+            { "256" },
+            { "" },
+            { pColumn2Formula }
+        };
+        ScAddress aPos(1,0,0);
+        ScRange aRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
+        CPPUNIT_ASSERT(aRange.aStart == aPos);
+    }
+
+    // Verify the formula result in B6 (64+128+256=448).
+    {
+        OUString aFormula( OUString::createFromAscii( pColumn2Formula));
+        ScAddress aPos(1,5,0);
+        OUString aPrefix( aPos.Format(SCA_VALID) + " " + aFormula + " : ");
+        CPPUNIT_ASSERT_EQUAL( aPrefix + OUString("448"), aPrefix + m_pDoc->GetString( aPos));
+    }
+
+    // Set header in column B. Use ScDocFunc to have table column names refreshed.
+    rDocFunc.SetStringCell(ScAddress(1,0,0), "NewHeader",true);
+    // Verify that formula adapted using the updated table column names.
+    if (!checkFormula(*m_pDoc, ScAddress(1,5,0), "SUM(table[[#Data];[NewHeader]])"))
+        CPPUNIT_FAIL("Wrong formula");
+
+    // Set header in column A to identical string. Internal table column name
+    // for B should get a "2" appended.
+    rDocFunc.SetStringCell(ScAddress(0,0,0), "NewHeader",true);
+    // Verify that formula adapted using the updated table column names.
+    if (!checkFormula(*m_pDoc, ScAddress(1,5,0), "SUM(table[[#Data];[NewHeader2]])"))
+        CPPUNIT_FAIL("Wrong formula");
+
+    // Set header in column B to empty string, effectively clearing the cell.
+    rDocFunc.SetStringCell(ScAddress(1,0,0), "",true);
+    // Verify that formula is still using the previous table column name.
+    if (!checkFormula(*m_pDoc, ScAddress(1,5,0), "SUM(table[[#Data];[NewHeader2]])"))
+        CPPUNIT_FAIL("Wrong formula");
+
+    // === header-less ===
+
+    {
+        ScDBCollection* pDBs = m_pDoc->GetDBCollection();
+        CPPUNIT_ASSERT_MESSAGE("Failed to fetch DB collection object.", pDBs);
+
+        // Insert "headerless" database range definition for E10:F12, without headers.
+        ScDBData* pData = new ScDBData( "hltable", 0, 4,9, 5,11, true, false);
+        bool bInserted = pDBs->getNamedDBs().insert(pData);
+        CPPUNIT_ASSERT_MESSAGE( "Failed to insert \"hltable\" database range.", bInserted);
+    }
+
+    {
+        // Populate "hltable" database range with data in E10:F12
+        const char* aData[][2] = {
+            { "1", "2" },
+            { "4", "8" },
+            { "16", "32" }
+        };
+        ScAddress aPos(4,9,0);
+        ScRange aRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
+        CPPUNIT_ASSERT(aRange.aStart == aPos);
+    }
+
+    // Named expressions that use header-less Table structured references.
+    struct {
+        const char* pName;
+        const char* pExpr;
+        const char* pCounta; // expected result when used in row 10 (first data row) as argument to COUNTA()
+        const char* pSum3;   // expected result when used in row 11 (second data row) as argument to SUM().
+        const char* pSum4;   // expected result when used in row 12 (third data row) as argument to SUM().
+        const char* pSumX;   // expected result when used in row 13 (non-intersecting) as argument to SUM().
+    } aHlNames[] = {
+        { "hl_all",                          "hltable[[#All]]",                          "6", "63", "63", "63" },
+        { "hl_data_implicit",                "hltable[]",                                "6", "63", "63", "63" },
+        { "hl_data",                         "hltable[[#Data]]",                         "6", "63", "63", "63" },
+        { "hl_headers",                      "hltable[[#Headers]]",                      "1", "#REF!", "#REF!", "#REF!" },
+        { "hl_column1",                      "hltable[[Column1]]",                       "3", "21", "21", "21" },
+        { "hl_column2",                      "hltable[[Column2]]",                       "3", "42", "42", "42" },
+        { "hl_data_column1",                 "hltable[[#Data];[Column1]]",               "3", "21", "21", "21" },
+        { "hl_data_column2",                 "hltable[[#Data];[Column2]]",               "3", "42", "42", "42" },
+        { "hl_this_row",                     "hltable[[#This Row]]",                     "2", "12", "48", "#VALUE!" },
+        { "hl_this_row_column1",             "hltable[[#This Row];[Column1]]",           "1",  "4", "16", "#VALUE!" },
+        { "hl_this_row_column2",             "hltable[[#This Row];[Column2]]",           "1",  "8", "32", "#VALUE!" },
+        { "hl_this_row_range_column_1_to_2", "hltable[[#This Row];[Column1]:[Column2]]", "2", "12", "48", "#VALUE!" }
+    };
+
+    {
+        // Insert named expressions.
+        ScRangeName* pGlobalNames = m_pDoc->GetRangeName();
+        CPPUNIT_ASSERT_MESSAGE("Failed to obtain global named expression object.", pGlobalNames);
+
+        for (size_t i = 0, n = SAL_N_ELEMENTS(aHlNames); i < n; ++i)
+        {
+            // Choose base position that does not intersect with the database
+            // range definition to test later use of [#This Row] results in
+            // proper rows.
+            ScRangeData* pName = new ScRangeData(
+                    m_pDoc, OUString::createFromAscii(aHlNames[i].pName), OUString::createFromAscii(aHlNames[i].pExpr),
+                    ScAddress(6,12,0), RT_NAME, formula::FormulaGrammar::GRAM_NATIVE);
+            bool bInserted = pGlobalNames->insert(pName);
+            CPPUNIT_ASSERT_MESSAGE(
+                    OString("Failed to insert named expression "+ OString(aHlNames[i].pName) +".").getStr(), bInserted);
+        }
+    }
+
+    // Use the named expressions in COUNTA() formulas, on row 10 that intersects.
+    for (size_t i = 0, n = SAL_N_ELEMENTS(aHlNames); i < n; ++i)
+    {
+        OUString aFormula( "=COUNTA(" + OUString::createFromAscii( aHlNames[i].pName) + ")");
+        ScAddress aPos(7+i,9,0);
+        m_pDoc->SetString( aPos, aFormula);
+        // For easier "debugability" have position and formula in assertion.
+        OUString aPrefix( aPos.Format(SCA_VALID) + " " + aFormula + " : ");
+        CPPUNIT_ASSERT_EQUAL( aPrefix + OUString::createFromAscii( aHlNames[i].pCounta),
+                aPrefix + m_pDoc->GetString( aPos));
+    }
+
+    // Use the named expressions in SUM() formulas, on row 11 that intersects.
+    for (size_t i = 0, n = SAL_N_ELEMENTS(aHlNames); i < n; ++i)
+    {
+        OUString aFormula( "=SUM(" + OUString::createFromAscii( aHlNames[i].pName) + ")");
+        ScAddress aPos(7+i,10,0);
+        m_pDoc->SetString( aPos, aFormula);
+        // For easier "debugability" have position and formula in assertion.
+        OUString aPrefix( aPos.Format(SCA_VALID) + " " + aFormula + " : ");
+        CPPUNIT_ASSERT_EQUAL( aPrefix + OUString::createFromAscii( aHlNames[i].pSum3),
+                aPrefix + m_pDoc->GetString( aPos));
+    }
+
+    // Use the named expressions in SUM() formulas, on row 12 that intersects.
+    for (size_t i = 0, n = SAL_N_ELEMENTS(aHlNames); i < n; ++i)
+    {
+        OUString aFormula( "=SUM(" + OUString::createFromAscii( aHlNames[i].pName) + ")");
+        ScAddress aPos(7+i,11,0);
+        m_pDoc->SetString( aPos, aFormula);
+        // For easier "debugability" have position and formula in assertion.
+        OUString aPrefix( aPos.Format(SCA_VALID) + " " + aFormula + " : ");
+        CPPUNIT_ASSERT_EQUAL( aPrefix + OUString::createFromAscii( aHlNames[i].pSum4),
+                aPrefix + m_pDoc->GetString( aPos));
+    }
+
+    // Use the named expressions in SUM() formulas, on row 13 that does not intersect.
+    for (size_t i = 0, n = SAL_N_ELEMENTS(aHlNames); i < n; ++i)
+    {
+        OUString aFormula( "=SUM(" + OUString::createFromAscii( aHlNames[i].pName) + ")");
+        ScAddress aPos(7+i,12,0);
+        m_pDoc->SetString( aPos, aFormula);
+        // For easier "debugability" have position and formula in assertion.
+        OUString aPrefix( aPos.Format(SCA_VALID) + " " + aFormula + " : ");
+        CPPUNIT_ASSERT_EQUAL( aPrefix + OUString::createFromAscii( aHlNames[i].pSumX),
+                aPrefix + m_pDoc->GetString( aPos));
+    }
+
+    // Insert a column at column F to extend database range from column E,F to
+    // E,F,G. Use ScDocFunc so RefreshDirtyTableColumnNames() is called.
+    rDocFunc.InsertCells(ScRange(5,0,0,5,MAXROW,0), &aMark, INS_INSCOLS_BEFORE, false, true);
+
+    // Re-verify the named expression in SUM() formula, on row 12 that
+    // intersects, now starting at column I, still works.
+    m_pDoc->CalcAll();
+    for (size_t i = 0, n = SAL_N_ELEMENTS(aHlNames); i < n; ++i)
+    {
+        OUString aFormula( "=SUM(" + OUString::createFromAscii( aHlNames[i].pName) + ")");
+        ScAddress aPos(8+i,11,0);
+        // For easier "debugability" have position and formula in assertion.
+        OUString aPrefix( aPos.Format(SCA_VALID) + " " + aFormula + " : ");
+        CPPUNIT_ASSERT_EQUAL( aPrefix + OUString::createFromAscii( aHlNames[i].pSum4),
+                aPrefix + m_pDoc->GetString( aPos));
+    }
+
+    const char* pColumn3Formula = "=SUM(hltable[[#Data];[Column3]])";
+    {
+        // Populate "hltable" database range with data in newly inserted
+        // column, F10:F12 plus a table formula in F14. The new header should
+        // result in the internal table column name "Column3" that is used in
+        // the formula.
+        const char* aData[][1] = {
+            { "64" },
+            { "128" },
+            { "256" },
+            { "" },
+            { pColumn3Formula }
+        };
+        ScAddress aPos(5,9,0);
+        ScRange aRange = insertRangeData(m_pDoc, aPos, aData, SAL_N_ELEMENTS(aData));
+        CPPUNIT_ASSERT(aRange.aStart == aPos);
+    }
+
+    // Verify the formula result in F14 (64+128+256=448).
+    {
+        OUString aFormula( OUString::createFromAscii( pColumn3Formula));
+        ScAddress aPos(5,13,0);
+        OUString aPrefix( aPos.Format(SCA_VALID) + " " + aFormula + " : ");
+        CPPUNIT_ASSERT_EQUAL( aPrefix + OUString("448"), aPrefix + m_pDoc->GetString( aPos));
+    }
+
     m_pDoc->DeleteTab(0);
 }
 
commit 8721b1c02fbbc36ca0848ca36a5094d7fbcebc96
Author: Eike Rathke <erack at redhat.com>
Date:   Tue Sep 8 20:43:01 2015 +0200

    TableRef: for header-less ScDBData generate table column names already
    
    ... during insertion as NamedDB, as they don't need to access header
    cells and thus don't have to add a (fake) dirty range.
    
    Change-Id: Iab3f1406e53ca39ad0820a86def70323a41ce241

diff --git a/sc/source/core/tool/dbdata.cxx b/sc/source/core/tool/dbdata.cxx
index c5b14a0..19c460b 100644
--- a/sc/source/core/tool/dbdata.cxx
+++ b/sc/source/core/tool/dbdata.cxx
@@ -771,7 +771,7 @@ void ScDBData::RefreshTableColumnNames( ScDocument* pDoc )
     ::std::vector<OUString> aNewNames;
     aNewNames.resize( nEndCol - nStartCol + 1);
     bool bHaveEmpty = false;
-    if (!HasHeader())
+    if (!HasHeader() || !pDoc)
         bHaveEmpty = true;  // Assume we have empty ones and fill below.
     else
     {
@@ -1065,10 +1065,17 @@ ScDBCollection::NamedDBs::NamedDBs(const NamedDBs& r)
                 p->StartTableColumnNamesListener(); // needs the container be set already
                 if (p->AreTableColumnNamesDirty())
                 {
-                    // Refresh table column names in next round.
-                    ScRange aHeader( p->GetHeaderArea());
-                    if (aHeader.IsValid())
-                        maDirtyTableColumnNames.Join( aHeader);
+                    if (p->HasHeader())
+                    {
+                        // Refresh table column names in next round.
+                        maDirtyTableColumnNames.Join( p->GetHeaderArea());
+                    }
+                    else
+                    {
+                        // Header-less table can generate its column names
+                        // already without accessing the document.
+                        p->RefreshTableColumnNames( nullptr);
+                    }
                 }
             }
         }
@@ -1135,10 +1142,17 @@ bool ScDBCollection::NamedDBs::insert(ScDBData* p)
             p->StartTableColumnNamesListener(); // needs the container be set already
             if (p->AreTableColumnNamesDirty())
             {
-                // Refresh table column names in next round.
-                ScRange aHeader( p->GetHeaderArea());
-                if (aHeader.IsValid())
-                    maDirtyTableColumnNames.Join( aHeader);
+                if (p->HasHeader())
+                {
+                    // Refresh table column names in next round.
+                    maDirtyTableColumnNames.Join( p->GetHeaderArea());
+                }
+                else
+                {
+                    // Header-less table can generate its column names
+                    // already without accessing the document.
+                    p->RefreshTableColumnNames( nullptr);
+                }
             }
         }
 


More information about the Libreoffice-commits mailing list