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

Kohei Yoshida kohei.yoshida at collabora.com
Thu Jul 31 06:05:36 PDT 2014


 sc/inc/document.hxx                 |    2 +
 sc/inc/refhint.hxx                  |    7 +++
 sc/inc/tokenarray.hxx               |    5 --
 sc/inc/types.hxx                    |    6 +++
 sc/qa/unit/ucalc.hxx                |    2 +
 sc/qa/unit/ucalc_sharedformula.cxx  |   68 ++++++++++++++++++++++++++++++++++
 sc/source/core/data/bcaslot.cxx     |   17 ++++++--
 sc/source/core/data/documen7.cxx    |    2 -
 sc/source/core/data/document10.cxx  |   13 ++++++
 sc/source/core/data/formulacell.cxx |   16 +++++++-
 sc/source/core/inc/bcaslot.hxx      |    6 ++-
 sc/source/core/tool/refhint.cxx     |    9 +++-
 sc/source/core/tool/token.cxx       |   24 +++++++++---
 sc/source/ui/docshell/docfunc.cxx   |    6 +--
 sc/source/ui/undo/undoblk.cxx       |   71 ++++++++++++++++++++++++++++++------
 15 files changed, 218 insertions(+), 36 deletions(-)

New commits:
commit 27182231acd3a0c9898a8dba78b76dc8a827b4c0
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Jul 30 13:51:28 2014 -0400

    fdo#78555: Retain formula results when moving a range of cells.
    
    * No need to re-compile RPN token array on reference change alone.  We do that
      when the formula contains one or more names that have been updated.
    
    * Adjust undo code to get it to work without relying on ref undo document,
      which would cause the token arrays to be unnecessarily recompiled.
    
    * Whatever else need to be changed in order to pass all unit tests.
    
    Change-Id: I99e86d23320aca8900fef011da23a9d34e42751e

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 0dc3239..6bfb138 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -1876,6 +1876,8 @@ public:
     void EndListeningCell( sc::EndListeningContext& rCxt, const ScAddress& rPos, SvtListener& rListener );
 
     void EndListeningFormulaCells( std::vector<ScFormulaCell*>& rCells );
+    void CollectAllAreaListeners(
+        std::vector<SvtListener*>& rListeners, const ScRange& rRange, sc::AreaOverlapType eType );
 
     void                PutInFormulaTree( ScFormulaCell* pCell );
     void                RemoveFromFormulaTree( ScFormulaCell* pCell );
