[ooo-build-commit] .: sc/inc sc/source

Kohei Yoshida kohei at kemper.freedesktop.org
Tue Oct 5 15:17:05 PDT 2010


 sc/inc/document.hxx                      |    4 
 sc/inc/externalrefmgr.hxx                |   96 ++++-
 sc/source/core/data/cell.cxx             |    2 
 sc/source/core/data/documen3.cxx         |    2 
 sc/source/core/data/documen4.cxx         |    2 
 sc/source/core/data/document.cxx         |    2 
 sc/source/core/inc/interpre.hxx          |   30 +
 sc/source/core/tool/address.cxx          |   13 
 sc/source/core/tool/interpr1.cxx         |  416 ++++++++++++++++++-------
 sc/source/core/tool/interpr4.cxx         |  499 +++++++++++++++++++++----------
 sc/source/core/tool/token.cxx            |   59 +--
 sc/source/filter/excel/xeformula.cxx     |    2 
 sc/source/filter/excel/xelink.cxx        |    2 
 sc/source/ui/docshell/externalrefmgr.cxx |  334 +++++++++++++-------
 14 files changed, 985 insertions(+), 478 deletions(-)

New commits:
commit c9d53a9a25770f6736c5f2342d57c237bde2f23e
Author: Kohei Yoshida <kyoshida at novell.com>
Date:   Tue Oct 5 18:14:37 2010 -0400

    Ported calc-extref-interpreter-rework-*.diff from ooo-build.
    
    Re-structured the interpreter code to handle external references with
    ocPush, instead of ocExternalRef.  This is necessary in order to
    support shifting of references in the same way you can with internal
    references.
    
    In addition, this change allows re-using of document instances already
    loaded when accessing external references that point to one of already
    loaded documents.  Previously, Calc would load the same document from
    disk even when the document was already loaded.
    
    (n#628876)

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 17c0111..7565e3f 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -496,7 +496,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; }
@@ -796,7 +796,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 a/sc/inc/externalrefmgr.hxx b/sc/inc/externalrefmgr.hxx
index 49627f2..e0988f9 100644
--- a/sc/inc/externalrefmgr.hxx
+++ b/sc/inc/externalrefmgr.hxx
@@ -1,7 +1,7 @@
 /*************************************************************************
  *
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- * 
+ *
  * Copyright 2000, 2010 Oracle and/or its affiliates.
  *
  * OpenOffice.org - a multi-platform office productivity suite
@@ -129,14 +129,14 @@ public:
     class Table;
     friend class ScExternalRefCache::Table;
 
-    /** 
-     * Represents a single cached table in an external document.  It only 
-     * stores non-empty cells; empty cells should never be stored in the data 
-     * cache. Instead, cached ranges should be used to determine whether or 
-     * not a cell is empty or needs fetching from the source document.  If a 
-     * cell's value is not stored but its address is within the cached ranges, 
-     * that cell is already queried in the source document and we know it's 
-     * empty. 
+    /**
+     * Represents a single cached table in an external document.  It only
+     * stores non-empty cells; empty cells should never be stored in the data
+     * cache. Instead, cached ranges should be used to determine whether or
+     * not a cell is empty or needs fetching from the source document.  If a
+     * cell's value is not stored but its address is within the cached ranges,
+     * that cell is already queried in the source document and we know it's
+     * empty.
      */
     class Table
     {
@@ -152,10 +152,10 @@ public:
         Table();
         ~Table();
 
-        /** 
+        /**
          * Add cell value to the cache.
          *
-         * @param bSetCacheRange if true, mark this cell 'cached'.  This is 
+         * @param bSetCacheRange if true, mark this cell 'cached'.  This is
          *                       false _only when_ adding a range of cell
          *                       values, for performance reasons.
          */
@@ -184,12 +184,12 @@ public:
         void setCachedCell(SCCOL nCol, SCROW nRow);
         void setCachedCellRange(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2);
 
-        /** 
+        /**
          * Call this to mark the entire table "cached".  This will prevent all
-         * future attempts to access the source document even when non-cached 
-         * cells are queried.  In such case, non-cached cells are treated as 
-         * empty cells.  Useful when loading a document with own external data 
-         * cache. 
+         * future attempts to access the source document even when non-cached
+         * cells are queried.  In such case, non-cached cells are treated as
+         * empty cells.  Useful when loading a document with own external data
+         * cache.
          */
         SC_DLLPUBLIC void setWholeTableCached();
     private:
@@ -390,10 +390,10 @@ public:
         };
     };
 
