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