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

Kohei Yoshida kohei.yoshida at collabora.com
Mon Apr 7 11:43:43 PDT 2014


 formula/source/core/api/token.cxx       |   13 ++
 include/formula/tokenarray.hxx          |   12 ++
 sc/inc/column.hxx                       |   11 ++
 sc/inc/document.hxx                     |   11 ++
 sc/inc/formulacell.hxx                  |    8 +
 sc/inc/formulagroup.hxx                 |   18 +++
 sc/inc/table.hxx                        |    4 
 sc/qa/unit/ucalc.cxx                    |   15 +--
 sc/qa/unit/ucalc.hxx                    |    5 -
 sc/qa/unit/ucalc_sharedformula.cxx      |   83 +++++++++++++++++
 sc/source/core/data/column.cxx          |   44 +++------
 sc/source/core/data/column2.cxx         |   21 ----
 sc/source/core/data/column4.cxx         |  151 ++++++++++++++++++++++++++++++++
 sc/source/core/data/documen4.cxx        |   11 --
 sc/source/core/data/document10.cxx      |   20 ++++
 sc/source/core/data/formulacell.cxx     |   76 ++++++----------
 sc/source/core/data/table4.cxx          |    6 -
 sc/source/core/data/table7.cxx          |   12 ++
 sc/source/core/tool/formulagroup.cxx    |    6 +
 sc/source/filter/oox/workbookhelper.cxx |    4 
 sc/source/ui/docshell/docfunc.cxx       |   11 --
 sc/source/ui/undo/undocell.cxx          |    4 
 sc/source/ui/undo/undorangename.cxx     |    6 -
 sc/source/ui/unoobj/nameuno.cxx         |    4 
 sc/source/ui/view/viewfunc.cxx          |    5 -
 25 files changed, 416 insertions(+), 145 deletions(-)

New commits:
commit 355baf573425165cbc1c789a6271eb29940e1f76
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Mon Apr 7 14:13:20 2014 -0400

    fdo#75741: Re-implement CompileNameFormula for formula groups.
    
    Change-Id: I57e1e464ac5f7abc10ce5ea5752e036ddb6cf6d7

diff --git a/formula/source/core/api/token.cxx b/formula/source/core/api/token.cxx
index 4f8b8aa..da98d0e 100644
--- a/formula/source/core/api/token.cxx
+++ b/formula/source/core/api/token.cxx
@@ -616,6 +616,19 @@ bool FormulaTokenArray::HasNameOrColRowName() const
     return false;
 }
 
+bool FormulaTokenArray::HasOpCodes( const boost::unordered_set<OpCode>& rOpCodes ) const
+{
+    FormulaToken** p = pCode;
+    FormulaToken** pEnd = p + static_cast<size_t>(nLen);
+    for (; p != pEnd; ++p)
+    {
+        OpCode eOp = (*p)->GetOpCode();
+        if (rOpCodes.count(eOp) > 0)
+            return true;
+    }
+
+    return false;
+}
 
 FormulaTokenArray::FormulaTokenArray() :
     pCode(NULL),
diff --git a/include/formula/tokenarray.hxx b/include/formula/tokenarray.hxx
index e5d0282..7370e43 100644
--- a/include/formula/tokenarray.hxx
+++ b/include/formula/tokenarray.hxx
@@ -25,6 +25,8 @@
 #include <formula/ExternalReferenceHelper.hxx>
 #include <limits.h>
 