-    /** 
-     * Use this guard when performing something from the API that might query 
-     * values from external references.  Interpreting formula strings is one 
-     * such example. 
+    /**
+     * Use this guard when performing something from the API that might query
+     * values from external references.  Interpreting formula strings is one
+     * such example.
      */
     class ApiGuard
     {
@@ -645,10 +645,10 @@ public:
      */
     void resetSrcFileData(const String& rBaseFileUrl);
 
-    /** 
-     * Stop tracking a specific formula cell. 
-     *  
-     * @param pCell pointer to cell that formerly contained external 
+    /**
+     * Stop tracking a specific formula cell.
+     *
+     * @param pCell pointer to cell that formerly contained external
      *              reference.
      */
     void removeRefCell(ScFormulaCell* pCell);
@@ -684,7 +684,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;
 
@@ -711,7 +751,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. */
@@ -744,8 +784,8 @@ private:
     /** Status whether in reference marking state. See isInReferenceMarking(). */
     bool mbInReferenceMarking:1;
 
-    /** 
-     * Controls whether or not to allow user interaction.  We don't want any 
+    /**
+     * Controls whether or not to allow user interaction.  We don't want any
      * user interaction when calling from the API.
      */
     bool mbUserInteractionEnabled:1;
diff --git a/sc/source/core/data/cell.cxx b/sc/source/core/data/cell.cxx
index 05466a8..c524f0c 100644
--- a/sc/source/core/data/cell.cxx
+++ b/sc/source/core/data/cell.cxx
@@ -776,7 +776,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 a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx
index cba55d9..2869ced 100644
--- a/sc/source/core/data/documen3.cxx
+++ b/sc/source/core/data/documen3.cxx
@@ -93,7 +93,7 @@ using namespace com::sun::star;
 
 //------------------------------------------------------------------------
 
-ScRangeName* ScDocument::GetRangeName()
+ScRangeName* ScDocument::GetRangeName() const
 {
     return pRangeName;
 }
diff --git a/sc/source/core/data/documen4.cxx b/sc/source/core/data/documen4.cxx
index cbd55fd..48f3e2b 100644
--- a/sc/source/core/data/documen4.cxx
+++ b/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 a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 998091c..7a75b14 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -2712,7 +2712,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 a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx
index d80573a..98c6afb 100644
--- a/sc/source/core/inc/interpre.hxx
+++ b/sc/source/core/inc/interpre.hxx
@@ -1,7 +1,7 @@
 /*************************************************************************
  *
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- * 
+ *
  * Copyright 2000, 2010 Oracle and/or its affiliates.
  *
  * OpenOffice.org - a multi-platform office productivity suite
@@ -35,6 +35,7 @@
 #include "scdll.hxx"
 #include "document.hxx"
 #include "scmatrix.hxx"
+#include "externalrefmgr.hxx"
 
 #include <math.h>
 #include <map>
@@ -148,7 +149,7 @@ private:
     ScFormulaCell* pMyFormulaCell;      // the cell of this formula expression
     SvNumberFormatter* pFormatter;
 
-    const formula::FormulaToken* 
+    const formula::FormulaToken*
                 pCur;                // current token
     String      aTempStr;               // for GetString()
     ScTokenStack* pStackObj;            // contains the stacks
@@ -294,10 +295,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.
@@ -315,7 +321,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.
@@ -327,11 +338,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,
@@ -527,7 +540,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();
@@ -537,10 +549,10 @@ void ScTTT();
 
 /** Obtain the date serial number for a given date.
     @param bStrict
-        If FALSE, nYear < 100 takes the two-digit year setting into account, 
-        and rollover of invalid calendar dates takes place, e.g. 1999-02-31 => 
+        If FALSE, nYear < 100 takes the two-digit year setting into account,
+        and rollover of invalid calendar dates takes place, e.g. 1999-02-31 =>
         1999-03-03.
-        If TRUE, the date passed must be a valid Gregorian calendar date. No 
+        If TRUE, the date passed must be a valid Gregorian calendar date. No
         two-digit expanding or rollover is done.
  */
 double GetDateSerial( INT16 nYear, INT16 nMonth, INT16 nDay, bool bStrict );
@@ -803,7 +815,7 @@ public:
     formula::StackVar  GetResultType()              const   { return xResult->GetType(); }
     const String&   GetStringResult()               const   { return xResult->GetString(); }
     double          GetNumResult()                  const   { return xResult->GetDouble(); }
-    formula::FormulaTokenRef 
+    formula::FormulaTokenRef
                     GetResultToken()                const   { return xResult; }
     short           GetRetFormatType()              const   { return nRetFmtType; }
     ULONG           GetRetFormatIndex()             const   { return nRetFmtIndex; }
diff --git a/sc/source/core/tool/address.cxx b/sc/source/core/tool/address.cxx
index 41e8314..59436ae 100644
--- a/sc/source/core/tool/address.cxx
+++ b/sc/source/core/tool/address.cxx
@@ -1008,7 +1008,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 a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index 6f87a48..fec2086 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -1,7 +1,7 @@
 /*************************************************************************
  *
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- * 
+ *
  * Copyright 2000, 2010 Oracle and/or its affiliates.
  *
  * OpenOffice.org - a multi-platform office productivity suite
@@ -327,7 +327,7 @@ void lcl_AdjustJumpMatrix( ScJumpMatrix* pJumpM, ScMatrixRef& pResMat, SCSIZE nP
     SCSIZE nAdjustCols, nAdjustRows;
     pJumpM->GetDimensions( nJumpCols, nJumpRows );
     pJumpM->GetResMatDimensions( nResCols, nResRows );
-    if (( nJumpCols == 1 && nParmCols > nResCols ) || 
+    if (( nJumpCols == 1 && nParmCols > nResCols ) ||
         ( nJumpRows == 1 && nParmRows > nResRows ))
     {
         if ( nJumpCols == 1 && nJumpRows == 1 )
@@ -636,8 +636,8 @@ ScCompareOptions::ScCompareOptions( ScDocument* pDoc, const ScQueryEntry& rEntry
     bIgnoreCase(true)
 {
     bRegEx = (bRegEx && (aQueryEntry.eOp == SC_EQUAL || aQueryEntry.eOp == SC_NOT_EQUAL));
-    // Interpreter functions usually are case insensitive, except the simple 
-    // comparison operators, for which these options aren't used. Override in 
+    // Interpreter functions usually are case insensitive, except the simple
+    // comparison operators, for which these options aren't used. Override in
     // struct if needed.
 }
 
@@ -717,8 +717,8 @@ double ScInterpreter::CompareFunc( const ScCompare& rComp, ScCompareOptions* pOp
         // Both strings.
         if (pOptions)
         {
-            // All similar to Sctable::ValidQuery(), *rComp.pVal[1] actually 
-            // is/must be identical to *rEntry.pStr, which is essential for 
+            // All similar to Sctable::ValidQuery(), *rComp.pVal[1] actually
+            // is/must be identical to *rEntry.pStr, which is essential for
             // regex to work through GetSearchTextPtr().
             ScQueryEntry& rEntry = pOptions->aQueryEntry;
             DBG_ASSERT( *rComp.pVal[1] == *rEntry.pStr, "ScInterpreter::CompareFunc: broken options");
@@ -726,8 +726,8 @@ double ScInterpreter::CompareFunc( const ScCompare& rComp, ScCompareOptions* pOp
             {
                 xub_StrLen nStart = 0;
                 xub_StrLen nStop  = rComp.pVal[0]->Len();
-                bool bMatch = rEntry.GetSearchTextPtr( 
-                        !pOptions->bIgnoreCase)->SearchFrwrd( *rComp.pVal[0], 
+                bool bMatch = rEntry.GetSearchTextPtr(
+                        !pOptions->bIgnoreCase)->SearchFrwrd( *rComp.pVal[0],
                             &nStart, &nStop);
                 if (bMatch && pOptions->bMatchWholeCell && (nStart != 0 || nStop != rComp.pVal[0]->Len()))
                     bMatch = false;     // RegEx must match entire string.
@@ -735,19 +735,19 @@ double ScInterpreter::CompareFunc( const ScCompare& rComp, ScCompareOptions* pOp
             }
             else if (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL)
             {
-                ::utl::TransliterationWrapper* pTransliteration = 
-                    (pOptions->bIgnoreCase ? ScGlobal::GetpTransliteration() : 
+                ::utl::TransliterationWrapper* pTransliteration =
+                    (pOptions->bIgnoreCase ? ScGlobal::GetpTransliteration() :
                      ScGlobal::GetCaseTransliteration());
                 bool bMatch;
                 if (pOptions->bMatchWholeCell)
                     bMatch = pTransliteration->isEqual( *rComp.pVal[0], *rComp.pVal[1]);
                 else
                 {
-                    String aCell( pTransliteration->transliterate( 
-                                *rComp.pVal[0], ScGlobal::eLnge, 0, 
+                    String aCell( pTransliteration->transliterate(
+                                *rComp.pVal[0], ScGlobal::eLnge, 0,
                                 rComp.pVal[0]->Len(), NULL));
-                    String aQuer( pTransliteration->transliterate( 
-                                *rComp.pVal[1], ScGlobal::eLnge, 0, 
+                    String aQuer( pTransliteration->transliterate(
+                                *rComp.pVal[1], ScGlobal::eLnge, 0,
                                 rComp.pVal[1]->Len(), NULL));
                     bMatch = (aCell.Search( aQuer ) != STRING_NOTFOUND);
                 }
@@ -1925,7 +1925,7 @@ void ScInterpreter::ScCell()
             else if( aInfoType.EqualsAscii( "COORD" ) )
             {   // address, lotus 1-2-3 formatted: $TABLE:$COL$ROW
                 // Yes, passing tab as col is intentional!
-                ScAddress( static_cast<SCCOL>(aCellPos.Tab()), 0, 0 ).Format( 
+                ScAddress( static_cast<SCCOL>(aCellPos.Tab()), 0, 0 ).Format(
                     aFuncResult, (SCA_COL_ABSOLUTE|SCA_VALID_COL), NULL, pDok->GetAddressConvention() );
                 aFuncResult += ':';
                 String aCellStr;
@@ -2480,7 +2480,7 @@ void ScInterpreter::ScN()
     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScN" );
     USHORT nErr = nGlobalError;
     nGlobalError = 0;
-    // Temporarily override the ConvertStringToValue() error for 
+    // Temporarily override the ConvertStringToValue() error for
     // GetCellValue() / GetCellValueOrZero()
     USHORT nSErr = mnStringNoValueError;
     mnStringNoValueError = errCellNoValue;
@@ -2774,7 +2774,7 @@ static ::rtl::OUString lcl_convertIntoFullWidth( const ::rtl::OUString & rStr )
     {
         aTrans.loadModuleByImplName( ::rtl::OUString::createFromAscii( "HALFWIDTH_FULLWIDTH_LIKE_JIS" ), LANGUAGE_SYSTEM );
         bFirstJISCall = false;
-    }    
+    }
 
     return aTrans.transliterate( rStr, 0, USHORT( rStr.getLength() ), NULL );
 }
@@ -2833,7 +2833,7 @@ void ScInterpreter::ScUnichar()
     if ( MustHaveParamCount( GetByte(), 1 ) )
     {
         double dVal = ::rtl::math::approxFloor( GetDouble() );
-        if ((dVal < 0x000000) || (dVal > 0x10FFFF)) 
+        if ((dVal < 0x000000) || (dVal > 0x10FFFF))
             PushIllegalArgument();
         else
         {
@@ -3094,6 +3094,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 )
 {
@@ -3175,6 +3228,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 );
@@ -3217,7 +3335,7 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, BOOL bTextAsZero )
                             case ifPRODUCT: fRes *= fVal; break;
                             case ifCOUNT:
                                 if ( nGlobalError )
-                                {    
+                                {
                                     nGlobalError = 0;
                                     nCount--;
                                 }
@@ -3321,53 +3439,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:
@@ -4082,29 +4167,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;
@@ -4162,6 +4257,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(
@@ -4537,7 +4658,7 @@ void ScInterpreter::ScCountIf()
                     SCSIZE nSize = pResultMatrix->GetElementCount();
                     for (SCSIZE nIndex = 0; nIndex < nSize; ++nIndex)
                     {
-                        if (pResultMatrix->IsValue( nIndex) && 
+                        if (pResultMatrix->IsValue( nIndex) &&
                                 pResultMatrix->GetDouble( nIndex))
                             ++fSum;
                     }
@@ -4827,7 +4948,7 @@ void ScInterpreter::ScSumIf()
                         {
                             for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
                             {
-                                if (pResultMatrix->IsValue( nCol, nRow) && 
+                                if (pResultMatrix->IsValue( nCol, nRow) &&
                                         pResultMatrix->GetDouble( nCol, nRow))
                                 {
                                     SCSIZE nC = nCol + nColDiff;
@@ -4962,9 +5083,9 @@ void ScInterpreter::ScLookup()
             case svDoubleRef:
             {
                 SCTAB nTabJunk;
-                PopDoubleRef(nResCol1, nResRow1, nResTab, 
+                PopDoubleRef(nResCol1, nResRow1, nResTab,
                              nResCol2, nResRow2, nTabJunk);
-                if (nResTab != nTabJunk || 
+                if (nResTab != nTabJunk ||
                     ((nResRow2 - nResRow1) > 0 && (nResCol2 - nResCol1) > 0))
                 {
                     // The result array must be a vector.
@@ -5098,7 +5219,7 @@ void ScInterpreter::ScLookup()
     {
         // Delta position for a single value is always 0.
 
-        // Found if data <= query, but not if query is string and found data is 
+        // Found if data <= query, but not if query is string and found data is
         // numeric or vice versa. This is how Excel does it but doesn't
         // document it.
 
@@ -5257,7 +5378,7 @@ void ScInterpreter::ScLookup()
         }
 
         // With 0-9 < A-Z, if query is numeric and data found is string, or
-        // vice versa, the (yet another undocumented) Excel behavior is to 
+        // vice versa, the (yet another undocumented) Excel behavior is to
         // return #N/A instead.
 
         if (bFound)
@@ -5839,7 +5960,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;
 
@@ -5897,7 +6018,7 @@ ScDBQueryParamBase* ScInterpreter::GetDBParams( BOOL& rMissingField )
                 SetError( errIllegalParameter );
         }
 
-        auto_ptr<ScDBRangeBase> pDBRef( PopDoubleRef() );
+        auto_ptr<ScDBRangeBase> pDBRef( PopDBDoubleRef() );
 
         if (nGlobalError || !pDBRef.get())
             return NULL;
@@ -5910,7 +6031,7 @@ ScDBQueryParamBase* ScInterpreter::GetDBParams( BOOL& rMissingField )
             else
                 SetError( errIllegalParameter );
         }
-        
+
         if (nGlobalError)
             return NULL;
 
@@ -5921,7 +6042,7 @@ ScDBQueryParamBase* ScInterpreter::GetDBParams( BOOL& rMissingField )
             nField = pDBRef->findFieldColumn(static_cast<SCCOL>(nVal));
         else
         {
-            sal_uInt16 nErr = 0;    
+            sal_uInt16 nErr = 0;
             nField = pDBRef->findFieldColumn(aStr, &nErr);
             SetError(nErr);
         }
@@ -6072,7 +6193,7 @@ void ScInterpreter::ScDBCount()
                 do
                 {
                     nCount++;
-                } 
+                }
                 while ( aValIter.GetNext(aValue) && !aValue.mnError );
             }
             SetError(aValue.mnError);
@@ -6100,7 +6221,7 @@ void ScInterpreter::ScDBCount2()
             do
             {
                 nCount++;
-            } 
+            }
             while ( aValIter.GetNext(aValue) && !aValue.mnError );
         }
         SetError(aValue.mnError);
@@ -6170,7 +6291,7 @@ void ScInterpreter::GetDBStVarParams( double& rVal, double& rValCount )
         SetError( errIllegalParameter);
 
     vMean = fSum / values.size();
-    
+
     for (size_t i = 0; i < values.size(); i++)
         vSum += (values[i] - vMean) * (values[i] - vMean);
 
@@ -6214,8 +6335,8 @@ void ScInterpreter::ScDBVarP()
 }
 
 
-ScTokenArray* lcl_CreateExternalRefTokenArray( const ScAddress& rPos, ScDocument* pDoc, 
-        const ScAddress::ExternalInfo& rExtInfo, const ScRefAddress& rRefAd1, 
+ScTokenArray* lcl_CreateExternalRefTokenArray( const ScAddress& rPos, ScDocument* pDoc,
+        const ScAddress::ExternalInfo& rExtInfo, const ScRefAddress& rRefAd1,
         const ScRefAddress* pRefAd2 )
 {
     ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
@@ -6249,10 +6370,10 @@ ScTokenArray* lcl_CreateExternalRefTokenArray( const ScAddress& rPos, ScDocument
         pTokenArray->AddExternalSingleReference( rExtInfo.mnFileId,
                 (pRealTab ? *pRealTab : rExtInfo.maTabName), aRef);
     }
-    // The indirect usage of the external table can't be detected during the 
-    // store-to-file cycle, mark it as permanently referenced so it gets stored 
+    // The indirect usage of the external table can't be detected during the
+    // store-to-file cycle, mark it as permanently referenced so it gets stored
     // even if not directly referenced anywhere.
-    pRefMgr->setCacheTableReferencedPermanently( rExtInfo.mnFileId, 
+    pRefMgr->setCacheTableReferencedPermanently( rExtInfo.mnFileId,
             rExtInfo.maTabName, nSheets);
     ScCompiler aComp( pDoc, rPos, *pTokenArray);
     aComp.CompileTokenArray();
@@ -6285,15 +6406,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(),
@@ -6305,15 +6421,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() );
@@ -6327,7 +6436,7 @@ void ScInterpreter::ScIndirect()
                     break;
 
                 USHORT nPos = 0;
-                if (!pNames->SearchName( sRefStr, nPos)) 
+                if (!pNames->SearchName( sRefStr, nPos))
                     break;
 
                 ScRangeData* rData = (*pNames)[nPos];
@@ -6341,12 +6450,12 @@ void ScInterpreter::ScIndirect()
 #if 0
                 // This is some really odd Excel behavior and renders named
                 // ranges containing relative references totally useless.
-                if (!rData->IsReference(aRange, ScAddress( aPos.Tab(), 0, 0))) 
+                if (!rData->IsReference(aRange, ScAddress( aPos.Tab(), 0, 0)))
                     break;
 #else
                 // This is the usual way to treat named ranges containing
                 // relative references.
-                if (!rData->IsReference( aRange, aPos)) 
+                if (!rData->IsReference( aRange, aPos))
                     break;
 #endif
 
@@ -6497,6 +6606,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);
@@ -6514,6 +6661,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();
     }
@@ -7104,7 +7278,7 @@ void ScInterpreter::ScText()
                     if (!nGlobalError)
                     {
                         PushTempToken( xTok);
-                        // Temporarily override the ConvertStringToValue() 
+                        // Temporarily override the ConvertStringToValue()
                         // error for GetCellValue() / GetCellValueOrZero()
                         USHORT nSErr = mnStringNoValueError;
                         mnStringNoValueError = errNotNumericString;
@@ -7137,7 +7311,7 @@ void ScInterpreter::ScText()
                 eCellLang = ScGlobal::eLnge;
             if (bString)
             {
-                if (!pFormatter->GetPreviewString( sFormatString, aStr, 
+                if (!pFormatter->GetPreviewString( sFormatString, aStr,
                             aResult, &pColor, eCellLang))
                     PushIllegalArgument();
                 else
@@ -7145,7 +7319,7 @@ void ScInterpreter::ScText()
             }
             else
             {
-                if (!pFormatter->GetPreviewStringGuess( sFormatString, fVal, 
+                if (!pFormatter->GetPreviewStringGuess( sFormatString, fVal,
                             aResult, &pColor, eCellLang))
                     PushIllegalArgument();
                 else
diff --git a/sc/source/core/tool/interpr4.cxx b/sc/source/core/tool/interpr4.cxx
index d248211..2edd18a 100644
--- a/sc/source/core/tool/interpr4.cxx
+++ b/sc/source/core/tool/interpr4.cxx
@@ -1,7 +1,7 @@
 /*************************************************************************
  *
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- * 
+ *
  * Copyright 2000, 2010 Oracle and/or its affiliates.
  *
  * OpenOffice.org - a multi-platform office productivity suite
@@ -198,11 +198,11 @@ double ScInterpreter::GetValueCellValue( const ScAddress& rPos, const ScValueCel
 
 
 /** Convert string content to numeric value.
-    
-    Converted are only integer numbers including exponent, and ISO 8601 dates 
-    and times in their extended formats with separators. Anything else, 
-    especially fractional numeric values with decimal separators or dates other 
-    than ISO 8601 would be locale dependent and is a no-no. Leading and 
+
+    Converted are only integer numbers including exponent, and ISO 8601 dates
+    and times in their extended formats with separators. Anything else,
+    especially fractional numeric values with decimal separators or dates other
+    than ISO 8601 would be locale dependent and is a no-no. Leading and
     trailing blanks are ignored.
 
     The following ISO 8601 formats are converted:
@@ -217,13 +217,13 @@ double ScInterpreter::GetValueCellValue( const ScAddress& rPos, const ScValueCel
     hh:mm:ss,s
     hh:mm:ss.s
 
-    The century CC may not be omitted and the two-digit year setting is not 
-    taken into account. Instead of the T date and time separator exactly one 
+    The century CC may not be omitted and the two-digit year setting is not
+    taken into account. Instead of the T date and time separator exactly one
     blank may be used.
 
-    If a date is given, it must be a valid Gregorian calendar date. In this 
+    If a date is given, it must be a valid Gregorian calendar date. In this
     case the optional time must be in the range 00:00 to 23:59:59.99999...
-    If only time is given, it may have any value for hours, taking elapsed time 
+    If only time is given, it may have any value for hours, taking elapsed time
     into account; minutes and seconds are limited to the value 59 as well.
  */
 
@@ -240,13 +240,13 @@ double ScInterpreter::ConvertStringToValue( const String& rStr )
     ::rtl::OUString aStr( rStr);
     rtl_math_ConversionStatus eStatus;
     sal_Int32 nParseEnd;
-    // Decimal and group separator 0 => only integer and possibly exponent, 
+    // Decimal and group separator 0 => only integer and possibly exponent,
     // stops at first non-digit non-sign.
     fValue = ::rtl::math::stringToDouble( aStr, 0, 0, &eStatus, &nParseEnd);
     sal_Int32 nLen;
     if (eStatus == rtl_math_ConversionStatus_Ok && nParseEnd < (nLen = aStr.getLength()))
     {
-        // Not at string end, check for trailing blanks or switch to date or 
+        // Not at string end, check for trailing blanks or switch to date or
         // time parsing or bail out.
         const sal_Unicode* const pStart = aStr.getStr();
         const sal_Unicode* p = pStart + nParseEnd;
@@ -270,8 +270,8 @@ double ScInterpreter::ConvertStringToValue( const String& rStr )
                     nCurFmtType = (bDate ? NUMBERFORMAT_DATE : NUMBERFORMAT_TIME);
                     nUnit[eState-1] = aStr.copy( 0, nParseEnd).toInt32();
                     const sal_Unicode* pLastStart = p;
-                    // Ensure there's no preceding sign. Negative dates 
-                    // currently aren't handled correctly. Also discard 
+                    // Ensure there's no preceding sign. Negative dates
+                    // currently aren't handled correctly. Also discard
                     // +CCYY-MM-DD
                     p = pStart;
                     while (p < pStop && *p == ' ')
@@ -299,12 +299,12 @@ double ScInterpreter::ConvertStringToValue( const String& rStr )
                                     SetError( mnStringNoValueError);
                             }
                             pLastStart = p + 1;     // hypothetical next start
-                            // Delimiters must match, a trailing delimiter 
+                            // Delimiters must match, a trailing delimiter
                             // yields an invalid date/time.
                             switch (eState)
                             {
                                 case month:
-                                    // Month must be followed by separator and 
+                                    // Month must be followed by separator and
                                     // day, no trailing blanks.
                                     if (*p != '-' || (p+1 == pStop))
                                         SetError( mnStringNoValueError);
@@ -312,11 +312,11 @@ double ScInterpreter::ConvertStringToValue( const String& rStr )
                                 case day:
                                     if ((*p != 'T' || (p+1 == pStop)) && *p != ' ')
                                         SetError( mnStringNoValueError);
-                                    // Take one blank as a valid delimiter 
+                                    // Take one blank as a valid delimiter
                                     // between date and time.
                                     break;
                                 case hour:
-                                    // Hour must be followed by separator and 
+                                    // Hour must be followed by separator and
                                     // minute, no trailing blanks.
                                     if (*p != ':' || (p+1 == pStop))
                                         SetError( mnStringNoValueError);
@@ -378,13 +378,13 @@ double ScInterpreter::ConvertStringToValue( const String& rStr )
                         {
                             if (bDate && nUnit[day] == 0)
                                 nUnit[day] = 1;
-                            double fFraction = (nUnit[fraction] <= 0 ? 0.0 : 
+                            double fFraction = (nUnit[fraction] <= 0 ? 0.0 :
                                     ::rtl::math::pow10Exp( nUnit[fraction],
                                         static_cast<int>( -ceil( log10( static_cast<double>( nUnit[fraction]))))));
-                            fValue = (bDate ? GetDateSerial( 
-                                        sal::static_int_cast<INT16>(nUnit[year]), 
-                                        sal::static_int_cast<INT16>(nUnit[month]), 
-                                        sal::static_int_cast<INT16>(nUnit[day]), 
+                            fValue = (bDate ? GetDateSerial(
+                                        sal::static_int_cast<INT16>(nUnit[year]),
+                                        sal::static_int_cast<INT16>(nUnit[month]),
+                                        sal::static_int_cast<INT16>(nUnit[day]),
                                         true) : 0.0);
                             fValue += ((nUnit[hour] * 3600) + (nUnit[minute] * 60) + nUnit[second] + fFraction) / 86400.0;
                         }
@@ -460,7 +460,7 @@ double ScInterpreter::GetCellValueOrZero( const ScAddress& rPos, const ScBaseCel
             case  CELLTYPE_STRING:
             case  CELLTYPE_EDIT:
             {
-                // SUM(A1:A2) differs from A1+A2. No good. But people insist on 
+                // SUM(A1:A2) differs from A1+A2. No good. But people insist on
                 // it ... #i5658#
                 String aStr;
                 if ( eType == CELLTYPE_STRING )
@@ -1233,40 +1233,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));
         }
         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);
         }
         default:
             SetError( errIllegalParameter);
     }
+
     return NULL;
 }
 
