ooo-build r13258 - in trunk: . patches/test



Author: kyoshida
Date: Thu Jul 17 00:28:28 2008
New Revision: 13258
URL: http://svn.gnome.org/viewvc/ooo-build?rev=13258&view=rev

Log:
2008-07-16  Kohei Yoshida  <kyoshida novell com>

	* patches/test/calc-external-defined-names.diff: more progress - support
	for true external single & double ref tokens & Excel export filter.


Modified:
   trunk/ChangeLog
   trunk/patches/test/calc-external-defined-names.diff

Modified: trunk/patches/test/calc-external-defined-names.diff
==============================================================================
--- trunk/patches/test/calc-external-defined-names.diff	(original)
+++ trunk/patches/test/calc-external-defined-names.diff	Thu Jul 17 00:28:28 2008
@@ -135,10 +135,10 @@
          @return  TRUE = Sheet created, rnTab contains valid sheet index. */
 diff --git sc/inc/externalrefmgr.hxx sc/inc/externalrefmgr.hxx
 new file mode 100644
-index 0000000..303d90b
+index 0000000..2af580a
 --- /dev/null
 +++ sc/inc/externalrefmgr.hxx
-@@ -0,0 +1,210 @@
+@@ -0,0 +1,217 @@
 +/*************************************************************************
 + *
 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -248,11 +248,11 @@
 +    typedef ::boost::shared_ptr<ScToken>        TokenRef;
 +    typedef ::boost::shared_ptr<ScTokenArray>   TokenArrayRef;
 +
-+    typedef ::std::hash_map<sal_uInt16, SrcDoc >             DocShellMap;
-+    typedef ::std::hash_map<ScAddress, TokenRef, AddressHash, ::std::equal_to<ScAddress> >          SingleTokenMap;
-+    typedef ::std::hash_map<ScRange, TokenArrayRef, RangeHash, ::std::equal_to<ScRange> >           DoubleTokenMap;
-+    typedef ::std::hash_map<String, TokenArrayRef, ScStringHashCode, ::std::equal_to<String> >      RangeNameMap;
-+    typedef ::std::hash_set<sal_uInt16, ScStringHashCode, ::std::equal_to<String> >                 LinkedDocSet;
++    typedef ::std::hash_map<sal_uInt16, SrcDoc>                                                 DocShellMap;
++    typedef ::std::hash_map<ScAddress, TokenRef, AddressHash, ::std::equal_to<ScAddress> >      SingleTokenMap;
++    typedef ::std::hash_map<ScRange, TokenArrayRef, RangeHash, ::std::equal_to<ScRange> >       DoubleTokenMap;
++    typedef ::std::hash_map<String, TokenArrayRef, ScStringHashCode, ::std::equal_to<String> >  RangeNameMap;
++    typedef ::std::hash_set<sal_uInt16, ScStringHashCode>                                       LinkedDocSet;
 +
 +    typedef ::std::hash_set<ScAddress, AddressHash, ::std::equal_to<ScAddress> >    RefCellSet;
 +    typedef ::std::hash_map<sal_uInt16, RefCellSet>                                 RefCellMap;
@@ -265,6 +265,7 @@
 +        SingleTokenMap  maSingleTokens;
 +        DoubleTokenMap  maDoubleTokens;
 +        RangeNameMap    maRangeNames;
++        ::std::vector<String> maTableNames;
 +    };
 +    typedef ::boost::shared_ptr<DocCache> DocCacheRef;
 +    typedef ::std::hash_map<sal_uInt16, DocCacheRef>   DocCacheMap;
@@ -273,19 +274,25 @@
 +    explicit ScExternalRefManager(ScDocument* pDoc);
 +    ~ScExternalRefManager();
 +
-+    ScToken* getSingleRefToken(sal_uInt16 nFileId, const ScAddress& rCell, const ScAddress& rCurPos);
-+    ScTokenArray* getDoubleRefTokens(sal_uInt16 nFileId, const ScRange& rRange, const ScAddress& rCurPos);
++    ScToken* getSingleRefToken(sal_uInt16 nFileId, const ScAddress& rCell, const ScAddress* pCurPos);
++    ScTokenArray* getDoubleRefTokens(sal_uInt16 nFileId, const ScRange& rRange, const ScAddress* pCurPos);
 +
 +    /** 
 +     * Get an array of tokens corresponding with a specified name in a 
 +     * specified file. 
++     *  
++     * @param pCurPos currnet cell address where this name token is used. 
++     *                This is purely to keep track of all cells containing
++     *                external names for refreshing purposes.  If this is
++     *                NULL, then the cell will not be added to the list.
 +     * 
-+     * @return ScTokenArray instance
++     * @return array of tokens composing the name
 +     */
-+    ScTokenArray* getRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScAddress& rCurPos);
++    ScTokenArray* getRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScAddress* pCurPos = NULL);
 +
 +    sal_uInt16 getExternalFileId(const String& rFile);
-+    const String* getExternalFileName(sal_uInt16 nIndex) const;
++    const String* getExternalFileName(sal_uInt16 nFileId) const;
++    const String* getExternalTableName(sal_uInt16 nFileId, SCTAB nTabId);
 +    
 +    void refreshNames(sal_uInt16 nFileId);
 +    void switchSrcFile(sal_uInt16 nFileId, const String& rNewFile);
@@ -362,7 +369,7 @@
  		ocIf				= SC_OPCODE_IF,
  		ocChose				= SC_OPCODE_CHOSE,
 diff --git sc/inc/token.hxx sc/inc/token.hxx
-index 23decd6..01e67ca 100644
+index 23decd6..1181360 100644
 --- sc/inc/token.hxx
 +++ sc/inc/token.hxx
 @@ -64,7 +64,7 @@ enum StackVarEnum
@@ -374,15 +381,55 @@
      svError,                            // error token
      svMissing = 0x70,                   // 0 or ""
      svUnknown                           // unknown StackType
-@@ -447,6 +447,21 @@ public:
+@@ -447,6 +447,61 @@ public:
  };
  
  
