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"
41 #include "tokenarray.hxx"
42 #include "address.hxx"
43 #include "tablink.hxx"
45 #include "scextopt.hxx"
46 #include "rangenam.hxx"
48 #include "viewdata.hxx"
49 #include "tabvwsh.hxx"
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"
71 using ::std::auto_ptr
;
72 using ::com::sun::star::uno::Any
;
73 using ::rtl::OUString
;
77 using ::std::distance
;
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)
88 class TabNameSearchPredicate
: public unary_function
<bool, ScExternalRefCache::TableName
>
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
);
106 class FindSrcFileByName
: public unary_function
<ScExternalRefManager::SrcFileData
, bool>
109 FindSrcFileByName(const String
& rMatchName
) :
110 mrMatchName(rMatchName
)
114 bool operator()(const ScExternalRefManager::SrcFileData
& rSrcData
) const
116 return rSrcData
.maFileName
.Equals(mrMatchName
);
120 const String
& mrMatchName
;
123 class NotifyLinkListener
: public unary_function
<ScExternalRefManager::LinkListener
*, void>
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
);
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
164 void ScExternalRefCache::Table::setCell(SCCOL nCol
, SCROW nRow
, TokenRef pToken
, sal_uInt32 nFmtIndex
)
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()));
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.
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.
206 const Cell
& rCell
= itrRow
->second
;
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
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());
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.
239 const RowDataType
& rRowData
= itrRow
->second
;
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());
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.
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.
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.
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.
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.
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.
349 const TableTypeRef
& pTableData
= rDoc
.maTables
[itrTabId
->second
];
350 if (!pTableData
.get())
352 // the table data is not instantiated yet.
356 TokenRef pToken
= pTableData
->getCell(nCol
, nRow
, pnFmtIndex
);
357 if (!pToken
&& bEmptyCellOnNull
)
359 pToken
.reset(new ScEmptyCellToken(false, false));
361 pTableData
->setCell(nCol
, nRow
, 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
];
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
);
419 if (bEmptyCellOnNull
)
421 pToken
.reset(new ScEmptyCellToken(false, false));
423 pTab
->setCell(nCol
, nRow
, pToken
);
426 return TokenArrayRef();
429 SCSIZE nC
= nCol
- nCol1
, nR
= nRow
- nRow1
;
430 switch (pToken
->GetType())
433 xMat
->PutDouble(pToken
->GetDouble(), nC
, nR
);
436 xMat
->PutString(pToken
->GetString(), nC
, nR
);
439 xMat
->PutEmpty(nC
, nR
);
445 pArray
->AddOpCode(ocSep
);
447 ScMatrix
* pMat2
= xMat
;
448 ScMatrixToken
aToken(pMat2
);
449 pArray
->AddToken(aToken
);
453 rDoc
.maRangeArrays
.insert(RangeArrayMap::value_type(rRange
, pArray
));
457 ScExternalRefCache::TokenArrayRef
ScExternalRefCache::getRangeNameTokens(sal_uInt16 nFileId
, const String
& rName
)
459 DocItem
* pDoc
= getDocItem(nFileId
);
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();
472 void ScExternalRefCache::setRangeNameTokens(sal_uInt16 nFileId
, const String
& rName
, TokenArrayRef pArray
)
474 DocItem
* pDoc
= getDocItem(nFileId
);
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
))
491 DocItem
* pDocItem
= getDocItem(nFileId
);
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 ???
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
)
515 if (rData
.empty() || !isDocInitialized(nFileId
))
519 // First, get the document item for the given file ID.
520 DocItem
* pDocItem
= getDocItem(nFileId
);
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.
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
];
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
;
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
)));
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
);
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())
584 rIndex
= itr
->second
;
588 void ScExternalRefCache::initializeDoc(sal_uInt16 nFileId
, const vector
<String
>& rTabNames
)
590 DocItem
* pDoc
= getDocItem(nFileId
);
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
611 vector
<TableTypeRef
> aNewTables(n
);
612 for (size_t i
= 0; i
< n
; ++i
)
615 if (lcl_getTableDataIndex(pDoc
->maTableNameIndex
, pDoc
->maTableNames
[i
].maUpperName
, nIndex
))
617 aNewTables
[i
] = pDoc
->maTables
[nIndex
];
620 pDoc
->maTables
.swap(aNewTables
);
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
;
639 void ScExternalRefCache::getAllTableNames(sal_uInt16 nFileId
, vector
<String
>& rTabNames
) const
642 DocItem
* pDoc
= getDocItem(nFileId
);
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
);
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
)
667 vector
<TableName
>::const_iterator itrEndTab
= ::std::find_if( itrBeg
, itrEnd
,
668 TabNameSearchPredicate( rEndTabName
));
669 if (itrEndTab
== itrEnd
)
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
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
;
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
);
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
);
728 return areAllCacheTablesReferenced();
730 for (::std::vector
<TableTypeRef
>::iterator itrTab
= pDocItem
->maTables
.begin();
731 itrTab
!= pDocItem
->maTables
.end(); ++itrTab
)
734 (*itrTab
)->setReferenced( true);
736 addCacheDocToReferenced( nFileId
);
737 return areAllCacheTablesReferenced();
740 bool ScExternalRefCache::setCacheTableReferenced( sal_uInt16 nFileId
, const String
& rTabName
)
743 TableTypeRef pTab
= getCacheTable( nFileId
, rTabName
, false, &nIndex
);
746 if (!pTab
->isReferenced())
748 pTab
->setReferenced( true);
749 addCacheTableToReferenced( nFileId
, nIndex
);
752 return areAllCacheTablesReferenced();
755 void ScExternalRefCache::setAllCacheTableReferencedStati( bool 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
)
767 (*itrTab
)->setReferenced( true);
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
];
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())
808 ::std::vector
<bool> & rTables
= maReferenced
.maDocs
[nFileId
].maTables
;
809 size_t nTables
= rTables
.size();
810 if (nIndex
>= nTables
)
813 if (!rTables
[nIndex
])
815 rTables
[nIndex
] = true;
817 while (i
< nTables
&& rTables
[i
])
821 maReferenced
.maDocs
[nFileId
].mbAllTablesReferenced
= true;
822 maReferenced
.checkAllDocs();
827 void ScExternalRefCache::addCacheDocToReferenced( sal_uInt16 nFileId
)
829 if (nFileId
>= maReferenced
.maDocs
.size())
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
)
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)
854 ScExternalRefCache::ReferencedStatus::ReferencedStatus( size_t nDocs
) :
855 mbAllReferenced(false)
860 void ScExternalRefCache::ReferencedStatus::reset( size_t nDocs
)
864 mbAllReferenced
= false;
865 DocReferencedVec
aRefs( nDocs
);
870 mbAllReferenced
= true;
871 DocReferencedVec aRefs
;
876 void ScExternalRefCache::ReferencedStatus::checkAllDocs()
878 for (DocReferencedVec::const_iterator itr
= maDocs
.begin(); itr
!= maDocs
.end(); ++itr
)
880 if (!(*itr
).mbAllTablesReferenced
)
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
);
899 return TableTypeRef();
901 DocItem
& rDoc
= *pDoc
;
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
];
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
));
926 void ScExternalRefCache::clearCache(sal_uInt16 nFileId
)
928 maDocs
.erase(nFileId
);
931 ScExternalRefCache::DocItem
* ScExternalRefCache::getDocItem(sal_uInt16 nFileId
) const
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()));
948 return &itrDoc
->second
;
951 // ============================================================================
953 ScExternalRefLink::ScExternalRefLink(ScDocument
* pDoc
, sal_uInt16 nFileId
, const String
& rFilter
) :
954 ::sfx2::SvBaseLink(::sfx2::LINKUPDATE_ONCALL
, FORMAT_FILE
),
956 maFilterName(rFilter
),
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*/)
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
);
984 if (pCurFile
->Equals(aFile
))
986 // Refresh the current source document.
987 pMgr
->refreshNames(mnFileId
);
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
)
1007 IMPL_LINK( ScExternalRefLink
, ExternalRefEndEditHdl
, ::sfx2::SvBaseLink
*, EMPTYARG
)
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())
1027 static_cast<ScEditCell
*>(pCell
)->GetString(aStr
);
1028 return new formula::FormulaStringToken(aStr
);
1031 case CELLTYPE_STRING
:
1034 static_cast<ScStringCell
*>(pCell
)->GetString(aStr
);
1035 return new formula::FormulaStringToken(aStr
);
1038 case CELLTYPE_VALUE
:
1040 double fVal
= static_cast<ScValueCell
*>(pCell
)->GetValue();
1041 return new formula::FormulaDoubleToken(fVal
);
1044 case CELLTYPE_FORMULA
:
1046 ScFormulaCell
* pFCell
= static_cast<ScFormulaCell
*>(pCell
);
1047 USHORT nError
= pFCell
->GetErrCode();
1049 return new FormulaErrorToken( nError
);
1050 else if (pFCell
->IsValue())
1052 double fVal
= pFCell
->GetValue();
1053 return new formula::FormulaDoubleToken(fVal
);
1058 pFCell
->GetString(aStr
);
1059 return new formula::FormulaStringToken(aStr
);
1064 DBG_ERROR("attempted to convert an unknown cell type.");
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();
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
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
;
1104 pSrcDoc
->GetCell(nCol
, nRow
, nTab
, pCell
);
1105 if (!pCell
|| pCell
->HasEmptyData())
1106 xMat
->PutEmpty(nC
, nR
);
1109 switch (pCell
->GetCellType())
1114 static_cast<ScEditCell
*>(pCell
)->GetString(aStr
);
1115 xMat
->PutString(aStr
, nC
, nR
);
1118 case CELLTYPE_STRING
:
1121 static_cast<ScStringCell
*>(pCell
)->GetString(aStr
);
1122 xMat
->PutString(aStr
, nC
, nR
);
1125 case CELLTYPE_VALUE
:
1127 double fVal
= static_cast<ScValueCell
*>(pCell
)->GetValue();
1128 xMat
->PutDouble(fVal
, nC
, nR
);
1131 case CELLTYPE_FORMULA
:
1133 ScFormulaCell
* pFCell
= static_cast<ScFormulaCell
*>(pCell
);
1134 USHORT nError
= pFCell
->GetErrCode();
1136 xMat
->PutDouble( CreateDoubleError( nError
), nC
, nR
);
1137 else if (pFCell
->IsValue())
1139 double fVal
= pFCell
->GetValue();
1140 xMat
->PutDouble(fVal
, nC
, nR
);
1145 pFCell
->GetString(aStr
);
1146 xMat
->PutString(aStr
, nC
, nR
);
1151 DBG_ERROR("attempted to convert an unknown cell type.");
1157 pArray
->AddOpCode(ocSep
);
1159 ScMatrix
* pMat2
= xMat
;
1160 ScMatrixToken
aToken(pMat2
);
1161 pArray
->AddToken(aToken
);
1163 itrCache
->mpRangeData
= xMat
;
1167 return pArray
.release();
1170 ScExternalRefManager::ScExternalRefManager(ScDocument
* pDoc
) :
1172 bInReferenceMarking(false)
1174 maSrcDocTimer
.SetTimeoutHdl( LINK(this, ScExternalRefManager
, TimeOutHdl
) );
1175 maSrcDocTimer
.SetTimeout(SRCDOC_SCAN_INTERVAL
);
1178 ScExternalRefManager::~ScExternalRefManager()
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
) :
1205 ScExternalRefManager::RefCells::TabItem::TabItem(const TabItem
& r
) :
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
)
1225 // Not found. return the end position.
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
);
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
)
1255 ColSet
& rCols
= xTabRef
->maCols
;
1257 // Then by column index.
1258 ColSet::iterator itrCol
= rCols
.find(nCol
);
1259 if (itrCol
== rCols
.end())
1262 pair
<ColSet::iterator
, bool> r
= rCols
.insert(ColSet::value_type(nCol
, aRows
));
1264 // column insertion failed.
1268 RowSet
& rRows
= itrCol
->second
;
1270 // Finally, insert the row index.
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
)
1286 ColSet
& rCols
= (*itrTab
)->maCols
;
1288 // Then by column index.
1289 ColSet::iterator itrCol
= rCols
.find(nCol
);
1290 if (itrCol
== rCols
.end())
1294 RowSet
& rRows
= itrCol
->second
;
1298 void ScExternalRefManager::RefCells::moveTable(SCTAB nOldTab
, SCTAB nNewTab
, bool bCopy
)
1300 if (nOldTab
== nNewTab
)
1301 // Nothing to do here.
1304 list
<TabItemRef
>::iterator itrOld
= getTabPos(nOldTab
);
1305 if (itrOld
== maTables
.end() || (*itrOld
)->mnIndex
!= nOldTab
)
1306 // No table to move or copy.
1309 list
<TabItemRef
>::iterator itrNew
= getTabPos(nNewTab
);
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;
1325 if (itrOld
== itrNew
)
1327 // No need to move the table. Just update the table index.
1328 (*itrOld
)->mnIndex
= nNewTab
;
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
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
);
1347 maTables
.insert(itrNew
, *itrOld
);
1349 // Remove the original table.
1350 maTables
.erase(itrOld
);
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
);
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.
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
;
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. */
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
)
1505 insertRefCell(nFileId
, *pCurPos
);
1507 maybeLinkExternalFile(nFileId
);
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
);
1531 short nFmtType
= mpDoc
->GetFormatTable()->GetType(nFmtIndex
);
1532 if (nFmtType
!= NUMBERFORMAT_UNDEFINED
)
1534 pFmt
->mbIsSet
= true;
1535 pFmt
->mnIndex
= nFmtIndex
;
1536 pFmt
->mnType
= nFmtType
;
1542 // reference not cached. read from the source document.
1543 ScDocument
* pSrcDoc
= getSrcDocument(nFileId
);
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
);
1554 ScBaseCell
* pCell
= NULL
;
1556 if (!pSrcDoc
->GetTable(rTabName
, nTab
))
1558 // specified table name doesn't exist in the source document.
1559 return ScExternalRefCache::TokenRef();
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
);
1572 short nFmtType
= mpDoc
->GetFormatTable()->GetType(nFmtIndex
);
1573 if (nFmtType
!= NUMBERFORMAT_UNDEFINED
)
1575 pFmt
->mbIsSet
= true;
1576 pFmt
->mnIndex
= nFmtIndex
;
1577 pFmt
->mnType
= nFmtType
;
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
);
1592 ScExternalRefCache::TokenArrayRef
ScExternalRefManager::getDoubleRefTokens(sal_uInt16 nFileId
, const String
& rTabName
, const ScRange
& rRange
, const ScAddress
* 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
);
1607 ScDocument
* pSrcDoc
= getSrcDocument(nFileId
);
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);
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
)
1632 if (!pSrcDoc
->GetName(nTab1
+ 1, aTabName
))
1633 // source document doesn't have any table by the specified name.
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
));
1647 // Cache these values.
1648 maRefCache
.setCellRangeData(nFileId
, rRange
, aCacheData
, pArray
);
1653 ScExternalRefCache::TokenArrayRef
ScExternalRefManager::getRangeNameTokens(sal_uInt16 nFileId
, const String
& rName
, const ScAddress
* pCurPos
)
1656 insertRefCell(nFileId
, *pCurPos
);
1658 maybeLinkExternalFile(nFileId
);
1660 ScExternalRefCache::TokenArrayRef pArray
= maRefCache
.getRangeNameTokens(nFileId
, rName
);
1664 ScDocument
* pSrcDoc
= getSrcDocument(nFileId
);
1666 return ScExternalRefCache::TokenArrayRef();
1668 ScRangeName
* pExtNames
= pSrcDoc
->GetRangeName();
1669 String aUpperName
= ScGlobal::pCharClass
->upper(rName
);
1671 bool bRes
= pExtNames
->SearchNameUpper(aUpperName
, n
);
1673 return ScExternalRefCache::TokenArrayRef();
1675 ScRangeData
* pRangeData
= (*pExtNames
)[n
];
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
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())
1694 const ScSingleRefData
& rRef
= static_cast<ScToken
*>(pToken
)->GetSingleRef();
1696 pSrcDoc
->GetName(rRef
.nTab
, aTabName
);
1697 ScExternalSingleRefToken
aNewToken(nFileId
, aTabName
, static_cast<ScToken
*>(pToken
)->GetSingleRef());
1698 pNew
->AddToken(aNewToken
);
1704 const ScSingleRefData
& rRef
= static_cast<ScToken
*>(pToken
)->GetSingleRef();
1706 pSrcDoc
->GetName(rRef
.nTab
, aTabName
);
1707 ScExternalDoubleRefToken
aNewToken(nFileId
, aTabName
, static_cast<ScToken
*>(pToken
)->GetDoubleRef());
1708 pNew
->AddToken(aNewToken
);
1717 pNew
->AddToken(*pToken
);
1720 // Make sure to pass the correctly-cased range name here.
1721 maRefCache
.setRangeNameTokens(nFileId
, pRangeData
->GetName(), pNew
);
1725 void ScExternalRefManager::refreshAllRefCells(sal_uInt16 nFileId
)
1727 RefCellMap::iterator itrFile
= maRefCells
.find(nFileId
);
1728 if (itrFile
== maRefCells
.end())
1731 RefCells
& rRefCells
= itrFile
->second
;
1732 rRefCells
.refreshAllCells(*this);
1734 ScViewData
* pViewData
= ScDocShell::GetViewData();
1738 ScTabViewShell
* pVShell
= pViewData
->GetViewShell();
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())
1754 pair
<RefCellMap::iterator
, bool> r
= maRefCells
.insert(
1755 RefCellMap::value_type(nFileId
, aRefCells
));
1757 // insertion failed.
1762 itr
->second
.insertCell(rCell
);
1765 ScDocument
* ScExternalRefManager::getSrcDocument(sal_uInt16 nFileId
)
1767 if (!mpDoc
->IsExecuteLinkEnabled())
1770 DocShellMap::iterator itrEnd
= maDocShells
.end();
1771 DocShellMap::iterator itr
= maDocShells
.find(nFileId
);
1775 SfxObjectShell
* p
= itr
->second
.maShell
;
1776 itr
->second
.maLastAccess
= Time();
1777 return static_cast<ScDocShell
*>(p
)->GetDocument();
1780 const String
* pFile
= getExternalFileName(nFileId
);
1782 // no file name associated with this ID.
1787 aSrcDoc
.maShell
= loadSrcDocument(nFileId
, aFilter
);
1788 if (!aSrcDoc
.maShell
.Is())
1790 // source document could not be loaded.
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
)
1813 pSrcDoc
->GetName(i
, aName
);
1814 aTabNames
.push_back(aName
);
1816 maRefCache
.initializeDoc(nFileId
, aTabNames
);
1821 SfxObjectShellRef
ScExternalRefManager::loadSrcDocument(sal_uInt16 nFileId
, String
& rFilter
)
1823 const SrcFileData
* pFileData
= getExternalFileData(nFileId
);
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
1831 String aFile
= pFileData
->maFileName
;
1832 maybeCreateRealFileName(nFileId
);
1833 if (pFileData
->maRealFileName
.Len())
1834 aFile
= pFileData
->maRealFileName
;
1836 if (!isFileLoadable(aFile
))
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());
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
)
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();
1878 pExtOptNew
= new ScExtDocOptions
;
1879 pSrcDoc
->SetExtDocOptions(pExtOptNew
);
1881 pExtOptNew
->GetDocSettings().mnLinkCnt
= nLinkCount
+ 1;
1883 pNewShell
->DoLoad(pMedium
.release());
1887 bool ScExternalRefManager::isFileLoadable(const String
& rFile
) const
1892 if (isOwnDocument(rFile
))
1895 if (utl::UCBContentHelper::IsFolder(rFile
))
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.
1907 // Source document not linked yet. Link it now.
1908 const String
* pFileName
= getExternalFileName(nFileId
);
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);
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.
1932 if (maRealFileName
.Len())
1933 // Real file name already created. Nothing to do.
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())
1949 maSrcFiles
[nFileId
].maybeCreateRealFileName(getOwnDocumentName());
1952 bool ScExternalRefManager::compileTokensByCell(const ScAddress
& rCell
)
1955 mpDoc
->GetCell(rCell
.Col(), rCell
.Row(), rCell
.Tab(), pCell
);
1957 if (!pCell
|| pCell
->GetCellType() != CELLTYPE_FORMULA
)
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
))
1969 ScTokenArray
* pArray
= pFC
->GetCode();
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();
1981 const String
& ScExternalRefManager::getOwnDocumentName() const
1983 SfxObjectShell
* pShell
= mpDoc
->GetDocumentShell();
1985 // This should not happen!
1986 return EMPTY_STRING
;
1988 SfxMedium
* pMed
= pShell
->GetMedium();
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
));
2012 size_t nId
= distance(itrBeg
, itr
);
2013 return static_cast<sal_uInt16
>(nId
);
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())
2027 maybeCreateRealFileName(nFileId
);
2029 if (maSrcFiles
[nFileId
].maRealFileName
.Len())
2030 return &maSrcFiles
[nFileId
].maRealFileName
;
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())
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())
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())
2119 maSrcFiles
[nFileId
].maRelativeName
= rRelUrl
;
2122 void ScExternalRefManager::setFilterData(sal_uInt16 nFileId
, const String
& rFilterName
, const String
& rOptions
)
2124 if (nFileId
>= maSrcFiles
.size())
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
)
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()));
2197 DBG_ERROR("insertion of new link listener list failed");
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.
2215 LinkListeners
& rList
= itr
->second
;
2216 rList
.erase(pListener
);
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.
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()));
2268 // insertion failed.
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
;
2285 IMPL_LINK(ScExternalRefManager
, TimeOutHdl
, AutoTimer
*, pTimer
)
2287 if (pTimer
== &maSrcDocTimer
)
2288 purgeStaleSrcDocument(SRCDOC_LIFE_SPAN
);