update ooo310-m15
[ooovba.git] / sc / source / ui / docshell / externalrefmgr.cxx
blobb831e93ff7616f2e294311de5fad6f9f2e20a246
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: externalrefmgr.cxx,v $
10 * $Revision: 1.1.2.33 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
36 // INCLUDE ---------------------------------------------------------------
38 #include "externalrefmgr.hxx"
39 #include "document.hxx"
40 #include "token.hxx"
41 #include "tokenarray.hxx"
42 #include "address.hxx"
43 #include "tablink.hxx"
44 #include "docsh.hxx"
45 #include "scextopt.hxx"
46 #include "rangenam.hxx"
47 #include "cell.hxx"
48 #include "viewdata.hxx"
49 #include "tabvwsh.hxx"
50 #include "sc.hrc"
52 #include "sfx2/app.hxx"
53 #include "sfx2/docfilt.hxx"
54 #include "sfx2/docfile.hxx"
55 #include "sfx2/fcontnr.hxx"
56 #include "sfx2/sfxsids.hrc"
57 #include "sfx2/objsh.hxx"
58 #include "svtools/broadcast.hxx"
59 #include "svtools/smplhint.hxx"
60 #include "svtools/itemset.hxx"
61 #include "svtools/stritem.hxx"
62 #include "svtools/urihelper.hxx"
63 #include "svtools/zformat.hxx"
64 #include "svx/linkmgr.hxx"
65 #include "tools/urlobj.hxx"
66 #include "unotools/ucbhelper.hxx"
68 #include <memory>
69 #include <algorithm>
71 using ::std::auto_ptr;
72 using ::com::sun::star::uno::Any;
73 using ::rtl::OUString;
74 using ::std::vector;
75 using ::std::find;
76 using ::std::find_if;
77 using ::std::distance;
78 using ::std::pair;
79 using ::std::list;
80 using ::std::unary_function;
81 using namespace formula;
83 #define SRCDOC_LIFE_SPAN 6000 // 1 minute (in 100th of a sec)
84 #define SRCDOC_SCAN_INTERVAL 1000*5 // every 5 seconds (in msec)
86 namespace {
88 class TabNameSearchPredicate : public unary_function<bool, ScExternalRefCache::TableName>
90 public:
91 explicit TabNameSearchPredicate(const String& rSearchName) :
92 maSearchName(ScGlobal::pCharClass->upper(rSearchName))
96 bool operator()(const ScExternalRefCache::TableName& rTabNameSet) const
98 // Ok, I'm doing case insensitive search here.
99 return rTabNameSet.maUpperName.Equals(maSearchName);
102 private:
103 String maSearchName;
106 class FindSrcFileByName : public unary_function<ScExternalRefManager::SrcFileData, bool>
108 public:
109 FindSrcFileByName(const String& rMatchName) :
110 mrMatchName(rMatchName)
114 bool operator()(const ScExternalRefManager::SrcFileData& rSrcData) const
116 return rSrcData.maFileName.Equals(mrMatchName);
119 private:
120 const String& mrMatchName;
123 class NotifyLinkListener : public unary_function<ScExternalRefManager::LinkListener*, void>
125 public:
126 NotifyLinkListener(sal_uInt16 nFileId, ScExternalRefManager::LinkUpdateType eType) :
127 mnFileId(nFileId), meType(eType) {}
129 NotifyLinkListener(const NotifyLinkListener& r) :
130 mnFileId(r.mnFileId), meType(r.meType) {}
132 void operator() (ScExternalRefManager::LinkListener* p) const
134 p->notify(mnFileId, meType);
136 private:
137 sal_uInt16 mnFileId;
138 ScExternalRefManager::LinkUpdateType meType;
143 // ============================================================================
145 ScExternalRefCache::Table::Table()
146 : mbReferenced( true) // Prevent accidental data loss due to lack of knowledge.
150 ScExternalRefCache::Table::~Table()
154 void ScExternalRefCache::Table::setReferenced( bool bReferenced )
156 mbReferenced = bReferenced;
159 bool ScExternalRefCache::Table::isReferenced() const
161 return mbReferenced;
164 void ScExternalRefCache::Table::setCell(SCCOL nCol, SCROW nRow, TokenRef pToken, sal_uInt32 nFmtIndex)
166 using ::std::pair;
167 RowsDataType::iterator itrRow = maRows.find(nRow);
168 if (itrRow == maRows.end())
170 // This row does not exist yet.
171 pair<RowsDataType::iterator, bool> res = maRows.insert(
172 RowsDataType::value_type(nRow, RowDataType()));
174 if (!res.second)
175 return;
177 itrRow = res.first;
180 // Insert this token into the specified column location. I don't need to
181 // check for existing data. Just overwrite it.
182 RowDataType& rRow = itrRow->second;
183 ScExternalRefCache::Cell aCell;
184 aCell.mxToken = pToken;
185 aCell.mnFmtIndex = nFmtIndex;
186 rRow.insert(RowDataType::value_type(nCol, aCell));
189 ScExternalRefCache::TokenRef ScExternalRefCache::Table::getCell(SCCOL nCol, SCROW nRow, sal_uInt32* pnFmtIndex) const
191 RowsDataType::const_iterator itrTable = maRows.find(nRow);
192 if (itrTable == maRows.end())
194 // this table doesn't have the specified row.
195 return TokenRef();
198 const RowDataType& rRowData = itrTable->second;
199 RowDataType::const_iterator itrRow = rRowData.find(nCol);
200 if (itrRow == rRowData.end())
202 // this row doesn't have the specified column.
203 return TokenRef();
206 const Cell& rCell = itrRow->second;
207 if (pnFmtIndex)
208 *pnFmtIndex = rCell.mnFmtIndex;
210 return rCell.mxToken;
213 bool ScExternalRefCache::Table::hasRow( SCROW nRow ) const
215 RowsDataType::const_iterator itrRow = maRows.find(nRow);
216 return itrRow != maRows.end();
219 void ScExternalRefCache::Table::getAllRows(vector<SCROW>& rRows) const
221 vector<SCROW> aRows;
222 aRows.reserve(maRows.size());
223 RowsDataType::const_iterator itr = maRows.begin(), itrEnd = maRows.end();
224 for (; itr != itrEnd; ++itr)
225 aRows.push_back(itr->first);
227 // hash map is not ordered, so we need to explicitly sort it.
228 ::std::sort(aRows.begin(), aRows.end());
229 rRows.swap(aRows);
232 void ScExternalRefCache::Table::getAllCols(SCROW nRow, vector<SCCOL>& rCols) const
234 RowsDataType::const_iterator itrRow = maRows.find(nRow);
235 if (itrRow == maRows.end())
236 // this table doesn't have the specified row.
237 return;
239 const RowDataType& rRowData = itrRow->second;
240 vector<SCCOL> aCols;
241 aCols.reserve(rRowData.size());
242 RowDataType::const_iterator itrCol = rRowData.begin(), itrColEnd = rRowData.end();
243 for (; itrCol != itrColEnd; ++itrCol)
244 aCols.push_back(itrCol->first);
246 // hash map is not ordered, so we need to explicitly sort it.
247 ::std::sort(aCols.begin(), aCols.end());
248 rCols.swap(aCols);
251 void ScExternalRefCache::Table::getAllNumberFormats(vector<sal_uInt32>& rNumFmts) const
253 RowsDataType::const_iterator itrRow = maRows.begin(), itrRowEnd = maRows.end();
254 for (; itrRow != itrRowEnd; ++itrRow)
256 const RowDataType& rRowData = itrRow->second;
257 RowDataType::const_iterator itrCol = rRowData.begin(), itrColEnd = rRowData.end();
258 for (; itrCol != itrColEnd; ++itrCol)
260 const Cell& rCell = itrCol->second;
261 rNumFmts.push_back(rCell.mnFmtIndex);
266 // ----------------------------------------------------------------------------
268 ScExternalRefCache::TableName::TableName(const String& rUpper, const String& rReal) :
269 maUpperName(rUpper), maRealName(rReal)
273 // ----------------------------------------------------------------------------
275 ScExternalRefCache::CellFormat::CellFormat() :
276 mbIsSet(false), mnType(NUMBERFORMAT_ALL), mnIndex(0)
280 // ----------------------------------------------------------------------------
282 ScExternalRefCache::ScExternalRefCache()
285 ScExternalRefCache::~ScExternalRefCache()
289 const String* ScExternalRefCache::getRealTableName(sal_uInt16 nFileId, const String& rTabName) const
291 DocDataType::const_iterator itrDoc = maDocs.find(nFileId);
292 if (itrDoc == maDocs.end())
294 // specified document is not cached.
295 return NULL;
298 const DocItem& rDoc = itrDoc->second;
299 TableNameIndexMap::const_iterator itrTabId = rDoc.maTableNameIndex.find(
300 ScGlobal::pCharClass->upper(rTabName));
301 if (itrTabId == rDoc.maTableNameIndex.end())
303 // the specified table is not in cache.
304 return NULL;
307 return &rDoc.maTableNames[itrTabId->second].maRealName;
310 const String* ScExternalRefCache::getRealRangeName(sal_uInt16 nFileId, const String& rRangeName) const
312 DocDataType::const_iterator itrDoc = maDocs.find(nFileId);
313 if (itrDoc == maDocs.end())
315 // specified document is not cached.
316 return NULL;
319 const DocItem& rDoc = itrDoc->second;
320 NamePairMap::const_iterator itr = rDoc.maRealRangeNameMap.find(
321 ScGlobal::pCharClass->upper(rRangeName));
322 if (itr == rDoc.maRealRangeNameMap.end())
323 // range name not found.
324 return NULL;
326 return &itr->second;
329 ScExternalRefCache::TokenRef ScExternalRefCache::getCellData(
330 sal_uInt16 nFileId, const String& rTabName, SCCOL nCol, SCROW nRow,
331 bool bEmptyCellOnNull, bool bWriteEmpty, sal_uInt32* pnFmtIndex)
333 DocDataType::const_iterator itrDoc = maDocs.find(nFileId);
334 if (itrDoc == maDocs.end())
336 // specified document is not cached.
337 return TokenRef();
340 const DocItem& rDoc = itrDoc->second;
341 TableNameIndexMap::const_iterator itrTabId = rDoc.maTableNameIndex.find(
342 ScGlobal::pCharClass->upper(rTabName));
343 if (itrTabId == rDoc.maTableNameIndex.end())
345 // the specified table is not in cache.
346 return TokenRef();
349 const TableTypeRef& pTableData = rDoc.maTables[itrTabId->second];
350 if (!pTableData.get())
352 // the table data is not instantiated yet.
353 return TokenRef();
356 TokenRef pToken = pTableData->getCell(nCol, nRow, pnFmtIndex);
357 if (!pToken && bEmptyCellOnNull)
359 pToken.reset(new ScEmptyCellToken(false, false));
360 if (bWriteEmpty)
361 pTableData->setCell(nCol, nRow, pToken);
363 return pToken;
366 ScExternalRefCache::TokenArrayRef ScExternalRefCache::getCellRangeData(
367 sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange, bool bEmptyCellOnNull, bool bWriteEmpty)
369 DocDataType::iterator itrDoc = maDocs.find(nFileId);
370 if (itrDoc == maDocs.end())
371 // specified document is not cached.
372 return TokenArrayRef();
374 DocItem& rDoc = itrDoc->second;
375 RangeArrayMap::const_iterator itrRange = rDoc.maRangeArrays.find(rRange);
376 if (itrRange != rDoc.maRangeArrays.end())
378 return itrRange->second;
381 TableNameIndexMap::iterator itrTabId = rDoc.maTableNameIndex.find(
382 ScGlobal::pCharClass->upper(rTabName));
383 if (itrTabId == rDoc.maTableNameIndex.end())
384 // the specified table is not in cache.
385 return TokenArrayRef();
387 const ScAddress& s = rRange.aStart;
388 const ScAddress& e = rRange.aEnd;
390 SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
391 SCCOL nCol1 = s.Col(), nCol2 = e.Col();
392 SCROW nRow1 = s.Row(), nRow2 = e.Row();
394 // Make sure I have all the tables cached.
395 size_t nTabFirstId = itrTabId->second;
396 size_t nTabLastId = nTabFirstId + nTab2 - nTab1;
397 if (nTabLastId >= rDoc.maTables.size())
398 // not all tables are cached.
399 return TokenArrayRef();
401 TokenArrayRef pArray(new ScTokenArray);
402 bool bFirstTab = true;
403 for (size_t nTab = nTabFirstId; nTab <= nTabLastId; ++nTab)
405 TableTypeRef pTab = rDoc.maTables[nTab];
406 if (!pTab.get())
407 return TokenArrayRef();
409 ScMatrixRef xMat = new ScMatrix(
410 static_cast<SCSIZE>(nCol2-nCol1+1), static_cast<SCSIZE>(nRow2-nRow1+1));
412 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
414 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
416 TokenRef pToken = pTab->getCell(nCol, nRow);
417 if (!pToken)
419 if (bEmptyCellOnNull)
421 pToken.reset(new ScEmptyCellToken(false, false));
422 if (bWriteEmpty)
423 pTab->setCell(nCol, nRow, pToken);
425 else
426 return TokenArrayRef();
429 SCSIZE nC = nCol - nCol1, nR = nRow - nRow1;
430 switch (pToken->GetType())
432 case svDouble:
433 xMat->PutDouble(pToken->GetDouble(), nC, nR);
434 break;
435 case svString:
436 xMat->PutString(pToken->GetString(), nC, nR);
437 break;
438 default:
439 xMat->PutEmpty(nC, nR);
444 if (!bFirstTab)
445 pArray->AddOpCode(ocSep);
447 ScMatrix* pMat2 = xMat;
448 ScMatrixToken aToken(pMat2);
449 pArray->AddToken(aToken);
451 bFirstTab = false;
453 rDoc.maRangeArrays.insert(RangeArrayMap::value_type(rRange, pArray));
454 return pArray;
457 ScExternalRefCache::TokenArrayRef ScExternalRefCache::getRangeNameTokens(sal_uInt16 nFileId, const String& rName)
459 DocItem* pDoc = getDocItem(nFileId);
460 if (!pDoc)
461 return TokenArrayRef();
463 RangeNameMap& rMap = pDoc->maRangeNames;
464 RangeNameMap::const_iterator itr = rMap.find(
465 ScGlobal::pCharClass->upper(rName));
466 if (itr == rMap.end())
467 return TokenArrayRef();
469 return itr->second;
472 void ScExternalRefCache::setRangeNameTokens(sal_uInt16 nFileId, const String& rName, TokenArrayRef pArray)
474 DocItem* pDoc = getDocItem(nFileId);
475 if (!pDoc)
476 return;
478 String aUpperName = ScGlobal::pCharClass->upper(rName);
479 RangeNameMap& rMap = pDoc->maRangeNames;
480 rMap.insert(RangeNameMap::value_type(aUpperName, pArray));
481 pDoc->maRealRangeNameMap.insert(NamePairMap::value_type(aUpperName, rName));
484 void ScExternalRefCache::setCellData(sal_uInt16 nFileId, const String& rTabName, SCROW nRow, SCCOL nCol,
485 TokenRef pToken, sal_uInt32 nFmtIndex)
487 if (!isDocInitialized(nFileId))
488 return;
490 using ::std::pair;
491 DocItem* pDocItem = getDocItem(nFileId);
492 if (!pDocItem)
493 return;
495 DocItem& rDoc = *pDocItem;
497 // See if the table by this name already exists.
498 TableNameIndexMap::iterator itrTabName = rDoc.maTableNameIndex.find(
499 ScGlobal::pCharClass->upper(rTabName));
500 if (itrTabName == rDoc.maTableNameIndex.end())
501 // Table not found. Maybe the table name or the file id is wrong ???
502 return;
504 TableTypeRef& pTableData = rDoc.maTables[itrTabName->second];
505 if (!pTableData.get())
506 pTableData.reset(new Table);
508 pTableData->setCell(nCol, nRow, pToken, nFmtIndex);
511 void ScExternalRefCache::setCellRangeData(sal_uInt16 nFileId, const ScRange& rRange, const vector<SingleRangeData>& rData,
512 TokenArrayRef pArray)
514 using ::std::pair;
515 if (rData.empty() || !isDocInitialized(nFileId))
516 // nothing to cache
517 return;
519 // First, get the document item for the given file ID.
520 DocItem* pDocItem = getDocItem(nFileId);
521 if (!pDocItem)
522 return;
524 DocItem& rDoc = *pDocItem;
526 // Now, find the table position of the first table to cache.
527 const String& rFirstTabName = rData.front().maTableName;
528 TableNameIndexMap::iterator itrTabName = rDoc.maTableNameIndex.find(
529 ScGlobal::pCharClass->upper(rFirstTabName));
530 if (itrTabName == rDoc.maTableNameIndex.end())
532 // table index not found.
533 return;
536 size_t nTab1 = itrTabName->second;
537 SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
538 SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
539 vector<SingleRangeData>::const_iterator itrDataBeg = rData.begin(), itrDataEnd = rData.end();
540 for (vector<SingleRangeData>::const_iterator itrData = itrDataBeg; itrData != itrDataEnd; ++itrData)
542 size_t i = nTab1 + ::std::distance(itrDataBeg, itrData);
543 TableTypeRef& pTabData = rDoc.maTables[i];
544 if (!pTabData.get())
545 pTabData.reset(new Table);
547 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
549 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
551 SCSIZE nC = nCol - nCol1, nR = nRow - nRow1;
552 TokenRef pToken;
553 const ScMatrixRef& pMat = itrData->mpRangeData;
554 if (pMat->IsValue(nC, nR))
555 pToken.reset(new formula::FormulaDoubleToken(pMat->GetDouble(nC, nR)));
556 else if (pMat->IsString(nC, nR))
557 pToken.reset(new formula::FormulaStringToken(pMat->GetString(nC, nR)));
558 else
559 pToken.reset(new ScEmptyCellToken(false, false));
561 pTabData->setCell(nCol, nRow, pToken);
566 rDoc.maRangeArrays.insert(RangeArrayMap::value_type(rRange, pArray));
569 bool ScExternalRefCache::isDocInitialized(sal_uInt16 nFileId)
571 DocItem* pDoc = getDocItem(nFileId);
572 if (!pDoc)
573 return false;
575 return pDoc->mbInitFromSource;
578 static bool lcl_getTableDataIndex(const ScExternalRefCache::TableNameIndexMap& rMap, const String& rName, size_t& rIndex)
580 ScExternalRefCache::TableNameIndexMap::const_iterator itr = rMap.find(rName);
581 if (itr == rMap.end())
582 return false;
584 rIndex = itr->second;
585 return true;
588 void ScExternalRefCache::initializeDoc(sal_uInt16 nFileId, const vector<String>& rTabNames)
590 DocItem* pDoc = getDocItem(nFileId);
591 if (!pDoc)
592 return;
594 size_t n = rTabNames.size();
596 // table name list - the list must include all table names in the source
597 // document and only to be populated when loading the source document, not
598 // when loading cached data from, say, Excel XCT/CRN records.
599 vector<TableName> aNewTabNames;
600 aNewTabNames.reserve(n);
601 for (vector<String>::const_iterator itr = rTabNames.begin(), itrEnd = rTabNames.end();
602 itr != itrEnd; ++itr)
604 TableName aNameItem(ScGlobal::pCharClass->upper(*itr), *itr);
605 aNewTabNames.push_back(aNameItem);
607 pDoc->maTableNames.swap(aNewTabNames);
609 // data tables - preserve any existing data that may have been set during
610 // file import.
611 vector<TableTypeRef> aNewTables(n);
612 for (size_t i = 0; i < n; ++i)
614 size_t nIndex;
615 if (lcl_getTableDataIndex(pDoc->maTableNameIndex, pDoc->maTableNames[i].maUpperName, nIndex))
617 aNewTables[i] = pDoc->maTables[nIndex];
620 pDoc->maTables.swap(aNewTables);
622 // name index map
623 TableNameIndexMap aNewNameIndex;
624 for (size_t i = 0; i < n; ++i)
625 aNewNameIndex.insert(TableNameIndexMap::value_type(pDoc->maTableNames[i].maUpperName, i));
626 pDoc->maTableNameIndex.swap(aNewNameIndex);
628 pDoc->mbInitFromSource = true;
631 String ScExternalRefCache::getTableName(sal_uInt16 nFileId, size_t nCacheId) const
633 if( DocItem* pDoc = getDocItem( nFileId ) )
634 if( nCacheId < pDoc->maTableNames.size() )
635 return pDoc->maTableNames[ nCacheId ].maRealName;
636 return EMPTY_STRING;
639 void ScExternalRefCache::getAllTableNames(sal_uInt16 nFileId, vector<String>& rTabNames) const
641 rTabNames.clear();
642 DocItem* pDoc = getDocItem(nFileId);
643 if (!pDoc)
644 return;
646 size_t n = pDoc->maTableNames.size();
647 rTabNames.reserve(n);
648 for (vector<TableName>::const_iterator itr = pDoc->maTableNames.begin(), itrEnd = pDoc->maTableNames.end();
649 itr != itrEnd; ++itr)
650 rTabNames.push_back(itr->maRealName);
653 SCsTAB ScExternalRefCache::getTabSpan( sal_uInt16 nFileId, const String& rStartTabName, const String& rEndTabName ) const
655 DocItem* pDoc = getDocItem(nFileId);
656 if (!pDoc)
657 return -1;
659 vector<TableName>::const_iterator itrBeg = pDoc->maTableNames.begin();
660 vector<TableName>::const_iterator itrEnd = pDoc->maTableNames.end();
662 vector<TableName>::const_iterator itrStartTab = ::std::find_if( itrBeg, itrEnd,
663 TabNameSearchPredicate( rStartTabName));
664 if (itrStartTab == itrEnd)
665 return -1;
667 vector<TableName>::const_iterator itrEndTab = ::std::find_if( itrBeg, itrEnd,
668 TabNameSearchPredicate( rEndTabName));
669 if (itrEndTab == itrEnd)
670 return 0;
672 size_t nStartDist = ::std::distance( itrBeg, itrStartTab);
673 size_t nEndDist = ::std::distance( itrBeg, itrEndTab);
674 return nStartDist <= nEndDist ? static_cast<SCsTAB>(nEndDist - nStartDist + 1) : -static_cast<SCsTAB>(nStartDist - nEndDist + 1);
677 void ScExternalRefCache::getAllNumberFormats(vector<sal_uInt32>& rNumFmts) const
679 using ::std::sort;
680 using ::std::unique;
682 vector<sal_uInt32> aNumFmts;
683 for (DocDataType::const_iterator itrDoc = maDocs.begin(), itrDocEnd = maDocs.end();
684 itrDoc != itrDocEnd; ++itrDoc)
686 const vector<TableTypeRef>& rTables = itrDoc->second.maTables;
687 for (vector<TableTypeRef>::const_iterator itrTab = rTables.begin(), itrTabEnd = rTables.end();
688 itrTab != itrTabEnd; ++itrTab)
690 TableTypeRef pTab = *itrTab;
691 if (!pTab)
692 continue;
694 pTab->getAllNumberFormats(aNumFmts);
698 // remove duplicates.
699 sort(aNumFmts.begin(), aNumFmts.end());
700 aNumFmts.erase(unique(aNumFmts.begin(), aNumFmts.end()), aNumFmts.end());
701 rNumFmts.swap(aNumFmts);
704 bool ScExternalRefCache::hasCacheTable(sal_uInt16 nFileId, const String& rTabName) const
706 DocItem* pDoc = getDocItem(nFileId);
707 if (!pDoc)
708 return false;
710 String aUpperName = ScGlobal::pCharClass->upper(rTabName);
711 vector<TableName>::const_iterator itrBeg = pDoc->maTableNames.begin(), itrEnd = pDoc->maTableNames.end();
712 vector<TableName>::const_iterator itr = ::std::find_if(
713 itrBeg, itrEnd, TabNameSearchPredicate(aUpperName));
715 return itr != itrEnd;
718 size_t ScExternalRefCache::getCacheTableCount(sal_uInt16 nFileId) const
720 DocItem* pDoc = getDocItem(nFileId);
721 return pDoc ? pDoc->maTables.size() : 0;
724 bool ScExternalRefCache::setCacheDocReferenced( sal_uInt16 nFileId )
726 DocItem* pDocItem = getDocItem(nFileId);
727 if (!pDocItem)
728 return areAllCacheTablesReferenced();
730 for (::std::vector<TableTypeRef>::iterator itrTab = pDocItem->maTables.begin();
731 itrTab != pDocItem->maTables.end(); ++itrTab)
733 if ((*itrTab).get())
734 (*itrTab)->setReferenced( true);
736 addCacheDocToReferenced( nFileId);
737 return areAllCacheTablesReferenced();
740 bool ScExternalRefCache::setCacheTableReferenced( sal_uInt16 nFileId, const String& rTabName )
742 size_t nIndex = 0;
743 TableTypeRef pTab = getCacheTable( nFileId, rTabName, false, &nIndex);
744 if (pTab.get())
746 if (!pTab->isReferenced())
748 pTab->setReferenced( true);
749 addCacheTableToReferenced( nFileId, nIndex);
752 return areAllCacheTablesReferenced();
755 void ScExternalRefCache::setAllCacheTableReferencedStati( bool bReferenced )
757 if (bReferenced)
759 maReferenced.reset(0);
760 for (DocDataType::iterator itrDoc = maDocs.begin(); itrDoc != maDocs.end(); ++itrDoc)
762 ScExternalRefCache::DocItem& rDocItem = (*itrDoc).second;
763 for (::std::vector<TableTypeRef>::iterator itrTab = rDocItem.maTables.begin();
764 itrTab != rDocItem.maTables.end(); ++itrTab)
766 if ((*itrTab).get())
767 (*itrTab)->setReferenced( true);
771 else
773 size_t nDocs = 0;
774 for (DocDataType::const_iterator itrDoc = maDocs.begin(); itrDoc != maDocs.end(); ++itrDoc)
776 if (nDocs <= (*itrDoc).first)
777 nDocs = (*itrDoc).first + 1;
779 maReferenced.reset( nDocs);
781 for (DocDataType::iterator itrDoc = maDocs.begin(); itrDoc != maDocs.end(); ++itrDoc)
783 ScExternalRefCache::DocItem& rDocItem = (*itrDoc).second;
784 sal_uInt16 nFileId = (*itrDoc).first;
785 size_t nTables = rDocItem.maTables.size();
786 ReferencedStatus::DocReferenced & rDocReferenced = maReferenced.maDocs[nFileId];
787 // All referenced => non-existing tables evaluate as completed.
788 rDocReferenced.maTables.resize( nTables, true);
789 for (size_t i=0; i < nTables; ++i)
791 TableTypeRef & xTab = rDocItem.maTables[i];
792 if (xTab.get())
794 xTab->setReferenced( false);
795 rDocReferenced.maTables[i] = false;
796 rDocReferenced.mbAllTablesReferenced = false;
803 void ScExternalRefCache::addCacheTableToReferenced( sal_uInt16 nFileId, size_t nIndex )
805 if (nFileId >= maReferenced.maDocs.size())
806 return;
808 ::std::vector<bool> & rTables = maReferenced.maDocs[nFileId].maTables;
809 size_t nTables = rTables.size();
810 if (nIndex >= nTables)
811 return;
813 if (!rTables[nIndex])
815 rTables[nIndex] = true;
816 size_t i = 0;
817 while (i < nTables && rTables[i])
818 ++i;
819 if (i == nTables)
821 maReferenced.maDocs[nFileId].mbAllTablesReferenced = true;
822 maReferenced.checkAllDocs();
827 void ScExternalRefCache::addCacheDocToReferenced( sal_uInt16 nFileId )
829 if (nFileId >= maReferenced.maDocs.size())
830 return;
832 if (!maReferenced.maDocs[nFileId].mbAllTablesReferenced)
834 ::std::vector<bool> & rTables = maReferenced.maDocs[nFileId].maTables;
835 size_t nSize = rTables.size();
836 for (size_t i=0; i < nSize; ++i)
837 rTables[i] = true;
838 maReferenced.maDocs[nFileId].mbAllTablesReferenced = true;
839 maReferenced.checkAllDocs();
843 bool ScExternalRefCache::areAllCacheTablesReferenced() const
845 return maReferenced.mbAllReferenced;
848 ScExternalRefCache::ReferencedStatus::ReferencedStatus() :
849 mbAllReferenced(false)
851 reset(0);
854 ScExternalRefCache::ReferencedStatus::ReferencedStatus( size_t nDocs ) :
855 mbAllReferenced(false)
857 reset( nDocs);
860 void ScExternalRefCache::ReferencedStatus::reset( size_t nDocs )
862 if (nDocs)
864 mbAllReferenced = false;
865 DocReferencedVec aRefs( nDocs);
866 maDocs.swap( aRefs);
868 else
870 mbAllReferenced = true;
871 DocReferencedVec aRefs;
872 maDocs.swap( aRefs);
876 void ScExternalRefCache::ReferencedStatus::checkAllDocs()
878 for (DocReferencedVec::const_iterator itr = maDocs.begin(); itr != maDocs.end(); ++itr)
880 if (!(*itr).mbAllTablesReferenced)
881 return;
883 mbAllReferenced = true;
886 ScExternalRefCache::TableTypeRef ScExternalRefCache::getCacheTable(sal_uInt16 nFileId, size_t nTabIndex) const
888 DocItem* pDoc = getDocItem(nFileId);
889 if (!pDoc || nTabIndex >= pDoc->maTables.size())
890 return TableTypeRef();
892 return pDoc->maTables[nTabIndex];
895 ScExternalRefCache::TableTypeRef ScExternalRefCache::getCacheTable(sal_uInt16 nFileId, const String& rTabName, bool bCreateNew, size_t* pnIndex)
897 DocItem* pDoc = getDocItem(nFileId);
898 if (!pDoc)
899 return TableTypeRef();
901 DocItem& rDoc = *pDoc;
903 size_t nIndex;
904 String aTabNameUpper = ScGlobal::pCharClass->upper(rTabName);
905 if (lcl_getTableDataIndex(rDoc.maTableNameIndex, aTabNameUpper, nIndex))
907 // specified table found.
908 if( pnIndex ) *pnIndex = nIndex;
909 return rDoc.maTables[nIndex];
912 if (!bCreateNew)
913 return TableTypeRef();
915 // Specified table doesn't exist yet. Create one.
916 nIndex = rDoc.maTables.size();
917 if( pnIndex ) *pnIndex = nIndex;
918 TableTypeRef pTab(new Table);
919 rDoc.maTables.push_back(pTab);
920 rDoc.maTableNames.push_back(TableName(aTabNameUpper, rTabName));
921 rDoc.maTableNameIndex.insert(
922 TableNameIndexMap::value_type(aTabNameUpper, nIndex));
923 return pTab;
926 void ScExternalRefCache::clearCache(sal_uInt16 nFileId)
928 maDocs.erase(nFileId);
931 ScExternalRefCache::DocItem* ScExternalRefCache::getDocItem(sal_uInt16 nFileId) const
933 using ::std::pair;
934 DocDataType::iterator itrDoc = maDocs.find(nFileId);
935 if (itrDoc == maDocs.end())
937 // specified document is not cached.
938 pair<DocDataType::iterator, bool> res = maDocs.insert(
939 DocDataType::value_type(nFileId, DocItem()));
941 if (!res.second)
942 // insertion failed.
943 return NULL;
945 itrDoc = res.first;
948 return &itrDoc->second;
951 // ============================================================================
953 ScExternalRefLink::ScExternalRefLink(ScDocument* pDoc, sal_uInt16 nFileId, const String& rFilter) :
954 ::sfx2::SvBaseLink(::sfx2::LINKUPDATE_ONCALL, FORMAT_FILE),
955 mnFileId(nFileId),
956 maFilterName(rFilter),
957 mpDoc(pDoc),
958 mbDoRefresh(true)
962 ScExternalRefLink::~ScExternalRefLink()
966 void ScExternalRefLink::Closed()
968 ScExternalRefManager* pMgr = mpDoc->GetExternalRefManager();
969 pMgr->breakLink(mnFileId);
972 void ScExternalRefLink::DataChanged(const String& /*rMimeType*/, const Any& /*rValue*/)
974 if (!mbDoRefresh)
975 return;
977 String aFile, aFilter;
978 mpDoc->GetLinkManager()->GetDisplayNames(this, NULL, &aFile, NULL, &aFilter);
979 ScExternalRefManager* pMgr = mpDoc->GetExternalRefManager();
980 const String* pCurFile = pMgr->getExternalFileName(mnFileId);
981 if (!pCurFile)
982 return;
984 if (pCurFile->Equals(aFile))
986 // Refresh the current source document.
987 pMgr->refreshNames(mnFileId);
989 else
991 // The source document has changed.
992 pMgr->switchSrcFile(mnFileId, aFile, aFilter);
993 maFilterName = aFilter;
997 void ScExternalRefLink::Edit(Window* pParent, const Link& /*rEndEditHdl*/)
999 SvBaseLink::Edit(pParent, LINK(this, ScExternalRefLink, ExternalRefEndEditHdl));
1002 void ScExternalRefLink::SetDoReferesh(bool b)
1004 mbDoRefresh = b;
1007 IMPL_LINK( ScExternalRefLink, ExternalRefEndEditHdl, ::sfx2::SvBaseLink*, EMPTYARG )
1009 return 0;
1012 // ============================================================================
1014 static FormulaToken* lcl_convertToToken(ScBaseCell* pCell)
1016 if (!pCell || pCell->HasEmptyData())
1018 bool bInherited = (pCell && pCell->GetCellType() == CELLTYPE_FORMULA);
1019 return new ScEmptyCellToken( bInherited, false);
1022 switch (pCell->GetCellType())
1024 case CELLTYPE_EDIT:
1026 String aStr;
1027 static_cast<ScEditCell*>(pCell)->GetString(aStr);
1028 return new formula::FormulaStringToken(aStr);
1030 //break;
1031 case CELLTYPE_STRING:
1033 String aStr;
1034 static_cast<ScStringCell*>(pCell)->GetString(aStr);
1035 return new formula::FormulaStringToken(aStr);
1037 //break;
1038 case CELLTYPE_VALUE:
1040 double fVal = static_cast<ScValueCell*>(pCell)->GetValue();
1041 return new formula::FormulaDoubleToken(fVal);
1043 //break;
1044 case CELLTYPE_FORMULA:
1046 ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
1047 USHORT nError = pFCell->GetErrCode();
1048 if (nError)
1049 return new FormulaErrorToken( nError);
1050 else if (pFCell->IsValue())
1052 double fVal = pFCell->GetValue();
1053 return new formula::FormulaDoubleToken(fVal);
1055 else
1057 String aStr;
1058 pFCell->GetString(aStr);
1059 return new formula::FormulaStringToken(aStr);
1062 //break;
1063 default:
1064 DBG_ERROR("attempted to convert an unknown cell type.");
1067 return NULL;
1070 static ScTokenArray* lcl_convertToTokenArray(ScDocument* pSrcDoc, const ScRange& rRange,
1071 vector<ScExternalRefCache::SingleRangeData>& rCacheData)
1073 const ScAddress& s = rRange.aStart;
1074 const ScAddress& e = rRange.aEnd;
1076 SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
1077 SCCOL nCol1 = s.Col(), nCol2 = e.Col();
1078 SCROW nRow1 = s.Row(), nRow2 = e.Row();
1080 if (nTab2 != nTab1)
1081 // For now, we don't support multi-sheet ranges intentionally because
1082 // we don't have a way to express them in a single token. In the
1083 // future we can introduce a new stack variable type svMatrixList with
1084 // a new token type that can store a 3D matrix value and convert a 3D
1085 // range to it.
1086 return NULL;
1088 auto_ptr<ScTokenArray> pArray(new ScTokenArray);
1089 bool bFirstTab = true;
1090 vector<ScExternalRefCache::SingleRangeData>::iterator
1091 itrCache = rCacheData.begin(), itrCacheEnd = rCacheData.end();
1092 for (SCTAB nTab = nTab1; nTab <= nTab2 && itrCache != itrCacheEnd; ++nTab, ++itrCache)
1094 ScMatrixRef xMat = new ScMatrix(
1095 static_cast<SCSIZE>(nCol2-nCol1+1),
1096 static_cast<SCSIZE>(nRow2-nRow1+1));
1098 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
1100 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
1102 SCSIZE nC = nCol - nCol1, nR = nRow - nRow1;
1103 ScBaseCell* pCell;
1104 pSrcDoc->GetCell(nCol, nRow, nTab, pCell);
1105 if (!pCell || pCell->HasEmptyData())
1106 xMat->PutEmpty(nC, nR);
1107 else
1109 switch (pCell->GetCellType())
1111 case CELLTYPE_EDIT:
1113 String aStr;
1114 static_cast<ScEditCell*>(pCell)->GetString(aStr);
1115 xMat->PutString(aStr, nC, nR);
1117 break;
1118 case CELLTYPE_STRING:
1120 String aStr;
1121 static_cast<ScStringCell*>(pCell)->GetString(aStr);
1122 xMat->PutString(aStr, nC, nR);
1124 break;
1125 case CELLTYPE_VALUE:
1127 double fVal = static_cast<ScValueCell*>(pCell)->GetValue();
1128 xMat->PutDouble(fVal, nC, nR);
1130 break;
1131 case CELLTYPE_FORMULA:
1133 ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
1134 USHORT nError = pFCell->GetErrCode();
1135 if (nError)
1136 xMat->PutDouble( CreateDoubleError( nError), nC, nR);
1137 else if (pFCell->IsValue())
1139 double fVal = pFCell->GetValue();
1140 xMat->PutDouble(fVal, nC, nR);
1142 else
1144 String aStr;
1145 pFCell->GetString(aStr);
1146 xMat->PutString(aStr, nC, nR);
1149 break;
1150 default:
1151 DBG_ERROR("attempted to convert an unknown cell type.");
1156 if (!bFirstTab)
1157 pArray->AddOpCode(ocSep);
1159 ScMatrix* pMat2 = xMat;
1160 ScMatrixToken aToken(pMat2);
1161 pArray->AddToken(aToken);
1163 itrCache->mpRangeData = xMat;
1165 bFirstTab = false;
1167 return pArray.release();
1170 ScExternalRefManager::ScExternalRefManager(ScDocument* pDoc) :
1171 mpDoc(pDoc),
1172 bInReferenceMarking(false)
1174 maSrcDocTimer.SetTimeoutHdl( LINK(this, ScExternalRefManager, TimeOutHdl) );
1175 maSrcDocTimer.SetTimeout(SRCDOC_SCAN_INTERVAL);
1178 ScExternalRefManager::~ScExternalRefManager()
1180 clear();
1183 String ScExternalRefManager::getCacheTableName(sal_uInt16 nFileId, size_t nTabIndex) const
1185 return maRefCache.getTableName(nFileId, nTabIndex);
1188 ScExternalRefCache::TableTypeRef ScExternalRefManager::getCacheTable(sal_uInt16 nFileId, size_t nTabIndex) const
1190 return maRefCache.getCacheTable(nFileId, nTabIndex);
1193 ScExternalRefCache::TableTypeRef ScExternalRefManager::getCacheTable(sal_uInt16 nFileId, const String& rTabName, bool bCreateNew, size_t* pnIndex)
1195 return maRefCache.getCacheTable(nFileId, rTabName, bCreateNew, pnIndex);
1198 // ============================================================================
1200 ScExternalRefManager::RefCells::TabItem::TabItem(SCTAB nIndex) :
1201 mnIndex(nIndex)
1205 ScExternalRefManager::RefCells::TabItem::TabItem(const TabItem& r) :
1206 mnIndex(r.mnIndex),
1207 maCols(r.maCols)
1211 ScExternalRefManager::RefCells::RefCells()
1215 ScExternalRefManager::RefCells::~RefCells()
1219 list<ScExternalRefManager::RefCells::TabItemRef>::iterator ScExternalRefManager::RefCells::getTabPos(SCTAB nTab)
1221 list<TabItemRef>::iterator itr = maTables.begin(), itrEnd = maTables.end();
1222 for (; itr != itrEnd; ++itr)
1223 if ((*itr)->mnIndex >= nTab)
1224 return itr;
1225 // Not found. return the end position.
1226 return itrEnd;
1229 void ScExternalRefManager::RefCells::insertCell(const ScAddress& rAddr)
1231 SCTAB nTab = rAddr.Tab();
1232 SCCOL nCol = rAddr.Col();
1233 SCROW nRow = rAddr.Row();
1235 // Search by table index.
1236 list<TabItemRef>::iterator itrTab = getTabPos(nTab);
1237 TabItemRef xTabRef;
1238 if (itrTab == maTables.end())
1240 // All previous tables come before the specificed table.
1241 xTabRef.reset(new TabItem(nTab));
1242 maTables.push_back(xTabRef);
1244 else if ((*itrTab)->mnIndex > nTab)
1246 // Insert at the current iterator position.
1247 xTabRef.reset(new TabItem(nTab));
1248 maTables.insert(itrTab, xTabRef);
1250 else if ((*itrTab)->mnIndex == nTab)
1252 // The table found.
1253 xTabRef = *itrTab;
1255 ColSet& rCols = xTabRef->maCols;
1257 // Then by column index.
1258 ColSet::iterator itrCol = rCols.find(nCol);
1259 if (itrCol == rCols.end())
1261 RowSet aRows;
1262 pair<ColSet::iterator, bool> r = rCols.insert(ColSet::value_type(nCol, aRows));
1263 if (!r.second)
1264 // column insertion failed.
1265 return;
1266 itrCol = r.first;
1268 RowSet& rRows = itrCol->second;
1270 // Finally, insert the row index.
1271 rRows.insert(nRow);
1274 void ScExternalRefManager::RefCells::removeCell(const ScAddress& rAddr)
1276 SCTAB nTab = rAddr.Tab();
1277 SCCOL nCol = rAddr.Col();
1278 SCROW nRow = rAddr.Row();
1280 // Search by table index.
1281 list<TabItemRef>::iterator itrTab = getTabPos(nTab);
1282 if (itrTab == maTables.end() || (*itrTab)->mnIndex != nTab)
1283 // No such table.
1284 return;
1286 ColSet& rCols = (*itrTab)->maCols;
1288 // Then by column index.
1289 ColSet::iterator itrCol = rCols.find(nCol);
1290 if (itrCol == rCols.end())
1291 // No such column
1292 return;
1294 RowSet& rRows = itrCol->second;
1295 rRows.erase(nRow);
1298 void ScExternalRefManager::RefCells::moveTable(SCTAB nOldTab, SCTAB nNewTab, bool bCopy)
1300 if (nOldTab == nNewTab)
1301 // Nothing to do here.
1302 return;
1304 list<TabItemRef>::iterator itrOld = getTabPos(nOldTab);
1305 if (itrOld == maTables.end() || (*itrOld)->mnIndex != nOldTab)
1306 // No table to move or copy.
1307 return;
1309 list<TabItemRef>::iterator itrNew = getTabPos(nNewTab);
1310 if (bCopy)
1312 // Simply make a duplicate of the original table, insert it at the
1313 // new tab position, and increment the table index for all tables
1314 // that come after that inserted table.
1316 TabItemRef xNewTab(new TabItem(*(*itrOld)));
1317 xNewTab->mnIndex = nNewTab;
1318 maTables.insert(itrNew, xNewTab);
1319 list<TabItemRef>::iterator itr = itrNew, itrEnd = maTables.end();
1320 for (++itr; itr != itrEnd; ++itr)
1321 (*itr)->mnIndex += 1;
1323 else
1325 if (itrOld == itrNew)
1327 // No need to move the table. Just update the table index.
1328 (*itrOld)->mnIndex = nNewTab;
1329 return;
1332 if (nOldTab < nNewTab)
1334 // Iterate from the old tab position to the new tab position (not
1335 // inclusive of the old tab itself), and decrement their tab
1336 // index by one.
1337 list<TabItemRef>::iterator itr = itrOld;
1338 for (++itr; itr != itrNew; ++itr)
1339 (*itr)->mnIndex -= 1;
1341 // Insert a duplicate of the original table. This does not
1342 // invalidate the iterators.
1343 (*itrOld)->mnIndex = nNewTab - 1;
1344 if (itrNew == maTables.end())
1345 maTables.push_back(*itrOld);
1346 else
1347 maTables.insert(itrNew, *itrOld);
1349 // Remove the original table.
1350 maTables.erase(itrOld);
1352 else
1354 // nNewTab < nOldTab
1356 // Iterate from the new tab position to the one before the old tab
1357 // position, and increment their tab index by one.
1358 list<TabItemRef>::iterator itr = itrNew;
1359 for (++itr; itr != itrOld; ++itr)
1360 (*itr)->mnIndex += 1;
1362 (*itrOld)->mnIndex = nNewTab;
1363 maTables.insert(itrNew, *itrOld);
1365 // Remove the original table.
1366 maTables.erase(itrOld);
1371 void ScExternalRefManager::RefCells::insertTable(SCTAB nPos)
1373 TabItemRef xNewTab(new TabItem(nPos));
1374 list<TabItemRef>::iterator itr = getTabPos(nPos);
1375 if (itr == maTables.end())
1376 maTables.push_back(xNewTab);
1377 else
1378 maTables.insert(itr, xNewTab);
1381 void ScExternalRefManager::RefCells::removeTable(SCTAB nPos)
1383 list<TabItemRef>::iterator itr = getTabPos(nPos);
1384 if (itr == maTables.end())
1385 // nothing to remove.
1386 return;
1388 maTables.erase(itr);
1391 void ScExternalRefManager::RefCells::refreshAllCells(ScExternalRefManager& rRefMgr)
1393 // Get ALL the cell positions for re-compilation.
1394 for (list<TabItemRef>::iterator itrTab = maTables.begin(), itrTabEnd = maTables.end();
1395 itrTab != itrTabEnd; ++itrTab)
1397 SCTAB nTab = (*itrTab)->mnIndex;
1398 ColSet& rCols = (*itrTab)->maCols;
1399 for (ColSet::iterator itrCol = rCols.begin(), itrColEnd = rCols.end();
1400 itrCol != itrColEnd; ++itrCol)
1402 SCCOL nCol = itrCol->first;
1403 RowSet& rRows = itrCol->second;
1404 RowSet aNewRows;
1405 for (RowSet::iterator itrRow = rRows.begin(), itrRowEnd = rRows.end();
1406 itrRow != itrRowEnd; ++itrRow)
1408 SCROW nRow = *itrRow;
1409 ScAddress aCell(nCol, nRow, nTab);
1410 if (rRefMgr.compileTokensByCell(aCell))
1411 // This cell still contains an external refernce.
1412 aNewRows.insert(nRow);
1414 // Update the rows so that cells with no external references are
1415 // no longer tracked.
1416 rRows.swap(aNewRows);
1421 // ----------------------------------------------------------------------------
1423 ScExternalRefManager::LinkListener::LinkListener()
1427 ScExternalRefManager::LinkListener::~LinkListener()
1431 // ----------------------------------------------------------------------------
1433 void ScExternalRefManager::getAllCachedTableNames(sal_uInt16 nFileId, vector<String>& rTabNames) const
1435 maRefCache.getAllTableNames(nFileId, rTabNames);
1438 SCsTAB ScExternalRefManager::getCachedTabSpan( sal_uInt16 nFileId, const String& rStartTabName, const String& rEndTabName ) const
1440 return maRefCache.getTabSpan( nFileId, rStartTabName, rEndTabName);
1443 void ScExternalRefManager::getAllCachedNumberFormats(vector<sal_uInt32>& rNumFmts) const
1445 maRefCache.getAllNumberFormats(rNumFmts);
1448 bool ScExternalRefManager::hasCacheTable(sal_uInt16 nFileId, const String& rTabName) const
1450 return maRefCache.hasCacheTable(nFileId, rTabName);
1453 size_t ScExternalRefManager::getCacheTableCount(sal_uInt16 nFileId) const
1455 return maRefCache.getCacheTableCount(nFileId);
1458 sal_uInt16 ScExternalRefManager::getExternalFileCount() const
1460 return static_cast< sal_uInt16 >( maSrcFiles.size() );
1463 bool ScExternalRefManager::markUsedByLinkListeners()
1465 bool bAllMarked = false;
1466 for (LinkListenerMap::const_iterator itr = maLinkListeners.begin();
1467 itr != maLinkListeners.end() && !bAllMarked; ++itr)
1469 if (!(*itr).second.empty())
1470 bAllMarked = maRefCache.setCacheDocReferenced( (*itr).first);
1471 /* TODO: LinkListeners should remember the table they're listening to.
1472 * As is, listening to one table will mark all tables of the document
1473 * being referenced. */
1475 return bAllMarked;
1478 bool ScExternalRefManager::setCacheDocReferenced( sal_uInt16 nFileId )
1480 return maRefCache.setCacheDocReferenced( nFileId);
1483 bool ScExternalRefManager::setCacheTableReferenced( sal_uInt16 nFileId, const String& rTabName )
1485 return maRefCache.setCacheTableReferenced( nFileId, rTabName);
1488 void ScExternalRefManager::setAllCacheTableReferencedStati( bool bReferenced )
1490 bInReferenceMarking = !bReferenced;
1491 maRefCache.setAllCacheTableReferencedStati( bReferenced );
1494 void ScExternalRefManager::storeRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScTokenArray& rArray)
1496 ScExternalRefCache::TokenArrayRef pArray(rArray.Clone());
1497 maRefCache.setRangeNameTokens(nFileId, rName, pArray);
1500 ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefToken(
1501 sal_uInt16 nFileId, const String& rTabName, const ScAddress& rCell,
1502 const ScAddress* pCurPos, SCTAB* pTab, ScExternalRefCache::CellFormat* pFmt)
1504 if (pCurPos)
1505 insertRefCell(nFileId, *pCurPos);
1507 maybeLinkExternalFile(nFileId);
1509 if (pTab)
1510 *pTab = -1;
1512 if (pFmt)
1513 pFmt->mbIsSet = false;
1515 bool bLoading = mpDoc->IsImportingXML();
1517 // Check if the given table name and the cell position is cached.
1518 // #i101304# When loading a file, the saved cache (hidden sheet)
1519 // is assumed to contain all data for the loaded formulas.
1520 // No cache entries are created from empty cells in the saved sheet,
1521 // so they have to be created here (bWriteEmpty parameter).
1522 // Otherwise, later interpretation of the loaded formulas would
1523 // load the source document even if the user didn't want to update.
1524 sal_uInt32 nFmtIndex = 0;
1525 ScExternalRefCache::TokenRef pToken = maRefCache.getCellData(
1526 nFileId, rTabName, rCell.Col(), rCell.Row(), bLoading, bLoading, &nFmtIndex);
1527 if (pToken)
1529 if (pFmt)
1531 short nFmtType = mpDoc->GetFormatTable()->GetType(nFmtIndex);
1532 if (nFmtType != NUMBERFORMAT_UNDEFINED)
1534 pFmt->mbIsSet = true;
1535 pFmt->mnIndex = nFmtIndex;
1536 pFmt->mnType = nFmtType;
1539 return pToken;
1542 // reference not cached. read from the source document.
1543 ScDocument* pSrcDoc = getSrcDocument(nFileId);
1544 if (!pSrcDoc)
1546 // Source document is not reachable. Try to get data from the cache
1547 // once again, but this time treat a non-cached cell as an empty cell
1548 // as long as the table itself is cached.
1549 pToken = maRefCache.getCellData(
1550 nFileId, rTabName, rCell.Col(), rCell.Row(), true, false, &nFmtIndex);
1551 return pToken;
1554 ScBaseCell* pCell = NULL;
1555 SCTAB nTab;
1556 if (!pSrcDoc->GetTable(rTabName, nTab))
1558 // specified table name doesn't exist in the source document.
1559 return ScExternalRefCache::TokenRef();
1562 if (pTab)
1563 *pTab = nTab;
1565 pSrcDoc->GetCell(rCell.Col(), rCell.Row(), nTab, pCell);
1566 ScExternalRefCache::TokenRef pTok(lcl_convertToToken(pCell));
1568 pSrcDoc->GetNumberFormat(rCell.Col(), rCell.Row(), nTab, nFmtIndex);
1569 nFmtIndex = getMappedNumberFormat(nFileId, nFmtIndex, pSrcDoc);
1570 if (pFmt)
1572 short nFmtType = mpDoc->GetFormatTable()->GetType(nFmtIndex);
1573 if (nFmtType != NUMBERFORMAT_UNDEFINED)
1575 pFmt->mbIsSet = true;
1576 pFmt->mnIndex = nFmtIndex;
1577 pFmt->mnType = nFmtType;
1581 if (!pTok.get())
1583 // Generate an error for unresolvable cells.
1584 pTok.reset( new FormulaErrorToken( errNoValue));
1587 // Now, insert the token into cache table.
1588 maRefCache.setCellData(nFileId, rTabName, rCell.Row(), rCell.Col(), pTok, nFmtIndex);
1589 return pTok;
1592 ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokens(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange, const ScAddress* pCurPos)
1594 if (pCurPos)
1595 insertRefCell(nFileId, *pCurPos);
1597 maybeLinkExternalFile(nFileId);
1599 bool bLoading = mpDoc->IsImportingXML();
1601 // Check if the given table name and the cell position is cached.
1602 // #i101304# When loading, put empty cells into cache, see getSingleRefToken.
1603 ScExternalRefCache::TokenArrayRef p = maRefCache.getCellRangeData(nFileId, rTabName, rRange, bLoading, bLoading);
1604 if (p.get())
1605 return p;
1607 ScDocument* pSrcDoc = getSrcDocument(nFileId);
1608 if (!pSrcDoc)
1610 // Source document is not reachable. Try to get data from the cache
1611 // once again, but this time treat non-cached cells as empty cells as
1612 // long as the table itself is cached.
1613 return maRefCache.getCellRangeData(nFileId, rTabName, rRange, true, false);
1616 SCTAB nTab1;
1617 if (!pSrcDoc->GetTable(rTabName, nTab1))
1618 // specified table name doesn't exist in the source document.
1619 return ScExternalRefCache::TokenArrayRef();
1621 ScRange aRange(rRange);
1622 SCTAB nTabSpan = aRange.aEnd.Tab() - aRange.aStart.Tab();
1624 vector<ScExternalRefCache::SingleRangeData> aCacheData;
1625 aCacheData.reserve(nTabSpan+1);
1626 aCacheData.push_back(ScExternalRefCache::SingleRangeData());
1627 aCacheData.back().maTableName = ScGlobal::pCharClass->upper(rTabName);
1629 for (SCTAB i = 1; i < nTabSpan + 1; ++i)
1631 String aTabName;
1632 if (!pSrcDoc->GetName(nTab1 + 1, aTabName))
1633 // source document doesn't have any table by the specified name.
1634 break;
1636 aCacheData.push_back(ScExternalRefCache::SingleRangeData());
1637 aCacheData.back().maTableName = ScGlobal::pCharClass->upper(aTabName);
1640 aRange.aStart.SetTab(nTab1);
1641 aRange.aEnd.SetTab(nTab1 + nTabSpan);
1643 ScExternalRefCache::TokenArrayRef pArray;
1644 pArray.reset(lcl_convertToTokenArray(pSrcDoc, aRange, aCacheData));
1646 if (pArray)
1647 // Cache these values.
1648 maRefCache.setCellRangeData(nFileId, rRange, aCacheData, pArray);
1650 return pArray;
1653 ScExternalRefCache::TokenArrayRef ScExternalRefManager::getRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScAddress* pCurPos)
1655 if (pCurPos)
1656 insertRefCell(nFileId, *pCurPos);
1658 maybeLinkExternalFile(nFileId);
1660 ScExternalRefCache::TokenArrayRef pArray = maRefCache.getRangeNameTokens(nFileId, rName);
1661 if (pArray.get())
1662 return pArray;
1664 ScDocument* pSrcDoc = getSrcDocument(nFileId);
1665 if (!pSrcDoc)
1666 return ScExternalRefCache::TokenArrayRef();
1668 ScRangeName* pExtNames = pSrcDoc->GetRangeName();
1669 String aUpperName = ScGlobal::pCharClass->upper(rName);
1670 USHORT n;
1671 bool bRes = pExtNames->SearchNameUpper(aUpperName, n);
1672 if (!bRes)
1673 return ScExternalRefCache::TokenArrayRef();
1675 ScRangeData* pRangeData = (*pExtNames)[n];
1676 if (!pRangeData)
1677 return ScExternalRefCache::TokenArrayRef();
1679 // Parse all tokens in this external range data, and replace each absolute
1680 // reference token with an external reference token, and cache them. Also
1681 // register the source document with the link manager if it's a new
1682 // source.
1684 ScExternalRefCache::TokenArrayRef pNew(new ScTokenArray);
1686 ScTokenArray* pCode = pRangeData->GetCode();
1687 for (FormulaToken* pToken = pCode->First(); pToken; pToken = pCode->Next())
1689 bool bTokenAdded = false;
1690 switch (pToken->GetType())
1692 case svSingleRef:
1694 const ScSingleRefData& rRef = static_cast<ScToken*>(pToken)->GetSingleRef();
1695 String aTabName;
1696 pSrcDoc->GetName(rRef.nTab, aTabName);
1697 ScExternalSingleRefToken aNewToken(nFileId, aTabName, static_cast<ScToken*>(pToken)->GetSingleRef());
1698 pNew->AddToken(aNewToken);
1699 bTokenAdded = true;
1701 break;
1702 case svDoubleRef:
1704 const ScSingleRefData& rRef = static_cast<ScToken*>(pToken)->GetSingleRef();
1705 String aTabName;
1706 pSrcDoc->GetName(rRef.nTab, aTabName);
1707 ScExternalDoubleRefToken aNewToken(nFileId, aTabName, static_cast<ScToken*>(pToken)->GetDoubleRef());
1708 pNew->AddToken(aNewToken);
1709 bTokenAdded = true;
1711 break;
1712 default:
1713 ; // nothing
1716 if (!bTokenAdded)
1717 pNew->AddToken(*pToken);
1720 // Make sure to pass the correctly-cased range name here.
1721 maRefCache.setRangeNameTokens(nFileId, pRangeData->GetName(), pNew);
1722 return pNew;
1725 void ScExternalRefManager::refreshAllRefCells(sal_uInt16 nFileId)
1727 RefCellMap::iterator itrFile = maRefCells.find(nFileId);
1728 if (itrFile == maRefCells.end())
1729 return;
1731 RefCells& rRefCells = itrFile->second;
1732 rRefCells.refreshAllCells(*this);
1734 ScViewData* pViewData = ScDocShell::GetViewData();
1735 if (!pViewData)
1736 return;
1738 ScTabViewShell* pVShell = pViewData->GetViewShell();
1739 if (!pVShell)
1740 return;
1742 // Repainting the grid also repaints the texts, but is there a better way
1743 // to refresh texts?
1744 pVShell->Invalidate(FID_REPAINT);
1745 pVShell->PaintGrid();
1748 void ScExternalRefManager::insertRefCell(sal_uInt16 nFileId, const ScAddress& rCell)
1750 RefCellMap::iterator itr = maRefCells.find(nFileId);
1751 if (itr == maRefCells.end())
1753 RefCells aRefCells;
1754 pair<RefCellMap::iterator, bool> r = maRefCells.insert(
1755 RefCellMap::value_type(nFileId, aRefCells));
1756 if (!r.second)
1757 // insertion failed.
1758 return;
1760 itr = r.first;
1762 itr->second.insertCell(rCell);
1765 ScDocument* ScExternalRefManager::getSrcDocument(sal_uInt16 nFileId)
1767 if (!mpDoc->IsExecuteLinkEnabled())
1768 return NULL;
1770 DocShellMap::iterator itrEnd = maDocShells.end();
1771 DocShellMap::iterator itr = maDocShells.find(nFileId);
1773 if (itr != itrEnd)
1775 SfxObjectShell* p = itr->second.maShell;
1776 itr->second.maLastAccess = Time();
1777 return static_cast<ScDocShell*>(p)->GetDocument();
1780 const String* pFile = getExternalFileName(nFileId);
1781 if (!pFile)
1782 // no file name associated with this ID.
1783 return NULL;
1785 String aFilter;
1786 SrcShell aSrcDoc;
1787 aSrcDoc.maShell = loadSrcDocument(nFileId, aFilter);
1788 if (!aSrcDoc.maShell.Is())
1790 // source document could not be loaded.
1791 return NULL;
1794 if (maDocShells.empty())
1796 // If this is the first source document insertion, start up the timer.
1797 maSrcDocTimer.Start();
1800 maDocShells.insert(DocShellMap::value_type(nFileId, aSrcDoc));
1801 SfxObjectShell* p = aSrcDoc.maShell;
1802 ScDocument* pSrcDoc = static_cast<ScDocShell*>(p)->GetDocument();
1804 SCTAB nTabCount = pSrcDoc->GetTableCount();
1805 if (!maRefCache.isDocInitialized(nFileId) && nTabCount)
1807 // Populate the cache with all table names in the source document.
1808 vector<String> aTabNames;
1809 aTabNames.reserve(nTabCount);
1810 for (SCTAB i = 0; i < nTabCount; ++i)
1812 String aName;
1813 pSrcDoc->GetName(i, aName);
1814 aTabNames.push_back(aName);
1816 maRefCache.initializeDoc(nFileId, aTabNames);
1818 return pSrcDoc;
1821 SfxObjectShellRef ScExternalRefManager::loadSrcDocument(sal_uInt16 nFileId, String& rFilter)
1823 const SrcFileData* pFileData = getExternalFileData(nFileId);
1824 if (!pFileData)
1825 return NULL;
1827 // Always load the document by using the path created from the relative
1828 // path. If the referenced document is not there, simply exit. The
1829 // original file name should be used only when the relative path is not
1830 // given.
1831 String aFile = pFileData->maFileName;
1832 maybeCreateRealFileName(nFileId);
1833 if (pFileData->maRealFileName.Len())
1834 aFile = pFileData->maRealFileName;
1836 if (!isFileLoadable(aFile))
1837 return NULL;
1839 String aOptions;
1840 ScDocumentLoader::GetFilterName(aFile, rFilter, aOptions, true, false);
1841 const SfxFilter* pFilter = ScDocShell::Factory().GetFilterContainer()->GetFilter4FilterName(rFilter);
1843 if (!pFileData->maRelativeName.Len())
1845 // Generate a relative file path.
1846 INetURLObject aBaseURL(getOwnDocumentName());
1847 aBaseURL.insertName(OUString::createFromAscii("content.xml"));
1849 String aStr = URIHelper::simpleNormalizedMakeRelative(
1850 aBaseURL.GetMainURL(INetURLObject::NO_DECODE), aFile);
1852 setRelativeFileName(nFileId, aStr);
1855 // Update the filter data now that we are loading it again.
1856 setFilterData(nFileId, rFilter, aOptions);
1858 SfxItemSet* pSet = new SfxAllItemSet(SFX_APP()->GetPool());
1859 if (aOptions.Len())
1860 pSet->Put(SfxStringItem(SID_FILE_FILTEROPTIONS, aOptions));
1862 auto_ptr<SfxMedium> pMedium(new SfxMedium(aFile, STREAM_STD_READ, false, pFilter, pSet));
1863 if (pMedium->GetError() != ERRCODE_NONE)
1864 return NULL;
1866 pMedium->UseInteractionHandler(false);
1868 ScDocShell* pNewShell = new ScDocShell(SFX_CREATE_MODE_INTERNAL);
1869 SfxObjectShellRef aRef = pNewShell;
1871 // increment the recursive link count of the source document.
1872 ScExtDocOptions* pExtOpt = mpDoc->GetExtDocOptions();
1873 sal_uInt32 nLinkCount = pExtOpt ? pExtOpt->GetDocSettings().mnLinkCnt : 0;
1874 ScDocument* pSrcDoc = pNewShell->GetDocument();
1875 ScExtDocOptions* pExtOptNew = pSrcDoc->GetExtDocOptions();
1876 if (!pExtOptNew)
1878 pExtOptNew = new ScExtDocOptions;
1879 pSrcDoc->SetExtDocOptions(pExtOptNew);
1881 pExtOptNew->GetDocSettings().mnLinkCnt = nLinkCount + 1;
1883 pNewShell->DoLoad(pMedium.release());
1884 return aRef;
1887 bool ScExternalRefManager::isFileLoadable(const String& rFile) const
1889 if (!rFile.Len())
1890 return false;
1892 if (isOwnDocument(rFile))
1893 return false;
1895 if (utl::UCBContentHelper::IsFolder(rFile))
1896 return false;
1898 return utl::UCBContentHelper::Exists(rFile);
1901 void ScExternalRefManager::maybeLinkExternalFile(sal_uInt16 nFileId)
1903 if (maLinkedDocs.count(nFileId))
1904 // file alerady linked, or the link has been broken.
1905 return;
1907 // Source document not linked yet. Link it now.
1908 const String* pFileName = getExternalFileName(nFileId);
1909 if (!pFileName)
1910 return;
1912 String aFilter, aOptions;
1913 ScDocumentLoader::GetFilterName(*pFileName, aFilter, aOptions, true, false);
1914 SvxLinkManager* pLinkMgr = mpDoc->GetLinkManager();
1915 ScExternalRefLink* pLink = new ScExternalRefLink(mpDoc, nFileId, aFilter);
1916 DBG_ASSERT(pFileName, "ScExternalRefManager::insertExternalFileLink: file name pointer is NULL");
1917 pLinkMgr->InsertFileLink(*pLink, OBJECT_CLIENT_FILE, *pFileName, &aFilter);
1919 pLink->SetDoReferesh(false);
1920 pLink->Update();
1921 pLink->SetDoReferesh(true);
1923 maLinkedDocs.insert(LinkedDocMap::value_type(nFileId, true));
1926 void ScExternalRefManager::SrcFileData::maybeCreateRealFileName(const String& rOwnDocName)
1928 if (!maRelativeName.Len())
1929 // No relative path given. Nothing to do.
1930 return;
1932 if (maRealFileName.Len())
1933 // Real file name already created. Nothing to do.
1934 return;
1936 // Formulate the absolute file path from the relative path.
1937 const String& rRelPath = maRelativeName;
1938 INetURLObject aBaseURL(rOwnDocName);
1939 aBaseURL.insertName(OUString::createFromAscii("content.xml"));
1940 bool bWasAbs = false;
1941 maRealFileName = aBaseURL.smartRel2Abs(rRelPath, bWasAbs).GetMainURL(INetURLObject::NO_DECODE);
1944 void ScExternalRefManager::maybeCreateRealFileName(sal_uInt16 nFileId)
1946 if (nFileId >= maSrcFiles.size())
1947 return;
1949 maSrcFiles[nFileId].maybeCreateRealFileName(getOwnDocumentName());
1952 bool ScExternalRefManager::compileTokensByCell(const ScAddress& rCell)
1954 ScBaseCell* pCell;
1955 mpDoc->GetCell(rCell.Col(), rCell.Row(), rCell.Tab(), pCell);
1957 if (!pCell || pCell->GetCellType() != CELLTYPE_FORMULA)
1958 return false;
1960 ScFormulaCell* pFC = static_cast<ScFormulaCell*>(pCell);
1962 // Check to make sure the cell really contains ocExternalRef.
1963 // External names, external cell and range references all have a
1964 // ocExternalRef token.
1965 const ScTokenArray* pCode = pFC->GetCode();
1966 if (!pCode->HasOpCode( ocExternalRef))
1967 return false;
1969 ScTokenArray* pArray = pFC->GetCode();
1970 if (pArray)
1971 // Clear the error code, or a cell with error won't get re-compiled.
1972 pArray->SetCodeError(0);
1974 pFC->SetCompile(true);
1975 pFC->CompileTokenArray();
1976 pFC->SetDirty();
1978 return true;
1981 const String& ScExternalRefManager::getOwnDocumentName() const
1983 SfxObjectShell* pShell = mpDoc->GetDocumentShell();
1984 if (!pShell)
1985 // This should not happen!
1986 return EMPTY_STRING;
1988 SfxMedium* pMed = pShell->GetMedium();
1989 if (!pMed)
1990 return EMPTY_STRING;
1992 return pMed->GetName();
1995 bool ScExternalRefManager::isOwnDocument(const String& rFile) const
1997 return getOwnDocumentName().Equals(rFile);
2000 void ScExternalRefManager::convertToAbsName(String& rFile) const
2002 SfxObjectShell* pDocShell = mpDoc->GetDocumentShell();
2003 rFile = ScGlobal::GetAbsDocName(rFile, pDocShell);
2006 sal_uInt16 ScExternalRefManager::getExternalFileId(const String& rFile)
2008 vector<SrcFileData>::const_iterator itrBeg = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
2009 vector<SrcFileData>::const_iterator itr = find_if(itrBeg, itrEnd, FindSrcFileByName(rFile));
2010 if (itr != itrEnd)
2012 size_t nId = distance(itrBeg, itr);
2013 return static_cast<sal_uInt16>(nId);
2016 SrcFileData aData;
2017 aData.maFileName = rFile;
2018 maSrcFiles.push_back(aData);
2019 return static_cast<sal_uInt16>(maSrcFiles.size() - 1);
2022 const String* ScExternalRefManager::getExternalFileName(sal_uInt16 nFileId)
2024 if (nFileId >= maSrcFiles.size())
2025 return NULL;
2027 maybeCreateRealFileName(nFileId);
2029 if (maSrcFiles[nFileId].maRealFileName.Len())
2030 return &maSrcFiles[nFileId].maRealFileName;
2031 else
2032 return &maSrcFiles[nFileId].maFileName;
2035 bool ScExternalRefManager::hasExternalFile(sal_uInt16 nFileId) const
2037 return nFileId < maSrcFiles.size();
2040 bool ScExternalRefManager::hasExternalFile(const String& rFile) const
2042 vector<SrcFileData>::const_iterator itrBeg = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
2043 vector<SrcFileData>::const_iterator itr = find_if(itrBeg, itrEnd, FindSrcFileByName(rFile));
2044 return itr != itrEnd;
2047 const ScExternalRefManager::SrcFileData* ScExternalRefManager::getExternalFileData(sal_uInt16 nFileId) const
2049 if (nFileId >= maSrcFiles.size())
2050 return NULL;
2052 return &maSrcFiles[nFileId];
2055 const String* ScExternalRefManager::getRealTableName(sal_uInt16 nFileId, const String& rTabName) const
2057 return maRefCache.getRealTableName(nFileId, rTabName);
2060 const String* ScExternalRefManager::getRealRangeName(sal_uInt16 nFileId, const String& rRangeName) const
2062 return maRefCache.getRealRangeName(nFileId, rRangeName);
2065 template<typename MapContainer>
2066 void lcl_removeByFileId(sal_uInt16 nFileId, MapContainer& rMap)
2068 typename MapContainer::iterator itr = rMap.find(nFileId);
2069 if (itr != rMap.end())
2070 rMap.erase(itr);
2073 void ScExternalRefManager::refreshNames(sal_uInt16 nFileId)
2075 maRefCache.clearCache(nFileId);
2076 lcl_removeByFileId(nFileId, maDocShells);
2078 if (maDocShells.empty())
2079 maSrcDocTimer.Stop();
2081 // Update all cells containing names from this source document.
2082 refreshAllRefCells(nFileId);
2084 notifyAllLinkListeners(nFileId, LINK_MODIFIED);
2087 void ScExternalRefManager::breakLink(sal_uInt16 nFileId)
2089 lcl_removeByFileId(nFileId, maDocShells);
2091 if (maDocShells.empty())
2092 maSrcDocTimer.Stop();
2094 LinkedDocMap::iterator itr = maLinkedDocs.find(nFileId);
2095 if (itr != maLinkedDocs.end())
2096 itr->second = false;
2098 notifyAllLinkListeners(nFileId, LINK_BROKEN);
2101 void ScExternalRefManager::switchSrcFile(sal_uInt16 nFileId, const String& rNewFile, const String& rNewFilter)
2103 maSrcFiles[nFileId].maFileName = rNewFile;
2104 maSrcFiles[nFileId].maRelativeName.Erase();
2105 maSrcFiles[nFileId].maRealFileName.Erase();
2106 if (!maSrcFiles[nFileId].maFilterName.Equals(rNewFilter))
2108 // Filter type has changed.
2109 maSrcFiles[nFileId].maFilterName = rNewFilter;
2110 maSrcFiles[nFileId].maFilterOptions.Erase();
2112 refreshNames(nFileId);
2115 void ScExternalRefManager::setRelativeFileName(sal_uInt16 nFileId, const String& rRelUrl)
2117 if (nFileId >= maSrcFiles.size())
2118 return;
2119 maSrcFiles[nFileId].maRelativeName = rRelUrl;
2122 void ScExternalRefManager::setFilterData(sal_uInt16 nFileId, const String& rFilterName, const String& rOptions)
2124 if (nFileId >= maSrcFiles.size())
2125 return;
2126 maSrcFiles[nFileId].maFilterName = rFilterName;
2127 maSrcFiles[nFileId].maFilterOptions = rOptions;
2130 void ScExternalRefManager::clear()
2132 DocShellMap::iterator itrEnd = maDocShells.end();
2133 for (DocShellMap::iterator itr = maDocShells.begin(); itr != itrEnd; ++itr)
2134 itr->second.maShell->DoClose();
2136 maDocShells.clear();
2137 maSrcDocTimer.Stop();
2140 bool ScExternalRefManager::hasExternalData() const
2142 return !maSrcFiles.empty();
2145 void ScExternalRefManager::resetSrcFileData(const String& rBaseFileUrl)
2147 for (vector<SrcFileData>::iterator itr = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
2148 itr != itrEnd; ++itr)
2150 // Re-generate relative file name from the absolute file name.
2151 String aAbsName = itr->maRealFileName;
2152 if (!aAbsName.Len())
2153 aAbsName = itr->maFileName;
2155 itr->maRelativeName = URIHelper::simpleNormalizedMakeRelative(
2156 rBaseFileUrl, aAbsName);
2160 void ScExternalRefManager::updateRefCell(const ScAddress& rOldPos, const ScAddress& rNewPos, bool bCopy)
2162 for (RefCellMap::iterator itr = maRefCells.begin(), itrEnd = maRefCells.end(); itr != itrEnd; ++itr)
2164 if (!bCopy)
2165 itr->second.removeCell(rOldPos);
2166 itr->second.insertCell(rNewPos);
2170 void ScExternalRefManager::updateRefMoveTable(SCTAB nOldTab, SCTAB nNewTab, bool bCopy)
2172 for (RefCellMap::iterator itr = maRefCells.begin(), itrEnd = maRefCells.end(); itr != itrEnd; ++itr)
2173 itr->second.moveTable(nOldTab, nNewTab, bCopy);
2176 void ScExternalRefManager::updateRefInsertTable(SCTAB nPos)
2178 for (RefCellMap::iterator itr = maRefCells.begin(), itrEnd = maRefCells.end(); itr != itrEnd; ++itr)
2179 itr->second.insertTable(nPos);
2182 void ScExternalRefManager::updateRefDeleteTable(SCTAB nPos)
2184 for (RefCellMap::iterator itr = maRefCells.begin(), itrEnd = maRefCells.end(); itr != itrEnd; ++itr)
2185 itr->second.removeTable(nPos);
2188 void ScExternalRefManager::addLinkListener(sal_uInt16 nFileId, LinkListener* pListener)
2190 LinkListenerMap::iterator itr = maLinkListeners.find(nFileId);
2191 if (itr == maLinkListeners.end())
2193 pair<LinkListenerMap::iterator, bool> r = maLinkListeners.insert(
2194 LinkListenerMap::value_type(nFileId, LinkListeners()));
2195 if (!r.second)
2197 DBG_ERROR("insertion of new link listener list failed");
2198 return;
2201 itr = r.first;
2204 LinkListeners& rList = itr->second;
2205 rList.insert(pListener);
2208 void ScExternalRefManager::removeLinkListener(sal_uInt16 nFileId, LinkListener* pListener)
2210 LinkListenerMap::iterator itr = maLinkListeners.find(nFileId);
2211 if (itr == maLinkListeners.end())
2212 // no listeners for a specified file.
2213 return;
2215 LinkListeners& rList = itr->second;
2216 rList.erase(pListener);
2218 if (rList.empty())
2219 // No more listeners for this file. Remove its entry.
2220 maLinkListeners.erase(itr);
2223 void ScExternalRefManager::removeLinkListener(LinkListener* pListener)
2225 LinkListenerMap::iterator itr = maLinkListeners.begin(), itrEnd = maLinkListeners.end();
2226 for (; itr != itrEnd; ++itr)
2227 itr->second.erase(pListener);
2230 void ScExternalRefManager::notifyAllLinkListeners(sal_uInt16 nFileId, LinkUpdateType eType)
2232 LinkListenerMap::iterator itr = maLinkListeners.find(nFileId);
2233 if (itr == maLinkListeners.end())
2234 // no listeners for a specified file.
2235 return;
2237 LinkListeners& rList = itr->second;
2238 for_each(rList.begin(), rList.end(), NotifyLinkListener(nFileId, eType));
2241 void ScExternalRefManager::purgeStaleSrcDocument(sal_Int32 nTimeOut)
2243 DocShellMap aNewDocShells;
2244 DocShellMap::iterator itr = maDocShells.begin(), itrEnd = maDocShells.end();
2245 for (; itr != itrEnd; ++itr)
2247 // in 100th of a second.
2248 sal_Int32 nSinceLastAccess = (Time() - itr->second.maLastAccess).GetTime();
2249 if (nSinceLastAccess < nTimeOut)
2250 aNewDocShells.insert(*itr);
2252 maDocShells.swap(aNewDocShells);
2254 if (maDocShells.empty())
2255 maSrcDocTimer.Stop();
2258 sal_uInt32 ScExternalRefManager::getMappedNumberFormat(sal_uInt16 nFileId, sal_uInt32 nNumFmt, ScDocument* pSrcDoc)
2260 NumFmtMap::iterator itr = maNumFormatMap.find(nFileId);
2261 if (itr == maNumFormatMap.end())
2263 // Number formatter map is not initialized for this external document.
2264 pair<NumFmtMap::iterator, bool> r = maNumFormatMap.insert(
2265 NumFmtMap::value_type(nFileId, SvNumberFormatterMergeMap()));
2267 if (!r.second)
2268 // insertion failed.
2269 return nNumFmt;
2271 itr = r.first;
2272 mpDoc->GetFormatTable()->MergeFormatter( *pSrcDoc->GetFormatTable());
2273 SvNumberFormatterMergeMap aMap = mpDoc->GetFormatTable()->ConvertMergeTableToMap();
2274 itr->second.swap(aMap);
2276 const SvNumberFormatterMergeMap& rMap = itr->second;
2277 SvNumberFormatterMergeMap::const_iterator itrNumFmt = rMap.find(nNumFmt);
2278 if (itrNumFmt != rMap.end())
2279 // mapped value found.
2280 return itrNumFmt->second;
2282 return nNumFmt;
2285 IMPL_LINK(ScExternalRefManager, TimeOutHdl, AutoTimer*, pTimer)
2287 if (pTimer == &maSrcDocTimer)
2288 purgeStaleSrcDocument(SRCDOC_LIFE_SPAN);
2290 return 0;