LCOV - code coverage report
Current view: top level - libreoffice/sc/source/ui/docshell - externalrefmgr.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 486 1345 36.1 %
Date: 2012-12-27 Functions: 69 155 44.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include "externalrefmgr.hxx"
      21             : #include "document.hxx"
      22             : #include "token.hxx"
      23             : #include "tokenarray.hxx"
      24             : #include "address.hxx"
      25             : #include "tablink.hxx"
      26             : #include "docsh.hxx"
      27             : #include "scextopt.hxx"
      28             : #include "rangenam.hxx"
      29             : #include "cell.hxx"
      30             : #include "viewdata.hxx"
      31             : #include "tabvwsh.hxx"
      32             : #include "sc.hrc"
      33             : #include "globstr.hrc"
      34             : 
      35             : #include "sfx2/app.hxx"
      36             : #include "sfx2/docfilt.hxx"
      37             : #include "sfx2/docfile.hxx"
      38             : #include "sfx2/fcontnr.hxx"
      39             : #include "sfx2/sfxsids.hrc"
      40             : #include "sfx2/objsh.hxx"
      41             : #include "svl/broadcast.hxx"
      42             : #include "svl/smplhint.hxx"
      43             : #include "svl/itemset.hxx"
      44             : #include "svl/stritem.hxx"
      45             : #include "svl/urihelper.hxx"
      46             : #include "svl/zformat.hxx"
      47             : #include "sfx2/linkmgr.hxx"
      48             : #include "tools/urlobj.hxx"
      49             : #include "unotools/ucbhelper.hxx"
      50             : #include "unotools/localfilehelper.hxx"
      51             : #include "vcl/msgbox.hxx"
      52             : 
      53             : #include <memory>
      54             : #include <algorithm>
      55             : 
      56             : #include <boost/scoped_ptr.hpp>
      57             : 
      58             : using ::std::auto_ptr;
      59             : using ::com::sun::star::uno::Any;
      60             : using ::rtl::OUString;
      61             : using ::std::vector;
      62             : using ::std::find;
      63             : using ::std::find_if;
      64             : using ::std::remove_if;
      65             : using ::std::distance;
      66             : using ::std::pair;
      67             : using ::std::list;
      68             : using ::std::unary_function;
      69             : using namespace formula;
      70             : 
      71             : #define SRCDOC_LIFE_SPAN     6000       // 1 minute (in 100th of a sec)
      72             : #define SRCDOC_SCAN_INTERVAL 1000*5     // every 5 seconds (in msec)
      73             : 
      74             : namespace {
      75             : 
      76           0 : class TabNameSearchPredicate : public unary_function<ScExternalRefCache::TableName, bool>
      77             : {
      78             : public:
      79           0 :     explicit TabNameSearchPredicate(const OUString& rSearchName) :
      80           0 :         maSearchName(ScGlobal::pCharClass->uppercase(rSearchName))
      81             :     {
      82           0 :     }
      83             : 
      84           0 :     bool operator()(const ScExternalRefCache::TableName& rTabNameSet) const
      85             :     {
      86             :         // Ok, I'm doing case insensitive search here.
      87           0 :         return rTabNameSet.maUpperName.equals(maSearchName);
      88             :     }
      89             : 
      90             : private:
      91             :     OUString maSearchName;
      92             : };
      93             : 
      94             : class FindSrcFileByName : public unary_function<ScExternalRefManager::SrcFileData, bool>
      95             : {
      96             : public:
      97          40 :     FindSrcFileByName(const OUString& rMatchName) :
      98          40 :         mrMatchName(rMatchName)
      99             :     {
     100          40 :     }
     101             : 
     102          37 :     bool operator()(const ScExternalRefManager::SrcFileData& rSrcData) const
     103             :     {
     104          37 :         return rSrcData.maFileName.equals(mrMatchName);
     105             :     }
     106             : 
     107             : private:
     108             :     const OUString& mrMatchName;
     109             : };
     110             : 
     111             : class NotifyLinkListener : public unary_function<ScExternalRefManager::LinkListener*,  void>
     112             : {
     113             : public:
     114           0 :     NotifyLinkListener(sal_uInt16 nFileId, ScExternalRefManager::LinkUpdateType eType) :
     115           0 :         mnFileId(nFileId), meType(eType) {}
     116             : 
     117           0 :     NotifyLinkListener(const NotifyLinkListener& r) :
     118           0 :         mnFileId(r.mnFileId), meType(r.meType) {}
     119             : 
     120           0 :     void operator() (ScExternalRefManager::LinkListener* p) const
     121             :     {
     122           0 :         p->notify(mnFileId, meType);
     123           0 :     }
     124             : private:
     125             :     sal_uInt16 mnFileId;
     126             :     ScExternalRefManager::LinkUpdateType meType;
     127             : };
     128             : 
     129             : struct UpdateFormulaCell : public unary_function<ScFormulaCell*, void>
     130             : {
     131           0 :     void operator() (ScFormulaCell* pCell) const
     132             :     {
     133             :         // Check to make sure the cell really contains ocExternalRef.
     134             :         // External names, external cell and range references all have a
     135             :         // ocExternalRef token.
     136           0 :         const ScTokenArray* pCode = pCell->GetCode();
     137           0 :         if (!pCode->HasExternalRef())
     138           0 :             return;
     139             : 
     140           0 :         ScTokenArray* pArray = pCell->GetCode();
     141           0 :         if (pArray)
     142             :             // Clear the error code, or a cell with error won't get re-compiled.
     143           0 :             pArray->SetCodeError(0);
     144             : 
     145           0 :         pCell->SetCompile(true);
     146           0 :         pCell->CompileTokenArray();
     147           0 :         pCell->SetDirty();
     148             :     }
     149             : };
     150             : 
     151             : class RemoveFormulaCell : public unary_function<pair<const sal_uInt16, ScExternalRefManager::RefCellSet>, void>
     152             : {
     153             : public:
     154          10 :     explicit RemoveFormulaCell(ScFormulaCell* p) : mpCell(p) {}
     155           6 :     void operator() (pair<const sal_uInt16, ScExternalRefManager::RefCellSet>& r) const
     156             :     {
     157           6 :         r.second.erase(mpCell);
     158           6 :     }
     159             : private:
     160             :     ScFormulaCell* mpCell;
     161             : };
     162             : 
     163             : class ConvertFormulaToStatic : public unary_function<ScFormulaCell*, void>
     164             : {
     165             : public:
     166           0 :     explicit ConvertFormulaToStatic(ScDocument* pDoc) : mpDoc(pDoc) {}
     167           0 :     void operator() (ScFormulaCell* pCell) const
     168             :     {
     169           0 :         ScAddress aPos = pCell->aPos;
     170             : 
     171             :         // We don't check for empty cells because empty external cells are
     172             :         // treated as having a value of 0.
     173             : 
     174           0 :         if (pCell->IsValue())
     175             :         {
     176             :             // Turn this into value cell.
     177           0 :             double fVal = pCell->GetValue();
     178           0 :             mpDoc->PutCell(aPos, new ScValueCell(fVal));
     179             :         }
     180             :         else
     181             :         {
     182             :             // string cell otherwise.
     183           0 :             rtl::OUString aVal = pCell->GetString();
     184           0 :             mpDoc->PutCell(aPos, new ScStringCell(aVal));
     185             :         }
     186           0 :     }
     187             : private:
     188             :     ScDocument* mpDoc;
     189             : };
     190             : 
     191             : /**
     192             :  * Check whether a named range contains an external reference to a
     193             :  * particular document.
     194             :  */
     195           0 : bool hasRefsToSrcDoc(ScRangeData& rData, sal_uInt16 nFileId)
     196             : {
     197           0 :     ScTokenArray* pArray = rData.GetCode();
     198           0 :     if (!pArray)
     199           0 :         return false;
     200             : 
     201           0 :     pArray->Reset();
     202           0 :     ScToken* p = static_cast<ScToken*>(pArray->GetNextReference());
     203           0 :     for (; p; p = static_cast<ScToken*>(pArray->GetNextReference()))
     204             :     {
     205           0 :         if (!p->IsExternalRef())
     206           0 :             continue;
     207             : 
     208           0 :         if (p->GetIndex() == nFileId)
     209           0 :             return true;
     210             :     }
     211           0 :     return false;
     212             : }
     213             : 
     214             : class EraseRangeByIterator : unary_function<ScRangeName::iterator, void>
     215             : {
     216             :     ScRangeName& mrRanges;
     217             : public:
     218           0 :     EraseRangeByIterator(ScRangeName& rRanges) : mrRanges(rRanges) {}
     219           0 :     void operator() (const ScRangeName::iterator& itr)
     220             :     {
     221           0 :         mrRanges.erase(itr);
     222           0 :     }
     223             : };
     224             : 
     225             : /**
     226             :  * Remove all named ranges that contain references to specified source
     227             :  * document.
     228             :  */
     229           0 : void removeRangeNamesBySrcDoc(ScRangeName& rRanges, sal_uInt16 nFileId)
     230             : {
     231           0 :     ScRangeName::iterator itr = rRanges.begin(), itrEnd = rRanges.end();
     232           0 :     vector<ScRangeName::iterator> v;
     233           0 :     for (; itr != itrEnd; ++itr)
     234             :     {
     235           0 :         if (hasRefsToSrcDoc(*itr->second, nFileId))
     236           0 :             v.push_back(itr);
     237             :     }
     238           0 :     for_each(v.begin(), v.end(), EraseRangeByIterator(rRanges));
     239           0 : }
     240             : 
     241             : }
     242             : 
     243             : // ============================================================================
     244             : 
     245           4 : ScExternalRefCache::Table::Table()
     246           4 :     : meReferenced( REFERENCED_MARKED )
     247             :       // Prevent accidental data loss due to lack of knowledge.
     248             : {
     249           4 : }
     250             : 
     251           1 : ScExternalRefCache::Table::~Table()
     252             : {
     253           1 : }
     254             : 
     255           0 : void ScExternalRefCache::Table::setReferencedFlag( ScExternalRefCache::Table::ReferencedFlag eFlag )
     256             : {
     257           0 :     meReferenced = eFlag;
     258           0 : }
     259             : 
     260           0 : void ScExternalRefCache::Table::setReferenced( bool bReferenced )
     261             : {
     262           0 :     if (meReferenced != REFERENCED_PERMANENT)
     263           0 :         meReferenced = (bReferenced ? REFERENCED_MARKED : UNREFERENCED);
     264           0 : }
     265             : 
     266           0 : ScExternalRefCache::Table::ReferencedFlag ScExternalRefCache::Table::getReferencedFlag() const
     267             : {
     268           0 :     return meReferenced;
     269             : }
     270             : 
     271           0 : bool ScExternalRefCache::Table::isReferenced() const
     272             : {
     273           0 :     return meReferenced != UNREFERENCED;
     274             : }
     275             : 
     276          63 : void ScExternalRefCache::Table::setCell(SCCOL nCol, SCROW nRow, TokenRef pToken, sal_uLong nFmtIndex, bool bSetCacheRange)
     277             : {
     278             :     using ::std::pair;
     279          63 :     RowsDataType::iterator itrRow = maRows.find(nRow);
     280          63 :     if (itrRow == maRows.end())
     281             :     {
     282             :         // This row does not exist yet.
     283             :         pair<RowsDataType::iterator, bool> res = maRows.insert(
     284          16 :             RowsDataType::value_type(nRow, RowDataType()));
     285             : 
     286          16 :         if (!res.second)
     287          63 :             return;
     288             : 
     289          16 :         itrRow = res.first;
     290             :     }
     291             : 
     292             :     // Insert this token into the specified column location.  I don't need to
     293             :     // check for existing data.  Just overwrite it.
     294          63 :     RowDataType& rRow = itrRow->second;
     295          63 :     ScExternalRefCache::Cell aCell;
     296          63 :     aCell.mxToken = pToken;
     297          63 :     aCell.mnFmtIndex = nFmtIndex;
     298          63 :     rRow.insert(RowDataType::value_type(nCol, aCell));
     299          63 :     if (bSetCacheRange)
     300          45 :         setCachedCell(nCol, nRow);
     301             : }
     302             : 
     303           0 : ScExternalRefCache::TokenRef ScExternalRefCache::Table::getCell(SCCOL nCol, SCROW nRow, sal_uInt32* pnFmtIndex) const
     304             : {
     305           0 :     RowsDataType::const_iterator itrTable = maRows.find(nRow);
     306           0 :     if (itrTable == maRows.end())
     307             :     {
     308             :         // this table doesn't have the specified row.
     309           0 :         return getEmptyOrNullToken(nCol, nRow);
     310             :     }
     311             : 
     312           0 :     const RowDataType& rRowData = itrTable->second;
     313           0 :     RowDataType::const_iterator itrRow = rRowData.find(nCol);
     314           0 :     if (itrRow == rRowData.end())
     315             :     {
     316             :         // this row doesn't have the specified column.
     317           0 :         return getEmptyOrNullToken(nCol, nRow);
     318             :     }
     319             : 
     320           0 :     const Cell& rCell = itrRow->second;
     321           0 :     if (pnFmtIndex)
     322           0 :         *pnFmtIndex = rCell.mnFmtIndex;
     323             : 
     324           0 :     return rCell.mxToken;
     325             : }
     326             : 
     327           0 : bool ScExternalRefCache::Table::hasRow( SCROW nRow ) const
     328             : {
     329           0 :     RowsDataType::const_iterator itrRow = maRows.find(nRow);
     330           0 :     return itrRow != maRows.end();
     331             : }
     332             : 
     333           2 : void ScExternalRefCache::Table::getAllRows(vector<SCROW>& rRows, SCROW nLow, SCROW nHigh) const
     334             : {
     335           2 :     vector<SCROW> aRows;
     336           2 :     aRows.reserve(maRows.size());
     337           2 :     RowsDataType::const_iterator itr = maRows.begin(), itrEnd = maRows.end();
     338          11 :     for (; itr != itrEnd; ++itr)
     339           9 :         if (nLow <= itr->first && itr->first <= nHigh)
     340           9 :             aRows.push_back(itr->first);
     341             : 
     342             :     // hash map is not ordered, so we need to explicitly sort it.
     343           2 :     ::std::sort(aRows.begin(), aRows.end());
     344           2 :     rRows.swap(aRows);
     345           2 : }
     346             : 
     347           0 : ::std::pair< SCROW, SCROW > ScExternalRefCache::Table::getRowRange() const
     348             : {
     349           0 :     ::std::pair< SCROW, SCROW > aRange( 0, 0 );
     350           0 :     if( !maRows.empty() )
     351             :     {
     352             :         // iterate over entire container (hash map is not sorted by key)
     353           0 :         RowsDataType::const_iterator itr = maRows.begin(), itrEnd = maRows.end();
     354           0 :         aRange.first = itr->first;
     355           0 :         aRange.second = itr->first + 1;
     356           0 :         while( ++itr != itrEnd )
     357             :         {
     358           0 :             if( itr->first < aRange.first )
     359           0 :                 aRange.first = itr->first;
     360           0 :             else if( itr->first >= aRange.second )
     361           0 :                 aRange.second = itr->first + 1;
     362             :         }
     363             :     }
     364           0 :     return aRange;
     365             : }
     366             : 
     367           9 : void ScExternalRefCache::Table::getAllCols(SCROW nRow, vector<SCCOL>& rCols, SCCOL nLow, SCCOL nHigh) const
     368             : {
     369           9 :     RowsDataType::const_iterator itrRow = maRows.find(nRow);
     370           9 :     if (itrRow == maRows.end())
     371             :         // this table doesn't have the specified row.
     372           9 :         return;
     373             : 
     374           9 :     const RowDataType& rRowData = itrRow->second;
     375           9 :     vector<SCCOL> aCols;
     376           9 :     aCols.reserve(rRowData.size());
     377           9 :     RowDataType::const_iterator itrCol = rRowData.begin(), itrColEnd = rRowData.end();
     378          27 :     for (; itrCol != itrColEnd; ++itrCol)
     379          18 :         if (nLow <= itrCol->first && itrCol->first <= nHigh)
     380          18 :             aCols.push_back(itrCol->first);
     381             : 
     382             :     // hash map is not ordered, so we need to explicitly sort it.
     383           9 :     ::std::sort(aCols.begin(), aCols.end());
     384           9 :     rCols.swap(aCols);
     385             : }
     386             : 
     387           0 : ::std::pair< SCCOL, SCCOL > ScExternalRefCache::Table::getColRange( SCROW nRow ) const
     388             : {
     389           0 :     ::std::pair< SCCOL, SCCOL > aRange( 0, 0 );
     390             : 
     391           0 :     RowsDataType::const_iterator itrRow = maRows.find( nRow );
     392           0 :     if (itrRow == maRows.end())
     393             :         // this table doesn't have the specified row.
     394             :         return aRange;
     395             : 
     396           0 :     const RowDataType& rRowData = itrRow->second;
     397           0 :     if( !rRowData.empty() )
     398             :     {
     399             :         // iterate over entire container (hash map is not sorted by key)
     400           0 :         RowDataType::const_iterator itr = rRowData.begin(), itrEnd = rRowData.end();
     401           0 :         aRange.first = itr->first;
     402           0 :         aRange.second = itr->first + 1;
     403           0 :         while( ++itr != itrEnd )
     404             :         {
     405           0 :             if( itr->first < aRange.first )
     406           0 :                 aRange.first = itr->first;
     407           0 :             else if( itr->first >= aRange.second )
     408           0 :                 aRange.second = itr->first + 1;
     409             :         }
     410             :     }
     411             :     return aRange;
     412             : }
     413             : 
     414           0 : void ScExternalRefCache::Table::getAllNumberFormats(vector<sal_uInt32>& rNumFmts) const
     415             : {
     416           0 :     RowsDataType::const_iterator itrRow = maRows.begin(), itrRowEnd = maRows.end();
     417           0 :     for (; itrRow != itrRowEnd; ++itrRow)
     418             :     {
     419           0 :         const RowDataType& rRowData = itrRow->second;
     420           0 :         RowDataType::const_iterator itrCol = rRowData.begin(), itrColEnd = rRowData.end();
     421           0 :         for (; itrCol != itrColEnd; ++itrCol)
     422             :         {
     423           0 :             const Cell& rCell = itrCol->second;
     424           0 :             rNumFmts.push_back(rCell.mnFmtIndex);
     425             :         }
     426             :     }
     427           0 : }
     428             : 
     429           0 : bool ScExternalRefCache::Table::isRangeCached(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
     430             : {
     431           0 :     return maCachedRanges.In(ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0));
     432             : }
     433             : 
     434          90 : void ScExternalRefCache::Table::setCachedCell(SCCOL nCol, SCROW nRow)
     435             : {
     436          90 :     setCachedCellRange(nCol, nRow, nCol, nRow);
     437          90 : }
     438             : 
     439          96 : void ScExternalRefCache::Table::setCachedCellRange(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
     440             : {
     441          96 :     ScRange aRange(nCol1, nRow1, 0, nCol2, nRow2, 0);
     442          96 :     if ( maCachedRanges.empty() )
     443           4 :         maCachedRanges.Append(aRange);
     444             :     else
     445          92 :         maCachedRanges.Join(aRange);
     446             : 
     447          96 :     String aStr;
     448          96 :     maCachedRanges.Format(aStr, SCA_VALID);
     449          96 : }
     450             : 
     451           0 : void ScExternalRefCache::Table::setWholeTableCached()
     452             : {
     453           0 :     setCachedCellRange(0, 0, MAXCOL, MAXROW);
     454           0 : }
     455             : 
     456           0 : bool ScExternalRefCache::Table::isInCachedRanges(SCCOL nCol, SCROW nRow) const
     457             : {
     458           0 :     return maCachedRanges.In(ScRange(nCol, nRow, 0, nCol, nRow, 0));
     459             : }
     460             : 
     461           0 : ScExternalRefCache::TokenRef ScExternalRefCache::Table::getEmptyOrNullToken(
     462             :     SCCOL nCol, SCROW nRow) const
     463             : {
     464           0 :     if (isInCachedRanges(nCol, nRow))
     465             :     {
     466           0 :         TokenRef p(new ScEmptyCellToken(false, false));
     467           0 :         return p;
     468             :     }
     469           0 :     return TokenRef();
     470             : }
     471             : 
     472             : // ----------------------------------------------------------------------------
     473             : 
     474           8 : ScExternalRefCache::TableName::TableName(const OUString& rUpper, const OUString& rReal) :
     475           8 :     maUpperName(rUpper), maRealName(rReal)
     476             : {
     477           8 : }
     478             : 
     479             : // ----------------------------------------------------------------------------
     480             : 
     481          43 : ScExternalRefCache::CellFormat::CellFormat() :
     482          43 :     mbIsSet(false), mnType(NUMBERFORMAT_ALL), mnIndex(0)
     483             : {
     484          43 : }
     485             : 
     486             : // ----------------------------------------------------------------------------
     487             : 
     488          19 : ScExternalRefCache::ScExternalRefCache()
     489             : {
     490          19 : }
     491          15 : ScExternalRefCache::~ScExternalRefCache()
     492             : {
     493          15 : }
     494             : 
     495          29 : const OUString* ScExternalRefCache::getRealTableName(sal_uInt16 nFileId, const OUString& rTabName) const
     496             : {
     497          29 :     DocDataType::const_iterator itrDoc = maDocs.find(nFileId);
     498          29 :     if (itrDoc == maDocs.end())
     499             :     {
     500             :         // specified document is not cached.
     501           0 :         return NULL;
     502             :     }
     503             : 
     504          29 :     const DocItem& rDoc = itrDoc->second;
     505             :     TableNameIndexMap::const_iterator itrTabId = rDoc.maTableNameIndex.find(
     506          29 :         ScGlobal::pCharClass->uppercase(rTabName));
     507          29 :     if (itrTabId == rDoc.maTableNameIndex.end())
     508             :     {
     509             :         // the specified table is not in cache.
     510           0 :         return NULL;
     511             :     }
     512             : 
     513          29 :     return &rDoc.maTableNames[itrTabId->second].maRealName;
     514             : }
     515             : 
     516           0 : const OUString* ScExternalRefCache::getRealRangeName(sal_uInt16 nFileId, const OUString& rRangeName) const
     517             : {
     518           0 :     DocDataType::const_iterator itrDoc = maDocs.find(nFileId);
     519           0 :     if (itrDoc == maDocs.end())
     520             :     {
     521             :         // specified document is not cached.
     522           0 :         return NULL;
     523             :     }
     524             : 
     525           0 :     const DocItem& rDoc = itrDoc->second;
     526             :     NamePairMap::const_iterator itr = rDoc.maRealRangeNameMap.find(
     527           0 :         ScGlobal::pCharClass->uppercase(rRangeName));
     528           0 :     if (itr == rDoc.maRealRangeNameMap.end())
     529             :         // range name not found.
     530           0 :         return NULL;
     531             : 
     532           0 :     return &itr->second;
     533             : }
     534             : 
     535           0 : ScExternalRefCache::TokenRef ScExternalRefCache::getCellData(
     536             :     sal_uInt16 nFileId, const OUString& rTabName, SCCOL nCol, SCROW nRow, sal_uInt32* pnFmtIndex)
     537             : {
     538           0 :     DocDataType::const_iterator itrDoc = maDocs.find(nFileId);
     539           0 :     if (itrDoc == maDocs.end())
     540             :     {
     541             :         // specified document is not cached.
     542           0 :         return TokenRef();
     543             :     }
     544             : 
     545           0 :     const DocItem& rDoc = itrDoc->second;
     546             :     TableNameIndexMap::const_iterator itrTabId = rDoc.maTableNameIndex.find(
     547           0 :         ScGlobal::pCharClass->uppercase(rTabName));
     548           0 :     if (itrTabId == rDoc.maTableNameIndex.end())
     549             :     {
     550             :         // the specified table is not in cache.
     551           0 :         return TokenRef();
     552             :     }
     553             : 
     554           0 :     const TableTypeRef& pTableData = rDoc.maTables[itrTabId->second];
     555           0 :     if (!pTableData.get())
     556             :     {
     557             :         // the table data is not instantiated yet.
     558           0 :         return TokenRef();
     559             :     }
     560             : 
     561           0 :     return pTableData->getCell(nCol, nRow, pnFmtIndex);
     562             : }
     563             : 
     564           0 : ScExternalRefCache::TokenArrayRef ScExternalRefCache::getCellRangeData(
     565             :     sal_uInt16 nFileId, const OUString& rTabName, const ScRange& rRange)
     566             : {
     567           0 :     DocDataType::iterator itrDoc = maDocs.find(nFileId);
     568           0 :     if (itrDoc == maDocs.end())
     569             :         // specified document is not cached.
     570           0 :         return TokenArrayRef();
     571             : 
     572           0 :     DocItem& rDoc = itrDoc->second;
     573             : 
     574             :     TableNameIndexMap::iterator itrTabId = rDoc.maTableNameIndex.find(
     575           0 :         ScGlobal::pCharClass->uppercase(rTabName));
     576           0 :     if (itrTabId == rDoc.maTableNameIndex.end())
     577             :         // the specified table is not in cache.
     578           0 :         return TokenArrayRef();
     579             : 
     580           0 :     const ScAddress& s = rRange.aStart;
     581           0 :     const ScAddress& e = rRange.aEnd;
     582             : 
     583           0 :     SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
     584           0 :     SCCOL nCol1 = s.Col(), nCol2 = e.Col();
     585           0 :     SCROW nRow1 = s.Row(), nRow2 = e.Row();
     586             : 
     587             :     // Make sure I have all the tables cached.
     588           0 :     size_t nTabFirstId = itrTabId->second;
     589           0 :     size_t nTabLastId  = nTabFirstId + nTab2 - nTab1;
     590           0 :     if (nTabLastId >= rDoc.maTables.size())
     591             :         // not all tables are cached.
     592           0 :         return TokenArrayRef();
     593             : 
     594           0 :     ScRange aCacheRange( nCol1, nRow1, static_cast<SCTAB>(nTabFirstId), nCol2, nRow2, static_cast<SCTAB>(nTabLastId));
     595             : 
     596           0 :     RangeArrayMap::const_iterator itrRange = rDoc.maRangeArrays.find( aCacheRange);
     597           0 :     if (itrRange != rDoc.maRangeArrays.end())
     598             :         // Cache hit!
     599           0 :         return itrRange->second;
     600             : 
     601           0 :     ::boost::scoped_ptr<ScRange> pNewRange;
     602           0 :     TokenArrayRef pArray;
     603           0 :     bool bFirstTab = true;
     604           0 :     for (size_t nTab = nTabFirstId; nTab <= nTabLastId; ++nTab)
     605             :     {
     606           0 :         TableTypeRef pTab = rDoc.maTables[nTab];
     607           0 :         if (!pTab.get())
     608           0 :             return TokenArrayRef();
     609             : 
     610           0 :         SCCOL nDataCol1 = nCol1, nDataCol2 = nCol2;
     611           0 :         SCROW nDataRow1 = nRow1, nDataRow2 = nRow2;
     612             : 
     613           0 :         if (!pTab->isRangeCached(nDataCol1, nDataRow1, nDataCol2, nDataRow2))
     614             :         {
     615             :             // specified range is not entirely within cached ranges.
     616           0 :             return TokenArrayRef();
     617             :         }
     618             : 
     619             :         ScMatrixRef xMat = new ScMatrix(
     620           0 :             static_cast<SCSIZE>(nDataCol2-nDataCol1+1), static_cast<SCSIZE>(nDataRow2-nDataRow1+1));
     621             : 
     622             :         // Only fill non-empty cells, for better performance.
     623           0 :         vector<SCROW> aRows;
     624           0 :         pTab->getAllRows(aRows, nDataRow1, nDataRow2);
     625           0 :         for (vector<SCROW>::const_iterator itr = aRows.begin(), itrEnd = aRows.end(); itr != itrEnd; ++itr)
     626             :         {
     627           0 :             SCROW nRow = *itr;
     628           0 :             vector<SCCOL> aCols;
     629           0 :             pTab->getAllCols(nRow, aCols, nDataCol1, nDataCol2);
     630           0 :             for (vector<SCCOL>::const_iterator itrCol = aCols.begin(), itrColEnd = aCols.end(); itrCol != itrColEnd; ++itrCol)
     631             :             {
     632           0 :                 SCCOL nCol = *itrCol;
     633           0 :                 TokenRef pToken = pTab->getCell(nCol, nRow);
     634           0 :                 if (!pToken)
     635             :                     // This should never happen!
     636           0 :                     return TokenArrayRef();
     637             : 
     638           0 :                 SCSIZE nC = nCol - nDataCol1, nR = nRow - nDataRow1;
     639           0 :                 switch (pToken->GetType())
     640             :                 {
     641             :                     case svDouble:
     642           0 :                         xMat->PutDouble(pToken->GetDouble(), nC, nR);
     643           0 :                     break;
     644             :                     case svString:
     645           0 :                         xMat->PutString(pToken->GetString(), nC, nR);
     646           0 :                     break;
     647             :                     default:
     648             :                         ;
     649             :                 }
     650           0 :             }
     651           0 :         }
     652             : 
     653           0 :         if (!bFirstTab)
     654           0 :             pArray->AddOpCode(ocSep);
     655             : 
     656           0 :         ScMatrixToken aToken(xMat);
     657           0 :         if (!pArray)
     658           0 :             pArray.reset(new ScTokenArray);
     659           0 :         pArray->AddToken(aToken);
     660             : 
     661           0 :         bFirstTab = false;
     662             : 
     663           0 :         if (!pNewRange)
     664           0 :             pNewRange.reset(new ScRange(nDataCol1, nDataRow1, 0, nDataCol2, nDataRow2, 0));
     665             :         else
     666           0 :             pNewRange->ExtendTo(ScRange(nDataCol1, nDataRow1, 0, nDataCol2, nDataRow2, 0));
     667           0 :     }
     668             : 
     669           0 :     if (pNewRange)
     670           0 :         rDoc.maRangeArrays.insert( RangeArrayMap::value_type(*pNewRange, pArray));
     671           0 :     return pArray;
     672             : }
     673             : 
     674           0 : ScExternalRefCache::TokenArrayRef ScExternalRefCache::getRangeNameTokens(sal_uInt16 nFileId, const OUString& rName)
     675             : {
     676           0 :     DocItem* pDoc = getDocItem(nFileId);
     677           0 :     if (!pDoc)
     678           0 :         return TokenArrayRef();
     679             : 
     680           0 :     RangeNameMap& rMap = pDoc->maRangeNames;
     681             :     RangeNameMap::const_iterator itr = rMap.find(
     682           0 :         ScGlobal::pCharClass->uppercase(rName));
     683           0 :     if (itr == rMap.end())
     684           0 :         return TokenArrayRef();
     685             : 
     686           0 :     return itr->second;
     687             : }
     688             : 
     689           0 : void ScExternalRefCache::setRangeNameTokens(sal_uInt16 nFileId, const OUString& rName, TokenArrayRef pArray)
     690             : {
     691           0 :     DocItem* pDoc = getDocItem(nFileId);
     692           0 :     if (!pDoc)
     693           0 :         return;
     694             : 
     695           0 :     String aUpperName = ScGlobal::pCharClass->uppercase(rName);
     696           0 :     RangeNameMap& rMap = pDoc->maRangeNames;
     697           0 :     rMap.insert(RangeNameMap::value_type(aUpperName, pArray));
     698           0 :     pDoc->maRealRangeNameMap.insert(NamePairMap::value_type(aUpperName, rName));
     699             : }
     700             : 
     701          45 : void ScExternalRefCache::setCellData(sal_uInt16 nFileId, const OUString& rTabName, SCCOL nCol, SCROW nRow,
     702             :                                      TokenRef pToken, sal_uLong nFmtIndex)
     703             : {
     704          45 :     if (!isDocInitialized(nFileId))
     705             :         return;
     706             : 
     707             :     using ::std::pair;
     708          45 :     DocItem* pDocItem = getDocItem(nFileId);
     709          45 :     if (!pDocItem)
     710             :         return;
     711             : 
     712          45 :     DocItem& rDoc = *pDocItem;
     713             : 
     714             :     // See if the table by this name already exists.
     715             :     TableNameIndexMap::iterator itrTabName = rDoc.maTableNameIndex.find(
     716          45 :         ScGlobal::pCharClass->uppercase(rTabName));
     717          45 :     if (itrTabName == rDoc.maTableNameIndex.end())
     718             :         // Table not found.  Maybe the table name or the file id is wrong ???
     719             :         return;
     720             : 
     721          45 :     TableTypeRef& pTableData = rDoc.maTables[itrTabName->second];
     722          45 :     if (!pTableData.get())
     723           4 :         pTableData.reset(new Table);
     724             : 
     725          45 :     pTableData->setCell(nCol, nRow, pToken, nFmtIndex);
     726          45 :     pTableData->setCachedCell(nCol, nRow);
     727             : }
     728             : 
     729           6 : void ScExternalRefCache::setCellRangeData(sal_uInt16 nFileId, const ScRange& rRange, const vector<SingleRangeData>& rData,
     730             :                                           const TokenArrayRef& pArray)
     731             : {
     732             :     using ::std::pair;
     733           6 :     if (rData.empty() || !isDocInitialized(nFileId))
     734             :         // nothing to cache
     735             :         return;
     736             : 
     737             :     // First, get the document item for the given file ID.
     738           6 :     DocItem* pDocItem = getDocItem(nFileId);
     739           6 :     if (!pDocItem)
     740             :         return;
     741             : 
     742           6 :     DocItem& rDoc = *pDocItem;
     743             : 
     744             :     // Now, find the table position of the first table to cache.
     745           6 :     const String& rFirstTabName = rData.front().maTableName;
     746             :     TableNameIndexMap::iterator itrTabName = rDoc.maTableNameIndex.find(
     747           6 :         ScGlobal::pCharClass->uppercase(rFirstTabName));
     748           6 :     if (itrTabName == rDoc.maTableNameIndex.end())
     749             :     {
     750             :         // table index not found.
     751             :         return;
     752             :     }
     753             : 
     754           6 :     size_t nTabFirstId = itrTabName->second;
     755           6 :     SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
     756           6 :     SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
     757           6 :     vector<SingleRangeData>::const_iterator itrDataBeg = rData.begin(), itrDataEnd = rData.end();
     758          12 :     for (vector<SingleRangeData>::const_iterator itrData = itrDataBeg; itrData != itrDataEnd; ++itrData)
     759             :     {
     760           6 :         size_t i = nTabFirstId + ::std::distance(itrDataBeg, itrData);
     761           6 :         TableTypeRef& pTabData = rDoc.maTables[i];
     762           6 :         if (!pTabData.get())
     763           0 :             pTabData.reset(new Table);
     764             : 
     765          27 :         for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
     766             :         {
     767          42 :             for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
     768             :             {
     769          21 :                 SCSIZE nC = nCol - nCol1, nR = nRow - nRow1;
     770          21 :                 TokenRef pToken;
     771          21 :                 const ScMatrixRef& pMat = itrData->mpRangeData;
     772          21 :                 if (pMat->IsEmpty(nC, nR))
     773             :                     // Don't cache empty cells.
     774           3 :                     continue;
     775             : 
     776          18 :                 if (pMat->IsValue(nC, nR))
     777          18 :                     pToken.reset(new formula::FormulaDoubleToken(pMat->GetDouble(nC, nR)));
     778           0 :                 else if (pMat->IsString(nC, nR))
     779           0 :                     pToken.reset(new formula::FormulaStringToken(pMat->GetString(nC, nR)));
     780             : 
     781          18 :                 if (pToken)
     782             :                     // Don't mark this cell 'cached' here, for better performance.
     783          18 :                     pTabData->setCell(nCol, nRow, pToken, 0, false);
     784          21 :             }
     785             :         }
     786             :         // Mark the whole range 'cached'.
     787           6 :         pTabData->setCachedCellRange(nCol1, nRow1, nCol2, nRow2);
     788             :     }
     789             : 
     790           6 :     size_t nTabLastId = nTabFirstId + rRange.aEnd.Tab() - rRange.aStart.Tab();
     791           6 :     ScRange aCacheRange( nCol1, nRow1, static_cast<SCTAB>(nTabFirstId), nCol2, nRow2, static_cast<SCTAB>(nTabLastId));
     792             : 
     793           6 :     rDoc.maRangeArrays.insert( RangeArrayMap::value_type( aCacheRange, pArray));
     794             : }
     795             : 
     796         109 : bool ScExternalRefCache::isDocInitialized(sal_uInt16 nFileId)
     797             : {
     798         109 :     DocItem* pDoc = getDocItem(nFileId);
     799         109 :     if (!pDoc)
     800           0 :         return false;
     801             : 
     802         109 :     return pDoc->mbInitFromSource;
     803             : }
     804             : 
     805          11 : static bool lcl_getTableDataIndex(const ScExternalRefCache::TableNameIndexMap& rMap, const String& rName, size_t& rIndex)
     806             : {
     807          11 :     ScExternalRefCache::TableNameIndexMap::const_iterator itr = rMap.find(rName);
     808          11 :     if (itr == rMap.end())
     809           8 :         return false;
     810             : 
     811           3 :     rIndex = itr->second;
     812           3 :     return true;
     813             : }
     814             : 
     815           3 : void ScExternalRefCache::initializeDoc(sal_uInt16 nFileId, const vector<OUString>& rTabNames)
     816             : {
     817           3 :     DocItem* pDoc = getDocItem(nFileId);
     818           3 :     if (!pDoc)
     819           3 :         return;
     820             : 
     821           3 :     size_t n = rTabNames.size();
     822             : 
     823             :     // table name list - the list must include all table names in the source
     824             :     // document and only to be populated when loading the source document, not
     825             :     // when loading cached data from, say, Excel XCT/CRN records.
     826           3 :     vector<TableName> aNewTabNames;
     827           3 :     aNewTabNames.reserve(n);
     828          11 :     for (vector<OUString>::const_iterator itr = rTabNames.begin(), itrEnd = rTabNames.end();
     829             :           itr != itrEnd; ++itr)
     830             :     {
     831           8 :         TableName aNameItem(ScGlobal::pCharClass->uppercase(*itr), *itr);
     832           8 :         aNewTabNames.push_back(aNameItem);
     833           8 :     }
     834           3 :     pDoc->maTableNames.swap(aNewTabNames);
     835             : 
     836             :     // data tables - preserve any existing data that may have been set during
     837             :     // file import.
     838           3 :     vector<TableTypeRef> aNewTables(n);
     839          11 :     for (size_t i = 0; i < n; ++i)
     840             :     {
     841             :         size_t nIndex;
     842           8 :         if (lcl_getTableDataIndex(pDoc->maTableNameIndex, pDoc->maTableNames[i].maUpperName, nIndex))
     843             :         {
     844           0 :             aNewTables[i] = pDoc->maTables[nIndex];
     845             :         }
     846             :     }
     847           3 :     pDoc->maTables.swap(aNewTables);
     848             : 
     849             :     // name index map
     850           3 :     TableNameIndexMap aNewNameIndex;
     851          11 :     for (size_t i = 0; i < n; ++i)
     852           8 :         aNewNameIndex.insert(TableNameIndexMap::value_type(pDoc->maTableNames[i].maUpperName, i));
     853           3 :     pDoc->maTableNameIndex.swap(aNewNameIndex);
     854             : 
     855           3 :     pDoc->mbInitFromSource = true;
     856             : }
     857             : 
     858           0 : String ScExternalRefCache::getTableName(sal_uInt16 nFileId, size_t nCacheId) const
     859             : {
     860           0 :     if( DocItem* pDoc = getDocItem( nFileId ) )
     861           0 :         if( nCacheId < pDoc->maTableNames.size() )
     862           0 :             return pDoc->maTableNames[ nCacheId ].maRealName;
     863           0 :     return EMPTY_STRING;
     864             : }
     865             : 
     866           1 : void ScExternalRefCache::getAllTableNames(sal_uInt16 nFileId, vector<OUString>& rTabNames) const
     867             : {
     868           1 :     rTabNames.clear();
     869           1 :     DocItem* pDoc = getDocItem(nFileId);
     870           1 :     if (!pDoc)
     871           1 :         return;
     872             : 
     873           1 :     size_t n = pDoc->maTableNames.size();
     874           1 :     rTabNames.reserve(n);
     875           5 :     for (vector<TableName>::const_iterator itr = pDoc->maTableNames.begin(), itrEnd = pDoc->maTableNames.end();
     876             :           itr != itrEnd; ++itr)
     877           4 :         rTabNames.push_back(itr->maRealName);
     878             : }
     879             : 
     880           0 : SCsTAB ScExternalRefCache::getTabSpan( sal_uInt16 nFileId, const OUString& rStartTabName, const OUString& rEndTabName ) const
     881             : {
     882           0 :     DocItem* pDoc = getDocItem(nFileId);
     883           0 :     if (!pDoc)
     884           0 :         return -1;
     885             : 
     886           0 :     vector<TableName>::const_iterator itrBeg = pDoc->maTableNames.begin();
     887           0 :     vector<TableName>::const_iterator itrEnd = pDoc->maTableNames.end();
     888             : 
     889             :     vector<TableName>::const_iterator itrStartTab = ::std::find_if( itrBeg, itrEnd,
     890           0 :             TabNameSearchPredicate( rStartTabName));
     891           0 :     if (itrStartTab == itrEnd)
     892           0 :         return -1;
     893             : 
     894             :     vector<TableName>::const_iterator itrEndTab = ::std::find_if( itrBeg, itrEnd,
     895           0 :             TabNameSearchPredicate( rEndTabName));
     896           0 :     if (itrEndTab == itrEnd)
     897           0 :         return 0;
     898             : 
     899           0 :     size_t nStartDist = ::std::distance( itrBeg, itrStartTab);
     900           0 :     size_t nEndDist = ::std::distance( itrBeg, itrEndTab);
     901           0 :     return nStartDist <= nEndDist ? static_cast<SCsTAB>(nEndDist - nStartDist + 1) : -static_cast<SCsTAB>(nStartDist - nEndDist + 1);
     902             : }
     903             : 
     904           0 : void ScExternalRefCache::getAllNumberFormats(vector<sal_uInt32>& rNumFmts) const
     905             : {
     906             :     using ::std::sort;
     907             :     using ::std::unique;
     908             : 
     909           0 :     vector<sal_uInt32> aNumFmts;
     910           0 :     for (DocDataType::const_iterator itrDoc = maDocs.begin(), itrDocEnd = maDocs.end();
     911             :           itrDoc != itrDocEnd; ++itrDoc)
     912             :     {
     913           0 :         const vector<TableTypeRef>& rTables = itrDoc->second.maTables;
     914           0 :         for (vector<TableTypeRef>::const_iterator itrTab = rTables.begin(), itrTabEnd = rTables.end();
     915             :               itrTab != itrTabEnd; ++itrTab)
     916             :         {
     917           0 :             TableTypeRef pTab = *itrTab;
     918           0 :             if (!pTab)
     919           0 :                 continue;
     920             : 
     921           0 :             pTab->getAllNumberFormats(aNumFmts);
     922           0 :         }
     923             :     }
     924             : 
     925             :     // remove duplicates.
     926           0 :     sort(aNumFmts.begin(), aNumFmts.end());
     927           0 :     aNumFmts.erase(unique(aNumFmts.begin(), aNumFmts.end()), aNumFmts.end());
     928           0 :     rNumFmts.swap(aNumFmts);
     929           0 : }
     930             : 
     931           0 : bool ScExternalRefCache::setCacheDocReferenced( sal_uInt16 nFileId )
     932             : {
     933           0 :     DocItem* pDocItem = getDocItem(nFileId);
     934           0 :     if (!pDocItem)
     935           0 :         return areAllCacheTablesReferenced();
     936             : 
     937           0 :     for (::std::vector<TableTypeRef>::iterator itrTab = pDocItem->maTables.begin();
     938           0 :             itrTab != pDocItem->maTables.end(); ++itrTab)
     939             :     {
     940           0 :         if ((*itrTab).get())
     941           0 :             (*itrTab)->setReferenced( true);
     942             :     }
     943           0 :     addCacheDocToReferenced( nFileId);
     944           0 :     return areAllCacheTablesReferenced();
     945             : }
     946             : 
     947           0 : bool ScExternalRefCache::setCacheTableReferenced( sal_uInt16 nFileId, const OUString& rTabName, size_t nSheets, bool bPermanent )
     948             : {
     949           0 :     DocItem* pDoc = getDocItem(nFileId);
     950           0 :     if (pDoc)
     951             :     {
     952           0 :         size_t nIndex = 0;
     953           0 :         String aTabNameUpper = ScGlobal::pCharClass->uppercase( rTabName);
     954           0 :         if (lcl_getTableDataIndex( pDoc->maTableNameIndex, aTabNameUpper, nIndex))
     955             :         {
     956           0 :             size_t nStop = ::std::min( nIndex + nSheets, pDoc->maTables.size());
     957           0 :             for (size_t i = nIndex; i < nStop; ++i)
     958             :             {
     959           0 :                 TableTypeRef pTab = pDoc->maTables[i];
     960           0 :                 if (pTab.get())
     961             :                 {
     962             :                     Table::ReferencedFlag eNewFlag = (bPermanent ?
     963             :                             Table::REFERENCED_PERMANENT :
     964           0 :                             Table::REFERENCED_MARKED);
     965           0 :                     Table::ReferencedFlag eOldFlag = pTab->getReferencedFlag();
     966           0 :                     if (eOldFlag != Table::REFERENCED_PERMANENT && eNewFlag != eOldFlag)
     967             :                     {
     968           0 :                         pTab->setReferencedFlag( eNewFlag);
     969           0 :                         addCacheTableToReferenced( nFileId, i);
     970             :                     }
     971             :                 }
     972           0 :             }
     973           0 :         }
     974             :     }
     975           0 :     return areAllCacheTablesReferenced();
     976             : }
     977             : 
     978           0 : void ScExternalRefCache::setAllCacheTableReferencedStati( bool bReferenced )
     979             : {
     980           0 :     if (bReferenced)
     981             :     {
     982           0 :         maReferenced.reset(0);
     983           0 :         for (DocDataType::iterator itrDoc = maDocs.begin(); itrDoc != maDocs.end(); ++itrDoc)
     984             :         {
     985           0 :             ScExternalRefCache::DocItem& rDocItem = (*itrDoc).second;
     986           0 :             for (::std::vector<TableTypeRef>::iterator itrTab = rDocItem.maTables.begin();
     987           0 :                     itrTab != rDocItem.maTables.end(); ++itrTab)
     988             :             {
     989           0 :                 if ((*itrTab).get())
     990           0 :                     (*itrTab)->setReferenced( true);
     991             :             }
     992             :         }
     993             :     }
     994             :     else
     995             :     {
     996           0 :         size_t nDocs = 0;
     997           0 :         for (DocDataType::const_iterator itrDoc = maDocs.begin(); itrDoc != maDocs.end(); ++itrDoc)
     998             :         {
     999           0 :             if (nDocs <= (*itrDoc).first)
    1000           0 :                 nDocs  = (*itrDoc).first + 1;
    1001             :         }
    1002           0 :         maReferenced.reset( nDocs);
    1003             : 
    1004           0 :         for (DocDataType::iterator itrDoc = maDocs.begin(); itrDoc != maDocs.end(); ++itrDoc)
    1005             :         {
    1006           0 :             ScExternalRefCache::DocItem& rDocItem = (*itrDoc).second;
    1007           0 :             sal_uInt16 nFileId = (*itrDoc).first;
    1008           0 :             size_t nTables = rDocItem.maTables.size();
    1009           0 :             ReferencedStatus::DocReferenced & rDocReferenced = maReferenced.maDocs[nFileId];
    1010             :             // All referenced => non-existing tables evaluate as completed.
    1011           0 :             rDocReferenced.maTables.resize( nTables, true);
    1012           0 :             for (size_t i=0; i < nTables; ++i)
    1013             :             {
    1014           0 :                 TableTypeRef & xTab = rDocItem.maTables[i];
    1015           0 :                 if (xTab.get())
    1016             :                 {
    1017           0 :                     if (xTab->getReferencedFlag() == Table::REFERENCED_PERMANENT)
    1018           0 :                         addCacheTableToReferenced( nFileId, i);
    1019             :                     else
    1020             :                     {
    1021           0 :                         xTab->setReferencedFlag( Table::UNREFERENCED);
    1022           0 :                         rDocReferenced.maTables[i] = false;
    1023           0 :                         rDocReferenced.mbAllTablesReferenced = false;
    1024             :                         // An addCacheTableToReferenced() actually may have
    1025             :                         // resulted in mbAllReferenced been set. Clear it.
    1026           0 :                         maReferenced.mbAllReferenced = false;
    1027             :                     }
    1028             :                 }
    1029             :             }
    1030             :         }
    1031             :     }
    1032           0 : }
    1033             : 
    1034           0 : void ScExternalRefCache::addCacheTableToReferenced( sal_uInt16 nFileId, size_t nIndex )
    1035             : {
    1036           0 :     if (nFileId >= maReferenced.maDocs.size())
    1037           0 :         return;
    1038             : 
    1039           0 :     ::std::vector<bool> & rTables = maReferenced.maDocs[nFileId].maTables;
    1040           0 :     size_t nTables = rTables.size();
    1041           0 :     if (nIndex >= nTables)
    1042           0 :         return;
    1043             : 
    1044           0 :     if (!rTables[nIndex])
    1045             :     {
    1046           0 :         rTables[nIndex] = true;
    1047           0 :         size_t i = 0;
    1048           0 :         while (i < nTables && rTables[i])
    1049           0 :             ++i;
    1050           0 :         if (i == nTables)
    1051             :         {
    1052           0 :             maReferenced.maDocs[nFileId].mbAllTablesReferenced = true;
    1053           0 :             maReferenced.checkAllDocs();
    1054             :         }
    1055             :     }
    1056             : }
    1057             : 
    1058           0 : void ScExternalRefCache::addCacheDocToReferenced( sal_uInt16 nFileId )
    1059             : {
    1060           0 :     if (nFileId >= maReferenced.maDocs.size())
    1061           0 :         return;
    1062             : 
    1063           0 :     if (!maReferenced.maDocs[nFileId].mbAllTablesReferenced)
    1064             :     {
    1065           0 :         ::std::vector<bool> & rTables = maReferenced.maDocs[nFileId].maTables;
    1066           0 :         size_t nSize = rTables.size();
    1067           0 :         for (size_t i=0; i < nSize; ++i)
    1068           0 :             rTables[i] = true;
    1069           0 :         maReferenced.maDocs[nFileId].mbAllTablesReferenced = true;
    1070           0 :         maReferenced.checkAllDocs();
    1071             :     }
    1072             : }
    1073             : 
    1074           0 : bool ScExternalRefCache::areAllCacheTablesReferenced() const
    1075             : {
    1076           0 :     return maReferenced.mbAllReferenced;
    1077             : }
    1078             : 
    1079          19 : ScExternalRefCache::ReferencedStatus::ReferencedStatus() :
    1080          19 :     mbAllReferenced(false)
    1081             : {
    1082          19 :     reset(0);
    1083          19 : }
    1084             : 
    1085          19 : void ScExternalRefCache::ReferencedStatus::reset( size_t nDocs )
    1086             : {
    1087          19 :     if (nDocs)
    1088             :     {
    1089           0 :         mbAllReferenced = false;
    1090           0 :         DocReferencedVec aRefs( nDocs);
    1091           0 :         maDocs.swap( aRefs);
    1092             :     }
    1093             :     else
    1094             :     {
    1095          19 :         mbAllReferenced = true;
    1096          19 :         DocReferencedVec aRefs;
    1097          19 :         maDocs.swap( aRefs);
    1098             :     }
    1099          19 : }
    1100             : 
    1101           0 : void ScExternalRefCache::ReferencedStatus::checkAllDocs()
    1102             : {
    1103           0 :     for (DocReferencedVec::const_iterator itr = maDocs.begin(); itr != maDocs.end(); ++itr)
    1104             :     {
    1105           0 :         if (!(*itr).mbAllTablesReferenced)
    1106           0 :             return;
    1107             :     }
    1108           0 :     mbAllReferenced = true;
    1109             : }
    1110             : 
    1111           0 : ScExternalRefCache::TableTypeRef ScExternalRefCache::getCacheTable(sal_uInt16 nFileId, size_t nTabIndex) const
    1112             : {
    1113           0 :     DocItem* pDoc = getDocItem(nFileId);
    1114           0 :     if (!pDoc || nTabIndex >= pDoc->maTables.size())
    1115           0 :         return TableTypeRef();
    1116             : 
    1117           0 :     return pDoc->maTables[nTabIndex];
    1118             : }
    1119             : 
    1120           3 : ScExternalRefCache::TableTypeRef ScExternalRefCache::getCacheTable(sal_uInt16 nFileId, const OUString& rTabName, bool bCreateNew, size_t* pnIndex)
    1121             : {
    1122             :     // In API, the index is transported as cached sheet ID of type sal_Int32 in
    1123             :     // sheet::SingleReference.Sheet or sheet::ComplexReference.Reference1.Sheet
    1124             :     // in a sheet::FormulaToken, choose a sensible value for N/A. Effectively
    1125             :     // being 0xffffffff
    1126           3 :     const size_t nNotAvailable = static_cast<size_t>( static_cast<sal_Int32>( -1));
    1127             : 
    1128           3 :     DocItem* pDoc = getDocItem(nFileId);
    1129           3 :     if (!pDoc)
    1130             :     {
    1131           0 :         if (pnIndex) *pnIndex = nNotAvailable;
    1132           0 :         return TableTypeRef();
    1133             :     }
    1134             : 
    1135           3 :     DocItem& rDoc = *pDoc;
    1136             : 
    1137             :     size_t nIndex;
    1138           3 :     String aTabNameUpper = ScGlobal::pCharClass->uppercase(rTabName);
    1139           3 :     if (lcl_getTableDataIndex(rDoc.maTableNameIndex, aTabNameUpper, nIndex))
    1140             :     {
    1141             :         // specified table found.
    1142           3 :         if( pnIndex ) *pnIndex = nIndex;
    1143           3 :         if (bCreateNew && !rDoc.maTables[nIndex])
    1144           0 :             rDoc.maTables[nIndex].reset(new Table);
    1145             : 
    1146           3 :         return rDoc.maTables[nIndex];
    1147             :     }
    1148             : 
    1149           0 :     if (!bCreateNew)
    1150             :     {
    1151           0 :         if (pnIndex) *pnIndex = nNotAvailable;
    1152           0 :         return TableTypeRef();
    1153             :     }
    1154             : 
    1155             :     // Specified table doesn't exist yet.  Create one.
    1156           0 :     nIndex = rDoc.maTables.size();
    1157           0 :     if( pnIndex ) *pnIndex = nIndex;
    1158           0 :     TableTypeRef pTab(new Table);
    1159           0 :     rDoc.maTables.push_back(pTab);
    1160           0 :     rDoc.maTableNames.push_back(TableName(aTabNameUpper, rTabName));
    1161             :     rDoc.maTableNameIndex.insert(
    1162           0 :         TableNameIndexMap::value_type(aTabNameUpper, nIndex));
    1163           0 :     return pTab;
    1164             : }
    1165             : 
    1166           1 : void ScExternalRefCache::clearCache(sal_uInt16 nFileId)
    1167             : {
    1168           1 :     maDocs.erase(nFileId);
    1169           1 : }
    1170             : 
    1171         167 : ScExternalRefCache::DocItem* ScExternalRefCache::getDocItem(sal_uInt16 nFileId) const
    1172             : {
    1173             :     using ::std::pair;
    1174         167 :     DocDataType::iterator itrDoc = maDocs.find(nFileId);
    1175         167 :     if (itrDoc == maDocs.end())
    1176             :     {
    1177             :         // specified document is not cached.
    1178             :         pair<DocDataType::iterator, bool> res = maDocs.insert(
    1179           3 :                 DocDataType::value_type(nFileId, DocItem()));
    1180             : 
    1181           3 :         if (!res.second)
    1182             :             // insertion failed.
    1183           0 :             return NULL;
    1184             : 
    1185           3 :         itrDoc = res.first;
    1186             :     }
    1187             : 
    1188         167 :     return &itrDoc->second;
    1189             : }
    1190             : 
    1191             : // ============================================================================
    1192             : 
    1193           2 : ScExternalRefLink::ScExternalRefLink(ScDocument* pDoc, sal_uInt16 nFileId, const String& rFilter) :
    1194             :     ::sfx2::SvBaseLink(::sfx2::LINKUPDATE_ONCALL, FORMAT_FILE),
    1195             :     mnFileId(nFileId),
    1196             :     maFilterName(rFilter),
    1197             :     mpDoc(pDoc),
    1198           2 :     mbDoRefresh(true)
    1199             : {
    1200           2 : }
    1201             : 
    1202           0 : ScExternalRefLink::~ScExternalRefLink()
    1203             : {
    1204           0 : }
    1205             : 
    1206           0 : void ScExternalRefLink::Closed()
    1207             : {
    1208           0 :     ScExternalRefManager* pMgr = mpDoc->GetExternalRefManager();
    1209           0 :     pMgr->breakLink(mnFileId);
    1210           0 : }
    1211             : 
    1212           2 : ::sfx2::SvBaseLink::UpdateResult ScExternalRefLink::DataChanged(const String& /*rMimeType*/, const Any& /*rValue*/)
    1213             : {
    1214           2 :     if (!mbDoRefresh)
    1215           2 :         return SUCCESS;
    1216             : 
    1217           0 :     rtl::OUString aFile, aFilter;
    1218           0 :     mpDoc->GetLinkManager()->GetDisplayNames(this, NULL, &aFile, NULL, &aFilter);
    1219           0 :     ScExternalRefManager* pMgr = mpDoc->GetExternalRefManager();
    1220             : 
    1221           0 :     if (!pMgr->isFileLoadable(aFile))
    1222           0 :         return ERROR_GENERAL;
    1223             : 
    1224           0 :     const OUString* pCurFile = pMgr->getExternalFileName(mnFileId);
    1225           0 :     if (!pCurFile)
    1226           0 :         return ERROR_GENERAL;
    1227             : 
    1228           0 :     if (pCurFile->equals(aFile))
    1229             :     {
    1230             :         // Refresh the current source document.
    1231           0 :         pMgr->refreshNames(mnFileId);
    1232             :     }
    1233             :     else
    1234             :     {
    1235             :         // The source document has changed.
    1236           0 :         ScDocShell* pDocShell = ScDocShell::GetViewData()->GetDocShell();
    1237           0 :         ScDocShellModificator aMod(*pDocShell);
    1238           0 :         pMgr->switchSrcFile(mnFileId, aFile, aFilter);
    1239           0 :         maFilterName = aFilter;
    1240           0 :         aMod.SetDocumentModified();
    1241             :     }
    1242             : 
    1243           0 :     return SUCCESS;
    1244             : }
    1245             : 
    1246           0 : void ScExternalRefLink::Edit(Window* pParent, const Link& /*rEndEditHdl*/)
    1247             : {
    1248           0 :     SvBaseLink::Edit(pParent, LINK(this, ScExternalRefLink, ExternalRefEndEditHdl));
    1249           0 : }
    1250             : 
    1251           4 : void ScExternalRefLink::SetDoReferesh(bool b)
    1252             : {
    1253           4 :     mbDoRefresh = b;
    1254           4 : }
    1255             : 
    1256           0 : IMPL_LINK_NOARG(ScExternalRefLink, ExternalRefEndEditHdl)
    1257             : {
    1258           0 :     return 0;
    1259             : }
    1260             : 
    1261             : // ============================================================================
    1262             : 
    1263          52 : static FormulaToken* lcl_convertToToken(ScBaseCell* pCell)
    1264             : {
    1265          52 :     if (!pCell || pCell->HasEmptyData())
    1266             :     {
    1267           7 :         bool bInherited = (pCell && pCell->GetCellType() == CELLTYPE_FORMULA);
    1268           7 :         return new ScEmptyCellToken( bInherited, false);
    1269             :     }
    1270             : 
    1271          45 :     switch (pCell->GetCellType())
    1272             :     {
    1273             :         case CELLTYPE_EDIT:
    1274             :         {
    1275           0 :             rtl::OUString aStr = static_cast<ScEditCell*>(pCell)->GetString();
    1276           0 :             return new formula::FormulaStringToken(aStr);
    1277             :         }
    1278             :         case CELLTYPE_STRING:
    1279             :         {
    1280          26 :             rtl::OUString aStr = static_cast<ScStringCell*>(pCell)->GetString();
    1281          26 :             return new formula::FormulaStringToken(aStr);
    1282             :         }
    1283             :         case CELLTYPE_VALUE:
    1284             :         {
    1285          19 :             double fVal = static_cast<ScValueCell*>(pCell)->GetValue();
    1286          19 :             return new formula::FormulaDoubleToken(fVal);
    1287             :         }
    1288             :         case CELLTYPE_FORMULA:
    1289             :         {
    1290           0 :             ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
    1291           0 :             sal_uInt16 nError = pFCell->GetErrCode();
    1292           0 :             if (nError)
    1293           0 :                 return new FormulaErrorToken( nError);
    1294           0 :             else if (pFCell->IsValue())
    1295             :             {
    1296           0 :                 double fVal = pFCell->GetValue();
    1297           0 :                 return new formula::FormulaDoubleToken(fVal);
    1298             :             }
    1299             :             else
    1300             :             {
    1301           0 :                 rtl::OUString aStr = pFCell->GetString();
    1302           0 :                 return new formula::FormulaStringToken(aStr);
    1303             :             }
    1304             :         }
    1305             :         default:
    1306             :             OSL_FAIL("attempted to convert an unknown cell type.");
    1307             :     }
    1308             : 
    1309           0 :     return NULL;
    1310             : }
    1311             : 
    1312           6 : static ScTokenArray* lcl_convertToTokenArray(const ScDocument* pSrcDoc, ScRange& rRange,
    1313             :                                              vector<ScExternalRefCache::SingleRangeData>& rCacheData)
    1314             : {
    1315           6 :     ScAddress& s = rRange.aStart;
    1316           6 :     ScAddress& e = rRange.aEnd;
    1317             : 
    1318           6 :     SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
    1319           6 :     SCCOL nCol1 = s.Col(), nCol2 = e.Col();
    1320           6 :     SCROW nRow1 = s.Row(), nRow2 = e.Row();
    1321             : 
    1322           6 :     if (nTab2 != nTab1)
    1323             :         // For now, we don't support multi-sheet ranges intentionally because
    1324             :         // we don't have a way to express them in a single token.  In the
    1325             :         // future we can introduce a new stack variable type svMatrixList with
    1326             :         // a new token type that can store a 3D matrix value and convert a 3D
    1327             :         // range to it.
    1328           0 :         return NULL;
    1329             : 
    1330           6 :     ::boost::scoped_ptr<ScRange> pUsedRange;
    1331             : 
    1332             :     SAL_WNODEPRECATED_DECLARATIONS_PUSH
    1333           6 :     auto_ptr<ScTokenArray> pArray(new ScTokenArray);
    1334             :     SAL_WNODEPRECATED_DECLARATIONS_POP
    1335           6 :     bool bFirstTab = true;
    1336             :     vector<ScExternalRefCache::SingleRangeData>::iterator
    1337           6 :         itrCache = rCacheData.begin(), itrCacheEnd = rCacheData.end();
    1338             : 
    1339          12 :     for (SCTAB nTab = nTab1; nTab <= nTab2 && itrCache != itrCacheEnd; ++nTab, ++itrCache)
    1340             :     {
    1341             :         // Only loop within the data area.
    1342           6 :         SCCOL nDataCol1 = nCol1, nDataCol2 = nCol2;
    1343           6 :         SCROW nDataRow1 = nRow1, nDataRow2 = nRow2;
    1344             :         bool bShrunk;
    1345           6 :         if (!pSrcDoc->ShrinkToUsedDataArea( bShrunk, nTab, nDataCol1, nDataRow1, nDataCol2, nDataRow2, false))
    1346             :             // no data within specified range.
    1347           0 :             continue;
    1348             : 
    1349           6 :         if (pUsedRange.get())
    1350             :             // Make sure the used area only grows, not shrinks.
    1351           0 :             pUsedRange->ExtendTo(ScRange(nDataCol1, nDataRow1, 0, nDataCol2, nDataRow2, 0));
    1352             :         else
    1353           6 :             pUsedRange.reset(new ScRange(nDataCol1, nDataRow1, 0, nDataCol2, nDataRow2, 0));
    1354             : 
    1355             :         ScMatrixRef xMat = new ScMatrix(
    1356           6 :             static_cast<SCSIZE>(nCol2-nCol1+1), static_cast<SCSIZE>(nRow2-nRow1+1));
    1357             : 
    1358          12 :         for (SCCOL nCol = nDataCol1; nCol <= nDataCol2; ++nCol)
    1359             :         {
    1360          27 :             for (SCROW nRow = nDataRow1; nRow <= nDataRow2; ++nRow)
    1361             :             {
    1362          21 :                 SCSIZE nC = nCol - nCol1, nR = nRow - nRow1;
    1363             :                 ScBaseCell* pCell;
    1364          21 :                 pSrcDoc->GetCell(nCol, nRow, nTab, pCell);
    1365          21 :                 if (!pCell || pCell->HasEmptyData())
    1366             :                     // Skip empty cells.  Matrix's default values are empty elements.
    1367           0 :                     continue;
    1368             : 
    1369          21 :                 switch (pCell->GetCellType())
    1370             :                 {
    1371             :                     case CELLTYPE_EDIT:
    1372             :                     {
    1373           0 :                         rtl::OUString aStr = static_cast<ScEditCell*>(pCell)->GetString();
    1374           0 :                         xMat->PutString(aStr, nC, nR);
    1375             :                     }
    1376           0 :                     break;
    1377             :                     case CELLTYPE_STRING:
    1378             :                     {
    1379           0 :                         rtl::OUString aStr = static_cast<ScStringCell*>(pCell)->GetString();
    1380           0 :                         xMat->PutString(aStr, nC, nR);
    1381             :                     }
    1382           0 :                     break;
    1383             :                     case CELLTYPE_VALUE:
    1384             :                     {
    1385          21 :                         double fVal = static_cast<ScValueCell*>(pCell)->GetValue();
    1386          21 :                         xMat->PutDouble(fVal, nC, nR);
    1387             :                     }
    1388          21 :                     break;
    1389             :                     case CELLTYPE_FORMULA:
    1390             :                     {
    1391           0 :                         ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
    1392           0 :                         sal_uInt16 nError = pFCell->GetErrCode();
    1393           0 :                         if (nError)
    1394           0 :                             xMat->PutDouble( CreateDoubleError( nError), nC, nR);
    1395           0 :                         else if (pFCell->IsValue())
    1396             :                         {
    1397           0 :                             double fVal = pFCell->GetValue();
    1398           0 :                             xMat->PutDouble(fVal, nC, nR);
    1399             :                         }
    1400             :                         else
    1401             :                         {
    1402           0 :                             rtl::OUString aStr = pFCell->GetString();
    1403           0 :                             xMat->PutString(aStr, nC, nR);
    1404             :                         }
    1405             :                     }
    1406           0 :                     break;
    1407             :                     default:
    1408             :                         OSL_FAIL("attempted to convert an unknown cell type.");
    1409             :                 }
    1410             :             }
    1411             :         }
    1412           6 :         if (!bFirstTab)
    1413           0 :             pArray->AddOpCode(ocSep);
    1414             : 
    1415           6 :         ScMatrixToken aToken(xMat);
    1416           6 :         pArray->AddToken(aToken);
    1417             : 
    1418           6 :         itrCache->mpRangeData = xMat;
    1419             : 
    1420           6 :         bFirstTab = false;
    1421           6 :     }
    1422             : 
    1423           6 :     if (!pUsedRange.get())
    1424           0 :         return NULL;
    1425             : 
    1426           6 :     s.SetCol(pUsedRange->aStart.Col());
    1427           6 :     s.SetRow(pUsedRange->aStart.Row());
    1428           6 :     e.SetCol(pUsedRange->aEnd.Col());
    1429           6 :     e.SetRow(pUsedRange->aEnd.Row());
    1430             : 
    1431           6 :     return pArray.release();
    1432             : }
    1433             : 
    1434           0 : static ScTokenArray* lcl_fillEmptyMatrix(const ScRange& rRange)
    1435             : {
    1436           0 :     SCSIZE nC = static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1);
    1437           0 :     SCSIZE nR = static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1);
    1438           0 :     ScMatrixRef xMat = new ScMatrix(nC, nR);
    1439             : 
    1440           0 :     ScMatrixToken aToken(xMat);
    1441             :     SAL_WNODEPRECATED_DECLARATIONS_PUSH
    1442           0 :     auto_ptr<ScTokenArray> pArray(new ScTokenArray);
    1443             :     SAL_WNODEPRECATED_DECLARATIONS_POP
    1444           0 :     pArray->AddToken(aToken);
    1445           0 :     return pArray.release();
    1446             : }
    1447             : 
    1448          19 : ScExternalRefManager::ScExternalRefManager(ScDocument* pDoc) :
    1449             :     mpDoc(pDoc),
    1450             :     mbInReferenceMarking(false),
    1451          19 :     mbUserInteractionEnabled(true)
    1452             : {
    1453          19 :     maSrcDocTimer.SetTimeoutHdl( LINK(this, ScExternalRefManager, TimeOutHdl) );
    1454          19 :     maSrcDocTimer.SetTimeout(SRCDOC_SCAN_INTERVAL);
    1455          19 : }
    1456             : 
    1457          45 : ScExternalRefManager::~ScExternalRefManager()
    1458             : {
    1459          15 :     clear();
    1460          30 : }
    1461             : 
    1462           0 : OUString ScExternalRefManager::getCacheTableName(sal_uInt16 nFileId, size_t nTabIndex) const
    1463             : {
    1464           0 :     return maRefCache.getTableName(nFileId, nTabIndex);
    1465             : }
    1466             : 
    1467           0 : ScExternalRefCache::TableTypeRef ScExternalRefManager::getCacheTable(sal_uInt16 nFileId, size_t nTabIndex) const
    1468             : {
    1469           0 :     return maRefCache.getCacheTable(nFileId, nTabIndex);
    1470             : }
    1471             : 
    1472           3 : ScExternalRefCache::TableTypeRef ScExternalRefManager::getCacheTable(
    1473             :     sal_uInt16 nFileId, const OUString& rTabName, bool bCreateNew, size_t* pnIndex)
    1474             : {
    1475           3 :     return maRefCache.getCacheTable(nFileId, rTabName, bCreateNew, pnIndex);
    1476             : }
    1477             : 
    1478             : // ============================================================================
    1479             : 
    1480           0 : ScExternalRefManager::LinkListener::LinkListener()
    1481             : {
    1482           0 : }
    1483             : 
    1484           0 : ScExternalRefManager::LinkListener::~LinkListener()
    1485             : {
    1486           0 : }
    1487             : 
    1488             : // ----------------------------------------------------------------------------
    1489             : 
    1490         392 : ScExternalRefManager::ApiGuard::ApiGuard(ScDocument* pDoc) :
    1491         392 :     mpMgr(pDoc->GetExternalRefManager()),
    1492         392 :     mbOldInteractionEnabled(mpMgr->mbUserInteractionEnabled)
    1493             : {
    1494             :     // We don't want user interaction handled in the API.
    1495         392 :     mpMgr->mbUserInteractionEnabled = false;
    1496         392 : }
    1497             : 
    1498         392 : ScExternalRefManager::ApiGuard::~ApiGuard()
    1499             : {
    1500             :     // Restore old value.
    1501         392 :     mpMgr->mbUserInteractionEnabled = mbOldInteractionEnabled;
    1502         392 : }
    1503             : 
    1504             : // ----------------------------------------------------------------------------
    1505             : 
    1506           1 : void ScExternalRefManager::getAllCachedTableNames(sal_uInt16 nFileId, vector<OUString>& rTabNames) const
    1507             : {
    1508           1 :     maRefCache.getAllTableNames(nFileId, rTabNames);
    1509           1 : }
    1510             : 
    1511           0 : SCsTAB ScExternalRefManager::getCachedTabSpan( sal_uInt16 nFileId, const OUString& rStartTabName, const OUString& rEndTabName ) const
    1512             : {
    1513           0 :     return maRefCache.getTabSpan( nFileId, rStartTabName, rEndTabName);
    1514             : }
    1515             : 
    1516           0 : void ScExternalRefManager::getAllCachedNumberFormats(vector<sal_uInt32>& rNumFmts) const
    1517             : {
    1518           0 :     maRefCache.getAllNumberFormats(rNumFmts);
    1519           0 : }
    1520             : 
    1521           2 : sal_uInt16 ScExternalRefManager::getExternalFileCount() const
    1522             : {
    1523           2 :     return static_cast< sal_uInt16 >( maSrcFiles.size() );
    1524             : }
    1525             : 
    1526           0 : bool ScExternalRefManager::markUsedByLinkListeners()
    1527             : {
    1528           0 :     bool bAllMarked = false;
    1529           0 :     for (LinkListenerMap::const_iterator itr = maLinkListeners.begin();
    1530           0 :             itr != maLinkListeners.end() && !bAllMarked; ++itr)
    1531             :     {
    1532           0 :         if (!(*itr).second.empty())
    1533           0 :             bAllMarked = maRefCache.setCacheDocReferenced( (*itr).first);
    1534             :         /* TODO: LinkListeners should remember the table they're listening to.
    1535             :          * As is, listening to one table will mark all tables of the document
    1536             :          * being referenced. */
    1537             :     }
    1538           0 :     return bAllMarked;
    1539             : }
    1540             : 
    1541           0 : bool ScExternalRefManager::markUsedExternalRefCells()
    1542             : {
    1543           0 :     RefCellMap::iterator itr = maRefCells.begin(), itrEnd = maRefCells.end();
    1544           0 :     for (; itr != itrEnd; ++itr)
    1545             :     {
    1546           0 :         RefCellSet::iterator itrCell = itr->second.begin(), itrCellEnd = itr->second.end();
    1547           0 :         for (; itrCell != itrCellEnd; ++itrCell)
    1548             :         {
    1549           0 :             ScFormulaCell* pCell = *itrCell;
    1550           0 :             bool bUsed = pCell->MarkUsedExternalReferences();
    1551           0 :             if (bUsed)
    1552             :                 // Return true when at least one cell references external docs.
    1553           0 :                 return true;
    1554             :         }
    1555             :     }
    1556           0 :     return false;
    1557             : }
    1558             : 
    1559           0 : bool ScExternalRefManager::setCacheTableReferenced( sal_uInt16 nFileId, const OUString& rTabName, size_t nSheets )
    1560             : {
    1561           0 :     return maRefCache.setCacheTableReferenced( nFileId, rTabName, nSheets, false);
    1562             : }
    1563             : 
    1564           0 : void ScExternalRefManager::setAllCacheTableReferencedStati( bool bReferenced )
    1565             : {
    1566           0 :     mbInReferenceMarking = !bReferenced;
    1567           0 :     maRefCache.setAllCacheTableReferencedStati( bReferenced );
    1568           0 : }
    1569             : 
    1570           0 : void ScExternalRefManager::storeRangeNameTokens(sal_uInt16 nFileId, const OUString& rName, const ScTokenArray& rArray)
    1571             : {
    1572           0 :     ScExternalRefCache::TokenArrayRef pArray(rArray.Clone());
    1573           0 :     maRefCache.setRangeNameTokens(nFileId, rName, pArray);
    1574           0 : }
    1575             : 
    1576             : namespace {
    1577             : 
    1578             : /**
    1579             :  * Put a single cell data into internal cache table.
    1580             :  *
    1581             :  * @param pFmt optional cell format index that may need to be stored with
    1582             :  *             the cell value.
    1583             :  */
    1584          52 : void putCellDataIntoCache(
    1585             :     ScExternalRefCache& rRefCache, const ScExternalRefCache::TokenRef& pToken,
    1586             :     sal_uInt16 nFileId, const String& rTabName, const ScAddress& rCell,
    1587             :     const ScExternalRefCache::CellFormat* pFmt)
    1588             : {
    1589             :     // Now, insert the token into cache table but don't cache empty cells.
    1590          52 :     if (pToken->GetType() != formula::svEmptyCell)
    1591             :     {
    1592          45 :         sal_uLong nFmtIndex = (pFmt && pFmt->mbIsSet) ? pFmt->mnIndex : 0;
    1593          45 :         rRefCache.setCellData(nFileId, rTabName, rCell.Col(), rCell.Row(), pToken, nFmtIndex);
    1594             :     }
    1595          52 : }
    1596             : 
    1597             : /**
    1598             :  * Put the data into our internal cache table.
    1599             :  *
    1600             :  * @param rRefCache cache table set.
    1601             :  * @param pArray single range data to be returned.
    1602             :  * @param nFileId external file ID
    1603             :  * @param rTabName name of the table where the data should be cached.
    1604             :  * @param rCacheData range data to be cached.
    1605             :  * @param rCacheRange original cache range, including the empty region if
    1606             :  *                    any.
    1607             :  * @param rDataRange reduced cache range that includes only the non-empty
    1608             :  *                   data area.
    1609             :  */
    1610           6 : void putRangeDataIntoCache(
    1611             :     ScExternalRefCache& rRefCache, ScExternalRefCache::TokenArrayRef& pArray,
    1612             :     sal_uInt16 nFileId, const String& rTabName,
    1613             :     const vector<ScExternalRefCache::SingleRangeData>& rCacheData,
    1614             :     const ScRange& rCacheRange, const ScRange& rDataRange)
    1615             : {
    1616           6 :     if (pArray)
    1617             :         // Cache these values.
    1618           6 :         rRefCache.setCellRangeData(nFileId, rDataRange, rCacheData, pArray);
    1619             :     else
    1620             :     {
    1621             :         // Array is empty.  Fill it with an empty matrix of the required size.
    1622           0 :         pArray.reset(lcl_fillEmptyMatrix(rCacheRange));
    1623             : 
    1624             :         // Make sure to set this range 'cached', to prevent unnecessarily
    1625             :         // accessing the src document time and time again.
    1626             :         ScExternalRefCache::TableTypeRef pCacheTab =
    1627           0 :             rRefCache.getCacheTable(nFileId, rTabName, true, NULL);
    1628           0 :         if (pCacheTab)
    1629             :             pCacheTab->setCachedCellRange(
    1630           0 :                 rCacheRange.aStart.Col(), rCacheRange.aStart.Row(), rCacheRange.aEnd.Col(), rCacheRange.aEnd.Row());
    1631             :     }
    1632           6 : }
    1633             : 
    1634             : /**
    1635             :  * When accessing an external document for the first time, we need to
    1636             :  * populate the cache with all its sheet names (whether they are referenced
    1637             :  * or not) in the correct order.  Many client codes that use external
    1638             :  * references make this assumption.
    1639             :  *
    1640             :  * @param rRefCache cache table set.
    1641             :  * @param pSrcDoc source document instance.
    1642             :  * @param nFileId external file ID associated with the source document.
    1643             :  */
    1644          58 : void initDocInCache(ScExternalRefCache& rRefCache, const ScDocument* pSrcDoc, sal_uInt16 nFileId)
    1645             : {
    1646          58 :     if (!pSrcDoc)
    1647           0 :         return;
    1648             : 
    1649          58 :     if (rRefCache.isDocInitialized(nFileId))
    1650             :         // Already initialized.  No need to do this twice.
    1651          55 :         return;
    1652             : 
    1653           3 :     SCTAB nTabCount = pSrcDoc->GetTableCount();
    1654           3 :     if (nTabCount)
    1655             :     {
    1656             :         // Populate the cache with all table names in the source document.
    1657           3 :         vector<OUString> aTabNames;
    1658           3 :         aTabNames.reserve(nTabCount);
    1659          11 :         for (SCTAB i = 0; i < nTabCount; ++i)
    1660             :         {
    1661           8 :             OUString aName;
    1662           8 :             pSrcDoc->GetName(i, aName);
    1663           8 :             aTabNames.push_back(aName);
    1664           8 :         }
    1665           3 :         rRefCache.initializeDoc(nFileId, aTabNames);
    1666             :     }
    1667             : }
    1668             : 
    1669             : }
    1670             : 
    1671          52 : ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefToken(
    1672             :     sal_uInt16 nFileId, const OUString& rTabName, const ScAddress& rCell,
    1673             :     const ScAddress* pCurPos, SCTAB* pTab, ScExternalRefCache::CellFormat* pFmt)
    1674             : {
    1675          52 :     if (pCurPos)
    1676          23 :         insertRefCell(nFileId, *pCurPos);
    1677             : 
    1678          52 :     maybeLinkExternalFile(nFileId);
    1679             : 
    1680          52 :     if (pTab)
    1681          29 :         *pTab = -1;
    1682             : 
    1683          52 :     if (pFmt)
    1684          23 :         pFmt->mbIsSet = false;
    1685             : 
    1686          52 :     const ScDocument* pSrcDoc = getInMemorySrcDocument(nFileId);
    1687          52 :     if (pSrcDoc)
    1688             :     {
    1689             :         // source document already loaded in memory.  Re-use this instance.
    1690             :         SCTAB nTab;
    1691          52 :         if (!pSrcDoc->GetTable(rTabName, nTab))
    1692             :         {
    1693             :             // specified table name doesn't exist in the source document.
    1694           0 :             ScExternalRefCache::TokenRef pToken(new FormulaErrorToken(errNoRef));
    1695           0 :             return pToken;
    1696             :         }
    1697             : 
    1698          52 :         if (pTab)
    1699          29 :             *pTab = nTab;
    1700             : 
    1701             :         ScExternalRefCache::TokenRef pToken =
    1702             :             getSingleRefTokenFromSrcDoc(
    1703          52 :                 nFileId, pSrcDoc, ScAddress(rCell.Col(),rCell.Row(),nTab), pFmt);
    1704             : 
    1705          52 :         putCellDataIntoCache(maRefCache, pToken, nFileId, rTabName, rCell, pFmt);
    1706          52 :         return pToken;
    1707             :     }
    1708             : 
    1709             :     // Check if the given table name and the cell position is cached.
    1710           0 :     sal_uInt32 nFmtIndex = 0;
    1711             :     ScExternalRefCache::TokenRef pToken = maRefCache.getCellData(
    1712           0 :         nFileId, rTabName, rCell.Col(), rCell.Row(), &nFmtIndex);
    1713           0 :     if (pToken)
    1714             :     {
    1715             :         // Cache hit !
    1716           0 :         fillCellFormat(nFmtIndex, pFmt);
    1717           0 :         return pToken;
    1718             :     }
    1719             : 
    1720             :     // reference not cached.  read from the source document.
    1721           0 :     pSrcDoc = getSrcDocument(nFileId);
    1722           0 :     if (!pSrcDoc)
    1723             :     {
    1724             :         // Source document not reachable.  Throw a reference error.
    1725           0 :         pToken.reset(new FormulaErrorToken(errNoRef));
    1726           0 :         return pToken;
    1727             :     }
    1728             : 
    1729             :     SCTAB nTab;
    1730           0 :     if (!pSrcDoc->GetTable(rTabName, nTab))
    1731             :     {
    1732             :         // specified table name doesn't exist in the source document.
    1733           0 :         pToken.reset(new FormulaErrorToken(errNoRef));
    1734           0 :         return pToken;
    1735             :     }
    1736             : 
    1737           0 :     if (pTab)
    1738           0 :         *pTab = nTab;
    1739             : 
    1740           0 :     SCCOL nDataCol1 = 0, nDataCol2 = MAXCOL;
    1741           0 :     SCROW nDataRow1 = 0, nDataRow2 = MAXROW;
    1742           0 :     bool bData = pSrcDoc->ShrinkToDataArea(nTab, nDataCol1, nDataRow1, nDataCol2, nDataRow2);
    1743           0 :     if (!bData || rCell.Col() < nDataCol1 || nDataCol2 < rCell.Col() || rCell.Row() < nDataRow1 || nDataRow2 < rCell.Row())
    1744             :     {
    1745             :         // requested cell is outside the data area.  Don't even bother caching
    1746             :         // this data, but add it to the cached range to prevent accessing the
    1747             :         // source document time and time again.
    1748             :         ScExternalRefCache::TableTypeRef pCacheTab =
    1749           0 :             maRefCache.getCacheTable(nFileId, rTabName, true, NULL);
    1750           0 :         if (pCacheTab)
    1751           0 :             pCacheTab->setCachedCell(rCell.Col(), rCell.Row());
    1752             : 
    1753           0 :         pToken.reset(new ScEmptyCellToken(false, false));
    1754           0 :         return pToken;
    1755             :     }
    1756             : 
    1757             :     pToken = getSingleRefTokenFromSrcDoc(
    1758           0 :         nFileId, pSrcDoc, ScAddress(rCell.Col(),rCell.Row(),nTab), pFmt);
    1759             : 
    1760           0 :     putCellDataIntoCache(maRefCache, pToken, nFileId, rTabName, rCell, pFmt);
    1761           0 :     return pToken;
    1762             : }
    1763             : 
    1764           6 : ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokens(
    1765             :     sal_uInt16 nFileId, const OUString& rTabName, const ScRange& rRange, const ScAddress* pCurPos)
    1766             : {
    1767           6 :     if (pCurPos)
    1768           6 :         insertRefCell(nFileId, *pCurPos);
    1769             : 
    1770           6 :     maybeLinkExternalFile(nFileId);
    1771             : 
    1772           6 :     ScRange aDataRange(rRange);
    1773           6 :     const ScDocument* pSrcDoc = getInMemorySrcDocument(nFileId);
    1774           6 :     if (pSrcDoc)
    1775             :     {
    1776             :         // Document already loaded in memory.
    1777           6 :         vector<ScExternalRefCache::SingleRangeData> aCacheData;
    1778             :         ScExternalRefCache::TokenArrayRef pArray =
    1779           6 :             getDoubleRefTokensFromSrcDoc(pSrcDoc, rTabName, aDataRange, aCacheData);
    1780             : 
    1781             :         // Put the data into cache.
    1782           6 :         putRangeDataIntoCache(maRefCache, pArray, nFileId, rTabName, aCacheData, rRange, aDataRange);
    1783           6 :         return pArray;
    1784             :     }
    1785             : 
    1786             :     // Check if the given table name and the cell position is cached.
    1787             :     ScExternalRefCache::TokenArrayRef pArray =
    1788           0 :         maRefCache.getCellRangeData(nFileId, rTabName, rRange);
    1789           0 :     if (pArray)
    1790             :         // Cache hit !
    1791           0 :         return pArray;
    1792             : 
    1793           0 :     pSrcDoc = getSrcDocument(nFileId);
    1794           0 :     if (!pSrcDoc)
    1795             :     {
    1796             :         // Source document is not reachable.  Throw a reference error.
    1797           0 :         pArray.reset(new ScTokenArray);
    1798           0 :         pArray->AddToken(FormulaErrorToken(errNoRef));
    1799           0 :         return pArray;
    1800             :     }
    1801             : 
    1802           0 :     vector<ScExternalRefCache::SingleRangeData> aCacheData;
    1803           0 :     pArray = getDoubleRefTokensFromSrcDoc(pSrcDoc, rTabName, aDataRange, aCacheData);
    1804             : 
    1805             :     // Put the data into cache.
    1806           0 :     putRangeDataIntoCache(maRefCache, pArray, nFileId, rTabName, aCacheData, rRange, aDataRange);
    1807           0 :     return pArray;
    1808             : }
    1809             : 
    1810           0 : ScExternalRefCache::TokenArrayRef ScExternalRefManager::getRangeNameTokens(
    1811             :     sal_uInt16 nFileId, const OUString& rName, const ScAddress* pCurPos)
    1812             : {
    1813           0 :     if (pCurPos)
    1814           0 :         insertRefCell(nFileId, *pCurPos);
    1815             : 
    1816           0 :     maybeLinkExternalFile(nFileId);
    1817             : 
    1818           0 :     OUString aName = rName; // make a copy to have the casing corrected.
    1819           0 :     const ScDocument* pSrcDoc = getInMemorySrcDocument(nFileId);
    1820           0 :     if (pSrcDoc)
    1821             :     {
    1822             :         // Document already loaded in memory.
    1823             :         ScExternalRefCache::TokenArrayRef pArray =
    1824           0 :             getRangeNameTokensFromSrcDoc(nFileId, pSrcDoc, aName);
    1825             : 
    1826           0 :         if (pArray)
    1827             :             // Cache this range name array.
    1828           0 :             maRefCache.setRangeNameTokens(nFileId, aName, pArray);
    1829             : 
    1830           0 :         return pArray;
    1831             :     }
    1832             : 
    1833           0 :     ScExternalRefCache::TokenArrayRef pArray = maRefCache.getRangeNameTokens(nFileId, rName);
    1834           0 :     if (pArray.get())
    1835             :         // This range name is cached.
    1836           0 :         return pArray;
    1837             : 
    1838           0 :     pSrcDoc = getSrcDocument(nFileId);
    1839           0 :     if (!pSrcDoc)
    1840             :         // failed to load document from disk.
    1841           0 :         return ScExternalRefCache::TokenArrayRef();
    1842             : 
    1843           0 :     pArray = getRangeNameTokensFromSrcDoc(nFileId, pSrcDoc, aName);
    1844             : 
    1845           0 :     if (pArray)
    1846             :         // Cache this range name array.
    1847           0 :         maRefCache.setRangeNameTokens(nFileId, aName, pArray);
    1848             : 
    1849           0 :     return pArray;
    1850             : }
    1851             : 
    1852           0 : void ScExternalRefManager::refreshAllRefCells(sal_uInt16 nFileId)
    1853             : {
    1854           0 :     RefCellMap::iterator itrFile = maRefCells.find(nFileId);
    1855           0 :     if (itrFile == maRefCells.end())
    1856             :         return;
    1857             : 
    1858           0 :     RefCellSet& rRefCells = itrFile->second;
    1859           0 :     for_each(rRefCells.begin(), rRefCells.end(), UpdateFormulaCell());
    1860             : 
    1861           0 :     ScViewData* pViewData = ScDocShell::GetViewData();
    1862           0 :     if (!pViewData)
    1863             :         return;
    1864             : 
    1865           0 :     ScTabViewShell* pVShell = pViewData->GetViewShell();
    1866           0 :     if (!pVShell)
    1867             :         return;
    1868             : 
    1869             :     // Repainting the grid also repaints the texts, but is there a better way
    1870             :     // to refresh texts?
    1871           0 :     pVShell->Invalidate(FID_REPAINT);
    1872           0 :     pVShell->PaintGrid();
    1873             : }
    1874             : 
    1875          29 : void ScExternalRefManager::insertRefCell(sal_uInt16 nFileId, const ScAddress& rCell)
    1876             : {
    1877          29 :     RefCellMap::iterator itr = maRefCells.find(nFileId);
    1878          29 :     if (itr == maRefCells.end())
    1879             :     {
    1880           2 :         RefCellSet aRefCells;
    1881             :         pair<RefCellMap::iterator, bool> r = maRefCells.insert(
    1882           2 :             RefCellMap::value_type(nFileId, aRefCells));
    1883           2 :         if (!r.second)
    1884             :             // insertion failed.
    1885          29 :             return;
    1886             : 
    1887           2 :         itr = r.first;
    1888             :     }
    1889             : 
    1890          29 :     ScBaseCell* pCell = mpDoc->GetCell(rCell);
    1891          29 :     if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
    1892          29 :         itr->second.insert(static_cast<ScFormulaCell*>(pCell));
    1893             : }
    1894             : 
    1895          52 : void ScExternalRefManager::fillCellFormat(sal_uLong nFmtIndex, ScExternalRefCache::CellFormat* pFmt) const
    1896             : {
    1897          52 :     if (!pFmt)
    1898          81 :         return;
    1899             : 
    1900          23 :     short nFmtType = mpDoc->GetFormatTable()->GetType(nFmtIndex);
    1901          23 :     if (nFmtType != NUMBERFORMAT_UNDEFINED)
    1902             :     {
    1903          23 :         pFmt->mbIsSet = true;
    1904          23 :         pFmt->mnIndex = nFmtIndex;
    1905          23 :         pFmt->mnType = nFmtType;
    1906             :     }
    1907             : }
    1908             : 
    1909          52 : ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefTokenFromSrcDoc(
    1910             :     sal_uInt16 nFileId, const ScDocument* pSrcDoc, const ScAddress& rCell,
    1911             :     ScExternalRefCache::CellFormat* pFmt)
    1912             : {
    1913             :     // Get the cell from src doc, and convert it into a token.
    1914          52 :     ScBaseCell* pCell = NULL;
    1915          52 :     pSrcDoc->GetCell(rCell.Col(), rCell.Row(), rCell.Tab(), pCell);
    1916          52 :     ScExternalRefCache::TokenRef pToken(lcl_convertToToken(pCell));
    1917             : 
    1918          52 :     if (!pToken.get())
    1919             :     {
    1920             :         // Generate an error for unresolvable cells.
    1921           0 :         pToken.reset( new FormulaErrorToken( errNoValue));
    1922             :     }
    1923             : 
    1924             :     // Get number format information.
    1925          52 :     sal_uInt32 nFmtIndex = 0;
    1926          52 :     pSrcDoc->GetNumberFormat(rCell.Col(), rCell.Row(), rCell.Tab(), nFmtIndex);
    1927          52 :     nFmtIndex = getMappedNumberFormat(nFileId, nFmtIndex, pSrcDoc);
    1928          52 :     fillCellFormat(nFmtIndex, pFmt);
    1929          52 :     return pToken;
    1930             : }
    1931             : 
    1932           6 : ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokensFromSrcDoc(
    1933             :     const ScDocument* pSrcDoc, const OUString& rTabName, ScRange& rRange,
    1934             :     vector<ScExternalRefCache::SingleRangeData>& rCacheData)
    1935             : {
    1936           6 :     ScExternalRefCache::TokenArrayRef pArray;
    1937             :     SCTAB nTab1;
    1938             : 
    1939           6 :     if (!pSrcDoc->GetTable(rTabName, nTab1))
    1940             :     {
    1941             :         // specified table name doesn't exist in the source document.
    1942           0 :         pArray.reset(new ScTokenArray);
    1943           0 :         pArray->AddToken(FormulaErrorToken(errNoRef));
    1944             :         return pArray;
    1945             :     }
    1946             : 
    1947           6 :     ScRange aRange(rRange);
    1948           6 :     SCTAB nTabSpan = aRange.aEnd.Tab() - aRange.aStart.Tab();
    1949             : 
    1950           6 :     vector<ScExternalRefCache::SingleRangeData> aCacheData;
    1951           6 :     aCacheData.reserve(nTabSpan+1);
    1952           6 :     aCacheData.push_back(ScExternalRefCache::SingleRangeData());
    1953           6 :     aCacheData.back().maTableName = ScGlobal::pCharClass->uppercase(rTabName);
    1954             : 
    1955           6 :     for (SCTAB i = 1; i < nTabSpan + 1; ++i)
    1956             :     {
    1957           0 :         OUString aTabName;
    1958           0 :         if (!pSrcDoc->GetName(nTab1 + 1, aTabName))
    1959             :             // source document doesn't have any table by the specified name.
    1960             :             break;
    1961             : 
    1962           0 :         aCacheData.push_back(ScExternalRefCache::SingleRangeData());
    1963           0 :         aCacheData.back().maTableName = ScGlobal::pCharClass->uppercase(aTabName);
    1964           0 :     }
    1965             : 
    1966           6 :     aRange.aStart.SetTab(nTab1);
    1967           6 :     aRange.aEnd.SetTab(nTab1 + nTabSpan);
    1968             : 
    1969           6 :     pArray.reset(lcl_convertToTokenArray(pSrcDoc, aRange, aCacheData));
    1970           6 :     rRange = aRange;
    1971           6 :     rCacheData.swap(aCacheData);
    1972           6 :     return pArray;
    1973             : }
    1974             : 
    1975           0 : ScExternalRefCache::TokenArrayRef ScExternalRefManager::getRangeNameTokensFromSrcDoc(
    1976             :     sal_uInt16 nFileId, const ScDocument* pSrcDoc, OUString& rName)
    1977             : {
    1978           0 :     ScRangeName* pExtNames = pSrcDoc->GetRangeName();
    1979           0 :     String aUpperName = ScGlobal::pCharClass->uppercase(rName);
    1980           0 :     const ScRangeData* pRangeData = pExtNames->findByUpperName(aUpperName);
    1981           0 :     if (!pRangeData)
    1982           0 :         return ScExternalRefCache::TokenArrayRef();
    1983             : 
    1984             :     // Parse all tokens in this external range data, and replace each absolute
    1985             :     // reference token with an external reference token, and cache them.  Also
    1986             :     // register the source document with the link manager if it's a new
    1987             :     // source.
    1988             : 
    1989           0 :     ScExternalRefCache::TokenArrayRef pNew(new ScTokenArray);
    1990             : 
    1991           0 :     ScTokenArray aCode(*pRangeData->GetCode());
    1992           0 :     for (const FormulaToken* pToken = aCode.First(); pToken; pToken = aCode.Next())
    1993             :     {
    1994           0 :         bool bTokenAdded = false;
    1995           0 :         switch (pToken->GetType())
    1996             :         {
    1997             :             case svSingleRef:
    1998             :             {
    1999           0 :                 const ScSingleRefData& rRef = static_cast<const ScToken*>(pToken)->GetSingleRef();
    2000           0 :                 OUString aTabName;
    2001           0 :                 pSrcDoc->GetName(rRef.nTab, aTabName);
    2002           0 :                 ScExternalSingleRefToken aNewToken(nFileId, aTabName, static_cast<const ScToken*>(pToken)->GetSingleRef());
    2003           0 :                 pNew->AddToken(aNewToken);
    2004           0 :                 bTokenAdded = true;
    2005             :             }
    2006           0 :             break;
    2007             :             case svDoubleRef:
    2008             :             {
    2009           0 :                 const ScSingleRefData& rRef = static_cast<const ScToken*>(pToken)->GetSingleRef();
    2010           0 :                 OUString aTabName;
    2011           0 :                 pSrcDoc->GetName(rRef.nTab, aTabName);
    2012           0 :                 ScExternalDoubleRefToken aNewToken(nFileId, aTabName, static_cast<const ScToken*>(pToken)->GetDoubleRef());
    2013           0 :                 pNew->AddToken(aNewToken);
    2014           0 :                 bTokenAdded = true;
    2015             :             }
    2016           0 :             break;
    2017             :             default:
    2018             :                 ;   // nothing
    2019             :         }
    2020             : 
    2021           0 :         if (!bTokenAdded)
    2022           0 :             pNew->AddToken(*pToken);
    2023             :     }
    2024             : 
    2025           0 :     rName = pRangeData->GetName(); // Get the correctly-cased name.
    2026           0 :     return pNew;
    2027             : }
    2028             : 
    2029          58 : const ScDocument* ScExternalRefManager::getInMemorySrcDocument(sal_uInt16 nFileId)
    2030             : {
    2031          58 :     const OUString* pFileName = getExternalFileName(nFileId);
    2032          58 :     if (!pFileName)
    2033           0 :         return NULL;
    2034             : 
    2035          58 :     ScDocument* pSrcDoc = NULL;
    2036          58 :     TypeId aType(TYPE(ScDocShell));
    2037          58 :     ScDocShell* pShell = static_cast<ScDocShell*>(SfxObjectShell::GetFirst(&aType, false));
    2038        1816 :     while (pShell)
    2039             :     {
    2040        1758 :         SfxMedium* pMedium = pShell->GetMedium();
    2041        1758 :         if (pMedium && !pMedium->GetName().isEmpty())
    2042             :         {
    2043             :             // TODO: We should make the case sensitivity platform dependent.
    2044          58 :             if (pFileName->equalsIgnoreAsciiCase(pMedium->GetName()))
    2045             :             {
    2046             :                 // Found !
    2047          58 :                 pSrcDoc = pShell->GetDocument();
    2048          58 :                 break;
    2049             :             }
    2050             :         }
    2051             :         else
    2052             :         {
    2053             :             // handle unsaved documents here
    2054        1700 :             OUString aName = pShell->GetName();
    2055        1700 :             if (pFileName->equalsIgnoreAsciiCase(aName))
    2056             :             {
    2057             :                 // Found !
    2058           0 :                 SrcShell aSrcDoc;
    2059           0 :                 aSrcDoc.maShell = pShell;
    2060           0 :                 maUnsavedDocShells.insert(DocShellMap::value_type(nFileId, aSrcDoc));
    2061           0 :                 StartListening(*pShell);
    2062           0 :                 pSrcDoc = pShell->GetDocument();
    2063           0 :                 break;
    2064        1700 :             }
    2065             :         }
    2066        1700 :         pShell = static_cast<ScDocShell*>(SfxObjectShell::GetNext(*pShell, &aType, false));
    2067             :     }
    2068             : 
    2069          58 :     initDocInCache(maRefCache, pSrcDoc, nFileId);
    2070          58 :     return pSrcDoc;
    2071             : }
    2072             : 
    2073           0 : const ScDocument* ScExternalRefManager::getSrcDocument(sal_uInt16 nFileId)
    2074             : {
    2075           0 :     if (!mpDoc->IsExecuteLinkEnabled())
    2076           0 :         return NULL;
    2077             : 
    2078           0 :     DocShellMap::iterator itrEnd = maDocShells.end();
    2079           0 :     DocShellMap::iterator itr = maDocShells.find(nFileId);
    2080             : 
    2081           0 :     if (itr != itrEnd)
    2082             :     {
    2083             :         // document already loaded.
    2084             : 
    2085           0 :         SfxObjectShell* p = itr->second.maShell;
    2086           0 :         itr->second.maLastAccess = Time( Time::SYSTEM );
    2087           0 :         return static_cast<ScDocShell*>(p)->GetDocument();
    2088             :     }
    2089             : 
    2090           0 :     itrEnd = maUnsavedDocShells.end();
    2091           0 :     itr = maUnsavedDocShells.find(nFileId);
    2092           0 :     if (itr != itrEnd)
    2093             :     {
    2094             :         //document is unsaved document
    2095             : 
    2096           0 :         SfxObjectShell* p = itr->second.maShell;
    2097           0 :         itr->second.maLastAccess = Time( Time::SYSTEM );
    2098           0 :         return static_cast<ScDocShell*>(p)->GetDocument();
    2099             :     }
    2100             : 
    2101           0 :     const OUString* pFile = getExternalFileName(nFileId);
    2102           0 :     if (!pFile)
    2103             :         // no file name associated with this ID.
    2104           0 :         return NULL;
    2105             : 
    2106           0 :     OUString aFilter;
    2107           0 :     SrcShell aSrcDoc;
    2108           0 :     aSrcDoc.maShell = loadSrcDocument(nFileId, aFilter);
    2109           0 :     if (!aSrcDoc.maShell.Is())
    2110             :     {
    2111             :         // source document could not be loaded.
    2112           0 :         return NULL;
    2113             :     }
    2114             : 
    2115           0 :     if (maDocShells.empty())
    2116             :     {
    2117             :         // If this is the first source document insertion, start up the timer.
    2118           0 :         maSrcDocTimer.Start();
    2119             :     }
    2120             : 
    2121           0 :     maDocShells.insert(DocShellMap::value_type(nFileId, aSrcDoc));
    2122           0 :     SfxObjectShell* p = aSrcDoc.maShell;
    2123           0 :     ScDocument* pSrcDoc = static_cast<ScDocShell*>(p)->GetDocument();
    2124           0 :     initDocInCache(maRefCache, pSrcDoc, nFileId);
    2125           0 :     return pSrcDoc;
    2126             : }
    2127             : 
    2128           0 : SfxObjectShellRef ScExternalRefManager::loadSrcDocument(sal_uInt16 nFileId, OUString& rFilter)
    2129             : {
    2130           0 :     const SrcFileData* pFileData = getExternalFileData(nFileId);
    2131           0 :     if (!pFileData)
    2132           0 :         return NULL;
    2133             : 
    2134             :     // Always load the document by using the path created from the relative
    2135             :     // path.  If the referenced document is not there, simply exit.  The
    2136             :     // original file name should be used only when the relative path is not
    2137             :     // given.
    2138           0 :     OUString aFile = pFileData->maFileName;
    2139           0 :     maybeCreateRealFileName(nFileId);
    2140           0 :     if (!pFileData->maRealFileName.isEmpty())
    2141           0 :         aFile = pFileData->maRealFileName;
    2142             : 
    2143           0 :     if (!isFileLoadable(aFile))
    2144           0 :         return NULL;
    2145             : 
    2146           0 :     OUString aOptions = pFileData->maFilterOptions;
    2147           0 :     if ( !pFileData->maFilterName.isEmpty() )
    2148           0 :         rFilter = pFileData->maFilterName;      // don't overwrite stored filter with guessed filter
    2149             :     else
    2150           0 :         ScDocumentLoader::GetFilterName(aFile, rFilter, aOptions, true, false);;
    2151           0 :     ScDocumentLoader::GetFilterName(aFile, rFilter, aOptions, true, false);
    2152           0 :     const SfxFilter* pFilter = ScDocShell::Factory().GetFilterContainer()->GetFilter4FilterName(rFilter);
    2153             : 
    2154           0 :     if (pFileData->maRelativeName.isEmpty())
    2155             :     {
    2156             :         // Generate a relative file path.
    2157           0 :         INetURLObject aBaseURL(getOwnDocumentName());
    2158           0 :         aBaseURL.insertName(OUString(RTL_CONSTASCII_USTRINGPARAM("content.xml")));
    2159             : 
    2160             :         OUString aStr = URIHelper::simpleNormalizedMakeRelative(
    2161           0 :             aBaseURL.GetMainURL(INetURLObject::NO_DECODE), aFile);
    2162             : 
    2163           0 :         setRelativeFileName(nFileId, aStr);
    2164             :     }
    2165             : 
    2166           0 :     SfxItemSet* pSet = new SfxAllItemSet(SFX_APP()->GetPool());
    2167           0 :     if (!aOptions.isEmpty())
    2168           0 :         pSet->Put(SfxStringItem(SID_FILE_FILTEROPTIONS, aOptions));
    2169             : 
    2170             :     // make medium hidden to prevent assertion from progress bar
    2171           0 :     pSet->Put( SfxBoolItem(SID_HIDDEN, true) );
    2172             : 
    2173             :     SAL_WNODEPRECATED_DECLARATIONS_PUSH
    2174           0 :     auto_ptr<SfxMedium> pMedium(new SfxMedium(aFile, STREAM_STD_READ, pFilter, pSet));
    2175             :     SAL_WNODEPRECATED_DECLARATIONS_POP
    2176           0 :     if (pMedium->GetError() != ERRCODE_NONE)
    2177           0 :         return NULL;
    2178             : 
    2179             :     // To load encrypted documents with password, user interaction needs to be enabled.
    2180           0 :     pMedium->UseInteractionHandler(mbUserInteractionEnabled);
    2181             : 
    2182           0 :     ScDocShell* pNewShell = new ScDocShell(SFX_CREATE_MODE_INTERNAL);
    2183           0 :     SfxObjectShellRef aRef = pNewShell;
    2184             : 
    2185             :     // increment the recursive link count of the source document.
    2186           0 :     ScExtDocOptions* pExtOpt = mpDoc->GetExtDocOptions();
    2187           0 :     sal_uInt32 nLinkCount = pExtOpt ? pExtOpt->GetDocSettings().mnLinkCnt : 0;
    2188           0 :     ScDocument* pSrcDoc = pNewShell->GetDocument();
    2189           0 :     pSrcDoc->EnableExecuteLink(false); // to prevent circular access of external references.
    2190           0 :     pSrcDoc->EnableUndo(false);
    2191           0 :     pSrcDoc->EnableAdjustHeight(false);
    2192           0 :     pSrcDoc->EnableUserInteraction(false);
    2193             : 
    2194           0 :     ScExtDocOptions* pExtOptNew = pSrcDoc->GetExtDocOptions();
    2195           0 :     if (!pExtOptNew)
    2196             :     {
    2197           0 :         pExtOptNew = new ScExtDocOptions;
    2198           0 :         pSrcDoc->SetExtDocOptions(pExtOptNew);
    2199             :     }
    2200           0 :     pExtOptNew->GetDocSettings().mnLinkCnt = nLinkCount + 1;
    2201             : 
    2202           0 :     pNewShell->DoLoad(pMedium.release());
    2203             : 
    2204             :     // with UseInteractionHandler, options may be set by dialog during DoLoad
    2205           0 :     OUString aNew = ScDocumentLoader::GetOptions(*pNewShell->GetMedium());
    2206           0 :     if (!aNew.isEmpty() && aNew != aOptions)
    2207           0 :         aOptions = aNew;
    2208           0 :     setFilterData(nFileId, rFilter, aOptions);    // update the filter data, including the new options
    2209             : 
    2210           0 :     return aRef;
    2211             : }
    2212             : 
    2213           0 : bool ScExternalRefManager::isFileLoadable(const OUString& rFile) const
    2214             : {
    2215           0 :     if (rFile.isEmpty())
    2216           0 :         return false;
    2217             : 
    2218           0 :     if (isOwnDocument(rFile))
    2219           0 :         return false;
    2220           0 :     rtl::OUString aPhysical;
    2221           0 :     if (utl::LocalFileHelper::ConvertURLToPhysicalName(rFile, aPhysical) && !aPhysical.isEmpty())
    2222             :     {
    2223             :         // #i114504# try IsFolder/Exists only for file URLs
    2224             : 
    2225           0 :         if (utl::UCBContentHelper::IsFolder(rFile))
    2226           0 :             return false;
    2227             : 
    2228           0 :         return utl::UCBContentHelper::Exists(rFile);
    2229             :     }
    2230             :     else
    2231           0 :         return true;    // for http and others, Exists doesn't work, but the URL can still be opened
    2232             : }
    2233             : 
    2234          58 : void ScExternalRefManager::maybeLinkExternalFile(sal_uInt16 nFileId)
    2235             : {
    2236          58 :     if (maLinkedDocs.count(nFileId))
    2237             :         // file alerady linked, or the link has been broken.
    2238             :         return;
    2239             : 
    2240             :     // Source document not linked yet.  Link it now.
    2241           2 :     const OUString* pFileName = getExternalFileName(nFileId);
    2242           2 :     if (!pFileName)
    2243             :         return;
    2244             : 
    2245           2 :     OUString aFilter, aOptions;
    2246           2 :     const SrcFileData* pFileData = getExternalFileData(nFileId);
    2247           2 :     if (pFileData)
    2248             :     {
    2249           2 :         aFilter = pFileData->maFilterName;
    2250           2 :         aOptions = pFileData->maFilterOptions;
    2251             :     }
    2252             :     // If a filter was already set (for example, loading the cached table),
    2253             :     // don't call GetFilterName which has to access the source file.
    2254           2 :     if (aFilter.isEmpty())
    2255           2 :         ScDocumentLoader::GetFilterName(*pFileName, aFilter, aOptions, true, false);
    2256           2 :     sfx2::LinkManager* pLinkMgr = mpDoc->GetLinkManager();
    2257           2 :     ScExternalRefLink* pLink = new ScExternalRefLink(mpDoc, nFileId, aFilter);
    2258             :     OSL_ENSURE(pFileName, "ScExternalRefManager::insertExternalFileLink: file name pointer is NULL");
    2259           2 :     String aTmp = aFilter;
    2260           2 :     pLinkMgr->InsertFileLink(*pLink, OBJECT_CLIENT_FILE, *pFileName, &aTmp);
    2261             : 
    2262           2 :     pLink->SetDoReferesh(false);
    2263           2 :     pLink->Update();
    2264           2 :     pLink->SetDoReferesh(true);
    2265             : 
    2266           2 :     maLinkedDocs.insert(LinkedDocMap::value_type(nFileId, true));
    2267             : }
    2268             : 
    2269          99 : void ScExternalRefManager::SrcFileData::maybeCreateRealFileName(const String& rOwnDocName)
    2270             : {
    2271          99 :     if (maRelativeName.isEmpty())
    2272             :         // No relative path given.  Nothing to do.
    2273             :         return;
    2274             : 
    2275           0 :     if (!maRealFileName.isEmpty())
    2276             :         // Real file name already created.  Nothing to do.
    2277             :         return;
    2278             : 
    2279             :     // Formulate the absolute file path from the relative path.
    2280           0 :     const OUString& rRelPath = maRelativeName;
    2281           0 :     INetURLObject aBaseURL(rOwnDocName);
    2282           0 :     aBaseURL.insertName(OUString(RTL_CONSTASCII_USTRINGPARAM("content.xml")));
    2283           0 :     bool bWasAbs = false;
    2284           0 :     maRealFileName = aBaseURL.smartRel2Abs(rRelPath, bWasAbs).GetMainURL(INetURLObject::NO_DECODE);
    2285             : }
    2286             : 
    2287          99 : void ScExternalRefManager::maybeCreateRealFileName(sal_uInt16 nFileId)
    2288             : {
    2289          99 :     if (nFileId >= maSrcFiles.size())
    2290          99 :         return;
    2291             : 
    2292          99 :     maSrcFiles[nFileId].maybeCreateRealFileName(getOwnDocumentName());
    2293             : }
    2294             : 
    2295         141 : OUString ScExternalRefManager::getOwnDocumentName() const
    2296             : {
    2297         141 :     SfxObjectShell* pShell = mpDoc->GetDocumentShell();
    2298         141 :     if (!pShell)
    2299             :         // This should not happen!
    2300           0 :         return OUString();
    2301             : 
    2302         141 :     SfxMedium* pMed = pShell->GetMedium();
    2303         141 :     if (!pMed)
    2304         131 :         return OUString();
    2305             : 
    2306          10 :     return pMed->GetName();
    2307             : }
    2308             : 
    2309          35 : bool ScExternalRefManager::isOwnDocument(const OUString& rFile) const
    2310             : {
    2311          35 :     return getOwnDocumentName().equals(rFile);
    2312             : }
    2313             : 
    2314          35 : void ScExternalRefManager::convertToAbsName(OUString& rFile) const
    2315             : {
    2316             :     // unsaved documents have no AbsName
    2317          35 :     TypeId aType(TYPE(ScDocShell));
    2318          35 :     ScDocShell* pShell = static_cast<ScDocShell*>(SfxObjectShell::GetFirst(&aType, false));
    2319        1135 :     while (pShell)
    2320             :     {
    2321        1065 :         if (rFile == rtl::OUString(pShell->GetName()))
    2322          35 :             return;
    2323             : 
    2324        1065 :         pShell = static_cast<ScDocShell*>(SfxObjectShell::GetNext(*pShell, &aType, false));
    2325             :     }
    2326             : 
    2327          35 :     SfxObjectShell* pDocShell = mpDoc->GetDocumentShell();
    2328          35 :     rFile = ScGlobal::GetAbsDocName(rFile, pDocShell);
    2329             : }
    2330             : 
    2331          40 : sal_uInt16 ScExternalRefManager::getExternalFileId(const OUString& rFile)
    2332             : {
    2333          40 :     vector<SrcFileData>::const_iterator itrBeg = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
    2334          40 :     vector<SrcFileData>::const_iterator itr = find_if(itrBeg, itrEnd, FindSrcFileByName(rFile));
    2335          40 :     if (itr != itrEnd)
    2336             :     {
    2337          37 :         size_t nId = distance(itrBeg, itr);
    2338          37 :         return static_cast<sal_uInt16>(nId);
    2339             :     }
    2340             : 
    2341           3 :     SrcFileData aData;
    2342           3 :     aData.maFileName = rFile;
    2343           3 :     maSrcFiles.push_back(aData);
    2344           3 :     return static_cast<sal_uInt16>(maSrcFiles.size() - 1);
    2345             : }
    2346             : 
    2347          99 : const OUString* ScExternalRefManager::getExternalFileName(sal_uInt16 nFileId, bool bForceOriginal)
    2348             : {
    2349          99 :     if (nFileId >= maSrcFiles.size())
    2350           0 :         return NULL;
    2351             : 
    2352          99 :     if (bForceOriginal)
    2353           0 :         return &maSrcFiles[nFileId].maFileName;
    2354             : 
    2355          99 :     maybeCreateRealFileName(nFileId);
    2356             : 
    2357          99 :     if (!maSrcFiles[nFileId].maRealFileName.isEmpty())
    2358           0 :         return &maSrcFiles[nFileId].maRealFileName;
    2359             : 
    2360          99 :     return &maSrcFiles[nFileId].maFileName;
    2361             : }
    2362             : 
    2363           0 : bool ScExternalRefManager::hasExternalFile(sal_uInt16 nFileId) const
    2364             : {
    2365           0 :     return nFileId < maSrcFiles.size();
    2366             : }
    2367             : 
    2368           0 : bool ScExternalRefManager::hasExternalFile(const OUString& rFile) const
    2369             : {
    2370           0 :     vector<SrcFileData>::const_iterator itrBeg = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
    2371           0 :     vector<SrcFileData>::const_iterator itr = find_if(itrBeg, itrEnd, FindSrcFileByName(rFile));
    2372           0 :     return itr != itrEnd;
    2373             : }
    2374             : 
    2375           2 : const ScExternalRefManager::SrcFileData* ScExternalRefManager::getExternalFileData(sal_uInt16 nFileId) const
    2376             : {
    2377           2 :     if (nFileId >= maSrcFiles.size())
    2378           0 :         return NULL;
    2379             : 
    2380           2 :     return &maSrcFiles[nFileId];
    2381             : }
    2382             : 
    2383          29 : const OUString* ScExternalRefManager::getRealTableName(sal_uInt16 nFileId, const OUString& rTabName) const
    2384             : {
    2385          29 :     return maRefCache.getRealTableName(nFileId, rTabName);
    2386             : }
    2387             : 
    2388           0 : const OUString* ScExternalRefManager::getRealRangeName(sal_uInt16 nFileId, const OUString& rRangeName) const
    2389             : {
    2390           0 :     return maRefCache.getRealRangeName(nFileId, rRangeName);
    2391             : }
    2392             : 
    2393             : template<typename MapContainer>
    2394           0 : static void lcl_removeByFileId(sal_uInt16 nFileId, MapContainer& rMap)
    2395             : {
    2396           0 :     typename MapContainer::iterator itr = rMap.find(nFileId);
    2397           0 :     if (itr != rMap.end())
    2398             :     {
    2399             :         // Close this document shell.
    2400           0 :         itr->second.maShell->DoClose();
    2401           0 :         rMap.erase(itr);
    2402             :     }
    2403           0 : }
    2404             : 
    2405           1 : void ScExternalRefManager::clearCache(sal_uInt16 nFileId)
    2406             : {
    2407           1 :     maRefCache.clearCache(nFileId);
    2408           1 : }
    2409             : 
    2410           0 : void ScExternalRefManager::refreshNames(sal_uInt16 nFileId)
    2411             : {
    2412           0 :     clearCache(nFileId);
    2413           0 :     lcl_removeByFileId(nFileId, maDocShells);
    2414             : 
    2415           0 :     if (maDocShells.empty())
    2416           0 :         maSrcDocTimer.Stop();
    2417             : 
    2418             :     // Update all cells containing names from this source document.
    2419           0 :     refreshAllRefCells(nFileId);
    2420             : 
    2421           0 :     notifyAllLinkListeners(nFileId, LINK_MODIFIED);
    2422           0 : }
    2423             : 
    2424           0 : void ScExternalRefManager::breakLink(sal_uInt16 nFileId)
    2425             : {
    2426             :     // Turn all formula cells referencing this external document into static
    2427             :     // cells.
    2428           0 :     RefCellMap::iterator itrRefs = maRefCells.find(nFileId);
    2429           0 :     if (itrRefs != maRefCells.end())
    2430             :     {
    2431             :         // Make a copy because removing the formula cells below will modify
    2432             :         // the original container.
    2433           0 :         RefCellSet aSet = itrRefs->second;
    2434           0 :         for_each(aSet.begin(), aSet.end(), ConvertFormulaToStatic(mpDoc));
    2435           0 :         maRefCells.erase(nFileId);
    2436             :     }
    2437             : 
    2438             :     // Remove all named ranges that reference this document.
    2439             : 
    2440             :     // Global named ranges.
    2441           0 :     ScRangeName* pRanges = mpDoc->GetRangeName();
    2442           0 :     if (pRanges)
    2443           0 :         removeRangeNamesBySrcDoc(*pRanges, nFileId);
    2444             : 
    2445             :     // Sheet-local named ranges.
    2446           0 :     for (SCTAB i = 0, n = mpDoc->GetTableCount(); i < n; ++i)
    2447             :     {
    2448           0 :         pRanges = mpDoc->GetRangeName(i);
    2449           0 :         if (pRanges)
    2450           0 :             removeRangeNamesBySrcDoc(*pRanges, nFileId);
    2451             :     }
    2452             : 
    2453           0 :     clearCache(nFileId);
    2454           0 :     lcl_removeByFileId(nFileId, maDocShells);
    2455             : 
    2456           0 :     if (maDocShells.empty())
    2457           0 :         maSrcDocTimer.Stop();
    2458             : 
    2459           0 :     LinkedDocMap::iterator itr = maLinkedDocs.find(nFileId);
    2460           0 :     if (itr != maLinkedDocs.end())
    2461           0 :         itr->second = false;
    2462             : 
    2463           0 :     notifyAllLinkListeners(nFileId, LINK_BROKEN);
    2464           0 : }
    2465             : 
    2466           0 : void ScExternalRefManager::switchSrcFile(sal_uInt16 nFileId, const OUString& rNewFile, const OUString& rNewFilter)
    2467             : {
    2468           0 :     maSrcFiles[nFileId].maFileName = rNewFile;
    2469           0 :     maSrcFiles[nFileId].maRelativeName = OUString();
    2470           0 :     maSrcFiles[nFileId].maRealFileName = OUString();
    2471           0 :     if (!maSrcFiles[nFileId].maFilterName.equals(rNewFilter))
    2472             :     {
    2473             :         // Filter type has changed.
    2474           0 :         maSrcFiles[nFileId].maFilterName = rNewFilter;
    2475           0 :         maSrcFiles[nFileId].maFilterOptions = OUString();
    2476             :     }
    2477           0 :     refreshNames(nFileId);
    2478           0 : }
    2479             : 
    2480           0 : void ScExternalRefManager::setRelativeFileName(sal_uInt16 nFileId, const OUString& rRelUrl)
    2481             : {
    2482           0 :     if (nFileId >= maSrcFiles.size())
    2483           0 :         return;
    2484           0 :     maSrcFiles[nFileId].maRelativeName = rRelUrl;
    2485             : }
    2486             : 
    2487           0 : void ScExternalRefManager::setFilterData(sal_uInt16 nFileId, const OUString& rFilterName, const OUString& rOptions)
    2488             : {
    2489           0 :     if (nFileId >= maSrcFiles.size())
    2490           0 :         return;
    2491           0 :     maSrcFiles[nFileId].maFilterName = rFilterName;
    2492           0 :     maSrcFiles[nFileId].maFilterOptions = rOptions;
    2493             : }
    2494             : 
    2495          15 : void ScExternalRefManager::clear()
    2496             : {
    2497          15 :     DocShellMap::iterator itrEnd = maDocShells.end();
    2498          15 :     for (DocShellMap::iterator itr = maDocShells.begin(); itr != itrEnd; ++itr)
    2499           0 :         itr->second.maShell->DoClose();
    2500             : 
    2501          15 :     maDocShells.clear();
    2502          15 :     maSrcDocTimer.Stop();
    2503          15 : }
    2504             : 
    2505           6 : bool ScExternalRefManager::hasExternalData() const
    2506             : {
    2507           6 :     return !maSrcFiles.empty();
    2508             : }
    2509             : 
    2510           2 : void ScExternalRefManager::resetSrcFileData(const OUString& rBaseFileUrl)
    2511             : {
    2512           2 :     for (vector<SrcFileData>::iterator itr = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
    2513             :           itr != itrEnd; ++itr)
    2514             :     {
    2515             :         // Re-generate relative file name from the absolute file name.
    2516           0 :         OUString aAbsName = itr->maRealFileName;
    2517           0 :         if (aAbsName.isEmpty())
    2518           0 :             aAbsName = itr->maFileName;
    2519             : 
    2520           0 :         itr->maRelativeName = URIHelper::simpleNormalizedMakeRelative(
    2521           0 :             rBaseFileUrl, aAbsName);
    2522           0 :     }
    2523           2 : }
    2524             : 
    2525           7 : void ScExternalRefManager::updateAbsAfterLoad()
    2526             : {
    2527           7 :     String aOwn( getOwnDocumentName() );
    2528           7 :     for (vector<SrcFileData>::iterator itr = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
    2529             :           itr != itrEnd; ++itr)
    2530             :     {
    2531             :         // update maFileName to the real file name,
    2532             :         // to be called when the original name is no longer needed (after CompileXML)
    2533             : 
    2534           0 :         itr->maybeCreateRealFileName( aOwn );
    2535           0 :         String aReal = itr->maRealFileName;
    2536           0 :         if (aReal.Len())
    2537           0 :             itr->maFileName = aReal;
    2538           7 :     }
    2539           7 : }
    2540             : 
    2541          10 : void ScExternalRefManager::removeRefCell(ScFormulaCell* pCell)
    2542             : {
    2543          10 :     for_each(maRefCells.begin(), maRefCells.end(), RemoveFormulaCell(pCell));
    2544          10 : }
    2545             : 
    2546           0 : void ScExternalRefManager::addLinkListener(sal_uInt16 nFileId, LinkListener* pListener)
    2547             : {
    2548           0 :     LinkListenerMap::iterator itr = maLinkListeners.find(nFileId);
    2549           0 :     if (itr == maLinkListeners.end())
    2550             :     {
    2551             :         pair<LinkListenerMap::iterator, bool> r = maLinkListeners.insert(
    2552           0 :             LinkListenerMap::value_type(nFileId, LinkListeners()));
    2553           0 :         if (!r.second)
    2554             :         {
    2555             :             OSL_FAIL("insertion of new link listener list failed");
    2556           0 :             return;
    2557             :         }
    2558             : 
    2559           0 :         itr = r.first;
    2560             :     }
    2561             : 
    2562           0 :     LinkListeners& rList = itr->second;
    2563           0 :     rList.insert(pListener);
    2564             : }
    2565             : 
    2566           0 : void ScExternalRefManager::removeLinkListener(sal_uInt16 nFileId, LinkListener* pListener)
    2567             : {
    2568           0 :     LinkListenerMap::iterator itr = maLinkListeners.find(nFileId);
    2569           0 :     if (itr == maLinkListeners.end())
    2570             :         // no listeners for a specified file.
    2571           0 :         return;
    2572             : 
    2573           0 :     LinkListeners& rList = itr->second;
    2574           0 :     rList.erase(pListener);
    2575             : 
    2576           0 :     if (rList.empty())
    2577             :         // No more listeners for this file.  Remove its entry.
    2578           0 :         maLinkListeners.erase(itr);
    2579             : }
    2580             : 
    2581           0 : void ScExternalRefManager::removeLinkListener(LinkListener* pListener)
    2582             : {
    2583           0 :     LinkListenerMap::iterator itr = maLinkListeners.begin(), itrEnd = maLinkListeners.end();
    2584           0 :     for (; itr != itrEnd; ++itr)
    2585           0 :         itr->second.erase(pListener);
    2586           0 : }
    2587             : 
    2588           0 : void ScExternalRefManager::notifyAllLinkListeners(sal_uInt16 nFileId, LinkUpdateType eType)
    2589             : {
    2590           0 :     LinkListenerMap::iterator itr = maLinkListeners.find(nFileId);
    2591           0 :     if (itr == maLinkListeners.end())
    2592             :         // no listeners for a specified file.
    2593           0 :         return;
    2594             : 
    2595           0 :     LinkListeners& rList = itr->second;
    2596           0 :     for_each(rList.begin(), rList.end(), NotifyLinkListener(nFileId, eType));
    2597             : }
    2598             : 
    2599           0 : void ScExternalRefManager::purgeStaleSrcDocument(sal_Int32 nTimeOut)
    2600             : {
    2601           0 :     DocShellMap aNewDocShells;
    2602           0 :     DocShellMap::iterator itr = maDocShells.begin(), itrEnd = maDocShells.end();
    2603           0 :     for (; itr != itrEnd; ++itr)
    2604             :     {
    2605             :         // in 100th of a second.
    2606           0 :         sal_Int32 nSinceLastAccess = (Time( Time::SYSTEM ) - itr->second.maLastAccess).GetTime();
    2607           0 :         if (nSinceLastAccess < nTimeOut)
    2608           0 :             aNewDocShells.insert(*itr);
    2609             :         else
    2610             :             // Timed out.  Let's close this.
    2611           0 :             itr->second.maShell->DoClose();
    2612             :     }
    2613           0 :     maDocShells.swap(aNewDocShells);
    2614             : 
    2615           0 :     if (maDocShells.empty())
    2616           0 :         maSrcDocTimer.Stop();
    2617           0 : }
    2618             : 
    2619          52 : sal_uInt32 ScExternalRefManager::getMappedNumberFormat(sal_uInt16 nFileId, sal_uInt32 nNumFmt, const ScDocument* pSrcDoc)
    2620             : {
    2621          52 :     NumFmtMap::iterator itr = maNumFormatMap.find(nFileId);
    2622          52 :     if (itr == maNumFormatMap.end())
    2623             :     {
    2624             :         // Number formatter map is not initialized for this external document.
    2625             :         pair<NumFmtMap::iterator, bool> r = maNumFormatMap.insert(
    2626           2 :             NumFmtMap::value_type(nFileId, SvNumberFormatterMergeMap()));
    2627             : 
    2628           2 :         if (!r.second)
    2629             :             // insertion failed.
    2630           0 :             return nNumFmt;
    2631             : 
    2632           2 :         itr = r.first;
    2633           2 :         mpDoc->GetFormatTable()->MergeFormatter( *pSrcDoc->GetFormatTable());
    2634           2 :         SvNumberFormatterMergeMap aMap = mpDoc->GetFormatTable()->ConvertMergeTableToMap();
    2635           2 :         itr->second.swap(aMap);
    2636             :     }
    2637          52 :     const SvNumberFormatterMergeMap& rMap = itr->second;
    2638          52 :     SvNumberFormatterMergeMap::const_iterator itrNumFmt = rMap.find(nNumFmt);
    2639          52 :     if (itrNumFmt != rMap.end())
    2640             :         // mapped value found.
    2641           0 :         return itrNumFmt->second;
    2642             : 
    2643          52 :     return nNumFmt;
    2644             : }
    2645             : 
    2646           0 : void ScExternalRefManager::transformUnsavedRefToSavedRef( SfxObjectShell* pShell )
    2647             : {
    2648           0 :     DocShellMap::iterator itr = maUnsavedDocShells.begin();
    2649           0 :     while( itr != maUnsavedDocShells.end() )
    2650             :     {
    2651           0 :         if (&(itr->second.maShell) == pShell)
    2652             :         {
    2653             :             // found that the shell is marked as unsaved
    2654           0 :             rtl::OUString aFileURL = pShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DECODE_TO_IURI);
    2655           0 :             switchSrcFile(itr->first, aFileURL, rtl::OUString());
    2656           0 :             EndListening(*pShell);
    2657           0 :             maUnsavedDocShells.erase(itr++);
    2658             :         }
    2659             :     }
    2660           0 : }
    2661             : 
    2662           0 : void ScExternalRefManager::Notify( SfxBroadcaster&, const SfxHint& rHint )
    2663             : {
    2664           0 :     if ( rHint.ISA( SfxEventHint ) )
    2665             :     {
    2666           0 :         sal_uLong nEventId = ((SfxEventHint&)rHint).GetEventId();
    2667           0 :         switch ( nEventId )
    2668             :         {
    2669             :             case SFX_EVENT_PREPARECLOSEDOC:
    2670             :                 {
    2671           0 :                     SfxObjectShell* pObjShell = static_cast<const SfxEventHint&>( rHint ).GetObjShell();
    2672           0 :                     ScDocShell* pDocShell = static_cast< ScDocShell* >( pObjShell );
    2673             :                     WarningBox aBox(  pDocShell->GetActiveDialogParent(), WinBits( WB_OK ),
    2674           0 :                                         ScGlobal::GetRscString( STR_CLOSE_WITH_UNSAVED_REFS ) );
    2675           0 :                     aBox.Execute();
    2676             :                 }
    2677           0 :                 break;
    2678             :             case SFX_EVENT_SAVEDOCDONE:
    2679             :             case SFX_EVENT_SAVEASDOCDONE:
    2680             :                 {
    2681           0 :                     SfxObjectShell* pObjShell = static_cast<const SfxEventHint&>( rHint ).GetObjShell();
    2682           0 :                     transformUnsavedRefToSavedRef(pObjShell);
    2683             :                 }
    2684           0 :                 break;
    2685             :             default:
    2686           0 :                 break;
    2687             :         }
    2688             :     }
    2689           0 : }
    2690             : 
    2691           0 : IMPL_LINK(ScExternalRefManager, TimeOutHdl, AutoTimer*, pTimer)
    2692             : {
    2693           0 :     if (pTimer == &maSrcDocTimer)
    2694           0 :         purgeStaleSrcDocument(SRCDOC_LIFE_SPAN);
    2695             : 
    2696           0 :     return 0;
    2697          15 : }
    2698             : 
    2699             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10