[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-6.0' - 5 commits - sc/inc sc/qa sc/source sd/qa

Andras Timar (via logerrit) logerrit at kemper.freedesktop.org
Wed Apr 24 20:49:26 UTC 2019


 sc/inc/column.hxx                            |   27 
 sc/inc/sharedformula.hxx                     |   13 
 sc/qa/unit/ucalc.hxx                         |    8 
 sc/qa/unit/ucalc_sharedformula.cxx           |  773 +++++++++++++++++++++++++++
 sc/source/core/data/column.cxx               |    4 
 sc/source/core/data/column3.cxx              |  324 +++++++++--
 sc/source/core/data/column4.cxx              |   27 
 sc/source/core/data/table2.cxx               |    2 
 sc/source/core/tool/sharedformula.cxx        |   46 +
 sd/qa/unit/tiledrendering/tiledrendering.cxx |    2 
 10 files changed, 1151 insertions(+), 75 deletions(-)

New commits:
commit 23b03b5e21d936d1fdb2096c1c57b932a1c6f9e3
Author:     Andras Timar <andras.timar at collabora.com>
AuthorDate: Wed Apr 24 22:43:49 2019 +0200
Commit:     Andras Timar <andras.timar at collabora.com>
CommitDate: Wed Apr 24 22:48:15 2019 +0200

    disable unreliable SdTiledRenderingTest::testPasteTextOnSlide
    
    Change-Id: I5ff8d4f1a9191aec082cacafb571e3171f464550

diff --git a/sd/qa/unit/tiledrendering/tiledrendering.cxx b/sd/qa/unit/tiledrendering/tiledrendering.cxx
index 04d2326cfd96..b2f6a59f43cd 100644
--- a/sd/qa/unit/tiledrendering/tiledrendering.cxx
+++ b/sd/qa/unit/tiledrendering/tiledrendering.cxx
@@ -2081,6 +2081,7 @@ void SdTiledRenderingTest::testTdf115783()
 
 void SdTiledRenderingTest::testPasteTextOnSlide()
 {
+#if 0
     // Load the document.
     comphelper::LibreOfficeKit::setActive();
     SdXImpressDocument* pXImpressDocument = createDoc("paste_text_onslide.odp");
@@ -2191,6 +2192,7 @@ void SdTiledRenderingTest::testPasteTextOnSlide()
     CPPUNIT_ASSERT_DOUBLES_EQUAL(static_cast<long>(7430), aPos.getY(), 100);
 
     comphelper::LibreOfficeKit::setActive(false);
+#endif
 }
 
 void SdTiledRenderingTest::testTdf115873()
commit 7a4657825a258b2c83cbb23dabaa29937bb0bdbc
Author:     Eike Rathke <erack at redhat.com>
AuthorDate: Tue Oct 16 11:22:20 2018 +0200
Commit:     Andras Timar <andras.timar at collabora.com>
CommitDate: Wed Apr 24 22:48:14 2019 +0200

    Unit test deleting shared formula group top cell, tdf#119623
    
    Change-Id: I9a497b9d9ae09c8764f62549a60c8a2a952bc9e9
    Reviewed-on: https://gerrit.libreoffice.org/61822
    Reviewed-by: Eike Rathke <erack at redhat.com>
    Tested-by: Jenkins

diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index f2304ccb823e..cd1f6b06914b 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -398,6 +398,7 @@ public:
     void testSharedFormulaUnshareAreaListeners();
     void testSharedFormulaListenerDeleteArea();
     void testSharedFormulaUpdateOnReplacement();
+    void testSharedFormulaDeleteTopCell();
     void testSharedFormulaCutCopyMoveIntoRef();
     void testSharedFormulaCutCopyMoveWithRef();
     void testSharedFormulaCutCopyMoveWithinRun();
@@ -736,6 +737,7 @@ public:
     CPPUNIT_TEST(testSharedFormulaUnshareAreaListeners);
     CPPUNIT_TEST(testSharedFormulaListenerDeleteArea);
     CPPUNIT_TEST(testSharedFormulaUpdateOnReplacement);
+    CPPUNIT_TEST(testSharedFormulaDeleteTopCell);
     CPPUNIT_TEST(testSharedFormulaCutCopyMoveIntoRef);
     CPPUNIT_TEST(testSharedFormulaCutCopyMoveWithRef);
     CPPUNIT_TEST(testSharedFormulaCutCopyMoveWithinRun);
diff --git a/sc/qa/unit/ucalc_sharedformula.cxx b/sc/qa/unit/ucalc_sharedformula.cxx
index e2205ba98358..8acbb06a1c4d 100644
--- a/sc/qa/unit/ucalc_sharedformula.cxx
+++ b/sc/qa/unit/ucalc_sharedformula.cxx
@@ -2344,6 +2344,48 @@ void Test::testSharedFormulaUpdateOnReplacement()
     m_pDoc->DeleteTab(0);
 }
 
