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

Generated by: LCOV version 1.10