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

Generated by: LCOV version 1.10