+void Test::testSharedFormulaDeleteTopCell()
+{
+    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
+
+    m_pDoc->InsertTab(0, "Test");
+
+    const char* pData[][2] = {
+        { "=SUM(B$1:B$2)", "1" },
+        { "=SUM(B$1:B$2)", "2" }
+    };
+
+    insertRangeData( m_pDoc, ScAddress(0,0,0), pData, SAL_N_ELEMENTS(pData));
+
+    // Check that A1:A2 is a formula group.
+    const ScFormulaCell* pFC = m_pDoc->GetFormulaCell( ScAddress(0,0,0));
+    CPPUNIT_ASSERT(pFC);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(2), pFC->GetSharedLength());
+
+    // Check results A1:A2.
+    CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue( ScAddress(0,0,0)));
+    CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue( ScAddress(0,1,0)));
+
+    // Delete cell A1.
+    ScMarkData aMark;
+    aMark.SelectOneTable(0);
+    getDocShell().GetDocFunc().DeleteCell( ScAddress(0,0,0), aMark, InsertDeleteFlags::CONTENTS, false);
+    // Check it's gone.
+    CPPUNIT_ASSERT(!m_pDoc->GetFormulaCell( ScAddress(0,0,0)));
+
+    // Check result A2.
+    CPPUNIT_ASSERT_EQUAL( 3.0, m_pDoc->GetValue( ScAddress(0,1,0)));
+
+    // Replace B1 with 4.
+    m_pDoc->SetString( ScAddress(1,0,0), "4");
+
+    // Check result A2.
+    CPPUNIT_ASSERT_EQUAL( 6.0, m_pDoc->GetValue( ScAddress(0,1,0)));
+
+    m_pDoc->DeleteTab(0);
+}
+
 
 void Test::testSharedFormulaCutCopyMoveIntoRef()
 {
commit c444aab457f1383cb94f9ab7b39ae87d37a4c817
Author:     Eike Rathke <erack at redhat.com>
AuthorDate: Mon Oct 15 23:10:07 2018 +0200
Commit:     Andras Timar <andras.timar at collabora.com>
CommitDate: Wed Apr 24 22:48:14 2019 +0200

    Resolves: tdf#119623 record group positions also for top cells
    
    So listeners can be re-established for remaining grouped cells if
    top cell is deleted (which ends listening and probably was the
    cause to exclude them here).
    
    Change-Id: Ic91b74c65013452d56b5cfbc132722c4314743c8
    Reviewed-on: https://gerrit.libreoffice.org/61808
    Reviewed-by: Eike Rathke <erack at redhat.com>
    Tested-by: Jenkins

diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx
index 520bd815873c..4739eace586b 100644
--- a/sc/source/core/data/column4.cxx
+++ b/sc/source/core/data/column4.cxx
@@ -1522,10 +1522,12 @@ void ScColumn::EndListeningIntersectedGroups(
     {
         ScFormulaCell* pFC = sc::formula_block::at(*it->data, aPos.second);
         ScFormulaCellGroupRef xGroup = pFC->GetCellGroup();
-        if (xGroup && !pFC->IsSharedTop())
+        if (xGroup)
         {
-            // End listening.
-            pFC->EndListeningTo(rCxt);
+            if (!pFC->IsSharedTop())
+                // End listening.
+                pFC->EndListeningTo(rCxt);
+
             if (pGroupPos)
                 // Record the position of the top cell of the group.
                 pGroupPos->push_back(xGroup->mpTopCell->aPos);
@@ -1538,10 +1540,12 @@ void ScColumn::EndListeningIntersectedGroups(
     {
         ScFormulaCell* pFC = sc::formula_block::at(*it->data, aPos.second);
         ScFormulaCellGroupRef xGroup = pFC->GetCellGroup();
-        if (xGroup && !pFC->IsSharedTop())
+        if (xGroup)
         {
-            // End listening.
-            pFC->EndListeningTo(rCxt);
+            if (!pFC->IsSharedTop())
+                // End listening.
+                pFC->EndListeningTo(rCxt);
+
             if (pGroupPos)
             {
                 // Record the position of the bottom cell of the group.
commit 46968a28c47b12ce4557fda5dd96641f3e0a4fa6
Author:     Eike Rathke <erack at redhat.com>
AuthorDate: Sun Mar 17 19:58:12 2019 +0100
Commit:     Andras Timar <andras.timar at collabora.com>
CommitDate: Wed Apr 24 22:48:14 2019 +0200

    Unit tests for tdf#121002 tdf#120013 tdf#123714 tdf#123736
    
     This is a combination of 4 commits.
    
    Add unit tests for tdf#123736 and related unshared/regrouped listening
    
    Reviewed-on: https://gerrit.libreoffice.org/69372
    Tested-by: Jenkins
    Reviewed-by: Eike Rathke <erack at redhat.com>
    (cherry picked from commit 8925bd2efca8dd07a3ac044ecbc6505bb7bfa0a6)
    
    Unit test for cut copy move into shared formula group reference, tdf#123714
    
    Reviewed-on: https://gerrit.libreoffice.org/69453
    Reviewed-by: Eike Rathke <erack at redhat.com>
    Tested-by: Jenkins
    (cherry picked from commit f81d532648ccbbd08d3cb568eadc9f402dac67ad)
    
    Unit test for cut copy move with a group reference adjusting along, tdf#121002
    
    Reviewed-on: https://gerrit.libreoffice.org/69532
    Reviewed-by: Eike Rathke <erack at redhat.com>
    Tested-by: Jenkins
    (cherry picked from commit 92657eed57548511f26f0c22f1bbc47d554c8b5b)
    
    bcf03f5068630c18eeecf2625cdff7ec1704d292
    4f3731e2236f1b8be97a6f5d21e32e678610fecb
    
    Unit test for cut copy move intersecting a formula group run, tdf#120013
    
    Reviewed-on: https://gerrit.libreoffice.org/69568
    Tested-by: Jenkins
    Reviewed-by: Eike Rathke <erack at redhat.com>
    (cherry picked from commit 6280b5c1c62ad40b5b9780a93c7cbee9ca0260f8)
    
    ce7e1e42dba7bfbc2db6a60e4457c3610430b87e
    
    Change-Id: If48e6d75288b42b47c90f3104006b7c52982c9f6
    Reviewed-on: https://gerrit.libreoffice.org/69555
    Tested-by: Jenkins
    Reviewed-by: Christian Lohmaier <lohmaier+LibreOffice at googlemail.com>

diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index 74729debe9ea..f2304ccb823e 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -398,6 +398,9 @@ public:
     void testSharedFormulaUnshareAreaListeners();
     void testSharedFormulaListenerDeleteArea();
     void testSharedFormulaUpdateOnReplacement();
+    void testSharedFormulaCutCopyMoveIntoRef();
+    void testSharedFormulaCutCopyMoveWithRef();
+    void testSharedFormulaCutCopyMoveWithinRun();
     void testFormulaPosition();
     void testFormulaWizardSubformula();
 
@@ -733,6 +736,9 @@ public:
     CPPUNIT_TEST(testSharedFormulaUnshareAreaListeners);
     CPPUNIT_TEST(testSharedFormulaListenerDeleteArea);
     CPPUNIT_TEST(testSharedFormulaUpdateOnReplacement);
+    CPPUNIT_TEST(testSharedFormulaCutCopyMoveIntoRef);
+    CPPUNIT_TEST(testSharedFormulaCutCopyMoveWithRef);
+    CPPUNIT_TEST(testSharedFormulaCutCopyMoveWithinRun);
     CPPUNIT_TEST(testFormulaPosition);
     CPPUNIT_TEST(testFormulaWizardSubformula);
     CPPUNIT_TEST(testMixData);
diff --git a/sc/qa/unit/ucalc_sharedformula.cxx b/sc/qa/unit/ucalc_sharedformula.cxx
index b0de3278653c..e2205ba98358 100644
--- a/sc/qa/unit/ucalc_sharedformula.cxx
+++ b/sc/qa/unit/ucalc_sharedformula.cxx
@@ -1645,6 +1645,21 @@ void Test::testSharedFormulaAbsCellListener()
     m_pDoc->DeleteTab(0);
 }
 
+static double checkNewValuesNotification( ScDocument* pDoc, const ScAddress& rOrgPos )
+{
+    ScAddress aPos(rOrgPos);
+    aPos.IncCol();
+    pDoc->SetValues( aPos, {1024.0, 2048.0, 4096.0, 8192.0, 16384.0});
+    aPos = rOrgPos;
+    double fVal = 0.0;
+    for (SCROW i=0; i < 5; ++i)
+    {
+        fVal += pDoc->GetValue(aPos);
+        aPos.IncRow();
+    }
+    return fVal;
+}
+
 void Test::testSharedFormulaUnshareAreaListeners()
 {
     sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
@@ -1673,6 +1688,460 @@ void Test::testSharedFormulaUnshareAreaListeners()
     CPPUNIT_ASSERT_EQUAL(17.0, m_pDoc->GetValue(ScAddress(0,0,0)));
     CPPUNIT_ASSERT_EQUAL(40.0, m_pDoc->GetValue(ScAddress(0,2,0)));
 
+    clearRange(m_pDoc, ScRange( 0,0,0, 1,3,0));
+
+    for (int nRun = 0; nRun < 7; ++nRun)
+    {
+        // Data in A2:C6
+        const ScAddress aOrgPos(0,1,0);
+        const char* pData2[][3] = {
+            { "=SUM(B2:C2)",   "1",   "2" },
+            { "=SUM(B3:C3)",   "4",   "8" },
+            { "=SUM(B4:C4)",  "16",  "32" },
+            { "=SUM(B5:C5)",  "64", "128" },
+            { "=SUM(B6:C6)", "256", "512" },
+        };
+        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));
+
+        // Check that A2:A6 is a formula group.
+        pFC = m_pDoc->GetFormulaCell(aOrgPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A2", pFC->IsSharedTop());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aOrgPos.Row(), pFC->GetSharedTopRow());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(5), pFC->GetSharedLength());
+
+        // Overwrite and thus unshare formula in A3.
+        // Check different code paths with different methods.
+        ScAddress aPos(aOrgPos);
+        aPos.IncRow(2);
+        switch (nRun)
+        {
+            case 0:
+                // Directly set a different formula cell, which bypasses
+                // ScDocument::SetString(), mimicking formula input in view.
+                {
+                    ScFormulaCell* pCell = new ScFormulaCell( m_pDoc, aPos, "=B4");
+                    ScDocFunc& rDocFunc = getDocShell().GetDocFunc();
+                    rDocFunc.SetFormulaCell( aPos, pCell, false);
+                }
+            break;
+            case 1:
+                m_pDoc->SetString( aPos, "=B4");    // set formula
+            break;
+            case 2:
+                m_pDoc->SetString( aPos, "x");      // set string
+            break;
+            case 3:
+                m_pDoc->SetString( aPos, "4096");   // set number/numeric
+            break;
+            case 4:
+                m_pDoc->SetValue( aPos, 4096.0);    // set numeric
+            break;
+            case 5:
+                m_pDoc->SetValues( aPos, {4096.0}); // set numeric vector
+            break;
+            case 6:
+                // Set formula cell vector.
+                {
+                    ScFormulaCell* pCell = new ScFormulaCell( m_pDoc, aPos, "=B4");
+                    std::vector<ScFormulaCell*> aCells;
+                    aCells.push_back(pCell);
+                    m_pDoc->SetFormulaCells( aPos, aCells);
+                }
+            break;
+        }
+
+        // Check that A2:A3 and A5:A6 are two formula groups.
+        aPos = aOrgPos;
+        pFC = m_pDoc->GetFormulaCell(aPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A2", pFC->IsSharedTop());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
+        aPos.IncRow(3);
+        pFC = m_pDoc->GetFormulaCell(aPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A5", pFC->IsSharedTop());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
+
+        // Check that listeners were set up and formulas are updated when B2:B6
+        // get new values input (tdf#123736).
+        aPos = aOrgPos;
+        aPos.IncCol();
+        m_pDoc->SetValues( aPos, {1024.0, 2048.0, 4096.0, 8192.0, 16384.0});
+
+        aPos = aOrgPos;
+        CPPUNIT_ASSERT_EQUAL(1026.0, m_pDoc->GetValue(aPos));
+        aPos.IncRow();
+        CPPUNIT_ASSERT_EQUAL(2056.0, m_pDoc->GetValue(aPos));
+        aPos.IncRow();
+        if (nRun != 2)  // if not string
+            CPPUNIT_ASSERT_EQUAL(4096.0, m_pDoc->GetValue(aPos));
+        aPos.IncRow();
+        CPPUNIT_ASSERT_EQUAL(8320.0, m_pDoc->GetValue(aPos));
+        aPos.IncRow();
+        CPPUNIT_ASSERT_EQUAL(16896.0, m_pDoc->GetValue(aPos));
+
+        clearRange(m_pDoc, ScRange( 0,0,0, 2,5,0));
+    }
+
+    // Check detach/regroup combinations of overlapping when setting formula
+    // cell vectors.
+    {
+        // Fixed data in A3:C7, modified formula range A1:A9
+        const ScAddress aOrgPos(0,2,0);
+        ScAddress aPos( ScAddress::UNINITIALIZED);
+        ScFormulaCell* pCell;
+        std::vector<ScFormulaCell*> aCells;
+        const char* pData2[][3] = {
+            { "=SUM(B3:C3)",   "1",   "2" },
+            { "=SUM(B4:C4)",   "4",   "8" },
+            { "=SUM(B5:C5)",  "16",  "32" },
+            { "=SUM(B6:C6)",  "64", "128" },
+            { "=SUM(B7:C7)", "256", "512" },
+        };
+
+        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));
+
+        // Add grouping formulas in A1:A2, keep A3:A7
+        aPos = ScAddress(0,0,0);
+        std::vector<ScFormulaCell*>().swap( aCells);
+        pCell = new ScFormulaCell( m_pDoc, aPos, "=SUM(B1:C1)");
+        aCells.push_back(pCell);
+        aPos.IncRow();
+        pCell = new ScFormulaCell( m_pDoc, aPos, "=SUM(B2:C2)");
+        aCells.push_back(pCell);
+        aPos.IncRow(-1);
+        m_pDoc->SetFormulaCells( aPos, aCells);
+
+        // Check it is one formula group.
+        pFC = m_pDoc->GetFormulaCell(aPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A1", pFC->IsSharedTop());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(7), pFC->GetSharedLength());
+
+        // Check notification of setting new values.
+        CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));
+
+        clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));
+
+        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));
+
+        // Add formulas in A1:A2, keep A3:A7
+        aPos = ScAddress(0,0,0);
+        std::vector<ScFormulaCell*>().swap( aCells);
+        pCell = new ScFormulaCell( m_pDoc, aPos, "=B1+C1");
+        aCells.push_back(pCell);
+        aPos.IncRow();
+        pCell = new ScFormulaCell( m_pDoc, aPos, "=B2+C2");
+        aCells.push_back(pCell);
+        aPos.IncRow(-1);
+        m_pDoc->SetFormulaCells( aPos, aCells);
+
+        // Check formula groups.
+        pFC = m_pDoc->GetFormulaCell(aPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A1", pFC->IsSharedTop());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
+        aPos.IncRow(2);
+        pFC = m_pDoc->GetFormulaCell(aPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A3", pFC->IsSharedTop());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(5), pFC->GetSharedLength());
+
+        // Check notification of setting new values.
+        CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));
+
+        clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));
+
+        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));
+
+        // Add formula in A2, overwrite A3, keep A4:A7
+        aPos = ScAddress(0,1,0);
+        std::vector<ScFormulaCell*>().swap( aCells);
+        pCell = new ScFormulaCell( m_pDoc, aPos, "=B2+C2");
+        aCells.push_back(pCell);
+        aPos.IncRow();
+        pCell = new ScFormulaCell( m_pDoc, aPos, "=B3+C3");
+        aCells.push_back(pCell);
+        aPos.IncRow(-1);
+        m_pDoc->SetFormulaCells( aPos, aCells);
+
+        // Check formula groups.
+        pFC = m_pDoc->GetFormulaCell(aPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A2", pFC->IsSharedTop());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
+        aPos.IncRow(2);
+        pFC = m_pDoc->GetFormulaCell(aPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A4", pFC->IsSharedTop());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(4), pFC->GetSharedLength());
+
+        // Check notification of setting new values.
+        CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));
+
+        clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));
+
+        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));
+
+        // Overwrite A3:A4, keep A5:A7
+        aPos = ScAddress(0,2,0);
+        std::vector<ScFormulaCell*>().swap( aCells);
+        pCell = new ScFormulaCell( m_pDoc, aPos, "=B3+C3");
+        aCells.push_back(pCell);
+        aPos.IncRow();
+        pCell = new ScFormulaCell( m_pDoc, aPos, "=B4+C4");
+        aCells.push_back(pCell);
+        aPos.IncRow(-1);
+        m_pDoc->SetFormulaCells( aPos, aCells);
+
+        // Check formula groups.
+        aPos = aOrgPos;
+        pFC = m_pDoc->GetFormulaCell(aPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A3", pFC->IsSharedTop());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
+        aPos.IncRow(2);
+        pFC = m_pDoc->GetFormulaCell(aPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A5", pFC->IsSharedTop());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(3), pFC->GetSharedLength());
+
+        // Check notification of setting new values.
+        CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));
+
+        clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));
+
+        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));
+
+        // Keep A3, overwrite A4:A5, keep A6:A7
+        aPos = ScAddress(0,3,0);
+        std::vector<ScFormulaCell*>().swap( aCells);
+        pCell = new ScFormulaCell( m_pDoc, aPos, "=B4+C4");
+        aCells.push_back(pCell);
+        aPos.IncRow();
+        pCell = new ScFormulaCell( m_pDoc, aPos, "=B5+C5");
+        aCells.push_back(pCell);
+        aPos.IncRow(-1);
+        m_pDoc->SetFormulaCells( aPos, aCells);
+
+        // Check formula groups.
+        aPos = aOrgPos;
+        pFC = m_pDoc->GetFormulaCell(aPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A3", !pFC->IsSharedTop());
+        aPos.IncRow(1);
+        pFC = m_pDoc->GetFormulaCell(aPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A4", pFC->IsSharedTop());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
+        aPos.IncRow(2);
+        pFC = m_pDoc->GetFormulaCell(aPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A6", pFC->IsSharedTop());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
+
+        // Check notification of setting new values.
+        CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));
+
+        clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));
+
+        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));
+
+        // Keep A3:A4, overwrite A5:A6, keep A7
+        aPos = ScAddress(0,4,0);
+        std::vector<ScFormulaCell*>().swap( aCells);
+        pCell = new ScFormulaCell( m_pDoc, aPos, "=B5+C5");
+        aCells.push_back(pCell);
+        aPos.IncRow();
+        pCell = new ScFormulaCell( m_pDoc, aPos, "=B6+C6");
+        aCells.push_back(pCell);
+        aPos.IncRow(-1);
+        m_pDoc->SetFormulaCells( aPos, aCells);
+
+        // Check formula groups.
+        aPos = aOrgPos;
+        pFC = m_pDoc->GetFormulaCell(aPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A3", pFC->IsSharedTop());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
+        aPos.IncRow(2);
+        pFC = m_pDoc->GetFormulaCell(aPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A5", pFC->IsSharedTop());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
+        aPos.IncRow(2);
+        pFC = m_pDoc->GetFormulaCell(aPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A7", !pFC->IsSharedTop());
+
+        // Check notification of setting new values.
+        CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));
+
+        clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));
+
+        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));
+
+        // Keep A3:A5, overwrite A6:A7
+        aPos = ScAddress(0,5,0);
+        std::vector<ScFormulaCell*>().swap( aCells);
+        pCell = new ScFormulaCell( m_pDoc, aPos, "=B6+C6");
+        aCells.push_back(pCell);
+        aPos.IncRow();
+        pCell = new ScFormulaCell( m_pDoc, aPos, "=B7+C7");
+        aCells.push_back(pCell);
+        aPos.IncRow(-1);
+        m_pDoc->SetFormulaCells( aPos, aCells);
+
+        // Check formula groups.
+        aPos = aOrgPos;
+        pFC = m_pDoc->GetFormulaCell(aPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A3", pFC->IsSharedTop());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(3), pFC->GetSharedLength());
+        aPos.IncRow(3);
+        pFC = m_pDoc->GetFormulaCell(aPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A6", pFC->IsSharedTop());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
+
+        // Check notification of setting new values.
+        CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));
+
+        clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));
+
+        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));
+
+        // Keep A3:A6, overwrite A7, add A8
+        aPos = ScAddress(0,6,0);
+        std::vector<ScFormulaCell*>().swap( aCells);
+        pCell = new ScFormulaCell( m_pDoc, aPos, "=B7+C7");
+        aCells.push_back(pCell);
+        aPos.IncRow();
+        pCell = new ScFormulaCell( m_pDoc, aPos, "=B8+C8");
+        aCells.push_back(pCell);
+        aPos.IncRow(-1);
+        m_pDoc->SetFormulaCells( aPos, aCells);
+
+        // Check formula groups.
+        aPos = aOrgPos;
+        pFC = m_pDoc->GetFormulaCell(aPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A3", pFC->IsSharedTop());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(4), pFC->GetSharedLength());
+        aPos.IncRow(4);
+        pFC = m_pDoc->GetFormulaCell(aPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A7", pFC->IsSharedTop());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
+
+        // Check notification of setting new values.
+        CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));
+
+        clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));
+
+        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));
+
+        // Keep A3:A7, add A8:A9
+        aPos = ScAddress(0,7,0);
+        std::vector<ScFormulaCell*>().swap( aCells);
+        pCell = new ScFormulaCell( m_pDoc, aPos, "=B8+C8");
+        aCells.push_back(pCell);
+        aPos.IncRow();
+        pCell = new ScFormulaCell( m_pDoc, aPos, "=B9+C9");
+        aCells.push_back(pCell);
+        aPos.IncRow(-1);
+        m_pDoc->SetFormulaCells( aPos, aCells);
+
+        // Check formula groups.
+        aPos = aOrgPos;
+        pFC = m_pDoc->GetFormulaCell(aPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A3", pFC->IsSharedTop());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(5), pFC->GetSharedLength());
+        aPos.IncRow(5);
+        pFC = m_pDoc->GetFormulaCell(aPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A7", pFC->IsSharedTop());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(2), pFC->GetSharedLength());
+
+        // Check notification of setting new values.
+        CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));
+
+        clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));
+
+        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));
+
+        // Keep A3:A7, add grouping formulas in A8:A9
+        aPos = ScAddress(0,7,0);
+        std::vector<ScFormulaCell*>().swap( aCells);
+        pCell = new ScFormulaCell( m_pDoc, aPos, "=SUM(B8:C8)");
+        aCells.push_back(pCell);
+        aPos.IncRow();
+        pCell = new ScFormulaCell( m_pDoc, aPos, "=SUM(B9:C9)");
+        aCells.push_back(pCell);
+        aPos.IncRow(-1);
+        m_pDoc->SetFormulaCells( aPos, aCells);
+
+        // Check it is one formula group.
+        aPos = aOrgPos;
+        pFC = m_pDoc->GetFormulaCell(aPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A1", pFC->IsSharedTop());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(7), pFC->GetSharedLength());
+
+        // Check notification of setting new values.
+        CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));
+
+        clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));
+
+        insertRangeData(m_pDoc, aOrgPos, pData2, SAL_N_ELEMENTS(pData2));
+
+        // Overwrite grouping formulas in A4:A5
+        aPos = ScAddress(0,3,0);
+        std::vector<ScFormulaCell*>().swap( aCells);
+        pCell = new ScFormulaCell( m_pDoc, aPos, "=SUM(B4:C4)");
+        aCells.push_back(pCell);
+        aPos.IncRow();
+        pCell = new ScFormulaCell( m_pDoc, aPos, "=SUM(B5:C5)");
+        aCells.push_back(pCell);
+        aPos.IncRow(-1);
+        m_pDoc->SetFormulaCells( aPos, aCells);
+
+        // Check it is one formula group.
+        aPos = aOrgPos;
+        pFC = m_pDoc->GetFormulaCell(aPos);
+        CPPUNIT_ASSERT(pFC);
+        CPPUNIT_ASSERT_MESSAGE("A1", pFC->IsSharedTop());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared top row.", aPos.Row(), pFC->GetSharedTopRow());
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Shared length.", static_cast<SCROW>(5), pFC->GetSharedLength());
+
+        // Check notification of setting new values.
+        CPPUNIT_ASSERT_EQUAL(32426.0, checkNewValuesNotification( m_pDoc, aOrgPos));
+
+        clearRange(m_pDoc, ScRange( 0,0,0, 2,8,0));
+    }
+
     m_pDoc->DeleteTab(0);
 }
 
