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 ()__anon8d18958d0111::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