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