@@ -1876,4 +2345,266 @@ void Test::testSharedFormulaUpdateOnReplacement()
 }
 
 
+void Test::testSharedFormulaCutCopyMoveIntoRef()
+{
+    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
+
+    // tdf#123714 case 1
+    {
+        m_pDoc->InsertTab(0, "Test");
+
+        // Data in A1:C3
+        std::vector<std::vector<const char*>> aData = {
+            { "=B1", "", "1" },
+            { "=B2", "", "1" },
+            { "=B3", "", ""  }
+        };
+        const ScAddress aOrgPos(0,0,0);
+        insertRangeData( m_pDoc, aOrgPos, aData);
+
+        ScMarkData aMark;
+        aMark.SelectOneTable(0);
+
+        // Set up clip document.
+        ScDocument aClipDoc(SCDOCMODE_CLIP);
+        aClipDoc.ResetClip(m_pDoc, &aMark);
+        // Cut C1:C2 to clipboard.
+        cutToClip( getDocShell(), ScRange(2,0,0, 2,1,0), &aClipDoc, false);
+
+        // Paste to B1:B2
+        ScRange aPasteRange(1,0,0, 1,1,0);
+        aMark.SetMarkArea(aPasteRange);
+        m_pDoc->CopyFromClip( aPasteRange, aMark, InsertDeleteFlags::CONTENTS, nullptr, &aClipDoc);
+
+        // Check data in A1:A2 after Paste.
+        ScAddress aPos(aOrgPos);
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("A1", 1.0, m_pDoc->GetValue(aPos));
+        aPos.IncRow();
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("A2", 1.0, m_pDoc->GetValue(aPos));
+
+        m_pDoc->DeleteTab(0);
+    }
+
+    // tdf#123714 case 2
+    {
+        m_pDoc->InsertTab(0, "Test");
+
+        // Data in A1:C3
+        std::vector<std::vector<const char*>> aData = {
+            {  "1",   "2", "=SUM(A1:B1)" },
+            {  "4",   "8", "=SUM(A2:B2)" },
+            { "16",  "32", "=SUM(A3:B3)" },
+            { "64", "128", "=SUM(A4:B4)" },
+        };
+        const ScAddress aOrgPos(0,0,0);
+        insertRangeData( m_pDoc, aOrgPos, aData);
+
+        ScAddress aPos;
+        // Check results in C1:C4
+        const double fVec0[] = { 3.0, 12.0, 48.0, 192.0 };
+        aPos = ScAddress(2,0,0);
+        for (SCROW i=0; i < 4; ++i)
+        {
+            CPPUNIT_ASSERT_EQUAL( fVec0[i], m_pDoc->GetValue(aPos));
+            aPos.IncRow();
+        }
+
+        ScMarkData aMark;
+        aMark.SelectOneTable(0);
+
+        // Set up clip document.
+        ScDocument aClipDoc(SCDOCMODE_CLIP);
+        aClipDoc.ResetClip(m_pDoc, &aMark);
+        // Cut B1:B2 to clipboard.
+        cutToClip( getDocShell(), ScRange(1,0,0, 1,1,0), &aClipDoc, false);
+
+        // Check results in C1:C4 after Cut.
+        const double fVec1[] = { 1.0, 4.0, 48.0, 192.0 };
+        aPos = ScAddress(2,0,0);
+        for (SCROW i=0; i < 4; ++i)
+        {
+            CPPUNIT_ASSERT_EQUAL( fVec1[i], m_pDoc->GetValue(aPos));
+            aPos.IncRow();
+        }
+
+        // Paste to B3:B4
+        ScRange aPasteRange(1,2,0, 1,3,0);
+        aMark.SetMarkArea(aPasteRange);
+        m_pDoc->CopyFromClip( aPasteRange, aMark, InsertDeleteFlags::CONTENTS, nullptr, &aClipDoc);
+
+        // Check results in C1:C4 after Paste.
+        const double fVec2[] = { 1.0, 4.0, 18.0, 72.0 };
+        aPos = ScAddress(2,0,0);
+        for (SCROW i=0; i < 4; ++i)
+        {
+            CPPUNIT_ASSERT_EQUAL( fVec2[i], m_pDoc->GetValue(aPos));
+            aPos.IncRow();
+        }
+
+        // Paste to B1:B2
+        aPasteRange = ScRange(1,0,0, 1,1,0);
+        aMark.SetMarkArea(aPasteRange);
+        m_pDoc->CopyFromClip( aPasteRange, aMark, InsertDeleteFlags::CONTENTS, nullptr, &aClipDoc);
+
+        // Check results in C1:C4 after Paste.
+        const double fVec3[] = { 3.0, 12.0, 18.0, 72.0 };
+        aPos = ScAddress(2,0,0);
+        for (SCROW i=0; i < 4; ++i)
+        {
+            CPPUNIT_ASSERT_EQUAL( fVec3[i], m_pDoc->GetValue(aPos));
+            aPos.IncRow();
+        }
+
+        m_pDoc->DeleteTab(0);
+    }
+}
+
+// tdf#121002
+void Test::testSharedFormulaCutCopyMoveWithRef()
+{
+    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
+
+    m_pDoc->InsertTab(0, "Test");
+
+    // Data in A1:C4
+    std::vector<std::vector<const char*>> aData = {
+        {  "",  "", "=SUM(A1:B1)" },
+        {  "",  "", "=SUM(A2:B2)" },
+        { "1", "2", "=SUM(A3:B3)" },
+        { "4", "8", "=SUM(A4:B4)" }
+    };
+    const ScAddress aOrgPos(0,0,0);
+    insertRangeData( m_pDoc, aOrgPos, aData);
+
+    ScMarkData aMark;
+    aMark.SelectOneTable(0);
+
+    ScAddress aPos( ScAddress::UNINITIALIZED);
+
+    // Check results in C1:C4
+    const double fVec0[] = { 0.0, 0.0, 3.0, 12.0 };
+    aPos = ScAddress(2,0,0);
+    for (SCROW i=0; i < 4; ++i)
+    {
+        CPPUNIT_ASSERT_EQUAL( fVec0[i], m_pDoc->GetValue(aPos));
+        aPos.IncRow();
+    }
+
+    // Set up clip document.
+    ScDocument aClipDoc(SCDOCMODE_CLIP);
+    aClipDoc.ResetClip(m_pDoc, &aMark);
+    // Cut A3:B3 to clipboard.
+    cutToClip( getDocShell(), ScRange(0,2,0, 1,2,0), &aClipDoc, false);
+
+    // Check results in C1:C4 after Cut.
+    const double fVec1[] = { 0.0, 0.0, 0.0, 12.0 };
+    aPos = ScAddress(2,0,0);
+    for (SCROW i=0; i < 4; ++i)
+    {
+        CPPUNIT_ASSERT_EQUAL( fVec1[i], m_pDoc->GetValue(aPos));
+        aPos.IncRow();
+    }
+
+    // Paste to A1:B1
+    ScRange aPasteRange(0,0,0, 1,0,0);
+    aMark.SetMarkArea(aPasteRange);
+    m_pDoc->CopyFromClip( aPasteRange, aMark, InsertDeleteFlags::CONTENTS, nullptr, &aClipDoc);
+
+    // Check results in C1:C4 after Paste.
+    const double fVec2[] = { 3.0, 0.0, 3.0, 12.0 };
+    aPos = ScAddress(2,0,0);
+    for (SCROW i=0; i < 4; ++i)
+    {
+        CPPUNIT_ASSERT_EQUAL( fVec2[i], m_pDoc->GetValue(aPos));
+        aPos.IncRow();
+    }
+
+    // Check formulas in C1:C4 after Paste.
+    const OUStringLiteral sForm[] = { "=SUM(A1:B1)", "=SUM(A2:B2)", "=SUM(A1:B1)", "=SUM(A4:B4)" };
+    for (SCROW i=0; i < 4; ++i)
+    {
+        OUString aFormula;
+        m_pDoc->GetFormula( 2,i,0, aFormula);
+        CPPUNIT_ASSERT_EQUAL( OUString(sForm[i]), aFormula);
+    }
+
+    m_pDoc->DeleteTab(0);
+}
+
+// tdf#120013
+void Test::testSharedFormulaCutCopyMoveWithinRun()
+{
+    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
+
+    m_pDoc->InsertTab(0, "Test");
+
+    // Data in C3:E9
+    const std::vector<std::vector<const char*>> aData = {
+        { "2200",     "", "=SUM(C$3:C3)-SUM(D$3:D3)" },
+        {     "",     "", "=SUM(C$3:C4)-SUM(D$3:D4)" },
+        {     "", "1900", "=SUM(C$3:C5)-SUM(D$3:D5)" },
+        {     "",     "", "=SUM(C$3:C6)-SUM(D$3:D6)" },
+        { "1600",     "", "=SUM(C$3:C7)-SUM(D$3:D7)" },
+        {     "", "1000", "=SUM(C$3:C8)-SUM(D$3:D8)" },
+        {     "",     "", "=SUM(C$3:C9)-SUM(D$3:D9)" }
+    };
+    const ScAddress aOrgPos(2,2,0);
+    insertRangeData( m_pDoc, aOrgPos, aData);
+
+    // Check that E3:E9 is a formula group.
+    const ScAddress aFormulaPos(4,2,0);
+    const ScFormulaCell* pFC = m_pDoc->GetFormulaCell( aFormulaPos);
+    CPPUNIT_ASSERT(pFC);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE( "Shared formula top row.", aFormulaPos.Row(), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL_MESSAGE( "Shared formula length.", static_cast<SCROW>(7), pFC->GetSharedLength());
+
+    ScAddress aPos( ScAddress::UNINITIALIZED);
+
+    // Check results in E3:E9
+    const double fVec0[] = { 2200.0, 2200.0, 300.0, 300.0, 1900.0, 900.0, 900.0 };
+    CPPUNIT_ASSERT_EQUAL_MESSAGE( "Number of checks mismatch.", SAL_N_ELEMENTS(fVec0), aData.size());
+    aPos = aFormulaPos;
+    for (size_t i=0; i < SAL_N_ELEMENTS(fVec0); ++i)
+    {
+        CPPUNIT_ASSERT_EQUAL_MESSAGE( "E3:E9", fVec0[i], m_pDoc->GetValue(aPos));
+        aPos.IncRow();
+    }
+
+    ScMarkData aMark;
+    aMark.SelectOneTable(0);
+
+    // Set up clip document.
+    ScDocument aClipDoc(SCDOCMODE_CLIP);
+    aClipDoc.ResetClip(m_pDoc, &aMark);
+    // Cut A8:D8 to clipboard.
+    cutToClip( getDocShell(), ScRange(0,7,0, 3,7,0), &aClipDoc, false);
+
+    // Check results in E3:E9 after Cut.
+    const double fVec1[] = { 2200.0, 2200.0, 300.0, 300.0, 1900.0, 1900.0, 1900.0 };
+    CPPUNIT_ASSERT_EQUAL_MESSAGE( "Number of checks mismatch.", SAL_N_ELEMENTS(fVec1), aData.size());
+    aPos = aFormulaPos;
+    for (size_t i=0; i < SAL_N_ELEMENTS(fVec1); ++i)
+    {
+        CPPUNIT_ASSERT_EQUAL_MESSAGE( "E3:E9 after Cut.", fVec1[i], m_pDoc->GetValue(aPos));
+        aPos.IncRow();
+    }
+
+    // Paste to A4:D4
+    ScRange aPasteRange(0,3,0, 3,3,0);
+    aMark.SetMarkArea(aPasteRange);
+    m_pDoc->CopyFromClip( aPasteRange, aMark, InsertDeleteFlags::CONTENTS, nullptr, &aClipDoc);
+
+    // Check results in E3:E9 after Paste.
+    const double fVec2[] = { 2200.0, 1200.0, -700.0, -700.0, 900.0, 900.0, 900.0 };
+    CPPUNIT_ASSERT_EQUAL_MESSAGE( "Number of checks mismatch.", SAL_N_ELEMENTS(fVec2), aData.size());
+    aPos = aFormulaPos;
+    for (size_t i=0; i < SAL_N_ELEMENTS(fVec2); ++i)
+    {
+        CPPUNIT_ASSERT_EQUAL_MESSAGE( "E3:E9 after Paste.", fVec2[i], m_pDoc->GetValue(aPos));
+        aPos.IncRow();
+    }
+
+    m_pDoc->DeleteTab(0);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit af7516c81be02a3500a85a3c66923bb18afcd628
Author:     Eike Rathke <erack at redhat.com>
AuthorDate: Sat Mar 9 01:20:46 2019 +0100
Commit:     Andras Timar <andras.timar at collabora.com>
CommitDate: Wed Apr 24 22:48:14 2019 +0200

    Resolves: tdf#120013 tdf#123714 tdf#123736 shared formula group split
    
     This is a combination of 7 commits.
    
    Resolves: tdf#123714 tdf#123736 all split formula groups; tdf#120013 related
    
    Add all split shared formula groups to regrouping and mark for
    listening, even if the references had not be to adjusted.
    
    This partly also resolves tdf#120013 but there's more to that, a
    remaining partial group is not updated.
    
    Reviewed-on: https://gerrit.libreoffice.org/68951
    Reviewed-by: Eike Rathke <erack at redhat.com>
    Tested-by: Jenkins
    (cherry picked from commit 7fdc5df36f5b50e0629405a47ff3d5765fcfeb93)
    
    Resolves: tdf#120013 tdf#123714 split-off group or single cell needs listening
    
    Reviewed-on: https://gerrit.libreoffice.org/69066
    Reviewed-by: Eike Rathke <erack at redhat.com>
    Tested-by: Jenkins
    (cherry picked from commit 5c27a048658afcd2f78ef4d7e6c7128554ed3f4c)
    
    Resolves: tdf#123736 re-establish listeners for unshared formula groups
    
    ... when replacing one of their formula cells, with another
    formula cell or any other cell, passing through
    DetachFormulaCell()
    
    Reviewed-on: https://gerrit.libreoffice.org/69221
    Reviewed-by: Eike Rathke <erack at redhat.com>
    Tested-by: Jenkins
    (cherry picked from commit 1634a6d926c6cfd8fe92be1f3ae6083d2fb80f5e)
    
    In case of sc::NoListening only SetNeedsListeningGroup(), tdf#123736 follow-up
    
    Reviewed-on: https://gerrit.libreoffice.org/69303
    Reviewed-by: Eike Rathke <erack at redhat.com>
    Tested-by: Jenkins
    (cherry picked from commit 6160025b27e97841321be29863bb1efd8c194a5f)
    
    Related: tdf#123736 re-establish listeners also for vector unsharing
    
    ... via DetachFormulaCells()
    
    Reviewed-on: https://gerrit.libreoffice.org/69320
    Reviewed-by: Eike Rathke <erack at redhat.com>
    Tested-by: Jenkins
    (cherry picked from commit 564d0d145cf9c164ea9c717b4b2113fd971fa0af)
    
    Reget position_type as the block or type may have changed, tdf#123736 related
    
    Reviewed-on: https://gerrit.libreoffice.org/69358
    Reviewed-by: Eike Rathke <erack at redhat.com>
    Tested-by: Jenkins
    (cherry picked from commit e5de84e73ffbaa1a45ab787750f5997582bbfa49)
    
    Listening when grouping in ScColumn::AttachNewFormulaCells(), (tdf#123736)
    
    Not directly related to tdf#123736 but similar approach.
    Setting a vector with ScColumn::SetFormulaCells() is currently
    only done for Undo documents, but implementation provided
    listening as only single cell listening for not-undo/clip
    documents, which wouldn't work if actually used in grouping
    context. The upcoming unit tests will use SetFormulaCells() for
    checks.
    
    Reviewed-on: https://gerrit.libreoffice.org/69371
    Reviewed-by: Eike Rathke <erack at redhat.com>
    Tested-by: Jenkins
    (cherry picked from commit de024e572dd7a588f82b84c68daa2051ec6b20e9)
    
    c511f618e9dde2288491c01cfcd889970fd6e4e5
    d527307ef5278d87345c6dbfab9d05cb490dfe6c
    3e5a5334dfe11002b526f942463626b62efbc340
    a57308495a06e0df612eb1610b5f387d6b60ce08
    2faf3e74d95cb1f3088f20cbb7de7ba965a6de21
    990e6a5d6e1efcf70a2661b3a9a39c37d9e4c2e6
    
    Change-Id: If6d1fef7e545017232a1b7e29b4d60dd58775e88
    Reviewed-on: https://gerrit.libreoffice.org/69554
    Tested-by: Jenkins
    Reviewed-by: Dennis Francis <dennis.francis at collabora.com>
    Reviewed-by: Katarina Behrens <Katarina.Behrens at cib.de>

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index a8d6e49a7ca4..5576153cbaed 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -636,13 +636,23 @@ public:
     /**
      * Detach a formula cell that's about to be deleted, or removed from
      * document storage (if that ever happens).
+     *
+     * @param rNewSharedRows collects possible new shared row ranges (top and
+     *        bottom of shared or remaining single twice) resulting from
+     *        unsharing to reestablish listeners on.
      */
-    void DetachFormulaCell( const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell );
+    void DetachFormulaCell( const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell,
+                            std::vector<SCROW>& rNewSharedRows );
+
+    /** Re-establish listeners on unshared formula groups */
+    void StartListeningUnshared( const std::vector<SCROW>& rNewSharedRows );
 
-    void DetachFormulaCells( const sc::CellStoreType::position_type& aPos, size_t nLength );
+    void DetachFormulaCells( const sc::CellStoreType::position_type& aPos, size_t nLength,
+                             std::vector<SCROW>* pNewSharedRows );
 
     void AttachFormulaCells( sc::StartListeningContext& rCxt, SCROW nRow1, SCROW nRow2 );
-    void DetachFormulaCells( sc::EndListeningContext& rCxt, SCROW nRow1, SCROW nRow2 );
+    void DetachFormulaCells( sc::EndListeningContext& rCxt, SCROW nRow1, SCROW nRow2,
+                             std::vector<SCROW>* pNewSharedRows );
 
     /**
      * Regroup formula cells for the entire column.
@@ -692,18 +702,23 @@ public:
     bool        ReservePatternCount( SCSIZE nReserve );
 private:
 
-    sc::CellStoreType::iterator GetPositionToInsert( SCROW nRow );
-    sc::CellStoreType::iterator GetPositionToInsert( const sc::CellStoreType::iterator& it, SCROW nRow );
+    sc::CellStoreType::iterator GetPositionToInsert( SCROW nRow, std::vector<SCROW>& rNewSharedRows );
+    sc::CellStoreType::iterator GetPositionToInsert( const sc::CellStoreType::iterator& it, SCROW nRow,
+                                                     std::vector<SCROW>& rNewSharedRows );
 
     void AttachNewFormulaCell(
         const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell,
+        const std::vector<SCROW>& rNewSharedRows,
         bool bJoin = true, sc::StartListeningType eListenType = sc::SingleCellListening );
 
     void AttachNewFormulaCell(
         const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell,
+        const std::vector<SCROW>& rNewSharedRows,
         bool bJoin = true, sc::StartListeningType eListenType = sc::SingleCellListening );
 
-    void AttachNewFormulaCells( const sc::CellStoreType::position_type& aPos, size_t nLength );
+    void AttachNewFormulaCells( const sc::CellStoreType::position_type& aPos, size_t nLength,
+                                std::vector<SCROW>& rNewSharedRows );
+
     void BroadcastNewCell( SCROW nRow );
     bool UpdateScriptType( sc::CellTextAttr& rAttr, SCROW nRow, sc::CellStoreType::iterator& itr );
 
diff --git a/sc/inc/sharedformula.hxx b/sc/inc/sharedformula.hxx
index f4c8ab018532..b7c9577b2dfa 100644
--- a/sc/inc/sharedformula.hxx
+++ b/sc/inc/sharedformula.hxx
@@ -57,6 +57,9 @@ public:
         }
     }
 
+    /** Get shared formula top cell from position, if any, else nullptr. */
+    static const ScFormulaCell* getSharedTopFormulaCell(const CellStoreType::position_type& aPos);
+
     /**
      * Split existing shared formula range at specified position. The cell at
      * specified position becomes the top cell of the lower shared formula
@@ -65,8 +68,11 @@ public:
      *
      * @param aPos position of cell to examine.
      * @param pCxt context to be used, if any, may be nullptr.
+     *
+     * @return TRUE if there indeed was a split, else FALSE (e.g. split
+     *         position was top or bottom cell or no formula group).
      */
-    static void splitFormulaCellGroup(const CellStoreType::position_type& aPos, sc::EndListeningContext* pCxt);
+    static bool splitFormulaCellGroup(const CellStoreType::position_type& aPos, sc::EndListeningContext* pCxt);
 
     /**
      * Split existing shared formula ranges at specified row positions.
@@ -75,8 +81,11 @@ public:
      * @param rBounds row positions at which to split existing shared formula
      *                ranges. Note that this method will directly modify this
      *                parameter to sort and remove duplicates.
+     *
+     * @return TRUE if there indeed was a split, else FALSE (e.g. split
+     *         positions were only top or bottom cells or no formula group).
      */
-    static void splitFormulaCellGroups(CellStoreType& rCells, std::vector<SCROW>& rBounds);
+    static bool splitFormulaCellGroups(CellStoreType& rCells, std::vector<SCROW>& rBounds);
 
     /**
      * See if two specified adjacent formula cells can be merged, and if they
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 0436dd3f3173..fcee215f1580 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -2441,7 +2441,7 @@ bool ScColumn::UpdateReference( sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc
     }
 
     // Do the actual splitting.
-    sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds);
+    const bool bSplit = sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds);
 
     // Collect all formula groups.
     std::vector<sc::FormulaGroupEntry> aGroups = GetFormulaGroupEntries();
@@ -2449,7 +2449,7 @@ bool ScColumn::UpdateReference( sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc
     // Process all collected formula groups.
     UpdateRefOnNonCopy aHandler(nCol, nTab, &rCxt, pUndoDoc);
     aHandler = std::for_each(aGroups.begin(), aGroups.end(), aHandler);
-    if (aHandler.isUpdated())
+    if (bSplit || aHandler.isUpdated())
         rCxt.maRegroupCols.set(nTab, nCol);
 
     return aHandler.isUpdated();
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index b0950987e20c..74440216b915 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -262,9 +262,9 @@ void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize, std::vector<ScAddress>*
     CellStorageModified();
 }
 
-sc::CellStoreType::iterator ScColumn::GetPositionToInsert( SCROW nRow )
+sc::CellStoreType::iterator ScColumn::GetPositionToInsert( SCROW nRow, std::vector<SCROW>& rNewSharedRows )
 {
-    return GetPositionToInsert(maCells.begin(), nRow);
+    return GetPositionToInsert(maCells.begin(), nRow, rNewSharedRows);
 }
 
 void ScColumn::JoinNewFormulaCell(
@@ -288,15 +288,74 @@ void ScColumn::JoinNewFormulaCell(
 }
 
 void ScColumn::DetachFormulaCell(
-    const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell )
+    const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell, std::vector<SCROW>& rNewSharedRows )
 {
     if (!GetDoc()->IsClipOrUndo())
+    {
+#if USE_FORMULA_GROUP_LISTENER
+        if (rCell.IsShared() && rCell.GetSharedLength() > 1)
+        {
+            // Record new spans (shared or remaining single) that will result
+            // from unsharing to reestablish listeners.
+            // Same cases as in unshareFormulaCell().
+            // XXX NOTE: this is not part of unshareFormulaCell() because that
+            // is called in other contexts as well, for which passing and
+            // determining the rows vector would be superfluous. If that was
+            // needed, move it there.
+            const SCROW nSharedTopRow = rCell.GetSharedTopRow();
+            const SCROW nSharedLength = rCell.GetSharedLength();
+            if (rCell.aPos.Row() == nSharedTopRow)
+            {
+                // Top cell.
+                // Next row will be new shared top or single cell.
+                rNewSharedRows.push_back( nSharedTopRow + 1);
+                rNewSharedRows.push_back( nSharedTopRow + nSharedLength - 1);
+            }
+            else if (rCell.aPos.Row() == nSharedTopRow + nSharedLength - 1)
+            {
+                // Bottom cell.
+                // Current shared top row will be new shared top again or
+                // single cell.
+                rNewSharedRows.push_back( nSharedTopRow);
+                rNewSharedRows.push_back( rCell.aPos.Row() - 1);
+            }
+            else
+            {
+                // Some mid cell.
+                // Current shared top row will be new shared top again or
+                // single cell, plus a new shared top below or single cell.
+                rNewSharedRows.push_back( nSharedTopRow);
+                rNewSharedRows.push_back( rCell.aPos.Row() - 1);
+                rNewSharedRows.push_back( rCell.aPos.Row() + 1);
+                rNewSharedRows.push_back( nSharedTopRow + nSharedLength - 1);
+            }
+        }
+#endif
+
         // Have the dying formula cell stop listening.
+        // If in a shared formula group this ends the group listening.
         rCell.EndListeningTo(GetDoc());
+    }
 
     sc::SharedFormulaUtil::unshareFormulaCell(aPos, rCell);
 }
 
+void ScColumn::StartListeningUnshared( const std::vector<SCROW>& rNewSharedRows )
+{
+    assert(rNewSharedRows.empty() || rNewSharedRows.size() == 2 || rNewSharedRows.size() == 4);
+    ScDocument* pDoc = GetDoc();
+    if (!rNewSharedRows.empty() /* && !pDoc->IsDelayedFormulaGrouping() N/A in backport */)
+    {
+        std::shared_ptr<sc::ColumnBlockPositionSet> pPosSet(new sc::ColumnBlockPositionSet(*pDoc));
+        sc::StartListeningContext aStartCxt(*pDoc, pPosSet);
+        sc::EndListeningContext aEndCxt(*pDoc, pPosSet);
+        if (rNewSharedRows.size() >= 2)
+            StartListeningFormulaCells(aStartCxt, aEndCxt, rNewSharedRows[0], rNewSharedRows[1]);
+        if (rNewSharedRows.size() >= 4)
+            StartListeningFormulaCells(aStartCxt, aEndCxt, rNewSharedRows[2], rNewSharedRows[3]);
+    }
+}
+
 namespace {
 
 class AttachFormulaCellsHandler
@@ -334,14 +393,59 @@ public:
 }
 
 void ScColumn::DetachFormulaCells(
-    const sc::CellStoreType::position_type& aPos, size_t nLength )
+    const sc::CellStoreType::position_type& aPos, size_t nLength, std::vector<SCROW>* pNewSharedRows )
 {
+    const size_t nRow = aPos.first->position + aPos.second;
+    const size_t nNextTopRow = nRow + nLength; // start row of next formula group.
+
+    bool bLowerSplitOff = false;
+    if (pNewSharedRows && !GetDoc()->IsClipOrUndo())
+    {
+        const ScFormulaCell* pFC = sc::SharedFormulaUtil::getSharedTopFormulaCell(aPos);
+        if (pFC)
+        {
+            const SCROW nTopRow = pFC->GetSharedTopRow();
+            const SCROW nBotRow = nTopRow + pFC->GetSharedLength() - 1;
+            // nTopRow <= nRow <= nBotRow, because otherwise pFC would not exist.
+            if (nTopRow < static_cast<SCROW>(nRow))
+            {
+                // Upper part will be split off.
+                pNewSharedRows->push_back(nTopRow);
+                pNewSharedRows->push_back(nRow - 1);
+            }
+            if (static_cast<SCROW>(nNextTopRow) <= nBotRow)
+            {
+                // Lower part will be split off.
+                pNewSharedRows->push_back(nNextTopRow);
+                pNewSharedRows->push_back(nBotRow);
+                bLowerSplitOff = true;
+            }
+        }
+    }
+
     // Split formula grouping at the top and bottom boundaries.
     sc::SharedFormulaUtil::splitFormulaCellGroup(aPos, nullptr);
-    size_t nRow = aPos.first->position + aPos.second;
-    size_t nNextTopRow = nRow + nLength; // start row of next formula group.
-    if (ValidRow(nNextTopRow))
+
+    if (nLength > 0 && ValidRow(nNextTopRow))
     {
+        if (pNewSharedRows && !bLowerSplitOff && !GetDoc()->IsClipOrUndo())
+        {
+            sc::CellStoreType::position_type aPos2 = maCells.position(aPos.first, nNextTopRow-1);
+            const ScFormulaCell* pFC = sc::SharedFormulaUtil::getSharedTopFormulaCell(aPos2);
+            if (pFC)
+            {
+                const SCROW nTopRow = pFC->GetSharedTopRow();
+                const SCROW nBotRow = nTopRow + pFC->GetSharedLength() - 1;
+                // nRow < nTopRow < nNextTopRow <= nBotRow
+                if (static_cast<SCROW>(nNextTopRow) <= nBotRow)
+                {
+                    // Lower part will be split off.
+                    pNewSharedRows->push_back(nNextTopRow);
+                    pNewSharedRows->push_back(nBotRow);
+                }
+            }
+        }
+
         sc::CellStoreType::position_type aPos2 = maCells.position(aPos.first, nNextTopRow);
         sc::SharedFormulaUtil::splitFormulaCellGroup(aPos2, nullptr);
     }
@@ -372,15 +476,59 @@ void ScColumn::AttachFormulaCells( sc::StartListeningContext& rCxt, SCROW nRow1,
     sc::ProcessFormula(it, maCells, nRow1, nRow2, aFunc);
 }
 
-void ScColumn::DetachFormulaCells( sc::EndListeningContext& rCxt, SCROW nRow1, SCROW nRow2 )
+void ScColumn::DetachFormulaCells( sc::EndListeningContext& rCxt, SCROW nRow1, SCROW nRow2,
+        std::vector<SCROW>* pNewSharedRows )
 {
     sc::CellStoreType::position_type aPos = maCells.position(nRow1);
     sc::CellStoreType::iterator it = aPos.first;
 
+    bool bLowerSplitOff = false;
+    if (pNewSharedRows && !GetDoc()->IsClipOrUndo())
+    {
+        const ScFormulaCell* pFC = sc::SharedFormulaUtil::getSharedTopFormulaCell(aPos);
+        if (pFC)
+        {
+            const SCROW nTopRow = pFC->GetSharedTopRow();
+            const SCROW nBotRow = nTopRow + pFC->GetSharedLength() - 1;
+            // nTopRow <= nRow1 <= nBotRow, because otherwise pFC would not exist.
+            if (nTopRow < nRow1)
+            {
+                // Upper part will be split off.
+                pNewSharedRows->push_back(nTopRow);
+                pNewSharedRows->push_back(nRow1 - 1);
+            }
+            if (nRow2 < nBotRow)
+            {
+                // Lower part will be split off.
+                pNewSharedRows->push_back(nRow2 + 1);
+                pNewSharedRows->push_back(nBotRow);
+                bLowerSplitOff = true;
+            }
+        }
+    }
+
     // Split formula grouping at the top and bottom boundaries.
     sc::SharedFormulaUtil::splitFormulaCellGroup(aPos, &rCxt);
     if (ValidRow(nRow2+1))
     {
+        if (pNewSharedRows && !bLowerSplitOff && !GetDoc()->IsClipOrUndo())
+        {
+            sc::CellStoreType::position_type aPos2 = maCells.position(aPos.first, nRow2);
+            const ScFormulaCell* pFC = sc::SharedFormulaUtil::getSharedTopFormulaCell(aPos2);
+            if (pFC)
+            {
+                const SCROW nTopRow = pFC->GetSharedTopRow();
+                const SCROW nBotRow = nTopRow + pFC->GetSharedLength() - 1;
+                // nRow1 < nTopRow <= nRow2 < nBotRow
+                if (nRow2 < nBotRow)
+                {
+                    // Lower part will be split off.
+                    pNewSharedRows->push_back(nRow2 + 1);
+                    pNewSharedRows->push_back(nBotRow);
+                }
+            }
+        }
+
         aPos = maCells.position(it, nRow2+1);
         sc::SharedFormulaUtil::splitFormulaCellGroup(aPos, &rCxt);
     }
@@ -392,7 +540,8 @@ void ScColumn::DetachFormulaCells( sc::EndListeningContext& rCxt, SCROW nRow1, S
     sc::ProcessFormula(it, maCells, nRow1, nRow2, aFunc);
 }
 
-sc::CellStoreType::iterator ScColumn::GetPositionToInsert( const sc::CellStoreType::iterator& it, SCROW nRow )
+sc::CellStoreType::iterator ScColumn::GetPositionToInsert( const sc::CellStoreType::iterator& it, SCROW nRow,
+        std::vector<SCROW>& rNewSharedRows )
 {
     // See if we are overwriting an existing formula cell.
     sc::CellStoreType::position_type aPos = maCells.position(it, nRow);
@@ -400,7 +549,7 @@ sc::CellStoreType::iterator ScColumn::GetPositionToInsert( const sc::CellStoreTy
     if (itRet->type == sc::element_type_formula)
     {
         ScFormulaCell& rCell = *sc::formula_block::at(*itRet->data, aPos.second);
-        DetachFormulaCell(aPos, rCell);
+        DetachFormulaCell(aPos, rCell, rNewSharedRows);
     }
 
     return itRet;
@@ -408,13 +557,15 @@ sc::CellStoreType::iterator ScColumn::GetPositionToInsert( const sc::CellStoreTy
 
 void ScColumn::AttachNewFormulaCell(
     const sc::CellStoreType::iterator& itPos, SCROW nRow, ScFormulaCell& rCell,
+    const std::vector<SCROW>& rNewSharedRows,
     bool bJoin, sc::StartListeningType eListenType )
 {
-    AttachNewFormulaCell(maCells.position(itPos, nRow), rCell, bJoin, eListenType);
+    AttachNewFormulaCell(maCells.position(itPos, nRow), rCell, rNewSharedRows, bJoin, eListenType);
 }
 
 void ScColumn::AttachNewFormulaCell(
     const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell,
+    const std::vector<SCROW>& rNewSharedRows,
     bool bJoin, sc::StartListeningType eListenType )
 {
     if (bJoin)
@@ -437,24 +588,50 @@ void ScColumn::AttachNewFormulaCell(
             std::shared_ptr<sc::ColumnBlockPositionSet> pPosSet(new sc::ColumnBlockPositionSet(*pDocument));
             sc::StartListeningContext aStartCxt(*pDocument, pPosSet);
             sc::EndListeningContext aEndCxt(*pDocument, pPosSet);
-            SCROW nRow = aPos.first->position + aPos.second;
-            StartListeningFormulaCells(aStartCxt, aEndCxt, nRow, nRow);
+            SCROW nStartRow, nEndRow;
+            nStartRow = nEndRow = aPos.first->position + aPos.second;
+            for (const SCROW nR : rNewSharedRows)
+            {
+                if (nStartRow > nR)
+                    nStartRow = nR;
+                if (nEndRow < nR)
+                    nEndRow = nR;
+            }
+            StartListeningFormulaCells(aStartCxt, aEndCxt, nStartRow, nEndRow);
         }
         break;
         case sc::SingleCellListening:
             rCell.StartListeningTo(pDocument);
+            StartListeningUnshared( rNewSharedRows);
         break;
         case sc::NoListening:
         default:
-            ;
-
+            if (!rNewSharedRows.empty())
+            {
+                assert(rNewSharedRows.size() == 2 || rNewSharedRows.size() == 4);
+                // Calling SetNeedsListeningGroup() with a top row sets it to
+                // all affected formula cells of that group.
+                const ScFormulaCell* pFC = GetFormulaCell( rNewSharedRows[0]);
+                assert(pFC);    // that *is* supposed to be a top row
+                if (pFC && !pFC->NeedsListening())
+                    SetNeedsListeningGroup( rNewSharedRows[0]);
+                if (rNewSharedRows.size() > 2)
+                {
+                    pFC = GetFormulaCell( rNewSharedRows[2]);
+                    assert(pFC);    // that *is* supposed to be a top row
+                    if (pFC && !pFC->NeedsListening())
+                        SetNeedsListeningGroup( rNewSharedRows[2]);
+                }
+            }
+        break;
     }
 
     if (!pDocument->IsCalcingAfterLoad())
         rCell.SetDirty();
 }
 
-void ScColumn::AttachNewFormulaCells( const sc::CellStoreType::position_type& aPos, size_t nLength )
+void ScColumn::AttachNewFormulaCells( const sc::CellStoreType::position_type& aPos, size_t nLength,
+        std::vector<SCROW>& rNewSharedRows )
 {
     // Make sure the whole length consists of formula cells.
     if (aPos.first->type != sc::element_type_formula)
@@ -465,26 +642,61 @@ void ScColumn::AttachNewFormulaCells( const sc::CellStoreType::position_type& aP
         return;
 
     // Join the top and bottom cells only.
-    ScFormulaCell* pCell = sc::formula_block::at(*aPos.first->data, aPos.second);
-    JoinNewFormulaCell(aPos, *pCell);
+    ScFormulaCell* pCell1 = sc::formula_block::at(*aPos.first->data, aPos.second);
+    JoinNewFormulaCell(aPos, *pCell1);
 
     sc::CellStoreType::position_type aPosLast = aPos;
     aPosLast.second += nLength - 1;
-    pCell = sc::formula_block::at(*aPosLast.first->data, aPosLast.second);
-    JoinNewFormulaCell(aPosLast, *pCell);
+    ScFormulaCell* pCell2 = sc::formula_block::at(*aPosLast.first->data, aPosLast.second);
+    JoinNewFormulaCell(aPosLast, *pCell2);
 
     ScDocument* pDocument = GetDoc();
     if (!pDocument->IsClipOrUndo() && !pDocument->IsInsertingFromOtherDoc())
     {
+        const bool bShared = pCell1->IsShared() || pCell2->IsShared();
+        if (bShared)
+        {
+            const SCROW nTopRow = (pCell1->IsShared() ? pCell1->GetSharedTopRow() : pCell1->aPos.Row());
+            const SCROW nBotRow = (pCell2->IsShared() ?
+                    pCell2->GetSharedTopRow() + pCell2->GetSharedLength() - 1 : pCell2->aPos.Row());
+            if (rNewSharedRows.empty())
+            {
+                rNewSharedRows.push_back( nTopRow);
+                rNewSharedRows.push_back( nBotRow);
+            }
+            else if (rNewSharedRows.size() == 2)
+            {
+                // Combine into one span.
+                if (rNewSharedRows[0] > nTopRow)
+                    rNewSharedRows[0] = nTopRow;
+                if (rNewSharedRows[1] < nBotRow)
+                    rNewSharedRows[1] = nBotRow;
+            }
+            else if (rNewSharedRows.size() == 4)
+            {
+                // Merge into one span.
+                // The original two spans are ordered from top to bottom.
+                std::vector<SCROW> aRows(2);
+                aRows[0] = std::min( rNewSharedRows[0], nTopRow);
+                aRows[1] = std::max( rNewSharedRows[3], nBotRow);
+                rNewSharedRows.swap( aRows);
+            }
+            else
+            {
+                assert(!"rNewSharedRows?");
+            }
+        }
+        StartListeningUnshared( rNewSharedRows);
+
         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 (!bShared)
+                (*pp)->StartListeningTo(aCxt);
             if (!pDocument->IsCalcingAfterLoad())
-                pCell->SetDirty();
+                (*pp)->SetDirty();
         }
     }
 }
@@ -1523,7 +1735,7 @@ public:
 
         // Stop all formula cells in the destination range first.
         sc::CellStoreType::position_type aPos = rDestCells.position(mrBlockPos.miCellPos, mnRowOffset);
-        mrDestColumn.DetachFormulaCells(aPos, maNewCells.size());
+        mrDestColumn.DetachFormulaCells(aPos, maNewCells.size(), nullptr);
 
         // Move the new cells to the destination range.
         sc::CellStoreType::iterator& itDestPos = mrBlockPos.miCellPos;
@@ -1882,24 +2094,30 @@ bool ScColumn::SetString( SCROW nRow, SCTAB nTabP, const OUString& rString,
 void ScColumn::SetEditText( SCROW nRow, EditTextObject* pEditText )
 {
     pEditText->NormalizeString(GetDoc()->GetSharedStringPool());
-    sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
+    std::vector<SCROW> aNewSharedRows;
+    sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows);
     maCells.set(it, nRow, pEditText);
     maCellTextAttrs.set(nRow, sc::CellTextAttr());
     CellStorageModified();
 
+    StartListeningUnshared( aNewSharedRows);
+
     BroadcastNewCell(nRow);
 }
 
 void ScColumn::SetEditText( sc::ColumnBlockPosition& rBlockPos, SCROW nRow, EditTextObject* pEditText )
 {
     pEditText->NormalizeString(GetDoc()->GetSharedStringPool());
-    rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
+    std::vector<SCROW> aNewSharedRows;
+    rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows);
     rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, pEditText);
     rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
         rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
 
     CellStorageModified();
 
+    StartListeningUnshared( aNewSharedRows);
+
     BroadcastNewCell(nRow);
 }
 
@@ -1939,7 +2157,8 @@ void ScColumn::SetFormula( SCROW nRow, const ScTokenArray& rArray, formula::Form
 {
     ScAddress aPos(nCol, nRow, nTab);
 
-    sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
+    std::vector<SCROW> aNewSharedRows;
+    sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows);
     ScFormulaCell* pCell = new ScFormulaCell(GetDoc(), aPos, rArray, eGram);
     sal_uInt32 nCellFormat = GetNumberFormat(GetDoc()->GetNonThreadedContext(), nRow);
     if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
@@ -1949,14 +2168,15 @@ void ScColumn::SetFormula( SCROW nRow, const ScTokenArray& rArray, formula::Form
 
     CellStorageModified();
 
-    AttachNewFormulaCell(it, nRow, *pCell);
+    AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows);
 }
 
 void ScColumn::SetFormula( SCROW nRow, const OUString& rFormula, formula::FormulaGrammar::Grammar eGram )
 {
     ScAddress aPos(nCol, nRow, nTab);
 
-    sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
+    std::vector<SCROW> aNewSharedRows;
+    sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows);
     ScFormulaCell* pCell = new ScFormulaCell(GetDoc(), aPos, rFormula, eGram);
     sal_uInt32 nCellFormat = GetNumberFormat(GetDoc()->GetNonThreadedContext(), nRow);
     if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
@@ -1966,14 +2186,15 @@ void ScColumn::SetFormula( SCROW nRow, const OUString& rFormula, formula::Formul
 
     CellStorageModified();
 
-    AttachNewFormulaCell(it, nRow, *pCell);
+    AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows);
 }
 
 ScFormulaCell* ScColumn::SetFormulaCell(
     SCROW nRow, ScFormulaCell* pCell, sc::StartListeningType eListenType,
     bool bInheritNumFormatIfNeeded )
 {
-    sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
+    std::vector<SCROW> aNewSharedRows;
+    sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows);
     sal_uInt32 nCellFormat = GetNumberFormat(GetDoc()->GetNonThreadedContext(), nRow);
     if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && bInheritNumFormatIfNeeded )
         pCell->SetNeedNumberFormat(true);
