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