@@ -1386,6 +1388,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 )
 {
@@ -1668,6 +1835,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" );
@@ -1870,6 +2071,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()
 {
@@ -1905,26 +2123,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:
@@ -2013,30 +2233,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:
@@ -2046,7 +2259,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 )
@@ -3185,82 +3421,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 ------------------------------------------------------------
 
 
@@ -3332,6 +3492,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;
@@ -3415,7 +3576,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;
@@ -3726,8 +3886,8 @@ StackVar ScInterpreter::Interpret()
                 default : PushError( errUnknownOpCode);                 break;
             }
 
-            // If the function signalled that it pushed a subroutine on the 
-            // instruction code stack instead of a result, continue with  
+            // If the function signalled that it pushed a subroutine on the
+            // instruction code stack instead of a result, continue with
             // execution of the subroutine.
             if (sp > nStackBase && pStack[sp-1]->GetOpCode() == ocCall)
             {
@@ -3884,9 +4044,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;
@@ -3931,6 +4097,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);
             }
@@ -3972,7 +4155,7 @@ StackVar ScInterpreter::Interpret()
 
     StackVar eType = xResult->GetType();
     if (eType == svMatrix)
-        // Results are immutable in case they would be reused as input for new 
+        // Results are immutable in case they would be reused as input for new
         // interpreters.
         static_cast<ScToken*>(xResult.operator->())->GetMatrix()->SetImmutable( true);
     return eType;
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index 1547012..e4a51bf 100644
--- a/sc/source/core/tool/token.cxx
+++ b/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;
 