@@ -1982,7 +2203,8 @@ ScFormulaCell* ScColumn::SetFormulaCell(
 
     CellStorageModified();
 
-    AttachNewFormulaCell(it, nRow, *pCell, true, eListenType);
+    AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows, true, eListenType);
+
     return pCell;
 }
 
@@ -1991,7 +2213,8 @@ void ScColumn::SetFormulaCell(
     sc::StartListeningType eListenType,
     bool bInheritNumFormatIfNeeded )
 {
-    rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
+    std::vector<SCROW> aNewSharedRows;
+    rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows);
     sal_uInt32 nCellFormat = GetNumberFormat(GetDoc()->GetNonThreadedContext(), nRow);
     if( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && bInheritNumFormatIfNeeded )
         pCell->SetNeedNumberFormat(true);
@@ -2001,7 +2224,7 @@ void ScColumn::SetFormulaCell(
 
     CellStorageModified();
 
-    AttachNewFormulaCell(rBlockPos.miCellPos, nRow, *pCell, true, eListenType);
+    AttachNewFormulaCell(rBlockPos.miCellPos, nRow, *pCell, aNewSharedRows, true, eListenType);
 }
 
 bool ScColumn::SetFormulaCells( SCROW nRow, std::vector<ScFormulaCell*>& rCells )