+#include <boost/unordered_set.hpp>
+
 namespace formula
 {
 
@@ -123,6 +125,16 @@ public:
     /// Token of type svIndex or opcode ocColRowName
     bool    HasNameOrColRowName() const;
 
+    /**
+     * Check if the token array contains any of specified opcode tokens.
+     *
+     * @param rOpCodes collection of opcodes to check against.
+     *
+     * @return true if the token array contains at least one of the specified
+     *         opcode tokens, false otherwise.
+     */
+    bool HasOpCodes( const boost::unordered_set<OpCode>& rOpCodes ) const;
+
     FormulaToken** GetArray() const  { return pCode; }
     FormulaToken** GetCode()  const  { return pRPN; }
     sal_uInt16    GetLen() const     { return nLen; }
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index a84f836..42f2779 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -40,6 +40,7 @@ namespace formula { struct VectorRefArray; }
 namespace sc {
 
 struct FormulaGroupContext;
+struct FormulaGroupEntry;
 class StartListeningContext;
 class EndListeningContext;
 class CopyFromClipContext;
@@ -371,6 +372,9 @@ public:
     void        SetTabNo(SCTAB nNewTab);
     void        FindRangeNamesInUse(SCROW nRow1, SCROW nRow2, std::set<sal_uInt16>& rIndexes) const;
 
+    void PreprocessRangeNameUpdate();
+    void PostprocessRangeNameUpdate();
+
     const SfxPoolItem*      GetAttr( SCROW nRow, sal_uInt16 nWhich ) const;
     const ScPatternAttr*    GetPattern( SCROW nRow ) const;
     const ScPatternAttr*    GetMostUsedPattern( SCROW nStartRow, SCROW nEndRow ) const;
@@ -470,7 +474,6 @@ public:
 
     void CompileDBFormula( sc::CompileFormulaContext& rCxt );
     void CompileDBFormula( sc::CompileFormulaContext& rCxt, bool bCreateFormulaString );
-    void CompileNameFormula( sc::CompileFormulaContext& rCxt, bool bCreateFormulaString );
     void CompileColRowNameFormula( sc::CompileFormulaContext& rCxt );
 
     sal_Int32   GetMaxStringLen( SCROW nRowStart, SCROW nRowEnd, rtl_TextEncoding eCharSet ) const;
@@ -599,6 +602,12 @@ private:
     void DeleteCells(
         sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2, sal_uInt16 nDelFlag,
         std::vector<SCROW>& rDeleted );
+
+    /**
+     * Get all non-grouped formula cells and formula cell groups in the whole
+     * column.
+     */
+    std::vector<sc::FormulaGroupEntry> GetFormulaGroupEntries();
 };
 
 #endif
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 5b8579b..6fe5f9f 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -516,6 +516,16 @@ public:
     void SetRangeName( ScRangeName* pNewRangeName );
 
     /**
+     * Call this immediately before updating all named ranges.
+     */
+    SC_DLLPUBLIC void PreprocessRangeNameUpdate();
+
+    /**
+     * Call this immediately after all named ranges have been updated.
+     */
+    SC_DLLPUBLIC void PostprocessRangeNameUpdate();
+
+    /**
      * Insert a new named expression to the global scope.
      *
      * @param rName name for the expression.
@@ -1967,7 +1977,6 @@ public:
 
     void            CompileDBFormula();
     void            CompileDBFormula( bool bCreateFormulaString );
-    SC_DLLPUBLIC void CompileNameFormula( bool bCreateFormulaString );
     void            CompileColRowNameFormula();
 
     /** Maximum string length of a column, e.g. for dBase export.
diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index 15b5adb..57f249d 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -76,6 +76,7 @@ struct SC_DLLPUBLIC ScFormulaCellGroup : boost::noncopyable
     void scheduleCompilation();
 
     void setCode( const ScTokenArray& rCode );
+    void setCode( ScTokenArray* pCode );
     void compileCode(
         ScDocument& rDoc, const ScAddress& rPos, formula::FormulaGrammar::Grammar eGram );
     void compileOpenCLKernel();
@@ -303,11 +304,12 @@ public:
     ScTokenArray* GetCode();
     const ScTokenArray* GetCode() const;
 
+    void SetCode( ScTokenArray* pNew );
+
     bool            IsRunning() const;
     void            SetRunning( bool bVal );
     void CompileDBFormula( sc::CompileFormulaContext& rCxt );
     void CompileDBFormula( sc::CompileFormulaContext& rCxt, bool bCreateFormulaString );
-    void CompileNameFormula( sc::CompileFormulaContext& rCxt, bool bCreateFormulaString );
     void CompileColRowNameFormula( sc::CompileFormulaContext& rCxt );
     ScFormulaCell*  GetPrevious() const;
     ScFormulaCell*  GetNext() const;
@@ -344,6 +346,8 @@ public:
     void SetHybridFormula(
         const OUString& r, const formula::FormulaGrammar::Grammar eGrammar );
 
+    OUString GetHybridFormula() const;
+
     void SetResultMatrix( SCCOL nCols, SCROW nRows, const ScConstMatrixRef& pMat, formula::FormulaToken* pUL );
 
     /** For import only: set a double result.
@@ -393,6 +397,8 @@ public:
     ScTokenArray* GetSharedCode();
     const ScTokenArray* GetSharedCode() const;
 
+    void SyncSharedCode();
+
     bool IsPostponedDirty() const;
 };
 
diff --git a/sc/inc/formulagroup.hxx b/sc/inc/formulagroup.hxx
index 4cca9c8..311653a 100644
--- a/sc/inc/formulagroup.hxx
+++ b/sc/inc/formulagroup.hxx
@@ -24,9 +24,27 @@
 
 class ScDocument;
 class ScTokenArray;
+class ScFormulaCell;
 
 namespace sc {
 
+struct FormulaGroupEntry
+{
+    union
+    {
+        ScFormulaCell* mpCell;   // non-shared formula cell
+        ScFormulaCell** mpCells; // pointer to the top formula cell in a shared group.
+    };
+
+    size_t mnRow;
+    size_t mnLength;
+    bool mbShared;
+
+    FormulaGroupEntry( ScFormulaCell** pCells, size_t nRow, size_t nLength );
+
+    FormulaGroupEntry( ScFormulaCell* pCell, size_t nRow );
+};
+
 struct FormulaGroupContext : boost::noncopyable
 {
     typedef AlignedAllocator<double,256> DoubleAllocType;
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 59a8f58..b325c80 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -847,6 +847,9 @@ public:
     void SetRangeName(ScRangeName* pNew);
     ScRangeName* GetRangeName() const;
 
+    void PreprocessRangeNameUpdate();
+    void PostprocessRangeNameUpdate();
+
     ScConditionalFormatList* GetCondFormList();
     const ScConditionalFormatList* GetCondFormList() const;
     void SetCondFormList( ScConditionalFormatList* pList );
@@ -1025,7 +1028,6 @@ private:
     bool        TestTabRefAbs(SCTAB nTable) const;
     void CompileDBFormula( sc::CompileFormulaContext& rCxt );
     void CompileDBFormula( sc::CompileFormulaContext& rCxt, bool bCreateFormulaString );
-    void CompileNameFormula( sc::CompileFormulaContext& rCxt, bool bCreateFormulaString );
     void CompileColRowNameFormula( sc::CompileFormulaContext& rCxt );
 
     void        StartListening( const ScAddress& rAddress, SvtListener* pListener );
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index f48a961..2d2c44e 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -44,6 +44,7 @@
 #include <listenercontext.hxx>
 #include <refhint.hxx>
 #include <stlalgorithm.hxx>
+#include <formulagroup.hxx>
 
 #include <svl/poolcach.hxx>
 #include <svl/zforlist.hxx>
@@ -2339,23 +2340,6 @@ void ScColumn::MarkSubTotalCells( sc::ColumnSpanSet& rSet, SCROW nRow1, SCROW nR
 
 namespace {
 
-struct FormulaGroup
-{
-    struct {
-        ScFormulaCell* mpCell;   // non-shared formula cell
-        ScFormulaCell** mpCells; // pointer to the top formula cell in a shared group.
-    };
-    size_t mnRow;
-    size_t mnLength;
-    bool mbShared;
-
-    FormulaGroup( ScFormulaCell** pCells, size_t nRow, size_t nLength ) :
-        mpCells(pCells), mnRow(nRow), mnLength(nLength), mbShared(true) {}
-
-    FormulaGroup( ScFormulaCell* pCell, size_t nRow ) :
-        mpCell(pCell), mnRow(nRow), mnLength(0), mbShared(false) {}
-};
-
 class SharedTopFormulaCellPicker : std::unary_function<sc::CellStoreType::value_type, void>
 {
 public:
@@ -2430,7 +2414,7 @@ public:
     }
 };
 
-class UpdateRefOnNonCopy : std::unary_function<FormulaGroup, void>
+class UpdateRefOnNonCopy : std::unary_function<sc::FormulaGroupEntry, void>
 {
     SCCOL mnCol;
     SCROW mnTab;
@@ -2438,7 +2422,7 @@ class UpdateRefOnNonCopy : std::unary_function<FormulaGroup, void>
     ScDocument* mpUndoDoc;
     bool mbUpdated;
 
-    void updateRefOnShift( FormulaGroup& rGroup )
+    void updateRefOnShift( sc::FormulaGroupEntry& rGroup )
     {
         if (!rGroup.mbShared)
         {
@@ -2500,7 +2484,7 @@ class UpdateRefOnNonCopy : std::unary_function<FormulaGroup, void>
         }
     }
 
-    void updateRefOnMove( FormulaGroup& rGroup )
+    void updateRefOnMove( sc::FormulaGroupEntry& rGroup )
     {
         if (!rGroup.mbShared)
         {
@@ -2611,7 +2595,7 @@ public:
         mnCol(nCol), mnTab(nTab), mpCxt(pCxt),
         mpUndoDoc(pUndoDoc), mbUpdated(false) {}
 
-    void operator() ( FormulaGroup& rGroup )
+    void operator() ( sc::FormulaGroupEntry& rGroup )
     {
         switch (mpCxt->meMode)
         {
@@ -2669,21 +2653,21 @@ public:
 
 class FormulaGroupPicker : public SharedTopFormulaCellPicker
 {
-    std::vector<FormulaGroup>& mrGroups;
+    std::vector<sc::FormulaGroupEntry>& mrGroups;
 
 public:
-    FormulaGroupPicker( std::vector<FormulaGroup>& rGroups ) : mrGroups(rGroups) {}
+    FormulaGroupPicker( std::vector<sc::FormulaGroupEntry>& rGroups ) : mrGroups(rGroups) {}
 
     virtual ~FormulaGroupPicker() {}
 
     virtual void processNonShared( ScFormulaCell* pCell, size_t nRow ) SAL_OVERRIDE
     {
-        mrGroups.push_back(FormulaGroup(pCell, nRow));
+        mrGroups.push_back(sc::FormulaGroupEntry(pCell, nRow));
     }
 
     virtual void processSharedTop( ScFormulaCell** ppCells, size_t nRow, size_t nLength ) SAL_OVERRIDE
     {
-        mrGroups.push_back(FormulaGroup(ppCells, nRow, nLength));
+        mrGroups.push_back(sc::FormulaGroupEntry(ppCells, nRow, nLength));
     }
 };
 
@@ -2756,8 +2740,7 @@ bool ScColumn::UpdateReference( sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc
     sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds);
 
     // Collect all formula groups.
-    std::vector<FormulaGroup> aGroups;
-    std::for_each(maCells.begin(), maCells.end(), FormulaGroupPicker(aGroups));
+    std::vector<sc::FormulaGroupEntry> aGroups = GetFormulaGroupEntries();
 
     // Process all collected formula groups.
     UpdateRefOnNonCopy aHandler(nCol, nTab, &rCxt, pUndoDoc);
@@ -2768,6 +2751,13 @@ bool ScColumn::UpdateReference( sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc
     return aHandler.isUpdated();
 }
 
+std::vector<sc::FormulaGroupEntry> ScColumn::GetFormulaGroupEntries()
+{
+    std::vector<sc::FormulaGroupEntry> aGroups;
+    std::for_each(maCells.begin(), maCells.end(), FormulaGroupPicker(aGroups));
+    return aGroups;
+}
+
 namespace {
 
 class UpdateTransHandler
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index a5d982f..aea1277 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -3009,21 +3009,6 @@ public:
     }
 };
 
-class CompileNameFormulaHandler
-{
-    sc::CompileFormulaContext& mrCxt;
-    bool mbCreateFormulaString;
-
-public:
-    CompileNameFormulaHandler( sc::CompileFormulaContext& rCxt, bool bCreateFormulaString) :
-        mrCxt(rCxt), mbCreateFormulaString(bCreateFormulaString) {}
-
-    void operator() (size_t, ScFormulaCell* p)
-    {
-        p->CompileNameFormula(mrCxt, mbCreateFormulaString);
-    }
-};
-
 struct CompileColRowNameFormulaHandler
 {
     sc::CompileFormulaContext& mrCxt;
@@ -3052,12 +3037,6 @@ void ScColumn::CompileDBFormula( sc::CompileFormulaContext& rCxt, bool bCreateFo
     RegroupFormulaCells();
 }
 
-void ScColumn::CompileNameFormula( sc::CompileFormulaContext& rCxt, bool bCreateFormulaString )
-{
-    CompileNameFormulaHandler aFunc(rCxt, bCreateFormulaString);
-    sc::ProcessFormula(maCells, aFunc);
-}
-
 void ScColumn::CompileColRowNameFormula( sc::CompileFormulaContext& rCxt )
 {
     CompileColRowNameFormulaHandler aFunc(rCxt);
diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx
index 2f21623..7a360d0 100644
--- a/sc/source/core/data/column4.cxx
+++ b/sc/source/core/data/column4.cxx
@@ -16,18 +16,23 @@
 #include <cellvalues.hxx>
 #include <columnspanset.hxx>
 #include <listenercontext.hxx>
+#include <tokenstringcontext.hxx>
 #include <mtvcellfunc.hxx>
 #include <clipcontext.hxx>
 #include <attrib.hxx>
 #include <patattr.hxx>
 #include <docpool.hxx>
 #include <conditio.hxx>
+#include <formulagroup.hxx>
+#include <tokenarray.hxx>
 
 #include <svl/sharedstringpool.hxx>
 
 #include <vector>
 #include <cassert>
 
+#include <boost/shared_ptr.hpp>
+
 bool ScColumn::IsMerged( SCROW nRow ) const
 {
     return pAttrArray->IsMerged(nRow);
@@ -544,4 +549,150 @@ void ScColumn::GetNotesInRange(SCROW nStartRow, SCROW nEndRow,
     std::for_each(it, itEnd, NoteEntryCollector(rNotes, nTab, nCol, nStartRow, nEndRow));
 }
 
+namespace {
+
+class PreRangeNameUpdateHandler
+{
+    ScDocument* mpDoc;
+    boost::shared_ptr<sc::EndListeningContext> mpEndListenCxt;
+    boost::shared_ptr<sc::CompileFormulaContext> mpCompileFormulaCxt;
+
+public:
+    PreRangeNameUpdateHandler( ScDocument* pDoc ) :
+        mpDoc(pDoc),
+        mpEndListenCxt(new sc::EndListeningContext(*pDoc)),
+        mpCompileFormulaCxt(new sc::CompileFormulaContext(pDoc)) {}
+
+    void operator() ( sc::FormulaGroupEntry& rEntry )
+    {
+        // Perform end listening, remove from formula tree, and set them up
+        // for re-compilation.
+
+        ScFormulaCell* pTop = NULL;
+
+        if (rEntry.mbShared)
+        {
+            // Only inspect the code from the top cell.
+            pTop = *rEntry.mpCells;
+        }
+        else
+            pTop = rEntry.mpCell;
+
+        ScTokenArray* pCode = pTop->GetCode();
+
+        boost::unordered_set<OpCode> aOps;
+        aOps.insert(ocBad);
+        aOps.insert(ocColRowName);
+        aOps.insert(ocName);
+        bool bRecompile = pCode->HasOpCodes(aOps);
+
+        if (bRecompile)
+        {
+            // Get the formula string.
+            OUString aFormula = pTop->GetFormula(*mpCompileFormulaCxt);
+            sal_Int32 n = aFormula.getLength();
+            if (pTop->GetMatrixFlag() != MM_NONE && n > 0)
+            {
+                if (aFormula[0] == '{' && aFormula[n-1] == '}')
+                    aFormula = aFormula.copy(1, n-2);
+            }
+
+            if (rEntry.mbShared)
+            {
+                ScFormulaCell** pp = rEntry.mpCells;
+                ScFormulaCell** ppEnd = pp + rEntry.mnLength;
+                for (; pp != ppEnd; ++pp)
+                {
+                    ScFormulaCell* p = *pp;
+                    p->EndListeningTo(*mpEndListenCxt);
+                    mpDoc->RemoveFromFormulaTree(p);
+                }
+            }
+            else
+            {
+                rEntry.mpCell->EndListeningTo(*mpEndListenCxt);
+                mpDoc->RemoveFromFormulaTree(rEntry.mpCell);
+            }
+
+            pCode->Clear();
+            pTop->SetHybridFormula(aFormula, mpDoc->GetGrammar());
+        }
+    }
+};
+
+class PostRangeNameUpdateHandler
+{
+    ScDocument* mpDoc;
+    boost::shared_ptr<sc::CompileFormulaContext> mpCompileFormulaCxt;
+
+public:
+    PostRangeNameUpdateHandler( ScDocument* pDoc ) :
+        mpDoc(pDoc),
+        mpCompileFormulaCxt(new sc::CompileFormulaContext(pDoc)) {}
+
+    void operator() ( sc::FormulaGroupEntry& rEntry )
+    {
+        if (rEntry.mbShared)
+        {
+            ScFormulaCell* pTop = *rEntry.mpCells;
+            OUString aFormula = pTop->GetHybridFormula();
+
+            // Create a new token array from the hybrid formula string, and
+            // set it to the group.
+            ScCompiler aComp(*mpCompileFormulaCxt, pTop->aPos);
+            ScTokenArray* pNewCode = aComp.CompileString(aFormula);
+            ScFormulaCellGroupRef xGroup = pTop->GetCellGroup();
+            assert(xGroup);
+            xGroup->setCode(pNewCode);
+            xGroup->compileCode(*mpDoc, pTop->aPos, mpDoc->GetGrammar());
+
+            // Propagate the new token array to all formula cells in the group.
+            ScFormulaCell** pp = rEntry.mpCells;
+            ScFormulaCell** ppEnd = pp + rEntry.mnLength;
+            for (; pp != ppEnd; ++pp)
+            {
+                ScFormulaCell* p = *pp;
+                p->SyncSharedCode();
+                p->SetDirty();
+            }
+        }
+        else
+        {
+            ScFormulaCell* pCell = rEntry.mpCell;
+            OUString aFormula = pCell->GetHybridFormula();
+
+            // Create token array from formula string.
+            ScCompiler aComp(*mpCompileFormulaCxt, pCell->aPos);
+            ScTokenArray* pNewCode = aComp.CompileString(aFormula);
+
+            // Generate RPN tokens.
+            ScCompiler aComp2(mpDoc, pCell->aPos, *pNewCode);
+            aComp2.CompileTokenArray();
+
+            pCell->SetCode(pNewCode);
+            pCell->SetDirty();
+        }
+    }
+};
+
+}
+
+void ScColumn::PreprocessRangeNameUpdate()
+{
+    // Collect all formula groups.
+    std::vector<sc::FormulaGroupEntry> aGroups = GetFormulaGroupEntries();
+
+    PreRangeNameUpdateHandler aFunc(pDocument);
+    std::for_each(aGroups.begin(), aGroups.end(), aFunc);
+}
+
+void ScColumn::PostprocessRangeNameUpdate()
+{
+    // Collect all formula groups.
+    std::vector<sc::FormulaGroupEntry> aGroups = GetFormulaGroupEntries();
+
+    PostRangeNameUpdateHandler aFunc(pDocument);
+    std::for_each(aGroups.begin(), aGroups.end(), aFunc);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/documen4.cxx b/sc/source/core/data/documen4.cxx
index 6e3cd33..7e378c1 100644
--- a/sc/source/core/data/documen4.cxx
+++ b/sc/source/core/data/documen4.cxx
@@ -559,17 +559,6 @@ void ScDocument::CompileDBFormula( bool bCreateFormulaString )
     }
 }
 
-void ScDocument::CompileNameFormula( bool bCreateFormulaString )
-{
-    sc::CompileFormulaContext aCxt(this);
-    TableContainer::iterator it = maTabs.begin();
-    for (;it != maTabs.end(); ++it)
-    {
-        if (*it)
-            (*it)->CompileNameFormula(aCxt, bCreateFormulaString);
-    }
-}
-
 void ScDocument::CompileColRowNameFormula()
 {
     sc::CompileFormulaContext aCxt(this);
diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx
index 5030128..84410ab 100644
--- a/sc/source/core/data/document10.cxx
+++ b/sc/source/core/data/document10.cxx
@@ -237,4 +237,24 @@ const ScCalcConfig& ScDocument::GetCalcConfig() const
     return maCalcConfig;
 }
 
+void ScDocument::PreprocessRangeNameUpdate()
+{
+    TableContainer::iterator it = maTabs.begin(), itEnd = maTabs.end();
+    for (; it != itEnd; ++it)
+    {
+        ScTable* p = *it;
+        p->PreprocessRangeNameUpdate();
+    }
+}
+
+void ScDocument::PostprocessRangeNameUpdate()
+{
+    TableContainer::iterator it = maTabs.begin(), itEnd = maTabs.end();
+    for (; it != itEnd; ++it)
+    {
+        ScTable* p = *it;
+        p->PostprocessRangeNameUpdate();
+    }
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index e7d566a..9a21066 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -477,6 +477,14 @@ void ScFormulaCellGroup::setCode( const ScTokenArray& rCode )
     mpCode->GenHash();
 }
 
+void ScFormulaCellGroup::setCode( ScTokenArray* pCode )
+{
+    delete mpCode;
+    mpCode = pCode; // takes ownership of the token array.
+    mbInvariant = mpCode->IsInvariant();
+    mpCode->GenHash();
+}
+
 void ScFormulaCellGroup::compileCode(
     ScDocument& rDoc, const ScAddress& rPos, FormulaGrammar::Grammar eGram )
 {
@@ -2107,6 +2115,11 @@ void ScFormulaCell::SetHybridFormula( const OUString& r,
     aResult.SetHybridFormula( r); eTempGrammar = eGrammar;
 }
 
+OUString ScFormulaCell::GetHybridFormula() const
+{
+    return aResult.GetHybridFormula();
+}
+
 // Dynamically create the URLField on a mouse-over action on a hyperlink() cell.
 void ScFormulaCell::GetURLResult( OUString& rURL, OUString& rCellText )
 {
@@ -3372,6 +3385,13 @@ const ScTokenArray* ScFormulaCell::GetCode() const
     return pCode;
 }
 
+void ScFormulaCell::SetCode( ScTokenArray* pNew )
+{
+    assert(!mxGroup); // Don't call this if it's shared.
+    delete pCode;
+    pCode = pNew; // takes ownership.
+}
+
 bool ScFormulaCell::IsRunning() const
 {
     return bRunning;
@@ -3448,53 +3468,6 @@ void ScFormulaCell::CompileDBFormula( sc::CompileFormulaContext& rCxt, bool bCre
     }
 }
 
-void ScFormulaCell::CompileNameFormula( sc::CompileFormulaContext& rCxt, bool bCreateFormulaString )
-{
-    // Two phases must be called after each other
-    // 1. Formula String with old generated names
-    // 2. Formula String with new generated names
-    if ( bCreateFormulaString )
-    {
-        bool bRecompile = false;
-        pCode->Reset();
-        for ( FormulaToken* p = pCode->First(); p && !bRecompile; p = pCode->Next() )
-        {
-            switch ( p->GetOpCode() )
-            {
-                case ocBad:             // in case RangeName goes bad
-                case ocColRowName:      // in case the names are the same
-                    bRecompile = true;
-                break;
-                default:
-                    if ( p->GetType() == svIndex )
-                        bRecompile = true;  // RangeName
-            }
-        }
-        if ( bRecompile )
-        {
-            OUString aFormula = GetFormula(rCxt);
-            if ( GetMatrixFlag() != MM_NONE && !aFormula.isEmpty() )
-            {
-                if ( aFormula[ aFormula.getLength()-1 ] == '}' )
-                    aFormula = aFormula.copy( 0, aFormula.getLength()-1 );
-                if ( aFormula[0] == '{' )
-                    aFormula = aFormula.copy( 1 );
-            }
-            EndListeningTo( pDocument );
-            pDocument->RemoveFromFormulaTree( this );
-            pCode->Clear();
-            SetHybridFormula(aFormula, rCxt.getGrammar());
-        }
-    }
-    else if ( !pCode->GetLen() && !aResult.GetHybridFormula().isEmpty() )
-    {
-        rCxt.setGrammar(eTempGrammar);
-        Compile(rCxt, aResult.GetHybridFormula(), false);
-        aResult.SetToken( NULL);
-        SetDirty();
-    }
-}
-
 void ScFormulaCell::CompileColRowNameFormula( sc::CompileFormulaContext& rCxt )
 {
     pCode->Reset();
@@ -4053,6 +4026,15 @@ const ScTokenArray* ScFormulaCell::GetSharedCode() const
     return mxGroup ? mxGroup->mpCode : NULL;
 }
 
+void ScFormulaCell::SyncSharedCode()
+{
+    if (!mxGroup)
+        // Not a shared formula cell.
+        return;
+
+    pCode = mxGroup->mpCode;
+}
+
 bool ScFormulaCell::IsPostponedDirty() const
 {
     return mbPostponedDirty;
diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx
index f24889e..96acd2c 100644
--- a/sc/source/core/data/table4.cxx
+++ b/sc/source/core/data/table4.cxx
@@ -2184,12 +2184,6 @@ void ScTable::CompileDBFormula( sc::CompileFormulaContext& rCxt, bool bCreateFor
         aCol[i].CompileDBFormula(rCxt, bCreateFormulaString);
 }
 
-void ScTable::CompileNameFormula( sc::CompileFormulaContext& rCxt, bool bCreateFormulaString )
-{
-    for (SCCOL i = 0; i <= MAXCOL; ++i)
-        aCol[i].CompileNameFormula(rCxt, bCreateFormulaString);
-}
-
 void ScTable::CompileColRowNameFormula( sc::CompileFormulaContext& rCxt )
 {
     for (SCCOL i = 0; i <= MAXCOL; ++i)
diff --git a/sc/source/core/data/table7.cxx b/sc/source/core/data/table7.cxx
index a5936cb..9406326 100644
--- a/sc/source/core/data/table7.cxx
+++ b/sc/source/core/data/table7.cxx
@@ -80,4 +80,16 @@ void ScTable::CopyCellValuesFrom( SCCOL nCol, SCROW nRow, const sc::CellValues&
     aCol[nCol].CopyCellValuesFrom(nRow, rSrc);
 }
 
+void ScTable::PreprocessRangeNameUpdate()
+{
+    for (SCCOL i = 0; i <= MAXCOL; ++i)
+        aCol[i].PreprocessRangeNameUpdate();
+}
+
+void ScTable::PostprocessRangeNameUpdate()
+{
+    for (SCCOL i = 0; i <= MAXCOL; ++i)
+        aCol[i].PostprocessRangeNameUpdate();
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index e0a580c..289563a 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -43,6 +43,12 @@ extern "C" void getOpenCLDeviceInfo(size_t*, size_t*);
 
 namespace sc {
 
+FormulaGroupEntry::FormulaGroupEntry( ScFormulaCell** pCells, size_t nRow, size_t nLength ) :
+    mpCells(pCells), mnRow(nRow), mnLength(nLength), mbShared(true) {}
+
+FormulaGroupEntry::FormulaGroupEntry( ScFormulaCell* pCell, size_t nRow ) :
+    mpCell(pCell), mnRow(nRow), mnLength(0), mbShared(false) {}
+
 size_t FormulaGroupContext::ColKey::Hash::operator ()( const FormulaGroupContext::ColKey& rKey ) const
 {
     return rKey.mnTab * MAXCOLCOUNT + rKey.mnCol;
diff --git a/sc/source/filter/oox/workbookhelper.cxx b/sc/source/filter/oox/workbookhelper.cxx
index 9bb9f3c..57e6b08 100644
--- a/sc/source/filter/oox/workbookhelper.cxx
+++ b/sc/source/filter/oox/workbookhelper.cxx
@@ -593,8 +593,6 @@ void WorkbookGlobals::initialize( bool bWorkbookFile )
         mpDoc->EnableAdjustHeight(true);
         // disable automatic update of linked sheets and DDE links
         mpDoc->EnableExecuteLink(false);
-        // #i79890# disable automatic update of defined names
-        mpDoc->CompileNameFormula(true);
 
         mxProgressBar.reset( new SegmentProgressBar( mrBaseFilter.getStatusIndicator(), ScGlobal::GetRscString(STR_LOAD_DOC) ) );
         mxFmlaParser.reset( new FormulaParser( *this ) );
@@ -629,8 +627,6 @@ void WorkbookGlobals::finalize()
     {
         // #i74668# do not insert default sheets
         mpDocShell->SetEmpty(false);
-        // #i79890# Compile named ranges before re-enabling row height adjustment. (no idea why).
-        mpDoc->CompileNameFormula(false);
         // enable automatic update of linked sheets and DDE links
         mpDoc->EnableExecuteLink(true);
         // #i79826# enable updating automatic row height after loading the document
diff --git a/sc/source/ui/docshell/docfunc.cxx b/sc/source/ui/docshell/docfunc.cxx
index 74c3467..5950a9d 100644
--- a/sc/source/ui/docshell/docfunc.cxx
+++ b/sc/source/ui/docshell/docfunc.cxx
@@ -4846,13 +4846,13 @@ bool ScDocFunc::SetNewRangeNames( ScRangeName* pNewRanges, bool bModifyDoc, SCTA
     bool bCompile = ( !pDoc->IsImportingXML() && pDoc->GetNamedRangesLockCount() == 0 );
 
     if ( bCompile )
-        pDoc->CompileNameFormula( true );   // CreateFormulaString
+        pDoc->PreprocessRangeNameUpdate();
     if (nTab >= 0)
         pDoc->SetRangeName( nTab, pNewRanges ); // takes ownership
     else
         pDoc->SetRangeName( pNewRanges );       // takes ownership
     if ( bCompile )
-        pDoc->CompileNameFormula( false );  // CompileFormulaString
+        pDoc->PostprocessRangeNameUpdate();
 
     if (bModifyDoc)
     {
@@ -4876,12 +4876,9 @@ void ScDocFunc::ModifyAllRangeNames( const boost::ptr_map<OUString, ScRangeName>
                 new ScUndoAllRangeNames(&rDocShell, aOldRangeMap, rRangeMap));
     }
 
-    pDoc->CompileNameFormula(true);
-
-    // set all range names
+    pDoc->PreprocessRangeNameUpdate();
     pDoc->SetAllRangeNames(rRangeMap);
-
-    pDoc->CompileNameFormula(false);
+    pDoc->PostprocessRangeNameUpdate();
 
     aModificator.SetDocumentModified();
     SFX_APP()->Broadcast(SfxSimpleHint(SC_HINT_AREAS_CHANGED));
diff --git a/sc/source/ui/undo/undocell.cxx b/sc/source/ui/undo/undocell.cxx
index 60f6594..f0e6803 100644
--- a/sc/source/ui/undo/undocell.cxx
+++ b/sc/source/ui/undo/undocell.cxx
@@ -992,7 +992,7 @@ OUString ScUndoRangeNames::GetComment() const
 void ScUndoRangeNames::DoChange( bool bUndo )
 {
     ScDocument* pDoc = pDocShell->GetDocument();
-    pDoc->CompileNameFormula( true );   // CreateFormulaString
+    pDoc->PreprocessRangeNameUpdate();
 
     if ( bUndo )
     {
@@ -1009,7 +1009,7 @@ void ScUndoRangeNames::DoChange( bool bUndo )
             pDoc->SetRangeName( new ScRangeName( *pNewRanges ) );
     }
 
-    pDoc->CompileNameFormula( false );  // CompileFormulaString
+    pDoc->PostprocessRangeNameUpdate();
 
     SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_AREAS_CHANGED ) );
 }
diff --git a/sc/source/ui/undo/undorangename.cxx b/sc/source/ui/undo/undorangename.cxx
index baf39b2..172f802 100644
--- a/sc/source/ui/undo/undorangename.cxx
+++ b/sc/source/ui/undo/undorangename.cxx
@@ -77,11 +77,9 @@ void ScUndoAllRangeNames::DoChange(const boost::ptr_map<OUString, ScRangeName>&
 {
     ScDocument& rDoc = *pDocShell->GetDocument();
 
-    rDoc.CompileNameFormula(true);
-
+    rDoc.PreprocessRangeNameUpdate();
     rDoc.SetAllRangeNames(rNames);
-
-    rDoc.CompileNameFormula(true);
+    rDoc.PostprocessRangeNameUpdate();
 
     SFX_APP()->Broadcast(SfxSimpleHint(SC_HINT_AREAS_CHANGED));
 }
diff --git a/sc/source/ui/unoobj/nameuno.cxx b/sc/source/ui/unoobj/nameuno.cxx
index 14f8a56..9386c11 100644
--- a/sc/source/ui/unoobj/nameuno.cxx
+++ b/sc/source/ui/unoobj/nameuno.cxx
@@ -743,13 +743,13 @@ sal_Bool SAL_CALL ScNamedRangesObj::hasByName( const OUString& aName )
 /** called from the XActionLockable interface methods on initial locking */
 void ScNamedRangesObj::lock()
 {
-    pDocShell->GetDocument()->CompileNameFormula( true ); // CreateFormulaString
+    pDocShell->GetDocument()->PreprocessRangeNameUpdate();
 }
 
 /** called from the XActionLockable interface methods on final unlock */
 void ScNamedRangesObj::unlock()
 {
-    pDocShell->GetDocument()->CompileNameFormula( false ); // CompileFormulaString
+    pDocShell->GetDocument()->PostprocessRangeNameUpdate();
 }
 
 // document::XActionLockable
diff --git a/sc/source/ui/view/viewfunc.cxx b/sc/source/ui/view/viewfunc.cxx
index 3eddb54..41a2109 100644
--- a/sc/source/ui/view/viewfunc.cxx
+++ b/sc/source/ui/view/viewfunc.cxx
@@ -2755,7 +2755,7 @@ bool ScViewFunc::InsertName( const OUString& rName, const OUString& rSymbol,
     {
         ScDocShellModificator aModificator( *pDocSh );
 
-        pDoc->CompileNameFormula( true );   // CreateFormulaString
+        pDoc->PreprocessRangeNameUpdate();
 
         // input available yet? Then remove beforehand (=change)
         ScRangeData* pData = pList->findByUpperName(ScGlobal::pCharClass->uppercase(rName));
@@ -2769,7 +2769,8 @@ bool ScViewFunc::InsertName( const OUString& rName, const OUString& rSymbol,
             bOk = true;
         pNewEntry = NULL;   // never delete, insert took ownership
 
-        pDoc->CompileNameFormula( false );  // CompileFormulaString
+        pDoc->PostprocessRangeNameUpdate();
+
         aModificator.SetDocumentModified();
         SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_AREAS_CHANGED ) );
     }
commit 137c288978fb8f4aee259fabfdcb9252b1b011d3
Author: Kohei Yoshida <kohei.yoshida at collabora.com>
Date:   Thu Apr 3 09:54:16 2014 -0400

    fdo#75741: Write test for this.
    
    Change-Id: Ibd3a2efe0a195b7c402572b0efb5c03183df9cf8

diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index 68d1b2e..6ee5a4e 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -1773,8 +1773,10 @@ void Test::testNamedRange()
 
     m_pDoc->SetValue (0, 0, 0, 101);
 
-    bool bSuccess = insertRangeNames(m_pDoc, aNames, aNames + SAL_N_ELEMENTS(aNames));
+    ScRangeName* pNames = new ScRangeName;
+    bool bSuccess = insertRangeNames(m_pDoc, pNames, aNames, aNames + SAL_N_ELEMENTS(aNames));
     CPPUNIT_ASSERT_MESSAGE("Failed to insert range names.", bSuccess);
+    m_pDoc->SetRangeName(pNames);
 
     ScRangeName* pNewRanges = m_pDoc->GetRangeName();
     CPPUNIT_ASSERT(pNewRanges);
@@ -1822,8 +1824,10 @@ void Test::testInsertNameList()
         { "MyRange3", "$Test.$C$1:$C$100", 3 }
     };
 