diff --git a/sc/inc/refhint.hxx b/sc/inc/refhint.hxx
index 1eff906..0f65aae 100644
--- a/sc/inc/refhint.hxx
+++ b/sc/inc/refhint.hxx
@@ -15,6 +15,8 @@
 
 namespace sc {
 
+struct RefUpdateContext;
+
 class RefHint : public SfxSimpleHint
 {
 public:
@@ -42,10 +44,11 @@ class RefMovedHint : public RefHint
 {
     ScRange maRange;
     ScAddress maMoveDelta;
+    const sc::RefUpdateContext& mrCxt;
 
 public:
 
-    RefMovedHint( const ScRange& rRange, const ScAddress& rMove );
+    RefMovedHint( const ScRange& rRange, const ScAddress& rMove, const sc::RefUpdateContext& rCxt );
     virtual ~RefMovedHint();
 
     /**
@@ -57,6 +60,8 @@ public:
      * Get the movement vector.
      */
     const ScAddress& getDelta() const;
+
+    const sc::RefUpdateContext& getContext() const;
 };
 
 class RefColReorderHint : public RefHint
diff --git a/sc/inc/tokenarray.hxx b/sc/inc/tokenarray.hxx
index 8ae6145..9762364 100644
--- a/sc/inc/tokenarray.hxx
+++ b/sc/inc/tokenarray.hxx
@@ -152,11 +152,8 @@ public:
      * Move reference positions that are within specified moved range.
      *
      * @param rPos position of this formula cell
-     * @param rMovedRange range that has been moved.
-     * @param rDelta movement vector.
      */
-    void MoveReference(
-        const ScAddress& rPos, const ScRange& rMovedRange, const ScAddress& rDelta );
+    sc::RefUpdateResult MoveReference( const ScAddress& rPos, const sc::RefUpdateContext& rCxt );
 
     /**
      * Move reference positions in response to column reordering.  A range
diff --git a/sc/inc/types.hxx b/sc/inc/types.hxx
index 37784dc..8dc8f18 100644
--- a/sc/inc/types.hxx
+++ b/sc/inc/types.hxx
@@ -100,6 +100,12 @@ struct RangeMatrix
 
 typedef boost::unordered_map<SCCOLROW,SCCOLROW> ColRowReorderMapType;
 
+enum AreaOverlapType
+{
+    AreaInside,
+    AreaPartialOverlap
+};
+
 }
 
 #endif
diff --git a/sc/source/core/data/bcaslot.cxx b/sc/source/core/data/bcaslot.cxx
index 701e530..ea70ffb 100644
--- a/sc/source/core/data/bcaslot.cxx
+++ b/sc/source/core/data/bcaslot.cxx
@@ -432,7 +432,8 @@ void ScBroadcastAreaSlot::EraseArea( ScBroadcastAreas::iterator& rIter )
     }
 }
 
-void ScBroadcastAreaSlot::GetAllListeners( const ScRange& rRange, std::vector<sc::AreaListener>& rListeners )
+void ScBroadcastAreaSlot::GetAllListeners(
+    const ScRange& rRange, std::vector<sc::AreaListener>& rListeners, sc::AreaOverlapType eType )
 {
     for (ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin()),
             aIterEnd( aBroadcastAreaTbl.end()); aIter != aIterEnd; ++aIter )
@@ -442,7 +443,14 @@ void ScBroadcastAreaSlot::GetAllListeners( const ScRange& rRange, std::vector<sc
 
         ScBroadcastArea* pArea = (*aIter).mpArea;
         const ScRange& rAreaRange = pArea->GetRange();
-        if (!rRange.In(rAreaRange))
+
+        if (eType == sc::AreaInside && !rRange.In(rAreaRange))
+            // The range needs to be fully inside specified range.
+            continue;
+
+        if (eType == sc::AreaPartialOverlap &&
+            (!rRange.Intersects(rAreaRange) || rRange.In(rAreaRange)))
+            // The range needs to be only partially overlapping.
             continue;
 
         SvtBroadcaster::ListenersType& rLst = pArea->GetBroadcaster().GetAllListeners();
@@ -967,7 +975,8 @@ void ScBroadcastAreaSlotMachine::FinallyEraseAreas( ScBroadcastAreaSlot* pSlot )
     maAreasToBeErased.swap( aCopy);
 }
 
-std::vector<sc::AreaListener> ScBroadcastAreaSlotMachine::GetAllListeners( const ScRange& rRange )
+std::vector<sc::AreaListener> ScBroadcastAreaSlotMachine::GetAllListeners(
+    const ScRange& rRange, sc::AreaOverlapType eType )
 {
     std::vector<sc::AreaListener> aRet;
 
@@ -984,7 +993,7 @@ std::vector<sc::AreaListener> ScBroadcastAreaSlotMachine::GetAllListeners( const
         while ( nOff <= nEnd )
         {
             ScBroadcastAreaSlot* p = *pp;
-            p->GetAllListeners(rRange, aRet);
+            p->GetAllListeners(rRange, aRet, eType);
             ComputeNextSlot( nOff, nBreak, pp, nStart, ppSlots, nRowBreak);
         }
     }
diff --git a/sc/source/core/data/documen7.cxx b/sc/source/core/data/documen7.cxx
index 5a4df60f1..1682332 100644
--- a/sc/source/core/data/documen7.cxx
+++ b/sc/source/core/data/documen7.cxx
@@ -152,7 +152,7 @@ void ScDocument::BroadcastRefMoved( const sc::RefMovedHint& rHint )
     const ScAddress& rDelta = rHint.getDelta();
 
     // Get all area listeners that listens on the old range, and end their listening.
-    std::vector<sc::AreaListener> aAreaListeners = pBASM->GetAllListeners(rSrcRange);
+    std::vector<sc::AreaListener> aAreaListeners = pBASM->GetAllListeners(rSrcRange, sc::AreaInside);
     {
         std::vector<sc::AreaListener>::iterator it = aAreaListeners.begin(), itEnd = aAreaListeners.end();
         for (; it != itEnd; ++it)
diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx
index eb9a742..49db92e 100644
--- a/sc/source/core/data/document10.cxx
+++ b/sc/source/core/data/document10.cxx
@@ -17,6 +17,7 @@
 #include <listenercontext.hxx>
 #include <tokenstringcontext.hxx>
 #include <poolhelp.hxx>
+#include <bcaslot.hxx>
 
 // Add totally brand-new methods to this source file.
 
@@ -319,4 +320,16 @@ void ScDocument::RegroupFormulaCells( SCTAB nTab, SCCOL nCol )
     pTab->RegroupFormulaCells(nCol);
 }
 
+void ScDocument::CollectAllAreaListeners(
+    std::vector<SvtListener*>& rListener, const ScRange& rRange, sc::AreaOverlapType eType )
+{
+    if (!pBASM)
+        return;
+
+    std::vector<sc::AreaListener> aAL = pBASM->GetAllListeners(rRange, eType);
+    std::vector<sc::AreaListener>::iterator it = aAL.begin(), itEnd = aAL.end();
+    for (; it != itEnd; ++it)
+        rListener.push_back(it->mpListener);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 3c506ae..d846501 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -1932,7 +1932,16 @@ void ScFormulaCell::Notify( const SfxHint& rHint )
 
                 const sc::RefMovedHint& rRefMoved = static_cast<const sc::RefMovedHint&>(rRefHint);
                 if (!IsShared() || IsSharedTop())
-                    pCode->MoveReference(aPos, rRefMoved.getRange(), rRefMoved.getDelta());
+                {
+                    sc::RefUpdateResult aRes = pCode->MoveReference(aPos, rRefMoved.getContext());
+                    if (aRes.mbNameModified)
+                    {
+                        // RPN token needs to be re-generated.
+                        bCompile = true;
+                        CompileTokenArray();
+                        SetDirtyVar();
+                    }
+                }
             }
             break;
             case sc::RefHint::ColumnReordered:
@@ -2883,6 +2892,9 @@ bool ScFormulaCell::UpdateReferenceOnMove(
         sc::RefUpdateResult aRes = pCode->AdjustReferenceOnMove(rCxt, aOldPos, aPos);
         bRefModified = aRes.mbReferenceModified || aRes.mbNameModified;
         bValChanged = aRes.mbValueChanged;
+        if (aRes.mbNameModified)
+            // Re-compile to get the RPN token regenerated to reflect updated names.
+            bCompile = true;
     }
 
     if (bValChanged || bRefModified)
@@ -2933,7 +2945,7 @@ bool ScFormulaCell::UpdateReferenceOnMove(
 
     bValChanged = false;
 
-    bCompile = (bCompile || bValChanged || bRefModified || bColRowNameCompile);
+    bCompile = (bCompile || bValChanged || bColRowNameCompile);
     if ( bCompile )
     {
         CompileTokenArray( bNewListening ); // no Listening
diff --git a/sc/source/core/inc/bcaslot.hxx b/sc/source/core/inc/bcaslot.hxx
index 2980875..59812af 100644
--- a/sc/source/core/inc/bcaslot.hxx
+++ b/sc/source/core/inc/bcaslot.hxx
@@ -214,7 +214,8 @@ public:
      */
     void                EraseArea( ScBroadcastAreas::iterator& rIter );
 
-    void GetAllListeners( const ScRange& rRange, std::vector<sc::AreaListener>& rListeners );
+    void GetAllListeners(
+        const ScRange& rRange, std::vector<sc::AreaListener>& rListeners, sc::AreaOverlapType eType );
 };
 
 /**
@@ -309,7 +310,8 @@ public:
     // only for ScBroadcastAreaSlot
     void                FinallyEraseAreas( ScBroadcastAreaSlot* pSlot );
 
-    std::vector<sc::AreaListener> GetAllListeners( const ScRange& rRange );
+    std::vector<sc::AreaListener> GetAllListeners(
+        const ScRange& rRange, sc::AreaOverlapType eType );
 };
 
 class ScBulkBroadcast
diff --git a/sc/source/core/tool/refhint.cxx b/sc/source/core/tool/refhint.cxx
index 533a41b..f76489c 100644
--- a/sc/source/core/tool/refhint.cxx
+++ b/sc/source/core/tool/refhint.cxx
@@ -19,8 +19,8 @@ RefHint::Type RefHint::getType() const
     return meType;
 }
 
-RefMovedHint::RefMovedHint( const ScRange& rRange, const ScAddress& rMove ) :
-    RefHint(Moved), maRange(rRange), maMoveDelta(rMove) {}
+RefMovedHint::RefMovedHint( const ScRange& rRange, const ScAddress& rMove, const sc::RefUpdateContext& rCxt ) :
+    RefHint(Moved), maRange(rRange), maMoveDelta(rMove), mrCxt(rCxt) {}
 
 RefMovedHint::~RefMovedHint() {}
 
@@ -34,6 +34,11 @@ const ScAddress& RefMovedHint::getDelta() const
     return maMoveDelta;
 }
 
+const sc::RefUpdateContext& RefMovedHint::getContext() const
+{
+    return mrCxt;
+}
+
 RefColReorderHint::RefColReorderHint( const sc::ColRowReorderMapType& rColMap, SCTAB nTab, SCROW nRow1, SCROW nRow2 ) :
     RefHint(ColumnReordered), mrColMap(rColMap), mnTab(nTab), mnRow1(nRow1), mnRow2(nRow2) {}
 
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index 569834a..080e958 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -2865,9 +2865,13 @@ sc::RefUpdateResult ScTokenArray::AdjustReferenceOnMove(
     return aRes;
 }
 
-void ScTokenArray::MoveReference(
-    const ScAddress& rPos, const ScRange& rMovedRange, const ScAddress& rDelta )
+sc::RefUpdateResult ScTokenArray::MoveReference( const ScAddress& rPos, const sc::RefUpdateContext& rCxt )
 {
+    sc::RefUpdateResult aRes;
+
+    ScRange aOldRange = rCxt.maRange;
+    aOldRange.Move(-rCxt.mnColDelta, -rCxt.mnRowDelta, -rCxt.mnTabDelta);
+
     FormulaToken** p = pCode;
     FormulaToken** pEnd = p + static_cast<size_t>(nLen);
     for (; p != pEnd; ++p)
@@ -2879,9 +2883,9 @@ void ScTokenArray::MoveReference(
                 ScToken* pToken = static_cast<ScToken*>(*p);
                 ScSingleRefData& rRef = pToken->GetSingleRef();
                 ScAddress aAbs = rRef.toAbs(rPos);
-                if (rMovedRange.In(aAbs))
+                if (aOldRange.In(aAbs))
                 {
-                    aAbs.Move(rDelta.Col(), rDelta.Row(), rDelta.Tab());
+                    aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
                     rRef.SetAddress(aAbs, rPos);
                 }
             }
@@ -2891,17 +2895,25 @@ void ScTokenArray::MoveReference(
                 ScToken* pToken = static_cast<ScToken*>(*p);
                 ScComplexRefData& rRef = pToken->GetDoubleRef();
                 ScRange aAbs = rRef.toAbs(rPos);
-                if (rMovedRange.In(aAbs))
+                if (aOldRange.In(aAbs))
                 {
-                    aAbs.Move(rDelta.Col(), rDelta.Row(), rDelta.Tab());
+                    aAbs.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
                     rRef.SetRange(aAbs, rPos);
                 }
             }
             break;
+            case svIndex:
+            {
+                if (isNameModified(rCxt.maUpdatedNames, aOldRange.aStart.Tab(), **p))
+                    aRes.mbNameModified = true;
+            }
+            break;
             default:
                 ;
         }
     }
+
+    return aRes;
 }
 
 void ScTokenArray::MoveReferenceColReorder(
diff --git a/sc/source/ui/docshell/docfunc.cxx b/sc/source/ui/docshell/docfunc.cxx
index d41caee..ff27635 100644
--- a/sc/source/ui/docshell/docfunc.cxx
+++ b/sc/source/ui/docshell/docfunc.cxx
@@ -2679,8 +2679,8 @@ bool ScDocFunc::MoveBlock( const ScRange& rSource, const ScAddress& rDestPos,
         {
             rDoc.CopyToDocument( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab,
                                     nUndoFlags, false, pUndoDoc );
-            pRefUndoDoc = new ScDocument( SCDOCMODE_UNDO );
-            pRefUndoDoc->InitUndo( &rDoc, 0, nTabCount-1, false, false );
+//          pRefUndoDoc = new ScDocument( SCDOCMODE_UNDO );
+//          pRefUndoDoc->InitUndo( &rDoc, 0, nTabCount-1, false, false );
         }
 
         if ( nDestTab != nStartTab )
@@ -2689,7 +2689,7 @@ bool ScDocFunc::MoveBlock( const ScRange& rSource, const ScAddress& rDestPos,
                                     nDestEndCol, nDestEndRow, nDestEndTab,
                                     nUndoFlags, false, pUndoDoc );
 
-        pUndoData = new ScRefUndoData( &rDoc );
+//      pUndoData = new ScRefUndoData( &rDoc );
 
         rDoc.BeginDrawUndo();
     }
diff --git a/sc/source/ui/undo/undoblk.cxx b/sc/source/ui/undo/undoblk.cxx
index 982925d..be6895f 100644
--- a/sc/source/ui/undo/undoblk.cxx
+++ b/sc/source/ui/undo/undoblk.cxx
@@ -52,6 +52,7 @@
 #include <refupdatecontext.hxx>
 #include <validat.hxx>
 #include <gridwin.hxx>
+#include <svl/listener.hxx>
 
 #include <set>
 #include <boost/scoped_ptr.hpp>
@@ -1249,6 +1250,22 @@ void ScUndoDragDrop::DoUndo( ScRange aRange )
     maPaintRanges.Join(aPaintRange);
 }
 
+namespace {
+
+class DataChangeNotifier : std::unary_function<SvtListener*, void>
+{
+    ScHint maHint;
+public:
+    DataChangeNotifier() : maHint(SC_HINT_DATACHANGED, ScAddress()) {}
+
+    void operator() ( SvtListener* p )
+    {
+        p->Notify(maHint);
+    }
+};
+
+}
+
 void ScUndoDragDrop::Undo()
 {
     mnPaintExtFlags = 0;
@@ -1258,32 +1275,64 @@ void ScUndoDragDrop::Undo()
 
     if (bCut)
     {
-        // Notify all listeners of the destination range, and have them update their references.
+        // During undo, we move cells from aDestRange to aSrcRange.
+
         ScDocument& rDoc = pDocShell->GetDocument();
+
         SCCOL nColDelta = aSrcRange.aStart.Col() - aDestRange.aStart.Col();
         SCROW nRowDelta = aSrcRange.aStart.Row() - aDestRange.aStart.Row();
         SCTAB nTabDelta = aSrcRange.aStart.Tab() - aDestRange.aStart.Tab();
-        sc::RefMovedHint aHint(aDestRange, ScAddress(nColDelta, nRowDelta, nTabDelta));
+
+        sc::RefUpdateContext aCxt(rDoc);
+        aCxt.meMode = URM_MOVE;
+        aCxt.maRange = aSrcRange;
+        aCxt.mnColDelta = nColDelta;
+        aCxt.mnRowDelta = nRowDelta;
+        aCxt.mnTabDelta = nTabDelta;
+
+        // Global range names.
+        ScRangeName* pName = rDoc.GetRangeName();
+        if (pName)
+            pName->UpdateReference(aCxt);
+
+        SCTAB nTabCount = rDoc.GetTableCount();
+        for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
+        {
+            // Sheet-local range names.
+            pName = rDoc.GetRangeName(nTab);
+            if (pName)
+                pName->UpdateReference(aCxt, nTab);
+        }
+
+        // Notify all listeners of the destination range, and have them update their references.
+        sc::RefMovedHint aHint(aDestRange, ScAddress(nColDelta, nRowDelta, nTabDelta), aCxt);
         rDoc.BroadcastRefMoved(aHint);
 
         ScValidationDataList* pValidList = rDoc.GetValidationList();
         if (pValidList)
         {
             // Update the references of validation entries.
-            sc::RefUpdateContext aCxt(rDoc);
-            aCxt.meMode = URM_MOVE;
-            aCxt.maRange = aSrcRange;
-            aCxt.mnColDelta = nColDelta;
-            aCxt.mnRowDelta = nRowDelta;
-            aCxt.mnTabDelta = nTabDelta;
             pValidList->UpdateReference(aCxt);
         }
-    }
 
-    DoUndo(aDestRange);
-    if (bCut)
+        DoUndo(aDestRange);
         DoUndo(aSrcRange);
 
+        // Notify all area listeners whose listened areas are partially moved, to
+        // recalculate.
+        std::vector<SvtListener*> aListeners;
+        rDoc.CollectAllAreaListeners(aListeners, aSrcRange, sc::AreaPartialOverlap);
+
+        // Remove any duplicate listener entries.  We must ensure that we notify
+        // each unique listener only once.
+        std::sort(aListeners.begin(), aListeners.end());
+        aListeners.erase(std::unique(aListeners.begin(), aListeners.end()), aListeners.end());
+
+        std::for_each(aListeners.begin(), aListeners.end(), DataChangeNotifier());
+    }
+    else
+        DoUndo(aDestRange);
+
     for (size_t i = 0; i < maPaintRanges.size(); ++i)
     {
         const ScRange* p = maPaintRanges[i];
commit 85f8f8f8589af3c404339c0f78021a7fe21cdfcd
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Wed Jul 30 12:35:26 2014 -0400

    fdo#78555: Write test for this first.
    
    Change-Id: I01f7ca80d8d2ac4c3b5f262625cc54a27cf4327a

diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index b067a22..e4a6b8c 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -290,6 +290,7 @@ public:
     void testSharedFormulas();
     void testSharedFormulasRefUpdate();
     void testSharedFormulasRefUpdateMove();
+    void testSharedFormulasRefUpdateMove2();
     void testSharedFormulasRefUpdateRange();
     void testSharedFormulasRefUpdateExternal();
     void testSharedFormulasInsertRow();
@@ -499,6 +500,7 @@ public:
     CPPUNIT_TEST(testSharedFormulas);
     CPPUNIT_TEST(testSharedFormulasRefUpdate);
     CPPUNIT_TEST(testSharedFormulasRefUpdateMove);
+    CPPUNIT_TEST(testSharedFormulasRefUpdateMove2);
     CPPUNIT_TEST(testSharedFormulasRefUpdateRange);
     CPPUNIT_TEST(testSharedFormulasRefUpdateExternal);
     CPPUNIT_TEST(testSharedFormulasInsertRow);
diff --git a/sc/qa/unit/ucalc_sharedformula.cxx b/sc/qa/unit/ucalc_sharedformula.cxx
index 5fa1dfa..8c49076 100644
--- a/sc/qa/unit/ucalc_sharedformula.cxx
+++ b/sc/qa/unit/ucalc_sharedformula.cxx
@@ -459,6 +459,74 @@ void Test::testSharedFormulasRefUpdateMove()
     m_pDoc->DeleteTab(0);
 }
 
+void Test::testSharedFormulasRefUpdateMove2()
+{
+    sc::AutoCalcSwitch aACSwitch(*m_pDoc, false); // turn auto calc off this time.
+    FormulaGrammarSwitch aFGSwitch(m_pDoc, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1);
+
+    m_pDoc->InsertTab(0, "Test");
+
+    // Set values in B2:B3, and E2:E3.
+    for (SCROW i = 1; i <= 2; ++i)
+    {
+        m_pDoc->SetValue(ScAddress(1,i,0), i);
+        m_pDoc->SetValue(ScAddress(4,i,0), i);
+    }
+
+    // Make sure the values are really there.
+    CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(1,1,0)));
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(1,2,0)));
+    CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(4,1,0)));
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(4,2,0)));
+
+    // Set formulas in C2:C3 that reference B2:B4 individually, and F2:F3 to E2:E3.
+    for (SCROW i = 1; i <= 2; ++i)
+    {
+        m_pDoc->SetString(ScAddress(2,i,0), "=RC[-1]");
+        m_pDoc->SetString(ScAddress(5,i,0), "=RC[-1]");
+    }
+
+    m_pDoc->CalcFormulaTree(); // calculate manually.
+
+    // Check the formula results.
+    CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(2,1,0)));
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(2,2,0)));
+    CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(5,1,0)));
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(5,2,0)));
+
+    // Move B2:C3 to C3:D4.
+    bool bMoved = getDocShell().GetDocFunc().MoveBlock(
+        ScRange(1,1,0,2,2,0), ScAddress(2,2,0), true, true, false, true);
+    CPPUNIT_ASSERT(bMoved);
+
+    // Make sure the range has been moved.
+    CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(2,2,0)));
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(2,3,0)));
+
+    // The formula cells should retain their results even with auto calc off
+    // and without recalculation.
+    CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(3,2,0)));
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(3,3,0)));
+
+    // And these formulas in F2:F3 are unaffected, therefore should not change.
+    CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(5,1,0)));
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(5,2,0)));
+
+    SfxUndoManager* pUndoMgr = m_pDoc->GetUndoManager();
+    CPPUNIT_ASSERT(pUndoMgr);
+
+    // Undo the move.
+    pUndoMgr->Undo();
+
+    // Check the formula results.  The results should still be intact.
+    CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(2,1,0)));
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(2,2,0)));
+    CPPUNIT_ASSERT_EQUAL(1.0, m_pDoc->GetValue(ScAddress(5,1,0)));
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(5,2,0)));
+
+    m_pDoc->DeleteTab(0);
+}
+
 void Test::testSharedFormulasRefUpdateRange()
 {
     m_pDoc->InsertTab(0, "Test");


More information about the Libreoffice-commits mailing list