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