-    bool bSuccess = insertRangeNames(m_pDoc, aNames, aNames + SAL_N_ELEMENTS(aNames));
+    ScRangeName* pNames = new ScRangeName;
+    bool bSuccess = insertRangeNames(m_pDoc, pNames, aNames, aNames + SAL_N_ELEMENTS(aNames));
     CPPUNIT_ASSERT_MESSAGE("Failed to insert range names.", bSuccess);
+    m_pDoc->SetRangeName(pNames);
 
     ScDocFunc& rDocFunc = getDocShell().GetDocFunc();
     ScAddress aPos(1,1,0);
@@ -5696,10 +5700,10 @@ ScDocShell* Test::findLoadedDocShellByName(const OUString& rName)
     return NULL;
 }
 
-bool Test::insertRangeNames(ScDocument* pDoc, const RangeNameDef* p, const RangeNameDef* pEnd)
+bool Test::insertRangeNames(
+    ScDocument* pDoc, ScRangeName* pNames, const RangeNameDef* p, const RangeNameDef* pEnd)
 {
     ScAddress aA1(0, 0, 0);
-    ScRangeName* pNewRanges = new ScRangeName();
     for (; p != pEnd; ++p)
     {
         ScRangeData* pNew = new ScRangeData(
@@ -5708,7 +5712,7 @@ bool Test::insertRangeNames(ScDocument* pDoc, const RangeNameDef* p, const Range
             OUString::createFromAscii(p->mpExpr),
             aA1, 0, formula::FormulaGrammar::GRAM_ENGLISH);
         pNew->SetIndex(p->mnIndex);
-        bool bSuccess = pNewRanges->insert(pNew);
+        bool bSuccess = pNames->insert(pNew);
         if (!bSuccess)
         {
             cerr << "Insertion failed." << endl;
@@ -5716,7 +5720,6 @@ bool Test::insertRangeNames(ScDocument* pDoc, const RangeNameDef* p, const Range
         }
     }
 
-    pDoc->SetRangeName(pNewRanges);
     return true;
 }
 
diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index f97d0e9..faf01de 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -39,7 +39,7 @@ public:
     };
 
     static ScDocShell* findLoadedDocShellByName(const OUString& rName);
-    static bool insertRangeNames(ScDocument* pDoc, const RangeNameDef* p, const RangeNameDef* pEnd);
+    static bool insertRangeNames(ScDocument* pDoc, ScRangeName* pNames, const RangeNameDef* p, const RangeNameDef* pEnd);
     static void printRange(ScDocument* pDoc, const ScRange& rRange, const char* pCaption);
     static void clearRange(ScDocument* pDoc, const ScRange& rRange);
     static void clearSheet(ScDocument* pDoc, SCTAB nTab);
@@ -277,6 +277,7 @@ public:
     void testSharedFormulasCopyPaste();
     void testSharedFormulaInsertColumn();
     void testSharedFormulaMoveBlock();
+    void testSharedFormulaUpdateOnNamedRangeChange();
     void testFormulaPosition();
 
     void testMixData();
@@ -457,7 +458,7 @@ public:
     CPPUNIT_TEST(testSharedFormulasRefUpdateDeleteSheets);
     CPPUNIT_TEST(testSharedFormulasCopyPaste);
     CPPUNIT_TEST(testSharedFormulaInsertColumn);
-    CPPUNIT_TEST(testSharedFormulaMoveBlock);
+    CPPUNIT_TEST(testSharedFormulaUpdateOnNamedRangeChange);
     CPPUNIT_TEST(testFormulaPosition);
     CPPUNIT_TEST(testMixData);
     CPPUNIT_TEST(testJumpToPrecedentsDependents);
diff --git a/sc/qa/unit/ucalc_sharedformula.cxx b/sc/qa/unit/ucalc_sharedformula.cxx
index b95a673..acb249a 100644
--- a/sc/qa/unit/ucalc_sharedformula.cxx
+++ b/sc/qa/unit/ucalc_sharedformula.cxx
@@ -18,6 +18,8 @@
 #include <docfunc.hxx>
 #include <tokenarray.hxx>
 #include <tokenstringcontext.hxx>
+#include <globalnames.hxx>
+
 #include "svl/sharedstring.hxx"
 
 #include "formula/grammar.hxx"
@@ -1189,4 +1191,85 @@ void Test::testSharedFormulaMoveBlock()
     m_pDoc->DeleteTab(0);
 }
 