@@ -2016,7 +2239,8 @@ bool ScColumn::SetFormulaCells( SCROW nRow, std::vector<ScFormulaCell*>& rCells
     sc::CellStoreType::position_type aPos = maCells.position(nRow);
 
     // Detach all formula cells that will be overwritten.
-    DetachFormulaCells(aPos, rCells.size());
+    std::vector<SCROW> aNewSharedRows;
+    DetachFormulaCells(aPos, rCells.size(), &aNewSharedRows);
 
     if (!GetDoc()->IsClipOrUndo())
     {
@@ -2036,7 +2260,10 @@ bool ScColumn::SetFormulaCells( SCROW nRow, std::vector<ScFormulaCell*>& rCells
 
     CellStorageModified();
 
-    AttachNewFormulaCells(aPos, rCells.size());
+    // Reget position_type as the type may have changed to formula, block and
+    // block size changed, ...
+    aPos = maCells.position(nRow);
+    AttachNewFormulaCells(aPos, rCells.size(), aNewSharedRows);
 
     return true;
 }
@@ -2473,13 +2700,14 @@ void ScColumn::SetError( SCROW nRow, const FormulaError nError)
     ScFormulaCell* pCell = new ScFormulaCell(GetDoc(), ScAddress(nCol, nRow, nTab));
     pCell->SetErrCode(nError);
 
-    sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
+    std::vector<SCROW> aNewSharedRows;
+    sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows);
     it = maCells.set(it, nRow, pCell);
     maCellTextAttrs.set(nRow, sc::CellTextAttr());
 
     CellStorageModified();
 
-    AttachNewFormulaCell(it, nRow, *pCell);
+    AttachNewFormulaCell(it, nRow, *pCell, aNewSharedRows);
 }
 
 void ScColumn::SetRawString( SCROW nRow, const OUString& rStr )
