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 : 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
171 bool ScExternalRefCache::Table::isReferenced() const
173 return meReferenced
!= UNREFERENCED
;
176 void ScExternalRefCache::Table::setCell(SCCOL nCol
, SCROW nRow
, TokenRef pToken
, sal_uInt32 nFmtIndex
)
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()));
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.
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.
218 const Cell
& rCell
= itrRow
->second
;
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
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());
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.
251 const RowDataType
& rRowData
= itrRow
->second
;
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());
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.
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.
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.
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.
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.
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.
361 const TableTypeRef
& pTableData
= rDoc
.maTables
[itrTabId
->second
];
362 if (!pTableData
.get())
364 // the table data is not instantiated yet.
368 TokenRef pToken
= pTableData
->getCell(nCol
, nRow
, pnFmtIndex
);
369 if (!pToken
&& bEmptyCellOnNull
)
371 pToken
.reset(new ScEmptyCellToken(false, false));
373 pTableData
->setCell(nCol
, nRow
, 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
];
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
);
431 if (bEmptyCellOnNull
)
433 pToken
.reset(new ScEmptyCellToken(false, false));
435 pTab
->setCell(nCol
, nRow
, pToken
);
438 return TokenArrayRef();
441 SCSIZE nC
= nCol
- nCol1
, nR
= nRow
- nRow1
;
442 switch (pToken
->GetType())
445 xMat
->PutDouble(pToken
->GetDouble(), nC
, nR
);
448 xMat
->PutString(pToken
->GetString(), nC
, nR
);
451 xMat
->PutEmpty(nC
, nR
);
457 pArray
->AddOpCode(ocSep
);
459 ScMatrix
* pMat2
= xMat
;
460 ScMatrixToken
aToken(pMat2
);
461 pArray
->AddToken(aToken
);
465 rDoc
.maRangeArrays
.insert(RangeArrayMap::value_type(rRange
, pArray
));
469 ScExternalRefCache::TokenArrayRef
ScExternalRefCache::getRangeNameTokens(sal_uInt16 nFileId
, const String
& rName
)
471 DocItem
* pDoc
= getDocItem(nFileId
);
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();
484 void ScExternalRefCache::setRangeNameTokens(sal_uInt16 nFileId
, const String
& rName
, TokenArrayRef pArray
)
486 DocItem
* pDoc
= getDocItem(nFileId
);
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
))
503 DocItem
* pDocItem
= getDocItem(nFileId
);
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 ???
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
)
527 if (rData
.empty() || !isDocInitialized(nFileId
))
531 // First, get the document item for the given file ID.
532 DocItem
* pDocItem
= getDocItem(nFileId
);
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.
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
];
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
;
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
)));
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
);
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())
596 rIndex
= itr
->second
;
600 void ScExternalRefCache::initializeDoc(sal_uInt16 nFileId
, const vector
<String
>& rTabNames
)
602 DocItem
* pDoc
= getDocItem(nFileId
);
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
623 vector
<TableTypeRef
> aNewTables(n
);
624 for (size_t i
= 0; i
< n
; ++i
)
627 if (lcl_getTableDataIndex(pDoc
->maTableNameIndex
, pDoc
->maTableNames
[i
].maUpperName
, nIndex
))
629 aNewTables
[i
] = pDoc
->maTables
[nIndex
];
632 pDoc
->maTables
.swap(aNewTables
);
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
;
651 void ScExternalRefCache::getAllTableNames(sal_uInt16 nFileId
, vector
<String
>& rTabNames
) const
654 DocItem
* pDoc
= getDocItem(nFileId
);
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
);
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
)
679 vector
<TableName
>::const_iterator itrEndTab
= ::std::find_if( itrBeg
, itrEnd
,
680 TabNameSearchPredicate( rEndTabName
));
681 if (itrEndTab
== itrEnd
)
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
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
;
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
);
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
);
740 return areAllCacheTablesReferenced();
742 for (::std::vector
<TableTypeRef
>::iterator itrTab
= pDocItem
->maTables
.begin();
743 itrTab
!= pDocItem
->maTables
.end(); ++itrTab
)
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
);
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
];
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
);
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
];
797 pTab
->setReferencedFlag( Table::REFERENCED_PERMANENT
);
803 void ScExternalRefCache::setAllCacheTableReferencedStati( bool 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
)
815 (*itrTab
)->setReferenced( true);
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
];
842 if (xTab
->getReferencedFlag() == Table::REFERENCED_PERMANENT
)
843 addCacheTableToReferenced( nFileId
, i
);
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())
864 ::std::vector
<bool> & rTables
= maReferenced
.maDocs
[nFileId
].maTables
;
865 size_t nTables
= rTables
.size();
866 if (nIndex
>= nTables
)
869 if (!rTables
[nIndex
])
871 rTables
[nIndex
] = true;
873 while (i
< nTables
&& rTables
[i
])
877 maReferenced
.maDocs
[nFileId
].mbAllTablesReferenced
= true;
878 maReferenced
.checkAllDocs();
883 void ScExternalRefCache::addCacheDocToReferenced( sal_uInt16 nFileId
)
885 if (nFileId
>= maReferenced
.maDocs
.size())
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
)
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)
910 ScExternalRefCache::ReferencedStatus::ReferencedStatus( size_t nDocs
) :
911 mbAllReferenced(false)
916 void ScExternalRefCache::ReferencedStatus::reset( size_t nDocs
)
920 mbAllReferenced
= false;
921 DocReferencedVec
aRefs( nDocs
);
926 mbAllReferenced
= true;
927 DocReferencedVec aRefs
;
932 void ScExternalRefCache::ReferencedStatus::checkAllDocs()
934 for (DocReferencedVec::const_iterator itr
= maDocs
.begin(); itr
!= maDocs
.end(); ++itr
)
936 if (!(*itr
).mbAllTablesReferenced
)
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 DocItem
* pDoc
= getDocItem(nFileId
);
955 return TableTypeRef();
957 DocItem
& rDoc
= *pDoc
;
960 String aTabNameUpper
= ScGlobal::pCharClass
->upper(rTabName
);
961 if (lcl_getTableDataIndex(rDoc
.maTableNameIndex
, aTabNameUpper
, nIndex
))
963 // specified table found.
964 if( pnIndex
) *pnIndex
= nIndex
;
965 return rDoc
.maTables
[nIndex
];
969 return TableTypeRef();
971 // Specified table doesn't exist yet. Create one.
972 nIndex
= rDoc
.maTables
.size();
973 if( pnIndex
) *pnIndex
= nIndex
;
974 TableTypeRef
pTab(new Table
);
975 rDoc
.maTables
.push_back(pTab
);
976 rDoc
.maTableNames
.push_back(TableName(aTabNameUpper
, rTabName
));
977 rDoc
.maTableNameIndex
.insert(
978 TableNameIndexMap::value_type(aTabNameUpper
, nIndex
));
982 void ScExternalRefCache::clearCache(sal_uInt16 nFileId
)
984 maDocs
.erase(nFileId
);
987 ScExternalRefCache::DocItem
* ScExternalRefCache::getDocItem(sal_uInt16 nFileId
) const
990 DocDataType::iterator itrDoc
= maDocs
.find(nFileId
);
991 if (itrDoc
== maDocs
.end())
993 // specified document is not cached.
994 pair
<DocDataType::iterator
, bool> res
= maDocs
.insert(
995 DocDataType::value_type(nFileId
, DocItem()));
1004 return &itrDoc
->second
;
1007 // ============================================================================
1009 ScExternalRefLink::ScExternalRefLink(ScDocument
* pDoc
, sal_uInt16 nFileId
, const String
& rFilter
) :
1010 ::sfx2::SvBaseLink(::sfx2::LINKUPDATE_ONCALL
, FORMAT_FILE
),
1012 maFilterName(rFilter
),
1018 ScExternalRefLink::~ScExternalRefLink()
1022 void ScExternalRefLink::Closed()
1024 ScExternalRefManager
* pMgr
= mpDoc
->GetExternalRefManager();
1025 pMgr
->breakLink(mnFileId
);
1028 void ScExternalRefLink::DataChanged(const String
& /*rMimeType*/, const Any
& /*rValue*/)
1033 String aFile
, aFilter
;
1034 mpDoc
->GetLinkManager()->GetDisplayNames(this, NULL
, &aFile
, NULL
, &aFilter
);
1035 ScExternalRefManager
* pMgr
= mpDoc
->GetExternalRefManager();
1036 const String
* pCurFile
= pMgr
->getExternalFileName(mnFileId
);
1040 if (pCurFile
->Equals(aFile
))
1042 // Refresh the current source document.
1043 pMgr
->refreshNames(mnFileId
);
1047 // The source document has changed.
1048 ScDocShell
* pDocShell
= ScDocShell::GetViewData()->GetDocShell();
1049 ScDocShellModificator
aMod(*pDocShell
);
1050 pMgr
->switchSrcFile(mnFileId
, aFile
);
1051 maFilterName
= aFilter
;
1052 aMod
.SetDocumentModified();
1056 void ScExternalRefLink::Edit(Window
* pParent
, const Link
& /*rEndEditHdl*/)
1058 SvBaseLink::Edit(pParent
, LINK(this, ScExternalRefLink
, ExternalRefEndEditHdl
));
1061 void ScExternalRefLink::SetDoReferesh(bool b
)
1066 IMPL_LINK( ScExternalRefLink
, ExternalRefEndEditHdl
, ::sfx2::SvBaseLink
*, EMPTYARG
)
1071 // ============================================================================
1073 static FormulaToken
* lcl_convertToToken(ScBaseCell
* pCell
)
1075 if (!pCell
|| pCell
->HasEmptyData())
1077 bool bInherited
= (pCell
&& pCell
->GetCellType() == CELLTYPE_FORMULA
);
1078 return new ScEmptyCellToken( bInherited
, false);
1081 switch (pCell
->GetCellType())
1086 static_cast<ScEditCell
*>(pCell
)->GetString(aStr
);
1087 return new formula::FormulaStringToken(aStr
);
1090 case CELLTYPE_STRING
:
1093 static_cast<ScStringCell
*>(pCell
)->GetString(aStr
);
1094 return new formula::FormulaStringToken(aStr
);
1097 case CELLTYPE_VALUE
:
1099 double fVal
= static_cast<ScValueCell
*>(pCell
)->GetValue();
1100 return new formula::FormulaDoubleToken(fVal
);
1103 case CELLTYPE_FORMULA
:
1105 ScFormulaCell
* pFCell
= static_cast<ScFormulaCell
*>(pCell
);
1106 USHORT nError
= pFCell
->GetErrCode();
1108 return new FormulaErrorToken( nError
);
1109 else if (pFCell
->IsValue())
1111 double fVal
= pFCell
->GetValue();
1112 return new formula::FormulaDoubleToken(fVal
);
1117 pFCell
->GetString(aStr
);
1118 return new formula::FormulaStringToken(aStr
);
1123 DBG_ERROR("attempted to convert an unknown cell type.");
1129 static ScTokenArray
* lcl_convertToTokenArray(ScDocument
* pSrcDoc
, const ScRange
& rRange
,
1130 vector
<ScExternalRefCache::SingleRangeData
>& rCacheData
)
1132 const ScAddress
& s
= rRange
.aStart
;
1133 const ScAddress
& e
= rRange
.aEnd
;
1135 SCTAB nTab1
= s
.Tab(), nTab2
= e
.Tab();
1136 SCCOL nCol1
= s
.Col(), nCol2
= e
.Col();
1137 SCROW nRow1
= s
.Row(), nRow2
= e
.Row();
1140 // For now, we don't support multi-sheet ranges intentionally because
1141 // we don't have a way to express them in a single token. In the
1142 // future we can introduce a new stack variable type svMatrixList with
1143 // a new token type that can store a 3D matrix value and convert a 3D
1147 auto_ptr
<ScTokenArray
> pArray(new ScTokenArray
);
1148 bool bFirstTab
= true;
1149 vector
<ScExternalRefCache::SingleRangeData
>::iterator
1150 itrCache
= rCacheData
.begin(), itrCacheEnd
= rCacheData
.end();
1151 for (SCTAB nTab
= nTab1
; nTab
<= nTab2
&& itrCache
!= itrCacheEnd
; ++nTab
, ++itrCache
)
1153 ScMatrixRef xMat
= new ScMatrix(
1154 static_cast<SCSIZE
>(nCol2
-nCol1
+1),
1155 static_cast<SCSIZE
>(nRow2
-nRow1
+1));
1157 for (SCCOL nCol
= nCol1
; nCol
<= nCol2
; ++nCol
)
1159 for (SCROW nRow
= nRow1
; nRow
<= nRow2
; ++nRow
)
1161 SCSIZE nC
= nCol
- nCol1
, nR
= nRow
- nRow1
;
1163 pSrcDoc
->GetCell(nCol
, nRow
, nTab
, pCell
);
1164 if (!pCell
|| pCell
->HasEmptyData())
1165 xMat
->PutEmpty(nC
, nR
);
1168 switch (pCell
->GetCellType())
1173 static_cast<ScEditCell
*>(pCell
)->GetString(aStr
);
1174 xMat
->PutString(aStr
, nC
, nR
);
1177 case CELLTYPE_STRING
:
1180 static_cast<ScStringCell
*>(pCell
)->GetString(aStr
);
1181 xMat
->PutString(aStr
, nC
, nR
);
1184 case CELLTYPE_VALUE
:
1186 double fVal
= static_cast<ScValueCell
*>(pCell
)->GetValue();
1187 xMat
->PutDouble(fVal
, nC
, nR
);
1190 case CELLTYPE_FORMULA
:
1192 ScFormulaCell
* pFCell
= static_cast<ScFormulaCell
*>(pCell
);
1193 USHORT nError
= pFCell
->GetErrCode();
1195 xMat
->PutDouble( CreateDoubleError( nError
), nC
, nR
);
1196 else if (pFCell
->IsValue())
1198 double fVal
= pFCell
->GetValue();
1199 xMat
->PutDouble(fVal
, nC
, nR
);
1204 pFCell
->GetString(aStr
);
1205 xMat
->PutString(aStr
, nC
, nR
);
1210 DBG_ERROR("attempted to convert an unknown cell type.");
1216 pArray
->AddOpCode(ocSep
);
1218 ScMatrix
* pMat2
= xMat
;
1219 ScMatrixToken
aToken(pMat2
);
1220 pArray
->AddToken(aToken
);
1222 itrCache
->mpRangeData
= xMat
;
1226 return pArray
.release();
1229 ScExternalRefManager::ScExternalRefManager(ScDocument
* pDoc
) :
1231 bInReferenceMarking(false)
1233 maSrcDocTimer
.SetTimeoutHdl( LINK(this, ScExternalRefManager
, TimeOutHdl
) );
1234 maSrcDocTimer
.SetTimeout(SRCDOC_SCAN_INTERVAL
);
1237 ScExternalRefManager::~ScExternalRefManager()
1242 String
ScExternalRefManager::getCacheTableName(sal_uInt16 nFileId
, size_t nTabIndex
) const
1244 return maRefCache
.getTableName(nFileId
, nTabIndex
);
1247 ScExternalRefCache::TableTypeRef
ScExternalRefManager::getCacheTable(sal_uInt16 nFileId
, size_t nTabIndex
) const
1249 return maRefCache
.getCacheTable(nFileId
, nTabIndex
);
1252 ScExternalRefCache::TableTypeRef
ScExternalRefManager::getCacheTable(sal_uInt16 nFileId
, const String
& rTabName
, bool bCreateNew
, size_t* pnIndex
)
1254 return maRefCache
.getCacheTable(nFileId
, rTabName
, bCreateNew
, pnIndex
);
1257 // ============================================================================
1259 ScExternalRefManager::RefCells::TabItem::TabItem(SCTAB nIndex
) :
1264 ScExternalRefManager::RefCells::TabItem::TabItem(const TabItem
& r
) :
1270 ScExternalRefManager::RefCells::RefCells()
1274 ScExternalRefManager::RefCells::~RefCells()
1278 list
<ScExternalRefManager::RefCells::TabItemRef
>::iterator
ScExternalRefManager::RefCells::getTabPos(SCTAB nTab
)
1280 list
<TabItemRef
>::iterator itr
= maTables
.begin(), itrEnd
= maTables
.end();
1281 for (; itr
!= itrEnd
; ++itr
)
1282 if ((*itr
)->mnIndex
>= nTab
)
1284 // Not found. return the end position.
1288 void ScExternalRefManager::RefCells::insertCell(const ScAddress
& rAddr
)
1290 SCTAB nTab
= rAddr
.Tab();
1291 SCCOL nCol
= rAddr
.Col();
1292 SCROW nRow
= rAddr
.Row();
1294 // Search by table index.
1295 list
<TabItemRef
>::iterator itrTab
= getTabPos(nTab
);
1297 if (itrTab
== maTables
.end())
1299 // All previous tables come before the specificed table.
1300 xTabRef
.reset(new TabItem(nTab
));
1301 maTables
.push_back(xTabRef
);
1303 else if ((*itrTab
)->mnIndex
> nTab
)
1305 // Insert at the current iterator position.
1306 xTabRef
.reset(new TabItem(nTab
));
1307 maTables
.insert(itrTab
, xTabRef
);
1309 else if ((*itrTab
)->mnIndex
== nTab
)
1314 ColSet
& rCols
= xTabRef
->maCols
;
1316 // Then by column index.
1317 ColSet::iterator itrCol
= rCols
.find(nCol
);
1318 if (itrCol
== rCols
.end())
1321 pair
<ColSet::iterator
, bool> r
= rCols
.insert(ColSet::value_type(nCol
, aRows
));
1323 // column insertion failed.
1327 RowSet
& rRows
= itrCol
->second
;
1329 // Finally, insert the row index.
1333 void ScExternalRefManager::RefCells::removeCell(const ScAddress
& rAddr
)
1335 SCTAB nTab
= rAddr
.Tab();
1336 SCCOL nCol
= rAddr
.Col();
1337 SCROW nRow
= rAddr
.Row();
1339 // Search by table index.
1340 list
<TabItemRef
>::iterator itrTab
= getTabPos(nTab
);
1341 if (itrTab
== maTables
.end() || (*itrTab
)->mnIndex
!= nTab
)
1345 ColSet
& rCols
= (*itrTab
)->maCols
;
1347 // Then by column index.
1348 ColSet::iterator itrCol
= rCols
.find(nCol
);
1349 if (itrCol
== rCols
.end())
1353 RowSet
& rRows
= itrCol
->second
;
1357 void ScExternalRefManager::RefCells::moveTable(SCTAB nOldTab
, SCTAB nNewTab
, bool bCopy
)
1359 if (nOldTab
== nNewTab
)
1360 // Nothing to do here.
1363 list
<TabItemRef
>::iterator itrOld
= getTabPos(nOldTab
);
1364 if (itrOld
== maTables
.end() || (*itrOld
)->mnIndex
!= nOldTab
)
1365 // No table to move or copy.
1368 list
<TabItemRef
>::iterator itrNew
= getTabPos(nNewTab
);
1371 // Simply make a duplicate of the original table, insert it at the
1372 // new tab position, and increment the table index for all tables
1373 // that come after that inserted table.
1375 TabItemRef
xNewTab(new TabItem(*(*itrOld
)));
1376 xNewTab
->mnIndex
= nNewTab
;
1377 maTables
.insert(itrNew
, xNewTab
);
1378 list
<TabItemRef
>::iterator itr
= itrNew
, itrEnd
= maTables
.end();
1379 if (itr
!= itrEnd
) // #i99807# check that itr is not at end already
1380 for (++itr
; itr
!= itrEnd
; ++itr
)
1381 (*itr
)->mnIndex
+= 1;
1385 if (itrOld
== itrNew
)
1387 // No need to move the table. Just update the table index.
1388 (*itrOld
)->mnIndex
= nNewTab
;
1392 if (nOldTab
< nNewTab
)
1394 // Iterate from the old tab position to the new tab position (not
1395 // inclusive of the old tab itself), and decrement their tab
1397 list
<TabItemRef
>::iterator itr
= itrOld
;
1398 for (++itr
; itr
!= itrNew
; ++itr
)
1399 (*itr
)->mnIndex
-= 1;
1401 // Insert a duplicate of the original table. This does not
1402 // invalidate the iterators.
1403 (*itrOld
)->mnIndex
= nNewTab
- 1;
1404 if (itrNew
== maTables
.end())
1405 maTables
.push_back(*itrOld
);
1407 maTables
.insert(itrNew
, *itrOld
);
1409 // Remove the original table.
1410 maTables
.erase(itrOld
);
1414 // nNewTab < nOldTab
1416 // Iterate from the new tab position to the one before the old tab
1417 // position, and increment their tab index by one.
1418 list
<TabItemRef
>::iterator itr
= itrNew
;
1419 for (++itr
; itr
!= itrOld
; ++itr
)
1420 (*itr
)->mnIndex
+= 1;
1422 (*itrOld
)->mnIndex
= nNewTab
;
1423 maTables
.insert(itrNew
, *itrOld
);
1425 // Remove the original table.
1426 maTables
.erase(itrOld
);
1431 void ScExternalRefManager::RefCells::insertTable(SCTAB nPos
)
1433 TabItemRef
xNewTab(new TabItem(nPos
));
1434 list
<TabItemRef
>::iterator itr
= getTabPos(nPos
);
1435 if (itr
== maTables
.end())
1436 maTables
.push_back(xNewTab
);
1438 maTables
.insert(itr
, xNewTab
);
1441 void ScExternalRefManager::RefCells::removeTable(SCTAB nPos
)
1443 list
<TabItemRef
>::iterator itr
= getTabPos(nPos
);
1444 if (itr
== maTables
.end())
1445 // nothing to remove.
1448 maTables
.erase(itr
);
1451 void ScExternalRefManager::RefCells::refreshAllCells(ScExternalRefManager
& rRefMgr
)
1453 // Get ALL the cell positions for re-compilation.
1454 for (list
<TabItemRef
>::iterator itrTab
= maTables
.begin(), itrTabEnd
= maTables
.end();
1455 itrTab
!= itrTabEnd
; ++itrTab
)
1457 SCTAB nTab
= (*itrTab
)->mnIndex
;
1458 ColSet
& rCols
= (*itrTab
)->maCols
;
1459 for (ColSet::iterator itrCol
= rCols
.begin(), itrColEnd
= rCols
.end();
1460 itrCol
!= itrColEnd
; ++itrCol
)
1462 SCCOL nCol
= itrCol
->first
;
1463 RowSet
& rRows
= itrCol
->second
;
1465 for (RowSet::iterator itrRow
= rRows
.begin(), itrRowEnd
= rRows
.end();
1466 itrRow
!= itrRowEnd
; ++itrRow
)
1468 SCROW nRow
= *itrRow
;
1469 ScAddress
aCell(nCol
, nRow
, nTab
);
1470 if (rRefMgr
.compileTokensByCell(aCell
))
1471 // This cell still contains an external refernce.
1472 aNewRows
.insert(nRow
);
1474 // Update the rows so that cells with no external references are
1475 // no longer tracked.
1476 rRows
.swap(aNewRows
);
1481 // ----------------------------------------------------------------------------
1483 ScExternalRefManager::LinkListener::LinkListener()
1487 ScExternalRefManager::LinkListener::~LinkListener()
1491 // ----------------------------------------------------------------------------
1493 void ScExternalRefManager::getAllCachedTableNames(sal_uInt16 nFileId
, vector
<String
>& rTabNames
) const
1495 maRefCache
.getAllTableNames(nFileId
, rTabNames
);
1498 SCsTAB
ScExternalRefManager::getCachedTabSpan( sal_uInt16 nFileId
, const String
& rStartTabName
, const String
& rEndTabName
) const
1500 return maRefCache
.getTabSpan( nFileId
, rStartTabName
, rEndTabName
);
1503 void ScExternalRefManager::getAllCachedNumberFormats(vector
<sal_uInt32
>& rNumFmts
) const
1505 maRefCache
.getAllNumberFormats(rNumFmts
);
1508 bool ScExternalRefManager::hasCacheTable(sal_uInt16 nFileId
, const String
& rTabName
) const
1510 return maRefCache
.hasCacheTable(nFileId
, rTabName
);
1513 size_t ScExternalRefManager::getCacheTableCount(sal_uInt16 nFileId
) const
1515 return maRefCache
.getCacheTableCount(nFileId
);
1518 sal_uInt16
ScExternalRefManager::getExternalFileCount() const
1520 return static_cast< sal_uInt16
>( maSrcFiles
.size() );
1523 bool ScExternalRefManager::markUsedByLinkListeners()
1525 bool bAllMarked
= false;
1526 for (LinkListenerMap::const_iterator itr
= maLinkListeners
.begin();
1527 itr
!= maLinkListeners
.end() && !bAllMarked
; ++itr
)
1529 if (!(*itr
).second
.empty())
1530 bAllMarked
= maRefCache
.setCacheDocReferenced( (*itr
).first
);
1531 /* TODO: LinkListeners should remember the table they're listening to.
1532 * As is, listening to one table will mark all tables of the document
1533 * being referenced. */
1538 bool ScExternalRefManager::setCacheDocReferenced( sal_uInt16 nFileId
)
1540 return maRefCache
.setCacheDocReferenced( nFileId
);
1543 bool ScExternalRefManager::setCacheTableReferenced( sal_uInt16 nFileId
, const String
& rTabName
, size_t nSheets
)
1545 return maRefCache
.setCacheTableReferenced( nFileId
, rTabName
, nSheets
, false);
1548 void ScExternalRefManager::setCacheTableReferencedPermanently( sal_uInt16 nFileId
, const String
& rTabName
, size_t nSheets
)
1550 if (isInReferenceMarking())
1551 // Do all maintenance work.
1552 maRefCache
.setCacheTableReferenced( nFileId
, rTabName
, nSheets
, true);
1554 // Set only the permanent flag.
1555 maRefCache
.setCacheTableReferencedPermanently( nFileId
, rTabName
, nSheets
);
1558 void ScExternalRefManager::setAllCacheTableReferencedStati( bool bReferenced
)
1560 bInReferenceMarking
= !bReferenced
;
1561 maRefCache
.setAllCacheTableReferencedStati( bReferenced
);
1564 void ScExternalRefManager::storeRangeNameTokens(sal_uInt16 nFileId
, const String
& rName
, const ScTokenArray
& rArray
)
1566 ScExternalRefCache::TokenArrayRef
pArray(rArray
.Clone());
1567 maRefCache
.setRangeNameTokens(nFileId
, rName
, pArray
);
1570 ScExternalRefCache::TokenRef
ScExternalRefManager::getSingleRefToken(
1571 sal_uInt16 nFileId
, const String
& rTabName
, const ScAddress
& rCell
,
1572 const ScAddress
* pCurPos
, SCTAB
* pTab
, ScExternalRefCache::CellFormat
* pFmt
)
1575 insertRefCell(nFileId
, *pCurPos
);
1577 maybeLinkExternalFile(nFileId
);
1583 pFmt
->mbIsSet
= false;
1585 bool bLoading
= mpDoc
->IsImportingXML();
1587 // Check if the given table name and the cell position is cached.
1588 // #i101304# When loading a file, the saved cache (hidden sheet)
1589 // is assumed to contain all data for the loaded formulas.
1590 // No cache entries are created from empty cells in the saved sheet,
1591 // so they have to be created here (bWriteEmpty parameter).
1592 // Otherwise, later interpretation of the loaded formulas would
1593 // load the source document even if the user didn't want to update.
1594 sal_uInt32 nFmtIndex
= 0;
1595 ScExternalRefCache::TokenRef pToken
= maRefCache
.getCellData(
1596 nFileId
, rTabName
, rCell
.Col(), rCell
.Row(), bLoading
, bLoading
, &nFmtIndex
);
1601 short nFmtType
= mpDoc
->GetFormatTable()->GetType(nFmtIndex
);
1602 if (nFmtType
!= NUMBERFORMAT_UNDEFINED
)
1604 pFmt
->mbIsSet
= true;
1605 pFmt
->mnIndex
= nFmtIndex
;
1606 pFmt
->mnType
= nFmtType
;
1612 // reference not cached. read from the source document.
1613 ScDocument
* pSrcDoc
= getSrcDocument(nFileId
);
1616 // Source document is not reachable. Try to get data from the cache
1617 // once again, but this time treat a non-cached cell as an empty cell
1618 // as long as the table itself is cached.
1619 pToken
= maRefCache
.getCellData(
1620 nFileId
, rTabName
, rCell
.Col(), rCell
.Row(), true, false, &nFmtIndex
);
1624 ScBaseCell
* pCell
= NULL
;
1626 if (!pSrcDoc
->GetTable(rTabName
, nTab
))
1628 // specified table name doesn't exist in the source document.
1629 return ScExternalRefCache::TokenRef();
1635 pSrcDoc
->GetCell(rCell
.Col(), rCell
.Row(), nTab
, pCell
);
1636 ScExternalRefCache::TokenRef
pTok(lcl_convertToToken(pCell
));
1638 pSrcDoc
->GetNumberFormat(rCell
.Col(), rCell
.Row(), nTab
, nFmtIndex
);
1639 nFmtIndex
= getMappedNumberFormat(nFileId
, nFmtIndex
, pSrcDoc
);
1642 short nFmtType
= mpDoc
->GetFormatTable()->GetType(nFmtIndex
);
1643 if (nFmtType
!= NUMBERFORMAT_UNDEFINED
)
1645 pFmt
->mbIsSet
= true;
1646 pFmt
->mnIndex
= nFmtIndex
;
1647 pFmt
->mnType
= nFmtType
;
1653 // Generate an error for unresolvable cells.
1654 pTok
.reset( new FormulaErrorToken( errNoValue
));
1657 // Now, insert the token into cache table.
1658 maRefCache
.setCellData(nFileId
, rTabName
, rCell
.Row(), rCell
.Col(), pTok
, nFmtIndex
);
1662 ScExternalRefCache::TokenArrayRef
ScExternalRefManager::getDoubleRefTokens(sal_uInt16 nFileId
, const String
& rTabName
, const ScRange
& rRange
, const ScAddress
* pCurPos
)
1665 insertRefCell(nFileId
, *pCurPos
);
1667 maybeLinkExternalFile(nFileId
);
1669 bool bLoading
= mpDoc
->IsImportingXML();
1671 // Check if the given table name and the cell position is cached.
1672 // #i101304# When loading, put empty cells into cache, see getSingleRefToken.
1673 ScExternalRefCache::TokenArrayRef p
= maRefCache
.getCellRangeData(nFileId
, rTabName
, rRange
, bLoading
, bLoading
);
1677 ScDocument
* pSrcDoc
= getSrcDocument(nFileId
);
1680 // Source document is not reachable. Try to get data from the cache
1681 // once again, but this time treat non-cached cells as empty cells as
1682 // long as the table itself is cached.
1683 return maRefCache
.getCellRangeData(nFileId
, rTabName
, rRange
, true, false);
1687 if (!pSrcDoc
->GetTable(rTabName
, nTab1
))
1688 // specified table name doesn't exist in the source document.
1689 return ScExternalRefCache::TokenArrayRef();
1691 ScRange
aRange(rRange
);
1692 SCTAB nTabSpan
= aRange
.aEnd
.Tab() - aRange
.aStart
.Tab();
1694 vector
<ScExternalRefCache::SingleRangeData
> aCacheData
;
1695 aCacheData
.reserve(nTabSpan
+1);
1696 aCacheData
.push_back(ScExternalRefCache::SingleRangeData());
1697 aCacheData
.back().maTableName
= ScGlobal::pCharClass
->upper(rTabName
);
1699 for (SCTAB i
= 1; i
< nTabSpan
+ 1; ++i
)
1702 if (!pSrcDoc
->GetName(nTab1
+ 1, aTabName
))
1703 // source document doesn't have any table by the specified name.
1706 aCacheData
.push_back(ScExternalRefCache::SingleRangeData());
1707 aCacheData
.back().maTableName
= ScGlobal::pCharClass
->upper(aTabName
);
1710 aRange
.aStart
.SetTab(nTab1
);
1711 aRange
.aEnd
.SetTab(nTab1
+ nTabSpan
);
1713 ScExternalRefCache::TokenArrayRef pArray
;
1714 pArray
.reset(lcl_convertToTokenArray(pSrcDoc
, aRange
, aCacheData
));
1717 // Cache these values.
1718 maRefCache
.setCellRangeData(nFileId
, rRange
, aCacheData
, pArray
);
1723 ScExternalRefCache::TokenArrayRef
ScExternalRefManager::getRangeNameTokens(sal_uInt16 nFileId
, const String
& rName
, const ScAddress
* pCurPos
)
1726 insertRefCell(nFileId
, *pCurPos
);
1728 maybeLinkExternalFile(nFileId
);
1730 ScExternalRefCache::TokenArrayRef pArray
= maRefCache
.getRangeNameTokens(nFileId
, rName
);
1734 ScDocument
* pSrcDoc
= getSrcDocument(nFileId
);
1736 return ScExternalRefCache::TokenArrayRef();
1738 ScRangeName
* pExtNames
= pSrcDoc
->GetRangeName();
1739 String aUpperName
= ScGlobal::pCharClass
->upper(rName
);
1741 bool bRes
= pExtNames
->SearchNameUpper(aUpperName
, n
);
1743 return ScExternalRefCache::TokenArrayRef();
1745 ScRangeData
* pRangeData
= (*pExtNames
)[n
];
1747 return ScExternalRefCache::TokenArrayRef();
1749 // Parse all tokens in this external range data, and replace each absolute
1750 // reference token with an external reference token, and cache them. Also
1751 // register the source document with the link manager if it's a new
1754 ScExternalRefCache::TokenArrayRef
pNew(new ScTokenArray
);
1756 ScTokenArray
* pCode
= pRangeData
->GetCode();
1757 for (FormulaToken
* pToken
= pCode
->First(); pToken
; pToken
= pCode
->Next())
1759 bool bTokenAdded
= false;
1760 switch (pToken
->GetType())
1764 const ScSingleRefData
& rRef
= static_cast<ScToken
*>(pToken
)->GetSingleRef();
1766 pSrcDoc
->GetName(rRef
.nTab
, aTabName
);
1767 ScExternalSingleRefToken
aNewToken(nFileId
, aTabName
, static_cast<ScToken
*>(pToken
)->GetSingleRef());
1768 pNew
->AddToken(aNewToken
);
1774 const ScSingleRefData
& rRef
= static_cast<ScToken
*>(pToken
)->GetSingleRef();
1776 pSrcDoc
->GetName(rRef
.nTab
, aTabName
);
1777 ScExternalDoubleRefToken
aNewToken(nFileId
, aTabName
, static_cast<ScToken
*>(pToken
)->GetDoubleRef());
1778 pNew
->AddToken(aNewToken
);
1787 pNew
->AddToken(*pToken
);
1790 // Make sure to pass the correctly-cased range name here.
1791 maRefCache
.setRangeNameTokens(nFileId
, pRangeData
->GetName(), pNew
);
1795 void ScExternalRefManager::refreshAllRefCells(sal_uInt16 nFileId
)
1797 RefCellMap::iterator itrFile
= maRefCells
.find(nFileId
);
1798 if (itrFile
== maRefCells
.end())
1801 RefCells
& rRefCells
= itrFile
->second
;
1802 rRefCells
.refreshAllCells(*this);
1804 ScViewData
* pViewData
= ScDocShell::GetViewData();
1808 ScTabViewShell
* pVShell
= pViewData
->GetViewShell();
1812 // Repainting the grid also repaints the texts, but is there a better way
1813 // to refresh texts?
1814 pVShell
->Invalidate(FID_REPAINT
);
1815 pVShell
->PaintGrid();
1818 void ScExternalRefManager::insertRefCell(sal_uInt16 nFileId
, const ScAddress
& rCell
)
1820 RefCellMap::iterator itr
= maRefCells
.find(nFileId
);
1821 if (itr
== maRefCells
.end())
1824 pair
<RefCellMap::iterator
, bool> r
= maRefCells
.insert(
1825 RefCellMap::value_type(nFileId
, aRefCells
));
1827 // insertion failed.
1832 itr
->second
.insertCell(rCell
);
1835 ScDocument
* ScExternalRefManager::getSrcDocument(sal_uInt16 nFileId
)
1837 if (!mpDoc
->IsExecuteLinkEnabled())
1840 DocShellMap::iterator itrEnd
= maDocShells
.end();
1841 DocShellMap::iterator itr
= maDocShells
.find(nFileId
);
1845 SfxObjectShell
* p
= itr
->second
.maShell
;
1846 itr
->second
.maLastAccess
= Time();
1847 return static_cast<ScDocShell
*>(p
)->GetDocument();
1850 const String
* pFile
= getExternalFileName(nFileId
);
1852 // no file name associated with this ID.
1857 aSrcDoc
.maShell
= loadSrcDocument(nFileId
, aFilter
);
1858 if (!aSrcDoc
.maShell
.Is())
1860 // source document could not be loaded.
1864 if (maDocShells
.empty())
1866 // If this is the first source document insertion, start up the timer.
1867 maSrcDocTimer
.Start();
1870 maDocShells
.insert(DocShellMap::value_type(nFileId
, aSrcDoc
));
1871 SfxObjectShell
* p
= aSrcDoc
.maShell
;
1872 ScDocument
* pSrcDoc
= static_cast<ScDocShell
*>(p
)->GetDocument();
1874 SCTAB nTabCount
= pSrcDoc
->GetTableCount();
1875 if (!maRefCache
.isDocInitialized(nFileId
) && nTabCount
)
1877 // Populate the cache with all table names in the source document.
1878 vector
<String
> aTabNames
;
1879 aTabNames
.reserve(nTabCount
);
1880 for (SCTAB i
= 0; i
< nTabCount
; ++i
)
1883 pSrcDoc
->GetName(i
, aName
);
1884 aTabNames
.push_back(aName
);
1886 maRefCache
.initializeDoc(nFileId
, aTabNames
);
1891 SfxObjectShellRef
ScExternalRefManager::loadSrcDocument(sal_uInt16 nFileId
, String
& rFilter
)
1893 const SrcFileData
* pFileData
= getExternalFileData(nFileId
);
1897 String aFile
= pFileData
->maFileName
;
1898 if (!isFileLoadable(aFile
))
1900 // The original file path is not loadable. Try the relative path.
1901 // Note that the path is relative to the content.xml substream which
1902 // is one-level higher than the file itself.
1904 if (!pFileData
->maRelativeName
.Len())
1907 INetURLObject
aBaseURL(getOwnDocumentName());
1908 aBaseURL
.insertName(OUString::createFromAscii("content.xml"));
1909 bool bWasAbs
= false;
1910 aFile
= aBaseURL
.smartRel2Abs(pFileData
->maRelativeName
, bWasAbs
).GetMainURL(INetURLObject::NO_DECODE
);
1911 if (!isFileLoadable(aFile
))
1912 // Ok, I've tried both paths but no success. Bail out.
1917 ScDocumentLoader::GetFilterName(aFile
, rFilter
, aOptions
, true, false);
1918 const SfxFilter
* pFilter
= ScDocShell::Factory().GetFilterContainer()->GetFilter4FilterName(rFilter
);
1920 if (!pFileData
->maRelativeName
.Len())
1922 // Generate a relative file path.
1923 INetURLObject
aBaseURL(getOwnDocumentName());
1924 aBaseURL
.insertName(OUString::createFromAscii("content.xml"));
1926 String aStr
= URIHelper::simpleNormalizedMakeRelative(
1927 aBaseURL
.GetMainURL(INetURLObject::NO_DECODE
), aFile
);
1929 setRelativeFileName(nFileId
, aStr
);
1932 // Update the filter data now that we are loading it again.
1933 setFilterData(nFileId
, rFilter
, aOptions
);
1935 SfxItemSet
* pSet
= new SfxAllItemSet(SFX_APP()->GetPool());
1937 pSet
->Put(SfxStringItem(SID_FILE_FILTEROPTIONS
, aOptions
));
1939 auto_ptr
<SfxMedium
> pMedium(new SfxMedium(aFile
, STREAM_STD_READ
, false, pFilter
, pSet
));
1940 if (pMedium
->GetError() != ERRCODE_NONE
)
1943 pMedium
->UseInteractionHandler(false);
1945 ScDocShell
* pNewShell
= new ScDocShell(SFX_CREATE_MODE_INTERNAL
);
1946 SfxObjectShellRef aRef
= pNewShell
;
1948 // increment the recursive link count of the source document.
1949 ScExtDocOptions
* pExtOpt
= mpDoc
->GetExtDocOptions();
1950 sal_uInt32 nLinkCount
= pExtOpt
? pExtOpt
->GetDocSettings().mnLinkCnt
: 0;
1951 ScDocument
* pSrcDoc
= pNewShell
->GetDocument();
1952 ScExtDocOptions
* pExtOptNew
= pSrcDoc
->GetExtDocOptions();
1955 pExtOptNew
= new ScExtDocOptions
;
1956 pSrcDoc
->SetExtDocOptions(pExtOptNew
);
1958 pExtOptNew
->GetDocSettings().mnLinkCnt
= nLinkCount
+ 1;
1960 pNewShell
->DoLoad(pMedium
.release());
1964 bool ScExternalRefManager::isFileLoadable(const String
& rFile
) const
1966 if (isOwnDocument(rFile
))
1969 if (utl::UCBContentHelper::IsFolder(rFile
))
1972 return utl::UCBContentHelper::Exists(rFile
);
1975 void ScExternalRefManager::maybeLinkExternalFile(sal_uInt16 nFileId
)
1977 if (maLinkedDocs
.count(nFileId
))
1978 // file alerady linked, or the link has been broken.
1981 // Source document not linked yet. Link it now.
1982 const String
* pFileName
= getExternalFileName(nFileId
);
1986 String aFilter
, aOptions
;
1987 ScDocumentLoader::GetFilterName(*pFileName
, aFilter
, aOptions
, true, false);
1988 SvxLinkManager
* pLinkMgr
= mpDoc
->GetLinkManager();
1989 ScExternalRefLink
* pLink
= new ScExternalRefLink(mpDoc
, nFileId
, aFilter
);
1990 DBG_ASSERT(pFileName
, "ScExternalRefManager::insertExternalFileLink: file name pointer is NULL");
1991 pLinkMgr
->InsertFileLink(*pLink
, OBJECT_CLIENT_FILE
, *pFileName
, &aFilter
);
1993 pLink
->SetDoReferesh(false);
1995 pLink
->SetDoReferesh(true);
1997 maLinkedDocs
.insert(LinkedDocMap::value_type(nFileId
, true));
2000 bool ScExternalRefManager::compileTokensByCell(const ScAddress
& rCell
)
2003 mpDoc
->GetCell(rCell
.Col(), rCell
.Row(), rCell
.Tab(), pCell
);
2005 if (!pCell
|| pCell
->GetCellType() != CELLTYPE_FORMULA
)
2008 ScFormulaCell
* pFC
= static_cast<ScFormulaCell
*>(pCell
);
2010 // Check to make sure the cell really contains ocExternalRef.
2011 // External names, external cell and range references all have a
2012 // ocExternalRef token.
2013 const ScTokenArray
* pCode
= pFC
->GetCode();
2014 if (!pCode
->HasOpCode( ocExternalRef
))
2017 ScTokenArray
* pArray
= pFC
->GetCode();
2019 // Clear the error code, or a cell with error won't get re-compiled.
2020 pArray
->SetCodeError(0);
2022 pFC
->SetCompile(true);
2023 pFC
->CompileTokenArray();
2029 const String
& ScExternalRefManager::getOwnDocumentName() const
2031 SfxObjectShell
* pShell
= mpDoc
->GetDocumentShell();
2033 // This should not happen!
2034 return EMPTY_STRING
;
2036 SfxMedium
* pMed
= pShell
->GetMedium();
2038 return EMPTY_STRING
;
2040 return pMed
->GetName();
2043 bool ScExternalRefManager::isOwnDocument(const String
& rFile
) const
2045 return getOwnDocumentName().Equals(rFile
);
2048 void ScExternalRefManager::convertToAbsName(String
& rFile
) const
2050 SfxObjectShell
* pDocShell
= mpDoc
->GetDocumentShell();
2051 rFile
= ScGlobal::GetAbsDocName(rFile
, pDocShell
);
2054 sal_uInt16
ScExternalRefManager::getExternalFileId(const String
& rFile
)
2056 vector
<SrcFileData
>::const_iterator itrBeg
= maSrcFiles
.begin(), itrEnd
= maSrcFiles
.end();
2057 vector
<SrcFileData
>::const_iterator itr
= find_if(itrBeg
, itrEnd
, FindSrcFileByName(rFile
));
2060 size_t nId
= distance(itrBeg
, itr
);
2061 return static_cast<sal_uInt16
>(nId
);
2065 aData
.maFileName
= rFile
;
2066 maSrcFiles
.push_back(aData
);
2067 return static_cast<sal_uInt16
>(maSrcFiles
.size() - 1);
2070 const String
* ScExternalRefManager::getExternalFileName(sal_uInt16 nFileId
) const
2072 if (nFileId
>= maSrcFiles
.size())
2075 return &maSrcFiles
[nFileId
].maFileName
;
2078 bool ScExternalRefManager::hasExternalFile(sal_uInt16 nFileId
) const
2080 return nFileId
< maSrcFiles
.size();
2083 bool ScExternalRefManager::hasExternalFile(const String
& rFile
) const
2085 vector
<SrcFileData
>::const_iterator itrBeg
= maSrcFiles
.begin(), itrEnd
= maSrcFiles
.end();
2086 vector
<SrcFileData
>::const_iterator itr
= find_if(itrBeg
, itrEnd
, FindSrcFileByName(rFile
));
2087 return itr
!= itrEnd
;
2090 const ScExternalRefManager::SrcFileData
* ScExternalRefManager::getExternalFileData(sal_uInt16 nFileId
) const
2092 if (nFileId
>= maSrcFiles
.size())
2095 return &maSrcFiles
[nFileId
];
2098 const String
* ScExternalRefManager::getRealTableName(sal_uInt16 nFileId
, const String
& rTabName
) const
2100 return maRefCache
.getRealTableName(nFileId
, rTabName
);
2103 const String
* ScExternalRefManager::getRealRangeName(sal_uInt16 nFileId
, const String
& rRangeName
) const
2105 return maRefCache
.getRealRangeName(nFileId
, rRangeName
);
2108 template<typename MapContainer
>
2109 void lcl_removeByFileId(sal_uInt16 nFileId
, MapContainer
& rMap
)
2111 typename
MapContainer::iterator itr
= rMap
.find(nFileId
);
2112 if (itr
!= rMap
.end())
2116 void ScExternalRefManager::refreshNames(sal_uInt16 nFileId
)
2118 maRefCache
.clearCache(nFileId
);
2119 lcl_removeByFileId(nFileId
, maDocShells
);
2121 if (maDocShells
.empty())
2122 maSrcDocTimer
.Stop();
2124 // Update all cells containing names from this source document.
2125 refreshAllRefCells(nFileId
);
2127 notifyAllLinkListeners(nFileId
, LINK_MODIFIED
);
2130 void ScExternalRefManager::breakLink(sal_uInt16 nFileId
)
2132 lcl_removeByFileId(nFileId
, maDocShells
);
2134 if (maDocShells
.empty())
2135 maSrcDocTimer
.Stop();
2137 LinkedDocMap::iterator itr
= maLinkedDocs
.find(nFileId
);
2138 if (itr
!= maLinkedDocs
.end())
2139 itr
->second
= false;
2141 notifyAllLinkListeners(nFileId
, LINK_BROKEN
);
2144 void ScExternalRefManager::switchSrcFile(sal_uInt16 nFileId
, const String
& rNewFile
)
2146 maSrcFiles
[nFileId
].maFileName
= rNewFile
;
2147 maSrcFiles
[nFileId
].maRelativeName
.Erase();
2148 refreshNames(nFileId
);
2151 void ScExternalRefManager::setRelativeFileName(sal_uInt16 nFileId
, const String
& rRelUrl
)
2153 if (nFileId
>= maSrcFiles
.size())
2155 maSrcFiles
[nFileId
].maRelativeName
= rRelUrl
;
2158 void ScExternalRefManager::setFilterData(sal_uInt16 nFileId
, const String
& rFilterName
, const String
& rOptions
)
2160 if (nFileId
>= maSrcFiles
.size())
2162 maSrcFiles
[nFileId
].maFilterName
= rFilterName
;
2163 maSrcFiles
[nFileId
].maFilterOptions
= rOptions
;
2166 void ScExternalRefManager::clear()
2168 DocShellMap::iterator itrEnd
= maDocShells
.end();
2169 for (DocShellMap::iterator itr
= maDocShells
.begin(); itr
!= itrEnd
; ++itr
)
2170 itr
->second
.maShell
->DoClose();
2172 maDocShells
.clear();
2173 maSrcDocTimer
.Stop();
2176 bool ScExternalRefManager::hasExternalData() const
2178 return !maSrcFiles
.empty();
2181 void ScExternalRefManager::resetSrcFileData()
2183 INetURLObject
aBaseURL(getOwnDocumentName());
2184 aBaseURL
.insertName(OUString::createFromAscii("content.xml"));
2185 String aBaseUrlStr
= aBaseURL
.GetMainURL(INetURLObject::NO_DECODE
);
2186 for (vector
<SrcFileData
>::iterator itr
= maSrcFiles
.begin(), itrEnd
= maSrcFiles
.end();
2187 itr
!= itrEnd
; ++itr
)
2189 if (!itr
->maRelativeName
.Len())
2191 itr
->maRelativeName
= URIHelper::simpleNormalizedMakeRelative(
2192 aBaseUrlStr
, itr
->maFileName
);
2197 void ScExternalRefManager::updateRefCell(const ScAddress
& rOldPos
, const ScAddress
& rNewPos
, bool bCopy
)
2199 for (RefCellMap::iterator itr
= maRefCells
.begin(), itrEnd
= maRefCells
.end(); itr
!= itrEnd
; ++itr
)
2202 itr
->second
.removeCell(rOldPos
);
2203 itr
->second
.insertCell(rNewPos
);
2207 void ScExternalRefManager::updateRefMoveTable(SCTAB nOldTab
, SCTAB nNewTab
, bool bCopy
)
2209 for (RefCellMap::iterator itr
= maRefCells
.begin(), itrEnd
= maRefCells
.end(); itr
!= itrEnd
; ++itr
)
2210 itr
->second
.moveTable(nOldTab
, nNewTab
, bCopy
);
2213 void ScExternalRefManager::updateRefInsertTable(SCTAB nPos
)
2215 for (RefCellMap::iterator itr
= maRefCells
.begin(), itrEnd
= maRefCells
.end(); itr
!= itrEnd
; ++itr
)
2216 itr
->second
.insertTable(nPos
);
2219 void ScExternalRefManager::updateRefDeleteTable(SCTAB nPos
)
2221 for (RefCellMap::iterator itr
= maRefCells
.begin(), itrEnd
= maRefCells
.end(); itr
!= itrEnd
; ++itr
)
2222 itr
->second
.removeTable(nPos
);
2225 void ScExternalRefManager::addLinkListener(sal_uInt16 nFileId
, LinkListener
* pListener
)
2227 LinkListenerMap::iterator itr
= maLinkListeners
.find(nFileId
);
2228 if (itr
== maLinkListeners
.end())
2230 pair
<LinkListenerMap::iterator
, bool> r
= maLinkListeners
.insert(
2231 LinkListenerMap::value_type(nFileId
, LinkListeners()));
2234 DBG_ERROR("insertion of new link listener list failed");
2241 LinkListeners
& rList
= itr
->second
;
2242 rList
.insert(pListener
);
2245 void ScExternalRefManager::removeLinkListener(sal_uInt16 nFileId
, LinkListener
* pListener
)
2247 LinkListenerMap::iterator itr
= maLinkListeners
.find(nFileId
);
2248 if (itr
== maLinkListeners
.end())
2249 // no listeners for a specified file.
2252 LinkListeners
& rList
= itr
->second
;
2253 rList
.erase(pListener
);
2256 // No more listeners for this file. Remove its entry.
2257 maLinkListeners
.erase(itr
);
2260 void ScExternalRefManager::removeLinkListener(LinkListener
* pListener
)
2262 LinkListenerMap::iterator itr
= maLinkListeners
.begin(), itrEnd
= maLinkListeners
.end();
2263 for (; itr
!= itrEnd
; ++itr
)
2264 itr
->second
.erase(pListener
);
2267 void ScExternalRefManager::notifyAllLinkListeners(sal_uInt16 nFileId
, LinkUpdateType eType
)
2269 LinkListenerMap::iterator itr
= maLinkListeners
.find(nFileId
);
2270 if (itr
== maLinkListeners
.end())
2271 // no listeners for a specified file.
2274 LinkListeners
& rList
= itr
->second
;
2275 for_each(rList
.begin(), rList
.end(), NotifyLinkListener(nFileId
, eType
));
2278 void ScExternalRefManager::purgeStaleSrcDocument(sal_Int32 nTimeOut
)
2280 DocShellMap aNewDocShells
;
2281 DocShellMap::iterator itr
= maDocShells
.begin(), itrEnd
= maDocShells
.end();
2282 for (; itr
!= itrEnd
; ++itr
)
2284 // in 100th of a second.
2285 sal_Int32 nSinceLastAccess
= (Time() - itr
->second
.maLastAccess
).GetTime();
2286 if (nSinceLastAccess
< nTimeOut
)
2287 aNewDocShells
.insert(*itr
);
2289 maDocShells
.swap(aNewDocShells
);
2291 if (maDocShells
.empty())
2292 maSrcDocTimer
.Stop();
2295 sal_uInt32
ScExternalRefManager::getMappedNumberFormat(sal_uInt16 nFileId
, sal_uInt32 nNumFmt
, ScDocument
* pSrcDoc
)
2297 NumFmtMap::iterator itr
= maNumFormatMap
.find(nFileId
);
2298 if (itr
== maNumFormatMap
.end())
2300 // Number formatter map is not initialized for this external document.
2301 pair
<NumFmtMap::iterator
, bool> r
= maNumFormatMap
.insert(
2302 NumFmtMap::value_type(nFileId
, SvNumberFormatterMergeMap()));
2305 // insertion failed.
2309 mpDoc
->GetFormatTable()->MergeFormatter( *pSrcDoc
->GetFormatTable());
2310 SvNumberFormatterMergeMap aMap
= mpDoc
->GetFormatTable()->ConvertMergeTableToMap();
2311 itr
->second
.swap(aMap
);
2313 const SvNumberFormatterMergeMap
& rMap
= itr
->second
;
2314 SvNumberFormatterMergeMap::const_iterator itrNumFmt
= rMap
.find(nNumFmt
);
2315 if (itrNumFmt
!= rMap
.end())
2316 // mapped value found.
2317 return itrNumFmt
->second
;
2322 IMPL_LINK(ScExternalRefManager
, TimeOutHdl
, AutoTimer
*, pTimer
)
2324 if (pTimer
== &maSrcDocTimer
)
2325 purgeStaleSrcDocument(SRCDOC_LIFE_SPAN
);