+void Test::testSharedFormulaUpdateOnNamedRangeChange()
+{
+    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn on auto calc.
+
+    m_pDoc->InsertTab(0, "Test");
+
+    const char* pName = "MyRange";
+    const char* pExpr1 = "$Test.$A$1:$A$3";
+    const char* pExpr2 = "$Test.$A$1:$A$4";
+
+    RangeNameDef aName;
+    aName.mpName = pName;
+    aName.mpExpr = pExpr1;
+    aName.mnIndex = 1;
+    ScRangeName* pNames = new ScRangeName;
+    bool bSuccess = insertRangeNames(m_pDoc, pNames, &aName, &aName + 1);
+    CPPUNIT_ASSERT(bSuccess);
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pNames->size());
+    m_pDoc->SetRangeName(pNames);
+
+    // Set values to A1:A4.
+    m_pDoc->SetValue(ScAddress(0,0,0), 1.0);
+    m_pDoc->SetValue(ScAddress(0,1,0), 2.0);
+    m_pDoc->SetValue(ScAddress(0,2,0), 3.0);
+    m_pDoc->SetValue(ScAddress(0,3,0), 4.0);
+
+    // Set formula to B1:B3.
+    m_pDoc->SetString(ScAddress(1,0,0), "=SUM(MyRange)");
+    m_pDoc->SetString(ScAddress(1,1,0), "=SUM(MyRange)");
+    m_pDoc->SetString(ScAddress(1,2,0), "=SUM(MyRange)");
+
+    // B1:B3 should be grouped.
+    ScFormulaCell* pFC = m_pDoc->GetFormulaCell(ScAddress(1,0,0));
+    CPPUNIT_ASSERT(pFC);
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(0), pFC->GetSharedTopRow());
+    CPPUNIT_ASSERT_EQUAL(static_cast<SCROW>(3), pFC->GetSharedLength());
+
+    CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(1,0,0)));
+    CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(1,1,0)));
+    CPPUNIT_ASSERT_EQUAL(6.0, m_pDoc->GetValue(ScAddress(1,2,0)));
+
+    // Set a single formula to C1.
+    m_pDoc->SetString(ScAddress(2,0,0), "=AVERAGE(MyRange)");
+    pFC = m_pDoc->GetFormulaCell(ScAddress(2,0,0));
+    CPPUNIT_ASSERT(pFC);
+    CPPUNIT_ASSERT_MESSAGE("C1 should not be shared.", !pFC->IsShared());
+    CPPUNIT_ASSERT_EQUAL(2.0, m_pDoc->GetValue(ScAddress(2,0,0)));
+
+    // Update the range of MyRange.
+    pNames = new ScRangeName;
+    aName.mpExpr = pExpr2;
+    bSuccess = insertRangeNames(m_pDoc, pNames, &aName, &aName + 1);
+    CPPUNIT_ASSERT(bSuccess);
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pNames->size());
+    ScDocFunc& rFunc = getDocShell().GetDocFunc();
+
+    typedef boost::ptr_map<OUString, ScRangeName> NameMapType;
+    NameMapType aNewNames;
+    OUString aScope(STR_GLOBAL_RANGE_NAME);
+    aNewNames.insert(aScope, pNames);
+    rFunc.ModifyAllRangeNames(aNewNames);
+
+    // Check to make sure all displayed formulas are still good.
+    if (!checkFormula(*m_pDoc, ScAddress(1,0,0), "SUM(MyRange)"))
+        CPPUNIT_FAIL("Wrong formula!");
+    if (!checkFormula(*m_pDoc, ScAddress(1,1,0), "SUM(MyRange)"))
+        CPPUNIT_FAIL("Wrong formula!");
+    if (!checkFormula(*m_pDoc, ScAddress(1,2,0), "SUM(MyRange)"))
+        CPPUNIT_FAIL("Wrong formula!");
+    if (!checkFormula(*m_pDoc, ScAddress(2,0,0), "AVERAGE(MyRange)"))
+        CPPUNIT_FAIL("Wrong formula!");
+
+    // Check the calculation results as well.
+    CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(1,0,0)));
+    CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(1,1,0)));
+    CPPUNIT_ASSERT_EQUAL(10.0, m_pDoc->GetValue(ScAddress(1,2,0)));
+    CPPUNIT_ASSERT_EQUAL(2.5, m_pDoc->GetValue(ScAddress(2,0,0)));
+
+    m_pDoc->DeleteTab(0);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list