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