[ooo-build-commit] .: Branch 'ooo-build-3-2-1' - patches/dev300

Kohei Yoshida kohei at kemper.freedesktop.org
Fri Aug 13 17:37:59 PDT 2010


 patches/dev300/apply                               |    3 
 patches/dev300/calc-extref-interpreter-rework.diff | 1948 +++++++++++++++++++++
 2 files changed, 1951 insertions(+)

New commits:
commit 09a38db1292eb94d1ae4f26f2ea85e91b7d682bd
Author: Kohei Yoshida <kyoshida at novell.com>
Date:   Fri Aug 13 20:33:06 2010 -0400

    Rework Calc's formula interpreter wrt external ref handling.
    
    Changed how external ref tokens are handled in the formula interpreter,
    in order to support them in OFFSET.  Also fixed INDIRECT to support
    special case reference syntax that Excel uses to point to external
    locations.
    
    Also, with this change the external ref manager can pull cell values
    directly from documents loaded in memory, instead of always pulling
    data from disk. (n#628876)
    
    NOTE: This patch is disabled in the default build.  To enable it, you
    need to enable the CalcExperimental section.
    
    * patches/dev300/apply:
    * patches/dev300/calc-extref-interpreter-rework.diff:

diff --git a/patches/dev300/apply b/patches/dev300/apply
index 8d8f5e0..4283ba1 100644
--- a/patches/dev300/apply
+++ b/patches/dev300/apply
@@ -4098,6 +4098,9 @@ dde-reconnect-on-load-sfx2.diff, n#618846, n#618864, kohei
 # Properly display data field names in the data field options dialog.
 calc-dp-sort-fix.diff, n#629920, kohei
 
+# Rework external ref token handling in interpreter, to fix OFFSET and INDIRECT.
+calc-extref-interpreter-rework.diff, n#628876, kohei
+
 [ Netbook ]
 netbook-window-decoration-update.diff, n#621116, rodo
 
diff --git a/patches/dev300/calc-extref-interpreter-rework.diff b/patches/dev300/calc-extref-interpreter-rework.diff
new file mode 100644
index 0000000..f5c248c
--- /dev/null
+++ b/patches/dev300/calc-extref-interpreter-rework.diff
@@ -0,0 +1,1948 @@
+diff --git formula/inc/formula/token.hxx formula/inc/formula/token.hxx
+index 6d440d1..d1e7f3b 100644
+--- formula/inc/formula/token.hxx
++++ formula/inc/formula/token.hxx
+@@ -113,6 +113,7 @@ public:
+     inline  StackVar      		GetType() const         { return eType; }
+             BOOL                IsFunction() const; // pure functions, no operators
+             BOOL                IsMatrixFunction() const;   // if a function _always_ returns a Matrix
++            bool                IsExternalRef() const;
+             BYTE                GetParamCount() const;
+     inline  void                IncRef() const          { nRefCnt++; }
+     inline  void                DecRef() const
+diff --git formula/inc/formula/tokenarray.hxx formula/inc/formula/tokenarray.hxx
+index a8a2b18..1b9e10a 100644
+--- formula/inc/formula/tokenarray.hxx
++++ formula/inc/formula/tokenarray.hxx
+@@ -126,6 +126,7 @@ public:
+     FormulaToken* LastRPN() { nIndex = nRPN; return PrevRPN(); }
+     FormulaToken* PrevRPN();
+ 
++    bool    HasExternalRef() const;
+     BOOL    HasOpCode( OpCode ) const;
+     BOOL    HasOpCodeRPN( OpCode ) const;
+     /// Token of type svIndex or opcode ocColRowName
+diff --git formula/source/core/api/FormulaCompiler.cxx formula/source/core/api/FormulaCompiler.cxx
+index 2737349..fd4237d 100644
+--- formula/source/core/api/FormulaCompiler.cxx
++++ formula/source/core/api/FormulaCompiler.cxx
+@@ -905,7 +905,7 @@ BOOL FormulaCompiler::GetToken()
+     }
+     if( pToken->GetOpCode() == ocSubTotal )
+         glSubTotal = TRUE;
+-    else if ( pToken->GetOpCode() == ocExternalRef )
++    else if ( pToken->IsExternalRef() )
+     {
+         return HandleExternalReference(*pToken);
+     }
+@@ -1187,7 +1187,7 @@ void FormulaCompiler::Factor()
+                 bCorrected = TRUE;
+             }
+         }
+-        else if ( eOp == ocExternalRef )
++        else if ( pToken->IsExternalRef() )
+         {
+             PutCode(pToken);
+             eOp = NextToken();
+@@ -1607,7 +1607,7 @@ FormulaToken* FormulaCompiler::CreateStringFromToken( rtl::OUStringBuffer& rBuff
+     }
+     if( bNext ) 
+     {
+-        if (eOp == ocExternalRef)
++        if (t->IsExternalRef())
+         {
+             CreateStringFromExternal(rBuffer, pTokenP);
+         }
+diff --git formula/source/core/api/token.cxx formula/source/core/api/token.cxx
+index 4f57d69..1899418 100644
+--- formula/source/core/api/token.cxx
++++ formula/source/core/api/token.cxx
+@@ -145,6 +145,18 @@ BOOL FormulaToken::IsMatrixFunction() const
+     return formula::FormulaCompiler::IsMatrixFunction(GetOpCode());
+ }
+ 
++bool FormulaToken::IsExternalRef() const
++{
++    switch (eType)
++    {
++        case svExternalSingleRef:
++        case svExternalDoubleRef:
++        case svExternalName:
++            return true;
++    }
++    return false;
++}
++
+ BOOL FormulaToken::operator==( const FormulaToken& rToken ) const
+ {
+     // don't compare reference count!
+@@ -550,6 +562,16 @@ FormulaToken* FormulaTokenArray::PeekPrevNoSpaces()
+         return NULL;
+ }
+ 
++bool FormulaTokenArray::HasExternalRef() const
++{
++    for ( USHORT j=0; j < nLen; j++ )
++    {
++        if (pCode[j]->IsExternalRef())
++            return true;
++    }
++    return false;
++}
++
+ BOOL FormulaTokenArray::HasOpCode( OpCode eOp ) const
+ {
+     for ( USHORT j=0; j < nLen; j++ )
+diff --git sc/inc/document.hxx sc/inc/document.hxx
+index 874ded2..ad854de 100644
+--- sc/inc/document.hxx
++++ sc/inc/document.hxx
+@@ -486,7 +486,7 @@ public:
+     ScFieldEditEngine*	CreateFieldEditEngine();
+     void				DisposeFieldEditEngine(ScFieldEditEngine*& rpEditEngine);
+ 
+-    SC_DLLPUBLIC ScRangeName*	GetRangeName();
++    SC_DLLPUBLIC ScRangeName*	GetRangeName() const;
+     void			SetRangeName( ScRangeName* pNewRangeName );
+     SCTAB			GetMaxTableNumber() { return nMaxTableNumber; }
+     void			SetMaxTableNumber(SCTAB nNumber) { nMaxTableNumber = nNumber; }
+@@ -766,7 +766,7 @@ public:
+     SC_DLLPUBLIC void			GetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, double& rValue );
+     SC_DLLPUBLIC double			RoundValueAsShown( double fVal, ULONG nFormat );
+     SC_DLLPUBLIC void			GetNumberFormat( SCCOL nCol, SCROW nRow, SCTAB nTab,
+-                                     sal_uInt32& rFormat );
++                                     sal_uInt32& rFormat ) const;
+     sal_uInt32      GetNumberFormat( const ScRange& rRange ) const;
+     SC_DLLPUBLIC sal_uInt32		GetNumberFormat( const ScAddress& ) const;
+                     /** If no number format attribute is set and the cell
+diff --git sc/inc/externalrefmgr.hxx sc/inc/externalrefmgr.hxx
+index 52a832f..799401b 100644
+--- sc/inc/externalrefmgr.hxx
++++ sc/inc/externalrefmgr.hxx
+@@ -658,7 +658,47 @@ private:
+ 
+     void insertRefCell(sal_uInt16 nFileId, const ScAddress& rCell);
+ 
+-    ScDocument* getSrcDocument(sal_uInt16 nFileId);
++    void fillCellFormat(sal_uInt32 nFmtIndex, ScExternalRefCache::CellFormat* pFmt) const;
++
++    ScExternalRefCache::TokenRef getSingleRefTokenFromSrcDoc(
++        sal_uInt16 nFileId, const ScDocument* pSrcDoc, const ScAddress& rCell, 
++        ScExternalRefCache::CellFormat* pFmt);
++
++    /**
++     * Retrieve a range token array from a source document instance. 
++     * 
++     * @param pSrcDoc pointer to the source document instance.
++     * @param rTabName name of the first table.
++     * @param rRange range specified.  Upon successful retrieval, this range 
++     *               gets modified to contain the correct table IDs, and in
++     *               case the range is larger than the data area of the source
++     *               document, it gets reduced to the data area.
++     * @param rCacheData an array of structs, with each struct containing the 
++     *                   table name and the data in the specified range.
++     * 
++     * @return range token array
++     */
++    ScExternalRefCache::TokenArrayRef getDoubleRefTokensFromSrcDoc(
++        const ScDocument* pSrcDoc, const String& rTabName, ScRange& rRange,
++        ::std::vector<ScExternalRefCache::SingleRangeData>& rCacheData);
++
++    /**
++     * Retrieve range name token array from a source document instance.
++     * 
++     * @param nFileId file ID of the source document.
++     * @param pSrcDoc pointer to the source document instance
++     * @param rName range name to retrieve.  Note that the range name lookup 
++     *              is case <i>in</i>-sensitive, and upon successful retrieval
++     *              of the range name array, this name gets updated to the
++     *              actual range name with the correct casing.
++     * 
++     * @return range name token array
++     */
++    ScExternalRefCache::TokenArrayRef getRangeNameTokensFromSrcDoc(
++        sal_uInt16 nFileId, const ScDocument* pSrcDoc, String& rName);
++    
++    const ScDocument* getInMemorySrcDocument(sal_uInt16 nFileId);
++    const ScDocument* getSrcDocument(sal_uInt16 nFileId);
+     SfxObjectShellRef loadSrcDocument(sal_uInt16 nFileId, String& rFilter);
+     bool isFileLoadable(const String& rFile) const;
+ 
+@@ -685,7 +725,7 @@ private:
+      */
+     void purgeStaleSrcDocument(sal_Int32 nTimeOut);
+ 
+-    sal_uInt32 getMappedNumberFormat(sal_uInt16 nFileId, sal_uInt32 nNumFmt, ScDocument* pSrcDoc);
++    sal_uInt32 getMappedNumberFormat(sal_uInt16 nFileId, sal_uInt32 nNumFmt, const ScDocument* pSrcDoc);
+ 
+ private:
+     /** cache of referenced ranges and names from source documents. */
+diff --git sc/source/core/data/cell.cxx sc/source/core/data/cell.cxx
+index 1164a54..9c33711 100644
+--- sc/source/core/data/cell.cxx
++++ sc/source/core/data/cell.cxx
+@@ -777,7 +777,7 @@ ScFormulaCell::ScFormulaCell( const ScFormulaCell& rCell, ScDocument& rDoc, cons
+         ScToken* t;
+         while ( ( t = static_cast<ScToken*>(pCode->GetNextReferenceOrName()) ) != NULL && !bCompile )
+         {
+-            if ( t->GetOpCode() == ocExternalRef )
++            if ( t->IsExternalRef() )
+             {
+                 // External name, cell, and area references.
+                 bCompile = true;
+diff --git sc/source/core/data/documen3.cxx sc/source/core/data/documen3.cxx
+index e5fba37..c322ac1 100644
+--- sc/source/core/data/documen3.cxx
++++ sc/source/core/data/documen3.cxx
+@@ -87,7 +87,7 @@ using ::std::auto_ptr;
+ 
+ //------------------------------------------------------------------------
+ 
+-ScRangeName* ScDocument::GetRangeName()
++ScRangeName* ScDocument::GetRangeName() const
+ {
+     return pRangeName;
+ }
+diff --git sc/source/core/data/documen4.cxx sc/source/core/data/documen4.cxx
+index 733f620..2cac415 100644
+--- sc/source/core/data/documen4.cxx
++++ sc/source/core/data/documen4.cxx
+@@ -305,7 +305,7 @@ bool ScDocument::MarkUsedExternalReferences( ScTokenArray & rArr )
+         ScToken* t;
+         while (!bAllMarked && (t = static_cast<ScToken*>(rArr.GetNextReferenceOrName())) != NULL)
+         {
+-            if (t->GetOpCode() == ocExternalRef)
++            if (t->IsExternalRef())
+             {
+                 if (!pRefMgr)
+                     pRefMgr = GetExternalRefManager();
+diff --git sc/source/core/data/document.cxx sc/source/core/data/document.cxx
+index 75c5266..65831a3 100644
+--- sc/source/core/data/document.cxx
++++ sc/source/core/data/document.cxx
+@@ -2715,7 +2715,7 @@ double ScDocument::GetValue( const ScAddress& rPos )
+ 
+ 
+ void ScDocument::GetNumberFormat( SCCOL nCol, SCROW nRow, SCTAB nTab,
+-                                  sal_uInt32& rFormat )
++                                  sal_uInt32& rFormat ) const
+ {
+     if (VALIDTAB(nTab))
+         if (pTab[nTab])
+diff --git sc/source/core/inc/interpre.hxx sc/source/core/inc/interpre.hxx
+index 6660bd8..f6e5499 100644
+--- sc/source/core/inc/interpre.hxx
++++ sc/source/core/inc/interpre.hxx
+@@ -37,6 +37,7 @@
+ #include "scdll.hxx"
+ #include "document.hxx"
+ #include "scmatrix.hxx"
++#include "externalrefmgr.hxx"
+ 
+ #if SC_SPEW_ENABLED
+ #include "scspew.hxx"
+@@ -313,10 +314,15 @@ void DoubleRefToVars( const ScToken* p,
+         SCCOL& rCol1, SCROW &rRow1, SCTAB& rTab1,
+         SCCOL& rCol2, SCROW &rRow2, SCTAB& rTab2,
+         BOOL bDontCheckForTableOp = FALSE );
+-ScDBRangeBase* PopDoubleRef();
++ScDBRangeBase* PopDBDoubleRef();
+ void PopDoubleRef(SCCOL& rCol1, SCROW &rRow1, SCTAB& rTab1,
+                           SCCOL& rCol2, SCROW &rRow2, SCTAB& rTab2,
+                           BOOL bDontCheckForTableOp = FALSE );
++void PopExternalSingleRef(sal_uInt16& rFileId, String& rTabName, ScSingleRefData& rRef);
++void PopExternalSingleRef(ScExternalRefCache::TokenRef& rToken, ScExternalRefCache::CellFormat* pFmt = NULL);
++void PopExternalDoubleRef(sal_uInt16& rFileId, String& rTabName, ScComplexRefData& rRef);
++void PopExternalDoubleRef(ScExternalRefCache::TokenArrayRef& rArray);
++void PopExternalDoubleRef(ScMatrixRef& rMat);
+ BOOL PopDoubleRefOrSingleRef( ScAddress& rAdr );
+ void PopDoubleRefPushMatrix();
+ // If MatrixFormula: convert formula::svDoubleRef to svMatrix, create JumpMatrix.
+@@ -334,7 +340,12 @@ void PushStringBuffer( const sal_Unicode* pString );
+ void PushString( const String& rString );
+ void PushSingleRef(SCCOL nCol, SCROW nRow, SCTAB nTab);
+ void PushDoubleRef(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+-                                 SCCOL nCol2, SCROW nRow2, SCTAB nTab2);
++                   SCCOL nCol2, SCROW nRow2, SCTAB nTab2);
++void PushExternalSingleRef(sal_uInt16 nFileId, const String& rTabName, 
++                           SCCOL nCol, SCROW nRow, SCTAB nTab);
++void PushExternalDoubleRef(sal_uInt16 nFileId, const String& rTabName, 
++                           SCCOL nCol1, SCROW nRow1, SCTAB nTab1, 
++                           SCCOL nCol2, SCROW nRow2, SCTAB nTab2);
+ void PushMatrix(ScMatrix* pMat);
+ void PushError( USHORT nError );
+ /// Raw stack type without default replacements.
+@@ -346,11 +357,13 @@ formula::StackVar GetStackType( BYTE nParam );
+ BYTE GetByte() { return cPar; }
+ // generiert aus DoubleRef positionsabhaengige SingleRef
+ BOOL DoubleRefToPosSingleRef( const ScRange& rRange, ScAddress& rAdr );
++double GetDoubleFromMatrix(const ScMatrixRef& pMat);
+ double GetDouble();
+ double GetDoubleWithDefault(double nDefault);
+ BOOL IsMissing();
+ BOOL GetBool() { return GetDouble() != 0.0; }
+ const String& GetString();
++const String& GetStringFromMatrix(const ScMatrixRef& pMat);
+ // pop matrix and obtain one element, upper left or according to jump matrix
+ ScMatValType GetDoubleOrStringFromMatrix( double& rDouble, String& rString );
+ ScMatrixRef CreateMatrixFromDoubleRef( const formula::FormulaToken* pToken,
+@@ -546,7 +559,6 @@ BOOL SetSbxVariable( SbxVariable* pVar, SCCOL nCol, SCROW nRow, SCTAB nTab );
+ void ScErrorType();
+ void ScDBArea();
+ void ScColRowNameAuto();
+-void ScExternalRef();
+ void ScGetPivotData();
+ void ScHyperLink();
+ void ScBahtText();
+diff --git sc/source/core/tool/address.cxx sc/source/core/tool/address.cxx
+index 4fda929..228fa99 100644
+--- sc/source/core/tool/address.cxx
++++ sc/source/core/tool/address.cxx
+@@ -1015,7 +1015,18 @@ lcl_ScAddress_Parse_OOo( const sal_Unicode* p, ScDocument* pDoc, ScAddress& rAdd
+             nBits = 0;
+ 
+         if (!bExtDoc && (!pDoc || !pDoc->GetTable( aTab, nTab )))
+-            nBits = 0;
++        {
++            // Specified table name is not found in this document.  Assume this is an external document.
++            bExtDoc = true;
++            aDocName = aTab;
++            xub_StrLen n = aTab.SearchBackward('.');
++            if (n != STRING_NOTFOUND && n > 0)
++                // Extension found.  Strip it.
++                aTab.Erase(n);
++            else
++                // No extension found.  This is probably not an external document.
++                nBits = 0;
++        }
+     }
+     else
+     {
+diff --git sc/source/core/tool/interpr1.cxx sc/source/core/tool/interpr1.cxx
+index 03ea598..5ca790a 100644
+--- sc/source/core/tool/interpr1.cxx
++++ sc/source/core/tool/interpr1.cxx
+@@ -3098,6 +3098,59 @@ void ScInterpreter::ScMax( BOOL bTextAsZero )
+ #pragma optimize("",on)
+ #endif
+ 
++namespace {
++
++void IterateMatrix(
++    const ScMatrixRef& pMat, ScIterFunc eFunc, BOOL bTextAsZero, 
++    ULONG& rCount, short& rFuncFmtType, double& fVal, double& fRes, double& fMem, BOOL& bNull)
++{
++    if (!pMat)
++        return;
++
++    SCSIZE nC, nR;
++    rFuncFmtType = NUMBERFORMAT_NUMBER;
++    pMat->GetDimensions(nC, nR);
++    if( eFunc == ifCOUNT2 )
++        rCount += (ULONG) nC * nR;
++    else
++    {
++        for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
++        {
++            for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
++            {
++                if (!pMat->IsString(nMatCol,nMatRow))
++                {
++                    rCount++;
++                    fVal = pMat->GetDouble(nMatCol,nMatRow);
++                    switch( eFunc )
++                    {
++                        case ifAVERAGE:
++                        case ifSUM:
++                            if ( bNull && fVal != 0.0 )
++                            {
++                                bNull = FALSE;
++                                fMem = fVal;
++                            }
++                            else
++                                fRes += fVal;
++                            break;
++                        case ifSUMSQ:   fRes += fVal * fVal; break;
++                        case ifPRODUCT: fRes *= fVal; break;
++                        default: ; // nothing
++                    }
++                }
++                else if ( bTextAsZero )
++                {
++                    rCount++;
++                    if ( eFunc == ifPRODUCT )
++                        fRes = 0.0;
++                }
++            }
++        }
++    }
++}
++
++}
+ 
+ double ScInterpreter::IterateParameters( ScIterFunc eFunc, BOOL bTextAsZero )
+ {
+@@ -3179,6 +3232,71 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, BOOL bTextAsZero )
+                 }
+                 nFuncFmtType = NUMBERFORMAT_NUMBER;
+                 break;
++            case svExternalSingleRef:
++            {
++                ScExternalRefCache::TokenRef pToken;
++                ScExternalRefCache::CellFormat aFmt;
++                PopExternalSingleRef(pToken, &aFmt);
++                if (nGlobalError && (eFunc == ifCOUNT2 || eFunc == ifCOUNT))
++                {
++                    nGlobalError = 0;
++                    if ( eFunc == ifCOUNT2 )
++                        ++nCount;
++                    break;
++                }
++
++                if (!pToken)
++                    break;
++
++                StackVar eType = pToken->GetType();
++                if (eFunc == ifCOUNT2)
++                {
++                    if (eType != formula::svEmptyCell)
++                        nCount++;
++                    if (nGlobalError)
++                        nGlobalError = 0;
++                }
++                else if (eType == formula::svDouble)
++                {
++                    nCount++;
++                    fVal = pToken->GetDouble();
++                    if (aFmt.mbIsSet)
++                    {
++                        nFuncFmtType = aFmt.mnType;
++                        nFuncFmtIndex = aFmt.mnIndex;
++                    }
++                    switch( eFunc )
++                    {
++                        case ifAVERAGE:
++                        case ifSUM:
++                            if ( bNull && fVal != 0.0 )
++                            {
++                                bNull = FALSE;
++                                fMem = fVal;
++                            }
++                            else
++                                fRes += fVal;
++                            break;
++                        case ifSUMSQ:   fRes += fVal * fVal; break;
++                        case ifPRODUCT: fRes *= fVal; break;
++                        case ifCOUNT:
++                            if ( nGlobalError )
++                            {    
++                                nGlobalError = 0;
++                                nCount--;
++                            }
++                            break;
++                        default: ; // nothing
++                    }
++                }
++                else if (bTextAsZero && eType == formula::svString)
++                {
++                    nCount++;
++                    if ( eFunc == ifPRODUCT )
++                        fRes = 0.0;
++                }
++            }
++            break;
+             case svSingleRef :
+             {
+                 PopSingleRef( aAdr );
+@@ -3325,53 +3443,20 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, BOOL bTextAsZero )
+                 }
+             }
+             break;
++            case svExternalDoubleRef:
++            {
++                ScMatrixRef pMat;
++                PopExternalDoubleRef(pMat);
++                if (nGlobalError)
++                    break;
++
++                IterateMatrix(pMat, eFunc, bTextAsZero, nCount, nFuncFmtType, fVal, fMem, fRes, bNull);
++            }
++            break;
+             case svMatrix :
+             {
+                 ScMatrixRef pMat = PopMatrix();
+-                if (pMat)
+-                {
+-                    SCSIZE nC, nR;
+-                    nFuncFmtType = NUMBERFORMAT_NUMBER;
+-                    pMat->GetDimensions(nC, nR);
+-                    if( eFunc == ifCOUNT2 )
+-                        nCount += (ULONG) nC * nR;
+-                    else
+-                    {
+-                        for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
+-                        {
+-                            for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
+-                            {
+-                                if (!pMat->IsString(nMatCol,nMatRow))
+-                                {
+-                                    nCount++;
+-                                    fVal = pMat->GetDouble(nMatCol,nMatRow);
+-                                    switch( eFunc )
+-                                    {
+-                                        case ifAVERAGE:
+-                                        case ifSUM:
+-                                            if ( bNull && fVal != 0.0 )
+-                                            {
+-                                                bNull = FALSE;
+-                                                fMem = fVal;
+-                                            }
+-                                            else
+-                                                fRes += fVal;
+-                                            break;
+-                                        case ifSUMSQ:   fRes += fVal * fVal; break;
+-                                        case ifPRODUCT: fRes *= fVal; break;
+-                                        default: ; // nothing
+-                                    }
+-                                }
+-                                else if ( bTextAsZero )
+-                                {
+-                                    nCount++;
+-                                    if ( eFunc == ifPRODUCT )
+-                                        fRes = 0.0;
+-                                }
+-                            }
+-                        }
+-                    }
+-                }
++                IterateMatrix(pMat, eFunc, bTextAsZero, nCount, nFuncFmtType, fVal, fMem, fRes, bNull);
+             }
+             break;
+             case svError:
+@@ -4086,29 +4171,39 @@ void ScInterpreter::ScMatch()
+         SCCOL nCol2 = 0;
+         SCROW nRow2 = 0;
+         SCTAB nTab2 = 0;
+-        if (GetStackType() == svDoubleRef)
++
++        switch (GetStackType())
+         {
+-            PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+-            if (nTab1 != nTab2 || (nCol1 != nCol2 && nRow1 != nRow2))
++            case svDoubleRef:
+             {
+-                PushIllegalParameter();
+-                return;
++                PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
++                if (nTab1 != nTab2 || (nCol1 != nCol2 && nRow1 != nRow2))
++                {
++                    PushIllegalParameter();
++                    return;
++                }
+             }
+-        }
+-        else if (GetStackType() == svMatrix)
+-        {
+-            pMatSrc = PopMatrix();
+-            if (!pMatSrc)
++            break;
++            case svMatrix:
++            case svExternalDoubleRef:
+             {
++                if (GetStackType() == svMatrix)
++                    pMatSrc = PopMatrix();
++                else
++                    PopExternalDoubleRef(pMatSrc);
++
++                if (!pMatSrc)
++                {
++                    PushIllegalParameter();
++                    return;
++                }
++            }
++            break;
++            default:
+                 PushIllegalParameter();
+                 return;
+-            }
+-        }
+-        else
+-        {
+-            PushIllegalParameter();
+-            return;
+         }
++
+         if (nGlobalError == 0)
+         {
+             double fVal;
+@@ -4166,6 +4261,32 @@ void ScInterpreter::ScMatch()
+                     }
+                 }
+                 break;
++                case svExternalSingleRef:
++                {
++                    ScExternalRefCache::TokenRef pToken;
++                    PopExternalSingleRef(pToken);
++                    if (!pToken)
++                    {
++                        PushInt(0);
++                        return;
++                    }
++                    if (pToken->GetType() == svDouble)
++                    {
++                        rEntry.bQueryByString = false;
++                        rEntry.nVal = pToken->GetDouble();
++                    }
++                    else
++                    {
++                        rEntry.bQueryByString = true;
++                        *rEntry.pStr = pToken->GetString();
++                    }
++                }
++                break;
++                case svExternalDoubleRef:
++                    // TODO: Implement this.
++                    PushIllegalParameter();
++                    return;
++                break;
+                 case svMatrix :
+                 {
+                     ScMatValType nType = GetDoubleOrStringFromMatrix(
+@@ -5853,7 +5974,7 @@ ScDBQueryParamBase* ScInterpreter::GetDBParams( BOOL& rMissingField )
+     if ( GetByte() == 3 )
+     {
+         // First, get the query criteria range.
+-        ::std::auto_ptr<ScDBRangeBase> pQueryRef( PopDoubleRef() );
++        ::std::auto_ptr<ScDBRangeBase> pQueryRef( PopDBDoubleRef() );
+         if (!pQueryRef.get())
+             return NULL;
+ 
+@@ -5911,7 +6032,7 @@ ScDBQueryParamBase* ScInterpreter::GetDBParams( BOOL& rMissingField )
+                 SetError( errIllegalParameter );
+         }
+ 
+-        auto_ptr<ScDBRangeBase> pDBRef( PopDoubleRef() );
++        auto_ptr<ScDBRangeBase> pDBRef( PopDBDoubleRef() );
+ 
+         if (nGlobalError || !pDBRef.get())
+             return NULL;
+@@ -5978,6 +6099,7 @@ ScDBQueryParamBase* ScInterpreter::GetDBParams( BOOL& rMissingField )
+ 
+ void ScInterpreter::DBIterator( ScIterFunc eFunc )
+ {
++//  StackPrinter __stack_printer__("ScInterpreter::DBIterator");
+     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::DBIterator" );
+     double nErg = 0.0;
+     double fMem = 0.0;
+@@ -6316,15 +6438,10 @@ void ScInterpreter::ScIndirect()
+         {
+             if (aExtInfo.mbExternal)
+             {
+-                /* TODO: future versions should implement a proper subroutine 
+-                 * token. This procedure here is a minimally invasive fix for 
+-                 * #i101645# in OOo3.1.1 */
+-                // Push a subroutine on the instruction code stack that 
+-                // resolves the external reference as the next instruction.
+-                aCode.Push( lcl_CreateExternalRefTokenArray( aPos, pDok, 
+-                            aExtInfo, aRefAd, &aRefAd2));
+-                // Signal subroutine call to interpreter.
+-                PushTempToken( new FormulaUnknownToken( ocCall));
++                PushExternalDoubleRef(
++                    aExtInfo.mnFileId, aExtInfo.maTabName, 
++                    aRefAd.Col(), aRefAd.Row(), aRefAd.Tab(),
++                    aRefAd2.Col(), aRefAd2.Row(), aRefAd2.Tab());
+             }
+             else
+                 PushDoubleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab(),
+@@ -6336,15 +6453,8 @@ void ScInterpreter::ScIndirect()
+         {
+             if (aExtInfo.mbExternal)
+             {
+-                /* TODO: future versions should implement a proper subroutine 
+-                 * token. This procedure here is a minimally invasive fix for 
+-                 * #i101645# in OOo3.1.1 */
+-                // Push a subroutine on the instruction code stack that 
+-                // resolves the external reference as the next instruction.
+-                aCode.Push( lcl_CreateExternalRefTokenArray( aPos, pDok, 
+-                            aExtInfo, aRefAd, NULL));
+-                // Signal subroutine call to interpreter.
+-                PushTempToken( new FormulaUnknownToken( ocCall));
++                PushExternalSingleRef(
++                    aExtInfo.mnFileId, aExtInfo.maTabName, aRefAd.Col(), aRefAd.Row(), aRefAd.Tab());
+             }
+             else
+                 PushSingleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab() );
+@@ -6528,6 +6638,44 @@ void ScInterpreter::ScOffset()
+                     PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1);
+             }
+         }
++        else if (GetStackType() == svExternalSingleRef)
++        {
++            sal_uInt16 nFileId;
++            String aTabName;
++            ScSingleRefData aRef;
++            PopExternalSingleRef(nFileId, aTabName, aRef);
++            aRef.CalcAbsIfRel(aPos);
++            nCol1 = aRef.nCol;
++            nRow1 = aRef.nRow;
++            nTab1 = aRef.nTab;
++
++            if (nParamCount == 3 || (nColNew < 0 && nRowNew < 0))
++            {
++                nCol1 = (SCCOL)((long) nCol1 + nColPlus);
++                nRow1 = (SCROW)((long) nRow1 + nRowPlus);
++                if (!ValidCol(nCol1) || !ValidRow(nRow1))
++                    PushIllegalArgument();
++                else
++                    PushExternalSingleRef(nFileId, aTabName, nCol1, nRow1, nTab1);
++            }
++            else
++            {
++                if (nColNew < 0)
++                    nColNew = 1;
++                if (nRowNew < 0)
++                    nRowNew = 1;
++                nCol1 = (SCCOL)((long)nCol1+nColPlus);      // ! nCol1 wird veraendert!
++                nRow1 = (SCROW)((long)nRow1+nRowPlus);
++                nCol2 = (SCCOL)((long)nCol1+nColNew-1);
++                nRow2 = (SCROW)((long)nRow1+nRowNew-1);
++                PushIllegalArgument();
++                if (!ValidCol(nCol1) || !ValidRow(nRow1) ||
++                    !ValidCol(nCol2) || !ValidRow(nRow2))
++                    PushIllegalArgument();
++                else
++                    PushExternalDoubleRef(nFileId, aTabName, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
++            }
++        }
+         else if (GetStackType() == svDoubleRef)
+         {
+             PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+@@ -6545,6 +6693,33 @@ void ScInterpreter::ScOffset()
+             else
+                 PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1);
+         }
++        else if (GetStackType() == svExternalDoubleRef)
++        {
++            sal_uInt16 nFileId;
++            String aTabName;
++            ScComplexRefData aRef;
++            PopExternalDoubleRef(nFileId, aTabName, aRef);
++            aRef.CalcAbsIfRel(aPos);
++            nCol1 = aRef.Ref1.nCol;
++            nRow1 = aRef.Ref1.nRow;
++            nTab1 = aRef.Ref1.nTab;
++            nCol2 = aRef.Ref2.nCol;
++            nRow2 = aRef.Ref2.nRow;
++            nTab2 = aRef.Ref2.nTab;
++            if (nColNew < 0)
++                nColNew = nCol2 - nCol1 + 1;
++            if (nRowNew < 0)
++                nRowNew = nRow2 - nRow1 + 1;
++            nCol1 = (SCCOL)((long)nCol1+nColPlus);
++            nRow1 = (SCROW)((long)nRow1+nRowPlus);
++            nCol2 = (SCCOL)((long)nCol1+nColNew-1);
++            nRow2 = (SCROW)((long)nRow1+nRowNew-1);
++            if (!ValidCol(nCol1) || !ValidRow(nRow1) ||
++                !ValidCol(nCol2) || !ValidRow(nRow2) || nTab1 != nTab2)
++                PushIllegalArgument();
++            else
++                PushExternalDoubleRef(nFileId, aTabName, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
++        }
+         else
+             PushIllegalParameter();
+     }
+diff --git sc/source/core/tool/interpr4.cxx sc/source/core/tool/interpr4.cxx
+index 642b2d2..66275d7 100644
+--- sc/source/core/tool/interpr4.cxx
++++ sc/source/core/tool/interpr4.cxx
+@@ -1241,42 +1241,42 @@ void ScInterpreter::DoubleRefToVars( const ScToken* p,
+     }
+ }
+ 
+-ScDBRangeBase* ScInterpreter::PopDoubleRef()
++ScDBRangeBase* ScInterpreter::PopDBDoubleRef()
+ {
+-    if (!sp)
+-    {    
+-        SetError(errUnknownStackVariable);
+-        return NULL;
+-    }
+-
+-    --sp;
+-    FormulaToken* p = pStack[sp];
+-    switch (p->GetType())
++    StackVar eType = GetStackType();
++    switch (eType)
+     {
++        case svUnknown:
++            SetError(errUnknownStackVariable);
++        break;
+         case svError:
+-            nGlobalError = p->GetError();
++            PopError();
+         break;
+         case svDoubleRef:
+         {
+             SCCOL nCol1, nCol2;
+             SCROW nRow1, nRow2;
+             SCTAB nTab1, nTab2;
+-            DoubleRefToVars(static_cast<ScToken*>(p), 
+-                            nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, false);
+-            
++            PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, false);
++            if (nGlobalError)
++                break;
+             return new ScDBInternalRange(pDok,
+                 ScRange(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2));
+         }
+-        break;
+         case svMatrix:
++        case svExternalDoubleRef:
+         {
+-            ScMatrixRef pMat = static_cast<ScToken*>(p)->GetMatrix();
++            ScMatrixRef pMat;
++            if (eType == svMatrix)
++                pMat = PopMatrix();
++            else
++                PopExternalDoubleRef(pMat);
+             return new ScDBExternalRange(pDok, pMat);
+         }
+-        break;
+         default:
+             SetError( errIllegalParameter);
+     }
++
+     return NULL;
+ }
+ 
+@@ -1396,6 +1396,171 @@ void ScInterpreter::PopDoubleRef( ScRange& rRange, BOOL bDontCheckForTableOp )
+         SetError( errUnknownStackVariable);
+ }
+ 
++void ScInterpreter::PopExternalSingleRef(sal_uInt16& rFileId, String& rTabName, ScSingleRefData& rRef)
++{
++    if (!sp)
++    {
++        SetError(errUnknownStackVariable);
++        return;
++    }
++
++    --sp;
++    FormulaToken* p = pStack[sp];
++    StackVar eType = p->GetType();
++
++    if (eType == svError)
++    {
++        nGlobalError = p->GetError();
++        return;
++    }
++
++    if (eType != svExternalSingleRef)
++    {
++        SetError( errIllegalParameter);
++        return;
++    }
++
++    rFileId = p->GetIndex();
++    rTabName = p->GetString();
++    rRef = static_cast<ScToken*>(p)->GetSingleRef();
++}
++
++void ScInterpreter::PopExternalSingleRef(ScExternalRefCache::TokenRef& rToken, ScExternalRefCache::CellFormat* pFmt)
++{
++
++    sal_uInt16 nFileId;
++    String aTabName;
++    ScSingleRefData aData;
++    PopExternalSingleRef(nFileId, aTabName, aData);
++    if (nGlobalError)
++        return;
++
++    ScExternalRefManager* pRefMgr = pDok->GetExternalRefManager();
++    const String* pFile = pRefMgr->getExternalFileName(nFileId);
++    if (!pFile)
++    {
++        SetError(errNoName);
++        return;
++    }
++
++    if (aData.IsTabRel())
++    {
++        DBG_ERROR("ScCompiler::GetToken: external single reference must have an absolute table reference!");
++        SetError(errNoRef);
++        return;
++    }
++
++    aData.CalcAbsIfRel(aPos);
++    ScAddress aAddr(aData.nCol, aData.nRow, aData.nTab);
++    ScExternalRefCache::CellFormat aFmt;
++    ScExternalRefCache::TokenRef xNew = pRefMgr->getSingleRefToken(
++        nFileId, aTabName, aAddr, &aPos, NULL, &aFmt);
++
++    if (!xNew)
++    {
++        SetError(errNoRef);
++        return;
++    }
++
++    rToken = xNew;
++    if (pFmt)
++        *pFmt = aFmt;
++}
++
++void ScInterpreter::PopExternalDoubleRef(sal_uInt16& rFileId, String& rTabName, ScComplexRefData& rRef)
++{
++    if (!sp)
++    {
++        SetError(errUnknownStackVariable);
++        return;
++    }
++
++    --sp;
++    FormulaToken* p = pStack[sp];
++    StackVar eType = p->GetType();
++
++    if (eType == svError)
++    {
++        nGlobalError = p->GetError();
++        return;
++    }
++
++    if (eType != svExternalDoubleRef)
++    {
++        SetError( errIllegalParameter);
++        return;
++    }
++
++    rFileId = p->GetIndex();
++    rTabName = p->GetString();
++    rRef = static_cast<ScToken*>(p)->GetDoubleRef();
++}
++
++void ScInterpreter::PopExternalDoubleRef(ScExternalRefCache::TokenArrayRef& rArray)
++{
++    sal_uInt16 nFileId;
++    String aTabName;
++    ScComplexRefData aData;
++    PopExternalDoubleRef(nFileId, aTabName, aData);
++    if (nGlobalError)
++        return;
++
++    ScExternalRefManager* pRefMgr = pDok->GetExternalRefManager();
++    const String* pFile = pRefMgr->getExternalFileName(nFileId);
++    if (!pFile)
++    {
++        SetError(errNoName);
++        return;
++    }
++    if (aData.Ref1.IsTabRel() || aData.Ref2.IsTabRel())
++    {
++        DBG_ERROR("ScCompiler::GetToken: external double reference must have an absolute table reference!");
++        SetError(errNoRef);
++        return;
++    }
++
++    aData.CalcAbsIfRel(aPos);
++    ScRange aRange(aData.Ref1.nCol, aData.Ref1.nRow, aData.Ref1.nTab,
++                   aData.Ref2.nCol, aData.Ref2.nRow, aData.Ref2.nTab);
++    ScExternalRefCache::TokenArrayRef pArray = pRefMgr->getDoubleRefTokens(
++        nFileId, aTabName, aRange, &aPos);
++
++    if (!pArray)
++    {
++        SetError(errIllegalArgument);
++        return;
++    }
++
++    ScToken* pToken = static_cast<ScToken*>(pArray->First());
++    if (pToken->GetType() != svMatrix)
++    {
++        SetError(errIllegalArgument);
++        return;
++    }
++
++    if (pArray->Next())
++    {
++        // Can't handle more than one matrix per parameter.
++        SetError( errIllegalArgument);
++        return;
++    }
++
++    rArray = pArray;
++}
++
++void ScInterpreter::PopExternalDoubleRef(ScMatrixRef& rMat)
++{
++    ScExternalRefCache::TokenArrayRef pArray;
++    PopExternalDoubleRef(pArray);
++    if (nGlobalError)
++        return;
++
++    // For now, we only support single range data for external
++    // references, which means the array should only contain a
++    // single matrix token.
++    ScToken* p = static_cast<ScToken*>(pArray->First());
++    rMat = p->GetMatrix();
++}
+ 
+ BOOL ScInterpreter::PopDoubleRefOrSingleRef( ScAddress& rAdr )
+ {
+@@ -1678,6 +1843,40 @@ void ScInterpreter::PushDoubleRef(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ }
+ 
+ 
++void ScInterpreter::PushExternalSingleRef(
++    sal_uInt16 nFileId, const String& rTabName, SCCOL nCol, SCROW nRow, SCTAB nTab)
++{
++    if (!IfErrorPushError())
++    {
++        ScSingleRefData aRef;
++        aRef.InitFlags();
++        aRef.nCol = nCol;
++        aRef.nRow = nRow;
++        aRef.nTab = nTab;
++        PushTempTokenWithoutError( new ScExternalSingleRefToken(nFileId, rTabName, aRef)) ;
++    }
++}
++
++
++void ScInterpreter::PushExternalDoubleRef(
++    sal_uInt16 nFileId, const String& rTabName, 
++    SCCOL nCol1, SCROW nRow1, SCTAB nTab1, SCCOL nCol2, SCROW nRow2, SCTAB nTab2)
++{
++    if (!IfErrorPushError())
++    {
++        ScComplexRefData aRef;
++        aRef.InitFlags();
++        aRef.Ref1.nCol = nCol1;
++        aRef.Ref1.nRow = nRow1;
++        aRef.Ref1.nTab = nTab1;
++        aRef.Ref2.nCol = nCol2;
++        aRef.Ref2.nRow = nRow2;
++        aRef.Ref2.nTab = nTab2;
++        PushTempTokenWithoutError( new ScExternalDoubleRefToken(nFileId, rTabName, aRef) );
++    }
++}
++
++
+ void ScInterpreter::PushMatrix(ScMatrix* pMat)
+ {
+     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::PushMatrix" );
+@@ -1880,6 +2079,23 @@ BOOL ScInterpreter::DoubleRefToPosSingleRef( const ScRange& rRange, ScAddress& r
+     return bOk;
+ }
+ 
++double ScInterpreter::GetDoubleFromMatrix(const ScMatrixRef& pMat)
++{
++    if (!pMat)
++        return 0.0;
++
++    if ( !pJumpMatrix )
++        return pMat->GetDouble( 0 );
++
++    SCSIZE nCols, nRows, nC, nR;
++    pMat->GetDimensions( nCols, nRows);
++    pJumpMatrix->GetPos( nC, nR);
++    if ( nC < nCols && nR < nRows )
++        return pMat->GetDouble( nC, nR);
++
++    SetError( errNoValue);
++    return 0.0;
++}
+ 
+ double ScInterpreter::GetDouble()
+ {
+@@ -1915,26 +2131,28 @@ double ScInterpreter::GetDouble()
+                 nVal = 0.0;
+         }
+         break;
++        case svExternalSingleRef:
++        {
++            ScExternalRefCache::TokenRef pToken;
++            PopExternalSingleRef(pToken);
++            if (!nGlobalError && pToken)
++                nVal = pToken->GetDouble();
++        }
++        break;
++        case svExternalDoubleRef:
++        {
++            ScMatrixRef pMat;
++            PopExternalDoubleRef(pMat);
++            if (nGlobalError)
++                break;
++
++            nVal = GetDoubleFromMatrix(pMat);
++        }
++        break;
+         case svMatrix:
+         {
+             ScMatrixRef pMat = PopMatrix();
+-            if ( !pMat )
+-                nVal = 0.0;
+-            else if ( !pJumpMatrix )
+-                nVal = pMat->GetDouble( 0 );
+-            else
+-            {
+-                SCSIZE nCols, nRows, nC, nR;
+-                pMat->GetDimensions( nCols, nRows);
+-                pJumpMatrix->GetPos( nC, nR);
+-                if ( nC < nCols && nR < nRows )
+-                    nVal = pMat->GetDouble( nC, nR);
+-                else
+-                {
+-                    SetError( errNoValue);
+-                    nVal = 0.0;
+-                }
+-            }
++            nVal = GetDoubleFromMatrix(pMat);
+         }
+         break;
+         case svError:
+@@ -2023,30 +2241,23 @@ const String& ScInterpreter::GetString()
+             else
+                 return EMPTY_STRING;
+         }
++        case svExternalSingleRef:
++        {
++            ScExternalRefCache::TokenRef pToken;
++            PopExternalSingleRef(pToken);
++            return nGlobalError ? EMPTY_STRING : pToken->GetString();
++        }
++        case svExternalDoubleRef:
++        {
++            ScMatrixRef pMat;
++            PopExternalDoubleRef(pMat);
++            return GetStringFromMatrix(pMat);
++        }
+         //break;
+         case svMatrix:
+         {
+             ScMatrixRef pMat = PopMatrix();
+-            if ( !pMat )
+-                ;   // nothing
+-            else if ( !pJumpMatrix )
+-            {
+-                aTempStr = pMat->GetString( *pFormatter, 0, 0);
+-                return aTempStr;
+-            }
+-            else
+-            {
+-                SCSIZE nCols, nRows, nC, nR;
+-                pMat->GetDimensions( nCols, nRows);
+-                pJumpMatrix->GetPos( nC, nR);
+-                if ( nC < nCols && nR < nRows )
+-                {
+-                    aTempStr = pMat->GetString( *pFormatter, nC, nR);
+-                    return aTempStr;
+-                }
+-                else
+-                    SetError( errNoValue);
+-            }
++            return GetStringFromMatrix(pMat);
+         }
+         break;
+         default:
+@@ -2056,7 +2267,30 @@ const String& ScInterpreter::GetString()
+     return EMPTY_STRING;
+ }
+ 
+-
++const String& ScInterpreter::GetStringFromMatrix(const ScMatrixRef& pMat)
++{
++    if ( !pMat )
++        ;   // nothing
++    else if ( !pJumpMatrix )
++    {
++        aTempStr = pMat->GetString( *pFormatter, 0, 0);
++        return aTempStr;
++    }
++    else
++    {
++        SCSIZE nCols, nRows, nC, nR;
++        pMat->GetDimensions( nCols, nRows);
++        pJumpMatrix->GetPos( nC, nR);
++        if ( nC < nCols && nR < nRows )
++        {
++            aTempStr = pMat->GetString( *pFormatter, nC, nR);
++            return aTempStr;
++        }
++        else
++            SetError( errNoValue);
++    }
++    return EMPTY_STRING;
++}
+ 
+ ScMatValType ScInterpreter::GetDoubleOrStringFromMatrix( double& rDouble,
+         String& rString )
+@@ -3252,82 +3486,6 @@ void ScInterpreter::ScColRowNameAuto()
+         PushError( errNoRef );
+ }
+ 
+-void ScInterpreter::ScExternalRef()
+-{
+-    ScExternalRefManager* pRefMgr = pDok->GetExternalRefManager();
+-    const String* pFile = pRefMgr->getExternalFileName(pCur->GetIndex());
+-    if (!pFile)
+-        PushError(errNoName);
+-
+-    switch (pCur->GetType())
+-    {
+-        case svExternalSingleRef:
+-        {
+-            ScSingleRefData aData(static_cast<const ScToken*>(pCur)->GetSingleRef());
+-            if (aData.IsTabRel())
+-            {
+-                DBG_ERROR("ScCompiler::GetToken: external single reference must have an absolute table reference!");
+-                break;
+-            }
+-
+-            aData.CalcAbsIfRel(aPos);
+-            ScAddress aAddr(aData.nCol, aData.nRow, aData.nTab);
+-            ScExternalRefCache::CellFormat aFmt;
+-            ScExternalRefCache::TokenRef xNew = pRefMgr->getSingleRefToken(
+-                pCur->GetIndex(), pCur->GetString(), aAddr, &aPos, NULL, &aFmt);
+-
+-            if (!xNew)
+-                break;
+-
+-            PushTempToken( *xNew);      // push a clone
+-
+-            if (aFmt.mbIsSet)
+-            {
+-                nFuncFmtType = aFmt.mnType;
+-                nFuncFmtIndex = aFmt.mnIndex;
+-            }
+-            return;
+-        }
+-        //break;    // unreachable, prevent compiler warning
+-        case svExternalDoubleRef:
+-        {
+-            ScComplexRefData aData(static_cast<const ScToken*>(pCur)->GetDoubleRef());
+-            if (aData.Ref1.IsTabRel() || aData.Ref2.IsTabRel())
+-            {
+-                DBG_ERROR("ScCompiler::GetToken: external double reference must have an absolute table reference!");
+-                break;
+-            }
+-
+-            aData.CalcAbsIfRel(aPos);
+-            ScRange aRange(aData.Ref1.nCol, aData.Ref1.nRow, aData.Ref1.nTab,
+-                           aData.Ref2.nCol, aData.Ref2.nRow, aData.Ref2.nTab);
+-            ScExternalRefCache::TokenArrayRef xNew = pRefMgr->getDoubleRefTokens(
+-                pCur->GetIndex(), pCur->GetString(), aRange, &aPos);
+-
+-            if (!xNew)
+-                break;
+-
+-            ScToken* p = static_cast<ScToken*>(xNew->First());
+-            if (p->GetType() != svMatrix)
+-                break;
+-
+-            if (xNew->Next())
+-            {
+-                // Can't handle more than one matrix per parameter.
+-                SetError( errIllegalArgument);
+-                break;
+-            }
+-
+-            PushMatrix(p->GetMatrix());
+-            return;
+-        }
+-        //break;    // unreachable, prevent compiler warning
+-        default:
+-            ;
+-    }
+-    PushError(errNoRef);
+-}
+-
+ // --- internals ------------------------------------------------------------
+ 
+ 
+@@ -3685,6 +3843,7 @@ void ScInterpreter::GlobalExit()        // static
+ 
+ StackVar ScInterpreter::Interpret()
+ {
++//  StackPrinter __stack_printer__("ScInterpreter::Interpret");
+     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::Interpret" );
+     short nRetTypeExpr = NUMBERFORMAT_UNDEFINED;
+     ULONG nRetIndexExpr = 0;
+@@ -3768,7 +3927,6 @@ StackVar ScInterpreter::Interpret()
+                 case ocDBArea           : ScDBArea();                   break;
+                 case ocColRowNameAuto   : ScColRowNameAuto();           break;
+ // separated    case ocPush             : Push( (ScToken&) *pCur );     break;
+-                case ocExternalRef      : ScExternalRef();              break;
+                 case ocIf               : ScIfJump();                   break;
+                 case ocChose            : ScChoseJump();                break;
+                 case ocAdd              : ScAdd();                      break;
+@@ -4244,9 +4402,15 @@ StackVar ScInterpreter::Interpret()
+                     }
+                 }
+                 // no break
++                case svExternalDoubleRef:
+                 case svMatrix :
+                 {
+-                    ScMatrixRef xMat = PopMatrix();
++                    ScMatrixRef xMat;
++                    if (pCur->GetType() == svMatrix)
++                        xMat = PopMatrix();
++                    else
++                        PopExternalDoubleRef(xMat);
++
+                     if (xMat)
+                     {
+                         ScMatValType nMatValType;
+@@ -4291,6 +4455,23 @@ StackVar ScInterpreter::Interpret()
+                         SetError( errUnknownStackVariable);
+                 }
+                 break;
++                case svExternalSingleRef:
++                {
++                    ScExternalRefCache::TokenRef pToken;
++                    ScExternalRefCache::CellFormat aFmt;
++                    PopExternalSingleRef(pToken, &aFmt);
++                    if (nGlobalError)
++                        break;
++
++                    PushTempToken(*pToken);
++
++                    if (aFmt.mbIsSet)
++                    {
++                        nFuncFmtType = aFmt.mnType;
++                        nFuncFmtIndex = aFmt.mnIndex;
++                    }
++                }
++                break;
+                 default :
+                     SetError( errUnknownStackVariable);
+             }
+diff --git sc/source/core/tool/token.cxx sc/source/core/tool/token.cxx
+index e467618..a1201c5 100644
+--- sc/source/core/tool/token.cxx
++++ sc/source/core/tool/token.cxx
+@@ -240,7 +240,7 @@ void ScRawToken::SetName( USHORT n )
+ 
+ void ScRawToken::SetExternalSingleRef( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef )
+ {
+-    eOp = ocExternalRef;
++    eOp = ocPush;
+     eType = svExternalSingleRef;
+     nRefCnt = 0;
+ 
+@@ -255,7 +255,7 @@ void ScRawToken::SetExternalSingleRef( sal_uInt16 nFileId, const String& rTabNam
+ 
+ void ScRawToken::SetExternalDoubleRef( sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef )
+ {
+-    eOp = ocExternalRef;
++    eOp = ocPush;
+     eType = svExternalDoubleRef;
+     nRefCnt = 0;
+ 
+@@ -269,7 +269,7 @@ void ScRawToken::SetExternalDoubleRef( sal_uInt16 nFileId, const String& rTabNam
+ 
+ void ScRawToken::SetExternalName( sal_uInt16 nFileId, const String& rName )
+ {
+-    eOp = ocExternalRef;
++    eOp = ocPush;
+     eType = svExternalName;
+     nRefCnt = 0;
+ 
+@@ -347,37 +347,26 @@ ScRawToken* ScRawToken::Clone() const
+         static USHORT nOffset = lcl_ScRawTokenOffset();     // offset of sbyte
+         USHORT n = nOffset;
+ 
+-        if (eOp == ocExternalRef)
++        switch( eType )
+         {
+-            switch (eType)
+-            {
+-                case svExternalSingleRef:
+-                case svExternalDoubleRef: n += sizeof(extref); break;
+-                case svExternalName:      n += sizeof(extname); break;
+-                default:
+-                {
+-                    DBG_ERROR1( "unknown ScRawToken::Clone() external type %d", int(eType));
+-                }
+-            }
+-        }
+-        else
+-        {
+-            switch( eType )
++            case svSep:         break;
++            case svByte:        n += sizeof(ScRawToken::sbyte); break;
++            case svDouble:      n += sizeof(double); break;
++            case svString:      n = sal::static_int_cast<USHORT>( n + GetStrLenBytes( cStr ) + GetStrLenBytes( 1 ) ); break;
++            case svSingleRef:
++            case svDoubleRef:   n += sizeof(aRef); break;
++            case svMatrix:      n += sizeof(ScMatrix*); break;
++            case svIndex:       n += sizeof(USHORT); break;
++            case svJump:        n += nJump[ 0 ] * 2 + 2; break;
++            case svExternal:    n = sal::static_int_cast<USHORT>( n + GetStrLenBytes( cStr+1 ) + GetStrLenBytes( 2 ) ); break;
++
++            // external references
++            case svExternalSingleRef:
++            case svExternalDoubleRef: n += sizeof(extref); break;
++            case svExternalName:      n += sizeof(extname); break;
++            default:
+             {
+-                case svSep:         break;
+-                case svByte:        n += sizeof(ScRawToken::sbyte); break;
+-                case svDouble:      n += sizeof(double); break;
+-                case svString:      n = sal::static_int_cast<USHORT>( n + GetStrLenBytes( cStr ) + GetStrLenBytes( 1 ) ); break;
+-                case svSingleRef:
+-                case svDoubleRef:   n += sizeof(aRef); break;
+-                case svMatrix:      n += sizeof(ScMatrix*); break;
+-                case svIndex:       n += sizeof(USHORT); break;
+-                case svJump:        n += nJump[ 0 ] * 2 + 2; break;
+-                case svExternal:    n = sal::static_int_cast<USHORT>( n + GetStrLenBytes( cStr+1 ) + GetStrLenBytes( 2 ) ); break;
+-                default:
+-                {
+-                    DBG_ERROR1( "unknown ScRawToken::Clone() type %d", int(eType));
+-                }
++                DBG_ERROR1( "unknown ScRawToken::Clone() type %d", int(eType));
+             }
+         }
+         p = (ScRawToken*) new BYTE[ n ];
+@@ -841,7 +830,7 @@ BOOL ScMatrixToken::operator==( const FormulaToken& r ) const
+ // ============================================================================
+ 
+ ScExternalSingleRefToken::ScExternalSingleRefToken( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& r ) :
+-    ScToken( svExternalSingleRef, ocExternalRef),
++    ScToken( svExternalSingleRef, ocPush),
+     mnFileId(nFileId),
+     maTabName(rTabName),
+     maSingleRef(r)
+@@ -907,7 +896,7 @@ BOOL ScExternalSingleRefToken::operator ==( const FormulaToken& r ) const
+ // ============================================================================
+ 
+ ScExternalDoubleRefToken::ScExternalDoubleRefToken( sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& r ) :
+-    ScToken( svExternalDoubleRef, ocExternalRef),
++    ScToken( svExternalDoubleRef, ocPush),
+     mnFileId(nFileId),
+     maTabName(rTabName),
+     maDoubleRef(r)
+@@ -993,7 +982,7 @@ BOOL ScExternalDoubleRefToken::operator ==( const FormulaToken& r ) const
+ // ============================================================================
+ 
+ ScExternalNameToken::ScExternalNameToken( sal_uInt16 nFileId, const String& rName ) :
+-    ScToken( svExternalName, ocExternalRef),
++    ScToken( svExternalName, ocPush),
+     mnFileId(nFileId),
+     maName(rName)
+ {
+diff --git sc/source/filter/excel/xeformula.cxx sc/source/filter/excel/xeformula.cxx
+index 34e4867..2b5d534 100644
+--- sc/source/filter/excel/xeformula.cxx
++++ sc/source/filter/excel/xeformula.cxx
+@@ -2104,7 +2104,7 @@ void XclExpFmlaCompImpl::ProcessExternalName( const XclExpScToken& rTokData )
+             {
+                 for( FormulaToken* pScToken = xArray->First(); pScToken; pScToken = xArray->Next() )
+                 {
+-                    if( pScToken->GetOpCode() == ocExternalRef )
++                    if( pScToken->IsExternalRef() )
+                     {
+                         switch( pScToken->GetType() )
+                         {
+diff --git sc/source/filter/excel/xelink.cxx sc/source/filter/excel/xelink.cxx
+index d5259c7..eb09768 100644
+--- sc/source/filter/excel/xelink.cxx
++++ sc/source/filter/excel/xelink.cxx
+@@ -1012,7 +1012,7 @@ void XclExpExtName::WriteAddData( XclExpStream& rStrm )
+             break;
+ 
+         const ScToken* p = static_cast<const ScToken*>(mpArray->First());
+-        if (p->GetOpCode() != ocExternalRef)
++        if (!p->IsExternalRef())
+             break;
+ 
+         switch (p->GetType())
+diff --git sc/source/filter/xlsx/xlsx-xeformula.cxx sc/source/filter/xlsx/xlsx-xeformula.cxx
+index 7f71543..dd15c7b 100644
+--- sc/source/filter/xlsx/xlsx-xeformula.cxx
++++ sc/source/filter/xlsx/xlsx-xeformula.cxx
+@@ -2109,26 +2109,23 @@ void XclExpFmlaCompImpl::ProcessExternalName( const XclExpScToken& rTokData )
+             {
+                 for( FormulaToken* pScToken = xArray->First(); pScToken; pScToken = xArray->Next() )
+                 {
+-                    if( pScToken->GetOpCode() == ocExternalRef )
++                    switch( pScToken->GetType() )
+                     {
+-                        switch( pScToken->GetType() )
++                        case svExternalSingleRef:
+                         {
+-                            case svExternalSingleRef:
+-                            {
+-                                ScSingleRefData aRefData = static_cast< ScToken* >( pScToken )->GetSingleRef();
+-                                aRefData.CalcAbsIfRel( *mxData->mpScBasePos );
+-                                mxData->mpLinkMgr->StoreCell( nFileId, pScToken->GetString(), aRefData );
+-                            }
+-                            break;
+-                            case svExternalDoubleRef:
+-                            {
+-                                ScComplexRefData aRefData = static_cast< ScToken* >( pScToken )->GetDoubleRef();
+-                                aRefData.CalcAbsIfRel( *mxData->mpScBasePos );
+-                                mxData->mpLinkMgr->StoreCellRange( nFileId, pScToken->GetString(), aRefData );
+-                            }
+-                            default:
+-                                ;   // nothing, avoid compiler warning
++                            ScSingleRefData aRefData = static_cast< ScToken* >( pScToken )->GetSingleRef();
++                            aRefData.CalcAbsIfRel( *mxData->mpScBasePos );
++                            mxData->mpLinkMgr->StoreCell( nFileId, pScToken->GetString(), aRefData );
+                         }
++                        break;
++                        case svExternalDoubleRef:
++                        {
++                            ScComplexRefData aRefData = static_cast< ScToken* >( pScToken )->GetDoubleRef();
++                            aRefData.CalcAbsIfRel( *mxData->mpScBasePos );
++                            mxData->mpLinkMgr->StoreCellRange( nFileId, pScToken->GetString(), aRefData );
++                        }
++                        default:
++                            ;   // nothing, avoid compiler warning
+                     }
+                 }
+             }
+diff --git sc/source/filter/xlsx/xlsx-xelink.cxx sc/source/filter/xlsx/xlsx-xelink.cxx
+index 6934d46..bbad5be 100644
+--- sc/source/filter/xlsx/xlsx-xelink.cxx
++++ sc/source/filter/xlsx/xlsx-xelink.cxx
+@@ -1015,8 +1015,6 @@ void XclExpExtName::WriteAddData( XclExpStream& rStrm )
+             break;
+ 
+         const ScToken* p = static_cast<const ScToken*>(mpArray->First());
+-        if (p->GetOpCode() != ocExternalRef)
+-            break;
+ 
+         switch (p->GetType())
+         {
+diff --git sc/source/ui/docshell/externalrefmgr.cxx sc/source/ui/docshell/externalrefmgr.cxx
+index 330f559..f3d2eed 100644
+--- sc/source/ui/docshell/externalrefmgr.cxx
++++ sc/source/ui/docshell/externalrefmgr.cxx
+@@ -145,7 +145,7 @@ struct UpdateFormulaCell : public unary_function<ScFormulaCell*, void>
+         // External names, external cell and range references all have a
+         // ocExternalRef token.
+         const ScTokenArray* pCode = pCell->GetCode();
+-        if (!pCode->HasOpCode( ocExternalRef))
++        if (!pCode->HasExternalRef())
+             return;
+ 
+         ScTokenArray* pArray = pCell->GetCode();
+@@ -1315,7 +1315,7 @@ static FormulaToken* lcl_convertToToken(ScBaseCell* pCell)
+     return NULL;
+ }
+ 
+-static ScTokenArray* lcl_convertToTokenArray(ScDocument* pSrcDoc, ScRange& rRange,
++static ScTokenArray* lcl_convertToTokenArray(const ScDocument* pSrcDoc, ScRange& rRange,
+                                              vector<ScExternalRefCache::SingleRangeData>& rCacheData)
+ {
+     ScAddress& s = rRange.aStart;
+@@ -1601,6 +1601,27 @@ ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefToken(
+     if (pFmt)
+         pFmt->mbIsSet = false;
+ 
++    const ScDocument* pSrcDoc = getInMemorySrcDocument(nFileId);
++    if (pSrcDoc)
++    {   
++        // source document already loaded in memory.  Re-use this instance.
++        // We don't even cache data when the document is loaded.
++
++        SCTAB nTab;
++        if (!pSrcDoc->GetTable(rTabName, nTab))
++        {
++            // specified table name doesn't exist in the source document.
++            ScExternalRefCache::TokenRef pToken(new FormulaErrorToken(errNoRef));
++            return pToken;
++        }
++
++        if (pTab)
++            *pTab = nTab;
++
++        return getSingleRefTokenFromSrcDoc(
++            nFileId, pSrcDoc, ScAddress(rCell.Col(),rCell.Row(),nTab), pFmt);
++    }
++
+     // Check if the given table name and the cell position is cached.
+     sal_uInt32 nFmtIndex = 0;
+     ScExternalRefCache::TokenRef pToken = maRefCache.getCellData(
+@@ -1608,21 +1629,12 @@ ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefToken(
+     if (pToken)
+     {
+         // Cache hit !
+-        if (pFmt)
+-        {
+-            short nFmtType = mpDoc->GetFormatTable()->GetType(nFmtIndex);
+-            if (nFmtType != NUMBERFORMAT_UNDEFINED)
+-            {
+-                pFmt->mbIsSet = true;
+-                pFmt->mnIndex = nFmtIndex;
+-                pFmt->mnType = nFmtType;
+-            }
+-        }
++        fillCellFormat(nFmtIndex, pFmt);
+         return pToken;
+     }
+ 
+     // reference not cached.  read from the source document.
+-    ScDocument* pSrcDoc = getSrcDocument(nFileId);
++    pSrcDoc = getSrcDocument(nFileId);
+     if (!pSrcDoc)
+     {
+         // Source document not reachable.  Throw a reference error.
+@@ -1630,7 +1642,6 @@ ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefToken(
+         return pToken;
+     }
+ 
+-    ScBaseCell* pCell = NULL;
+     SCTAB nTab;
+     if (!pSrcDoc->GetTable(rTabName, nTab))
+     {
+@@ -1659,33 +1670,14 @@ ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefToken(
+         return pToken;
+     }
+ 
+-    pSrcDoc->GetCell(rCell.Col(), rCell.Row(), nTab, pCell);
+-    ScExternalRefCache::TokenRef pTok(lcl_convertToToken(pCell));
+-
+-    pSrcDoc->GetNumberFormat(rCell.Col(), rCell.Row(), nTab, nFmtIndex);
+-    nFmtIndex = getMappedNumberFormat(nFileId, nFmtIndex, pSrcDoc);
+-    if (pFmt)
+-    {
+-        short nFmtType = mpDoc->GetFormatTable()->GetType(nFmtIndex);
+-        if (nFmtType != NUMBERFORMAT_UNDEFINED)
+-        {
+-            pFmt->mbIsSet = true;
+-            pFmt->mnIndex = nFmtIndex;
+-            pFmt->mnType = nFmtType;
+-        }
+-    }
+-
+-    if (!pTok.get())
+-    {
+-        // Generate an error for unresolvable cells.
+-        pTok.reset( new FormulaErrorToken( errNoValue));
+-    }
++    pToken = getSingleRefTokenFromSrcDoc(
++        nFileId, pSrcDoc, ScAddress(rCell.Col(),rCell.Row(),nTab), pFmt);
+ 
+     // Now, insert the token into cache table but don't cache empty cells.
+-    if (pTok->GetType() != formula::svEmptyCell)
+-        maRefCache.setCellData(nFileId, rTabName, rCell.Col(), rCell.Row(), pTok, nFmtIndex);
++    if (pToken->GetType() != formula::svEmptyCell)
++        maRefCache.setCellData(nFileId, rTabName, rCell.Col(), rCell.Row(), pToken, nFmtIndex);
+ 
+-    return pTok;
++    return pToken;
+ }
+ 
+ ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokens(
+@@ -1696,6 +1688,15 @@ ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokens(
+ 
+     maybeLinkExternalFile(nFileId);
+ 
++    ScRange aRange(rRange);
++    const ScDocument* pSrcDoc = getInMemorySrcDocument(nFileId);
++    if (pSrcDoc)
++    {
++        // Document already loaded.
++        vector<ScExternalRefCache::SingleRangeData> aCacheData;
++        return getDoubleRefTokensFromSrcDoc(pSrcDoc, rTabName, aRange, aCacheData);
++    }
++
+     // Check if the given table name and the cell position is cached.
+     ScExternalRefCache::TokenArrayRef pArray = 
+         maRefCache.getCellRangeData(nFileId, rTabName, rRange);
+@@ -1703,7 +1704,7 @@ ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokens(
+         // Cache hit !
+         return pArray;
+ 
+-    ScDocument* pSrcDoc = getSrcDocument(nFileId);
++    pSrcDoc = getSrcDocument(nFileId);
+     if (!pSrcDoc)
+     {
+         // Source document is not reachable.  Throw a reference error.
+@@ -1712,38 +1713,8 @@ ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokens(
+         return pArray;
+     }
+ 
+-    SCTAB nTab1;
+-    if (!pSrcDoc->GetTable(rTabName, nTab1))
+-    {
+-        // specified table name doesn't exist in the source document.
+-        pArray.reset(new ScTokenArray);
+-        pArray->AddToken(FormulaErrorToken(errNoRef));
+-        return pArray;
+-    }
+-
+-    ScRange aRange(rRange);
+-    SCTAB nTabSpan = aRange.aEnd.Tab() - aRange.aStart.Tab();
+-
+     vector<ScExternalRefCache::SingleRangeData> aCacheData;
+-    aCacheData.reserve(nTabSpan+1);
+-    aCacheData.push_back(ScExternalRefCache::SingleRangeData());
+-    aCacheData.back().maTableName = ScGlobal::pCharClass->upper(rTabName);
+-
+-    for (SCTAB i = 1; i < nTabSpan + 1; ++i)
+-    {
+-        String aTabName;
+-        if (!pSrcDoc->GetName(nTab1 + 1, aTabName))
+-            // source document doesn't have any table by the specified name.
+-            break;
+-
+-        aCacheData.push_back(ScExternalRefCache::SingleRangeData());
+-        aCacheData.back().maTableName = ScGlobal::pCharClass->upper(aTabName);
+-    }
+-
+-    aRange.aStart.SetTab(nTab1);
+-    aRange.aEnd.SetTab(nTab1 + nTabSpan);
+-
+-    pArray.reset(lcl_convertToTokenArray(pSrcDoc, aRange, aCacheData));
++    pArray = getDoubleRefTokensFromSrcDoc(pSrcDoc, rTabName, aRange, aCacheData);    
+ 
+     if (pArray)
+         // Cache these values.
+@@ -1772,14 +1743,159 @@ ScExternalRefCache::TokenArrayRef ScExternalRefManager::getRangeNameTokens(sal_u
+ 
+     maybeLinkExternalFile(nFileId);
+ 
++    String aName = rName; // make a copy to have the casing corrected.
++    const ScDocument* pSrcDoc = getInMemorySrcDocument(nFileId);
++    if (pSrcDoc)
++    {
++        // Document already loaded in memory.
++        return getRangeNameTokensFromSrcDoc(nFileId, pSrcDoc, aName);
++    }
++
+     ScExternalRefCache::TokenArrayRef pArray = maRefCache.getRangeNameTokens(nFileId, rName);
+     if (pArray.get())
++        // This range name is cached.
+         return pArray;
+ 
+-    ScDocument* pSrcDoc = getSrcDocument(nFileId);
++    pSrcDoc = getSrcDocument(nFileId);
+     if (!pSrcDoc)
++        // failed to load document from disk.
+         return ScExternalRefCache::TokenArrayRef();
+ 
++    pArray = getRangeNameTokensFromSrcDoc(nFileId, pSrcDoc, aName);
++
++    if (pArray)
++        // Cache this range name array.
++        maRefCache.setRangeNameTokens(nFileId, aName, pArray);
++
++    return pArray;
++}
++
++void ScExternalRefManager::refreshAllRefCells(sal_uInt16 nFileId)
++{
++    RefCellMap::iterator itrFile = maRefCells.find(nFileId);
++    if (itrFile == maRefCells.end())
++        return;
++
++    RefCellSet& rRefCells = itrFile->second;
++    for_each(rRefCells.begin(), rRefCells.end(), UpdateFormulaCell());
++
++    ScViewData* pViewData = ScDocShell::GetViewData();
++    if (!pViewData)
++        return;
++
++    ScTabViewShell* pVShell = pViewData->GetViewShell();
++    if (!pVShell)
++        return;
++
++    // Repainting the grid also repaints the texts, but is there a better way
++    // to refresh texts?
++    pVShell->Invalidate(FID_REPAINT);
++    pVShell->PaintGrid();
++}
++
++void ScExternalRefManager::insertRefCell(sal_uInt16 nFileId, const ScAddress& rCell)
++{
++    RefCellMap::iterator itr = maRefCells.find(nFileId);
++    if (itr == maRefCells.end())
++    {
++        RefCellSet aRefCells;
++        pair<RefCellMap::iterator, bool> r = maRefCells.insert(
++            RefCellMap::value_type(nFileId, aRefCells));
++        if (!r.second)
++            // insertion failed.
++            return;
++
++        itr = r.first;
++    }
++
++    ScBaseCell* pCell = mpDoc->GetCell(rCell);
++    if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
++        itr->second.insert(static_cast<ScFormulaCell*>(pCell));
++}
++
++void ScExternalRefManager::fillCellFormat(sal_uInt32 nFmtIndex, ScExternalRefCache::CellFormat* pFmt) const
++{
++    if (!pFmt)
++        return;
++
++    short nFmtType = mpDoc->GetFormatTable()->GetType(nFmtIndex);
++    if (nFmtType != NUMBERFORMAT_UNDEFINED)
++    {
++        pFmt->mbIsSet = true;
++        pFmt->mnIndex = nFmtIndex;
++        pFmt->mnType = nFmtType;
++    }
++}
++
++ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefTokenFromSrcDoc(
++    sal_uInt16 nFileId, const ScDocument* pSrcDoc, const ScAddress& rCell, 
++    ScExternalRefCache::CellFormat* pFmt)
++{
++    // Get the cell from src doc, and convert it into a token.
++    ScBaseCell* pCell = NULL;
++    pSrcDoc->GetCell(rCell.Col(), rCell.Row(), rCell.Tab(), pCell);
++    ScExternalRefCache::TokenRef pToken(lcl_convertToToken(pCell));
++
++    if (!pToken.get())
++    {
++        // Generate an error for unresolvable cells.
++        pToken.reset( new FormulaErrorToken( errNoValue));
++    }
++
++    // Get number format information.
++    sal_uInt32 nFmtIndex = 0;
++    pSrcDoc->GetNumberFormat(rCell.Col(), rCell.Row(), rCell.Tab(), nFmtIndex);
++    nFmtIndex = getMappedNumberFormat(nFileId, nFmtIndex, pSrcDoc);
++    fillCellFormat(nFmtIndex, pFmt);
++    return pToken;
++}
++
++ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokensFromSrcDoc(
++    const ScDocument* pSrcDoc, const String& rTabName, ScRange& rRange,
++    vector<ScExternalRefCache::SingleRangeData>& rCacheData)
++{
++    ScExternalRefCache::TokenArrayRef pArray;
++    SCTAB nTab1;
++
++    if (!pSrcDoc->GetTable(rTabName, nTab1))
++    {
++        // specified table name doesn't exist in the source document.
++        pArray.reset(new ScTokenArray);
++        pArray->AddToken(FormulaErrorToken(errNoRef));
++        return pArray;
++    }
++
++    ScRange aRange(rRange);
++    SCTAB nTabSpan = aRange.aEnd.Tab() - aRange.aStart.Tab();
++
++    vector<ScExternalRefCache::SingleRangeData> aCacheData;
++    aCacheData.reserve(nTabSpan+1);
++    aCacheData.push_back(ScExternalRefCache::SingleRangeData());
++    aCacheData.back().maTableName = ScGlobal::pCharClass->upper(rTabName);
++
++    for (SCTAB i = 1; i < nTabSpan + 1; ++i)
++    {
++        String aTabName;
++        if (!pSrcDoc->GetName(nTab1 + 1, aTabName))
++            // source document doesn't have any table by the specified name.
++            break;
++
++        aCacheData.push_back(ScExternalRefCache::SingleRangeData());
++        aCacheData.back().maTableName = ScGlobal::pCharClass->upper(aTabName);
++    }
++
++    aRange.aStart.SetTab(nTab1);
++    aRange.aEnd.SetTab(nTab1 + nTabSpan);
++
++    pArray.reset(lcl_convertToTokenArray(pSrcDoc, aRange, aCacheData));
++    rRange = aRange;
++    rCacheData.swap(aCacheData);
++    return pArray;
++}
++
++ScExternalRefCache::TokenArrayRef ScExternalRefManager::getRangeNameTokensFromSrcDoc(
++    sal_uInt16 nFileId, const ScDocument* pSrcDoc, String& rName)
++{
+     ScRangeName* pExtNames = pSrcDoc->GetRangeName();
+     String aUpperName = ScGlobal::pCharClass->upper(rName);
+     USHORT n;
+@@ -1832,55 +1948,37 @@ ScExternalRefCache::TokenArrayRef ScExternalRefManager::getRangeNameTokens(sal_u
+             pNew->AddToken(*pToken);
+     }
+ 
+-    // Make sure to pass the correctly-cased range name here.
+-    maRefCache.setRangeNameTokens(nFileId, pRangeData->GetName(), pNew);
++    rName = pRangeData->GetName(); // Get the correctly-cased name.
+     return pNew;
+ }
+ 
+-void ScExternalRefManager::refreshAllRefCells(sal_uInt16 nFileId)
++const ScDocument* ScExternalRefManager::getInMemorySrcDocument(sal_uInt16 nFileId)
+ {
+-    RefCellMap::iterator itrFile = maRefCells.find(nFileId);
+-    if (itrFile == maRefCells.end())
+-        return;
+-
+-    RefCellSet& rRefCells = itrFile->second;
+-    for_each(rRefCells.begin(), rRefCells.end(), UpdateFormulaCell());
+-
+-    ScViewData* pViewData = ScDocShell::GetViewData();
+-    if (!pViewData)
+-        return;
+-
+-    ScTabViewShell* pVShell = pViewData->GetViewShell();
+-    if (!pVShell)
+-        return;
+-
+-    // Repainting the grid also repaints the texts, but is there a better way
+-    // to refresh texts?
+-    pVShell->Invalidate(FID_REPAINT);
+-    pVShell->PaintGrid();
+-}
++    const String* pFileName = getExternalFileName(nFileId);
++    if (!pFileName)
++        return NULL;
+ 
+-void ScExternalRefManager::insertRefCell(sal_uInt16 nFileId, const ScAddress& rCell)
+-{
+-    RefCellMap::iterator itr = maRefCells.find(nFileId);
+-    if (itr == maRefCells.end())
++    TypeId aType(TYPE(ScDocShell));
++    ScDocShell* pShell = static_cast<ScDocShell*>(SfxObjectShell::GetFirst(&aType, false));
++    while (pShell)
+     {
+-        RefCellSet aRefCells;
+-        pair<RefCellMap::iterator, bool> r = maRefCells.insert(
+-            RefCellMap::value_type(nFileId, aRefCells));
+-        if (!r.second)
+-            // insertion failed.
+-            return;
+-
+-        itr = r.first;
++        SfxMedium* pMedium = pShell->GetMedium();
++        if (pMedium)
++        {
++            String aName = pMedium->GetName();
++            // TODO: We should make the case sensitivity platform dependent.
++            if (pFileName->EqualsIgnoreCaseAscii(aName))
++            {
++                // Found !
++                return pShell->GetDocument();
++            }
++        }
++        pShell = static_cast<ScDocShell*>(SfxObjectShell::GetNext(*pShell, &aType, false));
+     }
+-
+-    ScBaseCell* pCell = mpDoc->GetCell(rCell);
+-    if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
+-        itr->second.insert(static_cast<ScFormulaCell*>(pCell));
++    return NULL;
+ }
+ 
+-ScDocument* ScExternalRefManager::getSrcDocument(sal_uInt16 nFileId)
++const ScDocument* ScExternalRefManager::getSrcDocument(sal_uInt16 nFileId)
+ {
+     if (!mpDoc->IsExecuteLinkEnabled())
+         return NULL;
+@@ -2347,7 +2445,7 @@ void ScExternalRefManager::purgeStaleSrcDocument(sal_Int32 nTimeOut)
+         maSrcDocTimer.Stop();
+ }
+ 
+-sal_uInt32 ScExternalRefManager::getMappedNumberFormat(sal_uInt16 nFileId, sal_uInt32 nNumFmt, ScDocument* pSrcDoc)
++sal_uInt32 ScExternalRefManager::getMappedNumberFormat(sal_uInt16 nFileId, sal_uInt32 nNumFmt, const ScDocument* pSrcDoc)
+ {
+     NumFmtMap::iterator itr = maNumFormatMap.find(nFileId);
+     if (itr == maNumFormatMap.end())


More information about the ooo-build-commit mailing list