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

Generated by: LCOV version 1.11