@@ -2499,12 +2727,15 @@ void ScColumn::SetRawString( SCROW nRow, const svl::SharedString& rStr )
     if (!ValidRow(nRow))
         return;
 
-    sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
+    std::vector<SCROW> aNewSharedRows;
+    sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows);
     maCells.set(it, nRow, rStr);
     maCellTextAttrs.set(nRow, sc::CellTextAttr());
 
     CellStorageModified();
 
+    StartListeningUnshared( aNewSharedRows);
+
     BroadcastNewCell(nRow);
 }
 
@@ -2514,13 +2745,16 @@ void ScColumn::SetRawString(
     if (!ValidRow(nRow))
         return;
 
-    rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
+    std::vector<SCROW> aNewSharedRows;
+    rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows);
     rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, rStr);
     rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
         rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
 
     CellStorageModified();
 
+    StartListeningUnshared( aNewSharedRows);
+
     if (bBroadcast)
         BroadcastNewCell(nRow);
 }
@@ -2530,12 +2764,15 @@ void ScColumn::SetValue( SCROW nRow, double fVal )
     if (!ValidRow(nRow))
         return;
 
-    sc::CellStoreType::iterator it = GetPositionToInsert(nRow);
+    std::vector<SCROW> aNewSharedRows;
+    sc::CellStoreType::iterator it = GetPositionToInsert(nRow, aNewSharedRows);
     maCells.set(it, nRow, fVal);
     maCellTextAttrs.set(nRow, sc::CellTextAttr());
 
     CellStorageModified();
 