++class ScExternalSingleRefToken : public ScOpToken
++{
++private:
++    sal_uInt16                  mnFileId;
++    SingleRefData               maSingleRef;
++
++                                ScExternalSingleRefToken(); // disabled
++public:
++                                ScExternalSingleRefToken( sal_uInt16 nFileId, const SingleRefData& r );
++                                ScExternalSingleRefToken( const ScExternalSingleRefToken& r );
++    virtual                     ~ScExternalSingleRefToken();
++
++    virtual USHORT                  GetIndex() const;
++    virtual const SingleRefData&    GetSingleRef() const;
++    virtual SingleRefData&          GetSingleRef();
++    virtual BOOL                    operator==( const ScToken& rToken ) const;
++};
++
++
++class ScExternalDoubleRefToken : public ScOpToken
++{
++private:
++    sal_uInt16                  mnFileId;
++    ComplRefData               maDoubleRef;
++
++                                ScExternalDoubleRefToken(); // disabled
++public:
++                                ScExternalDoubleRefToken( sal_uInt16 nFileId, const ComplRefData& r );
++                                ScExternalDoubleRefToken( const ScExternalDoubleRefToken& r );
++    virtual                     ~ScExternalDoubleRefToken();
++
++    virtual USHORT                  GetIndex() const;
++    virtual const ComplRefData&    GetDoubleRef() const;
++    virtual ComplRefData&          GetDoubleRef();
++    virtual BOOL                    operator==( const ScToken& rToken ) const;
++};
++
++
 +class ScExternalNameToken : public ScOpToken
 +{
 +private:
 +    sal_uInt16                  mnFileId;
 +    String                      maName;
++private:
++                                ScExternalNameToken(); // disabled
 +public:
 +                                ScExternalNameToken( sal_uInt16 nFileId, const String& rName );
 +                                ScExternalNameToken( const ScExternalNameToken& r );
@@ -479,7 +526,7 @@
          const String& rFilterName, const String& rFilterOpt, const String& rTabName )
  {
 diff --git sc/source/core/tool/compiler.cxx sc/source/core/tool/compiler.cxx
-index 7caea76..10e0ccb 100644
+index 7caea76..c2d36c4 100644
 --- sc/source/core/tool/compiler.cxx
 +++ sc/source/core/tool/compiler.cxx
 @@ -73,9 +73,13 @@
@@ -655,30 +702,77 @@
                && !IsDBRange( aUpper )
                && !IsColRowName( aUpper )
                && !(bMayBeFuncName && IsMacro( aUpper ))
-@@ -3452,6 +3567,22 @@ BOOL ScCompiler::GetToken()
+@@ -3452,6 +3567,69 @@ BOOL ScCompiler::GetToken()
      }
      if( pToken->GetOpCode() == ocSubTotal )
          glSubTotal = TRUE;
 +    else if ( pToken->GetOpCode() == ocExternalName )
 +    {
++        // Handle external single and double references, or names.
++
 +        ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
 +        const String* pFile = pRefMgr->getExternalFileName(pToken->GetIndex());
 +        if (!pFile)
 +            SetError(errNoName);
 +
-+        const String& rName = pToken->GetString();
-+        ScTokenArray* pNew = pRefMgr->getRangeNameTokens(pToken->GetIndex(), rName, aPos);
-+        if (pNew)
++        switch (pToken->GetType())
 +        {
-+            PushTokenArray(pNew->Clone(), true);
-+            return GetToken();
++            case svExternalName:
++            {
++                fprintf(stdout, "ScCompiler::GetToken:   external name token\n");
++                const String& rName = pToken->GetString();
++                ScTokenArray* pNew = pRefMgr->getRangeNameTokens(pToken->GetIndex(), rName, &aPos);
++                if (pNew)
++                {
++                    PushTokenArray(pNew->Clone(), true);
++                    return GetToken();
++                }
++            }
++            break;
++            case svSingleRef:
++            {
++                fprintf(stdout, "ScCompiler::GetToken:   external single ref (file id = %d)\n", pToken->GetIndex());
++                SingleRefData aData(pToken->GetSingleRef());
++                if (aData.IsTabRel())
++                    // external single reference must have an absolute table reference!
++                    break;
++
++                aData.CalcAbsIfRel(aPos);
++                ScAddress aAddr(aData.nCol, aData.nRow, aData.nTab);
++                ScToken* pNew = pRefMgr->getSingleRefToken(pToken->GetIndex(), aAddr, &aPos);
++                if (pNew)
++                {
++                    pToken = pNew->Clone();
++                    return false;
++                }
++            }
++            break;
++            case svDoubleRef:
++            {
++                fprintf(stdout, "ScCompiler::GetToken:   external double ref (file id = %d)\n", pToken->GetIndex());
++                ComplRefData aData(pToken->GetDoubleRef());
++                if (aData.Ref1.IsTabRel() || aData.Ref2.IsTabRel())
++                    // 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);
++                ScTokenArray* pNew = pRefMgr->getDoubleRefTokens(pToken->GetIndex(), aRange, &aPos);
++                if (pNew)
++                {
++                    PushTokenArray(pNew->Clone(), true);
++                    return GetToken();
++                }
++            }
++            break;
 +        }
 +        SetError(errNoName);
 +    }
      else if( pToken->GetOpCode() == ocName )
      {
          ScRangeData* pRangeData = pDoc->GetRangeName()->FindIndex( pToken->GetIndex() );
-@@ -5402,6 +5533,15 @@ ScToken* ScCompiler::CreateStringFromToken( rtl::OUStringBuffer& rBuffer, ScToke
+@@ -5402,6 +5580,15 @@ ScToken* ScCompiler::CreateStringFromToken( rtl::OUStringBuffer& rBuffer, ScToke
      BOOL bSpaces = FALSE;
      ScToken* t = pTokenP;
      OpCode eOp = t->GetOpCode();
@@ -695,7 +789,7 @@
      {
          // AND, OR infix?
 diff --git sc/source/core/tool/token.cxx sc/source/core/tool/token.cxx
-index 7312257..8ccba56 100644
+index 7312257..5d1f006 100644
 --- sc/source/core/tool/token.cxx
 +++ sc/source/core/tool/token.cxx
 @@ -52,6 +52,8 @@
@@ -750,7 +844,43 @@
          case svJump :
              return new ScJumpToken( eOp, (short*) nJump );
          //break;
-@@ -505,6 +527,9 @@ ScToken* ScToken::Clone() const
+@@ -461,6 +483,7 @@ BOOL ScToken::IsMatrixFunction() const
+ 
+ ScToken* ScToken::Clone() const
+ {
++    OpCode nOp = GetOpCode();
+     switch ( GetType() )
+     {
+         case svByte :
+@@ -470,20 +493,24 @@ ScToken* ScToken::Clone() const
+             return new ScDoubleToken( *static_cast<const ScDoubleToken*>(this) );
+         //break;
+         case svString :
+-            if (GetOpCode() == ocPush)
++            if (nOp == ocPush)
+                 return new ScStringToken( *static_cast<const ScStringToken*>(this) );
+             else
+                 return new ScStringOpToken( *static_cast<const ScStringOpToken*>(this) );
+         //break;
+         case svSingleRef :
+-            if (GetOpCode() == ocPush)
++            if (nOp == ocPush)
+                 return new ScSingleRefToken( *static_cast<const ScSingleRefToken*>(this) );
++            else if (nOp == ocExternalName)
++                return new ScExternalSingleRefToken( *static_cast<const ScExternalSingleRefToken*>(this) );
+             else
+                 return new ScSingleRefOpToken( *static_cast<const ScSingleRefOpToken*>(this) );
+         //break;
+         case svDoubleRef :
+-            if (GetOpCode() == ocPush)
++            if (nOp == ocPush)
+                 return new ScDoubleRefToken( *static_cast<const ScDoubleRefToken*>(this) );
++            else if (nOp == ocExternalName)
++                return new ScExternalDoubleRefToken( *static_cast<const ScExternalDoubleRefToken*>(this) );
+             else
+                 return new ScDoubleRefOpToken( *static_cast<const ScDoubleRefOpToken*>(this) );
+         //break;
+@@ -505,6 +532,9 @@ ScToken* ScToken::Clone() const
          case svExternal :
              return new ScExternalToken( *static_cast<const ScExternalToken*>(this) );
          //break;
@@ -760,19 +890,113 @@
          case svFAP :
              return new ScFAPToken( *static_cast<const ScFAPToken*>(this) );
          //break;
-@@ -1016,6 +1041,56 @@ BOOL ScIndexToken::operator==( const ScToken& r ) const
+@@ -1015,6 +1045,150 @@ BOOL ScIndexToken::operator==( const ScToken& r ) const
+     return ScToken::operator==( r ) && nIndex == r.GetIndex();
  }
  
- 
++// ============================================================================
++
++ScExternalSingleRefToken::ScExternalSingleRefToken( sal_uInt16 nFileId, const SingleRefData& r ) :
++    ScOpToken(ocExternalName, svSingleRef),
++    mnFileId(nFileId),
++    maSingleRef(r)
++{
++}
++
++ScExternalSingleRefToken::ScExternalSingleRefToken( const ScExternalSingleRefToken& r ) :
++    ScOpToken(r), 
++    mnFileId(r.mnFileId),
++    maSingleRef(r.maSingleRef)
++{
++}
++
++ScExternalSingleRefToken::~ScExternalSingleRefToken()
++{
++}
++
++USHORT ScExternalSingleRefToken::GetIndex() const
++{
++    return mnFileId;
++}
++
++const SingleRefData& ScExternalSingleRefToken::GetSingleRef() const
++{
++    return maSingleRef;
++}
++
++SingleRefData& ScExternalSingleRefToken::GetSingleRef()
++{
++    return maSingleRef;
++}
++
++BOOL ScExternalSingleRefToken::operator ==( const ScToken& r ) const
++{
++    if (!ScToken::operator==(r))
++        return false;
++
++    if (mnFileId != r.GetIndex())
++        return false;
++
++    return maSingleRef == r.GetSingleRef();
++}
++
++// ============================================================================
++
++ScExternalDoubleRefToken::ScExternalDoubleRefToken( sal_uInt16 nFileId, const ComplRefData& r ) :
++    ScOpToken(ocExternalName, svDoubleRef),
++    mnFileId(nFileId),
++    maDoubleRef(r)
++{
++}
++
++ScExternalDoubleRefToken::ScExternalDoubleRefToken( const ScExternalDoubleRefToken& r ) :
++    ScOpToken(r), 
++    mnFileId(r.mnFileId),
++    maDoubleRef(r.maDoubleRef)
++{
++}
++
++ScExternalDoubleRefToken::~ScExternalDoubleRefToken()
++{
++}
++
++USHORT ScExternalDoubleRefToken::GetIndex() const
++{
++    return mnFileId;
++}
++
++const ComplRefData& ScExternalDoubleRefToken::GetDoubleRef() const
++{
++    return maDoubleRef;
++}
++
++ComplRefData& ScExternalDoubleRefToken::GetDoubleRef()
++{
++    return maDoubleRef;
++}
++
++BOOL ScExternalDoubleRefToken::operator ==( const ScToken& r ) const
++{
++    if (!ScToken::operator==(r))
++        return false;
++
++    if (mnFileId != r.GetIndex())
++        return false;
++
++    return maDoubleRef == r.GetDoubleRef();
++}
++
++// ============================================================================
++
 +ScExternalNameToken::ScExternalNameToken( sal_uInt16 nFileId, const String& rName ) :
-+    ScOpToken( ocExternalName, svExternalName ),
++    ScOpToken(ocExternalName, svExternalName),
 +    mnFileId(nFileId),
 +    maName(rName)
 +{
 +}
 +
 +ScExternalNameToken::ScExternalNameToken( const ScExternalNameToken& r ) :
-+    ScOpToken( r ),
++    ScOpToken(r),
 +    mnFileId(r.mnFileId),
 +    maName(r.maName)
 +{
@@ -813,11 +1037,11 @@
 +    return true;
 +}
 +
-+
++// ============================================================================
+ 
  short* ScJumpToken::GetJump() const                     { return pJump; }
  BOOL ScJumpToken::operator==( const ScToken& r ) const
- {
-@@ -1873,6 +1948,11 @@ ScToken* ScTokenArray::AddMatrix( ScMatrix* p )
+@@ -1873,6 +2047,11 @@ ScToken* ScTokenArray::AddMatrix( ScMatrix* p )
      return Add( new ScMatrixToken( p ) );
  }
  
@@ -933,6 +1157,790 @@
  }
  
  
+diff --git sc/source/filter/excel/xeformula.cxx sc/source/filter/excel/xeformula.cxx
+index c85aad1..ca36c38 100644
+--- sc/source/filter/excel/xeformula.cxx
++++ sc/source/filter/excel/xeformula.cxx
+@@ -42,6 +42,12 @@
+ #include "xelink.hxx"
+ #include "xename.hxx"
+ 
++#include "document.hxx"
++#include "externalrefmgr.hxx"
++
++#include <memory>
++#include <stdio.h>
++
+ // External reference log =====================================================
+ 
+ XclExpRefLogEntry::XclExpRefLogEntry() :
+@@ -300,6 +306,7 @@ private:
+     void                ProcessBoolean( const XclExpTokenData& rTokData );
+     void                ProcessDdeLink( const XclExpTokenData& rTokData, sal_uInt8 nExpClass );
+     void                ProcessExternal( const XclExpTokenData& rTokData, sal_uInt8 nExpClass );
++    void                ProcessExternalName( const XclExpTokenData& rTokData, sal_uInt8 nExpClass );
+ 
+     void                ProcessFunction( const XclExpTokenData& rTokData, sal_uInt8 nExpClass );
+     void                PrepareFunction( XclExpFuncData& rFuncData );
+@@ -1110,11 +1117,18 @@ XclExpTokenData XclExpFmlaCompImpl::RangeTerm( XclExpTokenData aTokData, sal_uIn
+ 
+ XclExpTokenData XclExpFmlaCompImpl::Factor( XclExpTokenData aTokData, sal_uInt8 nExpClass )
+ {
++    fprintf(stdout, "XclExpFmlaCompImpl::Factor: --begin\n");
+     if( !mbOk || !aTokData.Is() ) return XclExpTokenData();
+ 
+     StackVar eTokType = aTokData.GetType();
+     OpCode eOpCode = aTokData.GetOpCode();
+ 
++    if (eOpCode == ocExternalName)
++    {
++        ProcessExternalName( aTokData, nExpClass );
++        return GetNextToken();
++    }
++
+     switch( eTokType )
+     {
+         case svUnknown:     mbOk = false;                           break;
+@@ -1146,6 +1160,7 @@ XclExpTokenData XclExpFmlaCompImpl::Factor( XclExpTokenData aTokData, sal_uInt8
+         }
+     }
+ 
++    fprintf(stdout, "XclExpFmlaCompImpl::Factor: --end\n");
+     return GetNextToken();
+ }
+ 
+@@ -1249,6 +1264,72 @@ void XclExpFmlaCompImpl::ProcessExternal( const XclExpTokenData& rTokData, sal_u
+         ProcessFunction( rTokData, nExpClass );
+ }
+ 
++void XclExpFmlaCompImpl::ProcessExternalName( const XclExpTokenData& rTokData, sal_uInt8 nExpClass )
++{
++    fprintf(stdout, "XclExpFmlaCompImpl::ProcessExternalName: --begin\n");
++    StackVar eType = rTokData.GetType();
++
++    ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
++    USHORT nFileId = rTokData.mpScToken->GetIndex();
++    switch (eType)
++    {
++        case svSingleRef:
++        {
++            fprintf(stdout, "XclExpFmlaCompImpl::ProcessExternalName:   svSingleRef not supported yet\n");
++        }
++        break;
++        case svDoubleRef:
++        {
++            fprintf(stdout, "XclExpFmlaCompImpl::ProcessExternalName:   svDoubleRef not supported yet\n");
++        }
++        break;
++        case svExternalName:
++        {
++            fprintf(stdout, "XclExpFmlaCompImpl::ProcessExternalName:   svExternalName\n");
++            const String& aName = rTokData.mpScToken->GetString();
++            fprintf(stdout, "XclExpFmlaCompImpl::ProcessExternalName:   file id = %d; name = '%s'\n",
++                    nFileId, rtl::OUStringToOString(aName, RTL_TEXTENCODING_UTF8).getStr());
++
++            const String* pFile = pRefMgr->getExternalFileName(nFileId);
++            fprintf(stdout, "XclExpFmlaCompImpl::ProcessExternalName:   file name = '%s'\n",
++                    rtl::OUStringToOString(*pFile, RTL_TEXTENCODING_UTF8).getStr());
++
++            ScTokenArray* pArray = pRefMgr->getRangeNameTokens(nFileId, aName);
++            if (!pArray || !mpScBasePos)
++            {    
++                AppendErrorToken(XclTools::GetXclErrorCode(errNoName), rTokData.mnSpaces);
++                break;
++            }
++
++            ::std::auto_ptr<ScTokenArray> pNew(pArray->Clone());
++            for (ScToken* p = pNew->First(); p; p = pNew->Next())
++            {
++                if (p->GetOpCode() == ocExternalName)
++                {
++                    if (p->GetType() == svSingleRef)
++                    {
++                        SingleRefData aData(p->GetSingleRef());
++                        aData.CalcAbsIfRel(*mpScBasePos);
++                        mpLinkMgr->StoreCell(nFileId, aData);
++//                      mpLinkMgr->FindExtSheet(nFileId);
++                    }
++                    else if (p->GetType() == svDoubleRef)
++                    {
++                        ComplRefData aData(p->GetDoubleRef());
++                        aData.CalcAbsIfRel(*mpScBasePos);
++                        mpLinkMgr->StoreCellRange(nFileId, aData);
++//                      mpLinkMgr->FindExtSheet(nFileId);
++                    }
++                }
++            }
++
++        }
++        break;
++    }
++
++    fprintf(stdout, "XclExpFmlaCompImpl::ProcessExternalName: --end\n");
++}
++
+ void XclExpFmlaCompImpl::ProcessFunction( const XclExpTokenData& rTokData, sal_uInt8 nExpClass )
+ {
+     OpCode eOpCode = rTokData.GetOpCode();
+@@ -1751,6 +1832,9 @@ XclExpRefLogEntry* XclExpFmlaCompImpl::GetNewRefLogEntry()
+ 
+ void XclExpFmlaCompImpl::ProcessCellRef( const XclExpTokenData& rTokData, sal_uInt8 nExpClass )
+ {
++    fprintf(stdout, "XclExpFmlaCompImpl::ProcessCellRef: --begin (type = %d; opcode = %d)\n", 
++            rTokData.GetType(), rTokData.GetOpCode());
++
+     // get the Excel address components, adjust internal data in aRefData
+     bool bNatLangRef = (meBiff == EXC_BIFF8) && mpScBasePos && (rTokData.GetOpCode() == ocColRowName);
+     SingleRefData aRefData( rTokData.mpScToken->GetSingleRef() );
+@@ -1771,7 +1855,10 @@ void XclExpFmlaCompImpl::ProcessCellRef( const XclExpTokenData& rTokData, sal_uI
+     {
+         // store external cell contents in CRN records
+         if( maCfg.mbFromCell && mpLinkMgr && mpScBasePos )
++        {
++            fprintf(stdout, "XclExpFmlaCompImpl::ProcessCellRef:   store external cell contents in CRN records\n");
+             mpLinkMgr->StoreCell( aRefData );
++        }
+ 
+         // create the tRef, tRefErr, tRefN, tRef3d, or tRefErr3d token
+         if( !maCfg.mb3DRefOnly && IsRef2D( aRefData ) )
+@@ -1805,6 +1892,7 @@ void XclExpFmlaCompImpl::ProcessCellRef( const XclExpTokenData& rTokData, sal_uI
+             AppendErrorToken( EXC_ERR_REF, rTokData.mnSpaces );
+         }
+     }
++    fprintf(stdout, "XclExpFmlaCompImpl::ProcessCellRef: --end\n");
+ }
+ 
+ void XclExpFmlaCompImpl::ProcessRangeRef( const XclExpTokenData& rTokData, sal_uInt8 nExpClass )
+diff --git sc/source/filter/excel/xelink.cxx sc/source/filter/excel/xelink.cxx
+index b1bacad..660f944 100644
+--- sc/source/filter/excel/xelink.cxx
++++ sc/source/filter/excel/xelink.cxx
+@@ -38,6 +38,15 @@
+ #include "document.hxx"
+ #include "cell.hxx"
+ #include "scextopt.hxx"
++#include "externalrefmgr.hxx"
++
++#include <vector>
++#include <memory>
++#include <stdio.h>
++
++using ::std::auto_ptr;
++using ::std::find_if;
++using ::std::vector;
+ 
+ // ============================================================================
+ // *** Helper classes ***
+@@ -220,6 +229,9 @@ public:
+     /** Stores all cells in the given range in the CRN list. */
+     void                StoreCellRange( const XclExpRoot& rRoot, const ScRange& rRange );
+ 
++    void                StoreCell( const XclExpRoot& rRoot, const ScAddress& rCell, const ScToken& rToken );
++    void                StoreCellRange( const XclExpRoot& rRoot, const ScRange& rRange, const ScToken& rToken );
++
+     /** Writes the XCT and all CRN records. */
+     virtual void        Save( XclExpStream& rStrm );
+ 
+@@ -319,6 +331,11 @@ public:
+     /** Stores all cells in the given range in the CRN list of the specified SUPBOOK sheet. */
+     void                StoreCellRange( const ScRange& rRange, sal_uInt16 nSBTab );
+ 
++    void                StoreCell( sal_uInt16 nSBTab, const ScAddress& rCell, const ScToken& rToken );
++    void                StoreCellRange( sal_uInt16 nSBTab, const ScRange& rRange, const ScToken& rToken );
++
++    sal_uInt16          GetTabIndex( const String& rTabName );
++
+     /** Inserts a new sheet name into the SUPBOOK and returns the SUPBOOK internal sheet index. */
+     sal_uInt16          InsertTabName( const String& rTabName );
+     /** Finds or inserts an EXTERNNAME record for add-ins.
+@@ -394,6 +411,9 @@ public:
+     /** Stores all cells in the given range in a CRN record list. */
+     void                StoreCellRange( const ScRange& rRange );
+ 
++    void                StoreCell( sal_uInt16 nFileId, const ScAddress& rCell );
++    void                StoreCellRange( sal_uInt16 nFileId, const ScRange& rRange );
++
+     /** Finds or inserts an EXTERNNAME record for an add-in function name.
+         @param rnSupbook  Returns the index of the SUPBOOK record which contains the add-in function name.
+         @param rnExtName  Returns the 1-based EXTERNNAME record index. */
+@@ -410,6 +430,15 @@ public:
+     /** Writes all SUPBOOK records with their sub records. */
+     virtual void        Save( XclExpStream& rStrm );
+ 
++    struct XclExpSBIndex
++    {
++        sal_uInt16          mnSupbook;          /// SUPBOOK index for an Excel sheet.
++        sal_uInt16          mnSBTab;            /// Sheet name index in SUPBOOK for an Excel sheet.
++        inline void         Set( sal_uInt16 nSupbook, sal_uInt16 nSBTab )
++                                { mnSupbook = nSupbook; mnSBTab = nSBTab; }
++    };
++    typedef ::std::vector< XclExpSBIndex > XclExpSBIndexVec;
++
+ private:
+     typedef XclExpRecordList< XclExpSupbook >   XclExpSupbookList;
+     typedef XclExpSupbookList::RecordRefType    XclExpSupbookRef;
+@@ -435,15 +464,6 @@ private:
+     void                AddExtSupbook( SCTAB nScTab );
+ 
+ private:
+-    struct XclExpSBIndex
+-    {
+-        sal_uInt16          mnSupbook;          /// SUPBOOK index for an Excel sheet.
+-        sal_uInt16          mnSBTab;            /// Sheet name in SUPBOOK for an Excel sheet.
+-        inline void         Set( sal_uInt16 nSupbook, sal_uInt16 nSBTab )
+-                                { mnSupbook = nSupbook; mnSBTab = nSBTab; }
+-    };
+-    typedef ::std::vector< XclExpSBIndex > XclExpSBIndexVec;
+-
+     XclExpSupbookList   maSupbookList;      /// List of all SUPBOOK records.
+     XclExpSBIndexVec    maSBIndexVec;       /// SUPBOOK and sheet name index for each Excel sheet.
+     sal_uInt16          mnOwnDocSB;         /// Index to SUPBOOK for own document.
+@@ -467,6 +487,9 @@ public:
+     /** Derived classes store all cells in the given range in a CRN record list. */
+     virtual void        StoreCellRange( const SingleRefData& rRef1, const SingleRefData& rRef2 ) = 0;
+ 
++    virtual void        StoreCell( sal_uInt16 nFileId, const SingleRefData& rRef ) = 0;
++    virtual void        StoreCellRange( sal_uInt16 nFileId, const SingleRefData& rRef1, const SingleRefData& rRef2 ) = 0;
++
+     /** Derived classes find or insert an EXTERNNAME record for an add-in function name. */
+     virtual bool        InsertAddIn(
+                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+@@ -499,6 +522,9 @@ public:
+ 
+     virtual void        StoreCellRange( const SingleRefData& rRef1, const SingleRefData& rRef2 );
+ 
++    virtual void        StoreCell( sal_uInt16 nFileId, const SingleRefData& rRef );
++    virtual void        StoreCellRange( sal_uInt16 nFileId, const SingleRefData& rRef1, const SingleRefData& rRef2 );
++
+     virtual bool        InsertAddIn(
+                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+                             const String& rName );
+@@ -552,6 +578,9 @@ public:
+ 
+     virtual void        StoreCellRange( const SingleRefData& rRef1, const SingleRefData& rRef2 );
+ 
++    virtual void        StoreCell( sal_uInt16 nFileId, const SingleRefData& rRef );
++    virtual void        StoreCellRange( sal_uInt16 nFileId, const SingleRefData& rRef1, const SingleRefData& rRef2 );
++
+     virtual bool        InsertAddIn(
+                             sal_uInt16& rnExtSheet, sal_uInt16& rnExtName,
+                             const String& rName );
+@@ -1013,6 +1042,8 @@ XclExpXct::XclExpXct( const String& rTabName, sal_uInt16 nSBTab ) :
+     maTabName( rTabName ),
+     mnSBTab( nSBTab )
+ {
++    fprintf(stdout, "XclExpXct::XclExpXct:   sheet name = '%s'; supbook sheet index = %d\n",
++            rtl::OUStringToOString(rTabName, RTL_TEXTENCODING_UTF8).getStr(), nSBTab);
+ }
+ 
+ void XclExpXct::StoreCellRange( const XclExpRoot& rRoot, const ScRange& rRange )
+@@ -1066,6 +1097,83 @@ void XclExpXct::StoreCellRange( const XclExpRoot& rRoot, const ScRange& rRange )
+     maUsedCells.SetMultiMarkArea( rRange );
+ }
+ 
++void XclExpXct::StoreCell( const XclExpRoot& rRoot, const ScAddress& rCell, const ScToken& rToken )
++{
++    fprintf(stdout, "XclExpXct::StoreCell: --begin\n");
++    switch (rToken.GetType())
++    {
++        case svString:
++        {
++            XclExpCrnRef xCrn(
++                new XclExpCrnString(rCell.Col(), rCell.Row(), rToken.GetString()));
++            maCrnList.AppendRecord(xCrn);
++        }
++        break;
++        case svDouble:
++        {
++            XclExpCrnRef xCrn(
++                new XclExpCrnDouble(rCell.Col(), rCell.Row(), rToken.GetDouble()));
++            maCrnList.AppendRecord(xCrn);
++        }
++        break;
++        case svEmptyCell:
++        {
++            XclExpCrnRef xCrn(
++                new XclExpCrnDouble(rCell.Col(), rCell.Row(), 0.0));
++            maCrnList.AppendRecord(xCrn);
++        }
++        break;
++    }
++    fprintf(stdout, "XclExpXct::StoreCell: --end\n");
++}
++
++void XclExpXct::StoreCellRange( const XclExpRoot& rRoot, const ScRange& rRange, const ScToken& rToken )
++{
++    fprintf(stdout, "XclExpXct::StoreCellRange: --begin\n");
++    if (rToken.GetType() != svMatrix)
++        return;
++
++    if (rRange.aStart.Tab() != rRange.aEnd.Tab())
++        return;
++
++    const ScMatrix* pMtx = rToken.GetMatrix();
++    if (!pMtx)
++        return;
++
++    SCSIZE nCols, nRows;
++    pMtx->GetDimensions(nCols, nRows);
++    fprintf(stdout, "XclExpXct::StoreCellRange:   cols = %d; rows = %d\n", nCols, nRows);
++    const ScAddress& s = rRange.aStart;
++    const ScAddress& e = rRange.aEnd;
++    if (nCols != e.Col() - s.Col() + 1 || nRows != e.Row() - s.Row() + 1)
++    {
++        // size mis-match!
++        fprintf(stdout, "XclExpXct::StoreCellRange:   matrix and range sizes differ!\n");
++        return;
++    }
++
++    for (SCSIZE nCol = 0; nCol < nCols; ++nCol)
++    {
++        for (SCSIZE nRow = 0; nRow < nRows; ++nRow)
++        {
++            if (pMtx->IsString(nCol, nRow))
++            {
++                XclExpCrnRef xCrn(new XclExpCrnString(
++                    s.Col() + nCol, s.Row() + nRow, pMtx->GetString(nCol, nRow)));
++                maCrnList.AppendRecord(xCrn);
++            }
++            else if (pMtx->IsValueOrEmpty(nCol, nRow))
++            {
++                XclExpCrnRef xCrn(new XclExpCrnDouble(
++                    s.Col() + nCol, s.Row() + nRow, pMtx->GetDouble(nCol, nRow)));
++                maCrnList.AppendRecord(xCrn);
++            }
++        }
++    }
++
++    fprintf(stdout, "XclExpXct::StoreCellRange: --end\n");
++}
++
+ void XclExpXct::Save( XclExpStream& rStrm )
+ {
+     XclExpRecord::Save( rStrm );
+@@ -1206,13 +1314,60 @@ void XclExpSupbook::StoreCellRange( const ScRange& rRange, sal_uInt16 nSBTab )
+         xXct->StoreCellRange( GetRoot(), rRange );
+ }
+ 
++void XclExpSupbook::StoreCell( sal_uInt16 nSBTab, const ScAddress& rCell, const ScToken& rToken )
++{
++    XclExpXctRef xXct = maXctList.GetRecord(nSBTab);
++    if (!xXct.is())
++        return;
++
++    xXct->StoreCell(GetRoot(), rCell, rToken);
++}
++
++void XclExpSupbook::StoreCellRange( sal_uInt16 nSBTab, const ScRange& rRange, const ScToken& rToken )
++{
++    fprintf(stdout, "XclExpSupbook::StoreCellRange: --begin\n");
++    if (rRange.aStart.Tab() != rRange.aEnd.Tab())
++    {
++        // multi-table range is not allowed!
++        fprintf(stdout, "XclExpSupbook::StoreCellRange:   multi-table range is not allowed\n");
++        return;
++    }
++
++    XclExpXctRef xXct = maXctList.GetRecord(nSBTab);
++    if (!xXct.is())
++    {
++        fprintf(stdout, "XclExpSupbook::StoreCellRange:   no xct instance\n");
++        return;
++    }
++
++    xXct->StoreCellRange(GetRoot(), rRange, rToken);
++    fprintf(stdout, "XclExpSupbook::StoreCellRange: --end\n");
++}
++
++sal_uInt16 XclExpSupbook::GetTabIndex( const String& rTabName )
++{
++    XclExpString aXclName(rTabName);
++    size_t nSize = maXctList.GetSize();
++    for (size_t i = 0; i < nSize; ++i)
++    {
++        XclExpXctRef aRec = maXctList.GetRecord(i);
++        if (aXclName == aRec->GetTabName())
++            return ulimit_cast<sal_uInt16>(i);
++    }
++    return InsertTabName(rTabName);
++}
++
+ sal_uInt16 XclExpSupbook::InsertTabName( const String& rTabName )
+ {
++    fprintf(stdout, "XclExpSupbook::InsertTabName: --begin (sheet name = '%s')\n", 
++            rtl::OUStringToOString(rTabName, RTL_TEXTENCODING_UTF8).getStr());
++
+     DBG_ASSERT( meType == EXC_SBTYPE_EXTERN, "XclExpSupbook::InsertTabName - don't insert sheet names here" );
+     sal_uInt16 nSBTab = ulimit_cast< sal_uInt16 >( maXctList.GetSize() );
+     XclExpXctRef xXct( new XclExpXct( rTabName, nSBTab ) );
+     AddRecSize( xXct->GetTabName().GetSize() );
+     maXctList.AppendRecord( xXct );
++    fprintf(stdout, "XclExpSupbook::InsertTabName: --end (sheet index = %d)\n", nSBTab);
+     return nSBTab;
+ }
+ 
+@@ -1244,6 +1399,13 @@ const XclExpString* XclExpSupbook::GetTabName( sal_uInt16 nSBTab ) const
+ 
+ void XclExpSupbook::WriteBody( XclExpStream& rStrm )
+ {
++    fprintf(stdout, "XclExpSupbook::WriteBody: --begin\n");
++
++    fprintf(stdout, "XclExpSupbook::WriteBody:   url = '%s'\n",
++            rtl::OUStringToOString(maUrl, RTL_TEXTENCODING_UTF8).getStr());
++
++    fprintf(stdout, "XclExpSupbook::WriteBody:   sheet count = %d\n", mnXclTabCount);
++
+     switch( meType )
+     {
+         case EXC_SBTYPE_SELF:
+@@ -1265,6 +1427,7 @@ void XclExpSupbook::WriteBody( XclExpStream& rStrm )
+         default:
+             DBG_ERRORFILE( "XclExpSupbook::WriteBody - unknown SUPBOOK type" );
+     }
++    fprintf(stdout, "XclExpSupbook::WriteBody: --end\n");
+ }
+ 
+ // All SUPBOOKS in a document =================================================
+@@ -1274,11 +1437,15 @@ XclExpSupbookBuffer::XclExpSupbookBuffer( const XclExpRoot& rRoot ) :
+     mnOwnDocSB( SAL_MAX_UINT16 ),
+     mnAddInSB( SAL_MAX_UINT16 )
+ {
++    fprintf(stdout, "XclExpSupbookBuffer::XclExpSupbookBuffer: --begin ctor\n");
++
+     XclExpTabInfo& rTabInfo = GetTabInfo();
+     sal_uInt16 nXclCnt = rTabInfo.GetXclTabCount();
+     sal_uInt16 nCodeCnt = static_cast< sal_uInt16 >( GetExtDocOptions().GetCodeNameCount() );
+     size_t nCount = nXclCnt + rTabInfo.GetXclExtTabCount();
+ 
++    fprintf(stdout, "XclExpSupbookBuffer::XclExpSupbookBuffer:   external tab count = %d\n", nCount);
++
+     DBG_ASSERT( nCount > 0, "XclExpSupbookBuffer::XclExpSupbookBuffer - no sheets to export" );
+     if( nCount )
+     {
+@@ -1288,7 +1455,11 @@ XclExpSupbookBuffer::XclExpSupbookBuffer( const XclExpRoot& rRoot ) :
+         XclExpSupbookRef xSupbook( new XclExpSupbook( GetRoot(), ::std::max( nXclCnt, nCodeCnt ) ) );
+         mnOwnDocSB = Append( xSupbook );
+         for( sal_uInt16 nXclTab = 0; nXclTab < nXclCnt; ++nXclTab )
++        {
++            fprintf(stdout, "XclExpSupbookBuffer::XclExpSupbookBuffer:   supbook index = %d; sheet index = %d (internal)\n",
++                    mnOwnDocSB, nXclTab);
+             maSBIndexVec[ nXclTab ].Set( mnOwnDocSB, nXclTab );
++        }
+ 
+         // add SUPBOOKs with external references
+         for( SCTAB nScTab = 0, nScCnt = rTabInfo.GetScTabCount(); nScTab < nScCnt; ++nScTab )
+@@ -1352,6 +1523,147 @@ void XclExpSupbookBuffer::StoreCellRange( const ScRange& rRange )
+     }
+ }
+ 
++namespace {
++
++class FindSBIndexEntry
++{
++public:
++    explicit FindSBIndexEntry(sal_uInt16 nSupbookId, sal_uInt16 nTabId) :
++        mnSupbookId(nSupbookId), mnTabId(nTabId) {}
++
++    bool operator()(const XclExpSupbookBuffer::XclExpSBIndex& r) const
++    {
++        return mnSupbookId == r.mnSupbook && mnTabId == r.mnSBTab;
++    }
++
++private:
++    sal_uInt16 mnSupbookId;
++    sal_uInt16 mnTabId;
++};
++
++}
++
++void XclExpSupbookBuffer::StoreCell( sal_uInt16 nFileId, const ScAddress& rCell )
++{
++    ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
++    const String* pUrl = pRefMgr->getExternalFileName(nFileId);
++    if (!pUrl)
++        return;
++
++    fprintf(stdout, "XclExpSupbookBuffer::StoreCell: --begin (file url = '%s')\n",
++            rtl::OUStringToOString(*pUrl, RTL_TEXTENCODING_UTF8).getStr());
++
++    XclExpSupbookRef xSupbook;
++    sal_uInt16 nSupbookId;
++    if (!GetSupbookUrl(xSupbook, nSupbookId, *pUrl))
++    {
++        fprintf(stdout, "XclExpSupbookBuffer::StoreCellRange:   supbook for given url does not exist\n");
++        xSupbook.reset(new XclExpSupbook(GetRoot(), *pUrl));
++        nSupbookId = Append(xSupbook);
++    }
++
++    ScToken* pToken = pRefMgr->getSingleRefToken(nFileId, rCell, NULL);
++    if (!pToken)
++        return;
++
++    const String* pTabName = pRefMgr->getExternalTableName(nFileId, rCell.Tab());
++    if (!pTabName)
++        return;
++
++    fprintf(stdout, "XclExpSupbookBuffer::StoreCell:   tab name = '%s'\n", 
++            rtl::OUStringToOString(*pTabName, RTL_TEXTENCODING_UTF8).getStr());
++
++    sal_uInt16 nSheetId = xSupbook->GetTabIndex(*pTabName);
++    FindSBIndexEntry f(nSupbookId, nSheetId);
++    XclExpSBIndexVec::iterator itrEnd = maSBIndexVec.end();
++    XclExpSBIndexVec::const_iterator itr = find_if(maSBIndexVec.begin(), itrEnd, f);
++    if (itr == itrEnd)
++    {
++        maSBIndexVec.push_back(XclExpSBIndex());
++        XclExpSBIndex& r = maSBIndexVec.back();
++        r.mnSupbook = nSupbookId;
++        r.mnSBTab   = nSheetId;
++    }
++
++    xSupbook->StoreCell(nSheetId, rCell, *pToken);
++}
++
++void XclExpSupbookBuffer::StoreCellRange( sal_uInt16 nFileId, const ScRange& rRange )
++{
++    ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
++    const String* pUrl = pRefMgr->getExternalFileName(nFileId);
++    if (!pUrl)
++        return;
++
++    fprintf(stdout, "XclExpSupbookBuffer::StoreCellRange: --begin (file url = '%s')\n",
++            rtl::OUStringToOString(*pUrl, RTL_TEXTENCODING_UTF8).getStr());
++
++    XclExpSupbookRef xSupbook;
++    sal_uInt16 nSupbookId;
++    if (!GetSupbookUrl(xSupbook, nSupbookId, *pUrl))
++    {
++        fprintf(stdout, "XclExpSupbookBuffer::StoreCellRange:   supbook for given url does not exist\n");
++        xSupbook.reset(new XclExpSupbook(GetRoot(), *pUrl));
++        nSupbookId = Append(xSupbook);
++    }
++
++    SCTAB nTab1 = rRange.aStart.Tab(), nTab2 = rRange.aEnd.Tab();
++
++    // If this is a multi-table range, get token for each table.
++    vector<ScToken*> aMatrixList;
++    aMatrixList.reserve(nTab2 - nTab1 + 1);
++    ScTokenArray* pArray = pRefMgr->getDoubleRefTokens(nFileId, rRange, NULL);
++    if (!pArray)
++        return;
++
++    auto_ptr<ScTokenArray> pNew(pArray->Clone());
++    for (ScToken* p = pNew->First(); p; p = pNew->Next())
++    {
++        if (p->GetType() == svMatrix)
++            aMatrixList.push_back(p);
++        else if (p->GetOpCode() != ocSep)
++        {
++            fprintf(stdout, "XclExpSupbookBuffer::StoreCellRange:   this is supposed to be ocSep!!!\n");
++            return;
++        }
++    }
++
++    if (aMatrixList.size() != nTab2 - nTab1 + 1)
++    {
++        fprintf(stdout, "XclExpSupbookBuffer::StoreCellRange:   matrix size mismatch!\n");
++        return;
++    }
++
++    ScRange aRange(rRange);
++    aRange.aStart.SetTab(0);
++    aRange.aEnd.SetTab(0);
++    for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
++    {
++        const String* pTabName = pRefMgr->getExternalTableName(nFileId, nTab);
++        if (!pTabName)
++            continue;
++
++        fprintf(stdout, "XclExpSupbookBuffer::StoreCellRange:   tab name = '%s'\n", 
++                rtl::OUStringToOString(*pTabName, RTL_TEXTENCODING_UTF8).getStr());
++
++        sal_uInt16 nSheetId = xSupbook->GetTabIndex(*pTabName);
++        FindSBIndexEntry f(nSupbookId, nSheetId);
++        XclExpSBIndexVec::iterator itrEnd = maSBIndexVec.end();
++        XclExpSBIndexVec::const_iterator itr = find_if(maSBIndexVec.begin(), itrEnd, f);
++        if (itr == itrEnd)
++        {
++            maSBIndexVec.push_back(XclExpSBIndex());
++            XclExpSBIndex& r = maSBIndexVec.back();
++            r.mnSupbook = nSupbookId;
++            r.mnSBTab   = nSheetId;
++        }
++
++        xSupbook->StoreCellRange(nSheetId, aRange, *aMatrixList[nTab-nTab1]);
++    }
++
++    fprintf(stdout, "XclExpSupbookBuffer::StoreCellRange: --end\n");
++}
++
+ bool XclExpSupbookBuffer::InsertAddIn(
+         sal_uInt16& rnSupbook, sal_uInt16& rnExtName, const String& rName )
+ {
+@@ -1385,7 +1697,9 @@ bool XclExpSupbookBuffer::InsertDde(
+ 
+ void XclExpSupbookBuffer::Save( XclExpStream& rStrm )
+ {
++    fprintf(stdout, "XclExpSupbookBuffer::Save: --begin\n");
+     maSupbookList.Save( rStrm );
++    fprintf(stdout, "XclExpSupbookBuffer::Save: --end\n");
+ }
+ 
+ bool XclExpSupbookBuffer::GetSupbookUrl(
+@@ -1426,11 +1740,17 @@ sal_uInt16 XclExpSupbookBuffer::Append( XclExpSupbookRef xSupbook )
+ 
+ void XclExpSupbookBuffer::AddExtSupbook( SCTAB nScTab )
+ {
++    fprintf(stdout, "XclExpSupbookBuffer::AddExtSupbook: --begin (sctab = %d)\n", nScTab);
++
+     sal_uInt16 nXclTab = GetTabInfo().GetXclTab( nScTab );
++    fprintf(stdout, "XclExpSupbookBuffer::AddExtSupbook:   xlstab = %d\n", nXclTab);
+     DBG_ASSERT( nXclTab < maSBIndexVec.size(), "XclExpSupbookBuffer::AddExtSupbook - out of range" );
+ 
+     // find ext doc name or append new one, save position in maSBIndexBuffer
+     const String& rUrl = GetDoc().GetLinkDoc( nScTab );
++    fprintf(stdout, "XclExpSupbookBuffer::AddExtSupbook:   url = '%s'\n",
++            rtl::OUStringToOString(rUrl, RTL_TEXTENCODING_UTF8).getStr());
++
+     DBG_ASSERT( rUrl.Len(), "XclExpSupbookBuffer::AddExtSupbook - missing external linked sheet" );
+     sal_uInt16 nSupbook;
+     XclExpSupbookRef xSupbook;
+@@ -1439,10 +1759,15 @@ void XclExpSupbookBuffer::AddExtSupbook( SCTAB nScTab )
+         xSupbook.reset( new XclExpSupbook( GetRoot(), rUrl ) );
+         nSupbook = Append( xSupbook );
+     }
++    fprintf(stdout, "XclExpSupbookBuffer::AddExtSupbook:   nSupbook = %d\n", nSupbook);
+ 
+     // append new sheet name, save SUPBOOK and sheet position in maSBIndexVec
+     maSBIndexVec[ nXclTab ].mnSupbook = nSupbook;
+     maSBIndexVec[ nXclTab ].mnSBTab = xSupbook->InsertTabName( GetDoc().GetLinkTab( nScTab ) );
++
++    fprintf(stdout, "XclExpSupbookBuffer::AddExtSupbook:   supbook = %d; sheet index = %d; sheet name = '%s'\n", 
++            nSupbook, maSBIndexVec[nXclTab].mnSBTab,
++            rtl::OUStringToOString(GetDoc().GetLinkTab(nScTab), RTL_TEXTENCODING_UTF8).getStr());
+ }
+ 
+ // Export link manager ========================================================
+@@ -1490,6 +1815,16 @@ void XclExpLinkManagerImpl5::StoreCellRange( const SingleRefData& /*rRef1*/, con
+     // not implemented
+ }
+ 
++void XclExpLinkManagerImpl5::StoreCell( sal_uInt16 /*nFileId*/, const SingleRefData& /*rRef*/ )
++{
++    // not implemented
++}
++
++void XclExpLinkManagerImpl5::StoreCellRange( sal_uInt16 /*nFileId*/, const SingleRefData& /*rRef1*/, const SingleRefData& /*rRef2*/ )
++{
++    // not implemented
++}
++
+ bool XclExpLinkManagerImpl5::InsertAddIn(
+         sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
+ {
+@@ -1640,10 +1975,15 @@ void XclExpLinkManagerImpl8::StoreCellRange( const SingleRefData& rRef1, const S
+         ScRange aRange(
+             static_cast< SCCOL >( rRef1.nCol ), static_cast< SCROW >( rRef1.nRow ), 0,
+             static_cast< SCCOL >( rRef2.nCol ), static_cast< SCROW >( rRef2.nRow ), 0 );
++        String aStr;
++        aRange.Format(aStr, SCR_ABS_3D, &GetDoc());
++        fprintf(stdout, "XclExpLinkManagerImpl8::StoreCellRange:   range = '%s'\n", 
++                rtl::OUStringToOString(aStr, RTL_TEXTENCODING_UTF8).getStr());
+         for( SCTAB nScTab = nFirstScTab; nScTab <= nLastScTab; ++nScTab )
+         {
+             if( rTabInfo.IsExternalTab( nScTab ) )
+             {
++                fprintf(stdout, "XclExpLinkManagerImpl8::StoreCellRange:   %d is an external sheet\n", nScTab);
+                 aRange.aStart.SetTab( nScTab );
+                 aRange.aEnd.SetTab( nScTab );
+                 maSBBuffer.StoreCellRange( aRange );
+@@ -1652,6 +1992,36 @@ void XclExpLinkManagerImpl8::StoreCellRange( const SingleRefData& rRef1, const S
+     }
+ }
+ 
++void XclExpLinkManagerImpl8::StoreCell( sal_uInt16 nFileId, const SingleRefData& rRef )
++{
++    ScAddress aAddr(rRef.nCol, rRef.nRow, rRef.nTab);
++    maSBBuffer.StoreCell(nFileId, aAddr);
++}
++
++void XclExpLinkManagerImpl8::StoreCellRange( sal_uInt16 nFileId, const SingleRefData& rRef1, const SingleRefData& rRef2 )
++{
++    fprintf(stdout, "XclExpLinkManagerImpl8::StoreCellRange: --begin (file id = %d)\n", nFileId);
++
++    // XclExpXti -- stores supbook ID and first and last sheet IDs for EXTERNSHEET.
++    // 
++    // XclExpSupbookBuffer -- stores
++
++    // 1) Insert into supbook buffer first, and get the supbook ID.
++    SCTAB nFirstScTab = static_cast<SCTAB>(rRef1.nTab);
++    SCTAB nLastScTab  = static_cast<SCTAB>(rRef2.nTab);
++    ScRange aRange(static_cast<SCCOL>(rRef1.nCol), static_cast<SCROW>(rRef1.nRow), static_cast<SCTAB>(rRef1.nTab),
++                   static_cast<SCCOL>(rRef2.nCol), static_cast<SCROW>(rRef2.nRow), static_cast<SCTAB>(rRef2.nTab));
++    maSBBuffer.StoreCellRange(nFileId, aRange);
++//  for (SCTAB nScTab = nFirstScTab; nScTab <= nLastScTab; ++nScTab)
++//  {
++//      aRange.aStart.SetTab(nScTab);
++//      aRange.aEnd.SetTab(nScTab);
++//      maSBBuffer.StoreCellRange(nFileId, aRange);
++//  }
++    
++    fprintf(stdout, "XclExpLinkManagerImpl8::StoreCellRange: --end\n");
++}
++
+ bool XclExpLinkManagerImpl8::InsertAddIn(
+         sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
+ {
+@@ -1693,13 +2063,20 @@ void XclExpLinkManagerImpl8::Save( XclExpStream& rStrm )
+             aIt->Save( rStrm );
+         rStrm.EndRecord();
+     }
++    else
++    {
++        fprintf(stdout, "XclExpLinkManagerImpl8::Save:   xti (external table index) list is empty - nothing to save\n");
++        maSBBuffer.Save(rStrm);
++    }
+ }
+ 
+ sal_uInt16 XclExpLinkManagerImpl8::InsertXti( const XclExpXti& rXti )
+ {
+-    for( XclExpXtiVec::const_iterator aIt = maXtiVec.begin(), aEnd = maXtiVec.end(); aIt != aEnd; ++aIt )
++    using ::std::distance;
++    for( XclExpXtiVec::const_iterator aIt = maXtiVec.begin(), aBeg = maXtiVec.begin(), aEnd = maXtiVec.end(); 
++         aIt != aEnd; ++aIt )
+         if( *aIt == rXti )
+-            return ulimit_cast< sal_uInt16 >( aIt - maXtiVec.begin() );
++            return ulimit_cast< sal_uInt16 >( distance(aBeg, aIt) );
+     maXtiVec.push_back( rXti );
+     return ulimit_cast< sal_uInt16 >( maXtiVec.size() - 1 );
+ }
+@@ -1755,6 +2132,16 @@ void XclExpLinkManager::StoreCellRange( const ComplRefData& rRef )
+     mxImpl->StoreCellRange( rRef.Ref1, rRef.Ref2 );
+ }
+ 
++void XclExpLinkManager::StoreCell( sal_uInt16 nFileId, const SingleRefData& rRef )
++{
++    mxImpl->StoreCell( nFileId, rRef );
++}
++
++void XclExpLinkManager::StoreCellRange( sal_uInt16 nFileId, const ComplRefData& rRef )
++{
++    mxImpl->StoreCellRange( nFileId, rRef.Ref1, rRef.Ref2 );
++}
++
+ bool XclExpLinkManager::InsertAddIn(
+         sal_uInt16& rnExtSheet, sal_uInt16& rnExtName, const String& rName )
+ {
+@@ -1770,7 +2157,9 @@ bool XclExpLinkManager::InsertDde(
+ 
+ void XclExpLinkManager::Save( XclExpStream& rStrm )
+ {
++    fprintf(stdout, "XclExpLinkManager::Save: --begin\n");
+     mxImpl->Save( rStrm );
++    fprintf(stdout, "XclExpLinkManager::Save: --end\n");
+ }
+ 
+ // ============================================================================
 diff --git sc/source/filter/excel/xilink.cxx sc/source/filter/excel/xilink.cxx
 index e351863..b58f6ec 100644
 --- sc/source/filter/excel/xilink.cxx
@@ -1020,6 +2028,21 @@
  
  		inline const TokenId		LastId( void ) const;
  		inline const ScTokenArray*	operator []( const TokenId nId );
+diff --git sc/source/filter/inc/xelink.hxx sc/source/filter/inc/xelink.hxx
+index 795219c..37f1457 100644
+--- sc/source/filter/inc/xelink.hxx
++++ sc/source/filter/inc/xelink.hxx
+@@ -178,6 +178,10 @@ public:
+     /** Stores all cells in the given range in a CRN record list. */
+     void                StoreCellRange( const ComplRefData& rRef );
+ 
++    void                StoreCell( sal_uInt16 nFileId, const SingleRefData& rRef );
++
++    void                StoreCellRange( sal_uInt16 nFileId, const ComplRefData& rRef );
++
+     /** Finds or inserts an EXTERNNAME record for an add-in function name.
+         @param rnExtSheet  (out-param) Returns the index of the EXTSHEET structure for the add-in function name.
+         @param rnExtName  (out-param) Returns the 1-based EXTERNNAME record index.
 diff --git sc/source/filter/inc/xilink.hxx sc/source/filter/inc/xilink.hxx
 index 0d547fe..3c2d0d9 100644
 --- sc/source/filter/inc/xilink.hxx
@@ -1036,10 +2059,10 @@
          For OLE object links: Decodes to class name and document URL.
 diff --git sc/source/ui/docshell/externalrefmgr.cxx sc/source/ui/docshell/externalrefmgr.cxx
 new file mode 100644
-index 0000000..adb7452
+index 0000000..c7c0bae
 --- /dev/null
 +++ sc/source/ui/docshell/externalrefmgr.cxx
-@@ -0,0 +1,788 @@
+@@ -0,0 +1,789 @@
 +/*************************************************************************
 + *
 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -1112,6 +2135,9 @@
 +using ::std::find;
 +using ::std::distance;
 +
++#define SRCDOC_LIFE_SPAN     6000       // 1 minute (in 100th of sec)
++#define SRCDOC_SCAN_INTERVAL 1000*2     // every 2 seconds (in msec)
++
 +ScExternalRefLink::ScExternalRefLink(ScDocument* pDoc, sal_uInt16 nFileId, const String& rFilter) :
 +    ::sfx2::SvBaseLink(::sfx2::LINKUPDATE_ONCALL, FORMAT_FILE),
 +    mnFileId(nFileId),
@@ -1303,8 +2329,7 @@
 +    mpDoc(pDoc)
 +{
 +    maSrcDocTimer.SetTimeoutHdl( LINK(this, ScExternalRefManager, TimeOutHdl) );
-+//  maSrcDocTimer.SetTimeout(60000*5); // every 5 minutes
-+    maSrcDocTimer.SetTimeout(1000*2); // every 2 seconds
++    maSrcDocTimer.SetTimeout(SRCDOC_SCAN_INTERVAL);
 +}
 +
 +ScExternalRefManager::~ScExternalRefManager()
@@ -1312,9 +2337,10 @@
 +    clear();
 +}
 +
-+ScToken* ScExternalRefManager::getSingleRefToken(sal_uInt16 nFileId, const ScAddress& rCell, const ScAddress& rCurPos)
++ScToken* ScExternalRefManager::getSingleRefToken(sal_uInt16 nFileId, const ScAddress& rCell, const ScAddress* pCurPos)
 +{
-+    // TODO: add the current cell position to the list.
++    if (pCurPos)
++        insertReferencingCell(nFileId, *pCurPos);
 +    return getSingleRefToken(nFileId, rCell);
 +}
 +
@@ -1358,9 +2384,10 @@
 +    return pTok.get();
 +}
 +
-+ScTokenArray* ScExternalRefManager::getDoubleRefTokens(sal_uInt16 nFileId, const ScRange& rRange, const ScAddress& rCurPos)
++ScTokenArray* ScExternalRefManager::getDoubleRefTokens(sal_uInt16 nFileId, const ScRange& rRange, const ScAddress* pCurPos)
 +{
-+    // TODO: add the current cell position to the list of affected cells.
++    if (pCurPos)
++        insertReferencingCell(nFileId, *pCurPos);
 +    return getDoubleRefTokens(nFileId, rRange);
 +}
 +
@@ -1402,19 +2429,22 @@
 +    return pArray.get();
 +}
 +
-+ScTokenArray* ScExternalRefManager::getRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScAddress& rCurPos)
++ScTokenArray* ScExternalRefManager::getRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScAddress* pCurPos)
 +{
++    if (pCurPos)
 +    {
 +        String aCellStr;
-+        rCurPos.Format(aCellStr, SCA_ABS_3D);
++        pCurPos->Format(aCellStr, SCA_ABS_3D);
 +        const String* pFile = getExternalFileName(nFileId);
-+        fprintf(stdout, "ScExternalRefManager::getRangeNameTokens: --begin (file = '%s'; name = '%s'; pos = '%s')\n",
++        fprintf(stdout, "ScExternalRefManager::getRangeNameTokens: --begin (file = '%s' [%d]; name = '%s'; pos = '%s')\n",
 +                rtl::OUStringToOString(*pFile, RTL_TEXTENCODING_UTF8).getStr(),
++                nFileId,
 +                rtl::OUStringToOString(rName, RTL_TEXTENCODING_UTF8).getStr(),
 +                rtl::OUStringToOString(aCellStr, RTL_TEXTENCODING_UTF8).getStr());
 +    }
 +
-+    insertReferencingCell(nFileId, rCurPos);
++    if (pCurPos)
++        insertReferencingCell(nFileId, *pCurPos);
 +
 +    // First, check if this name has already been cached.
 +    RangeNameMap& rMap = getDocumentCache(nFileId)->maRangeNames;
@@ -1457,46 +2487,17 @@
 +            case svSingleRef:
 +            {
 +                fprintf(stdout, "ScDocument::FindExternalRangeName:   single ref\n");
-+                SingleRefData aRef(pToken->GetSingleRef());
-+                if (aRef.IsTabRel())
-+                    break;
-+
-+                // The sheet reference is absolute.  Get the cell from the 
-+                // source document, and convert it to a static value.
-+    
-+                aRef.CalcAbsIfRel(rCurPos);
-+                ScToken* pTok = getSingleRefToken(nFileId, ScAddress(aRef.nCol, aRef.nRow, aRef.nTab));
-+                if (pTok)
-+                {
-+                    pNew->AddToken(*pTok);
-+                    bTokenAdded = true;
-+                }
++                ScExternalSingleRefToken aNewToken(nFileId, pToken->GetSingleRef());
++                pNew->AddToken(aNewToken);
++                bTokenAdded = true;
 +            }
 +            break;
 +            case svDoubleRef:
 +            {
 +                fprintf(stdout, "ScDocument::FindExternalRangeName:   double ref\n");
-+                ComplRefData aComRef(pToken->GetDoubleRef());
-+                if (aComRef.Ref1.IsTabRel() || aComRef.Ref2.IsTabRel())
-+                    break;
-+
-+                aComRef.CalcAbsIfRel(rCurPos);
-+                SCsTAB nTab1 = aComRef.Ref1.nTab;
-+                SCsCOL nCol1 = aComRef.Ref1.nCol;
-+                SCsROW nRow1 = aComRef.Ref1.nRow;
-+                SCsTAB nTab2 = aComRef.Ref2.nTab;
-+                SCsCOL nCol2 = aComRef.Ref2.nCol;
-+                SCsROW nRow2 = aComRef.Ref2.nRow;
-+
-+                ScTokenArray* pArray = getDoubleRefTokens(nFileId, ScRange(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2));
-+                if (pArray)
-+                {
-+                    for (ScToken* p = pArray->First(); p; p = pArray->Next())
-+                    {
-+                        pNew->AddToken(*p);
-+                        bTokenAdded = true;
-+                    }
-+                }
++                ScExternalDoubleRefToken aNewToken(nFileId, pToken->GetDoubleRef());
++                pNew->AddToken(aNewToken);
++                bTokenAdded = true;
 +            }
 +            break;
 +        }
@@ -1517,13 +2518,8 @@
 +    if (itr == maRefCells.end())
 +    {
 +        const String* pFile = getExternalFileName(nFileId);
-+        if (pFile)
-+        {
-+            fprintf(stdout, "ScExternalRefManager::refreshAllReferencingCells:   no referencing cells for names from '%s'\n",
-+                    rtl::OUStringToOString(*pFile, RTL_TEXTENCODING_UTF8).getStr());
-+        }
-+        else
-+            fprintf(stdout, "ScExternalRefManager::refreshAllReferencingCells:   file name not found (file ID = %d)\n", nFileId);
++        fprintf(stdout, "ScExternalRefManager::refreshAllReferencingCells:   no referencing cells for names from '%s'\n",
++                rtl::OUStringToOString(*pFile, RTL_TEXTENCODING_UTF8).getStr());
 +        return;
 +    }
 +
@@ -1612,11 +2608,27 @@
 +    maDocShells.insert(DocShellMap::value_type(nFileId, aSrcDoc));
 +    if (!maLinkedDocs.count(nFileId))
 +    {
++        // Source document not linked yet.  Link it now.
 +        insertExternalFileLink(nFileId, aFilter);
 +        maLinkedDocs.insert(nFileId);
 +    }
 +    SfxObjectShell* p = aSrcDoc.maShell;
-+    return static_cast<ScDocShell*>(p)->GetDocument();
++    ScDocument* pSrcDoc = static_cast<ScDocShell*>(p)->GetDocument();
++
++    // Store all its table names.  Excel exporter needs this info.
++    vector<String> aTableNames;
++    SCTAB nCount = pSrcDoc->GetTableCount();
++    aTableNames.reserve(nCount);
++    for (SCTAB i = 0; i < nCount; ++i)
++    {
++        String aTabName;
++        pSrcDoc->GetName(i, aTabName);
++        aTableNames.push_back(aTabName);
++    }
++    DocCache* pCache = getDocumentCache(nFileId);
++    pCache->maTableNames.swap(aTableNames);
++
++    return pSrcDoc;
 +}
 +
 +SfxObjectShellRef ScExternalRefManager::loadSrcDocument(const String& rFile, String& rFilter)
@@ -1729,12 +2741,24 @@
 +    return static_cast<sal_uInt16>(maFileNames.size() - 1);
 +}
 +
-+const String* ScExternalRefManager::getExternalFileName(sal_uInt16 nIndex) const
++const String* ScExternalRefManager::getExternalFileName(sal_uInt16 nFileId) const
 +{
-+    if (nIndex >= maFileNames.size())
++    if (nFileId >= maFileNames.size())
 +        return NULL;
 +
-+    return &maFileNames[nIndex];
++    return &maFileNames[nFileId];
++}
++
++const String* ScExternalRefManager::getExternalTableName(sal_uInt16 nFileId, SCTAB nTabId)
++{
++    if (nFileId >= maFileNames.size())
++        return NULL;
++
++    DocCache* pCache = getDocumentCache(nFileId);
++    if (nTabId >= pCache->maTableNames.size())
++        return NULL;
++
++    return &pCache->maTableNames[nTabId];
 +}
 +
 +template<typename MapContainer>
@@ -1763,9 +2787,8 @@
 +            rtl::OUStringToOString(*pOldFile, RTL_TEXTENCODING_UTF8).getStr(), 
 +            rtl::OUStringToOString(rNewFile, RTL_TEXTENCODING_UTF8).getStr());
 +
-+    removeSrcDocument(nFileId, false);
 +    maFileNames[nFileId] = rNewFile;
-+    refreshAllReferencingCells(nFileId);
++    refreshNames(nFileId);
 +}
 +
 +void ScExternalRefManager::removeSrcDocument(sal_uInt16 nFileId, bool bBreakLink)
@@ -1807,10 +2830,10 @@
 +    {
 +        // in 100th of a second.
 +        sal_Int32 nSinceLastAccess = (Time() - itr->second.maLastAccess).GetTime(); 
-+        const String* pStr = getExternalFileName(itr->first);
-+        if (pStr)
-+            fprintf(stdout, "ScExternalRefManager::purgeStaleSrcDocument:   file = '%s'; since last access = %ld\n",
-+                    rtl::OUStringToOString(*pStr, RTL_TEXTENCODING_UTF8).getStr(), nSinceLastAccess);
++//      const String* pStr = getExternalFileName(itr->first);
++//      if (pStr)
++//          fprintf(stdout, "ScExternalRefManager::purgeStaleSrcDocument:   file = '%s'; since last access = %ld\n",
++//                  rtl::OUStringToOString(*pStr, RTL_TEXTENCODING_UTF8).getStr(), nSinceLastAccess);
 +
 +        if (nSinceLastAccess < nTimeOut)
 +            aNewDocShells.insert(*itr);
@@ -1824,10 +2847,11 @@
 +IMPL_LINK(ScExternalRefManager, TimeOutHdl, AutoTimer*, pTimer)
 +{
 +    if (pTimer == &maSrcDocTimer)
-+        purgeStaleSrcDocument(1000); // max life span is 10 seconds (TODO: configure this).
++        purgeStaleSrcDocument(SRCDOC_LIFE_SPAN);
 +
 +    return 0;
 +}
++
 diff --git sc/source/ui/docshell/makefile.mk sc/source/ui/docshell/makefile.mk
 index db83fec..6286dfb 100644
 --- sc/source/ui/docshell/makefile.mk



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]