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