@@ -319,37 +319,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 ];
@@ -813,7 +802,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)
@@ -879,7 +868,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)
@@ -965,7 +954,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 a/sc/source/filter/excel/xeformula.cxx b/sc/source/filter/excel/xeformula.cxx
index 17124e8..3fa343a 100644
--- a/sc/source/filter/excel/xeformula.cxx
+++ b/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 a/sc/source/filter/excel/xelink.cxx b/sc/source/filter/excel/xelink.cxx
index f8bc434..27b46e2 100644
--- a/sc/source/filter/excel/xelink.cxx
+++ b/sc/source/filter/excel/xelink.cxx
@@ -962,7 +962,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 a/sc/source/ui/docshell/externalrefmgr.cxx b/sc/source/ui/docshell/externalrefmgr.cxx
index 269c3d5..68f0b27 100644
--- a/sc/source/ui/docshell/externalrefmgr.cxx
+++ b/sc/source/ui/docshell/externalrefmgr.cxx
@@ -1,7 +1,7 @@
 /*************************************************************************
  *
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- * 
+ *
  * Copyright 2000, 2010 Oracle and/or its affiliates.
  *
  * OpenOffice.org - a multi-platform office productivity suite
@@ -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();
@@ -179,7 +179,7 @@ public:
     {
         ScAddress aPos = pCell->aPos;
 
-        // We don't check for empty cells because empty external cells are 
+        // We don't check for empty cells because empty external cells are
         // treated as having a value of 0.
 
         if (pCell->IsValue())
@@ -587,7 +587,7 @@ ScExternalRefCache::TokenArrayRef ScExternalRefCache::getCellRangeData(
             static_cast<SCSIZE>(nDataCol2-nDataCol1+1), static_cast<SCSIZE>(nDataRow2-nDataRow1+1));
 
 #if 0
-        // TODO: Switch to this code block once we have support for sparsely-filled 
+        // TODO: Switch to this code block once we have support for sparsely-filled
         // matrices in ScMatrix.
 
         // Only fill non-empty cells, for better performance.
@@ -1362,7 +1362,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;
@@ -1613,7 +1613,7 @@ bool ScExternalRefManager::markUsedExternalRefCells()
         RefCellSet::iterator itrCell = itr->second.begin(), itrCellEnd = itr->second.end();
         for (; itrCell != itrCellEnd; ++itrCell)
         {
-            ScFormulaCell* pCell = *itrCell;    
+            ScFormulaCell* pCell = *itrCell;
             bool bUsed = pCell->MarkUsedExternalReferences();
             if (bUsed)
                 // Return true when at least one cell references external docs.
@@ -1665,6 +1665,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(
@@ -1672,21 +1693,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.
@@ -1694,7 +1706,6 @@ ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefToken(
         return pToken;
     }
 
-    ScBaseCell* pCell = NULL;
     SCTAB nTab;
     if (!pSrcDoc->GetTable(rTabName, nTab))
     {
@@ -1714,7 +1725,7 @@ ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefToken(
         // requested cell is outside the data area.  Don't even bother caching
         // this data, but add it to the cached range to prevent accessing the
         // source document time and time again.
-        ScExternalRefCache::TableTypeRef pCacheTab = 
+        ScExternalRefCache::TableTypeRef pCacheTab =
             maRefCache.getCacheTable(nFileId, rTabName, true, NULL);
         if (pCacheTab)
             pCacheTab->setCachedCell(rCell.Col(), rCell.Row());
@@ -1723,33 +1734,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(
@@ -1760,14 +1752,23 @@ 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 = 
+    ScExternalRefCache::TokenArrayRef pArray =
         maRefCache.getCellRangeData(nFileId, rTabName, rRange);
     if (pArray)
         // Cache hit !
         return pArray;
 
-    ScDocument* pSrcDoc = getSrcDocument(nFileId);
+    pSrcDoc = getSrcDocument(nFileId);
     if (!pSrcDoc)
     {
         // Source document is not reachable.  Throw a reference error.
@@ -1776,7 +1777,150 @@ ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokens(
         return pArray;
     }
 
+    vector<ScExternalRefCache::SingleRangeData> aCacheData;
+    pArray = getDoubleRefTokensFromSrcDoc(pSrcDoc, rTabName, aRange, aCacheData);
+
+    if (pArray)
+        // Cache these values.
+        maRefCache.setCellRangeData(nFileId, aRange, aCacheData, pArray);
+    else
+    {
+        // Array is empty.  Fill it with an empty matrix of the required size.
+        pArray.reset(lcl_fillEmptyMatrix(rRange));
+
+        // Make sure to set this range 'cached', to prevent unnecessarily
+        // accessing the src document time and time again.
+        ScExternalRefCache::TableTypeRef pCacheTab =
+            maRefCache.getCacheTable(nFileId, rTabName, true, NULL);
+        if (pCacheTab)
+            pCacheTab->setCachedCellRange(
+                rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
+    }
+
+    return pArray;
+}
+
+ScExternalRefCache::TokenArrayRef ScExternalRefManager::getRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScAddress* pCurPos)
+{
+    if (pCurPos)
+        insertRefCell(nFileId, *pCurPos);
+
+    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;
+
+    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.
@@ -1808,42 +1952,14 @@ ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokens(
     aRange.aEnd.SetTab(nTab1 + nTabSpan);
 
     pArray.reset(lcl_convertToTokenArray(pSrcDoc, aRange, aCacheData));
-
-    if (pArray)
-        // Cache these values.
-        maRefCache.setCellRangeData(nFileId, aRange, aCacheData, pArray);
-    else
-    {    
-        // Array is empty.  Fill it with an empty matrix of the required size.
-        pArray.reset(lcl_fillEmptyMatrix(rRange));
-
-        // Make sure to set this range 'cached', to prevent unnecessarily 
-        // accessing the src document time and time again.
-        ScExternalRefCache::TableTypeRef pCacheTab = 
-            maRefCache.getCacheTable(nFileId, rTabName, true, NULL);
-        if (pCacheTab)
-            pCacheTab->setCachedCellRange(
-                rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
-    }
-
+    rRange = aRange;
+    rCacheData.swap(aCacheData);
     return pArray;
 }
 
-ScExternalRefCache::TokenArrayRef ScExternalRefManager::getRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScAddress* pCurPos)
+ScExternalRefCache::TokenArrayRef ScExternalRefManager::getRangeNameTokensFromSrcDoc(
+    sal_uInt16 nFileId, const ScDocument* pSrcDoc, String& rName)
 {
-    if (pCurPos)
-        insertRefCell(nFileId, *pCurPos);
-
-    maybeLinkExternalFile(nFileId);
-
-    ScExternalRefCache::TokenArrayRef pArray = maRefCache.getRangeNameTokens(nFileId, rName);
-    if (pArray.get())
-        return pArray;
-
-    ScDocument* pSrcDoc = getSrcDocument(nFileId);
-    if (!pSrcDoc)
-        return ScExternalRefCache::TokenArrayRef();
-
     ScRangeName* pExtNames = pSrcDoc->GetRangeName();
     String aUpperName = ScGlobal::pCharClass->upper(rName);
     USHORT n;
@@ -1896,55 +2012,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;
@@ -2418,7 +2516,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