+    StartListeningUnshared( aNewSharedRows);
+
     BroadcastNewCell(nRow);
 }
 
@@ -2545,13 +2782,16 @@ void ScColumn::SetValue(
     if (!ValidRow(nRow))
         return;
 
-    rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow);
+    std::vector<SCROW> aNewSharedRows;
+    rBlockPos.miCellPos = GetPositionToInsert(rBlockPos.miCellPos, nRow, aNewSharedRows);
     rBlockPos.miCellPos = maCells.set(rBlockPos.miCellPos, nRow, fVal);
     rBlockPos.miCellTextAttrPos = maCellTextAttrs.set(
         rBlockPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
 
     CellStorageModified();
 
+    StartListeningUnshared( aNewSharedRows);
+
     if (bBroadcast)
         BroadcastNewCell(nRow);
 }
diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx
index 59d8923dded1..520bd815873c 100644
--- a/sc/source/core/data/column4.cxx
+++ b/sc/source/core/data/column4.cxx
@@ -316,7 +316,8 @@ void ScColumn::SetValues( SCROW nRow, const std::vector<double>& rVals )
         return;
 
     sc::CellStoreType::position_type aPos = maCells.position(nRow);
-    DetachFormulaCells(aPos, rVals.size());
+    std::vector<SCROW> aNewSharedRows;
+    DetachFormulaCells(aPos, rVals.size(), &aNewSharedRows);
 
     maCells.set(nRow, rVals.begin(), rVals.end());
     std::vector<sc::CellTextAttr> aDefaults(rVals.size());
