merge the formfield patch from ooo-build
[ooovba.git] / sc / source / ui / docshell / externalrefmgr.cxx
blob8464799d7861f6e81eccf8fdc80e118274389abd
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 : meReferenced( REFERENCED_MARKED )
147 // Prevent accidental data loss due to lack of knowledge.
151 ScExternalRefCache::Table::~Table()
155 void ScExternalRefCache::Table::setReferencedFlag( ScExternalRefCache::Table::ReferencedFlag eFlag )
157 meReferenced = eFlag;
160 void ScExternalRefCache::Table::setReferenced( bool bReferenced )
162 if (meReferenced != REFERENCED_PERMANENT)
163 meReferenced = (bReferenced ? REFERENCED_MARKED : UNREFERENCED);
166 ScExternalRefCache::Table::ReferencedFlag ScExternalRefCache::Table::getReferencedFlag() const
168 return meReferenced;
171 bool ScExternalRefCache::Table::isReferenced() const
173 return meReferenced != UNREFERENCED;
176 void ScExternalRefCache::Table::setCell(SCCOL nCol, SCROW nRow, TokenRef pToken, sal_uInt32 nFmtIndex)
178 using ::std::pair;
179 RowsDataType::iterator itrRow = maRows.find(nRow);
180 if (itrRow == maRows.end())
182 // This row does not exist yet.
183 pair<RowsDataType::iterator, bool> res = maRows.insert(
184 RowsDataType::value_type(nRow, RowDataType()));
186 if (!res.second)
187 return;
189 itrRow = res.first;
192 // Insert this token into the specified column location. I don't need to
193 // check for existing data. Just overwrite it.
194 RowDataType& rRow = itrRow->second;
195 ScExternalRefCache::Cell aCell;
196 aCell.mxToken = pToken;
197 aCell.mnFmtIndex = nFmtIndex;
198 rRow.insert(RowDataType::value_type(nCol, aCell));
201 ScExternalRefCache::TokenRef ScExternalRefCache::Table::getCell(SCCOL nCol, SCROW nRow, sal_uInt32* pnFmtIndex) const
203 RowsDataType::const_iterator itrTable = maRows.find(nRow);
204 if (itrTable == maRows.end())
206 // this table doesn't have the specified row.
207 return TokenRef();
210 const RowDataType& rRowData = itrTable->second;
211 RowDataType::const_iterator itrRow = rRowData.find(nCol);
212 if (itrRow == rRowData.end())
214 // this row doesn't have the specified column.
215 return TokenRef();
218 const Cell& rCell = itrRow->second;
219 if (pnFmtIndex)
220 *pnFmtIndex = rCell.mnFmtIndex;
222 return rCell.mxToken;
225 bool ScExternalRefCache::Table::hasRow( SCROW nRow ) const
227 RowsDataType::const_iterator itrRow = maRows.find(nRow);
228 return itrRow != maRows.end();
231 void ScExternalRefCache::Table::getAllRows(vector<SCROW>& rRows) const
233 vector<SCROW> aRows;
234 aRows.reserve(maRows.size());
235 RowsDataType::const_iterator itr = maRows.begin(), itrEnd = maRows.end();
236 for (; itr != itrEnd; ++itr)
237 aRows.push_back(itr->first);
239 // hash map is not ordered, so we need to explicitly sort it.
240 ::std::sort(aRows.begin(), aRows.end());
241 rRows.swap(aRows);
244 void ScExternalRefCache::Table::getAllCols(SCROW nRow, vector<SCCOL>& rCols) const
246 RowsDataType::const_iterator itrRow = maRows.find(nRow);
247 if (itrRow == maRows.end())
248 // this table doesn't have the specified row.
249 return;
251 const RowDataType& rRowData = itrRow->second;
252 vector<SCCOL> aCols;
253 aCols.reserve(rRowData.size());
254 RowDataType::const_iterator itrCol = rRowData.begin(), itrColEnd = rRowData.end();
255 for (; itrCol != itrColEnd; ++itrCol)
256 aCols.push_back(itrCol->first);
258 // hash map is not ordered, so we need to explicitly sort it.
259 ::std::sort(aCols.begin(), aCols.end());
260 rCols.swap(aCols);
263 void ScExternalRefCache::Table::getAllNumberFormats(vector<sal_uInt32>& rNumFmts) const
265 RowsDataType::const_iterator itrRow = maRows.begin(), itrRowEnd = maRows.end();
266 for (; itrRow != itrRowEnd; ++itrRow)
268 const RowDataType& rRowData = itrRow->second;
269 RowDataType::const_iterator itrCol = rRowData.begin(), itrColEnd = rRowData.end();
270 for (; itrCol != itrColEnd; ++itrCol)
272 const Cell& rCell = itrCol->second;
273 rNumFmts.push_back(rCell.mnFmtIndex);
278 // ----------------------------------------------------------------------------
280 ScExternalRefCache::TableName::TableName(const String& rUpper, const String& rReal) :
281 maUpperName(rUpper), maRealName(rReal)
285 // ----------------------------------------------------------------------------
287 ScExternalRefCache::CellFormat::CellFormat() :
288 mbIsSet(false), mnType(NUMBERFORMAT_ALL), mnIndex(0)
292 // ----------------------------------------------------------------------------
294 ScExternalRefCache::ScExternalRefCache()
297 ScExternalRefCache::~ScExternalRefCache()
301 const String* ScExternalRefCache::getRealTableName(sal_uInt16 nFileId, const String& rTabName) const
303 DocDataType::const_iterator itrDoc = maDocs.find(nFileId);
304 if (itrDoc == maDocs.end())
306 // specified document is not cached.
307 return NULL;
310 const DocItem& rDoc = itrDoc->second;
311 TableNameIndexMap::const_iterator itrTabId = rDoc.maTableNameIndex.find(
312 ScGlobal::pCharClass->upper(rTabName));
313 if (itrTabId == rDoc.maTableNameIndex.end())
315 // the specified table is not in cache.
316 return NULL;
319 return &rDoc.maTableNames[itrTabId->second].maRealName;
322 const String* ScExternalRefCache::getRealRangeName(sal_uInt16 nFileId, const String& rRangeName) const
324 DocDataType::const_iterator itrDoc = maDocs.find(nFileId);
325 if (itrDoc == maDocs.end())
327 // specified document is not cached.
328 return NULL;
331 const DocItem& rDoc = itrDoc->second;
332 NamePairMap::const_iterator itr = rDoc.maRealRangeNameMap.find(
333 ScGlobal::pCharClass->upper(rRangeName));
334 if (itr == rDoc.maRealRangeNameMap.end())
335 // range name not found.
336 return NULL;
338 return &itr->second;
341 ScExternalRefCache::TokenRef ScExternalRefCache::getCellData(
342 sal_uInt16 nFileId, const String& rTabName, SCCOL nCol, SCROW nRow,
343 bool bEmptyCellOnNull, bool bWriteEmpty, sal_uInt32* pnFmtIndex)
345 DocDataType::const_iterator itrDoc = maDocs.find(nFileId);
346 if (itrDoc == maDocs.end())
348 // specified document is not cached.
349 return TokenRef();
352 const DocItem& rDoc = itrDoc->second;
353 TableNameIndexMap::const_iterator itrTabId = rDoc.maTableNameIndex.find(
354 ScGlobal::pCharClass->upper(rTabName));
355 if (itrTabId == rDoc.maTableNameIndex.end())
357 // the specified table is not in cache.
358 return TokenRef();
361 const TableTypeRef& pTableData = rDoc.maTables[itrTabId->second];
362 if (!pTableData.get())
364 // the table data is not instantiated yet.
365 return TokenRef();
368 TokenRef pToken = pTableData->getCell(nCol, nRow, pnFmtIndex);
369 if (!pToken && bEmptyCellOnNull)
371 pToken.reset(new ScEmptyCellToken(false, false));
372 if (bWriteEmpty)
373 pTableData->setCell(nCol, nRow, pToken);
375 return pToken;
378 ScExternalRefCache::TokenArrayRef ScExternalRefCache::getCellRangeData(
379 sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange, bool bEmptyCellOnNull, bool bWriteEmpty)
381 DocDataType::iterator itrDoc = maDocs.find(nFileId);
382 if (itrDoc == maDocs.end())
383 // specified document is not cached.
384 return TokenArrayRef();
386 DocItem& rDoc = itrDoc->second;
387 RangeArrayMap::const_iterator itrRange = rDoc.maRangeArrays.find(rRange);
388 if (itrRange != rDoc.maRangeArrays.end())
390 return itrRange->second;
393 TableNameIndexMap::iterator itrTabId = rDoc.maTableNameIndex.find(
394 ScGlobal::pCharClass->upper(rTabName));
395 if (itrTabId == rDoc.maTableNameIndex.end())
396 // the specified table is not in cache.
397 return TokenArrayRef();
399 const ScAddress& s = rRange.aStart;
400 const ScAddress& e = rRange.aEnd;
402 SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
403 SCCOL nCol1 = s.Col(), nCol2 = e.Col();
404 SCROW nRow1 = s.Row(), nRow2 = e.Row();
406 // Make sure I have all the tables cached.
407 size_t nTabFirstId = itrTabId->second;
408 size_t nTabLastId = nTabFirstId + nTab2 - nTab1;
409 if (nTabLastId >= rDoc.maTables.size())
410 // not all tables are cached.
411 return TokenArrayRef();
413 TokenArrayRef pArray(new ScTokenArray);
414 bool bFirstTab = true;
415 for (size_t nTab = nTabFirstId; nTab <= nTabLastId; ++nTab)
417 TableTypeRef pTab = rDoc.maTables[nTab];
418 if (!pTab.get())
419 return TokenArrayRef();
421 ScMatrixRef xMat = new ScMatrix(
422 static_cast<SCSIZE>(nCol2-nCol1+1), static_cast<SCSIZE>(nRow2-nRow1+1));
424 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
426 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
428 TokenRef pToken = pTab->getCell(nCol, nRow);
429 if (!pToken)
431 if (bEmptyCellOnNull)
433 pToken.reset(new ScEmptyCellToken(false, false));
434 if (bWriteEmpty)
435 pTab->setCell(nCol, nRow, pToken);
437 else
438 return TokenArrayRef();
441 SCSIZE nC = nCol - nCol1, nR = nRow - nRow1;
442 switch (pToken->GetType())
444 case svDouble:
445 xMat->PutDouble(pToken->GetDouble(), nC, nR);
446 break;
447 case svString:
448 xMat->PutString(pToken->GetString(), nC, nR);
449 break;
450 default:
451 xMat->PutEmpty(nC, nR);
456 if (!bFirstTab)
457 pArray->AddOpCode(ocSep);
459 ScMatrix* pMat2 = xMat;
460 ScMatrixToken aToken(pMat2);
461 pArray->AddToken(aToken);
463 bFirstTab = false;
465 rDoc.maRangeArrays.insert(RangeArrayMap::value_type(rRange, pArray));
466 return pArray;
469 ScExternalRefCache::TokenArrayRef ScExternalRefCache::getRangeNameTokens(sal_uInt16 nFileId, const String& rName)
471 DocItem* pDoc = getDocItem(nFileId);
472 if (!pDoc)
473 return TokenArrayRef();
475 RangeNameMap& rMap = pDoc->maRangeNames;
476 RangeNameMap::const_iterator itr = rMap.find(
477 ScGlobal::pCharClass->upper(rName));
478 if (itr == rMap.end())
479 return TokenArrayRef();
481 return itr->second;
484 void ScExternalRefCache::setRangeNameTokens(sal_uInt16 nFileId, const String& rName, TokenArrayRef pArray)
486 DocItem* pDoc = getDocItem(nFileId);
487 if (!pDoc)
488 return;
490 String aUpperName = ScGlobal::pCharClass->upper(rName);
491 RangeNameMap& rMap = pDoc->maRangeNames;
492 rMap.insert(RangeNameMap::value_type(aUpperName, pArray));
493 pDoc->maRealRangeNameMap.insert(NamePairMap::value_type(aUpperName, rName));
496 void ScExternalRefCache::setCellData(sal_uInt16 nFileId, const String& rTabName, SCROW nRow, SCCOL nCol,
497 TokenRef pToken, sal_uInt32 nFmtIndex)
499 if (!isDocInitialized(nFileId))
500 return;
502 using ::std::pair;
503 DocItem* pDocItem = getDocItem(nFileId);
504 if (!pDocItem)
505 return;
507 DocItem& rDoc = *pDocItem;
509 // See if the table by this name already exists.
510 TableNameIndexMap::iterator itrTabName = rDoc.maTableNameIndex.find(
511 ScGlobal::pCharClass->upper(rTabName));
512 if (itrTabName == rDoc.maTableNameIndex.end())
513 // Table not found. Maybe the table name or the file id is wrong ???
514 return;
516 TableTypeRef& pTableData = rDoc.maTables[itrTabName->second];
517 if (!pTableData.get())
518 pTableData.reset(new Table);
520 pTableData->setCell(nCol, nRow, pToken, nFmtIndex);
523 void ScExternalRefCache::setCellRangeData(sal_uInt16 nFileId, const ScRange& rRange, const vector<SingleRangeData>& rData,
524 TokenArrayRef pArray)
526 using ::std::pair;
527 if (rData.empty() || !isDocInitialized(nFileId))
528 // nothing to cache
529 return;
531 // First, get the document item for the given file ID.
532 DocItem* pDocItem = getDocItem(nFileId);
533 if (!pDocItem)
534 return;
536 DocItem& rDoc = *pDocItem;
538 // Now, find the table position of the first table to cache.
539 const String& rFirstTabName = rData.front().maTableName;
540 TableNameIndexMap::iterator itrTabName = rDoc.maTableNameIndex.find(
541 ScGlobal::pCharClass->upper(rFirstTabName));
542 if (itrTabName == rDoc.maTableNameIndex.end())
544 // table index not found.
545 return;
548 size_t nTab1 = itrTabName->second;
549 SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
550 SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
551 vector<SingleRangeData>::const_iterator itrDataBeg = rData.begin(), itrDataEnd = rData.end();
552 for (vector<SingleRangeData>::const_iterator itrData = itrDataBeg; itrData != itrDataEnd; ++itrData)
554 size_t i = nTab1 + ::std::distance(itrDataBeg, itrData);
555 TableTypeRef& pTabData = rDoc.maTables[i];
556 if (!pTabData.get())
557 pTabData.reset(new Table);
559 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
561 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
563 SCSIZE nC = nCol - nCol1, nR = nRow - nRow1;
564 TokenRef pToken;
565 const ScMatrixRef& pMat = itrData->mpRangeData;
566 if (pMat->IsValue(nC, nR))
567 pToken.reset(new formula::FormulaDoubleToken(pMat->GetDouble(nC, nR)));
568 else if (pMat->IsString(nC, nR))
569 pToken.reset(new formula::FormulaStringToken(pMat->GetString(nC, nR)));
570 else
571 pToken.reset(new ScEmptyCellToken(false, false));
573 pTabData->setCell(nCol, nRow, pToken);
578 rDoc.maRangeArrays.insert(RangeArrayMap::value_type(rRange, pArray));
581 bool ScExternalRefCache::isDocInitialized(sal_uInt16 nFileId)
583 DocItem* pDoc = getDocItem(nFileId);
584 if (!pDoc)
585 return false;
587 return pDoc->mbInitFromSource;
590 static bool lcl_getTableDataIndex(const ScExternalRefCache::TableNameIndexMap& rMap, const String& rName, size_t& rIndex)
592 ScExternalRefCache::TableNameIndexMap::const_iterator itr = rMap.find(rName);
593 if (itr == rMap.end())
594 return false;
596 rIndex = itr->second;
597 return true;
600 void ScExternalRefCache::initializeDoc(sal_uInt16 nFileId, const vector<String>& rTabNames)
602 DocItem* pDoc = getDocItem(nFileId);
603 if (!pDoc)
604 return;
606 size_t n = rTabNames.size();
608 // table name list - the list must include all table names in the source
609 // document and only to be populated when loading the source document, not
610 // when loading cached data from, say, Excel XCT/CRN records.
611 vector<TableName> aNewTabNames;
612 aNewTabNames.reserve(n);
613 for (vector<String>::const_iterator itr = rTabNames.begin(), itrEnd = rTabNames.end();
614 itr != itrEnd; ++itr)
616 TableName aNameItem(ScGlobal::pCharClass->upper(*itr), *itr);
617 aNewTabNames.push_back(aNameItem);
619 pDoc->maTableNames.swap(aNewTabNames);
621 // data tables - preserve any existing data that may have been set during
622 // file import.
623 vector<TableTypeRef> aNewTables(n);
624 for (size_t i = 0; i < n; ++i)
626 size_t nIndex;
627 if (lcl_getTableDataIndex(pDoc->maTableNameIndex, pDoc->maTableNames[i].maUpperName, nIndex))
629 aNewTables[i] = pDoc->maTables[nIndex];
632 pDoc->maTables.swap(aNewTables);
634 // name index map
635 TableNameIndexMap aNewNameIndex;
636 for (size_t i = 0; i < n; ++i)
637 aNewNameIndex.insert(TableNameIndexMap::value_type(pDoc->maTableNames[i].maUpperName, i));
638 pDoc->maTableNameIndex.swap(aNewNameIndex);
640 pDoc->mbInitFromSource = true;
643 String ScExternalRefCache::getTableName(sal_uInt16 nFileId, size_t nCacheId) const
645 if( DocItem* pDoc = getDocItem( nFileId ) )
646 if( nCacheId < pDoc->maTableNames.size() )
647 return pDoc->maTableNames[ nCacheId ].maRealName;
648 return EMPTY_STRING;
651 void ScExternalRefCache::getAllTableNames(sal_uInt16 nFileId, vector<String>& rTabNames) const
653 rTabNames.clear();
654 DocItem* pDoc = getDocItem(nFileId);
655 if (!pDoc)
656 return;
658 size_t n = pDoc->maTableNames.size();
659 rTabNames.reserve(n);
660 for (vector<TableName>::const_iterator itr = pDoc->maTableNames.begin(), itrEnd = pDoc->maTableNames.end();
661 itr != itrEnd; ++itr)
662 rTabNames.push_back(itr->maRealName);
665 SCsTAB ScExternalRefCache::getTabSpan( sal_uInt16 nFileId, const String& rStartTabName, const String& rEndTabName ) const
667 DocItem* pDoc = getDocItem(nFileId);
668 if (!pDoc)
669 return -1;
671 vector<TableName>::const_iterator itrBeg = pDoc->maTableNames.begin();
672 vector<TableName>::const_iterator itrEnd = pDoc->maTableNames.end();
674 vector<TableName>::const_iterator itrStartTab = ::std::find_if( itrBeg, itrEnd,
675 TabNameSearchPredicate( rStartTabName));
676 if (itrStartTab == itrEnd)
677 return -1;
679 vector<TableName>::const_iterator itrEndTab = ::std::find_if( itrBeg, itrEnd,
680 TabNameSearchPredicate( rEndTabName));
681 if (itrEndTab == itrEnd)
682 return 0;
684 size_t nStartDist = ::std::distance( itrBeg, itrStartTab);
685 size_t nEndDist = ::std::distance( itrBeg, itrEndTab);
686 return nStartDist <= nEndDist ? static_cast<SCsTAB>(nEndDist - nStartDist + 1) : -static_cast<SCsTAB>(nStartDist - nEndDist + 1);
689 void ScExternalRefCache::getAllNumberFormats(vector<sal_uInt32>& rNumFmts) const
691 using ::std::sort;
692 using ::std::unique;
694 vector<sal_uInt32> aNumFmts;
695 for (DocDataType::const_iterator itrDoc = maDocs.begin(), itrDocEnd = maDocs.end();
696 itrDoc != itrDocEnd; ++itrDoc)
698 const vector<TableTypeRef>& rTables = itrDoc->second.maTables;
699 for (vector<TableTypeRef>::const_iterator itrTab = rTables.begin(), itrTabEnd = rTables.end();
700 itrTab != itrTabEnd; ++itrTab)
702 TableTypeRef pTab = *itrTab;
703 if (!pTab)
704 continue;
706 pTab->getAllNumberFormats(aNumFmts);
710 // remove duplicates.
711 sort(aNumFmts.begin(), aNumFmts.end());
712 aNumFmts.erase(unique(aNumFmts.begin(), aNumFmts.end()), aNumFmts.end());
713 rNumFmts.swap(aNumFmts);
716 bool ScExternalRefCache::hasCacheTable(sal_uInt16 nFileId, const String& rTabName) const
718 DocItem* pDoc = getDocItem(nFileId);
719 if (!pDoc)
720 return false;
722 String aUpperName = ScGlobal::pCharClass->upper(rTabName);
723 vector<TableName>::const_iterator itrBeg = pDoc->maTableNames.begin(), itrEnd = pDoc->maTableNames.end();
724 vector<TableName>::const_iterator itr = ::std::find_if(
725 itrBeg, itrEnd, TabNameSearchPredicate(aUpperName));
727 return itr != itrEnd;
730 size_t ScExternalRefCache::getCacheTableCount(sal_uInt16 nFileId) const
732 DocItem* pDoc = getDocItem(nFileId);
733 return pDoc ? pDoc->maTables.size() : 0;
736 bool ScExternalRefCache::setCacheDocReferenced( sal_uInt16 nFileId )
738 DocItem* pDocItem = getDocItem(nFileId);
739 if (!pDocItem)
740 return areAllCacheTablesReferenced();
742 for (::std::vector<TableTypeRef>::iterator itrTab = pDocItem->maTables.begin();
743 itrTab != pDocItem->maTables.end(); ++itrTab)
745 if ((*itrTab).get())
746 (*itrTab)->setReferenced( true);
748 addCacheDocToReferenced( nFileId);
749 return areAllCacheTablesReferenced();
752 bool ScExternalRefCache::setCacheTableReferenced( sal_uInt16 nFileId, const String& rTabName, size_t nSheets, bool bPermanent )
754 DocItem* pDoc = getDocItem(nFileId);
755 if (pDoc)
757 size_t nIndex = 0;
758 String aTabNameUpper = ScGlobal::pCharClass->upper( rTabName);
759 if (lcl_getTableDataIndex( pDoc->maTableNameIndex, aTabNameUpper, nIndex))
761 size_t nStop = ::std::min( nIndex + nSheets, pDoc->maTables.size());
762 for (size_t i = nIndex; i < nStop; ++i)
764 TableTypeRef pTab = pDoc->maTables[i];
765 if (pTab.get())
767 Table::ReferencedFlag eNewFlag = (bPermanent ?
768 Table::REFERENCED_PERMANENT :
769 Table::REFERENCED_MARKED);
770 Table::ReferencedFlag eOldFlag = pTab->getReferencedFlag();
771 if (eOldFlag != Table::REFERENCED_PERMANENT && eNewFlag != eOldFlag)
773 pTab->setReferencedFlag( eNewFlag);
774 addCacheTableToReferenced( nFileId, i);
780 return areAllCacheTablesReferenced();
783 void ScExternalRefCache::setCacheTableReferencedPermanently( sal_uInt16 nFileId, const String& rTabName, size_t nSheets )
785 DocItem* pDoc = getDocItem(nFileId);
786 if (pDoc)
788 size_t nIndex = 0;
789 String aTabNameUpper = ScGlobal::pCharClass->upper( rTabName);
790 if (lcl_getTableDataIndex( pDoc->maTableNameIndex, aTabNameUpper, nIndex))
792 size_t nStop = ::std::min( nIndex + nSheets, pDoc->maTables.size());
793 for (size_t i = nIndex; i < nStop; ++i)
795 TableTypeRef pTab = pDoc->maTables[i];
796 if (pTab.get())
797 pTab->setReferencedFlag( Table::REFERENCED_PERMANENT);
803 void ScExternalRefCache::setAllCacheTableReferencedStati( bool bReferenced )
805 if (bReferenced)
807 maReferenced.reset(0);
808 for (DocDataType::iterator itrDoc = maDocs.begin(); itrDoc != maDocs.end(); ++itrDoc)
810 ScExternalRefCache::DocItem& rDocItem = (*itrDoc).second;
811 for (::std::vector<TableTypeRef>::iterator itrTab = rDocItem.maTables.begin();
812 itrTab != rDocItem.maTables.end(); ++itrTab)
814 if ((*itrTab).get())
815 (*itrTab)->setReferenced( true);
819 else
821 size_t nDocs = 0;
822 for (DocDataType::const_iterator itrDoc = maDocs.begin(); itrDoc != maDocs.end(); ++itrDoc)
824 if (nDocs <= (*itrDoc).first)
825 nDocs = (*itrDoc).first + 1;
827 maReferenced.reset( nDocs);
829 for (DocDataType::iterator itrDoc = maDocs.begin(); itrDoc != maDocs.end(); ++itrDoc)
831 ScExternalRefCache::DocItem& rDocItem = (*itrDoc).second;
832 sal_uInt16 nFileId = (*itrDoc).first;
833 size_t nTables = rDocItem.maTables.size();
834 ReferencedStatus::DocReferenced & rDocReferenced = maReferenced.maDocs[nFileId];
835 // All referenced => non-existing tables evaluate as completed.
836 rDocReferenced.maTables.resize( nTables, true);
837 for (size_t i=0; i < nTables; ++i)
839 TableTypeRef & xTab = rDocItem.maTables[i];
840 if (xTab.get())
842 if (xTab->getReferencedFlag() == Table::REFERENCED_PERMANENT)
843 addCacheTableToReferenced( nFileId, i);
844 else
846 xTab->setReferencedFlag( Table::UNREFERENCED);
847 rDocReferenced.maTables[i] = false;
848 rDocReferenced.mbAllTablesReferenced = false;
849 // An addCacheTableToReferenced() actually may have
850 // resulted in mbAllReferenced been set. Clear it.
851 maReferenced.mbAllReferenced = false;
859 void ScExternalRefCache::addCacheTableToReferenced( sal_uInt16 nFileId, size_t nIndex )
861 if (nFileId >= maReferenced.maDocs.size())
862 return;
864 ::std::vector<bool> & rTables = maReferenced.maDocs[nFileId].maTables;
865 size_t nTables = rTables.size();
866 if (nIndex >= nTables)
867 return;
869 if (!rTables[nIndex])
871 rTables[nIndex] = true;
872 size_t i = 0;
873 while (i < nTables && rTables[i])
874 ++i;
875 if (i == nTables)
877 maReferenced.maDocs[nFileId].mbAllTablesReferenced = true;
878 maReferenced.checkAllDocs();
883 void ScExternalRefCache::addCacheDocToReferenced( sal_uInt16 nFileId )
885 if (nFileId >= maReferenced.maDocs.size())
886 return;
888 if (!maReferenced.maDocs[nFileId].mbAllTablesReferenced)
890 ::std::vector<bool> & rTables = maReferenced.maDocs[nFileId].maTables;
891 size_t nSize = rTables.size();
892 for (size_t i=0; i < nSize; ++i)
893 rTables[i] = true;
894 maReferenced.maDocs[nFileId].mbAllTablesReferenced = true;
895 maReferenced.checkAllDocs();
899 bool ScExternalRefCache::areAllCacheTablesReferenced() const
901 return maReferenced.mbAllReferenced;
904 ScExternalRefCache::ReferencedStatus::ReferencedStatus() :
905 mbAllReferenced(false)
907 reset(0);
910 ScExternalRefCache::ReferencedStatus::ReferencedStatus( size_t nDocs ) :
911 mbAllReferenced(false)
913 reset( nDocs);
916 void ScExternalRefCache::ReferencedStatus::reset( size_t nDocs )
918 if (nDocs)
920 mbAllReferenced = false;
921 DocReferencedVec aRefs( nDocs);
922 maDocs.swap( aRefs);
924 else
926 mbAllReferenced = true;
927 DocReferencedVec aRefs;
928 maDocs.swap( aRefs);
932 void ScExternalRefCache::ReferencedStatus::checkAllDocs()
934 for (DocReferencedVec::const_iterator itr = maDocs.begin(); itr != maDocs.end(); ++itr)
936 if (!(*itr).mbAllTablesReferenced)
937 return;
939 mbAllReferenced = true;
942 ScExternalRefCache::TableTypeRef ScExternalRefCache::getCacheTable(sal_uInt16 nFileId, size_t nTabIndex) const
944 DocItem* pDoc = getDocItem(nFileId);
945 if (!pDoc || nTabIndex >= pDoc->maTables.size())
946 return TableTypeRef();
948 return pDoc->maTables[nTabIndex];
951 ScExternalRefCache::TableTypeRef ScExternalRefCache::getCacheTable(sal_uInt16 nFileId, const String& rTabName, bool bCreateNew, size_t* pnIndex)
953 // In API, the index is transported as cached sheet ID of type sal_Int32 in
954 // sheet::SingleReference.Sheet or sheet::ComplexReference.Reference1.Sheet
955 // in a sheet::FormulaToken, choose a sensible value for N/A. Effectively
956 // being 0xffffffff
957 const size_t nNotAvailable = static_cast<size_t>( static_cast<sal_Int32>( -1));
959 DocItem* pDoc = getDocItem(nFileId);
960 if (!pDoc)
962 if (pnIndex) *pnIndex = nNotAvailable;
963 return TableTypeRef();
966 DocItem& rDoc = *pDoc;
968 size_t nIndex;
969 String aTabNameUpper = ScGlobal::pCharClass->upper(rTabName);
970 if (lcl_getTableDataIndex(rDoc.maTableNameIndex, aTabNameUpper, nIndex))
972 // specified table found.
973 if( pnIndex ) *pnIndex = nIndex;
974 return rDoc.maTables[nIndex];
977 if (!bCreateNew)
979 if (pnIndex) *pnIndex = nNotAvailable;
980 return TableTypeRef();
983 // Specified table doesn't exist yet. Create one.
984 nIndex = rDoc.maTables.size();
985 if( pnIndex ) *pnIndex = nIndex;
986 TableTypeRef pTab(new Table);
987 rDoc.maTables.push_back(pTab);
988 rDoc.maTableNames.push_back(TableName(aTabNameUpper, rTabName));
989 rDoc.maTableNameIndex.insert(
990 TableNameIndexMap::value_type(aTabNameUpper, nIndex));
991 return pTab;
994 void ScExternalRefCache::clearCache(sal_uInt16 nFileId)
996 maDocs.erase(nFileId);
999 ScExternalRefCache::DocItem* ScExternalRefCache::getDocItem(sal_uInt16 nFileId) const
1001 using ::std::pair;
1002 DocDataType::iterator itrDoc = maDocs.find(nFileId);
1003 if (itrDoc == maDocs.end())
1005 // specified document is not cached.
1006 pair<DocDataType::iterator, bool> res = maDocs.insert(
1007 DocDataType::value_type(nFileId, DocItem()));
1009 if (!res.second)
1010 // insertion failed.
1011 return NULL;
1013 itrDoc = res.first;
1016 return &itrDoc->second;
1019 // ============================================================================
1021 ScExternalRefLink::ScExternalRefLink(ScDocument* pDoc, sal_uInt16 nFileId, const String& rFilter) :
1022 ::sfx2::SvBaseLink(::sfx2::LINKUPDATE_ONCALL, FORMAT_FILE),
1023 mnFileId(nFileId),
1024 maFilterName(rFilter),
1025 mpDoc(pDoc),
1026 mbDoRefresh(true)
1030 ScExternalRefLink::~ScExternalRefLink()
1034 void ScExternalRefLink::Closed()
1036 ScExternalRefManager* pMgr = mpDoc->GetExternalRefManager();
1037 pMgr->breakLink(mnFileId);
1040 void ScExternalRefLink::DataChanged(const String& /*rMimeType*/, const Any& /*rValue*/)
1042 if (!mbDoRefresh)
1043 return;
1045 String aFile, aFilter;
1046 mpDoc->GetLinkManager()->GetDisplayNames(this, NULL, &aFile, NULL, &aFilter);
1047 ScExternalRefManager* pMgr = mpDoc->GetExternalRefManager();
1048 const String* pCurFile = pMgr->getExternalFileName(mnFileId);
1049 if (!pCurFile)
1050 return;
1052 if (pCurFile->Equals(aFile))
1054 // Refresh the current source document.
1055 pMgr->refreshNames(mnFileId);
1057 else
1059 // The source document has changed.
1060 ScDocShell* pDocShell = ScDocShell::GetViewData()->GetDocShell();
1061 ScDocShellModificator aMod(*pDocShell);
1062 pMgr->switchSrcFile(mnFileId, aFile, aFilter);
1063 maFilterName = aFilter;
1064 aMod.SetDocumentModified();
1068 void ScExternalRefLink::Edit(Window* pParent, const Link& /*rEndEditHdl*/)
1070 SvBaseLink::Edit(pParent, LINK(this, ScExternalRefLink, ExternalRefEndEditHdl));
1073 void ScExternalRefLink::SetDoReferesh(bool b)
1075 mbDoRefresh = b;
1078 IMPL_LINK( ScExternalRefLink, ExternalRefEndEditHdl, ::sfx2::SvBaseLink*, EMPTYARG )
1080 return 0;
1083 // ============================================================================
1085 static FormulaToken* lcl_convertToToken(ScBaseCell* pCell)
1087 if (!pCell || pCell->HasEmptyData())
1089 bool bInherited = (pCell && pCell->GetCellType() == CELLTYPE_FORMULA);
1090 return new ScEmptyCellToken( bInherited, false);
1093 switch (pCell->GetCellType())
1095 case CELLTYPE_EDIT:
1097 String aStr;
1098 static_cast<ScEditCell*>(pCell)->GetString(aStr);
1099 return new formula::FormulaStringToken(aStr);
1101 //break;
1102 case CELLTYPE_STRING:
1104 String aStr;
1105 static_cast<ScStringCell*>(pCell)->GetString(aStr);
1106 return new formula::FormulaStringToken(aStr);
1108 //break;
1109 case CELLTYPE_VALUE:
1111 double fVal = static_cast<ScValueCell*>(pCell)->GetValue();
1112 return new formula::FormulaDoubleToken(fVal);
1114 //break;
1115 case CELLTYPE_FORMULA:
1117 ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
1118 USHORT nError = pFCell->GetErrCode();
1119 if (nError)
1120 return new FormulaErrorToken( nError);
1121 else if (pFCell->IsValue())
1123 double fVal = pFCell->GetValue();
1124 return new formula::FormulaDoubleToken(fVal);
1126 else
1128 String aStr;
1129 pFCell->GetString(aStr);
1130 return new formula::FormulaStringToken(aStr);
1133 //break;
1134 default:
1135 DBG_ERROR("attempted to convert an unknown cell type.");
1138 return NULL;
1141 static ScTokenArray* lcl_convertToTokenArray(ScDocument* pSrcDoc, const ScRange& rRange,
1142 vector<ScExternalRefCache::SingleRangeData>& rCacheData)
1144 const ScAddress& s = rRange.aStart;
1145 const ScAddress& e = rRange.aEnd;
1147 SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
1148 SCCOL nCol1 = s.Col(), nCol2 = e.Col();
1149 SCROW nRow1 = s.Row(), nRow2 = e.Row();
1151 if (nTab2 != nTab1)
1152 // For now, we don't support multi-sheet ranges intentionally because
1153 // we don't have a way to express them in a single token. In the
1154 // future we can introduce a new stack variable type svMatrixList with
1155 // a new token type that can store a 3D matrix value and convert a 3D
1156 // range to it.
1157 return NULL;
1159 auto_ptr<ScTokenArray> pArray(new ScTokenArray);
1160 bool bFirstTab = true;
1161 vector<ScExternalRefCache::SingleRangeData>::iterator
1162 itrCache = rCacheData.begin(), itrCacheEnd = rCacheData.end();
1163 for (SCTAB nTab = nTab1; nTab <= nTab2 && itrCache != itrCacheEnd; ++nTab, ++itrCache)
1165 ScMatrixRef xMat = new ScMatrix(
1166 static_cast<SCSIZE>(nCol2-nCol1+1),
1167 static_cast<SCSIZE>(nRow2-nRow1+1));
1169 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
1171 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
1173 SCSIZE nC = nCol - nCol1, nR = nRow - nRow1;
1174 ScBaseCell* pCell;
1175 pSrcDoc->GetCell(nCol, nRow, nTab, pCell);
1176 if (!pCell || pCell->HasEmptyData())
1177 xMat->PutEmpty(nC, nR);
1178 else
1180 switch (pCell->GetCellType())
1182 case CELLTYPE_EDIT:
1184 String aStr;
1185 static_cast<ScEditCell*>(pCell)->GetString(aStr);
1186 xMat->PutString(aStr, nC, nR);
1188 break;
1189 case CELLTYPE_STRING:
1191 String aStr;
1192 static_cast<ScStringCell*>(pCell)->GetString(aStr);
1193 xMat->PutString(aStr, nC, nR);
1195 break;
1196 case CELLTYPE_VALUE:
1198 double fVal = static_cast<ScValueCell*>(pCell)->GetValue();
1199 xMat->PutDouble(fVal, nC, nR);
1201 break;
1202 case CELLTYPE_FORMULA:
1204 ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
1205 USHORT nError = pFCell->GetErrCode();
1206 if (nError)
1207 xMat->PutDouble( CreateDoubleError( nError), nC, nR);
1208 else if (pFCell->IsValue())
1210 double fVal = pFCell->GetValue();
1211 xMat->PutDouble(fVal, nC, nR);
1213 else
1215 String aStr;
1216 pFCell->GetString(aStr);
1217 xMat->PutString(aStr, nC, nR);
1220 break;
1221 default:
1222 DBG_ERROR("attempted to convert an unknown cell type.");
1227 if (!bFirstTab)
1228 pArray->AddOpCode(ocSep);
1230 ScMatrix* pMat2 = xMat;
1231 ScMatrixToken aToken(pMat2);
1232 pArray->AddToken(aToken);
1234 itrCache->mpRangeData = xMat;
1236 bFirstTab = false;
1238 return pArray.release();
1241 ScExternalRefManager::ScExternalRefManager(ScDocument* pDoc) :
1242 mpDoc(pDoc),
1243 bInReferenceMarking(false)
1245 maSrcDocTimer.SetTimeoutHdl( LINK(this, ScExternalRefManager, TimeOutHdl) );
1246 maSrcDocTimer.SetTimeout(SRCDOC_SCAN_INTERVAL);
1249 ScExternalRefManager::~ScExternalRefManager()
1251 clear();
1254 String ScExternalRefManager::getCacheTableName(sal_uInt16 nFileId, size_t nTabIndex) const
1256 return maRefCache.getTableName(nFileId, nTabIndex);
1259 ScExternalRefCache::TableTypeRef ScExternalRefManager::getCacheTable(sal_uInt16 nFileId, size_t nTabIndex) const
1261 return maRefCache.getCacheTable(nFileId, nTabIndex);
1264 ScExternalRefCache::TableTypeRef ScExternalRefManager::getCacheTable(sal_uInt16 nFileId, const String& rTabName, bool bCreateNew, size_t* pnIndex)
1266 return maRefCache.getCacheTable(nFileId, rTabName, bCreateNew, pnIndex);
1269 // ============================================================================
1271 ScExternalRefManager::RefCells::TabItem::TabItem(SCTAB nIndex) :
1272 mnIndex(nIndex)
1276 ScExternalRefManager::RefCells::TabItem::TabItem(const TabItem& r) :
1277 mnIndex(r.mnIndex),
1278 maCols(r.maCols)
1282 ScExternalRefManager::RefCells::RefCells()
1286 ScExternalRefManager::RefCells::~RefCells()
1290 list<ScExternalRefManager::RefCells::TabItemRef>::iterator ScExternalRefManager::RefCells::getTabPos(SCTAB nTab)
1292 list<TabItemRef>::iterator itr = maTables.begin(), itrEnd = maTables.end();
1293 for (; itr != itrEnd; ++itr)
1294 if ((*itr)->mnIndex >= nTab)
1295 return itr;
1296 // Not found. return the end position.
1297 return itrEnd;
1300 void ScExternalRefManager::RefCells::insertCell(const ScAddress& rAddr)
1302 SCTAB nTab = rAddr.Tab();
1303 SCCOL nCol = rAddr.Col();
1304 SCROW nRow = rAddr.Row();
1306 // Search by table index.
1307 list<TabItemRef>::iterator itrTab = getTabPos(nTab);
1308 TabItemRef xTabRef;
1309 if (itrTab == maTables.end())
1311 // All previous tables come before the specificed table.
1312 xTabRef.reset(new TabItem(nTab));
1313 maTables.push_back(xTabRef);
1315 else if ((*itrTab)->mnIndex > nTab)
1317 // Insert at the current iterator position.
1318 xTabRef.reset(new TabItem(nTab));
1319 maTables.insert(itrTab, xTabRef);
1321 else if ((*itrTab)->mnIndex == nTab)
1323 // The table found.
1324 xTabRef = *itrTab;
1326 ColSet& rCols = xTabRef->maCols;
1328 // Then by column index.
1329 ColSet::iterator itrCol = rCols.find(nCol);
1330 if (itrCol == rCols.end())
1332 RowSet aRows;
1333 pair<ColSet::iterator, bool> r = rCols.insert(ColSet::value_type(nCol, aRows));
1334 if (!r.second)
1335 // column insertion failed.
1336 return;
1337 itrCol = r.first;
1339 RowSet& rRows = itrCol->second;
1341 // Finally, insert the row index.
1342 rRows.insert(nRow);
1345 void ScExternalRefManager::RefCells::removeCell(const ScAddress& rAddr)
1347 SCTAB nTab = rAddr.Tab();
1348 SCCOL nCol = rAddr.Col();
1349 SCROW nRow = rAddr.Row();
1351 // Search by table index.
1352 list<TabItemRef>::iterator itrTab = getTabPos(nTab);
1353 if (itrTab == maTables.end() || (*itrTab)->mnIndex != nTab)
1354 // No such table.
1355 return;
1357 ColSet& rCols = (*itrTab)->maCols;
1359 // Then by column index.
1360 ColSet::iterator itrCol = rCols.find(nCol);
1361 if (itrCol == rCols.end())
1362 // No such column
1363 return;
1365 RowSet& rRows = itrCol->second;
1366 rRows.erase(nRow);
1369 void ScExternalRefManager::RefCells::moveTable(SCTAB nOldTab, SCTAB nNewTab, bool bCopy)
1371 if (nOldTab == nNewTab)
1372 // Nothing to do here.
1373 return;
1375 list<TabItemRef>::iterator itrOld = getTabPos(nOldTab);
1376 if (itrOld == maTables.end() || (*itrOld)->mnIndex != nOldTab)
1377 // No table to move or copy.
1378 return;
1380 list<TabItemRef>::iterator itrNew = getTabPos(nNewTab);
1381 if (bCopy)
1383 // Simply make a duplicate of the original table, insert it at the
1384 // new tab position, and increment the table index for all tables
1385 // that come after that inserted table.
1387 TabItemRef xNewTab(new TabItem(*(*itrOld)));
1388 xNewTab->mnIndex = nNewTab;
1389 maTables.insert(itrNew, xNewTab);
1390 list<TabItemRef>::iterator itr = itrNew, itrEnd = maTables.end();
1391 if (itr != itrEnd) // #i99807# check that itr is not at end already
1392 for (++itr; itr != itrEnd; ++itr)
1393 (*itr)->mnIndex += 1;
1395 else
1397 if (itrOld == itrNew)
1399 // No need to move the table. Just update the table index.
1400 (*itrOld)->mnIndex = nNewTab;
1401 return;
1404 if (nOldTab < nNewTab)
1406 // Iterate from the old tab position to the new tab position (not
1407 // inclusive of the old tab itself), and decrement their tab
1408 // index by one.
1409 list<TabItemRef>::iterator itr = itrOld;
1410 for (++itr; itr != itrNew; ++itr)
1411 (*itr)->mnIndex -= 1;
1413 // Insert a duplicate of the original table. This does not
1414 // invalidate the iterators.
1415 (*itrOld)->mnIndex = nNewTab - 1;
1416 if (itrNew == maTables.end())
1417 maTables.push_back(*itrOld);
1418 else
1419 maTables.insert(itrNew, *itrOld);
1421 // Remove the original table.
1422 maTables.erase(itrOld);
1424 else
1426 // nNewTab < nOldTab
1428 // Iterate from the new tab position to the one before the old tab
1429 // position, and increment their tab index by one.
1430 list<TabItemRef>::iterator itr = itrNew;
1431 for (++itr; itr != itrOld; ++itr)
1432 (*itr)->mnIndex += 1;
1434 (*itrOld)->mnIndex = nNewTab;
1435 maTables.insert(itrNew, *itrOld);
1437 // Remove the original table.
1438 maTables.erase(itrOld);
1443 void ScExternalRefManager::RefCells::insertTable(SCTAB nPos)
1445 TabItemRef xNewTab(new TabItem(nPos));
1446 list<TabItemRef>::iterator itr = getTabPos(nPos);
1447 if (itr == maTables.end())
1448 maTables.push_back(xNewTab);
1449 else
1450 maTables.insert(itr, xNewTab);
1453 void ScExternalRefManager::RefCells::removeTable(SCTAB nPos)
1455 list<TabItemRef>::iterator itr = getTabPos(nPos);
1456 if (itr == maTables.end())
1457 // nothing to remove.
1458 return;
1460 maTables.erase(itr);
1463 void ScExternalRefManager::RefCells::refreshAllCells(ScExternalRefManager& rRefMgr)
1465 // Get ALL the cell positions for re-compilation.
1466 for (list<TabItemRef>::iterator itrTab = maTables.begin(), itrTabEnd = maTables.end();
1467 itrTab != itrTabEnd; ++itrTab)
1469 SCTAB nTab = (*itrTab)->mnIndex;
1470 ColSet& rCols = (*itrTab)->maCols;
1471 for (ColSet::iterator itrCol = rCols.begin(), itrColEnd = rCols.end();
1472 itrCol != itrColEnd; ++itrCol)
1474 SCCOL nCol = itrCol->first;
1475 RowSet& rRows = itrCol->second;
1476 RowSet aNewRows;
1477 for (RowSet::iterator itrRow = rRows.begin(), itrRowEnd = rRows.end();
1478 itrRow != itrRowEnd; ++itrRow)
1480 SCROW nRow = *itrRow;
1481 ScAddress aCell(nCol, nRow, nTab);
1482 if (rRefMgr.compileTokensByCell(aCell))
1483 // This cell still contains an external refernce.
1484 aNewRows.insert(nRow);
1486 // Update the rows so that cells with no external references are
1487 // no longer tracked.
1488 rRows.swap(aNewRows);
1493 // ----------------------------------------------------------------------------
1495 ScExternalRefManager::LinkListener::LinkListener()
1499 ScExternalRefManager::LinkListener::~LinkListener()
1503 // ----------------------------------------------------------------------------
1505 void ScExternalRefManager::getAllCachedTableNames(sal_uInt16 nFileId, vector<String>& rTabNames) const
1507 maRefCache.getAllTableNames(nFileId, rTabNames);
1510 SCsTAB ScExternalRefManager::getCachedTabSpan( sal_uInt16 nFileId, const String& rStartTabName, const String& rEndTabName ) const
1512 return maRefCache.getTabSpan( nFileId, rStartTabName, rEndTabName);
1515 void ScExternalRefManager::getAllCachedNumberFormats(vector<sal_uInt32>& rNumFmts) const
1517 maRefCache.getAllNumberFormats(rNumFmts);
1520 bool ScExternalRefManager::hasCacheTable(sal_uInt16 nFileId, const String& rTabName) const
1522 return maRefCache.hasCacheTable(nFileId, rTabName);
1525 size_t ScExternalRefManager::getCacheTableCount(sal_uInt16 nFileId) const
1527 return maRefCache.getCacheTableCount(nFileId);
1530 sal_uInt16 ScExternalRefManager::getExternalFileCount() const
1532 return static_cast< sal_uInt16 >( maSrcFiles.size() );
1535 bool ScExternalRefManager::markUsedByLinkListeners()
1537 bool bAllMarked = false;
1538 for (LinkListenerMap::const_iterator itr = maLinkListeners.begin();
1539 itr != maLinkListeners.end() && !bAllMarked; ++itr)
1541 if (!(*itr).second.empty())
1542 bAllMarked = maRefCache.setCacheDocReferenced( (*itr).first);
1543 /* TODO: LinkListeners should remember the table they're listening to.
1544 * As is, listening to one table will mark all tables of the document
1545 * being referenced. */
1547 return bAllMarked;
1550 bool ScExternalRefManager::setCacheDocReferenced( sal_uInt16 nFileId )
1552 return maRefCache.setCacheDocReferenced( nFileId);
1555 bool ScExternalRefManager::setCacheTableReferenced( sal_uInt16 nFileId, const String& rTabName, size_t nSheets )
1557 return maRefCache.setCacheTableReferenced( nFileId, rTabName, nSheets, false);
1560 void ScExternalRefManager::setCacheTableReferencedPermanently( sal_uInt16 nFileId, const String& rTabName, size_t nSheets )
1562 if (isInReferenceMarking())
1563 // Do all maintenance work.
1564 maRefCache.setCacheTableReferenced( nFileId, rTabName, nSheets, true);
1565 else
1566 // Set only the permanent flag.
1567 maRefCache.setCacheTableReferencedPermanently( nFileId, rTabName, nSheets);
1570 void ScExternalRefManager::setAllCacheTableReferencedStati( bool bReferenced )
1572 bInReferenceMarking = !bReferenced;
1573 maRefCache.setAllCacheTableReferencedStati( bReferenced );
1576 void ScExternalRefManager::storeRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScTokenArray& rArray)
1578 ScExternalRefCache::TokenArrayRef pArray(rArray.Clone());
1579 maRefCache.setRangeNameTokens(nFileId, rName, pArray);
1582 ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefToken(
1583 sal_uInt16 nFileId, const String& rTabName, const ScAddress& rCell,
1584 const ScAddress* pCurPos, SCTAB* pTab, ScExternalRefCache::CellFormat* pFmt)
1586 if (pCurPos)
1587 insertRefCell(nFileId, *pCurPos);
1589 maybeLinkExternalFile(nFileId);
1591 if (pTab)
1592 *pTab = -1;
1594 if (pFmt)
1595 pFmt->mbIsSet = false;
1597 bool bLoading = mpDoc->IsImportingXML();
1599 // Check if the given table name and the cell position is cached.
1600 // #i101304# When loading a file, the saved cache (hidden sheet)
1601 // is assumed to contain all data for the loaded formulas.
1602 // No cache entries are created from empty cells in the saved sheet,
1603 // so they have to be created here (bWriteEmpty parameter).
1604 // Otherwise, later interpretation of the loaded formulas would
1605 // load the source document even if the user didn't want to update.
1606 sal_uInt32 nFmtIndex = 0;
1607 ScExternalRefCache::TokenRef pToken = maRefCache.getCellData(
1608 nFileId, rTabName, rCell.Col(), rCell.Row(), bLoading, bLoading, &nFmtIndex);
1609 if (pToken)
1611 if (pFmt)
1613 short nFmtType = mpDoc->GetFormatTable()->GetType(nFmtIndex);
1614 if (nFmtType != NUMBERFORMAT_UNDEFINED)
1616 pFmt->mbIsSet = true;
1617 pFmt->mnIndex = nFmtIndex;
1618 pFmt->mnType = nFmtType;
1621 return pToken;
1624 // reference not cached. read from the source document.
1625 ScDocument* pSrcDoc = getSrcDocument(nFileId);
1626 if (!pSrcDoc)
1628 // Source document is not reachable. Try to get data from the cache
1629 // once again, but this time treat a non-cached cell as an empty cell
1630 // as long as the table itself is cached.
1631 pToken = maRefCache.getCellData(
1632 nFileId, rTabName, rCell.Col(), rCell.Row(), true, false, &nFmtIndex);
1633 return pToken;
1636 ScBaseCell* pCell = NULL;
1637 SCTAB nTab;
1638 if (!pSrcDoc->GetTable(rTabName, nTab))
1640 // specified table name doesn't exist in the source document.
1641 return ScExternalRefCache::TokenRef();
1644 if (pTab)
1645 *pTab = nTab;
1647 pSrcDoc->GetCell(rCell.Col(), rCell.Row(), nTab, pCell);
1648 ScExternalRefCache::TokenRef pTok(lcl_convertToToken(pCell));
1650 pSrcDoc->GetNumberFormat(rCell.Col(), rCell.Row(), nTab, nFmtIndex);
1651 nFmtIndex = getMappedNumberFormat(nFileId, nFmtIndex, pSrcDoc);
1652 if (pFmt)
1654 short nFmtType = mpDoc->GetFormatTable()->GetType(nFmtIndex);
1655 if (nFmtType != NUMBERFORMAT_UNDEFINED)
1657 pFmt->mbIsSet = true;
1658 pFmt->mnIndex = nFmtIndex;
1659 pFmt->mnType = nFmtType;
1663 if (!pTok.get())
1665 // Generate an error for unresolvable cells.
1666 pTok.reset( new FormulaErrorToken( errNoValue));
1669 // Now, insert the token into cache table.
1670 maRefCache.setCellData(nFileId, rTabName, rCell.Row(), rCell.Col(), pTok, nFmtIndex);
1671 return pTok;
1674 ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokens(sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange, const ScAddress* pCurPos)
1676 if (pCurPos)
1677 insertRefCell(nFileId, *pCurPos);
1679 maybeLinkExternalFile(nFileId);
1681 bool bLoading = mpDoc->IsImportingXML();
1683 // Check if the given table name and the cell position is cached.
1684 // #i101304# When loading, put empty cells into cache, see getSingleRefToken.
1685 ScExternalRefCache::TokenArrayRef p = maRefCache.getCellRangeData(nFileId, rTabName, rRange, bLoading, bLoading);
1686 if (p.get())
1687 return p;
1689 ScDocument* pSrcDoc = getSrcDocument(nFileId);
1690 if (!pSrcDoc)
1692 // Source document is not reachable. Try to get data from the cache
1693 // once again, but this time treat non-cached cells as empty cells as
1694 // long as the table itself is cached.
1695 return maRefCache.getCellRangeData(nFileId, rTabName, rRange, true, false);
1698 SCTAB nTab1;
1699 if (!pSrcDoc->GetTable(rTabName, nTab1))
1700 // specified table name doesn't exist in the source document.
1701 return ScExternalRefCache::TokenArrayRef();
1703 ScRange aRange(rRange);
1704 SCTAB nTabSpan = aRange.aEnd.Tab() - aRange.aStart.Tab();
1706 vector<ScExternalRefCache::SingleRangeData> aCacheData;
1707 aCacheData.reserve(nTabSpan+1);
1708 aCacheData.push_back(ScExternalRefCache::SingleRangeData());
1709 aCacheData.back().maTableName = ScGlobal::pCharClass->upper(rTabName);
1711 for (SCTAB i = 1; i < nTabSpan + 1; ++i)
1713 String aTabName;
1714 if (!pSrcDoc->GetName(nTab1 + 1, aTabName))
1715 // source document doesn't have any table by the specified name.
1716 break;
1718 aCacheData.push_back(ScExternalRefCache::SingleRangeData());
1719 aCacheData.back().maTableName = ScGlobal::pCharClass->upper(aTabName);
1722 aRange.aStart.SetTab(nTab1);
1723 aRange.aEnd.SetTab(nTab1 + nTabSpan);
1725 ScExternalRefCache::TokenArrayRef pArray;
1726 pArray.reset(lcl_convertToTokenArray(pSrcDoc, aRange, aCacheData));
1728 if (pArray)
1729 // Cache these values.
1730 maRefCache.setCellRangeData(nFileId, rRange, aCacheData, pArray);
1732 return pArray;
1735 ScExternalRefCache::TokenArrayRef ScExternalRefManager::getRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScAddress* pCurPos)
1737 if (pCurPos)
1738 insertRefCell(nFileId, *pCurPos);
1740 maybeLinkExternalFile(nFileId);
1742 ScExternalRefCache::TokenArrayRef pArray = maRefCache.getRangeNameTokens(nFileId, rName);
1743 if (pArray.get())
1744 return pArray;
1746 ScDocument* pSrcDoc = getSrcDocument(nFileId);
1747 if (!pSrcDoc)
1748 return ScExternalRefCache::TokenArrayRef();
1750 ScRangeName* pExtNames = pSrcDoc->GetRangeName();
1751 String aUpperName = ScGlobal::pCharClass->upper(rName);
1752 USHORT n;
1753 bool bRes = pExtNames->SearchNameUpper(aUpperName, n);
1754 if (!bRes)
1755 return ScExternalRefCache::TokenArrayRef();
1757 ScRangeData* pRangeData = (*pExtNames)[n];
1758 if (!pRangeData)
1759 return ScExternalRefCache::TokenArrayRef();
1761 // Parse all tokens in this external range data, and replace each absolute
1762 // reference token with an external reference token, and cache them. Also
1763 // register the source document with the link manager if it's a new
1764 // source.
1766 ScExternalRefCache::TokenArrayRef pNew(new ScTokenArray);
1768 ScTokenArray* pCode = pRangeData->GetCode();
1769 for (FormulaToken* pToken = pCode->First(); pToken; pToken = pCode->Next())
1771 bool bTokenAdded = false;
1772 switch (pToken->GetType())
1774 case svSingleRef:
1776 const ScSingleRefData& rRef = static_cast<ScToken*>(pToken)->GetSingleRef();
1777 String aTabName;
1778 pSrcDoc->GetName(rRef.nTab, aTabName);
1779 ScExternalSingleRefToken aNewToken(nFileId, aTabName, static_cast<ScToken*>(pToken)->GetSingleRef());
1780 pNew->AddToken(aNewToken);
1781 bTokenAdded = true;
1783 break;
1784 case svDoubleRef:
1786 const ScSingleRefData& rRef = static_cast<ScToken*>(pToken)->GetSingleRef();
1787 String aTabName;
1788 pSrcDoc->GetName(rRef.nTab, aTabName);
1789 ScExternalDoubleRefToken aNewToken(nFileId, aTabName, static_cast<ScToken*>(pToken)->GetDoubleRef());
1790 pNew->AddToken(aNewToken);
1791 bTokenAdded = true;
1793 break;
1794 default:
1795 ; // nothing
1798 if (!bTokenAdded)
1799 pNew->AddToken(*pToken);
1802 // Make sure to pass the correctly-cased range name here.
1803 maRefCache.setRangeNameTokens(nFileId, pRangeData->GetName(), pNew);
1804 return pNew;
1807 void ScExternalRefManager::refreshAllRefCells(sal_uInt16 nFileId)
1809 RefCellMap::iterator itrFile = maRefCells.find(nFileId);
1810 if (itrFile == maRefCells.end())
1811 return;
1813 RefCells& rRefCells = itrFile->second;
1814 rRefCells.refreshAllCells(*this);
1816 ScViewData* pViewData = ScDocShell::GetViewData();
1817 if (!pViewData)
1818 return;
1820 ScTabViewShell* pVShell = pViewData->GetViewShell();
1821 if (!pVShell)
1822 return;
1824 // Repainting the grid also repaints the texts, but is there a better way
1825 // to refresh texts?
1826 pVShell->Invalidate(FID_REPAINT);
1827 pVShell->PaintGrid();
1830 void ScExternalRefManager::insertRefCell(sal_uInt16 nFileId, const ScAddress& rCell)
1832 RefCellMap::iterator itr = maRefCells.find(nFileId);
1833 if (itr == maRefCells.end())
1835 RefCells aRefCells;
1836 pair<RefCellMap::iterator, bool> r = maRefCells.insert(
1837 RefCellMap::value_type(nFileId, aRefCells));
1838 if (!r.second)
1839 // insertion failed.
1840 return;
1842 itr = r.first;
1844 itr->second.insertCell(rCell);
1847 ScDocument* ScExternalRefManager::getSrcDocument(sal_uInt16 nFileId)
1849 if (!mpDoc->IsExecuteLinkEnabled())
1850 return NULL;
1852 DocShellMap::iterator itrEnd = maDocShells.end();
1853 DocShellMap::iterator itr = maDocShells.find(nFileId);
1855 if (itr != itrEnd)
1857 SfxObjectShell* p = itr->second.maShell;
1858 itr->second.maLastAccess = Time();
1859 return static_cast<ScDocShell*>(p)->GetDocument();
1862 const String* pFile = getExternalFileName(nFileId);
1863 if (!pFile)
1864 // no file name associated with this ID.
1865 return NULL;
1867 String aFilter;
1868 SrcShell aSrcDoc;
1869 aSrcDoc.maShell = loadSrcDocument(nFileId, aFilter);
1870 if (!aSrcDoc.maShell.Is())
1872 // source document could not be loaded.
1873 return NULL;
1876 if (maDocShells.empty())
1878 // If this is the first source document insertion, start up the timer.
1879 maSrcDocTimer.Start();
1882 maDocShells.insert(DocShellMap::value_type(nFileId, aSrcDoc));
1883 SfxObjectShell* p = aSrcDoc.maShell;
1884 ScDocument* pSrcDoc = static_cast<ScDocShell*>(p)->GetDocument();
1886 SCTAB nTabCount = pSrcDoc->GetTableCount();
1887 if (!maRefCache.isDocInitialized(nFileId) && nTabCount)
1889 // Populate the cache with all table names in the source document.
1890 vector<String> aTabNames;
1891 aTabNames.reserve(nTabCount);
1892 for (SCTAB i = 0; i < nTabCount; ++i)
1894 String aName;
1895 pSrcDoc->GetName(i, aName);
1896 aTabNames.push_back(aName);
1898 maRefCache.initializeDoc(nFileId, aTabNames);
1900 return pSrcDoc;
1903 SfxObjectShellRef ScExternalRefManager::loadSrcDocument(sal_uInt16 nFileId, String& rFilter)
1905 const SrcFileData* pFileData = getExternalFileData(nFileId);
1906 if (!pFileData)
1907 return NULL;
1909 // Always load the document by using the path created from the relative
1910 // path. If the referenced document is not there, simply exit. The
1911 // original file name should be used only when the relative path is not
1912 // given.
1913 String aFile = pFileData->maFileName;
1914 maybeCreateRealFileName(nFileId);
1915 if (pFileData->maRealFileName.Len())
1916 aFile = pFileData->maRealFileName;
1918 if (!isFileLoadable(aFile))
1919 return NULL;
1921 String aOptions;
1922 ScDocumentLoader::GetFilterName(aFile, rFilter, aOptions, true, false);
1923 const SfxFilter* pFilter = ScDocShell::Factory().GetFilterContainer()->GetFilter4FilterName(rFilter);
1925 if (!pFileData->maRelativeName.Len())
1927 // Generate a relative file path.
1928 INetURLObject aBaseURL(getOwnDocumentName());
1929 aBaseURL.insertName(OUString::createFromAscii("content.xml"));
1931 String aStr = URIHelper::simpleNormalizedMakeRelative(
1932 aBaseURL.GetMainURL(INetURLObject::NO_DECODE), aFile);
1934 setRelativeFileName(nFileId, aStr);
1937 // Update the filter data now that we are loading it again.
1938 setFilterData(nFileId, rFilter, aOptions);
1940 SfxItemSet* pSet = new SfxAllItemSet(SFX_APP()->GetPool());
1941 if (aOptions.Len())
1942 pSet->Put(SfxStringItem(SID_FILE_FILTEROPTIONS, aOptions));
1944 auto_ptr<SfxMedium> pMedium(new SfxMedium(aFile, STREAM_STD_READ, false, pFilter, pSet));
1945 if (pMedium->GetError() != ERRCODE_NONE)
1946 return NULL;
1948 pMedium->UseInteractionHandler(false);
1950 ScDocShell* pNewShell = new ScDocShell(SFX_CREATE_MODE_INTERNAL);
1951 SfxObjectShellRef aRef = pNewShell;
1953 // increment the recursive link count of the source document.
1954 ScExtDocOptions* pExtOpt = mpDoc->GetExtDocOptions();
1955 sal_uInt32 nLinkCount = pExtOpt ? pExtOpt->GetDocSettings().mnLinkCnt : 0;
1956 ScDocument* pSrcDoc = pNewShell->GetDocument();
1957 ScExtDocOptions* pExtOptNew = pSrcDoc->GetExtDocOptions();
1958 if (!pExtOptNew)
1960 pExtOptNew = new ScExtDocOptions;
1961 pSrcDoc->SetExtDocOptions(pExtOptNew);
1963 pExtOptNew->GetDocSettings().mnLinkCnt = nLinkCount + 1;
1965 pNewShell->DoLoad(pMedium.release());
1966 return aRef;
1969 bool ScExternalRefManager::isFileLoadable(const String& rFile) const
1971 if (!rFile.Len())
1972 return false;
1974 if (isOwnDocument(rFile))
1975 return false;
1977 if (utl::UCBContentHelper::IsFolder(rFile))
1978 return false;
1980 return utl::UCBContentHelper::Exists(rFile);
1983 void ScExternalRefManager::maybeLinkExternalFile(sal_uInt16 nFileId)
1985 if (maLinkedDocs.count(nFileId))
1986 // file alerady linked, or the link has been broken.
1987 return;
1989 // Source document not linked yet. Link it now.
1990 const String* pFileName = getExternalFileName(nFileId);
1991 if (!pFileName)
1992 return;
1994 String aFilter, aOptions;
1995 ScDocumentLoader::GetFilterName(*pFileName, aFilter, aOptions, true, false);
1996 SvxLinkManager* pLinkMgr = mpDoc->GetLinkManager();
1997 ScExternalRefLink* pLink = new ScExternalRefLink(mpDoc, nFileId, aFilter);
1998 DBG_ASSERT(pFileName, "ScExternalRefManager::insertExternalFileLink: file name pointer is NULL");
1999 pLinkMgr->InsertFileLink(*pLink, OBJECT_CLIENT_FILE, *pFileName, &aFilter);
2001 pLink->SetDoReferesh(false);
2002 pLink->Update();
2003 pLink->SetDoReferesh(true);
2005 maLinkedDocs.insert(LinkedDocMap::value_type(nFileId, true));
2008 void ScExternalRefManager::SrcFileData::maybeCreateRealFileName(const String& rOwnDocName)
2010 if (!maRelativeName.Len())
2011 // No relative path given. Nothing to do.
2012 return;
2014 if (maRealFileName.Len())
2015 // Real file name already created. Nothing to do.
2016 return;
2018 // Formulate the absolute file path from the relative path.
2019 const String& rRelPath = maRelativeName;
2020 INetURLObject aBaseURL(rOwnDocName);
2021 aBaseURL.insertName(OUString::createFromAscii("content.xml"));
2022 bool bWasAbs = false;
2023 maRealFileName = aBaseURL.smartRel2Abs(rRelPath, bWasAbs).GetMainURL(INetURLObject::NO_DECODE);
2026 void ScExternalRefManager::maybeCreateRealFileName(sal_uInt16 nFileId)
2028 if (nFileId >= maSrcFiles.size())
2029 return;
2031 maSrcFiles[nFileId].maybeCreateRealFileName(getOwnDocumentName());
2034 bool ScExternalRefManager::compileTokensByCell(const ScAddress& rCell)
2036 ScBaseCell* pCell;
2037 mpDoc->GetCell(rCell.Col(), rCell.Row(), rCell.Tab(), pCell);
2039 if (!pCell || pCell->GetCellType() != CELLTYPE_FORMULA)
2040 return false;
2042 ScFormulaCell* pFC = static_cast<ScFormulaCell*>(pCell);
2044 // Check to make sure the cell really contains ocExternalRef.
2045 // External names, external cell and range references all have a
2046 // ocExternalRef token.
2047 const ScTokenArray* pCode = pFC->GetCode();
2048 if (!pCode->HasOpCode( ocExternalRef))
2049 return false;
2051 ScTokenArray* pArray = pFC->GetCode();
2052 if (pArray)
2053 // Clear the error code, or a cell with error won't get re-compiled.
2054 pArray->SetCodeError(0);
2056 pFC->SetCompile(true);
2057 pFC->CompileTokenArray();
2058 pFC->SetDirty();
2060 return true;
2063 const String& ScExternalRefManager::getOwnDocumentName() const
2065 SfxObjectShell* pShell = mpDoc->GetDocumentShell();
2066 if (!pShell)
2067 // This should not happen!
2068 return EMPTY_STRING;
2070 SfxMedium* pMed = pShell->GetMedium();
2071 if (!pMed)
2072 return EMPTY_STRING;
2074 return pMed->GetName();
2077 bool ScExternalRefManager::isOwnDocument(const String& rFile) const
2079 return getOwnDocumentName().Equals(rFile);
2082 void ScExternalRefManager::convertToAbsName(String& rFile) const
2084 SfxObjectShell* pDocShell = mpDoc->GetDocumentShell();
2085 rFile = ScGlobal::GetAbsDocName(rFile, pDocShell);
2088 sal_uInt16 ScExternalRefManager::getExternalFileId(const String& rFile)
2090 vector<SrcFileData>::const_iterator itrBeg = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
2091 vector<SrcFileData>::const_iterator itr = find_if(itrBeg, itrEnd, FindSrcFileByName(rFile));
2092 if (itr != itrEnd)
2094 size_t nId = distance(itrBeg, itr);
2095 return static_cast<sal_uInt16>(nId);
2098 SrcFileData aData;
2099 aData.maFileName = rFile;
2100 maSrcFiles.push_back(aData);
2101 return static_cast<sal_uInt16>(maSrcFiles.size() - 1);
2104 const String* ScExternalRefManager::getExternalFileName(sal_uInt16 nFileId, bool bForceOriginal)
2106 if (nFileId >= maSrcFiles.size())
2107 return NULL;
2109 if (bForceOriginal)
2110 return &maSrcFiles[nFileId].maFileName;
2112 maybeCreateRealFileName(nFileId);
2114 if (maSrcFiles[nFileId].maRealFileName.Len())
2115 return &maSrcFiles[nFileId].maRealFileName;
2116 else
2117 return &maSrcFiles[nFileId].maFileName;
2120 bool ScExternalRefManager::hasExternalFile(sal_uInt16 nFileId) const
2122 return nFileId < maSrcFiles.size();
2125 bool ScExternalRefManager::hasExternalFile(const String& rFile) const
2127 vector<SrcFileData>::const_iterator itrBeg = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
2128 vector<SrcFileData>::const_iterator itr = find_if(itrBeg, itrEnd, FindSrcFileByName(rFile));
2129 return itr != itrEnd;
2132 const ScExternalRefManager::SrcFileData* ScExternalRefManager::getExternalFileData(sal_uInt16 nFileId) const
2134 if (nFileId >= maSrcFiles.size())
2135 return NULL;
2137 return &maSrcFiles[nFileId];
2140 const String* ScExternalRefManager::getRealTableName(sal_uInt16 nFileId, const String& rTabName) const
2142 return maRefCache.getRealTableName(nFileId, rTabName);
2145 const String* ScExternalRefManager::getRealRangeName(sal_uInt16 nFileId, const String& rRangeName) const
2147 return maRefCache.getRealRangeName(nFileId, rRangeName);
2150 template<typename MapContainer>
2151 void lcl_removeByFileId(sal_uInt16 nFileId, MapContainer& rMap)
2153 typename MapContainer::iterator itr = rMap.find(nFileId);
2154 if (itr != rMap.end())
2155 rMap.erase(itr);
2158 void ScExternalRefManager::refreshNames(sal_uInt16 nFileId)
2160 maRefCache.clearCache(nFileId);
2161 lcl_removeByFileId(nFileId, maDocShells);
2163 if (maDocShells.empty())
2164 maSrcDocTimer.Stop();
2166 // Update all cells containing names from this source document.
2167 refreshAllRefCells(nFileId);
2169 notifyAllLinkListeners(nFileId, LINK_MODIFIED);
2172 void ScExternalRefManager::breakLink(sal_uInt16 nFileId)
2174 lcl_removeByFileId(nFileId, maDocShells);
2176 if (maDocShells.empty())
2177 maSrcDocTimer.Stop();
2179 LinkedDocMap::iterator itr = maLinkedDocs.find(nFileId);
2180 if (itr != maLinkedDocs.end())
2181 itr->second = false;
2183 notifyAllLinkListeners(nFileId, LINK_BROKEN);
2186 void ScExternalRefManager::switchSrcFile(sal_uInt16 nFileId, const String& rNewFile, const String& rNewFilter)
2188 maSrcFiles[nFileId].maFileName = rNewFile;
2189 maSrcFiles[nFileId].maRelativeName.Erase();
2190 maSrcFiles[nFileId].maRealFileName.Erase();
2191 if (!maSrcFiles[nFileId].maFilterName.Equals(rNewFilter))
2193 // Filter type has changed.
2194 maSrcFiles[nFileId].maFilterName = rNewFilter;
2195 maSrcFiles[nFileId].maFilterOptions.Erase();
2197 refreshNames(nFileId);
2200 void ScExternalRefManager::setRelativeFileName(sal_uInt16 nFileId, const String& rRelUrl)
2202 if (nFileId >= maSrcFiles.size())
2203 return;
2204 maSrcFiles[nFileId].maRelativeName = rRelUrl;
2207 void ScExternalRefManager::setFilterData(sal_uInt16 nFileId, const String& rFilterName, const String& rOptions)
2209 if (nFileId >= maSrcFiles.size())
2210 return;
2211 maSrcFiles[nFileId].maFilterName = rFilterName;
2212 maSrcFiles[nFileId].maFilterOptions = rOptions;
2215 void ScExternalRefManager::clear()
2217 DocShellMap::iterator itrEnd = maDocShells.end();
2218 for (DocShellMap::iterator itr = maDocShells.begin(); itr != itrEnd; ++itr)
2219 itr->second.maShell->DoClose();
2221 maDocShells.clear();
2222 maSrcDocTimer.Stop();
2225 bool ScExternalRefManager::hasExternalData() const
2227 return !maSrcFiles.empty();
2230 void ScExternalRefManager::resetSrcFileData(const String& rBaseFileUrl)
2232 for (vector<SrcFileData>::iterator itr = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
2233 itr != itrEnd; ++itr)
2235 // Re-generate relative file name from the absolute file name.
2236 String aAbsName = itr->maRealFileName;
2237 if (!aAbsName.Len())
2238 aAbsName = itr->maFileName;
2240 itr->maRelativeName = URIHelper::simpleNormalizedMakeRelative(
2241 rBaseFileUrl, aAbsName);
2245 void ScExternalRefManager::updateRefCell(const ScAddress& rOldPos, const ScAddress& rNewPos, bool bCopy)
2247 for (RefCellMap::iterator itr = maRefCells.begin(), itrEnd = maRefCells.end(); itr != itrEnd; ++itr)
2249 if (!bCopy)
2250 itr->second.removeCell(rOldPos);
2251 itr->second.insertCell(rNewPos);
2255 void ScExternalRefManager::updateRefMoveTable(SCTAB nOldTab, SCTAB nNewTab, bool bCopy)
2257 for (RefCellMap::iterator itr = maRefCells.begin(), itrEnd = maRefCells.end(); itr != itrEnd; ++itr)
2258 itr->second.moveTable(nOldTab, nNewTab, bCopy);
2261 void ScExternalRefManager::updateRefInsertTable(SCTAB nPos)
2263 for (RefCellMap::iterator itr = maRefCells.begin(), itrEnd = maRefCells.end(); itr != itrEnd; ++itr)
2264 itr->second.insertTable(nPos);
2267 void ScExternalRefManager::updateRefDeleteTable(SCTAB nPos)
2269 for (RefCellMap::iterator itr = maRefCells.begin(), itrEnd = maRefCells.end(); itr != itrEnd; ++itr)
2270 itr->second.removeTable(nPos);
2273 void ScExternalRefManager::addLinkListener(sal_uInt16 nFileId, LinkListener* pListener)
2275 LinkListenerMap::iterator itr = maLinkListeners.find(nFileId);
2276 if (itr == maLinkListeners.end())
2278 pair<LinkListenerMap::iterator, bool> r = maLinkListeners.insert(
2279 LinkListenerMap::value_type(nFileId, LinkListeners()));
2280 if (!r.second)
2282 DBG_ERROR("insertion of new link listener list failed");
2283 return;
2286 itr = r.first;
2289 LinkListeners& rList = itr->second;
2290 rList.insert(pListener);
2293 void ScExternalRefManager::removeLinkListener(sal_uInt16 nFileId, LinkListener* pListener)
2295 LinkListenerMap::iterator itr = maLinkListeners.find(nFileId);
2296 if (itr == maLinkListeners.end())
2297 // no listeners for a specified file.
2298 return;
2300 LinkListeners& rList = itr->second;
2301 rList.erase(pListener);
2303 if (rList.empty())
2304 // No more listeners for this file. Remove its entry.
2305 maLinkListeners.erase(itr);
2308 void ScExternalRefManager::removeLinkListener(LinkListener* pListener)
2310 LinkListenerMap::iterator itr = maLinkListeners.begin(), itrEnd = maLinkListeners.end();
2311 for (; itr != itrEnd; ++itr)
2312 itr->second.erase(pListener);
2315 void ScExternalRefManager::notifyAllLinkListeners(sal_uInt16 nFileId, LinkUpdateType eType)
2317 LinkListenerMap::iterator itr = maLinkListeners.find(nFileId);
2318 if (itr == maLinkListeners.end())
2319 // no listeners for a specified file.
2320 return;
2322 LinkListeners& rList = itr->second;
2323 for_each(rList.begin(), rList.end(), NotifyLinkListener(nFileId, eType));
2326 void ScExternalRefManager::purgeStaleSrcDocument(sal_Int32 nTimeOut)
2328 DocShellMap aNewDocShells;
2329 DocShellMap::iterator itr = maDocShells.begin(), itrEnd = maDocShells.end();
2330 for (; itr != itrEnd; ++itr)
2332 // in 100th of a second.
2333 sal_Int32 nSinceLastAccess = (Time() - itr->second.maLastAccess).GetTime();
2334 if (nSinceLastAccess < nTimeOut)
2335 aNewDocShells.insert(*itr);
2337 maDocShells.swap(aNewDocShells);
2339 if (maDocShells.empty())
2340 maSrcDocTimer.Stop();
2343 sal_uInt32 ScExternalRefManager::getMappedNumberFormat(sal_uInt16 nFileId, sal_uInt32 nNumFmt, ScDocument* pSrcDoc)
2345 NumFmtMap::iterator itr = maNumFormatMap.find(nFileId);
2346 if (itr == maNumFormatMap.end())
2348 // Number formatter map is not initialized for this external document.
2349 pair<NumFmtMap::iterator, bool> r = maNumFormatMap.insert(
2350 NumFmtMap::value_type(nFileId, SvNumberFormatterMergeMap()));
2352 if (!r.second)
2353 // insertion failed.
2354 return nNumFmt;
2356 itr = r.first;
2357 mpDoc->GetFormatTable()->MergeFormatter( *pSrcDoc->GetFormatTable());
2358 SvNumberFormatterMergeMap aMap = mpDoc->GetFormatTable()->ConvertMergeTableToMap();
2359 itr->second.swap(aMap);
2361 const SvNumberFormatterMergeMap& rMap = itr->second;
2362 SvNumberFormatterMergeMap::const_iterator itrNumFmt = rMap.find(nNumFmt);
2363 if (itrNumFmt != rMap.end())
2364 // mapped value found.
2365 return itrNumFmt->second;
2367 return nNumFmt;
2370 IMPL_LINK(ScExternalRefManager, TimeOutHdl, AutoTimer*, pTimer)
2372 if (pTimer == &maSrcDocTimer)
2373 purgeStaleSrcDocument(SRCDOC_LIFE_SPAN);
2375 return 0;