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 // In API, the index is transported as cached sheet ID of type sal_Int32 in
954 // sheet::SingleReference.Sheet or sheet::ComplexReference.Reference1.Sheet
955 // in a sheet::FormulaToken, choose a sensible value for N/A. Effectively
957 const size_t nNotAvailable
= static_cast<size_t>( static_cast<sal_Int32
>( -1));
959 DocItem
* pDoc
= getDocItem(nFileId
);
962 if (pnIndex
) *pnIndex
= nNotAvailable
;
963 return TableTypeRef();
966 DocItem
& rDoc
= *pDoc
;
969 String aTabNameUpper
= ScGlobal::pCharClass
->upper(rTabName
);
970 if (lcl_getTableDataIndex(rDoc
.maTableNameIndex
, aTabNameUpper
, nIndex
))
972 // specified table found.
973 if( pnIndex
) *pnIndex
= nIndex
;
974 return rDoc
.maTables
[nIndex
];
979 if (pnIndex
) *pnIndex
= nNotAvailable
;
980 return TableTypeRef();
983 // Specified table doesn't exist yet. Create one.
984 nIndex
= rDoc
.maTables
.size();
985 if( pnIndex
) *pnIndex
= nIndex
;
986 TableTypeRef
pTab(new Table
);
987 rDoc
.maTables
.push_back(pTab
);
988 rDoc
.maTableNames
.push_back(TableName(aTabNameUpper
, rTabName
));
989 rDoc
.maTableNameIndex
.insert(
990 TableNameIndexMap::value_type(aTabNameUpper
, nIndex
));
994 void ScExternalRefCache::clearCache(sal_uInt16 nFileId
)
996 maDocs
.erase(nFileId
);
999 ScExternalRefCache::DocItem
* ScExternalRefCache::getDocItem(sal_uInt16 nFileId
) const
1002 DocDataType::iterator itrDoc
= maDocs
.find(nFileId
);
1003 if (itrDoc
== maDocs
.end())
1005 // specified document is not cached.
1006 pair
<DocDataType::iterator
, bool> res
= maDocs
.insert(
1007 DocDataType::value_type(nFileId
, DocItem()));
1010 // insertion failed.
1016 return &itrDoc
->second
;
1019 // ============================================================================
1021 ScExternalRefLink::ScExternalRefLink(ScDocument
* pDoc
, sal_uInt16 nFileId
, const String
& rFilter
) :
1022 ::sfx2::SvBaseLink(::sfx2::LINKUPDATE_ONCALL
, FORMAT_FILE
),
1024 maFilterName(rFilter
),
1030 ScExternalRefLink::~ScExternalRefLink()
1034 void ScExternalRefLink::Closed()
1036 ScExternalRefManager
* pMgr
= mpDoc
->GetExternalRefManager();
1037 pMgr
->breakLink(mnFileId
);
1040 void ScExternalRefLink::DataChanged(const String
& /*rMimeType*/, const Any
& /*rValue*/)
1045 String aFile
, aFilter
;
1046 mpDoc
->GetLinkManager()->GetDisplayNames(this, NULL
, &aFile
, NULL
, &aFilter
);
1047 ScExternalRefManager
* pMgr
= mpDoc
->GetExternalRefManager();
1048 const String
* pCurFile
= pMgr
->getExternalFileName(mnFileId
);
1052 if (pCurFile
->Equals(aFile
))
1054 // Refresh the current source document.
1055 pMgr
->refreshNames(mnFileId
);
1059 // The source document has changed.
1060 ScDocShell
* pDocShell
= ScDocShell::GetViewData()->GetDocShell();
1061 ScDocShellModificator
aMod(*pDocShell
);
1062 pMgr
->switchSrcFile(mnFileId
, aFile
, aFilter
);
1063 maFilterName
= aFilter
;
1064 aMod
.SetDocumentModified();
1068 void ScExternalRefLink::Edit(Window
* pParent
, const Link
& /*rEndEditHdl*/)
1070 SvBaseLink::Edit(pParent
, LINK(this, ScExternalRefLink
, ExternalRefEndEditHdl
));
1073 void ScExternalRefLink::SetDoReferesh(bool b
)
1078 IMPL_LINK( ScExternalRefLink
, ExternalRefEndEditHdl
, ::sfx2::SvBaseLink
*, EMPTYARG
)
1083 // ============================================================================
1085 static FormulaToken
* lcl_convertToToken(ScBaseCell
* pCell
)
1087 if (!pCell
|| pCell
->HasEmptyData())
1089 bool bInherited
= (pCell
&& pCell
->GetCellType() == CELLTYPE_FORMULA
);
1090 return new ScEmptyCellToken( bInherited
, false);
1093 switch (pCell
->GetCellType())
1098 static_cast<ScEditCell
*>(pCell
)->GetString(aStr
);
1099 return new formula::FormulaStringToken(aStr
);
1102 case CELLTYPE_STRING
:
1105 static_cast<ScStringCell
*>(pCell
)->GetString(aStr
);
1106 return new formula::FormulaStringToken(aStr
);
1109 case CELLTYPE_VALUE
:
1111 double fVal
= static_cast<ScValueCell
*>(pCell
)->GetValue();
1112 return new formula::FormulaDoubleToken(fVal
);
1115 case CELLTYPE_FORMULA
:
1117 ScFormulaCell
* pFCell
= static_cast<ScFormulaCell
*>(pCell
);
1118 USHORT nError
= pFCell
->GetErrCode();
1120 return new FormulaErrorToken( nError
);
1121 else if (pFCell
->IsValue())
1123 double fVal
= pFCell
->GetValue();
1124 return new formula::FormulaDoubleToken(fVal
);
1129 pFCell
->GetString(aStr
);
1130 return new formula::FormulaStringToken(aStr
);
1135 DBG_ERROR("attempted to convert an unknown cell type.");
1141 static ScTokenArray
* lcl_convertToTokenArray(ScDocument
* pSrcDoc
, const ScRange
& rRange
,
1142 vector
<ScExternalRefCache::SingleRangeData
>& rCacheData
)
1144 const ScAddress
& s
= rRange
.aStart
;
1145 const ScAddress
& e
= rRange
.aEnd
;
1147 SCTAB nTab1
= s
.Tab(), nTab2
= e
.Tab();
1148 SCCOL nCol1
= s
.Col(), nCol2
= e
.Col();
1149 SCROW nRow1
= s
.Row(), nRow2
= e
.Row();
1152 // For now, we don't support multi-sheet ranges intentionally because
1153 // we don't have a way to express them in a single token. In the
1154 // future we can introduce a new stack variable type svMatrixList with
1155 // a new token type that can store a 3D matrix value and convert a 3D
1159 auto_ptr
<ScTokenArray
> pArray(new ScTokenArray
);
1160 bool bFirstTab
= true;
1161 vector
<ScExternalRefCache::SingleRangeData
>::iterator
1162 itrCache
= rCacheData
.begin(), itrCacheEnd
= rCacheData
.end();
1163 for (SCTAB nTab
= nTab1
; nTab
<= nTab2
&& itrCache
!= itrCacheEnd
; ++nTab
, ++itrCache
)
1165 ScMatrixRef xMat
= new ScMatrix(
1166 static_cast<SCSIZE
>(nCol2
-nCol1
+1),
1167 static_cast<SCSIZE
>(nRow2
-nRow1
+1));
1169 for (SCCOL nCol
= nCol1
; nCol
<= nCol2
; ++nCol
)
1171 for (SCROW nRow
= nRow1
; nRow
<= nRow2
; ++nRow
)
1173 SCSIZE nC
= nCol
- nCol1
, nR
= nRow
- nRow1
;
1175 pSrcDoc
->GetCell(nCol
, nRow
, nTab
, pCell
);
1176 if (!pCell
|| pCell
->HasEmptyData())
1177 xMat
->PutEmpty(nC
, nR
);
1180 switch (pCell
->GetCellType())
1185 static_cast<ScEditCell
*>(pCell
)->GetString(aStr
);
1186 xMat
->PutString(aStr
, nC
, nR
);
1189 case CELLTYPE_STRING
:
1192 static_cast<ScStringCell
*>(pCell
)->GetString(aStr
);
1193 xMat
->PutString(aStr
, nC
, nR
);
1196 case CELLTYPE_VALUE
:
1198 double fVal
= static_cast<ScValueCell
*>(pCell
)->GetValue();
1199 xMat
->PutDouble(fVal
, nC
, nR
);
1202 case CELLTYPE_FORMULA
:
1204 ScFormulaCell
* pFCell
= static_cast<ScFormulaCell
*>(pCell
);
1205 USHORT nError
= pFCell
->GetErrCode();
1207 xMat
->PutDouble( CreateDoubleError( nError
), nC
, nR
);
1208 else if (pFCell
->IsValue())
1210 double fVal
= pFCell
->GetValue();
1211 xMat
->PutDouble(fVal
, nC
, nR
);
1216 pFCell
->GetString(aStr
);
1217 xMat
->PutString(aStr
, nC
, nR
);
1222 DBG_ERROR("attempted to convert an unknown cell type.");
1228 pArray
->AddOpCode(ocSep
);
1230 ScMatrix
* pMat2
= xMat
;
1231 ScMatrixToken
aToken(pMat2
);
1232 pArray
->AddToken(aToken
);
1234 itrCache
->mpRangeData
= xMat
;
1238 return pArray
.release();
1241 ScExternalRefManager::ScExternalRefManager(ScDocument
* pDoc
) :
1243 bInReferenceMarking(false)
1245 maSrcDocTimer
.SetTimeoutHdl( LINK(this, ScExternalRefManager
, TimeOutHdl
) );
1246 maSrcDocTimer
.SetTimeout(SRCDOC_SCAN_INTERVAL
);
1249 ScExternalRefManager::~ScExternalRefManager()
1254 String
ScExternalRefManager::getCacheTableName(sal_uInt16 nFileId
, size_t nTabIndex
) const
1256 return maRefCache
.getTableName(nFileId
, nTabIndex
);
1259 ScExternalRefCache::TableTypeRef
ScExternalRefManager::getCacheTable(sal_uInt16 nFileId
, size_t nTabIndex
) const
1261 return maRefCache
.getCacheTable(nFileId
, nTabIndex
);
1264 ScExternalRefCache::TableTypeRef
ScExternalRefManager::getCacheTable(sal_uInt16 nFileId
, const String
& rTabName
, bool bCreateNew
, size_t* pnIndex
)
1266 return maRefCache
.getCacheTable(nFileId
, rTabName
, bCreateNew
, pnIndex
);
1269 // ============================================================================
1271 ScExternalRefManager::RefCells::TabItem::TabItem(SCTAB nIndex
) :
1276 ScExternalRefManager::RefCells::TabItem::TabItem(const TabItem
& r
) :
1282 ScExternalRefManager::RefCells::RefCells()
1286 ScExternalRefManager::RefCells::~RefCells()
1290 list
<ScExternalRefManager::RefCells::TabItemRef
>::iterator
ScExternalRefManager::RefCells::getTabPos(SCTAB nTab
)
1292 list
<TabItemRef
>::iterator itr
= maTables
.begin(), itrEnd
= maTables
.end();
1293 for (; itr
!= itrEnd
; ++itr
)
1294 if ((*itr
)->mnIndex
>= nTab
)
1296 // Not found. return the end position.
1300 void ScExternalRefManager::RefCells::insertCell(const ScAddress
& rAddr
)
1302 SCTAB nTab
= rAddr
.Tab();
1303 SCCOL nCol
= rAddr
.Col();
1304 SCROW nRow
= rAddr
.Row();
1306 // Search by table index.
1307 list
<TabItemRef
>::iterator itrTab
= getTabPos(nTab
);
1309 if (itrTab
== maTables
.end())
1311 // All previous tables come before the specificed table.
1312 xTabRef
.reset(new TabItem(nTab
));
1313 maTables
.push_back(xTabRef
);
1315 else if ((*itrTab
)->mnIndex
> nTab
)
1317 // Insert at the current iterator position.
1318 xTabRef
.reset(new TabItem(nTab
));
1319 maTables
.insert(itrTab
, xTabRef
);
1321 else if ((*itrTab
)->mnIndex
== nTab
)
1326 ColSet
& rCols
= xTabRef
->maCols
;
1328 // Then by column index.
1329 ColSet::iterator itrCol
= rCols
.find(nCol
);
1330 if (itrCol
== rCols
.end())
1333 pair
<ColSet::iterator
, bool> r
= rCols
.insert(ColSet::value_type(nCol
, aRows
));
1335 // column insertion failed.
1339 RowSet
& rRows
= itrCol
->second
;
1341 // Finally, insert the row index.
1345 void ScExternalRefManager::RefCells::removeCell(const ScAddress
& rAddr
)
1347 SCTAB nTab
= rAddr
.Tab();
1348 SCCOL nCol
= rAddr
.Col();
1349 SCROW nRow
= rAddr
.Row();
1351 // Search by table index.
1352 list
<TabItemRef
>::iterator itrTab
= getTabPos(nTab
);
1353 if (itrTab
== maTables
.end() || (*itrTab
)->mnIndex
!= nTab
)
1357 ColSet
& rCols
= (*itrTab
)->maCols
;
1359 // Then by column index.
1360 ColSet::iterator itrCol
= rCols
.find(nCol
);
1361 if (itrCol
== rCols
.end())
1365 RowSet
& rRows
= itrCol
->second
;
1369 void ScExternalRefManager::RefCells::moveTable(SCTAB nOldTab
, SCTAB nNewTab
, bool bCopy
)
1371 if (nOldTab
== nNewTab
)
1372 // Nothing to do here.
1375 list
<TabItemRef
>::iterator itrOld
= getTabPos(nOldTab
);
1376 if (itrOld
== maTables
.end() || (*itrOld
)->mnIndex
!= nOldTab
)
1377 // No table to move or copy.
1380 list
<TabItemRef
>::iterator itrNew
= getTabPos(nNewTab
);
1383 // Simply make a duplicate of the original table, insert it at the
1384 // new tab position, and increment the table index for all tables
1385 // that come after that inserted table.
1387 TabItemRef
xNewTab(new TabItem(*(*itrOld
)));
1388 xNewTab
->mnIndex
= nNewTab
;
1389 maTables
.insert(itrNew
, xNewTab
);
1390 list
<TabItemRef
>::iterator itr
= itrNew
, itrEnd
= maTables
.end();
1391 if (itr
!= itrEnd
) // #i99807# check that itr is not at end already
1392 for (++itr
; itr
!= itrEnd
; ++itr
)
1393 (*itr
)->mnIndex
+= 1;
1397 if (itrOld
== itrNew
)
1399 // No need to move the table. Just update the table index.
1400 (*itrOld
)->mnIndex
= nNewTab
;
1404 if (nOldTab
< nNewTab
)
1406 // Iterate from the old tab position to the new tab position (not
1407 // inclusive of the old tab itself), and decrement their tab
1409 list
<TabItemRef
>::iterator itr
= itrOld
;
1410 for (++itr
; itr
!= itrNew
; ++itr
)
1411 (*itr
)->mnIndex
-= 1;
1413 // Insert a duplicate of the original table. This does not
1414 // invalidate the iterators.
1415 (*itrOld
)->mnIndex
= nNewTab
- 1;
1416 if (itrNew
== maTables
.end())
1417 maTables
.push_back(*itrOld
);
1419 maTables
.insert(itrNew
, *itrOld
);
1421 // Remove the original table.
1422 maTables
.erase(itrOld
);
1426 // nNewTab < nOldTab
1428 // Iterate from the new tab position to the one before the old tab
1429 // position, and increment their tab index by one.
1430 list
<TabItemRef
>::iterator itr
= itrNew
;
1431 for (++itr
; itr
!= itrOld
; ++itr
)
1432 (*itr
)->mnIndex
+= 1;
1434 (*itrOld
)->mnIndex
= nNewTab
;
1435 maTables
.insert(itrNew
, *itrOld
);
1437 // Remove the original table.
1438 maTables
.erase(itrOld
);
1443 void ScExternalRefManager::RefCells::insertTable(SCTAB nPos
)
1445 TabItemRef
xNewTab(new TabItem(nPos
));
1446 list
<TabItemRef
>::iterator itr
= getTabPos(nPos
);
1447 if (itr
== maTables
.end())
1448 maTables
.push_back(xNewTab
);
1450 maTables
.insert(itr
, xNewTab
);
1453 void ScExternalRefManager::RefCells::removeTable(SCTAB nPos
)
1455 list
<TabItemRef
>::iterator itr
= getTabPos(nPos
);
1456 if (itr
== maTables
.end())
1457 // nothing to remove.
1460 maTables
.erase(itr
);
1463 void ScExternalRefManager::RefCells::refreshAllCells(ScExternalRefManager
& rRefMgr
)
1465 // Get ALL the cell positions for re-compilation.
1466 for (list
<TabItemRef
>::iterator itrTab
= maTables
.begin(), itrTabEnd
= maTables
.end();
1467 itrTab
!= itrTabEnd
; ++itrTab
)
1469 SCTAB nTab
= (*itrTab
)->mnIndex
;
1470 ColSet
& rCols
= (*itrTab
)->maCols
;
1471 for (ColSet::iterator itrCol
= rCols
.begin(), itrColEnd
= rCols
.end();
1472 itrCol
!= itrColEnd
; ++itrCol
)
1474 SCCOL nCol
= itrCol
->first
;
1475 RowSet
& rRows
= itrCol
->second
;
1477 for (RowSet::iterator itrRow
= rRows
.begin(), itrRowEnd
= rRows
.end();
1478 itrRow
!= itrRowEnd
; ++itrRow
)
1480 SCROW nRow
= *itrRow
;
1481 ScAddress
aCell(nCol
, nRow
, nTab
);
1482 if (rRefMgr
.compileTokensByCell(aCell
))
1483 // This cell still contains an external refernce.
1484 aNewRows
.insert(nRow
);
1486 // Update the rows so that cells with no external references are
1487 // no longer tracked.
1488 rRows
.swap(aNewRows
);
1493 // ----------------------------------------------------------------------------
1495 ScExternalRefManager::LinkListener::LinkListener()
1499 ScExternalRefManager::LinkListener::~LinkListener()
1503 // ----------------------------------------------------------------------------
1505 void ScExternalRefManager::getAllCachedTableNames(sal_uInt16 nFileId
, vector
<String
>& rTabNames
) const
1507 maRefCache
.getAllTableNames(nFileId
, rTabNames
);
1510 SCsTAB
ScExternalRefManager::getCachedTabSpan( sal_uInt16 nFileId
, const String
& rStartTabName
, const String
& rEndTabName
) const
1512 return maRefCache
.getTabSpan( nFileId
, rStartTabName
, rEndTabName
);
1515 void ScExternalRefManager::getAllCachedNumberFormats(vector
<sal_uInt32
>& rNumFmts
) const
1517 maRefCache
.getAllNumberFormats(rNumFmts
);
1520 bool ScExternalRefManager::hasCacheTable(sal_uInt16 nFileId
, const String
& rTabName
) const
1522 return maRefCache
.hasCacheTable(nFileId
, rTabName
);
1525 size_t ScExternalRefManager::getCacheTableCount(sal_uInt16 nFileId
) const
1527 return maRefCache
.getCacheTableCount(nFileId
);
1530 sal_uInt16
ScExternalRefManager::getExternalFileCount() const
1532 return static_cast< sal_uInt16
>( maSrcFiles
.size() );
1535 bool ScExternalRefManager::markUsedByLinkListeners()
1537 bool bAllMarked
= false;
1538 for (LinkListenerMap::const_iterator itr
= maLinkListeners
.begin();
1539 itr
!= maLinkListeners
.end() && !bAllMarked
; ++itr
)
1541 if (!(*itr
).second
.empty())
1542 bAllMarked
= maRefCache
.setCacheDocReferenced( (*itr
).first
);
1543 /* TODO: LinkListeners should remember the table they're listening to.
1544 * As is, listening to one table will mark all tables of the document
1545 * being referenced. */
1550 bool ScExternalRefManager::setCacheDocReferenced( sal_uInt16 nFileId
)
1552 return maRefCache
.setCacheDocReferenced( nFileId
);
1555 bool ScExternalRefManager::setCacheTableReferenced( sal_uInt16 nFileId
, const String
& rTabName
, size_t nSheets
)
1557 return maRefCache
.setCacheTableReferenced( nFileId
, rTabName
, nSheets
, false);
1560 void ScExternalRefManager::setCacheTableReferencedPermanently( sal_uInt16 nFileId
, const String
& rTabName
, size_t nSheets
)
1562 if (isInReferenceMarking())
1563 // Do all maintenance work.
1564 maRefCache
.setCacheTableReferenced( nFileId
, rTabName
, nSheets
, true);
1566 // Set only the permanent flag.
1567 maRefCache
.setCacheTableReferencedPermanently( nFileId
, rTabName
, nSheets
);
1570 void ScExternalRefManager::setAllCacheTableReferencedStati( bool bReferenced
)
1572 bInReferenceMarking
= !bReferenced
;
1573 maRefCache
.setAllCacheTableReferencedStati( bReferenced
);
1576 void ScExternalRefManager::storeRangeNameTokens(sal_uInt16 nFileId
, const String
& rName
, const ScTokenArray
& rArray
)
1578 ScExternalRefCache::TokenArrayRef
pArray(rArray
.Clone());
1579 maRefCache
.setRangeNameTokens(nFileId
, rName
, pArray
);
1582 ScExternalRefCache::TokenRef
ScExternalRefManager::getSingleRefToken(
1583 sal_uInt16 nFileId
, const String
& rTabName
, const ScAddress
& rCell
,
1584 const ScAddress
* pCurPos
, SCTAB
* pTab
, ScExternalRefCache::CellFormat
* pFmt
)
1587 insertRefCell(nFileId
, *pCurPos
);
1589 maybeLinkExternalFile(nFileId
);
1595 pFmt
->mbIsSet
= false;
1597 bool bLoading
= mpDoc
->IsImportingXML();
1599 // Check if the given table name and the cell position is cached.
1600 // #i101304# When loading a file, the saved cache (hidden sheet)
1601 // is assumed to contain all data for the loaded formulas.
1602 // No cache entries are created from empty cells in the saved sheet,
1603 // so they have to be created here (bWriteEmpty parameter).
1604 // Otherwise, later interpretation of the loaded formulas would
1605 // load the source document even if the user didn't want to update.
1606 sal_uInt32 nFmtIndex
= 0;
1607 ScExternalRefCache::TokenRef pToken
= maRefCache
.getCellData(
1608 nFileId
, rTabName
, rCell
.Col(), rCell
.Row(), bLoading
, bLoading
, &nFmtIndex
);
1613 short nFmtType
= mpDoc
->GetFormatTable()->GetType(nFmtIndex
);
1614 if (nFmtType
!= NUMBERFORMAT_UNDEFINED
)
1616 pFmt
->mbIsSet
= true;
1617 pFmt
->mnIndex
= nFmtIndex
;
1618 pFmt
->mnType
= nFmtType
;
1624 // reference not cached. read from the source document.
1625 ScDocument
* pSrcDoc
= getSrcDocument(nFileId
);
1628 // Source document is not reachable. Try to get data from the cache
1629 // once again, but this time treat a non-cached cell as an empty cell
1630 // as long as the table itself is cached.
1631 pToken
= maRefCache
.getCellData(
1632 nFileId
, rTabName
, rCell
.Col(), rCell
.Row(), true, false, &nFmtIndex
);
1636 ScBaseCell
* pCell
= NULL
;
1638 if (!pSrcDoc
->GetTable(rTabName
, nTab
))
1640 // specified table name doesn't exist in the source document.
1641 return ScExternalRefCache::TokenRef();
1647 pSrcDoc
->GetCell(rCell
.Col(), rCell
.Row(), nTab
, pCell
);
1648 ScExternalRefCache::TokenRef
pTok(lcl_convertToToken(pCell
));
1650 pSrcDoc
->GetNumberFormat(rCell
.Col(), rCell
.Row(), nTab
, nFmtIndex
);
1651 nFmtIndex
= getMappedNumberFormat(nFileId
, nFmtIndex
, pSrcDoc
);
1654 short nFmtType
= mpDoc
->GetFormatTable()->GetType(nFmtIndex
);
1655 if (nFmtType
!= NUMBERFORMAT_UNDEFINED
)
1657 pFmt
->mbIsSet
= true;
1658 pFmt
->mnIndex
= nFmtIndex
;
1659 pFmt
->mnType
= nFmtType
;
1665 // Generate an error for unresolvable cells.
1666 pTok
.reset( new FormulaErrorToken( errNoValue
));
1669 // Now, insert the token into cache table.
1670 maRefCache
.setCellData(nFileId
, rTabName
, rCell
.Row(), rCell
.Col(), pTok
, nFmtIndex
);
1674 ScExternalRefCache::TokenArrayRef
ScExternalRefManager::getDoubleRefTokens(sal_uInt16 nFileId
, const String
& rTabName
, const ScRange
& rRange
, const ScAddress
* pCurPos
)
1677 insertRefCell(nFileId
, *pCurPos
);
1679 maybeLinkExternalFile(nFileId
);
1681 bool bLoading
= mpDoc
->IsImportingXML();
1683 // Check if the given table name and the cell position is cached.
1684 // #i101304# When loading, put empty cells into cache, see getSingleRefToken.
1685 ScExternalRefCache::TokenArrayRef p
= maRefCache
.getCellRangeData(nFileId
, rTabName
, rRange
, bLoading
, bLoading
);
1689 ScDocument
* pSrcDoc
= getSrcDocument(nFileId
);
1692 // Source document is not reachable. Try to get data from the cache
1693 // once again, but this time treat non-cached cells as empty cells as
1694 // long as the table itself is cached.
1695 return maRefCache
.getCellRangeData(nFileId
, rTabName
, rRange
, true, false);
1699 if (!pSrcDoc
->GetTable(rTabName
, nTab1
))
1700 // specified table name doesn't exist in the source document.
1701 return ScExternalRefCache::TokenArrayRef();
1703 ScRange
aRange(rRange
);
1704 SCTAB nTabSpan
= aRange
.aEnd
.Tab() - aRange
.aStart
.Tab();
1706 vector
<ScExternalRefCache::SingleRangeData
> aCacheData
;
1707 aCacheData
.reserve(nTabSpan
+1);
1708 aCacheData
.push_back(ScExternalRefCache::SingleRangeData());
1709 aCacheData
.back().maTableName
= ScGlobal::pCharClass
->upper(rTabName
);
1711 for (SCTAB i
= 1; i
< nTabSpan
+ 1; ++i
)
1714 if (!pSrcDoc
->GetName(nTab1
+ 1, aTabName
))
1715 // source document doesn't have any table by the specified name.
1718 aCacheData
.push_back(ScExternalRefCache::SingleRangeData());
1719 aCacheData
.back().maTableName
= ScGlobal::pCharClass
->upper(aTabName
);
1722 aRange
.aStart
.SetTab(nTab1
);
1723 aRange
.aEnd
.SetTab(nTab1
+ nTabSpan
);
1725 ScExternalRefCache::TokenArrayRef pArray
;
1726 pArray
.reset(lcl_convertToTokenArray(pSrcDoc
, aRange
, aCacheData
));
1729 // Cache these values.
1730 maRefCache
.setCellRangeData(nFileId
, rRange
, aCacheData
, pArray
);
1735 ScExternalRefCache::TokenArrayRef
ScExternalRefManager::getRangeNameTokens(sal_uInt16 nFileId
, const String
& rName
, const ScAddress
* pCurPos
)
1738 insertRefCell(nFileId
, *pCurPos
);
1740 maybeLinkExternalFile(nFileId
);
1742 ScExternalRefCache::TokenArrayRef pArray
= maRefCache
.getRangeNameTokens(nFileId
, rName
);
1746 ScDocument
* pSrcDoc
= getSrcDocument(nFileId
);
1748 return ScExternalRefCache::TokenArrayRef();
1750 ScRangeName
* pExtNames
= pSrcDoc
->GetRangeName();
1751 String aUpperName
= ScGlobal::pCharClass
->upper(rName
);
1753 bool bRes
= pExtNames
->SearchNameUpper(aUpperName
, n
);
1755 return ScExternalRefCache::TokenArrayRef();
1757 ScRangeData
* pRangeData
= (*pExtNames
)[n
];
1759 return ScExternalRefCache::TokenArrayRef();
1761 // Parse all tokens in this external range data, and replace each absolute
1762 // reference token with an external reference token, and cache them. Also
1763 // register the source document with the link manager if it's a new
1766 ScExternalRefCache::TokenArrayRef
pNew(new ScTokenArray
);
1768 ScTokenArray
* pCode
= pRangeData
->GetCode();
1769 for (FormulaToken
* pToken
= pCode
->First(); pToken
; pToken
= pCode
->Next())
1771 bool bTokenAdded
= false;
1772 switch (pToken
->GetType())
1776 const ScSingleRefData
& rRef
= static_cast<ScToken
*>(pToken
)->GetSingleRef();
1778 pSrcDoc
->GetName(rRef
.nTab
, aTabName
);
1779 ScExternalSingleRefToken
aNewToken(nFileId
, aTabName
, static_cast<ScToken
*>(pToken
)->GetSingleRef());
1780 pNew
->AddToken(aNewToken
);
1786 const ScSingleRefData
& rRef
= static_cast<ScToken
*>(pToken
)->GetSingleRef();
1788 pSrcDoc
->GetName(rRef
.nTab
, aTabName
);
1789 ScExternalDoubleRefToken
aNewToken(nFileId
, aTabName
, static_cast<ScToken
*>(pToken
)->GetDoubleRef());
1790 pNew
->AddToken(aNewToken
);
1799 pNew
->AddToken(*pToken
);
1802 // Make sure to pass the correctly-cased range name here.
1803 maRefCache
.setRangeNameTokens(nFileId
, pRangeData
->GetName(), pNew
);
1807 void ScExternalRefManager::refreshAllRefCells(sal_uInt16 nFileId
)
1809 RefCellMap::iterator itrFile
= maRefCells
.find(nFileId
);
1810 if (itrFile
== maRefCells
.end())
1813 RefCells
& rRefCells
= itrFile
->second
;
1814 rRefCells
.refreshAllCells(*this);
1816 ScViewData
* pViewData
= ScDocShell::GetViewData();
1820 ScTabViewShell
* pVShell
= pViewData
->GetViewShell();
1824 // Repainting the grid also repaints the texts, but is there a better way
1825 // to refresh texts?
1826 pVShell
->Invalidate(FID_REPAINT
);
1827 pVShell
->PaintGrid();
1830 void ScExternalRefManager::insertRefCell(sal_uInt16 nFileId
, const ScAddress
& rCell
)
1832 RefCellMap::iterator itr
= maRefCells
.find(nFileId
);
1833 if (itr
== maRefCells
.end())
1836 pair
<RefCellMap::iterator
, bool> r
= maRefCells
.insert(
1837 RefCellMap::value_type(nFileId
, aRefCells
));
1839 // insertion failed.
1844 itr
->second
.insertCell(rCell
);
1847 ScDocument
* ScExternalRefManager::getSrcDocument(sal_uInt16 nFileId
)
1849 if (!mpDoc
->IsExecuteLinkEnabled())
1852 DocShellMap::iterator itrEnd
= maDocShells
.end();
1853 DocShellMap::iterator itr
= maDocShells
.find(nFileId
);
1857 SfxObjectShell
* p
= itr
->second
.maShell
;
1858 itr
->second
.maLastAccess
= Time();
1859 return static_cast<ScDocShell
*>(p
)->GetDocument();
1862 const String
* pFile
= getExternalFileName(nFileId
);
1864 // no file name associated with this ID.
1869 aSrcDoc
.maShell
= loadSrcDocument(nFileId
, aFilter
);
1870 if (!aSrcDoc
.maShell
.Is())
1872 // source document could not be loaded.
1876 if (maDocShells
.empty())
1878 // If this is the first source document insertion, start up the timer.
1879 maSrcDocTimer
.Start();
1882 maDocShells
.insert(DocShellMap::value_type(nFileId
, aSrcDoc
));
1883 SfxObjectShell
* p
= aSrcDoc
.maShell
;
1884 ScDocument
* pSrcDoc
= static_cast<ScDocShell
*>(p
)->GetDocument();
1886 SCTAB nTabCount
= pSrcDoc
->GetTableCount();
1887 if (!maRefCache
.isDocInitialized(nFileId
) && nTabCount
)
1889 // Populate the cache with all table names in the source document.
1890 vector
<String
> aTabNames
;
1891 aTabNames
.reserve(nTabCount
);
1892 for (SCTAB i
= 0; i
< nTabCount
; ++i
)
1895 pSrcDoc
->GetName(i
, aName
);
1896 aTabNames
.push_back(aName
);
1898 maRefCache
.initializeDoc(nFileId
, aTabNames
);
1903 SfxObjectShellRef
ScExternalRefManager::loadSrcDocument(sal_uInt16 nFileId
, String
& rFilter
)
1905 const SrcFileData
* pFileData
= getExternalFileData(nFileId
);
1909 // Always load the document by using the path created from the relative
1910 // path. If the referenced document is not there, simply exit. The
1911 // original file name should be used only when the relative path is not
1913 String aFile
= pFileData
->maFileName
;
1914 maybeCreateRealFileName(nFileId
);
1915 if (pFileData
->maRealFileName
.Len())
1916 aFile
= pFileData
->maRealFileName
;
1918 if (!isFileLoadable(aFile
))
1922 ScDocumentLoader::GetFilterName(aFile
, rFilter
, aOptions
, true, false);
1923 const SfxFilter
* pFilter
= ScDocShell::Factory().GetFilterContainer()->GetFilter4FilterName(rFilter
);
1925 if (!pFileData
->maRelativeName
.Len())
1927 // Generate a relative file path.
1928 INetURLObject
aBaseURL(getOwnDocumentName());
1929 aBaseURL
.insertName(OUString::createFromAscii("content.xml"));
1931 String aStr
= URIHelper::simpleNormalizedMakeRelative(
1932 aBaseURL
.GetMainURL(INetURLObject::NO_DECODE
), aFile
);
1934 setRelativeFileName(nFileId
, aStr
);
1937 // Update the filter data now that we are loading it again.
1938 setFilterData(nFileId
, rFilter
, aOptions
);
1940 SfxItemSet
* pSet
= new SfxAllItemSet(SFX_APP()->GetPool());
1942 pSet
->Put(SfxStringItem(SID_FILE_FILTEROPTIONS
, aOptions
));
1944 auto_ptr
<SfxMedium
> pMedium(new SfxMedium(aFile
, STREAM_STD_READ
, false, pFilter
, pSet
));
1945 if (pMedium
->GetError() != ERRCODE_NONE
)
1948 pMedium
->UseInteractionHandler(false);
1950 ScDocShell
* pNewShell
= new ScDocShell(SFX_CREATE_MODE_INTERNAL
);
1951 SfxObjectShellRef aRef
= pNewShell
;
1953 // increment the recursive link count of the source document.
1954 ScExtDocOptions
* pExtOpt
= mpDoc
->GetExtDocOptions();
1955 sal_uInt32 nLinkCount
= pExtOpt
? pExtOpt
->GetDocSettings().mnLinkCnt
: 0;
1956 ScDocument
* pSrcDoc
= pNewShell
->GetDocument();
1957 ScExtDocOptions
* pExtOptNew
= pSrcDoc
->GetExtDocOptions();
1960 pExtOptNew
= new ScExtDocOptions
;
1961 pSrcDoc
->SetExtDocOptions(pExtOptNew
);
1963 pExtOptNew
->GetDocSettings().mnLinkCnt
= nLinkCount
+ 1;
1965 pNewShell
->DoLoad(pMedium
.release());
1969 bool ScExternalRefManager::isFileLoadable(const String
& rFile
) const
1974 if (isOwnDocument(rFile
))
1977 if (utl::UCBContentHelper::IsFolder(rFile
))
1980 return utl::UCBContentHelper::Exists(rFile
);
1983 void ScExternalRefManager::maybeLinkExternalFile(sal_uInt16 nFileId
)
1985 if (maLinkedDocs
.count(nFileId
))
1986 // file alerady linked, or the link has been broken.
1989 // Source document not linked yet. Link it now.
1990 const String
* pFileName
= getExternalFileName(nFileId
);
1994 String aFilter
, aOptions
;
1995 ScDocumentLoader::GetFilterName(*pFileName
, aFilter
, aOptions
, true, false);
1996 SvxLinkManager
* pLinkMgr
= mpDoc
->GetLinkManager();
1997 ScExternalRefLink
* pLink
= new ScExternalRefLink(mpDoc
, nFileId
, aFilter
);
1998 DBG_ASSERT(pFileName
, "ScExternalRefManager::insertExternalFileLink: file name pointer is NULL");
1999 pLinkMgr
->InsertFileLink(*pLink
, OBJECT_CLIENT_FILE
, *pFileName
, &aFilter
);
2001 pLink
->SetDoReferesh(false);
2003 pLink
->SetDoReferesh(true);
2005 maLinkedDocs
.insert(LinkedDocMap::value_type(nFileId
, true));
2008 void ScExternalRefManager::SrcFileData::maybeCreateRealFileName(const String
& rOwnDocName
)
2010 if (!maRelativeName
.Len())
2011 // No relative path given. Nothing to do.
2014 if (maRealFileName
.Len())
2015 // Real file name already created. Nothing to do.
2018 // Formulate the absolute file path from the relative path.
2019 const String
& rRelPath
= maRelativeName
;
2020 INetURLObject
aBaseURL(rOwnDocName
);
2021 aBaseURL
.insertName(OUString::createFromAscii("content.xml"));
2022 bool bWasAbs
= false;
2023 maRealFileName
= aBaseURL
.smartRel2Abs(rRelPath
, bWasAbs
).GetMainURL(INetURLObject::NO_DECODE
);
2026 void ScExternalRefManager::maybeCreateRealFileName(sal_uInt16 nFileId
)
2028 if (nFileId
>= maSrcFiles
.size())
2031 maSrcFiles
[nFileId
].maybeCreateRealFileName(getOwnDocumentName());
2034 bool ScExternalRefManager::compileTokensByCell(const ScAddress
& rCell
)
2037 mpDoc
->GetCell(rCell
.Col(), rCell
.Row(), rCell
.Tab(), pCell
);
2039 if (!pCell
|| pCell
->GetCellType() != CELLTYPE_FORMULA
)
2042 ScFormulaCell
* pFC
= static_cast<ScFormulaCell
*>(pCell
);
2044 // Check to make sure the cell really contains ocExternalRef.
2045 // External names, external cell and range references all have a
2046 // ocExternalRef token.
2047 const ScTokenArray
* pCode
= pFC
->GetCode();
2048 if (!pCode
->HasOpCode( ocExternalRef
))
2051 ScTokenArray
* pArray
= pFC
->GetCode();
2053 // Clear the error code, or a cell with error won't get re-compiled.
2054 pArray
->SetCodeError(0);
2056 pFC
->SetCompile(true);
2057 pFC
->CompileTokenArray();
2063 const String
& ScExternalRefManager::getOwnDocumentName() const
2065 SfxObjectShell
* pShell
= mpDoc
->GetDocumentShell();
2067 // This should not happen!
2068 return EMPTY_STRING
;
2070 SfxMedium
* pMed
= pShell
->GetMedium();
2072 return EMPTY_STRING
;
2074 return pMed
->GetName();
2077 bool ScExternalRefManager::isOwnDocument(const String
& rFile
) const
2079 return getOwnDocumentName().Equals(rFile
);
2082 void ScExternalRefManager::convertToAbsName(String
& rFile
) const
2084 SfxObjectShell
* pDocShell
= mpDoc
->GetDocumentShell();
2085 rFile
= ScGlobal::GetAbsDocName(rFile
, pDocShell
);
2088 sal_uInt16
ScExternalRefManager::getExternalFileId(const String
& rFile
)
2090 vector
<SrcFileData
>::const_iterator itrBeg
= maSrcFiles
.begin(), itrEnd
= maSrcFiles
.end();
2091 vector
<SrcFileData
>::const_iterator itr
= find_if(itrBeg
, itrEnd
, FindSrcFileByName(rFile
));
2094 size_t nId
= distance(itrBeg
, itr
);
2095 return static_cast<sal_uInt16
>(nId
);
2099 aData
.maFileName
= rFile
;
2100 maSrcFiles
.push_back(aData
);
2101 return static_cast<sal_uInt16
>(maSrcFiles
.size() - 1);
2104 const String
* ScExternalRefManager::getExternalFileName(sal_uInt16 nFileId
, bool bForceOriginal
)
2106 if (nFileId
>= maSrcFiles
.size())
2110 return &maSrcFiles
[nFileId
].maFileName
;
2112 maybeCreateRealFileName(nFileId
);
2114 if (maSrcFiles
[nFileId
].maRealFileName
.Len())
2115 return &maSrcFiles
[nFileId
].maRealFileName
;
2117 return &maSrcFiles
[nFileId
].maFileName
;
2120 bool ScExternalRefManager::hasExternalFile(sal_uInt16 nFileId
) const
2122 return nFileId
< maSrcFiles
.size();
2125 bool ScExternalRefManager::hasExternalFile(const String
& rFile
) const
2127 vector
<SrcFileData
>::const_iterator itrBeg
= maSrcFiles
.begin(), itrEnd
= maSrcFiles
.end();
2128 vector
<SrcFileData
>::const_iterator itr
= find_if(itrBeg
, itrEnd
, FindSrcFileByName(rFile
));
2129 return itr
!= itrEnd
;
2132 const ScExternalRefManager::SrcFileData
* ScExternalRefManager::getExternalFileData(sal_uInt16 nFileId
) const
2134 if (nFileId
>= maSrcFiles
.size())
2137 return &maSrcFiles
[nFileId
];
2140 const String
* ScExternalRefManager::getRealTableName(sal_uInt16 nFileId
, const String
& rTabName
) const
2142 return maRefCache
.getRealTableName(nFileId
, rTabName
);
2145 const String
* ScExternalRefManager::getRealRangeName(sal_uInt16 nFileId
, const String
& rRangeName
) const
2147 return maRefCache
.getRealRangeName(nFileId
, rRangeName
);
2150 template<typename MapContainer
>
2151 void lcl_removeByFileId(sal_uInt16 nFileId
, MapContainer
& rMap
)
2153 typename
MapContainer::iterator itr
= rMap
.find(nFileId
);
2154 if (itr
!= rMap
.end())
2158 void ScExternalRefManager::refreshNames(sal_uInt16 nFileId
)
2160 maRefCache
.clearCache(nFileId
);
2161 lcl_removeByFileId(nFileId
, maDocShells
);
2163 if (maDocShells
.empty())
2164 maSrcDocTimer
.Stop();
2166 // Update all cells containing names from this source document.
2167 refreshAllRefCells(nFileId
);
2169 notifyAllLinkListeners(nFileId
, LINK_MODIFIED
);
2172 void ScExternalRefManager::breakLink(sal_uInt16 nFileId
)
2174 lcl_removeByFileId(nFileId
, maDocShells
);
2176 if (maDocShells
.empty())
2177 maSrcDocTimer
.Stop();
2179 LinkedDocMap::iterator itr
= maLinkedDocs
.find(nFileId
);
2180 if (itr
!= maLinkedDocs
.end())
2181 itr
->second
= false;
2183 notifyAllLinkListeners(nFileId
, LINK_BROKEN
);
2186 void ScExternalRefManager::switchSrcFile(sal_uInt16 nFileId
, const String
& rNewFile
, const String
& rNewFilter
)
2188 maSrcFiles
[nFileId
].maFileName
= rNewFile
;
2189 maSrcFiles
[nFileId
].maRelativeName
.Erase();
2190 maSrcFiles
[nFileId
].maRealFileName
.Erase();
2191 if (!maSrcFiles
[nFileId
].maFilterName
.Equals(rNewFilter
))
2193 // Filter type has changed.
2194 maSrcFiles
[nFileId
].maFilterName
= rNewFilter
;
2195 maSrcFiles
[nFileId
].maFilterOptions
.Erase();
2197 refreshNames(nFileId
);
2200 void ScExternalRefManager::setRelativeFileName(sal_uInt16 nFileId
, const String
& rRelUrl
)
2202 if (nFileId
>= maSrcFiles
.size())
2204 maSrcFiles
[nFileId
].maRelativeName
= rRelUrl
;
2207 void ScExternalRefManager::setFilterData(sal_uInt16 nFileId
, const String
& rFilterName
, const String
& rOptions
)
2209 if (nFileId
>= maSrcFiles
.size())
2211 maSrcFiles
[nFileId
].maFilterName
= rFilterName
;
2212 maSrcFiles
[nFileId
].maFilterOptions
= rOptions
;
2215 void ScExternalRefManager::clear()
2217 DocShellMap::iterator itrEnd
= maDocShells
.end();
2218 for (DocShellMap::iterator itr
= maDocShells
.begin(); itr
!= itrEnd
; ++itr
)
2219 itr
->second
.maShell
->DoClose();
2221 maDocShells
.clear();
2222 maSrcDocTimer
.Stop();
2225 bool ScExternalRefManager::hasExternalData() const
2227 return !maSrcFiles
.empty();
2230 void ScExternalRefManager::resetSrcFileData(const String
& rBaseFileUrl
)
2232 for (vector
<SrcFileData
>::iterator itr
= maSrcFiles
.begin(), itrEnd
= maSrcFiles
.end();
2233 itr
!= itrEnd
; ++itr
)
2235 // Re-generate relative file name from the absolute file name.
2236 String aAbsName
= itr
->maRealFileName
;
2237 if (!aAbsName
.Len())
2238 aAbsName
= itr
->maFileName
;
2240 itr
->maRelativeName
= URIHelper::simpleNormalizedMakeRelative(
2241 rBaseFileUrl
, aAbsName
);
2245 void ScExternalRefManager::updateRefCell(const ScAddress
& rOldPos
, const ScAddress
& rNewPos
, bool bCopy
)
2247 for (RefCellMap::iterator itr
= maRefCells
.begin(), itrEnd
= maRefCells
.end(); itr
!= itrEnd
; ++itr
)
2250 itr
->second
.removeCell(rOldPos
);
2251 itr
->second
.insertCell(rNewPos
);
2255 void ScExternalRefManager::updateRefMoveTable(SCTAB nOldTab
, SCTAB nNewTab
, bool bCopy
)
2257 for (RefCellMap::iterator itr
= maRefCells
.begin(), itrEnd
= maRefCells
.end(); itr
!= itrEnd
; ++itr
)
2258 itr
->second
.moveTable(nOldTab
, nNewTab
, bCopy
);
2261 void ScExternalRefManager::updateRefInsertTable(SCTAB nPos
)
2263 for (RefCellMap::iterator itr
= maRefCells
.begin(), itrEnd
= maRefCells
.end(); itr
!= itrEnd
; ++itr
)
2264 itr
->second
.insertTable(nPos
);
2267 void ScExternalRefManager::updateRefDeleteTable(SCTAB nPos
)
2269 for (RefCellMap::iterator itr
= maRefCells
.begin(), itrEnd
= maRefCells
.end(); itr
!= itrEnd
; ++itr
)
2270 itr
->second
.removeTable(nPos
);
2273 void ScExternalRefManager::addLinkListener(sal_uInt16 nFileId
, LinkListener
* pListener
)
2275 LinkListenerMap::iterator itr
= maLinkListeners
.find(nFileId
);
2276 if (itr
== maLinkListeners
.end())
2278 pair
<LinkListenerMap::iterator
, bool> r
= maLinkListeners
.insert(
2279 LinkListenerMap::value_type(nFileId
, LinkListeners()));
2282 DBG_ERROR("insertion of new link listener list failed");
2289 LinkListeners
& rList
= itr
->second
;
2290 rList
.insert(pListener
);
2293 void ScExternalRefManager::removeLinkListener(sal_uInt16 nFileId
, LinkListener
* pListener
)
2295 LinkListenerMap::iterator itr
= maLinkListeners
.find(nFileId
);
2296 if (itr
== maLinkListeners
.end())
2297 // no listeners for a specified file.
2300 LinkListeners
& rList
= itr
->second
;
2301 rList
.erase(pListener
);
2304 // No more listeners for this file. Remove its entry.
2305 maLinkListeners
.erase(itr
);
2308 void ScExternalRefManager::removeLinkListener(LinkListener
* pListener
)
2310 LinkListenerMap::iterator itr
= maLinkListeners
.begin(), itrEnd
= maLinkListeners
.end();
2311 for (; itr
!= itrEnd
; ++itr
)
2312 itr
->second
.erase(pListener
);
2315 void ScExternalRefManager::notifyAllLinkListeners(sal_uInt16 nFileId
, LinkUpdateType eType
)
2317 LinkListenerMap::iterator itr
= maLinkListeners
.find(nFileId
);
2318 if (itr
== maLinkListeners
.end())
2319 // no listeners for a specified file.
2322 LinkListeners
& rList
= itr
->second
;
2323 for_each(rList
.begin(), rList
.end(), NotifyLinkListener(nFileId
, eType
));
2326 void ScExternalRefManager::purgeStaleSrcDocument(sal_Int32 nTimeOut
)
2328 DocShellMap aNewDocShells
;
2329 DocShellMap::iterator itr
= maDocShells
.begin(), itrEnd
= maDocShells
.end();
2330 for (; itr
!= itrEnd
; ++itr
)
2332 // in 100th of a second.
2333 sal_Int32 nSinceLastAccess
= (Time() - itr
->second
.maLastAccess
).GetTime();
2334 if (nSinceLastAccess
< nTimeOut
)
2335 aNewDocShells
.insert(*itr
);
2337 maDocShells
.swap(aNewDocShells
);
2339 if (maDocShells
.empty())
2340 maSrcDocTimer
.Stop();
2343 sal_uInt32
ScExternalRefManager::getMappedNumberFormat(sal_uInt16 nFileId
, sal_uInt32 nNumFmt
, ScDocument
* pSrcDoc
)
2345 NumFmtMap::iterator itr
= maNumFormatMap
.find(nFileId
);
2346 if (itr
== maNumFormatMap
.end())
2348 // Number formatter map is not initialized for this external document.
2349 pair
<NumFmtMap::iterator
, bool> r
= maNumFormatMap
.insert(
2350 NumFmtMap::value_type(nFileId
, SvNumberFormatterMergeMap()));
2353 // insertion failed.
2357 mpDoc
->GetFormatTable()->MergeFormatter( *pSrcDoc
->GetFormatTable());
2358 SvNumberFormatterMergeMap aMap
= mpDoc
->GetFormatTable()->ConvertMergeTableToMap();
2359 itr
->second
.swap(aMap
);
2361 const SvNumberFormatterMergeMap
& rMap
= itr
->second
;
2362 SvNumberFormatterMergeMap::const_iterator itrNumFmt
= rMap
.find(nNumFmt
);
2363 if (itrNumFmt
!= rMap
.end())
2364 // mapped value found.
2365 return itrNumFmt
->second
;
2370 IMPL_LINK(ScExternalRefManager
, TimeOutHdl
, AutoTimer
*, pTimer
)
2372 if (pTimer
== &maSrcDocTimer
)
2373 purgeStaleSrcDocument(SRCDOC_LIFE_SPAN
);