@@ -324,6 +325,8 @@ void ScColumn::SetValues( SCROW nRow, const std::vector<double>& rVals )
 
     CellStorageModified();
 
+    StartListeningUnshared( aNewSharedRows);
+
     std::vector<SCROW> aRows;
     aRows.reserve(rVals.size());
     for (SCROW i = nRow; i <= nLastRow; ++i)
@@ -343,7 +346,7 @@ void ScColumn::TransferCellValuesTo( SCROW nRow, size_t nLen, sc::CellValues& rD
         return;
 
     sc::CellStoreType::position_type aPos = maCells.position(nRow);
-    DetachFormulaCells(aPos, nLen);
+    DetachFormulaCells(aPos, nLen, nullptr);
 
     rDest.transferFrom(*this, nRow, nLen);
 
@@ -368,7 +371,7 @@ void ScColumn::CopyCellValuesFrom( SCROW nRow, const sc::CellValues& rSrc )
         return;
 
     sc::CellStoreType::position_type aPos = maCells.position(nRow);
-    DetachFormulaCells(aPos, rSrc.size());
+    DetachFormulaCells(aPos, rSrc.size(), nullptr);
 
     rSrc.copyTo(*this, nRow);
 
@@ -444,7 +447,7 @@ void ScColumn::ConvertFormulaToValue(
         // No formula cells encountered.
         return;
 
-    DetachFormulaCells(rCxt, nRow1, nRow2);
+    DetachFormulaCells(rCxt, nRow1, nRow2, nullptr);
 
     // Undo storage to hold static values which will get swapped to the cell storage later.
     sc::CellValues aUndoCells;
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index ed6046dea2a0..715ed11dbc49 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -1079,7 +1079,7 @@ void ScTable::DetachFormulaCells(
     sc::EndListeningContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
 {
     for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
-        aCol[nCol].DetachFormulaCells(rCxt, nRow1, nRow2);
+        aCol[nCol].DetachFormulaCells(rCxt, nRow1, nRow2, nullptr);
 }
 
 void ScTable::SetDirtyFromClip(
diff --git a/sc/source/core/tool/sharedformula.cxx b/sc/source/core/tool/sharedformula.cxx
index 4b688654077c..c91e512fee5e 100644
--- a/sc/source/core/tool/sharedformula.cxx
+++ b/sc/source/core/tool/sharedformula.cxx
@@ -16,28 +16,44 @@
 
 namespace sc {
 
-void SharedFormulaUtil::splitFormulaCellGroup(const CellStoreType::position_type& aPos, sc::EndListeningContext* pCxt)
+const ScFormulaCell* SharedFormulaUtil::getSharedTopFormulaCell(const CellStoreType::position_type& aPos)
+{
+    if (aPos.first->type != sc::element_type_formula)
+        // Not a formula cell block.
+        return nullptr;
+
+    sc::formula_block::iterator it = sc::formula_block::begin(*aPos.first->data);
+    std::advance(it, aPos.second);
+    const ScFormulaCell* pCell = *it;
+    if (!pCell->IsShared())
+        // Not a shared formula.
+        return nullptr;
+
+    return pCell->GetCellGroup()->mpTopCell;
+}
+
+bool SharedFormulaUtil::splitFormulaCellGroup(const CellStoreType::position_type& aPos, sc::EndListeningContext* pCxt)
 {
     SCROW nRow = aPos.first->position + aPos.second;
 
     if (aPos.first->type != sc::element_type_formula)
         // Not a formula cell block.
-        return;
+        return false;
 
     if (aPos.second == 0)
         // Split position coincides with the block border. Nothing to do.
-        return;
+        return false;
 
     sc::formula_block::iterator it = sc::formula_block::begin(*aPos.first->data);
     std::advance(it, aPos.second);
     ScFormulaCell& rTop = **it;
     if (!rTop.IsShared())
         // Not a shared formula.
-        return;
+        return false;
 
     if (nRow == rTop.GetSharedTopRow())
         // Already the top cell of a shared group.
-        return;
+        return false;
 
     ScFormulaCellGroupRef xGroup = rTop.GetCellGroup();
 
@@ -70,6 +86,9 @@ void SharedFormulaUtil::splitFormulaCellGroup(const CellStoreType::position_type
         else
             rPrevTop.EndListeningTo( rPrevTop.GetDocument(), nullptr, ScAddress( ScAddress::UNINITIALIZED));
         rPrevTop.SetNeedsListening(true);
+
+        // The new group or remaining single cell needs a new listening.
+        rTop.SetNeedsListening(true);
     }
 #endif
 
@@ -96,12 +115,14 @@ void SharedFormulaUtil::splitFormulaCellGroup(const CellStoreType::position_type
         ScFormulaCell& rCell = **it;
         rCell.SetCellGroup(xGroup2);
     }
+
+    return true;
 }
 
-void SharedFormulaUtil::splitFormulaCellGroups(CellStoreType& rCells, std::vector<SCROW>& rBounds)
+bool SharedFormulaUtil::splitFormulaCellGroups(CellStoreType& rCells, std::vector<SCROW>& rBounds)
 {
     if (rBounds.empty())
-        return;
+        return false;
 
     // Sort and remove duplicates.
     std::sort(rBounds.begin(), rBounds.end());
@@ -112,9 +133,9 @@ void SharedFormulaUtil::splitFormulaCellGroups(CellStoreType& rCells, std::vecto
     SCROW nRow = *it;
     CellStoreType::position_type aPos = rCells.position(nRow);
     if (aPos.first == rCells.end())
-        return;
+        return false;
 
-    splitFormulaCellGroup(aPos, nullptr);
+    bool bSplit = splitFormulaCellGroup(aPos, nullptr);
     std::vector<SCROW>::iterator itEnd = rBounds.end();
     for (++it; it != itEnd; ++it)
     {
@@ -123,10 +144,11 @@ void SharedFormulaUtil::splitFormulaCellGroups(CellStoreType& rCells, std::vecto
         {
             aPos = rCells.position(aPos.first, nRow);
             if (aPos.first == rCells.end())
-                return;
-            splitFormulaCellGroup(aPos, nullptr);
+                return bSplit;
+            bSplit |= splitFormulaCellGroup(aPos, nullptr);
         }
     }
+    return bSplit;
 }
 
 bool SharedFormulaUtil::joinFormulaCells(
@@ -234,9 +256,9 @@ void SharedFormulaUtil::unshareFormulaCell(const CellStoreType::position_type& a
         {
             // Move the top cell to the next formula cell down.
             ScFormulaCell& rNext = *sc::formula_block::at(*it->data, aPos.second+1);
-            --xGroup->mnLength;
             xGroup->mpTopCell = &rNext;
         }
+        --xGroup->mnLength;
     }
     else if (rCell.aPos.Row() == rCell.GetSharedTopRow() + rCell.GetSharedLength() - 1)
     {


More information about the Libreoffice-commits mailing list