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