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

Generated by: LCOV version 1.10