1*b3f79822SAndrew Rist /**************************************************************
2cdf0e10cSrcweir *
3*b3f79822SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one
4*b3f79822SAndrew Rist * or more contributor license agreements. See the NOTICE file
5*b3f79822SAndrew Rist * distributed with this work for additional information
6*b3f79822SAndrew Rist * regarding copyright ownership. The ASF licenses this file
7*b3f79822SAndrew Rist * to you under the Apache License, Version 2.0 (the
8*b3f79822SAndrew Rist * "License"); you may not use this file except in compliance
9*b3f79822SAndrew Rist * with the License. You may obtain a copy of the License at
10*b3f79822SAndrew Rist *
11*b3f79822SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0
12*b3f79822SAndrew Rist *
13*b3f79822SAndrew Rist * Unless required by applicable law or agreed to in writing,
14*b3f79822SAndrew Rist * software distributed under the License is distributed on an
15*b3f79822SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b3f79822SAndrew Rist * KIND, either express or implied. See the License for the
17*b3f79822SAndrew Rist * specific language governing permissions and limitations
18*b3f79822SAndrew Rist * under the License.
19*b3f79822SAndrew Rist *
20*b3f79822SAndrew Rist *************************************************************/
21*b3f79822SAndrew Rist
22*b3f79822SAndrew Rist
23cdf0e10cSrcweir
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_sc.hxx"
26cdf0e10cSrcweir
27cdf0e10cSrcweir
28cdf0e10cSrcweir
29cdf0e10cSrcweir // INCLUDE ---------------------------------------------------------------
30cdf0e10cSrcweir
31cdf0e10cSrcweir #include "externalrefmgr.hxx"
32cdf0e10cSrcweir #include "document.hxx"
33cdf0e10cSrcweir #include "token.hxx"
34cdf0e10cSrcweir #include "tokenarray.hxx"
35cdf0e10cSrcweir #include "address.hxx"
36cdf0e10cSrcweir #include "tablink.hxx"
37cdf0e10cSrcweir #include "docsh.hxx"
38cdf0e10cSrcweir #include "scextopt.hxx"
39cdf0e10cSrcweir #include "rangenam.hxx"
40cdf0e10cSrcweir #include "cell.hxx"
41cdf0e10cSrcweir #include "viewdata.hxx"
42cdf0e10cSrcweir #include "tabvwsh.hxx"
43cdf0e10cSrcweir #include "sc.hrc"
44cdf0e10cSrcweir
45cdf0e10cSrcweir #include "sfx2/app.hxx"
46cdf0e10cSrcweir #include "sfx2/docfilt.hxx"
47cdf0e10cSrcweir #include "sfx2/docfile.hxx"
48cdf0e10cSrcweir #include "sfx2/fcontnr.hxx"
49cdf0e10cSrcweir #include "sfx2/sfxsids.hrc"
50cdf0e10cSrcweir #include "sfx2/objsh.hxx"
51cdf0e10cSrcweir #include "svl/broadcast.hxx"
52cdf0e10cSrcweir #include "svl/smplhint.hxx"
53cdf0e10cSrcweir #include "svl/itemset.hxx"
54cdf0e10cSrcweir #include "svl/stritem.hxx"
55cdf0e10cSrcweir #include "svl/urihelper.hxx"
56cdf0e10cSrcweir #include "svl/zformat.hxx"
57cdf0e10cSrcweir #include "sfx2/linkmgr.hxx"
58cdf0e10cSrcweir #include "tools/urlobj.hxx"
59cdf0e10cSrcweir #include "unotools/ucbhelper.hxx"
60cdf0e10cSrcweir #include "unotools/localfilehelper.hxx"
61cdf0e10cSrcweir
62cdf0e10cSrcweir #include <memory>
63cdf0e10cSrcweir #include <algorithm>
64cdf0e10cSrcweir
65cdf0e10cSrcweir #include <boost/scoped_ptr.hpp>
66cdf0e10cSrcweir
67cdf0e10cSrcweir using ::std::auto_ptr;
68cdf0e10cSrcweir using ::com::sun::star::uno::Any;
69cdf0e10cSrcweir using ::rtl::OUString;
70cdf0e10cSrcweir using ::std::vector;
71cdf0e10cSrcweir using ::std::find;
72cdf0e10cSrcweir using ::std::find_if;
73cdf0e10cSrcweir using ::std::distance;
74cdf0e10cSrcweir using ::std::pair;
75cdf0e10cSrcweir using ::std::list;
76cdf0e10cSrcweir using ::std::unary_function;
77cdf0e10cSrcweir using namespace formula;
78cdf0e10cSrcweir
79cdf0e10cSrcweir #define SRCDOC_LIFE_SPAN 6000 // 1 minute (in 100th of a sec)
80cdf0e10cSrcweir #define SRCDOC_SCAN_INTERVAL 1000*5 // every 5 seconds (in msec)
81cdf0e10cSrcweir
82cdf0e10cSrcweir namespace {
83cdf0e10cSrcweir
84cdf0e10cSrcweir class TabNameSearchPredicate : public unary_function<bool, ScExternalRefCache::TableName>
85cdf0e10cSrcweir {
86cdf0e10cSrcweir public:
TabNameSearchPredicate(const String & rSearchName)87cdf0e10cSrcweir explicit TabNameSearchPredicate(const String& rSearchName) :
88cdf0e10cSrcweir maSearchName(ScGlobal::pCharClass->upper(rSearchName))
89cdf0e10cSrcweir {
90cdf0e10cSrcweir }
91cdf0e10cSrcweir
operator ()(const ScExternalRefCache::TableName & rTabNameSet) const92cdf0e10cSrcweir bool operator()(const ScExternalRefCache::TableName& rTabNameSet) const
93cdf0e10cSrcweir {
94cdf0e10cSrcweir // Ok, I'm doing case insensitive search here.
95cdf0e10cSrcweir return rTabNameSet.maUpperName.Equals(maSearchName);
96cdf0e10cSrcweir }
97cdf0e10cSrcweir
98cdf0e10cSrcweir private:
99cdf0e10cSrcweir String maSearchName;
100cdf0e10cSrcweir };
101cdf0e10cSrcweir
102cdf0e10cSrcweir class FindSrcFileByName : public unary_function<ScExternalRefManager::SrcFileData, bool>
103cdf0e10cSrcweir {
104cdf0e10cSrcweir public:
FindSrcFileByName(const String & rMatchName)105cdf0e10cSrcweir FindSrcFileByName(const String& rMatchName) :
106cdf0e10cSrcweir mrMatchName(rMatchName)
107cdf0e10cSrcweir {
108cdf0e10cSrcweir }
109cdf0e10cSrcweir
operator ()(const ScExternalRefManager::SrcFileData & rSrcData) const110cdf0e10cSrcweir bool operator()(const ScExternalRefManager::SrcFileData& rSrcData) const
111cdf0e10cSrcweir {
112cdf0e10cSrcweir return rSrcData.maFileName.Equals(mrMatchName);
113cdf0e10cSrcweir }
114cdf0e10cSrcweir
115cdf0e10cSrcweir private:
116cdf0e10cSrcweir const String& mrMatchName;
117cdf0e10cSrcweir };
118cdf0e10cSrcweir
119cdf0e10cSrcweir class NotifyLinkListener : public unary_function<ScExternalRefManager::LinkListener*, void>
120cdf0e10cSrcweir {
121cdf0e10cSrcweir public:
NotifyLinkListener(sal_uInt16 nFileId,ScExternalRefManager::LinkUpdateType eType)122cdf0e10cSrcweir NotifyLinkListener(sal_uInt16 nFileId, ScExternalRefManager::LinkUpdateType eType) :
123cdf0e10cSrcweir mnFileId(nFileId), meType(eType) {}
124cdf0e10cSrcweir
NotifyLinkListener(const NotifyLinkListener & r)125cdf0e10cSrcweir NotifyLinkListener(const NotifyLinkListener& r) :
126cdf0e10cSrcweir mnFileId(r.mnFileId), meType(r.meType) {}
127cdf0e10cSrcweir
operator ()(ScExternalRefManager::LinkListener * p) const128cdf0e10cSrcweir void operator() (ScExternalRefManager::LinkListener* p) const
129cdf0e10cSrcweir {
130cdf0e10cSrcweir p->notify(mnFileId, meType);
131cdf0e10cSrcweir }
132cdf0e10cSrcweir private:
133cdf0e10cSrcweir sal_uInt16 mnFileId;
134cdf0e10cSrcweir ScExternalRefManager::LinkUpdateType meType;
135cdf0e10cSrcweir };
136cdf0e10cSrcweir
137cdf0e10cSrcweir struct UpdateFormulaCell : public unary_function<ScFormulaCell*, void>
138cdf0e10cSrcweir {
operator ()__anonbb8c2bac0111::UpdateFormulaCell139cdf0e10cSrcweir void operator() (ScFormulaCell* pCell) const
140cdf0e10cSrcweir {
141cdf0e10cSrcweir // Check to make sure the cell really contains ocExternalRef.
142cdf0e10cSrcweir // External names, external cell and range references all have a
143cdf0e10cSrcweir // ocExternalRef token.
144cdf0e10cSrcweir const ScTokenArray* pCode = pCell->GetCode();
145cdf0e10cSrcweir if (!pCode->HasOpCode( ocExternalRef))
146cdf0e10cSrcweir return;
147cdf0e10cSrcweir
148cdf0e10cSrcweir ScTokenArray* pArray = pCell->GetCode();
149cdf0e10cSrcweir if (pArray)
150cdf0e10cSrcweir // Clear the error code, or a cell with error won't get re-compiled.
151cdf0e10cSrcweir pArray->SetCodeError(0);
152cdf0e10cSrcweir
153cdf0e10cSrcweir pCell->SetCompile(true);
154cdf0e10cSrcweir pCell->CompileTokenArray();
155cdf0e10cSrcweir pCell->SetDirty();
156cdf0e10cSrcweir }
157cdf0e10cSrcweir };
158cdf0e10cSrcweir
159cdf0e10cSrcweir class RemoveFormulaCell : public unary_function<pair<const sal_uInt16, ScExternalRefManager::RefCellSet>, void>
160cdf0e10cSrcweir {
161cdf0e10cSrcweir public:
RemoveFormulaCell(ScFormulaCell * p)162cdf0e10cSrcweir explicit RemoveFormulaCell(ScFormulaCell* p) : mpCell(p) {}
operator ()(pair<const sal_uInt16,ScExternalRefManager::RefCellSet> & r) const163cdf0e10cSrcweir void operator() (pair<const sal_uInt16, ScExternalRefManager::RefCellSet>& r) const
164cdf0e10cSrcweir {
165cdf0e10cSrcweir r.second.erase(mpCell);
166cdf0e10cSrcweir }
167cdf0e10cSrcweir private:
168cdf0e10cSrcweir ScFormulaCell* mpCell;
169cdf0e10cSrcweir };
170cdf0e10cSrcweir
171cdf0e10cSrcweir class ConvertFormulaToStatic : public unary_function<ScFormulaCell*, void>
172cdf0e10cSrcweir {
173cdf0e10cSrcweir public:
ConvertFormulaToStatic(ScDocument * pDoc)174cdf0e10cSrcweir explicit ConvertFormulaToStatic(ScDocument* pDoc) : mpDoc(pDoc) {}
operator ()(ScFormulaCell * pCell) const175cdf0e10cSrcweir void operator() (ScFormulaCell* pCell) const
176cdf0e10cSrcweir {
177cdf0e10cSrcweir ScAddress aPos = pCell->aPos;
178cdf0e10cSrcweir
179cdf0e10cSrcweir // We don't check for empty cells because empty external cells are
180cdf0e10cSrcweir // treated as having a value of 0.
181cdf0e10cSrcweir
182cdf0e10cSrcweir if (pCell->IsValue())
183cdf0e10cSrcweir {
184cdf0e10cSrcweir // Turn this into value cell.
185cdf0e10cSrcweir double fVal = pCell->GetValue();
186cdf0e10cSrcweir mpDoc->PutCell(aPos, new ScValueCell(fVal));
187cdf0e10cSrcweir }
188cdf0e10cSrcweir else
189cdf0e10cSrcweir {
190cdf0e10cSrcweir // string cell otherwise.
191cdf0e10cSrcweir String aVal;
192cdf0e10cSrcweir pCell->GetString(aVal);
193cdf0e10cSrcweir mpDoc->PutCell(aPos, new ScStringCell(aVal));
194cdf0e10cSrcweir }
195cdf0e10cSrcweir }
196cdf0e10cSrcweir private:
197cdf0e10cSrcweir ScDocument* mpDoc;
198cdf0e10cSrcweir };
199cdf0e10cSrcweir
200cdf0e10cSrcweir }
201cdf0e10cSrcweir
202cdf0e10cSrcweir // ============================================================================
203cdf0e10cSrcweir
Table()204cdf0e10cSrcweir ScExternalRefCache::Table::Table()
205cdf0e10cSrcweir : meReferenced( REFERENCED_MARKED )
206cdf0e10cSrcweir // Prevent accidental data loss due to lack of knowledge.
207cdf0e10cSrcweir {
208cdf0e10cSrcweir }
209cdf0e10cSrcweir
~Table()210cdf0e10cSrcweir ScExternalRefCache::Table::~Table()
211cdf0e10cSrcweir {
212cdf0e10cSrcweir }
213cdf0e10cSrcweir
setReferencedFlag(ScExternalRefCache::Table::ReferencedFlag eFlag)214cdf0e10cSrcweir void ScExternalRefCache::Table::setReferencedFlag( ScExternalRefCache::Table::ReferencedFlag eFlag )
215cdf0e10cSrcweir {
216cdf0e10cSrcweir meReferenced = eFlag;
217cdf0e10cSrcweir }
218cdf0e10cSrcweir
setReferenced(bool bReferenced)219cdf0e10cSrcweir void ScExternalRefCache::Table::setReferenced( bool bReferenced )
220cdf0e10cSrcweir {
221cdf0e10cSrcweir if (meReferenced != REFERENCED_PERMANENT)
222cdf0e10cSrcweir meReferenced = (bReferenced ? REFERENCED_MARKED : UNREFERENCED);
223cdf0e10cSrcweir }
224cdf0e10cSrcweir
getReferencedFlag() const225cdf0e10cSrcweir ScExternalRefCache::Table::ReferencedFlag ScExternalRefCache::Table::getReferencedFlag() const
226cdf0e10cSrcweir {
227cdf0e10cSrcweir return meReferenced;
228cdf0e10cSrcweir }
229cdf0e10cSrcweir
isReferenced() const230cdf0e10cSrcweir bool ScExternalRefCache::Table::isReferenced() const
231cdf0e10cSrcweir {
232cdf0e10cSrcweir return meReferenced != UNREFERENCED;
233cdf0e10cSrcweir }
234cdf0e10cSrcweir
setCell(SCCOL nCol,SCROW nRow,TokenRef pToken,sal_uInt32 nFmtIndex,bool bSetCacheRange)235cdf0e10cSrcweir void ScExternalRefCache::Table::setCell(SCCOL nCol, SCROW nRow, TokenRef pToken, sal_uInt32 nFmtIndex, bool bSetCacheRange)
236cdf0e10cSrcweir {
237cdf0e10cSrcweir using ::std::pair;
238cdf0e10cSrcweir RowsDataType::iterator itrRow = maRows.find(nRow);
239cdf0e10cSrcweir if (itrRow == maRows.end())
240cdf0e10cSrcweir {
241cdf0e10cSrcweir // This row does not exist yet.
242cdf0e10cSrcweir pair<RowsDataType::iterator, bool> res = maRows.insert(
243cdf0e10cSrcweir RowsDataType::value_type(nRow, RowDataType()));
244cdf0e10cSrcweir
245cdf0e10cSrcweir if (!res.second)
246cdf0e10cSrcweir return;
247cdf0e10cSrcweir
248cdf0e10cSrcweir itrRow = res.first;
249cdf0e10cSrcweir }
250cdf0e10cSrcweir
251cdf0e10cSrcweir // Insert this token into the specified column location. I don't need to
252cdf0e10cSrcweir // check for existing data. Just overwrite it.
253cdf0e10cSrcweir RowDataType& rRow = itrRow->second;
254cdf0e10cSrcweir ScExternalRefCache::Cell aCell;
255cdf0e10cSrcweir aCell.mxToken = pToken;
256cdf0e10cSrcweir aCell.mnFmtIndex = nFmtIndex;
257cdf0e10cSrcweir rRow.insert(RowDataType::value_type(nCol, aCell));
258cdf0e10cSrcweir if (bSetCacheRange)
259cdf0e10cSrcweir setCachedCell(nCol, nRow);
260cdf0e10cSrcweir }
261cdf0e10cSrcweir
getCell(SCCOL nCol,SCROW nRow,sal_uInt32 * pnFmtIndex) const262cdf0e10cSrcweir ScExternalRefCache::TokenRef ScExternalRefCache::Table::getCell(SCCOL nCol, SCROW nRow, sal_uInt32* pnFmtIndex) const
263cdf0e10cSrcweir {
264cdf0e10cSrcweir RowsDataType::const_iterator itrTable = maRows.find(nRow);
265cdf0e10cSrcweir if (itrTable == maRows.end())
266cdf0e10cSrcweir {
267cdf0e10cSrcweir // this table doesn't have the specified row.
268cdf0e10cSrcweir return getEmptyOrNullToken(nCol, nRow);
269cdf0e10cSrcweir }
270cdf0e10cSrcweir
271cdf0e10cSrcweir const RowDataType& rRowData = itrTable->second;
272cdf0e10cSrcweir RowDataType::const_iterator itrRow = rRowData.find(nCol);
273cdf0e10cSrcweir if (itrRow == rRowData.end())
274cdf0e10cSrcweir {
275cdf0e10cSrcweir // this row doesn't have the specified column.
276cdf0e10cSrcweir return getEmptyOrNullToken(nCol, nRow);
277cdf0e10cSrcweir }
278cdf0e10cSrcweir
279cdf0e10cSrcweir const Cell& rCell = itrRow->second;
280cdf0e10cSrcweir if (pnFmtIndex)
281cdf0e10cSrcweir *pnFmtIndex = rCell.mnFmtIndex;
282cdf0e10cSrcweir
283cdf0e10cSrcweir return rCell.mxToken;
284cdf0e10cSrcweir }
285cdf0e10cSrcweir
hasRow(SCROW nRow) const286cdf0e10cSrcweir bool ScExternalRefCache::Table::hasRow( SCROW nRow ) const
287cdf0e10cSrcweir {
288cdf0e10cSrcweir RowsDataType::const_iterator itrRow = maRows.find(nRow);
289cdf0e10cSrcweir return itrRow != maRows.end();
290cdf0e10cSrcweir }
291cdf0e10cSrcweir
getAllRows(vector<SCROW> & rRows,SCROW nLow,SCROW nHigh) const292cdf0e10cSrcweir void ScExternalRefCache::Table::getAllRows(vector<SCROW>& rRows, SCROW nLow, SCROW nHigh) const
293cdf0e10cSrcweir {
294cdf0e10cSrcweir vector<SCROW> aRows;
295cdf0e10cSrcweir aRows.reserve(maRows.size());
296cdf0e10cSrcweir RowsDataType::const_iterator itr = maRows.begin(), itrEnd = maRows.end();
297cdf0e10cSrcweir for (; itr != itrEnd; ++itr)
298cdf0e10cSrcweir if (nLow <= itr->first && itr->first <= nHigh)
299cdf0e10cSrcweir aRows.push_back(itr->first);
300cdf0e10cSrcweir
301cdf0e10cSrcweir // hash map is not ordered, so we need to explicitly sort it.
302cdf0e10cSrcweir ::std::sort(aRows.begin(), aRows.end());
303cdf0e10cSrcweir rRows.swap(aRows);
304cdf0e10cSrcweir }
305cdf0e10cSrcweir
getRowRange() const306cdf0e10cSrcweir ::std::pair< SCROW, SCROW > ScExternalRefCache::Table::getRowRange() const
307cdf0e10cSrcweir {
308cdf0e10cSrcweir ::std::pair< SCROW, SCROW > aRange( 0, 0 );
309cdf0e10cSrcweir if( !maRows.empty() )
310cdf0e10cSrcweir {
311cdf0e10cSrcweir // iterate over entire container (hash map is not sorted by key)
312cdf0e10cSrcweir RowsDataType::const_iterator itr = maRows.begin(), itrEnd = maRows.end();
313cdf0e10cSrcweir aRange.first = itr->first;
314cdf0e10cSrcweir aRange.second = itr->first + 1;
315cdf0e10cSrcweir while( ++itr != itrEnd )
316cdf0e10cSrcweir {
317cdf0e10cSrcweir if( itr->first < aRange.first )
318cdf0e10cSrcweir aRange.first = itr->first;
319cdf0e10cSrcweir else if( itr->first >= aRange.second )
320cdf0e10cSrcweir aRange.second = itr->first + 1;
321cdf0e10cSrcweir }
322cdf0e10cSrcweir }
323cdf0e10cSrcweir return aRange;
324cdf0e10cSrcweir }
325cdf0e10cSrcweir
getAllCols(SCROW nRow,vector<SCCOL> & rCols,SCCOL nLow,SCCOL nHigh) const326cdf0e10cSrcweir void ScExternalRefCache::Table::getAllCols(SCROW nRow, vector<SCCOL>& rCols, SCCOL nLow, SCCOL nHigh) const
327cdf0e10cSrcweir {
328cdf0e10cSrcweir RowsDataType::const_iterator itrRow = maRows.find(nRow);
329cdf0e10cSrcweir if (itrRow == maRows.end())
330cdf0e10cSrcweir // this table doesn't have the specified row.
331cdf0e10cSrcweir return;
332cdf0e10cSrcweir
333cdf0e10cSrcweir const RowDataType& rRowData = itrRow->second;
334cdf0e10cSrcweir vector<SCCOL> aCols;
335cdf0e10cSrcweir aCols.reserve(rRowData.size());
336cdf0e10cSrcweir RowDataType::const_iterator itrCol = rRowData.begin(), itrColEnd = rRowData.end();
337cdf0e10cSrcweir for (; itrCol != itrColEnd; ++itrCol)
338cdf0e10cSrcweir if (nLow <= itrCol->first && itrCol->first <= nHigh)
339cdf0e10cSrcweir aCols.push_back(itrCol->first);
340cdf0e10cSrcweir
341cdf0e10cSrcweir // hash map is not ordered, so we need to explicitly sort it.
342cdf0e10cSrcweir ::std::sort(aCols.begin(), aCols.end());
343cdf0e10cSrcweir rCols.swap(aCols);
344cdf0e10cSrcweir }
345cdf0e10cSrcweir
getColRange(SCROW nRow) const346cdf0e10cSrcweir ::std::pair< SCCOL, SCCOL > ScExternalRefCache::Table::getColRange( SCROW nRow ) const
347cdf0e10cSrcweir {
348cdf0e10cSrcweir ::std::pair< SCCOL, SCCOL > aRange( 0, 0 );
349cdf0e10cSrcweir
350cdf0e10cSrcweir RowsDataType::const_iterator itrRow = maRows.find( nRow );
351cdf0e10cSrcweir if (itrRow == maRows.end())
352cdf0e10cSrcweir // this table doesn't have the specified row.
353cdf0e10cSrcweir return aRange;
354cdf0e10cSrcweir
355cdf0e10cSrcweir const RowDataType& rRowData = itrRow->second;
356cdf0e10cSrcweir if( !rRowData.empty() )
357cdf0e10cSrcweir {
358cdf0e10cSrcweir // iterate over entire container (hash map is not sorted by key)
359cdf0e10cSrcweir RowDataType::const_iterator itr = rRowData.begin(), itrEnd = rRowData.end();
360cdf0e10cSrcweir aRange.first = itr->first;
361cdf0e10cSrcweir aRange.second = itr->first + 1;
362cdf0e10cSrcweir while( ++itr != itrEnd )
363cdf0e10cSrcweir {
364cdf0e10cSrcweir if( itr->first < aRange.first )
365cdf0e10cSrcweir aRange.first = itr->first;
366cdf0e10cSrcweir else if( itr->first >= aRange.second )
367cdf0e10cSrcweir aRange.second = itr->first + 1;
368cdf0e10cSrcweir }
369cdf0e10cSrcweir }
370cdf0e10cSrcweir return aRange;
371cdf0e10cSrcweir }
372cdf0e10cSrcweir
getAllNumberFormats(vector<sal_uInt32> & rNumFmts) const373cdf0e10cSrcweir void ScExternalRefCache::Table::getAllNumberFormats(vector<sal_uInt32>& rNumFmts) const
374cdf0e10cSrcweir {
375cdf0e10cSrcweir RowsDataType::const_iterator itrRow = maRows.begin(), itrRowEnd = maRows.end();
376cdf0e10cSrcweir for (; itrRow != itrRowEnd; ++itrRow)
377cdf0e10cSrcweir {
378cdf0e10cSrcweir const RowDataType& rRowData = itrRow->second;
379cdf0e10cSrcweir RowDataType::const_iterator itrCol = rRowData.begin(), itrColEnd = rRowData.end();
380cdf0e10cSrcweir for (; itrCol != itrColEnd; ++itrCol)
381cdf0e10cSrcweir {
382cdf0e10cSrcweir const Cell& rCell = itrCol->second;
383cdf0e10cSrcweir rNumFmts.push_back(rCell.mnFmtIndex);
384cdf0e10cSrcweir }
385cdf0e10cSrcweir }
386cdf0e10cSrcweir }
387cdf0e10cSrcweir
getCachedRanges() const388cdf0e10cSrcweir const ScRangeList& ScExternalRefCache::Table::getCachedRanges() const
389cdf0e10cSrcweir {
390cdf0e10cSrcweir return maCachedRanges;
391cdf0e10cSrcweir }
392cdf0e10cSrcweir
isRangeCached(SCCOL nCol1,SCROW nRow1,SCCOL nCol2,SCROW nRow2) const393cdf0e10cSrcweir bool ScExternalRefCache::Table::isRangeCached(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
394cdf0e10cSrcweir {
395cdf0e10cSrcweir return maCachedRanges.In(ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0));
396cdf0e10cSrcweir }
397cdf0e10cSrcweir
setCachedCell(SCCOL nCol,SCROW nRow)398cdf0e10cSrcweir void ScExternalRefCache::Table::setCachedCell(SCCOL nCol, SCROW nRow)
399cdf0e10cSrcweir {
400cdf0e10cSrcweir setCachedCellRange(nCol, nRow, nCol, nRow);
401cdf0e10cSrcweir }
402cdf0e10cSrcweir
setCachedCellRange(SCCOL nCol1,SCROW nRow1,SCCOL nCol2,SCROW nRow2)403cdf0e10cSrcweir void ScExternalRefCache::Table::setCachedCellRange(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
404cdf0e10cSrcweir {
405cdf0e10cSrcweir ScRange aRange(nCol1, nRow1, 0, nCol2, nRow2, 0);
406cdf0e10cSrcweir if (!maCachedRanges.Count())
407cdf0e10cSrcweir maCachedRanges.Append(aRange);
408cdf0e10cSrcweir else
409cdf0e10cSrcweir maCachedRanges.Join(aRange);
410cdf0e10cSrcweir
411cdf0e10cSrcweir String aStr;
412cdf0e10cSrcweir maCachedRanges.Format(aStr, SCA_VALID);
413cdf0e10cSrcweir }
414cdf0e10cSrcweir
setWholeTableCached()415cdf0e10cSrcweir void ScExternalRefCache::Table::setWholeTableCached()
416cdf0e10cSrcweir {
417cdf0e10cSrcweir setCachedCellRange(0, 0, MAXCOL, MAXROW);
418cdf0e10cSrcweir }
419cdf0e10cSrcweir
isInCachedRanges(SCCOL nCol,SCROW nRow) const420cdf0e10cSrcweir bool ScExternalRefCache::Table::isInCachedRanges(SCCOL nCol, SCROW nRow) const
421cdf0e10cSrcweir {
422cdf0e10cSrcweir return maCachedRanges.In(ScRange(nCol, nRow, 0, nCol, nRow, 0));
423cdf0e10cSrcweir }
424cdf0e10cSrcweir
getEmptyOrNullToken(SCCOL nCol,SCROW nRow) const425cdf0e10cSrcweir ScExternalRefCache::TokenRef ScExternalRefCache::Table::getEmptyOrNullToken(
426cdf0e10cSrcweir SCCOL nCol, SCROW nRow) const
427cdf0e10cSrcweir {
428cdf0e10cSrcweir if (isInCachedRanges(nCol, nRow))
429cdf0e10cSrcweir {
430cdf0e10cSrcweir TokenRef p(new ScEmptyCellToken(false, false));
431cdf0e10cSrcweir return p;
432cdf0e10cSrcweir }
433cdf0e10cSrcweir return TokenRef();
434cdf0e10cSrcweir }
435cdf0e10cSrcweir
436cdf0e10cSrcweir // ----------------------------------------------------------------------------
437cdf0e10cSrcweir
TableName(const String & rUpper,const String & rReal)438cdf0e10cSrcweir ScExternalRefCache::TableName::TableName(const String& rUpper, const String& rReal) :
439cdf0e10cSrcweir maUpperName(rUpper), maRealName(rReal)
440cdf0e10cSrcweir {
441cdf0e10cSrcweir }
442cdf0e10cSrcweir
443cdf0e10cSrcweir // ----------------------------------------------------------------------------
444cdf0e10cSrcweir
CellFormat()445cdf0e10cSrcweir ScExternalRefCache::CellFormat::CellFormat() :
446cdf0e10cSrcweir mbIsSet(false), mnType(NUMBERFORMAT_ALL), mnIndex(0)
447cdf0e10cSrcweir {
448cdf0e10cSrcweir }
449cdf0e10cSrcweir
450cdf0e10cSrcweir // ----------------------------------------------------------------------------
451cdf0e10cSrcweir
ScExternalRefCache()452cdf0e10cSrcweir ScExternalRefCache::ScExternalRefCache()
453cdf0e10cSrcweir {
454cdf0e10cSrcweir }
~ScExternalRefCache()455cdf0e10cSrcweir ScExternalRefCache::~ScExternalRefCache()
456cdf0e10cSrcweir {
457cdf0e10cSrcweir }
458cdf0e10cSrcweir
getRealTableName(sal_uInt16 nFileId,const String & rTabName) const459cdf0e10cSrcweir const String* ScExternalRefCache::getRealTableName(sal_uInt16 nFileId, const String& rTabName) const
460cdf0e10cSrcweir {
461cdf0e10cSrcweir DocDataType::const_iterator itrDoc = maDocs.find(nFileId);
462cdf0e10cSrcweir if (itrDoc == maDocs.end())
463cdf0e10cSrcweir {
464cdf0e10cSrcweir // specified document is not cached.
465cdf0e10cSrcweir return NULL;
466cdf0e10cSrcweir }
467cdf0e10cSrcweir
468cdf0e10cSrcweir const DocItem& rDoc = itrDoc->second;
469cdf0e10cSrcweir TableNameIndexMap::const_iterator itrTabId = rDoc.maTableNameIndex.find(
470cdf0e10cSrcweir ScGlobal::pCharClass->upper(rTabName));
471cdf0e10cSrcweir if (itrTabId == rDoc.maTableNameIndex.end())
472cdf0e10cSrcweir {
473cdf0e10cSrcweir // the specified table is not in cache.
474cdf0e10cSrcweir return NULL;
475cdf0e10cSrcweir }
476cdf0e10cSrcweir
477cdf0e10cSrcweir return &rDoc.maTableNames[itrTabId->second].maRealName;
478cdf0e10cSrcweir }
479cdf0e10cSrcweir
getRealRangeName(sal_uInt16 nFileId,const String & rRangeName) const480cdf0e10cSrcweir const String* ScExternalRefCache::getRealRangeName(sal_uInt16 nFileId, const String& rRangeName) const
481cdf0e10cSrcweir {
482cdf0e10cSrcweir DocDataType::const_iterator itrDoc = maDocs.find(nFileId);
483cdf0e10cSrcweir if (itrDoc == maDocs.end())
484cdf0e10cSrcweir {
485cdf0e10cSrcweir // specified document is not cached.
486cdf0e10cSrcweir return NULL;
487cdf0e10cSrcweir }
488cdf0e10cSrcweir
489cdf0e10cSrcweir const DocItem& rDoc = itrDoc->second;
490cdf0e10cSrcweir NamePairMap::const_iterator itr = rDoc.maRealRangeNameMap.find(
491cdf0e10cSrcweir ScGlobal::pCharClass->upper(rRangeName));
492cdf0e10cSrcweir if (itr == rDoc.maRealRangeNameMap.end())
493cdf0e10cSrcweir // range name not found.
494cdf0e10cSrcweir return NULL;
495cdf0e10cSrcweir
496cdf0e10cSrcweir return &itr->second;
497cdf0e10cSrcweir }
498cdf0e10cSrcweir
getCellData(sal_uInt16 nFileId,const String & rTabName,SCCOL nCol,SCROW nRow,sal_uInt32 * pnFmtIndex)499cdf0e10cSrcweir ScExternalRefCache::TokenRef ScExternalRefCache::getCellData(
500cdf0e10cSrcweir sal_uInt16 nFileId, const String& rTabName, SCCOL nCol, SCROW nRow, sal_uInt32* pnFmtIndex)
501cdf0e10cSrcweir {
502cdf0e10cSrcweir DocDataType::const_iterator itrDoc = maDocs.find(nFileId);
503cdf0e10cSrcweir if (itrDoc == maDocs.end())
504cdf0e10cSrcweir {
505cdf0e10cSrcweir // specified document is not cached.
506cdf0e10cSrcweir return TokenRef();
507cdf0e10cSrcweir }
508cdf0e10cSrcweir
509cdf0e10cSrcweir const DocItem& rDoc = itrDoc->second;
510cdf0e10cSrcweir TableNameIndexMap::const_iterator itrTabId = rDoc.maTableNameIndex.find(
511cdf0e10cSrcweir ScGlobal::pCharClass->upper(rTabName));
512cdf0e10cSrcweir if (itrTabId == rDoc.maTableNameIndex.end())
513cdf0e10cSrcweir {
514cdf0e10cSrcweir // the specified table is not in cache.
515cdf0e10cSrcweir return TokenRef();
516cdf0e10cSrcweir }
517cdf0e10cSrcweir
518cdf0e10cSrcweir const TableTypeRef& pTableData = rDoc.maTables[itrTabId->second];
519cdf0e10cSrcweir if (!pTableData.get())
520cdf0e10cSrcweir {
521cdf0e10cSrcweir // the table data is not instantiated yet.
522cdf0e10cSrcweir return TokenRef();
523cdf0e10cSrcweir }
524cdf0e10cSrcweir
525cdf0e10cSrcweir return pTableData->getCell(nCol, nRow, pnFmtIndex);
526cdf0e10cSrcweir }
527cdf0e10cSrcweir
getCellRangeData(sal_uInt16 nFileId,const String & rTabName,const ScRange & rRange)528cdf0e10cSrcweir ScExternalRefCache::TokenArrayRef ScExternalRefCache::getCellRangeData(
529cdf0e10cSrcweir sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange)
530cdf0e10cSrcweir {
531cdf0e10cSrcweir DocDataType::iterator itrDoc = maDocs.find(nFileId);
532cdf0e10cSrcweir if (itrDoc == maDocs.end())
533cdf0e10cSrcweir // specified document is not cached.
534cdf0e10cSrcweir return TokenArrayRef();
535cdf0e10cSrcweir
536cdf0e10cSrcweir DocItem& rDoc = itrDoc->second;
537cdf0e10cSrcweir
538cdf0e10cSrcweir TableNameIndexMap::iterator itrTabId = rDoc.maTableNameIndex.find(
539cdf0e10cSrcweir ScGlobal::pCharClass->upper(rTabName));
540cdf0e10cSrcweir if (itrTabId == rDoc.maTableNameIndex.end())
541cdf0e10cSrcweir // the specified table is not in cache.
542cdf0e10cSrcweir return TokenArrayRef();
543cdf0e10cSrcweir
544cdf0e10cSrcweir const ScAddress& s = rRange.aStart;
545cdf0e10cSrcweir const ScAddress& e = rRange.aEnd;
546cdf0e10cSrcweir
547cdf0e10cSrcweir SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
548cdf0e10cSrcweir SCCOL nCol1 = s.Col(), nCol2 = e.Col();
549cdf0e10cSrcweir SCROW nRow1 = s.Row(), nRow2 = e.Row();
550cdf0e10cSrcweir
551cdf0e10cSrcweir // Make sure I have all the tables cached.
552cdf0e10cSrcweir size_t nTabFirstId = itrTabId->second;
553cdf0e10cSrcweir size_t nTabLastId = nTabFirstId + nTab2 - nTab1;
554cdf0e10cSrcweir if (nTabLastId >= rDoc.maTables.size())
555cdf0e10cSrcweir // not all tables are cached.
556cdf0e10cSrcweir return TokenArrayRef();
557cdf0e10cSrcweir
558cdf0e10cSrcweir ScRange aCacheRange( nCol1, nRow1, static_cast<SCTAB>(nTabFirstId), nCol2, nRow2, static_cast<SCTAB>(nTabLastId));
559cdf0e10cSrcweir
560cdf0e10cSrcweir RangeArrayMap::const_iterator itrRange = rDoc.maRangeArrays.find( aCacheRange);
561cdf0e10cSrcweir if (itrRange != rDoc.maRangeArrays.end())
562cdf0e10cSrcweir // Cache hit!
563cdf0e10cSrcweir return itrRange->second;
564cdf0e10cSrcweir
565cdf0e10cSrcweir ::boost::scoped_ptr<ScRange> pNewRange;
566cdf0e10cSrcweir TokenArrayRef pArray;
567cdf0e10cSrcweir bool bFirstTab = true;
568cdf0e10cSrcweir for (size_t nTab = nTabFirstId; nTab <= nTabLastId; ++nTab)
569cdf0e10cSrcweir {
570cdf0e10cSrcweir TableTypeRef pTab = rDoc.maTables[nTab];
571cdf0e10cSrcweir if (!pTab.get())
572cdf0e10cSrcweir return TokenArrayRef();
573cdf0e10cSrcweir
574cdf0e10cSrcweir SCCOL nDataCol1 = nCol1, nDataCol2 = nCol2;
575cdf0e10cSrcweir SCROW nDataRow1 = nRow1, nDataRow2 = nRow2;
576cdf0e10cSrcweir
577cdf0e10cSrcweir if (!pTab->isRangeCached(nDataCol1, nDataRow1, nDataCol2, nDataRow2))
578cdf0e10cSrcweir {
579cdf0e10cSrcweir // specified range is not entirely within cached ranges.
580cdf0e10cSrcweir return TokenArrayRef();
581cdf0e10cSrcweir }
582cdf0e10cSrcweir
583cdf0e10cSrcweir ScMatrixRef xMat = new ScMatrix(
584cdf0e10cSrcweir static_cast<SCSIZE>(nDataCol2-nDataCol1+1), static_cast<SCSIZE>(nDataRow2-nDataRow1+1));
585cdf0e10cSrcweir
586cdf0e10cSrcweir #if 0
587cdf0e10cSrcweir // TODO: Switch to this code block once we have support for sparsely-filled
588cdf0e10cSrcweir // matrices in ScMatrix.
589cdf0e10cSrcweir
590cdf0e10cSrcweir // Only fill non-empty cells, for better performance.
591cdf0e10cSrcweir vector<SCROW> aRows;
592cdf0e10cSrcweir pTab->getAllRows(aRows, nDataRow1, nDataRow2);
593cdf0e10cSrcweir for (vector<SCROW>::const_iterator itr = aRows.begin(), itrEnd = aRows.end(); itr != itrEnd; ++itr)
594cdf0e10cSrcweir {
595cdf0e10cSrcweir SCROW nRow = *itr;
596cdf0e10cSrcweir vector<SCCOL> aCols;
597cdf0e10cSrcweir pTab->getAllCols(nRow, aCols, nDataCol1, nDataCol2);
598cdf0e10cSrcweir for (vector<SCCOL>::const_iterator itrCol = aCols.begin(), itrColEnd = aCols.end(); itrCol != itrColEnd; ++itrCol)
599cdf0e10cSrcweir {
600cdf0e10cSrcweir SCCOL nCol = *itrCol;
601cdf0e10cSrcweir TokenRef pToken = pTab->getCell(nCol, nRow);
602cdf0e10cSrcweir if (!pToken)
603cdf0e10cSrcweir // This should never happen!
604cdf0e10cSrcweir return TokenArrayRef();
605cdf0e10cSrcweir
606cdf0e10cSrcweir SCSIZE nC = nCol - nDataCol1, nR = nRow - nDataRow1;
607cdf0e10cSrcweir switch (pToken->GetType())
608cdf0e10cSrcweir {
609cdf0e10cSrcweir case svDouble:
610cdf0e10cSrcweir xMat->PutDouble(pToken->GetDouble(), nC, nR);
611cdf0e10cSrcweir break;
612cdf0e10cSrcweir case svString:
613cdf0e10cSrcweir xMat->PutString(pToken->GetString(), nC, nR);
614cdf0e10cSrcweir break;
615cdf0e10cSrcweir default:
616cdf0e10cSrcweir ;
617cdf0e10cSrcweir }
618cdf0e10cSrcweir }
619cdf0e10cSrcweir }
620cdf0e10cSrcweir #else
621cdf0e10cSrcweir vector<SCROW> aRows;
622cdf0e10cSrcweir pTab->getAllRows(aRows, nDataRow1, nDataRow2);
623cdf0e10cSrcweir if (aRows.empty())
624cdf0e10cSrcweir // Cache is empty.
625cdf0e10cSrcweir return TokenArrayRef();
626cdf0e10cSrcweir else
627cdf0e10cSrcweir // Trim the column below the last non-empty row.
628cdf0e10cSrcweir nDataRow2 = aRows.back();
629cdf0e10cSrcweir
630cdf0e10cSrcweir // Empty all matrix elements first, and fill only non-empty elements.
631cdf0e10cSrcweir for (SCROW nRow = nDataRow1; nRow <= nDataRow2; ++nRow)
632cdf0e10cSrcweir {
633cdf0e10cSrcweir for (SCCOL nCol = nDataCol1; nCol <= nDataCol2; ++nCol)
634cdf0e10cSrcweir {
635cdf0e10cSrcweir TokenRef pToken = pTab->getCell(nCol, nRow);
636cdf0e10cSrcweir SCSIZE nC = nCol - nCol1, nR = nRow - nRow1;
637cdf0e10cSrcweir if (!pToken)
638cdf0e10cSrcweir return TokenArrayRef();
639cdf0e10cSrcweir
640cdf0e10cSrcweir switch (pToken->GetType())
641cdf0e10cSrcweir {
642cdf0e10cSrcweir case svDouble:
643cdf0e10cSrcweir xMat->PutDouble(pToken->GetDouble(), nC, nR);
644cdf0e10cSrcweir break;
645cdf0e10cSrcweir case svString:
646cdf0e10cSrcweir xMat->PutString(pToken->GetString(), nC, nR);
647cdf0e10cSrcweir break;
648cdf0e10cSrcweir default:
649cdf0e10cSrcweir xMat->PutEmpty(nC, nR);
650cdf0e10cSrcweir }
651cdf0e10cSrcweir }
652cdf0e10cSrcweir }
653cdf0e10cSrcweir #endif
654cdf0e10cSrcweir
655cdf0e10cSrcweir if (!bFirstTab)
656cdf0e10cSrcweir pArray->AddOpCode(ocSep);
657cdf0e10cSrcweir
658cdf0e10cSrcweir ScMatrix* pMat2 = xMat;
659cdf0e10cSrcweir ScMatrixToken aToken(pMat2);
660cdf0e10cSrcweir if (!pArray)
661cdf0e10cSrcweir pArray.reset(new ScTokenArray);
662cdf0e10cSrcweir pArray->AddToken(aToken);
663cdf0e10cSrcweir
664cdf0e10cSrcweir bFirstTab = false;
665cdf0e10cSrcweir
666cdf0e10cSrcweir if (!pNewRange)
667cdf0e10cSrcweir pNewRange.reset(new ScRange(nDataCol1, nDataRow1, 0, nDataCol2, nDataRow2, 0));
668cdf0e10cSrcweir else
669cdf0e10cSrcweir pNewRange->ExtendTo(ScRange(nDataCol1, nDataRow1, 0, nDataCol2, nDataRow2, 0));
670cdf0e10cSrcweir }
671cdf0e10cSrcweir
672cdf0e10cSrcweir if (pNewRange)
673cdf0e10cSrcweir rDoc.maRangeArrays.insert( RangeArrayMap::value_type(*pNewRange, pArray));
674cdf0e10cSrcweir return pArray;
675cdf0e10cSrcweir }
676cdf0e10cSrcweir
getRangeNameTokens(sal_uInt16 nFileId,const String & rName)677cdf0e10cSrcweir ScExternalRefCache::TokenArrayRef ScExternalRefCache::getRangeNameTokens(sal_uInt16 nFileId, const String& rName)
678cdf0e10cSrcweir {
679cdf0e10cSrcweir DocItem* pDoc = getDocItem(nFileId);
680cdf0e10cSrcweir if (!pDoc)
681cdf0e10cSrcweir return TokenArrayRef();
682cdf0e10cSrcweir
683cdf0e10cSrcweir RangeNameMap& rMap = pDoc->maRangeNames;
684cdf0e10cSrcweir RangeNameMap::const_iterator itr = rMap.find(
685cdf0e10cSrcweir ScGlobal::pCharClass->upper(rName));
686cdf0e10cSrcweir if (itr == rMap.end())
687cdf0e10cSrcweir return TokenArrayRef();
688cdf0e10cSrcweir
689cdf0e10cSrcweir return itr->second;
690cdf0e10cSrcweir }
691cdf0e10cSrcweir
setRangeNameTokens(sal_uInt16 nFileId,const String & rName,TokenArrayRef pArray)692cdf0e10cSrcweir void ScExternalRefCache::setRangeNameTokens(sal_uInt16 nFileId, const String& rName, TokenArrayRef pArray)
693cdf0e10cSrcweir {
694cdf0e10cSrcweir DocItem* pDoc = getDocItem(nFileId);
695cdf0e10cSrcweir if (!pDoc)
696cdf0e10cSrcweir return;
697cdf0e10cSrcweir
698cdf0e10cSrcweir String aUpperName = ScGlobal::pCharClass->upper(rName);
699cdf0e10cSrcweir RangeNameMap& rMap = pDoc->maRangeNames;
700cdf0e10cSrcweir rMap.insert(RangeNameMap::value_type(aUpperName, pArray));
701cdf0e10cSrcweir pDoc->maRealRangeNameMap.insert(NamePairMap::value_type(aUpperName, rName));
702cdf0e10cSrcweir }
703cdf0e10cSrcweir
setCellData(sal_uInt16 nFileId,const String & rTabName,SCCOL nCol,SCROW nRow,TokenRef pToken,sal_uInt32 nFmtIndex)704cdf0e10cSrcweir void ScExternalRefCache::setCellData(sal_uInt16 nFileId, const String& rTabName, SCCOL nCol, SCROW nRow,
705cdf0e10cSrcweir TokenRef pToken, sal_uInt32 nFmtIndex)
706cdf0e10cSrcweir {
707cdf0e10cSrcweir if (!isDocInitialized(nFileId))
708cdf0e10cSrcweir return;
709cdf0e10cSrcweir
710cdf0e10cSrcweir using ::std::pair;
711cdf0e10cSrcweir DocItem* pDocItem = getDocItem(nFileId);
712cdf0e10cSrcweir if (!pDocItem)
713cdf0e10cSrcweir return;
714cdf0e10cSrcweir
715cdf0e10cSrcweir DocItem& rDoc = *pDocItem;
716cdf0e10cSrcweir
717cdf0e10cSrcweir // See if the table by this name already exists.
718cdf0e10cSrcweir TableNameIndexMap::iterator itrTabName = rDoc.maTableNameIndex.find(
719cdf0e10cSrcweir ScGlobal::pCharClass->upper(rTabName));
720cdf0e10cSrcweir if (itrTabName == rDoc.maTableNameIndex.end())
721cdf0e10cSrcweir // Table not found. Maybe the table name or the file id is wrong ???
722cdf0e10cSrcweir return;
723cdf0e10cSrcweir
724cdf0e10cSrcweir TableTypeRef& pTableData = rDoc.maTables[itrTabName->second];
725cdf0e10cSrcweir if (!pTableData.get())
726cdf0e10cSrcweir pTableData.reset(new Table);
727cdf0e10cSrcweir
728cdf0e10cSrcweir pTableData->setCell(nCol, nRow, pToken, nFmtIndex);
729cdf0e10cSrcweir pTableData->setCachedCell(nCol, nRow);
730cdf0e10cSrcweir }
731cdf0e10cSrcweir
setCellRangeData(sal_uInt16 nFileId,const ScRange & rRange,const vector<SingleRangeData> & rData,TokenArrayRef pArray)732cdf0e10cSrcweir void ScExternalRefCache::setCellRangeData(sal_uInt16 nFileId, const ScRange& rRange, const vector<SingleRangeData>& rData,
733cdf0e10cSrcweir TokenArrayRef pArray)
734cdf0e10cSrcweir {
735cdf0e10cSrcweir using ::std::pair;
736cdf0e10cSrcweir if (rData.empty() || !isDocInitialized(nFileId))
737cdf0e10cSrcweir // nothing to cache
738cdf0e10cSrcweir return;
739cdf0e10cSrcweir
740cdf0e10cSrcweir // First, get the document item for the given file ID.
741cdf0e10cSrcweir DocItem* pDocItem = getDocItem(nFileId);
742cdf0e10cSrcweir if (!pDocItem)
743cdf0e10cSrcweir return;
744cdf0e10cSrcweir
745cdf0e10cSrcweir DocItem& rDoc = *pDocItem;
746cdf0e10cSrcweir
747cdf0e10cSrcweir // Now, find the table position of the first table to cache.
748cdf0e10cSrcweir const String& rFirstTabName = rData.front().maTableName;
749cdf0e10cSrcweir TableNameIndexMap::iterator itrTabName = rDoc.maTableNameIndex.find(
750cdf0e10cSrcweir ScGlobal::pCharClass->upper(rFirstTabName));
751cdf0e10cSrcweir if (itrTabName == rDoc.maTableNameIndex.end())
752cdf0e10cSrcweir {
753cdf0e10cSrcweir // table index not found.
754cdf0e10cSrcweir return;
755cdf0e10cSrcweir }
756cdf0e10cSrcweir
757cdf0e10cSrcweir size_t nTabFirstId = itrTabName->second;
758cdf0e10cSrcweir SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
759cdf0e10cSrcweir SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
760cdf0e10cSrcweir vector<SingleRangeData>::const_iterator itrDataBeg = rData.begin(), itrDataEnd = rData.end();
761cdf0e10cSrcweir for (vector<SingleRangeData>::const_iterator itrData = itrDataBeg; itrData != itrDataEnd; ++itrData)
762cdf0e10cSrcweir {
763cdf0e10cSrcweir size_t i = nTabFirstId + ::std::distance(itrDataBeg, itrData);
764cdf0e10cSrcweir TableTypeRef& pTabData = rDoc.maTables[i];
765cdf0e10cSrcweir if (!pTabData.get())
766cdf0e10cSrcweir pTabData.reset(new Table);
767cdf0e10cSrcweir
768cdf0e10cSrcweir for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
769cdf0e10cSrcweir {
770cdf0e10cSrcweir for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
771cdf0e10cSrcweir {
772cdf0e10cSrcweir SCSIZE nC = nCol - nCol1, nR = nRow - nRow1;
773cdf0e10cSrcweir TokenRef pToken;
774cdf0e10cSrcweir const ScMatrixRef& pMat = itrData->mpRangeData;
775cdf0e10cSrcweir if (pMat->IsEmpty(nC, nR))
776cdf0e10cSrcweir // Don't cache empty cells.
777cdf0e10cSrcweir continue;
778cdf0e10cSrcweir
779cdf0e10cSrcweir if (pMat->IsValue(nC, nR))
780cdf0e10cSrcweir pToken.reset(new formula::FormulaDoubleToken(pMat->GetDouble(nC, nR)));
781cdf0e10cSrcweir else if (pMat->IsString(nC, nR))
782cdf0e10cSrcweir pToken.reset(new formula::FormulaStringToken(pMat->GetString(nC, nR)));
783cdf0e10cSrcweir
784cdf0e10cSrcweir if (pToken)
785cdf0e10cSrcweir // Don't mark this cell 'cached' here, for better performance.
786cdf0e10cSrcweir pTabData->setCell(nCol, nRow, pToken, 0, false);
787cdf0e10cSrcweir }
788cdf0e10cSrcweir }
789cdf0e10cSrcweir // Mark the whole range 'cached'.
790cdf0e10cSrcweir pTabData->setCachedCellRange(nCol1, nRow1, nCol2, nRow2);
791cdf0e10cSrcweir }
792cdf0e10cSrcweir
793cdf0e10cSrcweir size_t nTabLastId = nTabFirstId + rRange.aEnd.Tab() - rRange.aStart.Tab();
794cdf0e10cSrcweir ScRange aCacheRange( nCol1, nRow1, static_cast<SCTAB>(nTabFirstId), nCol2, nRow2, static_cast<SCTAB>(nTabLastId));
795cdf0e10cSrcweir
796cdf0e10cSrcweir rDoc.maRangeArrays.insert( RangeArrayMap::value_type( aCacheRange, pArray));
797cdf0e10cSrcweir }
798cdf0e10cSrcweir
isDocInitialized(sal_uInt16 nFileId)799cdf0e10cSrcweir bool ScExternalRefCache::isDocInitialized(sal_uInt16 nFileId)
800cdf0e10cSrcweir {
801cdf0e10cSrcweir DocItem* pDoc = getDocItem(nFileId);
802cdf0e10cSrcweir if (!pDoc)
803cdf0e10cSrcweir return false;
804cdf0e10cSrcweir
805cdf0e10cSrcweir return pDoc->mbInitFromSource;
806cdf0e10cSrcweir }
807cdf0e10cSrcweir
lcl_getTableDataIndex(const ScExternalRefCache::TableNameIndexMap & rMap,const String & rName,size_t & rIndex)808cdf0e10cSrcweir static bool lcl_getTableDataIndex(const ScExternalRefCache::TableNameIndexMap& rMap, const String& rName, size_t& rIndex)
809cdf0e10cSrcweir {
810cdf0e10cSrcweir ScExternalRefCache::TableNameIndexMap::const_iterator itr = rMap.find(rName);
811cdf0e10cSrcweir if (itr == rMap.end())
812cdf0e10cSrcweir return false;
813cdf0e10cSrcweir
814cdf0e10cSrcweir rIndex = itr->second;
815cdf0e10cSrcweir return true;
816cdf0e10cSrcweir }
817cdf0e10cSrcweir
initializeDoc(sal_uInt16 nFileId,const vector<String> & rTabNames)818cdf0e10cSrcweir void ScExternalRefCache::initializeDoc(sal_uInt16 nFileId, const vector<String>& rTabNames)
819cdf0e10cSrcweir {
820cdf0e10cSrcweir DocItem* pDoc = getDocItem(nFileId);
821cdf0e10cSrcweir if (!pDoc)
822cdf0e10cSrcweir return;
823cdf0e10cSrcweir
824cdf0e10cSrcweir size_t n = rTabNames.size();
825cdf0e10cSrcweir
826cdf0e10cSrcweir // table name list - the list must include all table names in the source
827cdf0e10cSrcweir // document and only to be populated when loading the source document, not
828cdf0e10cSrcweir // when loading cached data from, say, Excel XCT/CRN records.
829cdf0e10cSrcweir vector<TableName> aNewTabNames;
830cdf0e10cSrcweir aNewTabNames.reserve(n);
831cdf0e10cSrcweir for (vector<String>::const_iterator itr = rTabNames.begin(), itrEnd = rTabNames.end();
832cdf0e10cSrcweir itr != itrEnd; ++itr)
833cdf0e10cSrcweir {
834cdf0e10cSrcweir TableName aNameItem(ScGlobal::pCharClass->upper(*itr), *itr);
835cdf0e10cSrcweir aNewTabNames.push_back(aNameItem);
836cdf0e10cSrcweir }
837cdf0e10cSrcweir pDoc->maTableNames.swap(aNewTabNames);
838cdf0e10cSrcweir
839cdf0e10cSrcweir // data tables - preserve any existing data that may have been set during
840cdf0e10cSrcweir // file import.
841cdf0e10cSrcweir vector<TableTypeRef> aNewTables(n);
842cdf0e10cSrcweir for (size_t i = 0; i < n; ++i)
843cdf0e10cSrcweir {
844cdf0e10cSrcweir size_t nIndex;
845cdf0e10cSrcweir if (lcl_getTableDataIndex(pDoc->maTableNameIndex, pDoc->maTableNames[i].maUpperName, nIndex))
846cdf0e10cSrcweir {
847cdf0e10cSrcweir aNewTables[i] = pDoc->maTables[nIndex];
848cdf0e10cSrcweir }
849cdf0e10cSrcweir }
850cdf0e10cSrcweir pDoc->maTables.swap(aNewTables);
851cdf0e10cSrcweir
852cdf0e10cSrcweir // name index map
853cdf0e10cSrcweir TableNameIndexMap aNewNameIndex;
854cdf0e10cSrcweir for (size_t i = 0; i < n; ++i)
855cdf0e10cSrcweir aNewNameIndex.insert(TableNameIndexMap::value_type(pDoc->maTableNames[i].maUpperName, i));
856cdf0e10cSrcweir pDoc->maTableNameIndex.swap(aNewNameIndex);
857cdf0e10cSrcweir
858cdf0e10cSrcweir pDoc->mbInitFromSource = true;
859cdf0e10cSrcweir }
860cdf0e10cSrcweir
getTableName(sal_uInt16 nFileId,size_t nCacheId) const861cdf0e10cSrcweir String ScExternalRefCache::getTableName(sal_uInt16 nFileId, size_t nCacheId) const
862cdf0e10cSrcweir {
863cdf0e10cSrcweir if( DocItem* pDoc = getDocItem( nFileId ) )
864cdf0e10cSrcweir if( nCacheId < pDoc->maTableNames.size() )
865cdf0e10cSrcweir return pDoc->maTableNames[ nCacheId ].maRealName;
866cdf0e10cSrcweir return EMPTY_STRING;
867cdf0e10cSrcweir }
868cdf0e10cSrcweir
getAllTableNames(sal_uInt16 nFileId,vector<String> & rTabNames) const869cdf0e10cSrcweir void ScExternalRefCache::getAllTableNames(sal_uInt16 nFileId, vector<String>& rTabNames) const
870cdf0e10cSrcweir {
871cdf0e10cSrcweir rTabNames.clear();
872cdf0e10cSrcweir DocItem* pDoc = getDocItem(nFileId);
873cdf0e10cSrcweir if (!pDoc)
874cdf0e10cSrcweir return;
875cdf0e10cSrcweir
876cdf0e10cSrcweir size_t n = pDoc->maTableNames.size();
877cdf0e10cSrcweir rTabNames.reserve(n);
878cdf0e10cSrcweir for (vector<TableName>::const_iterator itr = pDoc->maTableNames.begin(), itrEnd = pDoc->maTableNames.end();
879cdf0e10cSrcweir itr != itrEnd; ++itr)
880cdf0e10cSrcweir rTabNames.push_back(itr->maRealName);
881cdf0e10cSrcweir }
882cdf0e10cSrcweir
getTabSpan(sal_uInt16 nFileId,const String & rStartTabName,const String & rEndTabName) const883cdf0e10cSrcweir SCsTAB ScExternalRefCache::getTabSpan( sal_uInt16 nFileId, const String& rStartTabName, const String& rEndTabName ) const
884cdf0e10cSrcweir {
885cdf0e10cSrcweir DocItem* pDoc = getDocItem(nFileId);
886cdf0e10cSrcweir if (!pDoc)
887cdf0e10cSrcweir return -1;
888cdf0e10cSrcweir
889cdf0e10cSrcweir vector<TableName>::const_iterator itrBeg = pDoc->maTableNames.begin();
890cdf0e10cSrcweir vector<TableName>::const_iterator itrEnd = pDoc->maTableNames.end();
891cdf0e10cSrcweir
892cdf0e10cSrcweir vector<TableName>::const_iterator itrStartTab = ::std::find_if( itrBeg, itrEnd,
893cdf0e10cSrcweir TabNameSearchPredicate( rStartTabName));
894cdf0e10cSrcweir if (itrStartTab == itrEnd)
895cdf0e10cSrcweir return -1;
896cdf0e10cSrcweir
897cdf0e10cSrcweir vector<TableName>::const_iterator itrEndTab = ::std::find_if( itrBeg, itrEnd,
898cdf0e10cSrcweir TabNameSearchPredicate( rEndTabName));
899cdf0e10cSrcweir if (itrEndTab == itrEnd)
900cdf0e10cSrcweir return 0;
901cdf0e10cSrcweir
902cdf0e10cSrcweir size_t nStartDist = ::std::distance( itrBeg, itrStartTab);
903cdf0e10cSrcweir size_t nEndDist = ::std::distance( itrBeg, itrEndTab);
904cdf0e10cSrcweir return nStartDist <= nEndDist ? static_cast<SCsTAB>(nEndDist - nStartDist + 1) : -static_cast<SCsTAB>(nStartDist - nEndDist + 1);
905cdf0e10cSrcweir }
906cdf0e10cSrcweir
getAllNumberFormats(vector<sal_uInt32> & rNumFmts) const907cdf0e10cSrcweir void ScExternalRefCache::getAllNumberFormats(vector<sal_uInt32>& rNumFmts) const
908cdf0e10cSrcweir {
909cdf0e10cSrcweir using ::std::sort;
910cdf0e10cSrcweir using ::std::unique;
911cdf0e10cSrcweir
912cdf0e10cSrcweir vector<sal_uInt32> aNumFmts;
913cdf0e10cSrcweir for (DocDataType::const_iterator itrDoc = maDocs.begin(), itrDocEnd = maDocs.end();
914cdf0e10cSrcweir itrDoc != itrDocEnd; ++itrDoc)
915cdf0e10cSrcweir {
916cdf0e10cSrcweir const vector<TableTypeRef>& rTables = itrDoc->second.maTables;
917cdf0e10cSrcweir for (vector<TableTypeRef>::const_iterator itrTab = rTables.begin(), itrTabEnd = rTables.end();
918cdf0e10cSrcweir itrTab != itrTabEnd; ++itrTab)
919cdf0e10cSrcweir {
920cdf0e10cSrcweir TableTypeRef pTab = *itrTab;
921cdf0e10cSrcweir if (!pTab)
922cdf0e10cSrcweir continue;
923cdf0e10cSrcweir
924cdf0e10cSrcweir pTab->getAllNumberFormats(aNumFmts);
925cdf0e10cSrcweir }
926cdf0e10cSrcweir }
927cdf0e10cSrcweir
928cdf0e10cSrcweir // remove duplicates.
929cdf0e10cSrcweir sort(aNumFmts.begin(), aNumFmts.end());
930cdf0e10cSrcweir aNumFmts.erase(unique(aNumFmts.begin(), aNumFmts.end()), aNumFmts.end());
931cdf0e10cSrcweir rNumFmts.swap(aNumFmts);
932cdf0e10cSrcweir }
933cdf0e10cSrcweir
setCacheDocReferenced(sal_uInt16 nFileId)934cdf0e10cSrcweir bool ScExternalRefCache::setCacheDocReferenced( sal_uInt16 nFileId )
935cdf0e10cSrcweir {
936cdf0e10cSrcweir DocItem* pDocItem = getDocItem(nFileId);
937cdf0e10cSrcweir if (!pDocItem)
938cdf0e10cSrcweir return areAllCacheTablesReferenced();
939cdf0e10cSrcweir
940cdf0e10cSrcweir for (::std::vector<TableTypeRef>::iterator itrTab = pDocItem->maTables.begin();
941cdf0e10cSrcweir itrTab != pDocItem->maTables.end(); ++itrTab)
942cdf0e10cSrcweir {
943cdf0e10cSrcweir if ((*itrTab).get())
944cdf0e10cSrcweir (*itrTab)->setReferenced( true);
945cdf0e10cSrcweir }
946cdf0e10cSrcweir addCacheDocToReferenced( nFileId);
947cdf0e10cSrcweir return areAllCacheTablesReferenced();
948cdf0e10cSrcweir }
949cdf0e10cSrcweir
setCacheTableReferenced(sal_uInt16 nFileId,const String & rTabName,size_t nSheets,bool bPermanent)950cdf0e10cSrcweir bool ScExternalRefCache::setCacheTableReferenced( sal_uInt16 nFileId, const String& rTabName, size_t nSheets, bool bPermanent )
951cdf0e10cSrcweir {
952cdf0e10cSrcweir DocItem* pDoc = getDocItem(nFileId);
953cdf0e10cSrcweir if (pDoc)
954cdf0e10cSrcweir {
955cdf0e10cSrcweir size_t nIndex = 0;
956cdf0e10cSrcweir String aTabNameUpper = ScGlobal::pCharClass->upper( rTabName);
957cdf0e10cSrcweir if (lcl_getTableDataIndex( pDoc->maTableNameIndex, aTabNameUpper, nIndex))
958cdf0e10cSrcweir {
959cdf0e10cSrcweir size_t nStop = ::std::min( nIndex + nSheets, pDoc->maTables.size());
960cdf0e10cSrcweir for (size_t i = nIndex; i < nStop; ++i)
961cdf0e10cSrcweir {
962cdf0e10cSrcweir TableTypeRef pTab = pDoc->maTables[i];
963cdf0e10cSrcweir if (pTab.get())
964cdf0e10cSrcweir {
965cdf0e10cSrcweir Table::ReferencedFlag eNewFlag = (bPermanent ?
966cdf0e10cSrcweir Table::REFERENCED_PERMANENT :
967cdf0e10cSrcweir Table::REFERENCED_MARKED);
968cdf0e10cSrcweir Table::ReferencedFlag eOldFlag = pTab->getReferencedFlag();
969cdf0e10cSrcweir if (eOldFlag != Table::REFERENCED_PERMANENT && eNewFlag != eOldFlag)
970cdf0e10cSrcweir {
971cdf0e10cSrcweir pTab->setReferencedFlag( eNewFlag);
972cdf0e10cSrcweir addCacheTableToReferenced( nFileId, i);
973cdf0e10cSrcweir }
974cdf0e10cSrcweir }
975cdf0e10cSrcweir }
976cdf0e10cSrcweir }
977cdf0e10cSrcweir }
978cdf0e10cSrcweir return areAllCacheTablesReferenced();
979cdf0e10cSrcweir }
980cdf0e10cSrcweir
setCacheTableReferencedPermanently(sal_uInt16 nFileId,const String & rTabName,size_t nSheets)981cdf0e10cSrcweir void ScExternalRefCache::setCacheTableReferencedPermanently( sal_uInt16 nFileId, const String& rTabName, size_t nSheets )
982cdf0e10cSrcweir {
983cdf0e10cSrcweir DocItem* pDoc = getDocItem(nFileId);
984cdf0e10cSrcweir if (pDoc)
985cdf0e10cSrcweir {
986cdf0e10cSrcweir size_t nIndex = 0;
987cdf0e10cSrcweir String aTabNameUpper = ScGlobal::pCharClass->upper( rTabName);
988cdf0e10cSrcweir if (lcl_getTableDataIndex( pDoc->maTableNameIndex, aTabNameUpper, nIndex))
989cdf0e10cSrcweir {
990cdf0e10cSrcweir size_t nStop = ::std::min( nIndex + nSheets, pDoc->maTables.size());
991cdf0e10cSrcweir for (size_t i = nIndex; i < nStop; ++i)
992cdf0e10cSrcweir {
993cdf0e10cSrcweir TableTypeRef pTab = pDoc->maTables[i];
994cdf0e10cSrcweir if (pTab.get())
995cdf0e10cSrcweir pTab->setReferencedFlag( Table::REFERENCED_PERMANENT);
996cdf0e10cSrcweir }
997cdf0e10cSrcweir }
998cdf0e10cSrcweir }
999cdf0e10cSrcweir }
1000cdf0e10cSrcweir
setAllCacheTableReferencedStati(bool bReferenced)1001cdf0e10cSrcweir void ScExternalRefCache::setAllCacheTableReferencedStati( bool bReferenced )
1002cdf0e10cSrcweir {
1003cdf0e10cSrcweir if (bReferenced)
1004cdf0e10cSrcweir {
1005cdf0e10cSrcweir maReferenced.reset(0);
1006cdf0e10cSrcweir for (DocDataType::iterator itrDoc = maDocs.begin(); itrDoc != maDocs.end(); ++itrDoc)
1007cdf0e10cSrcweir {
1008cdf0e10cSrcweir ScExternalRefCache::DocItem& rDocItem = (*itrDoc).second;
1009cdf0e10cSrcweir for (::std::vector<TableTypeRef>::iterator itrTab = rDocItem.maTables.begin();
1010cdf0e10cSrcweir itrTab != rDocItem.maTables.end(); ++itrTab)
1011cdf0e10cSrcweir {
1012cdf0e10cSrcweir if ((*itrTab).get())
1013cdf0e10cSrcweir (*itrTab)->setReferenced( true);
1014cdf0e10cSrcweir }
1015cdf0e10cSrcweir }
1016cdf0e10cSrcweir }
1017cdf0e10cSrcweir else
1018cdf0e10cSrcweir {
1019cdf0e10cSrcweir size_t nDocs = 0;
1020cdf0e10cSrcweir for (DocDataType::const_iterator itrDoc = maDocs.begin(); itrDoc != maDocs.end(); ++itrDoc)
1021cdf0e10cSrcweir {
1022cdf0e10cSrcweir if (nDocs <= (*itrDoc).first)
1023cdf0e10cSrcweir nDocs = (*itrDoc).first + 1;
1024cdf0e10cSrcweir }
1025cdf0e10cSrcweir maReferenced.reset( nDocs);
1026cdf0e10cSrcweir
1027cdf0e10cSrcweir for (DocDataType::iterator itrDoc = maDocs.begin(); itrDoc != maDocs.end(); ++itrDoc)
1028cdf0e10cSrcweir {
1029cdf0e10cSrcweir ScExternalRefCache::DocItem& rDocItem = (*itrDoc).second;
1030cdf0e10cSrcweir sal_uInt16 nFileId = (*itrDoc).first;
1031cdf0e10cSrcweir size_t nTables = rDocItem.maTables.size();
1032cdf0e10cSrcweir ReferencedStatus::DocReferenced & rDocReferenced = maReferenced.maDocs[nFileId];
1033cdf0e10cSrcweir // All referenced => non-existing tables evaluate as completed.
1034cdf0e10cSrcweir rDocReferenced.maTables.resize( nTables, true);
1035cdf0e10cSrcweir for (size_t i=0; i < nTables; ++i)
1036cdf0e10cSrcweir {
1037cdf0e10cSrcweir TableTypeRef & xTab = rDocItem.maTables[i];
1038cdf0e10cSrcweir if (xTab.get())
1039cdf0e10cSrcweir {
1040cdf0e10cSrcweir if (xTab->getReferencedFlag() == Table::REFERENCED_PERMANENT)
1041cdf0e10cSrcweir addCacheTableToReferenced( nFileId, i);
1042cdf0e10cSrcweir else
1043cdf0e10cSrcweir {
1044cdf0e10cSrcweir xTab->setReferencedFlag( Table::UNREFERENCED);
1045cdf0e10cSrcweir rDocReferenced.maTables[i] = false;
1046cdf0e10cSrcweir rDocReferenced.mbAllTablesReferenced = false;
1047cdf0e10cSrcweir // An addCacheTableToReferenced() actually may have
1048cdf0e10cSrcweir // resulted in mbAllReferenced been set. Clear it.
1049cdf0e10cSrcweir maReferenced.mbAllReferenced = false;
1050cdf0e10cSrcweir }
1051cdf0e10cSrcweir }
1052cdf0e10cSrcweir }
1053cdf0e10cSrcweir }
1054cdf0e10cSrcweir }
1055cdf0e10cSrcweir }
1056cdf0e10cSrcweir
addCacheTableToReferenced(sal_uInt16 nFileId,size_t nIndex)1057cdf0e10cSrcweir void ScExternalRefCache::addCacheTableToReferenced( sal_uInt16 nFileId, size_t nIndex )
1058cdf0e10cSrcweir {
1059cdf0e10cSrcweir if (nFileId >= maReferenced.maDocs.size())
1060cdf0e10cSrcweir return;
1061cdf0e10cSrcweir
1062cdf0e10cSrcweir ::std::vector<bool> & rTables = maReferenced.maDocs[nFileId].maTables;
1063cdf0e10cSrcweir size_t nTables = rTables.size();
1064cdf0e10cSrcweir if (nIndex >= nTables)
1065cdf0e10cSrcweir return;
1066cdf0e10cSrcweir
1067cdf0e10cSrcweir if (!rTables[nIndex])
1068cdf0e10cSrcweir {
1069cdf0e10cSrcweir rTables[nIndex] = true;
1070cdf0e10cSrcweir size_t i = 0;
1071cdf0e10cSrcweir while (i < nTables && rTables[i])
1072cdf0e10cSrcweir ++i;
1073cdf0e10cSrcweir if (i == nTables)
1074cdf0e10cSrcweir {
1075cdf0e10cSrcweir maReferenced.maDocs[nFileId].mbAllTablesReferenced = true;
1076cdf0e10cSrcweir maReferenced.checkAllDocs();
1077cdf0e10cSrcweir }
1078cdf0e10cSrcweir }
1079cdf0e10cSrcweir }
1080cdf0e10cSrcweir
addCacheDocToReferenced(sal_uInt16 nFileId)1081cdf0e10cSrcweir void ScExternalRefCache::addCacheDocToReferenced( sal_uInt16 nFileId )
1082cdf0e10cSrcweir {
1083cdf0e10cSrcweir if (nFileId >= maReferenced.maDocs.size())
1084cdf0e10cSrcweir return;
1085cdf0e10cSrcweir
1086cdf0e10cSrcweir if (!maReferenced.maDocs[nFileId].mbAllTablesReferenced)
1087cdf0e10cSrcweir {
1088cdf0e10cSrcweir ::std::vector<bool> & rTables = maReferenced.maDocs[nFileId].maTables;
1089cdf0e10cSrcweir size_t nSize = rTables.size();
1090cdf0e10cSrcweir for (size_t i=0; i < nSize; ++i)
1091cdf0e10cSrcweir rTables[i] = true;
1092cdf0e10cSrcweir maReferenced.maDocs[nFileId].mbAllTablesReferenced = true;
1093cdf0e10cSrcweir maReferenced.checkAllDocs();
1094cdf0e10cSrcweir }
1095cdf0e10cSrcweir }
1096cdf0e10cSrcweir
areAllCacheTablesReferenced() const1097cdf0e10cSrcweir bool ScExternalRefCache::areAllCacheTablesReferenced() const
1098cdf0e10cSrcweir {
1099cdf0e10cSrcweir return maReferenced.mbAllReferenced;
1100cdf0e10cSrcweir }
1101cdf0e10cSrcweir
ReferencedStatus()1102cdf0e10cSrcweir ScExternalRefCache::ReferencedStatus::ReferencedStatus() :
1103cdf0e10cSrcweir mbAllReferenced(false)
1104cdf0e10cSrcweir {
1105cdf0e10cSrcweir reset(0);
1106cdf0e10cSrcweir }
1107cdf0e10cSrcweir
ReferencedStatus(size_t nDocs)1108cdf0e10cSrcweir ScExternalRefCache::ReferencedStatus::ReferencedStatus( size_t nDocs ) :
1109cdf0e10cSrcweir mbAllReferenced(false)
1110cdf0e10cSrcweir {
1111cdf0e10cSrcweir reset( nDocs);
1112cdf0e10cSrcweir }
1113cdf0e10cSrcweir
reset(size_t nDocs)1114cdf0e10cSrcweir void ScExternalRefCache::ReferencedStatus::reset( size_t nDocs )
1115cdf0e10cSrcweir {
1116cdf0e10cSrcweir if (nDocs)
1117cdf0e10cSrcweir {
1118cdf0e10cSrcweir mbAllReferenced = false;
1119cdf0e10cSrcweir DocReferencedVec aRefs( nDocs);
1120cdf0e10cSrcweir maDocs.swap( aRefs);
1121cdf0e10cSrcweir }
1122cdf0e10cSrcweir else
1123cdf0e10cSrcweir {
1124cdf0e10cSrcweir mbAllReferenced = true;
1125cdf0e10cSrcweir DocReferencedVec aRefs;
1126cdf0e10cSrcweir maDocs.swap( aRefs);
1127cdf0e10cSrcweir }
1128cdf0e10cSrcweir }
1129cdf0e10cSrcweir
checkAllDocs()1130cdf0e10cSrcweir void ScExternalRefCache::ReferencedStatus::checkAllDocs()
1131cdf0e10cSrcweir {
1132cdf0e10cSrcweir for (DocReferencedVec::const_iterator itr = maDocs.begin(); itr != maDocs.end(); ++itr)
1133cdf0e10cSrcweir {
1134cdf0e10cSrcweir if (!(*itr).mbAllTablesReferenced)
1135cdf0e10cSrcweir return;
1136cdf0e10cSrcweir }
1137cdf0e10cSrcweir mbAllReferenced = true;
1138cdf0e10cSrcweir }
1139cdf0e10cSrcweir
getCacheTable(sal_uInt16 nFileId,size_t nTabIndex) const1140cdf0e10cSrcweir ScExternalRefCache::TableTypeRef ScExternalRefCache::getCacheTable(sal_uInt16 nFileId, size_t nTabIndex) const
1141cdf0e10cSrcweir {
1142cdf0e10cSrcweir DocItem* pDoc = getDocItem(nFileId);
1143cdf0e10cSrcweir if (!pDoc || nTabIndex >= pDoc->maTables.size())
1144cdf0e10cSrcweir return TableTypeRef();
1145cdf0e10cSrcweir
1146cdf0e10cSrcweir return pDoc->maTables[nTabIndex];
1147cdf0e10cSrcweir }
1148cdf0e10cSrcweir
getCacheTable(sal_uInt16 nFileId,const String & rTabName,bool bCreateNew,size_t * pnIndex)1149cdf0e10cSrcweir ScExternalRefCache::TableTypeRef ScExternalRefCache::getCacheTable(sal_uInt16 nFileId, const String& rTabName, bool bCreateNew, size_t* pnIndex)
1150cdf0e10cSrcweir {
1151cdf0e10cSrcweir // In API, the index is transported as cached sheet ID of type sal_Int32 in
1152cdf0e10cSrcweir // sheet::SingleReference.Sheet or sheet::ComplexReference.Reference1.Sheet
1153cdf0e10cSrcweir // in a sheet::FormulaToken, choose a sensible value for N/A. Effectively
1154cdf0e10cSrcweir // being 0xffffffff
1155cdf0e10cSrcweir const size_t nNotAvailable = static_cast<size_t>( static_cast<sal_Int32>( -1));
1156cdf0e10cSrcweir
1157cdf0e10cSrcweir DocItem* pDoc = getDocItem(nFileId);
1158cdf0e10cSrcweir if (!pDoc)
1159cdf0e10cSrcweir {
1160cdf0e10cSrcweir if (pnIndex) *pnIndex = nNotAvailable;
1161cdf0e10cSrcweir return TableTypeRef();
1162cdf0e10cSrcweir }
1163cdf0e10cSrcweir
1164cdf0e10cSrcweir DocItem& rDoc = *pDoc;
1165cdf0e10cSrcweir
1166cdf0e10cSrcweir size_t nIndex;
1167cdf0e10cSrcweir String aTabNameUpper = ScGlobal::pCharClass->upper(rTabName);
1168cdf0e10cSrcweir if (lcl_getTableDataIndex(rDoc.maTableNameIndex, aTabNameUpper, nIndex))
1169cdf0e10cSrcweir {
1170cdf0e10cSrcweir // specified table found.
1171cdf0e10cSrcweir if( pnIndex ) *pnIndex = nIndex;
1172cdf0e10cSrcweir if (bCreateNew && !rDoc.maTables[nIndex])
1173cdf0e10cSrcweir rDoc.maTables[nIndex].reset(new Table);
1174cdf0e10cSrcweir
1175cdf0e10cSrcweir return rDoc.maTables[nIndex];
1176cdf0e10cSrcweir }
1177cdf0e10cSrcweir
1178cdf0e10cSrcweir if (!bCreateNew)
1179cdf0e10cSrcweir {
1180cdf0e10cSrcweir if (pnIndex) *pnIndex = nNotAvailable;
1181cdf0e10cSrcweir return TableTypeRef();
1182cdf0e10cSrcweir }
1183cdf0e10cSrcweir
1184cdf0e10cSrcweir // Specified table doesn't exist yet. Create one.
1185cdf0e10cSrcweir nIndex = rDoc.maTables.size();
1186cdf0e10cSrcweir if( pnIndex ) *pnIndex = nIndex;
1187cdf0e10cSrcweir TableTypeRef pTab(new Table);
1188cdf0e10cSrcweir rDoc.maTables.push_back(pTab);
1189cdf0e10cSrcweir rDoc.maTableNames.push_back(TableName(aTabNameUpper, rTabName));
1190cdf0e10cSrcweir rDoc.maTableNameIndex.insert(
1191cdf0e10cSrcweir TableNameIndexMap::value_type(aTabNameUpper, nIndex));
1192cdf0e10cSrcweir return pTab;
1193cdf0e10cSrcweir }
1194cdf0e10cSrcweir
clearCache(sal_uInt16 nFileId)1195cdf0e10cSrcweir void ScExternalRefCache::clearCache(sal_uInt16 nFileId)
1196cdf0e10cSrcweir {
1197cdf0e10cSrcweir maDocs.erase(nFileId);
1198cdf0e10cSrcweir }
1199cdf0e10cSrcweir
getDocItem(sal_uInt16 nFileId) const1200cdf0e10cSrcweir ScExternalRefCache::DocItem* ScExternalRefCache::getDocItem(sal_uInt16 nFileId) const
1201cdf0e10cSrcweir {
1202cdf0e10cSrcweir using ::std::pair;
1203cdf0e10cSrcweir DocDataType::iterator itrDoc = maDocs.find(nFileId);
1204cdf0e10cSrcweir if (itrDoc == maDocs.end())
1205cdf0e10cSrcweir {
1206cdf0e10cSrcweir // specified document is not cached.
1207cdf0e10cSrcweir pair<DocDataType::iterator, bool> res = maDocs.insert(
1208cdf0e10cSrcweir DocDataType::value_type(nFileId, DocItem()));
1209cdf0e10cSrcweir
1210cdf0e10cSrcweir if (!res.second)
1211cdf0e10cSrcweir // insertion failed.
1212cdf0e10cSrcweir return NULL;
1213cdf0e10cSrcweir
1214cdf0e10cSrcweir itrDoc = res.first;
1215cdf0e10cSrcweir }
1216cdf0e10cSrcweir
1217cdf0e10cSrcweir return &itrDoc->second;
1218cdf0e10cSrcweir }
1219cdf0e10cSrcweir
1220cdf0e10cSrcweir // ============================================================================
1221cdf0e10cSrcweir
ScExternalRefLink(ScDocument * pDoc,sal_uInt16 nFileId,const String & rFilter)1222cdf0e10cSrcweir ScExternalRefLink::ScExternalRefLink(ScDocument* pDoc, sal_uInt16 nFileId, const String& rFilter) :
1223cdf0e10cSrcweir ::sfx2::SvBaseLink(::sfx2::LINKUPDATE_ONCALL, FORMAT_FILE),
1224cdf0e10cSrcweir mnFileId(nFileId),
1225cdf0e10cSrcweir maFilterName(rFilter),
1226cdf0e10cSrcweir mpDoc(pDoc),
1227cdf0e10cSrcweir mbDoRefresh(true)
1228cdf0e10cSrcweir {
1229cdf0e10cSrcweir }
1230cdf0e10cSrcweir
~ScExternalRefLink()1231cdf0e10cSrcweir ScExternalRefLink::~ScExternalRefLink()
1232cdf0e10cSrcweir {
1233cdf0e10cSrcweir }
1234cdf0e10cSrcweir
Closed()1235cdf0e10cSrcweir void ScExternalRefLink::Closed()
1236cdf0e10cSrcweir {
1237cdf0e10cSrcweir ScExternalRefManager* pMgr = mpDoc->GetExternalRefManager();
1238cdf0e10cSrcweir pMgr->breakLink(mnFileId);
1239cdf0e10cSrcweir }
1240cdf0e10cSrcweir
DataChanged(const String &,const Any &)1241cdf0e10cSrcweir void ScExternalRefLink::DataChanged(const String& /*rMimeType*/, const Any& /*rValue*/)
1242cdf0e10cSrcweir {
1243cdf0e10cSrcweir if (!mbDoRefresh)
1244cdf0e10cSrcweir return;
1245cdf0e10cSrcweir
1246cdf0e10cSrcweir String aFile, aFilter;
1247cdf0e10cSrcweir mpDoc->GetLinkManager()->GetDisplayNames(this, NULL, &aFile, NULL, &aFilter);
1248cdf0e10cSrcweir ScExternalRefManager* pMgr = mpDoc->GetExternalRefManager();
1249cdf0e10cSrcweir const String* pCurFile = pMgr->getExternalFileName(mnFileId);
1250cdf0e10cSrcweir if (!pCurFile)
1251cdf0e10cSrcweir return;
1252cdf0e10cSrcweir
1253cdf0e10cSrcweir if (pCurFile->Equals(aFile))
1254cdf0e10cSrcweir {
1255cdf0e10cSrcweir // Refresh the current source document.
1256cdf0e10cSrcweir pMgr->refreshNames(mnFileId);
1257cdf0e10cSrcweir }
1258cdf0e10cSrcweir else
1259cdf0e10cSrcweir {
1260cdf0e10cSrcweir // The source document has changed.
1261cdf0e10cSrcweir ScDocShell* pDocShell = ScDocShell::GetViewData()->GetDocShell();
1262cdf0e10cSrcweir ScDocShellModificator aMod(*pDocShell);
1263cdf0e10cSrcweir pMgr->switchSrcFile(mnFileId, aFile, aFilter);
1264cdf0e10cSrcweir maFilterName = aFilter;
1265cdf0e10cSrcweir aMod.SetDocumentModified();
1266cdf0e10cSrcweir }
1267cdf0e10cSrcweir }
1268cdf0e10cSrcweir
Edit(Window * pParent,const Link &)1269cdf0e10cSrcweir void ScExternalRefLink::Edit(Window* pParent, const Link& /*rEndEditHdl*/)
1270cdf0e10cSrcweir {
1271cdf0e10cSrcweir SvBaseLink::Edit(pParent, LINK(this, ScExternalRefLink, ExternalRefEndEditHdl));
1272cdf0e10cSrcweir }
1273cdf0e10cSrcweir
SetDoReferesh(bool b)1274cdf0e10cSrcweir void ScExternalRefLink::SetDoReferesh(bool b)
1275cdf0e10cSrcweir {
1276cdf0e10cSrcweir mbDoRefresh = b;
1277cdf0e10cSrcweir }
1278cdf0e10cSrcweir
IMPL_LINK(ScExternalRefLink,ExternalRefEndEditHdl,::sfx2::SvBaseLink *,EMPTYARG)1279cdf0e10cSrcweir IMPL_LINK( ScExternalRefLink, ExternalRefEndEditHdl, ::sfx2::SvBaseLink*, EMPTYARG )
1280cdf0e10cSrcweir {
1281cdf0e10cSrcweir return 0;
1282cdf0e10cSrcweir }
1283cdf0e10cSrcweir
1284cdf0e10cSrcweir // ============================================================================
1285cdf0e10cSrcweir
lcl_convertToToken(ScBaseCell * pCell)1286cdf0e10cSrcweir static FormulaToken* lcl_convertToToken(ScBaseCell* pCell)
1287cdf0e10cSrcweir {
1288cdf0e10cSrcweir if (!pCell || pCell->HasEmptyData())
1289cdf0e10cSrcweir {
1290cdf0e10cSrcweir bool bInherited = (pCell && pCell->GetCellType() == CELLTYPE_FORMULA);
1291cdf0e10cSrcweir return new ScEmptyCellToken( bInherited, false);
1292cdf0e10cSrcweir }
1293cdf0e10cSrcweir
1294cdf0e10cSrcweir switch (pCell->GetCellType())
1295cdf0e10cSrcweir {
1296cdf0e10cSrcweir case CELLTYPE_EDIT:
1297cdf0e10cSrcweir {
1298cdf0e10cSrcweir String aStr;
1299cdf0e10cSrcweir static_cast<ScEditCell*>(pCell)->GetString(aStr);
1300cdf0e10cSrcweir return new formula::FormulaStringToken(aStr);
1301cdf0e10cSrcweir }
1302cdf0e10cSrcweir //break;
1303cdf0e10cSrcweir case CELLTYPE_STRING:
1304cdf0e10cSrcweir {
1305cdf0e10cSrcweir String aStr;
1306cdf0e10cSrcweir static_cast<ScStringCell*>(pCell)->GetString(aStr);
1307cdf0e10cSrcweir return new formula::FormulaStringToken(aStr);
1308cdf0e10cSrcweir }
1309cdf0e10cSrcweir //break;
1310cdf0e10cSrcweir case CELLTYPE_VALUE:
1311cdf0e10cSrcweir {
1312cdf0e10cSrcweir double fVal = static_cast<ScValueCell*>(pCell)->GetValue();
1313cdf0e10cSrcweir return new formula::FormulaDoubleToken(fVal);
1314cdf0e10cSrcweir }
1315cdf0e10cSrcweir //break;
1316cdf0e10cSrcweir case CELLTYPE_FORMULA:
1317cdf0e10cSrcweir {
1318cdf0e10cSrcweir ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
1319cdf0e10cSrcweir sal_uInt16 nError = pFCell->GetErrCode();
1320cdf0e10cSrcweir if (nError)
1321cdf0e10cSrcweir return new FormulaErrorToken( nError);
1322cdf0e10cSrcweir else if (pFCell->IsValue())
1323cdf0e10cSrcweir {
1324cdf0e10cSrcweir double fVal = pFCell->GetValue();
1325cdf0e10cSrcweir return new formula::FormulaDoubleToken(fVal);
1326cdf0e10cSrcweir }
1327cdf0e10cSrcweir else
1328cdf0e10cSrcweir {
1329cdf0e10cSrcweir String aStr;
1330cdf0e10cSrcweir pFCell->GetString(aStr);
1331cdf0e10cSrcweir return new formula::FormulaStringToken(aStr);
1332cdf0e10cSrcweir }
1333cdf0e10cSrcweir }
1334cdf0e10cSrcweir //break;
1335cdf0e10cSrcweir default:
1336cdf0e10cSrcweir DBG_ERROR("attempted to convert an unknown cell type.");
1337cdf0e10cSrcweir }
1338cdf0e10cSrcweir
1339cdf0e10cSrcweir return NULL;
1340cdf0e10cSrcweir }
1341cdf0e10cSrcweir
lcl_convertToTokenArray(ScDocument * pSrcDoc,ScRange & rRange,vector<ScExternalRefCache::SingleRangeData> & rCacheData)1342cdf0e10cSrcweir static ScTokenArray* lcl_convertToTokenArray(ScDocument* pSrcDoc, ScRange& rRange,
1343cdf0e10cSrcweir vector<ScExternalRefCache::SingleRangeData>& rCacheData)
1344cdf0e10cSrcweir {
1345cdf0e10cSrcweir ScAddress& s = rRange.aStart;
1346cdf0e10cSrcweir ScAddress& e = rRange.aEnd;
1347cdf0e10cSrcweir
1348cdf0e10cSrcweir SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
1349cdf0e10cSrcweir SCCOL nCol1 = s.Col(), nCol2 = e.Col();
1350cdf0e10cSrcweir SCROW nRow1 = s.Row(), nRow2 = e.Row();
1351cdf0e10cSrcweir
1352cdf0e10cSrcweir if (nTab2 != nTab1)
1353cdf0e10cSrcweir // For now, we don't support multi-sheet ranges intentionally because
1354cdf0e10cSrcweir // we don't have a way to express them in a single token. In the
1355cdf0e10cSrcweir // future we can introduce a new stack variable type svMatrixList with
1356cdf0e10cSrcweir // a new token type that can store a 3D matrix value and convert a 3D
1357cdf0e10cSrcweir // range to it.
1358cdf0e10cSrcweir return NULL;
1359cdf0e10cSrcweir
1360cdf0e10cSrcweir ::boost::scoped_ptr<ScRange> pUsedRange;
1361cdf0e10cSrcweir
1362cdf0e10cSrcweir auto_ptr<ScTokenArray> pArray(new ScTokenArray);
1363cdf0e10cSrcweir bool bFirstTab = true;
1364cdf0e10cSrcweir vector<ScExternalRefCache::SingleRangeData>::iterator
1365cdf0e10cSrcweir itrCache = rCacheData.begin(), itrCacheEnd = rCacheData.end();
1366cdf0e10cSrcweir
1367cdf0e10cSrcweir for (SCTAB nTab = nTab1; nTab <= nTab2 && itrCache != itrCacheEnd; ++nTab, ++itrCache)
1368cdf0e10cSrcweir {
1369cdf0e10cSrcweir // Only loop within the data area.
1370cdf0e10cSrcweir SCCOL nDataCol1 = nCol1, nDataCol2 = nCol2;
1371cdf0e10cSrcweir SCROW nDataRow1 = nRow1, nDataRow2 = nRow2;
1372cdf0e10cSrcweir bool bShrunk;
1373cdf0e10cSrcweir if (!pSrcDoc->ShrinkToUsedDataArea( bShrunk, nTab, nDataCol1, nDataRow1, nDataCol2, nDataRow2, false))
1374cdf0e10cSrcweir // no data within specified range.
1375cdf0e10cSrcweir continue;
1376cdf0e10cSrcweir
1377cdf0e10cSrcweir if (pUsedRange.get())
1378cdf0e10cSrcweir // Make sure the used area only grows, not shrinks.
1379cdf0e10cSrcweir pUsedRange->ExtendTo(ScRange(nDataCol1, nDataRow1, 0, nDataCol2, nDataRow2, 0));
1380cdf0e10cSrcweir else
1381cdf0e10cSrcweir pUsedRange.reset(new ScRange(nDataCol1, nDataRow1, 0, nDataCol2, nDataRow2, 0));
1382cdf0e10cSrcweir
1383cdf0e10cSrcweir ScMatrixRef xMat = new ScMatrix(
1384cdf0e10cSrcweir static_cast<SCSIZE>(nDataCol2-nDataCol1+1),
1385cdf0e10cSrcweir static_cast<SCSIZE>(nDataRow2-nDataRow1+1));
1386cdf0e10cSrcweir
1387cdf0e10cSrcweir for (SCCOL nCol = nDataCol1; nCol <= nDataCol2; ++nCol)
1388cdf0e10cSrcweir {
1389cdf0e10cSrcweir for (SCROW nRow = nDataRow1; nRow <= nDataRow2; ++nRow)
1390cdf0e10cSrcweir {
1391cdf0e10cSrcweir SCSIZE nC = nCol - nCol1, nR = nRow - nRow1;
1392cdf0e10cSrcweir ScBaseCell* pCell;
1393cdf0e10cSrcweir pSrcDoc->GetCell(nCol, nRow, nTab, pCell);
1394cdf0e10cSrcweir if (!pCell || pCell->HasEmptyData())
1395cdf0e10cSrcweir xMat->PutEmpty(nC, nR);
1396cdf0e10cSrcweir else
1397cdf0e10cSrcweir {
1398cdf0e10cSrcweir switch (pCell->GetCellType())
1399cdf0e10cSrcweir {
1400cdf0e10cSrcweir case CELLTYPE_EDIT:
1401cdf0e10cSrcweir {
1402cdf0e10cSrcweir String aStr;
1403cdf0e10cSrcweir static_cast<ScEditCell*>(pCell)->GetString(aStr);
1404cdf0e10cSrcweir xMat->PutString(aStr, nC, nR);
1405cdf0e10cSrcweir }
1406cdf0e10cSrcweir break;
1407cdf0e10cSrcweir case CELLTYPE_STRING:
1408cdf0e10cSrcweir {
1409cdf0e10cSrcweir String aStr;
1410cdf0e10cSrcweir static_cast<ScStringCell*>(pCell)->GetString(aStr);
1411cdf0e10cSrcweir xMat->PutString(aStr, nC, nR);
1412cdf0e10cSrcweir }
1413cdf0e10cSrcweir break;
1414cdf0e10cSrcweir case CELLTYPE_VALUE:
1415cdf0e10cSrcweir {
1416cdf0e10cSrcweir double fVal = static_cast<ScValueCell*>(pCell)->GetValue();
1417cdf0e10cSrcweir xMat->PutDouble(fVal, nC, nR);
1418cdf0e10cSrcweir }
1419cdf0e10cSrcweir break;
1420cdf0e10cSrcweir case CELLTYPE_FORMULA:
1421cdf0e10cSrcweir {
1422cdf0e10cSrcweir ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
1423cdf0e10cSrcweir sal_uInt16 nError = pFCell->GetErrCode();
1424cdf0e10cSrcweir if (nError)
1425cdf0e10cSrcweir xMat->PutDouble( CreateDoubleError( nError), nC, nR);
1426cdf0e10cSrcweir else if (pFCell->IsValue())
1427cdf0e10cSrcweir {
1428cdf0e10cSrcweir double fVal = pFCell->GetValue();
1429cdf0e10cSrcweir xMat->PutDouble(fVal, nC, nR);
1430cdf0e10cSrcweir }
1431cdf0e10cSrcweir else
1432cdf0e10cSrcweir {
1433cdf0e10cSrcweir String aStr;
1434cdf0e10cSrcweir pFCell->GetString(aStr);
1435cdf0e10cSrcweir xMat->PutString(aStr, nC, nR);
1436cdf0e10cSrcweir }
1437cdf0e10cSrcweir }
1438cdf0e10cSrcweir break;
1439cdf0e10cSrcweir default:
1440cdf0e10cSrcweir DBG_ERROR("attempted to convert an unknown cell type.");
1441cdf0e10cSrcweir }
1442cdf0e10cSrcweir }
1443cdf0e10cSrcweir }
1444cdf0e10cSrcweir }
1445cdf0e10cSrcweir if (!bFirstTab)
1446cdf0e10cSrcweir pArray->AddOpCode(ocSep);
1447cdf0e10cSrcweir
1448cdf0e10cSrcweir ScMatrix* pMat2 = xMat;
1449cdf0e10cSrcweir ScMatrixToken aToken(pMat2);
1450cdf0e10cSrcweir pArray->AddToken(aToken);
1451cdf0e10cSrcweir
1452cdf0e10cSrcweir itrCache->mpRangeData = xMat;
1453cdf0e10cSrcweir
1454cdf0e10cSrcweir bFirstTab = false;
1455cdf0e10cSrcweir }
1456cdf0e10cSrcweir
1457cdf0e10cSrcweir if (!pUsedRange.get())
1458cdf0e10cSrcweir return NULL;
1459cdf0e10cSrcweir
1460cdf0e10cSrcweir s.SetCol(pUsedRange->aStart.Col());
1461cdf0e10cSrcweir s.SetRow(pUsedRange->aStart.Row());
1462cdf0e10cSrcweir e.SetCol(pUsedRange->aEnd.Col());
1463cdf0e10cSrcweir e.SetRow(pUsedRange->aEnd.Row());
1464cdf0e10cSrcweir
1465cdf0e10cSrcweir return pArray.release();
1466cdf0e10cSrcweir }
1467cdf0e10cSrcweir
lcl_fillEmptyMatrix(const ScRange & rRange)1468cdf0e10cSrcweir static ScTokenArray* lcl_fillEmptyMatrix(const ScRange& rRange)
1469cdf0e10cSrcweir {
1470cdf0e10cSrcweir SCSIZE nC = static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1);
1471cdf0e10cSrcweir SCSIZE nR = static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1);
1472cdf0e10cSrcweir ScMatrixRef xMat = new ScMatrix(nC, nR);
1473cdf0e10cSrcweir for (SCSIZE i = 0; i < nC; ++i)
1474cdf0e10cSrcweir for (SCSIZE j = 0; j < nR; ++j)
1475cdf0e10cSrcweir xMat->PutEmpty(i, j);
1476cdf0e10cSrcweir
1477cdf0e10cSrcweir ScMatrix* pMat2 = xMat;
1478cdf0e10cSrcweir ScMatrixToken aToken(pMat2);
1479cdf0e10cSrcweir auto_ptr<ScTokenArray> pArray(new ScTokenArray);
1480cdf0e10cSrcweir pArray->AddToken(aToken);
1481cdf0e10cSrcweir return pArray.release();
1482cdf0e10cSrcweir }
1483cdf0e10cSrcweir
ScExternalRefManager(ScDocument * pDoc)1484cdf0e10cSrcweir ScExternalRefManager::ScExternalRefManager(ScDocument* pDoc) :
1485cdf0e10cSrcweir mpDoc(pDoc),
1486cdf0e10cSrcweir mbInReferenceMarking(false),
1487cdf0e10cSrcweir mbUserInteractionEnabled(true)
1488cdf0e10cSrcweir {
1489cdf0e10cSrcweir maSrcDocTimer.SetTimeoutHdl( LINK(this, ScExternalRefManager, TimeOutHdl) );
1490cdf0e10cSrcweir maSrcDocTimer.SetTimeout(SRCDOC_SCAN_INTERVAL);
1491cdf0e10cSrcweir }
1492cdf0e10cSrcweir
~ScExternalRefManager()1493cdf0e10cSrcweir ScExternalRefManager::~ScExternalRefManager()
1494cdf0e10cSrcweir {
1495cdf0e10cSrcweir clear();
1496cdf0e10cSrcweir }
1497cdf0e10cSrcweir
getCacheTableName(sal_uInt16 nFileId,size_t nTabIndex) const1498cdf0e10cSrcweir String ScExternalRefManager::getCacheTableName(sal_uInt16 nFileId, size_t nTabIndex) const
1499cdf0e10cSrcweir {
1500cdf0e10cSrcweir return maRefCache.getTableName(nFileId, nTabIndex);
1501cdf0e10cSrcweir }
1502cdf0e10cSrcweir
getCacheTable(sal_uInt16 nFileId,size_t nTabIndex) const1503cdf0e10cSrcweir ScExternalRefCache::TableTypeRef ScExternalRefManager::getCacheTable(sal_uInt16 nFileId, size_t nTabIndex) const
1504cdf0e10cSrcweir {
1505cdf0e10cSrcweir return maRefCache.getCacheTable(nFileId, nTabIndex);
1506cdf0e10cSrcweir }
1507cdf0e10cSrcweir
getCacheTable(sal_uInt16 nFileId,const String & rTabName,bool bCreateNew,size_t * pnIndex)1508cdf0e10cSrcweir ScExternalRefCache::TableTypeRef ScExternalRefManager::getCacheTable(sal_uInt16 nFileId, const String& rTabName, bool bCreateNew, size_t* pnIndex)
1509cdf0e10cSrcweir {
1510cdf0e10cSrcweir return maRefCache.getCacheTable(nFileId, rTabName, bCreateNew, pnIndex);
1511cdf0e10cSrcweir }
1512cdf0e10cSrcweir
1513cdf0e10cSrcweir // ============================================================================
1514cdf0e10cSrcweir
LinkListener()1515cdf0e10cSrcweir ScExternalRefManager::LinkListener::LinkListener()
1516cdf0e10cSrcweir {
1517cdf0e10cSrcweir }
1518cdf0e10cSrcweir
~LinkListener()1519cdf0e10cSrcweir ScExternalRefManager::LinkListener::~LinkListener()
1520cdf0e10cSrcweir {
1521cdf0e10cSrcweir }
1522cdf0e10cSrcweir
1523cdf0e10cSrcweir // ----------------------------------------------------------------------------
1524cdf0e10cSrcweir
ApiGuard(ScDocument * pDoc)1525cdf0e10cSrcweir ScExternalRefManager::ApiGuard::ApiGuard(ScDocument* pDoc) :
1526cdf0e10cSrcweir mpMgr(pDoc->GetExternalRefManager()),
1527cdf0e10cSrcweir mbOldInteractionEnabled(mpMgr->mbUserInteractionEnabled)
1528cdf0e10cSrcweir {
1529cdf0e10cSrcweir // We don't want user interaction handled in the API.
1530cdf0e10cSrcweir mpMgr->mbUserInteractionEnabled = false;
1531cdf0e10cSrcweir }
1532cdf0e10cSrcweir
~ApiGuard()1533cdf0e10cSrcweir ScExternalRefManager::ApiGuard::~ApiGuard()
1534cdf0e10cSrcweir {
1535cdf0e10cSrcweir // Restore old value.
1536cdf0e10cSrcweir mpMgr->mbUserInteractionEnabled = mbOldInteractionEnabled;
1537cdf0e10cSrcweir }
1538cdf0e10cSrcweir
1539cdf0e10cSrcweir // ----------------------------------------------------------------------------
1540cdf0e10cSrcweir
getAllCachedTableNames(sal_uInt16 nFileId,vector<String> & rTabNames) const1541cdf0e10cSrcweir void ScExternalRefManager::getAllCachedTableNames(sal_uInt16 nFileId, vector<String>& rTabNames) const
1542cdf0e10cSrcweir {
1543cdf0e10cSrcweir maRefCache.getAllTableNames(nFileId, rTabNames);
1544cdf0e10cSrcweir }
1545cdf0e10cSrcweir
getCachedTabSpan(sal_uInt16 nFileId,const String & rStartTabName,const String & rEndTabName) const1546cdf0e10cSrcweir SCsTAB ScExternalRefManager::getCachedTabSpan( sal_uInt16 nFileId, const String& rStartTabName, const String& rEndTabName ) const
1547cdf0e10cSrcweir {
1548cdf0e10cSrcweir return maRefCache.getTabSpan( nFileId, rStartTabName, rEndTabName);
1549cdf0e10cSrcweir }
1550cdf0e10cSrcweir
getAllCachedNumberFormats(vector<sal_uInt32> & rNumFmts) const1551cdf0e10cSrcweir void ScExternalRefManager::getAllCachedNumberFormats(vector<sal_uInt32>& rNumFmts) const
1552cdf0e10cSrcweir {
1553cdf0e10cSrcweir maRefCache.getAllNumberFormats(rNumFmts);
1554cdf0e10cSrcweir }
1555cdf0e10cSrcweir
getExternalFileCount() const1556cdf0e10cSrcweir sal_uInt16 ScExternalRefManager::getExternalFileCount() const
1557cdf0e10cSrcweir {
1558cdf0e10cSrcweir return static_cast< sal_uInt16 >( maSrcFiles.size() );
1559cdf0e10cSrcweir }
1560cdf0e10cSrcweir
markUsedByLinkListeners()1561cdf0e10cSrcweir bool ScExternalRefManager::markUsedByLinkListeners()
1562cdf0e10cSrcweir {
1563cdf0e10cSrcweir bool bAllMarked = false;
1564cdf0e10cSrcweir for (LinkListenerMap::const_iterator itr = maLinkListeners.begin();
1565cdf0e10cSrcweir itr != maLinkListeners.end() && !bAllMarked; ++itr)
1566cdf0e10cSrcweir {
1567cdf0e10cSrcweir if (!(*itr).second.empty())
1568cdf0e10cSrcweir bAllMarked = maRefCache.setCacheDocReferenced( (*itr).first);
1569cdf0e10cSrcweir /* TODO: LinkListeners should remember the table they're listening to.
1570cdf0e10cSrcweir * As is, listening to one table will mark all tables of the document
1571cdf0e10cSrcweir * being referenced. */
1572cdf0e10cSrcweir }
1573cdf0e10cSrcweir return bAllMarked;
1574cdf0e10cSrcweir }
1575cdf0e10cSrcweir
markUsedExternalRefCells()1576cdf0e10cSrcweir bool ScExternalRefManager::markUsedExternalRefCells()
1577cdf0e10cSrcweir {
1578cdf0e10cSrcweir RefCellMap::iterator itr = maRefCells.begin(), itrEnd = maRefCells.end();
1579cdf0e10cSrcweir for (; itr != itrEnd; ++itr)
1580cdf0e10cSrcweir {
1581cdf0e10cSrcweir RefCellSet::iterator itrCell = itr->second.begin(), itrCellEnd = itr->second.end();
1582cdf0e10cSrcweir for (; itrCell != itrCellEnd; ++itrCell)
1583cdf0e10cSrcweir {
1584cdf0e10cSrcweir ScFormulaCell* pCell = *itrCell;
1585cdf0e10cSrcweir bool bUsed = pCell->MarkUsedExternalReferences();
1586cdf0e10cSrcweir if (bUsed)
1587cdf0e10cSrcweir // Return true when at least one cell references external docs.
1588cdf0e10cSrcweir return true;
1589cdf0e10cSrcweir }
1590cdf0e10cSrcweir }
1591cdf0e10cSrcweir return false;
1592cdf0e10cSrcweir }
1593cdf0e10cSrcweir
setCacheTableReferenced(sal_uInt16 nFileId,const String & rTabName,size_t nSheets)1594cdf0e10cSrcweir bool ScExternalRefManager::setCacheTableReferenced( sal_uInt16 nFileId, const String& rTabName, size_t nSheets )
1595cdf0e10cSrcweir {
1596cdf0e10cSrcweir return maRefCache.setCacheTableReferenced( nFileId, rTabName, nSheets, false);
1597cdf0e10cSrcweir }
1598cdf0e10cSrcweir
setCacheTableReferencedPermanently(sal_uInt16 nFileId,const String & rTabName,size_t nSheets)1599cdf0e10cSrcweir void ScExternalRefManager::setCacheTableReferencedPermanently( sal_uInt16 nFileId, const String& rTabName, size_t nSheets )
1600cdf0e10cSrcweir {
1601cdf0e10cSrcweir if (isInReferenceMarking())
1602cdf0e10cSrcweir // Do all maintenance work.
1603cdf0e10cSrcweir maRefCache.setCacheTableReferenced( nFileId, rTabName, nSheets, true);
1604cdf0e10cSrcweir else
1605cdf0e10cSrcweir // Set only the permanent flag.
1606cdf0e10cSrcweir maRefCache.setCacheTableReferencedPermanently( nFileId, rTabName, nSheets);
1607cdf0e10cSrcweir }
1608cdf0e10cSrcweir
setAllCacheTableReferencedStati(bool bReferenced)1609cdf0e10cSrcweir void ScExternalRefManager::setAllCacheTableReferencedStati( bool bReferenced )
1610cdf0e10cSrcweir {
1611cdf0e10cSrcweir mbInReferenceMarking = !bReferenced;
1612cdf0e10cSrcweir maRefCache.setAllCacheTableReferencedStati( bReferenced );
1613cdf0e10cSrcweir }
1614cdf0e10cSrcweir
storeRangeNameTokens(sal_uInt16 nFileId,const String & rName,const ScTokenArray & rArray)1615cdf0e10cSrcweir void ScExternalRefManager::storeRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScTokenArray& rArray)
1616cdf0e10cSrcweir {
1617cdf0e10cSrcweir ScExternalRefCache::TokenArrayRef pArray(rArray.Clone());
1618cdf0e10cSrcweir maRefCache.setRangeNameTokens(nFileId, rName, pArray);
1619cdf0e10cSrcweir }
1620cdf0e10cSrcweir
getSingleRefToken(sal_uInt16 nFileId,const String & rTabName,const ScAddress & rCell,const ScAddress * pCurPos,SCTAB * pTab,ScExternalRefCache::CellFormat * pFmt)1621cdf0e10cSrcweir ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefToken(
1622cdf0e10cSrcweir sal_uInt16 nFileId, const String& rTabName, const ScAddress& rCell,
1623cdf0e10cSrcweir const ScAddress* pCurPos, SCTAB* pTab, ScExternalRefCache::CellFormat* pFmt)
1624cdf0e10cSrcweir {
1625cdf0e10cSrcweir if (pCurPos)
1626cdf0e10cSrcweir insertRefCell(nFileId, *pCurPos);
1627cdf0e10cSrcweir
1628cdf0e10cSrcweir maybeLinkExternalFile(nFileId);
1629cdf0e10cSrcweir
1630cdf0e10cSrcweir if (pTab)
1631cdf0e10cSrcweir *pTab = -1;
1632cdf0e10cSrcweir
1633cdf0e10cSrcweir if (pFmt)
1634cdf0e10cSrcweir pFmt->mbIsSet = false;
1635cdf0e10cSrcweir
1636cdf0e10cSrcweir // Check if the given table name and the cell position is cached.
1637cdf0e10cSrcweir sal_uInt32 nFmtIndex = 0;
1638cdf0e10cSrcweir ScExternalRefCache::TokenRef pToken = maRefCache.getCellData(
1639cdf0e10cSrcweir nFileId, rTabName, rCell.Col(), rCell.Row(), &nFmtIndex);
1640cdf0e10cSrcweir if (pToken)
1641cdf0e10cSrcweir {
1642cdf0e10cSrcweir // Cache hit !
1643cdf0e10cSrcweir if (pFmt)
1644cdf0e10cSrcweir {
1645cdf0e10cSrcweir short nFmtType = mpDoc->GetFormatTable()->GetType(nFmtIndex);
1646cdf0e10cSrcweir if (nFmtType != NUMBERFORMAT_UNDEFINED)
1647cdf0e10cSrcweir {
1648cdf0e10cSrcweir pFmt->mbIsSet = true;
1649cdf0e10cSrcweir pFmt->mnIndex = nFmtIndex;
1650cdf0e10cSrcweir pFmt->mnType = nFmtType;
1651cdf0e10cSrcweir }
1652cdf0e10cSrcweir }
1653cdf0e10cSrcweir return pToken;
1654cdf0e10cSrcweir }
1655cdf0e10cSrcweir
1656cdf0e10cSrcweir // reference not cached. read from the source document.
1657cdf0e10cSrcweir ScDocument* pSrcDoc = getSrcDocument(nFileId);
1658cdf0e10cSrcweir if (!pSrcDoc)
1659cdf0e10cSrcweir {
1660cdf0e10cSrcweir // Source document not reachable. Throw a reference error.
1661cdf0e10cSrcweir pToken.reset(new FormulaErrorToken(errNoRef));
1662cdf0e10cSrcweir return pToken;
1663cdf0e10cSrcweir }
1664cdf0e10cSrcweir
1665cdf0e10cSrcweir ScBaseCell* pCell = NULL;
1666cdf0e10cSrcweir SCTAB nTab;
1667cdf0e10cSrcweir if (!pSrcDoc->GetTable(rTabName, nTab))
1668cdf0e10cSrcweir {
1669cdf0e10cSrcweir // specified table name doesn't exist in the source document.
1670cdf0e10cSrcweir pToken.reset(new FormulaErrorToken(errNoRef));
1671cdf0e10cSrcweir return pToken;
1672cdf0e10cSrcweir }
1673cdf0e10cSrcweir
1674cdf0e10cSrcweir if (pTab)
1675cdf0e10cSrcweir *pTab = nTab;
1676cdf0e10cSrcweir
1677cdf0e10cSrcweir SCCOL nDataCol1 = 0, nDataCol2 = MAXCOL;
1678cdf0e10cSrcweir SCROW nDataRow1 = 0, nDataRow2 = MAXROW;
1679cdf0e10cSrcweir bool bData = pSrcDoc->ShrinkToDataArea(nTab, nDataCol1, nDataRow1, nDataCol2, nDataRow2);
1680cdf0e10cSrcweir if (!bData || rCell.Col() < nDataCol1 || nDataCol2 < rCell.Col() || rCell.Row() < nDataRow1 || nDataRow2 < rCell.Row())
1681cdf0e10cSrcweir {
1682cdf0e10cSrcweir // requested cell is outside the data area. Don't even bother caching
1683cdf0e10cSrcweir // this data, but add it to the cached range to prevent accessing the
1684cdf0e10cSrcweir // source document time and time again.
1685cdf0e10cSrcweir ScExternalRefCache::TableTypeRef pCacheTab =
1686cdf0e10cSrcweir maRefCache.getCacheTable(nFileId, rTabName, true, NULL);
1687cdf0e10cSrcweir if (pCacheTab)
1688cdf0e10cSrcweir pCacheTab->setCachedCell(rCell.Col(), rCell.Row());
1689cdf0e10cSrcweir
1690cdf0e10cSrcweir pToken.reset(new ScEmptyCellToken(false, false));
1691cdf0e10cSrcweir return pToken;
1692cdf0e10cSrcweir }
1693cdf0e10cSrcweir
1694cdf0e10cSrcweir pSrcDoc->GetCell(rCell.Col(), rCell.Row(), nTab, pCell);
1695cdf0e10cSrcweir ScExternalRefCache::TokenRef pTok(lcl_convertToToken(pCell));
1696cdf0e10cSrcweir
1697cdf0e10cSrcweir pSrcDoc->GetNumberFormat(rCell.Col(), rCell.Row(), nTab, nFmtIndex);
1698cdf0e10cSrcweir nFmtIndex = getMappedNumberFormat(nFileId, nFmtIndex, pSrcDoc);
1699cdf0e10cSrcweir if (pFmt)
1700cdf0e10cSrcweir {
1701cdf0e10cSrcweir short nFmtType = mpDoc->GetFormatTable()->GetType(nFmtIndex);
1702cdf0e10cSrcweir if (nFmtType != NUMBERFORMAT_UNDEFINED)
1703cdf0e10cSrcweir {
1704cdf0e10cSrcweir pFmt->mbIsSet = true;
1705cdf0e10cSrcweir pFmt->mnIndex = nFmtIndex;
1706cdf0e10cSrcweir pFmt->mnType = nFmtType;
1707cdf0e10cSrcweir }
1708cdf0e10cSrcweir }
1709cdf0e10cSrcweir
1710cdf0e10cSrcweir if (!pTok.get())
1711cdf0e10cSrcweir {
1712cdf0e10cSrcweir // Generate an error for unresolvable cells.
1713cdf0e10cSrcweir pTok.reset( new FormulaErrorToken( errNoValue));
1714cdf0e10cSrcweir }
1715cdf0e10cSrcweir
1716cdf0e10cSrcweir // Now, insert the token into cache table but don't cache empty cells.
1717cdf0e10cSrcweir if (pTok->GetType() != formula::svEmptyCell)
1718cdf0e10cSrcweir maRefCache.setCellData(nFileId, rTabName, rCell.Col(), rCell.Row(), pTok, nFmtIndex);
1719cdf0e10cSrcweir
1720cdf0e10cSrcweir return pTok;
1721cdf0e10cSrcweir }
1722cdf0e10cSrcweir
getDoubleRefTokens(sal_uInt16 nFileId,const String & rTabName,const ScRange & rRange,const ScAddress * pCurPos)1723cdf0e10cSrcweir ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokens(
1724cdf0e10cSrcweir sal_uInt16 nFileId, const String& rTabName, const ScRange& rRange, const ScAddress* pCurPos)
1725cdf0e10cSrcweir {
1726cdf0e10cSrcweir if (pCurPos)
1727cdf0e10cSrcweir insertRefCell(nFileId, *pCurPos);
1728cdf0e10cSrcweir
1729cdf0e10cSrcweir maybeLinkExternalFile(nFileId);
1730cdf0e10cSrcweir
1731cdf0e10cSrcweir // Check if the given table name and the cell position is cached.
1732cdf0e10cSrcweir ScExternalRefCache::TokenArrayRef pArray =
1733cdf0e10cSrcweir maRefCache.getCellRangeData(nFileId, rTabName, rRange);
1734cdf0e10cSrcweir if (pArray)
1735cdf0e10cSrcweir // Cache hit !
1736cdf0e10cSrcweir return pArray;
1737cdf0e10cSrcweir
1738cdf0e10cSrcweir ScDocument* pSrcDoc = getSrcDocument(nFileId);
1739cdf0e10cSrcweir if (!pSrcDoc)
1740cdf0e10cSrcweir {
1741cdf0e10cSrcweir // Source document is not reachable. Throw a reference error.
1742cdf0e10cSrcweir pArray.reset(new ScTokenArray);
1743cdf0e10cSrcweir pArray->AddToken(FormulaErrorToken(errNoRef));
1744cdf0e10cSrcweir return pArray;
1745cdf0e10cSrcweir }
1746cdf0e10cSrcweir
1747cdf0e10cSrcweir SCTAB nTab1;
1748cdf0e10cSrcweir if (!pSrcDoc->GetTable(rTabName, nTab1))
1749cdf0e10cSrcweir {
1750cdf0e10cSrcweir // specified table name doesn't exist in the source document.
1751cdf0e10cSrcweir pArray.reset(new ScTokenArray);
1752cdf0e10cSrcweir pArray->AddToken(FormulaErrorToken(errNoRef));
1753cdf0e10cSrcweir return pArray;
1754cdf0e10cSrcweir }
1755cdf0e10cSrcweir
1756cdf0e10cSrcweir ScRange aRange(rRange);
1757cdf0e10cSrcweir SCTAB nTabSpan = aRange.aEnd.Tab() - aRange.aStart.Tab();
1758cdf0e10cSrcweir
1759cdf0e10cSrcweir vector<ScExternalRefCache::SingleRangeData> aCacheData;
1760cdf0e10cSrcweir aCacheData.reserve(nTabSpan+1);
1761cdf0e10cSrcweir aCacheData.push_back(ScExternalRefCache::SingleRangeData());
1762cdf0e10cSrcweir aCacheData.back().maTableName = ScGlobal::pCharClass->upper(rTabName);
1763cdf0e10cSrcweir
1764cdf0e10cSrcweir for (SCTAB i = 1; i < nTabSpan + 1; ++i)
1765cdf0e10cSrcweir {
1766cdf0e10cSrcweir String aTabName;
1767cdf0e10cSrcweir if (!pSrcDoc->GetName(nTab1 + 1, aTabName))
1768cdf0e10cSrcweir // source document doesn't have any table by the specified name.
1769cdf0e10cSrcweir break;
1770cdf0e10cSrcweir
1771cdf0e10cSrcweir aCacheData.push_back(ScExternalRefCache::SingleRangeData());
1772cdf0e10cSrcweir aCacheData.back().maTableName = ScGlobal::pCharClass->upper(aTabName);
1773cdf0e10cSrcweir }
1774cdf0e10cSrcweir
1775cdf0e10cSrcweir aRange.aStart.SetTab(nTab1);
1776cdf0e10cSrcweir aRange.aEnd.SetTab(nTab1 + nTabSpan);
1777cdf0e10cSrcweir
1778cdf0e10cSrcweir pArray.reset(lcl_convertToTokenArray(pSrcDoc, aRange, aCacheData));
1779cdf0e10cSrcweir
1780cdf0e10cSrcweir if (pArray)
1781cdf0e10cSrcweir // Cache these values.
1782cdf0e10cSrcweir maRefCache.setCellRangeData(nFileId, aRange, aCacheData, pArray);
1783cdf0e10cSrcweir else
1784cdf0e10cSrcweir {
1785cdf0e10cSrcweir // Array is empty. Fill it with an empty matrix of the required size.
1786cdf0e10cSrcweir pArray.reset(lcl_fillEmptyMatrix(rRange));
1787cdf0e10cSrcweir
1788cdf0e10cSrcweir // Make sure to set this range 'cached', to prevent unnecessarily
1789cdf0e10cSrcweir // accessing the src document time and time again.
1790cdf0e10cSrcweir ScExternalRefCache::TableTypeRef pCacheTab =
1791cdf0e10cSrcweir maRefCache.getCacheTable(nFileId, rTabName, true, NULL);
1792cdf0e10cSrcweir if (pCacheTab)
1793cdf0e10cSrcweir pCacheTab->setCachedCellRange(
1794cdf0e10cSrcweir rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
1795cdf0e10cSrcweir }
1796cdf0e10cSrcweir
1797cdf0e10cSrcweir return pArray;
1798cdf0e10cSrcweir }
1799cdf0e10cSrcweir
getRangeNameTokens(sal_uInt16 nFileId,const String & rName,const ScAddress * pCurPos)1800cdf0e10cSrcweir ScExternalRefCache::TokenArrayRef ScExternalRefManager::getRangeNameTokens(sal_uInt16 nFileId, const String& rName, const ScAddress* pCurPos)
1801cdf0e10cSrcweir {
1802cdf0e10cSrcweir if (pCurPos)
1803cdf0e10cSrcweir insertRefCell(nFileId, *pCurPos);
1804cdf0e10cSrcweir
1805cdf0e10cSrcweir maybeLinkExternalFile(nFileId);
1806cdf0e10cSrcweir
1807cdf0e10cSrcweir ScExternalRefCache::TokenArrayRef pArray = maRefCache.getRangeNameTokens(nFileId, rName);
1808cdf0e10cSrcweir if (pArray.get())
1809cdf0e10cSrcweir return pArray;
1810cdf0e10cSrcweir
1811cdf0e10cSrcweir ScDocument* pSrcDoc = getSrcDocument(nFileId);
1812cdf0e10cSrcweir if (!pSrcDoc)
1813cdf0e10cSrcweir return ScExternalRefCache::TokenArrayRef();
1814cdf0e10cSrcweir
1815cdf0e10cSrcweir ScRangeName* pExtNames = pSrcDoc->GetRangeName();
1816cdf0e10cSrcweir String aUpperName = ScGlobal::pCharClass->upper(rName);
1817cdf0e10cSrcweir sal_uInt16 n;
1818cdf0e10cSrcweir bool bRes = pExtNames->SearchNameUpper(aUpperName, n);
1819cdf0e10cSrcweir if (!bRes)
1820cdf0e10cSrcweir return ScExternalRefCache::TokenArrayRef();
1821cdf0e10cSrcweir
1822cdf0e10cSrcweir ScRangeData* pRangeData = (*pExtNames)[n];
1823cdf0e10cSrcweir if (!pRangeData)
1824cdf0e10cSrcweir return ScExternalRefCache::TokenArrayRef();
1825cdf0e10cSrcweir
1826cdf0e10cSrcweir // Parse all tokens in this external range data, and replace each absolute
1827cdf0e10cSrcweir // reference token with an external reference token, and cache them. Also
1828cdf0e10cSrcweir // register the source document with the link manager if it's a new
1829cdf0e10cSrcweir // source.
1830cdf0e10cSrcweir
1831cdf0e10cSrcweir ScExternalRefCache::TokenArrayRef pNew(new ScTokenArray);
1832cdf0e10cSrcweir
1833cdf0e10cSrcweir ScTokenArray* pCode = pRangeData->GetCode();
1834cdf0e10cSrcweir for (FormulaToken* pToken = pCode->First(); pToken; pToken = pCode->Next())
1835cdf0e10cSrcweir {
1836cdf0e10cSrcweir bool bTokenAdded = false;
1837cdf0e10cSrcweir switch (pToken->GetType())
1838cdf0e10cSrcweir {
1839cdf0e10cSrcweir case svSingleRef:
1840cdf0e10cSrcweir {
1841cdf0e10cSrcweir const ScSingleRefData& rRef = static_cast<ScToken*>(pToken)->GetSingleRef();
1842cdf0e10cSrcweir String aTabName;
1843cdf0e10cSrcweir pSrcDoc->GetName(rRef.nTab, aTabName);
1844cdf0e10cSrcweir ScExternalSingleRefToken aNewToken(nFileId, aTabName, static_cast<ScToken*>(pToken)->GetSingleRef());
1845cdf0e10cSrcweir pNew->AddToken(aNewToken);
1846cdf0e10cSrcweir bTokenAdded = true;
1847cdf0e10cSrcweir }
1848cdf0e10cSrcweir break;
1849cdf0e10cSrcweir case svDoubleRef:
1850cdf0e10cSrcweir {
1851cdf0e10cSrcweir const ScSingleRefData& rRef = static_cast<ScToken*>(pToken)->GetSingleRef();
1852cdf0e10cSrcweir String aTabName;
1853cdf0e10cSrcweir pSrcDoc->GetName(rRef.nTab, aTabName);
1854cdf0e10cSrcweir ScExternalDoubleRefToken aNewToken(nFileId, aTabName, static_cast<ScToken*>(pToken)->GetDoubleRef());
1855cdf0e10cSrcweir pNew->AddToken(aNewToken);
1856cdf0e10cSrcweir bTokenAdded = true;
1857cdf0e10cSrcweir }
1858cdf0e10cSrcweir break;
1859cdf0e10cSrcweir default:
1860cdf0e10cSrcweir ; // nothing
1861cdf0e10cSrcweir }
1862cdf0e10cSrcweir
1863cdf0e10cSrcweir if (!bTokenAdded)
1864cdf0e10cSrcweir pNew->AddToken(*pToken);
1865cdf0e10cSrcweir }
1866cdf0e10cSrcweir
1867cdf0e10cSrcweir // Make sure to pass the correctly-cased range name here.
1868cdf0e10cSrcweir maRefCache.setRangeNameTokens(nFileId, pRangeData->GetName(), pNew);
1869cdf0e10cSrcweir return pNew;
1870cdf0e10cSrcweir }
1871cdf0e10cSrcweir
refreshAllRefCells(sal_uInt16 nFileId)1872cdf0e10cSrcweir void ScExternalRefManager::refreshAllRefCells(sal_uInt16 nFileId)
1873cdf0e10cSrcweir {
1874cdf0e10cSrcweir RefCellMap::iterator itrFile = maRefCells.find(nFileId);
1875cdf0e10cSrcweir if (itrFile == maRefCells.end())
1876cdf0e10cSrcweir return;
1877cdf0e10cSrcweir
1878cdf0e10cSrcweir RefCellSet& rRefCells = itrFile->second;
1879cdf0e10cSrcweir for_each(rRefCells.begin(), rRefCells.end(), UpdateFormulaCell());
1880cdf0e10cSrcweir
1881cdf0e10cSrcweir ScViewData* pViewData = ScDocShell::GetViewData();
1882cdf0e10cSrcweir if (!pViewData)
1883cdf0e10cSrcweir return;
1884cdf0e10cSrcweir
1885cdf0e10cSrcweir ScTabViewShell* pVShell = pViewData->GetViewShell();
1886cdf0e10cSrcweir if (!pVShell)
1887cdf0e10cSrcweir return;
1888cdf0e10cSrcweir
1889cdf0e10cSrcweir // Repainting the grid also repaints the texts, but is there a better way
1890cdf0e10cSrcweir // to refresh texts?
1891cdf0e10cSrcweir pVShell->Invalidate(FID_REPAINT);
1892cdf0e10cSrcweir pVShell->PaintGrid();
1893cdf0e10cSrcweir }
1894cdf0e10cSrcweir
insertRefCell(sal_uInt16 nFileId,const ScAddress & rCell)1895cdf0e10cSrcweir void ScExternalRefManager::insertRefCell(sal_uInt16 nFileId, const ScAddress& rCell)
1896cdf0e10cSrcweir {
1897cdf0e10cSrcweir RefCellMap::iterator itr = maRefCells.find(nFileId);
1898cdf0e10cSrcweir if (itr == maRefCells.end())
1899cdf0e10cSrcweir {
1900cdf0e10cSrcweir RefCellSet aRefCells;
1901cdf0e10cSrcweir pair<RefCellMap::iterator, bool> r = maRefCells.insert(
1902cdf0e10cSrcweir RefCellMap::value_type(nFileId, aRefCells));
1903cdf0e10cSrcweir if (!r.second)
1904cdf0e10cSrcweir // insertion failed.
1905cdf0e10cSrcweir return;
1906cdf0e10cSrcweir
1907cdf0e10cSrcweir itr = r.first;
1908cdf0e10cSrcweir }
1909cdf0e10cSrcweir
1910cdf0e10cSrcweir ScBaseCell* pCell = mpDoc->GetCell(rCell);
1911cdf0e10cSrcweir if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
1912cdf0e10cSrcweir itr->second.insert(static_cast<ScFormulaCell*>(pCell));
1913cdf0e10cSrcweir }
1914cdf0e10cSrcweir
getSrcDocument(sal_uInt16 nFileId)1915cdf0e10cSrcweir ScDocument* ScExternalRefManager::getSrcDocument(sal_uInt16 nFileId)
1916cdf0e10cSrcweir {
1917cdf0e10cSrcweir if (!mpDoc->IsExecuteLinkEnabled())
1918cdf0e10cSrcweir return NULL;
1919cdf0e10cSrcweir
1920cdf0e10cSrcweir DocShellMap::iterator itrEnd = maDocShells.end();
1921cdf0e10cSrcweir DocShellMap::iterator itr = maDocShells.find(nFileId);
1922cdf0e10cSrcweir
1923cdf0e10cSrcweir if (itr != itrEnd)
1924cdf0e10cSrcweir {
1925cdf0e10cSrcweir // document already loaded.
1926cdf0e10cSrcweir
1927cdf0e10cSrcweir // TODO: Find out a way to access a document that's already open in
1928cdf0e10cSrcweir // memory and re-use that instance, instead of loading it from the
1929cdf0e10cSrcweir // disk again.
1930cdf0e10cSrcweir
1931cdf0e10cSrcweir SfxObjectShell* p = itr->second.maShell;
1932cdf0e10cSrcweir itr->second.maLastAccess = Time();
1933cdf0e10cSrcweir return static_cast<ScDocShell*>(p)->GetDocument();
1934cdf0e10cSrcweir }
1935cdf0e10cSrcweir
1936cdf0e10cSrcweir const String* pFile = getExternalFileName(nFileId);
1937cdf0e10cSrcweir if (!pFile)
1938cdf0e10cSrcweir // no file name associated with this ID.
1939cdf0e10cSrcweir return NULL;
1940cdf0e10cSrcweir
1941cdf0e10cSrcweir String aFilter;
1942cdf0e10cSrcweir SrcShell aSrcDoc;
1943cdf0e10cSrcweir aSrcDoc.maShell = loadSrcDocument(nFileId, aFilter);
1944cdf0e10cSrcweir if (!aSrcDoc.maShell.Is())
1945cdf0e10cSrcweir {
1946cdf0e10cSrcweir // source document could not be loaded.
1947cdf0e10cSrcweir return NULL;
1948cdf0e10cSrcweir }
1949cdf0e10cSrcweir
1950cdf0e10cSrcweir if (maDocShells.empty())
1951cdf0e10cSrcweir {
1952cdf0e10cSrcweir // If this is the first source document insertion, start up the timer.
1953cdf0e10cSrcweir maSrcDocTimer.Start();
1954cdf0e10cSrcweir }
1955cdf0e10cSrcweir
1956cdf0e10cSrcweir maDocShells.insert(DocShellMap::value_type(nFileId, aSrcDoc));
1957cdf0e10cSrcweir SfxObjectShell* p = aSrcDoc.maShell;
1958cdf0e10cSrcweir ScDocument* pSrcDoc = static_cast<ScDocShell*>(p)->GetDocument();
1959cdf0e10cSrcweir
1960cdf0e10cSrcweir SCTAB nTabCount = pSrcDoc->GetTableCount();
1961cdf0e10cSrcweir if (!maRefCache.isDocInitialized(nFileId) && nTabCount)
1962cdf0e10cSrcweir {
1963cdf0e10cSrcweir // Populate the cache with all table names in the source document.
1964cdf0e10cSrcweir vector<String> aTabNames;
1965cdf0e10cSrcweir aTabNames.reserve(nTabCount);
1966cdf0e10cSrcweir for (SCTAB i = 0; i < nTabCount; ++i)
1967cdf0e10cSrcweir {
1968cdf0e10cSrcweir String aName;
1969cdf0e10cSrcweir pSrcDoc->GetName(i, aName);
1970cdf0e10cSrcweir aTabNames.push_back(aName);
1971cdf0e10cSrcweir }
1972cdf0e10cSrcweir maRefCache.initializeDoc(nFileId, aTabNames);
1973cdf0e10cSrcweir }
1974cdf0e10cSrcweir return pSrcDoc;
1975cdf0e10cSrcweir }
1976cdf0e10cSrcweir
loadSrcDocument(sal_uInt16 nFileId,String & rFilter)1977cdf0e10cSrcweir SfxObjectShellRef ScExternalRefManager::loadSrcDocument(sal_uInt16 nFileId, String& rFilter)
1978cdf0e10cSrcweir {
1979cdf0e10cSrcweir const SrcFileData* pFileData = getExternalFileData(nFileId);
1980cdf0e10cSrcweir if (!pFileData)
1981cdf0e10cSrcweir return NULL;
1982cdf0e10cSrcweir
1983cdf0e10cSrcweir // Always load the document by using the path created from the relative
1984cdf0e10cSrcweir // path. If the referenced document is not there, simply exit. The
1985cdf0e10cSrcweir // original file name should be used only when the relative path is not
1986cdf0e10cSrcweir // given.
1987cdf0e10cSrcweir String aFile = pFileData->maFileName;
1988cdf0e10cSrcweir maybeCreateRealFileName(nFileId);
1989cdf0e10cSrcweir if (pFileData->maRealFileName.Len())
1990cdf0e10cSrcweir aFile = pFileData->maRealFileName;
1991cdf0e10cSrcweir
1992cdf0e10cSrcweir if (!isFileLoadable(aFile))
1993cdf0e10cSrcweir return NULL;
1994cdf0e10cSrcweir
1995cdf0e10cSrcweir String aOptions( pFileData->maFilterOptions );
1996cdf0e10cSrcweir if ( pFileData->maFilterName.Len() )
1997cdf0e10cSrcweir rFilter = pFileData->maFilterName; // don't overwrite stored filter with guessed filter
1998cdf0e10cSrcweir else
1999cdf0e10cSrcweir ScDocumentLoader::GetFilterName(aFile, rFilter, aOptions, true, false);
2000cdf0e10cSrcweir const SfxFilter* pFilter = ScDocShell::Factory().GetFilterContainer()->GetFilter4FilterName(rFilter);
2001cdf0e10cSrcweir
2002cdf0e10cSrcweir if (!pFileData->maRelativeName.Len())
2003cdf0e10cSrcweir {
2004cdf0e10cSrcweir // Generate a relative file path.
2005cdf0e10cSrcweir INetURLObject aBaseURL(getOwnDocumentName());
2006cdf0e10cSrcweir aBaseURL.insertName(OUString::createFromAscii("content.xml"));
2007cdf0e10cSrcweir
2008cdf0e10cSrcweir String aStr = URIHelper::simpleNormalizedMakeRelative(
2009cdf0e10cSrcweir aBaseURL.GetMainURL(INetURLObject::NO_DECODE), aFile);
2010cdf0e10cSrcweir
2011cdf0e10cSrcweir setRelativeFileName(nFileId, aStr);
2012cdf0e10cSrcweir }
2013cdf0e10cSrcweir
2014cdf0e10cSrcweir SfxItemSet* pSet = new SfxAllItemSet(SFX_APP()->GetPool());
2015cdf0e10cSrcweir if (aOptions.Len())
2016cdf0e10cSrcweir pSet->Put(SfxStringItem(SID_FILE_FILTEROPTIONS, aOptions));
2017cdf0e10cSrcweir
2018cdf0e10cSrcweir // make medium hidden to prevent assertion from progress bar
2019cdf0e10cSrcweir pSet->Put( SfxBoolItem( SID_HIDDEN, sal_True ) );
2020cdf0e10cSrcweir
2021cdf0e10cSrcweir auto_ptr<SfxMedium> pMedium(new SfxMedium(aFile, STREAM_STD_READ, false, pFilter, pSet));
2022cdf0e10cSrcweir if (pMedium->GetError() != ERRCODE_NONE)
2023cdf0e10cSrcweir return NULL;
2024cdf0e10cSrcweir
2025cdf0e10cSrcweir // To load encrypted documents with password, user interaction needs to be enabled.
2026cdf0e10cSrcweir pMedium->UseInteractionHandler(mbUserInteractionEnabled);
2027cdf0e10cSrcweir
2028cdf0e10cSrcweir ScDocShell* pNewShell = new ScDocShell(SFX_CREATE_MODE_INTERNAL);
2029cdf0e10cSrcweir SfxObjectShellRef aRef = pNewShell;
2030cdf0e10cSrcweir
2031cdf0e10cSrcweir // increment the recursive link count of the source document.
2032cdf0e10cSrcweir ScExtDocOptions* pExtOpt = mpDoc->GetExtDocOptions();
2033cdf0e10cSrcweir sal_uInt32 nLinkCount = pExtOpt ? pExtOpt->GetDocSettings().mnLinkCnt : 0;
2034cdf0e10cSrcweir ScDocument* pSrcDoc = pNewShell->GetDocument();
2035cdf0e10cSrcweir pSrcDoc->EnableExecuteLink(false); // to prevent circular access of external references.
2036cdf0e10cSrcweir pSrcDoc->EnableUndo(false);
2037cdf0e10cSrcweir pSrcDoc->EnableAdjustHeight(false);
2038cdf0e10cSrcweir
2039cdf0e10cSrcweir ScExtDocOptions* pExtOptNew = pSrcDoc->GetExtDocOptions();
2040cdf0e10cSrcweir if (!pExtOptNew)
2041cdf0e10cSrcweir {
2042cdf0e10cSrcweir pExtOptNew = new ScExtDocOptions;
2043cdf0e10cSrcweir pSrcDoc->SetExtDocOptions(pExtOptNew);
2044cdf0e10cSrcweir }
2045cdf0e10cSrcweir pExtOptNew->GetDocSettings().mnLinkCnt = nLinkCount + 1;
2046cdf0e10cSrcweir
2047cdf0e10cSrcweir pNewShell->DoLoad(pMedium.release());
2048cdf0e10cSrcweir
2049cdf0e10cSrcweir // with UseInteractionHandler, options may be set by dialog during DoLoad
2050cdf0e10cSrcweir String aNew = ScDocumentLoader::GetOptions(*pNewShell->GetMedium());
2051cdf0e10cSrcweir if (aNew.Len() && aNew != aOptions)
2052cdf0e10cSrcweir aOptions = aNew;
2053cdf0e10cSrcweir setFilterData(nFileId, rFilter, aOptions); // update the filter data, including the new options
2054cdf0e10cSrcweir
2055cdf0e10cSrcweir return aRef;
2056cdf0e10cSrcweir }
2057cdf0e10cSrcweir
isFileLoadable(const String & rFile) const2058cdf0e10cSrcweir bool ScExternalRefManager::isFileLoadable(const String& rFile) const
2059cdf0e10cSrcweir {
2060cdf0e10cSrcweir if (!rFile.Len())
2061cdf0e10cSrcweir return false;
2062cdf0e10cSrcweir
2063cdf0e10cSrcweir if (isOwnDocument(rFile))
2064cdf0e10cSrcweir return false;
2065cdf0e10cSrcweir
2066cdf0e10cSrcweir String aPhysical;
2067cdf0e10cSrcweir if (utl::LocalFileHelper::ConvertURLToPhysicalName(rFile, aPhysical) && aPhysical.Len())
2068cdf0e10cSrcweir {
2069cdf0e10cSrcweir // #i114504# try IsFolder/Exists only for file URLs
2070cdf0e10cSrcweir
2071cdf0e10cSrcweir if (utl::UCBContentHelper::IsFolder(rFile))
2072cdf0e10cSrcweir return false;
2073cdf0e10cSrcweir
2074cdf0e10cSrcweir return utl::UCBContentHelper::Exists(rFile);
2075cdf0e10cSrcweir }
2076cdf0e10cSrcweir else
2077cdf0e10cSrcweir return true; // for http and others, Exists doesn't work, but the URL can still be opened
2078cdf0e10cSrcweir }
2079cdf0e10cSrcweir
maybeLinkExternalFile(sal_uInt16 nFileId)2080cdf0e10cSrcweir void ScExternalRefManager::maybeLinkExternalFile(sal_uInt16 nFileId)
2081cdf0e10cSrcweir {
2082cdf0e10cSrcweir if (maLinkedDocs.count(nFileId))
2083cdf0e10cSrcweir // file alerady linked, or the link has been broken.
2084cdf0e10cSrcweir return;
2085cdf0e10cSrcweir
2086cdf0e10cSrcweir // Source document not linked yet. Link it now.
2087cdf0e10cSrcweir const String* pFileName = getExternalFileName(nFileId);
2088cdf0e10cSrcweir if (!pFileName)
2089cdf0e10cSrcweir return;
2090cdf0e10cSrcweir
2091cdf0e10cSrcweir String aFilter, aOptions;
2092cdf0e10cSrcweir const SrcFileData* pFileData = getExternalFileData(nFileId);
2093cdf0e10cSrcweir if (pFileData)
2094cdf0e10cSrcweir {
2095cdf0e10cSrcweir aFilter = pFileData->maFilterName;
2096cdf0e10cSrcweir aOptions = pFileData->maFilterOptions;
2097cdf0e10cSrcweir }
2098cdf0e10cSrcweir // If a filter was already set (for example, loading the cached table),
2099cdf0e10cSrcweir // don't call GetFilterName which has to access the source file.
2100cdf0e10cSrcweir if (!aFilter.Len())
2101cdf0e10cSrcweir ScDocumentLoader::GetFilterName(*pFileName, aFilter, aOptions, true, false);
2102cdf0e10cSrcweir sfx2::LinkManager* pLinkMgr = mpDoc->GetLinkManager();
2103cdf0e10cSrcweir ScExternalRefLink* pLink = new ScExternalRefLink(mpDoc, nFileId, aFilter);
2104cdf0e10cSrcweir DBG_ASSERT(pFileName, "ScExternalRefManager::insertExternalFileLink: file name pointer is NULL");
2105cdf0e10cSrcweir pLinkMgr->InsertFileLink(*pLink, OBJECT_CLIENT_FILE, *pFileName, &aFilter);
2106cdf0e10cSrcweir
2107cdf0e10cSrcweir pLink->SetDoReferesh(false);
2108cdf0e10cSrcweir pLink->Update();
2109cdf0e10cSrcweir pLink->SetDoReferesh(true);
2110cdf0e10cSrcweir
2111cdf0e10cSrcweir maLinkedDocs.insert(LinkedDocMap::value_type(nFileId, true));
2112cdf0e10cSrcweir }
2113cdf0e10cSrcweir
maybeCreateRealFileName(const String & rOwnDocName)2114cdf0e10cSrcweir void ScExternalRefManager::SrcFileData::maybeCreateRealFileName(const String& rOwnDocName)
2115cdf0e10cSrcweir {
2116cdf0e10cSrcweir if (!maRelativeName.Len())
2117cdf0e10cSrcweir // No relative path given. Nothing to do.
2118cdf0e10cSrcweir return;
2119cdf0e10cSrcweir
2120cdf0e10cSrcweir if (maRealFileName.Len())
2121cdf0e10cSrcweir // Real file name already created. Nothing to do.
2122cdf0e10cSrcweir return;
2123cdf0e10cSrcweir
2124cdf0e10cSrcweir // Formulate the absolute file path from the relative path.
2125cdf0e10cSrcweir const String& rRelPath = maRelativeName;
2126cdf0e10cSrcweir INetURLObject aBaseURL(rOwnDocName);
2127cdf0e10cSrcweir aBaseURL.insertName(OUString::createFromAscii("content.xml"));
2128cdf0e10cSrcweir bool bWasAbs = false;
2129cdf0e10cSrcweir maRealFileName = aBaseURL.smartRel2Abs(rRelPath, bWasAbs).GetMainURL(INetURLObject::NO_DECODE);
2130cdf0e10cSrcweir }
2131cdf0e10cSrcweir
maybeCreateRealFileName(sal_uInt16 nFileId)2132cdf0e10cSrcweir void ScExternalRefManager::maybeCreateRealFileName(sal_uInt16 nFileId)
2133cdf0e10cSrcweir {
2134cdf0e10cSrcweir if (nFileId >= maSrcFiles.size())
2135cdf0e10cSrcweir return;
2136cdf0e10cSrcweir
2137cdf0e10cSrcweir maSrcFiles[nFileId].maybeCreateRealFileName(getOwnDocumentName());
2138cdf0e10cSrcweir }
2139cdf0e10cSrcweir
getOwnDocumentName() const2140cdf0e10cSrcweir const String& ScExternalRefManager::getOwnDocumentName() const
2141cdf0e10cSrcweir {
2142cdf0e10cSrcweir SfxObjectShell* pShell = mpDoc->GetDocumentShell();
2143cdf0e10cSrcweir if (!pShell)
2144cdf0e10cSrcweir // This should not happen!
2145cdf0e10cSrcweir return EMPTY_STRING;
2146cdf0e10cSrcweir
2147cdf0e10cSrcweir SfxMedium* pMed = pShell->GetMedium();
2148cdf0e10cSrcweir if (!pMed)
2149cdf0e10cSrcweir return EMPTY_STRING;
2150cdf0e10cSrcweir
2151cdf0e10cSrcweir return pMed->GetName();
2152cdf0e10cSrcweir }
2153cdf0e10cSrcweir
isOwnDocument(const String & rFile) const2154cdf0e10cSrcweir bool ScExternalRefManager::isOwnDocument(const String& rFile) const
2155cdf0e10cSrcweir {
2156cdf0e10cSrcweir return getOwnDocumentName().Equals(rFile);
2157cdf0e10cSrcweir }
2158cdf0e10cSrcweir
convertToAbsName(String & rFile) const2159cdf0e10cSrcweir void ScExternalRefManager::convertToAbsName(String& rFile) const
2160cdf0e10cSrcweir {
2161cdf0e10cSrcweir SfxObjectShell* pDocShell = mpDoc->GetDocumentShell();
2162cdf0e10cSrcweir rFile = ScGlobal::GetAbsDocName(rFile, pDocShell);
2163cdf0e10cSrcweir }
2164cdf0e10cSrcweir
getExternalFileId(const String & rFile)2165cdf0e10cSrcweir sal_uInt16 ScExternalRefManager::getExternalFileId(const String& rFile)
2166cdf0e10cSrcweir {
2167cdf0e10cSrcweir vector<SrcFileData>::const_iterator itrBeg = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
2168cdf0e10cSrcweir vector<SrcFileData>::const_iterator itr = find_if(itrBeg, itrEnd, FindSrcFileByName(rFile));
2169cdf0e10cSrcweir if (itr != itrEnd)
2170cdf0e10cSrcweir {
2171cdf0e10cSrcweir size_t nId = distance(itrBeg, itr);
2172cdf0e10cSrcweir return static_cast<sal_uInt16>(nId);
2173cdf0e10cSrcweir }
2174cdf0e10cSrcweir
2175cdf0e10cSrcweir SrcFileData aData;
2176cdf0e10cSrcweir aData.maFileName = rFile;
2177cdf0e10cSrcweir maSrcFiles.push_back(aData);
2178cdf0e10cSrcweir return static_cast<sal_uInt16>(maSrcFiles.size() - 1);
2179cdf0e10cSrcweir }
2180cdf0e10cSrcweir
getExternalFileName(sal_uInt16 nFileId,bool bForceOriginal)2181cdf0e10cSrcweir const String* ScExternalRefManager::getExternalFileName(sal_uInt16 nFileId, bool bForceOriginal)
2182cdf0e10cSrcweir {
2183cdf0e10cSrcweir if (nFileId >= maSrcFiles.size())
2184cdf0e10cSrcweir return NULL;
2185cdf0e10cSrcweir
2186cdf0e10cSrcweir if (bForceOriginal)
2187cdf0e10cSrcweir return &maSrcFiles[nFileId].maFileName;
2188cdf0e10cSrcweir
2189cdf0e10cSrcweir maybeCreateRealFileName(nFileId);
2190cdf0e10cSrcweir
2191cdf0e10cSrcweir if (maSrcFiles[nFileId].maRealFileName.Len())
2192cdf0e10cSrcweir return &maSrcFiles[nFileId].maRealFileName;
2193cdf0e10cSrcweir else
2194cdf0e10cSrcweir return &maSrcFiles[nFileId].maFileName;
2195cdf0e10cSrcweir }
2196cdf0e10cSrcweir
hasExternalFile(sal_uInt16 nFileId) const2197cdf0e10cSrcweir bool ScExternalRefManager::hasExternalFile(sal_uInt16 nFileId) const
2198cdf0e10cSrcweir {
2199cdf0e10cSrcweir return nFileId < maSrcFiles.size();
2200cdf0e10cSrcweir }
2201cdf0e10cSrcweir
hasExternalFile(const String & rFile) const2202cdf0e10cSrcweir bool ScExternalRefManager::hasExternalFile(const String& rFile) const
2203cdf0e10cSrcweir {
2204cdf0e10cSrcweir vector<SrcFileData>::const_iterator itrBeg = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
2205cdf0e10cSrcweir vector<SrcFileData>::const_iterator itr = find_if(itrBeg, itrEnd, FindSrcFileByName(rFile));
2206cdf0e10cSrcweir return itr != itrEnd;
2207cdf0e10cSrcweir }
2208cdf0e10cSrcweir
getExternalFileData(sal_uInt16 nFileId) const2209cdf0e10cSrcweir const ScExternalRefManager::SrcFileData* ScExternalRefManager::getExternalFileData(sal_uInt16 nFileId) const
2210cdf0e10cSrcweir {
2211cdf0e10cSrcweir if (nFileId >= maSrcFiles.size())
2212cdf0e10cSrcweir return NULL;
2213cdf0e10cSrcweir
2214cdf0e10cSrcweir return &maSrcFiles[nFileId];
2215cdf0e10cSrcweir }
2216cdf0e10cSrcweir
getRealTableName(sal_uInt16 nFileId,const String & rTabName) const2217cdf0e10cSrcweir const String* ScExternalRefManager::getRealTableName(sal_uInt16 nFileId, const String& rTabName) const
2218cdf0e10cSrcweir {
2219cdf0e10cSrcweir return maRefCache.getRealTableName(nFileId, rTabName);
2220cdf0e10cSrcweir }
2221cdf0e10cSrcweir
getRealRangeName(sal_uInt16 nFileId,const String & rRangeName) const2222cdf0e10cSrcweir const String* ScExternalRefManager::getRealRangeName(sal_uInt16 nFileId, const String& rRangeName) const
2223cdf0e10cSrcweir {
2224cdf0e10cSrcweir return maRefCache.getRealRangeName(nFileId, rRangeName);
2225cdf0e10cSrcweir }
2226cdf0e10cSrcweir
2227cdf0e10cSrcweir template<typename MapContainer>
lcl_removeByFileId(sal_uInt16 nFileId,MapContainer & rMap)2228cdf0e10cSrcweir void lcl_removeByFileId(sal_uInt16 nFileId, MapContainer& rMap)
2229cdf0e10cSrcweir {
2230cdf0e10cSrcweir typename MapContainer::iterator itr = rMap.find(nFileId);
2231cdf0e10cSrcweir if (itr != rMap.end())
2232cdf0e10cSrcweir rMap.erase(itr);
2233cdf0e10cSrcweir }
2234cdf0e10cSrcweir
refreshNames(sal_uInt16 nFileId)2235cdf0e10cSrcweir void ScExternalRefManager::refreshNames(sal_uInt16 nFileId)
2236cdf0e10cSrcweir {
2237cdf0e10cSrcweir maRefCache.clearCache(nFileId);
2238cdf0e10cSrcweir lcl_removeByFileId(nFileId, maDocShells);
2239cdf0e10cSrcweir
2240cdf0e10cSrcweir if (maDocShells.empty())
2241cdf0e10cSrcweir maSrcDocTimer.Stop();
2242cdf0e10cSrcweir
2243cdf0e10cSrcweir // Update all cells containing names from this source document.
2244cdf0e10cSrcweir refreshAllRefCells(nFileId);
2245cdf0e10cSrcweir
2246cdf0e10cSrcweir notifyAllLinkListeners(nFileId, LINK_MODIFIED);
2247cdf0e10cSrcweir }
2248cdf0e10cSrcweir
breakLink(sal_uInt16 nFileId)2249cdf0e10cSrcweir void ScExternalRefManager::breakLink(sal_uInt16 nFileId)
2250cdf0e10cSrcweir {
2251cdf0e10cSrcweir // Turn all formula cells referencing this external document into static
2252cdf0e10cSrcweir // cells.
2253cdf0e10cSrcweir RefCellMap::iterator itrRefs = maRefCells.find(nFileId);
2254cdf0e10cSrcweir if (itrRefs != maRefCells.end())
2255cdf0e10cSrcweir {
2256cdf0e10cSrcweir // Make a copy because removing the formula cells below will modify
2257cdf0e10cSrcweir // the original container.
2258cdf0e10cSrcweir RefCellSet aSet = itrRefs->second;
2259cdf0e10cSrcweir for_each(aSet.begin(), aSet.end(), ConvertFormulaToStatic(mpDoc));
2260cdf0e10cSrcweir maRefCells.erase(nFileId);
2261cdf0e10cSrcweir }
2262cdf0e10cSrcweir
2263cdf0e10cSrcweir lcl_removeByFileId(nFileId, maDocShells);
2264cdf0e10cSrcweir
2265cdf0e10cSrcweir if (maDocShells.empty())
2266cdf0e10cSrcweir maSrcDocTimer.Stop();
2267cdf0e10cSrcweir
2268cdf0e10cSrcweir LinkedDocMap::iterator itr = maLinkedDocs.find(nFileId);
2269cdf0e10cSrcweir if (itr != maLinkedDocs.end())
2270cdf0e10cSrcweir itr->second = false;
2271cdf0e10cSrcweir
2272cdf0e10cSrcweir notifyAllLinkListeners(nFileId, LINK_BROKEN);
2273cdf0e10cSrcweir }
2274cdf0e10cSrcweir
switchSrcFile(sal_uInt16 nFileId,const String & rNewFile,const String & rNewFilter)2275cdf0e10cSrcweir void ScExternalRefManager::switchSrcFile(sal_uInt16 nFileId, const String& rNewFile, const String& rNewFilter)
2276cdf0e10cSrcweir {
2277cdf0e10cSrcweir maSrcFiles[nFileId].maFileName = rNewFile;
2278cdf0e10cSrcweir maSrcFiles[nFileId].maRelativeName.Erase();
2279cdf0e10cSrcweir maSrcFiles[nFileId].maRealFileName.Erase();
2280cdf0e10cSrcweir if (!maSrcFiles[nFileId].maFilterName.Equals(rNewFilter))
2281cdf0e10cSrcweir {
2282cdf0e10cSrcweir // Filter type has changed.
2283cdf0e10cSrcweir maSrcFiles[nFileId].maFilterName = rNewFilter;
2284cdf0e10cSrcweir maSrcFiles[nFileId].maFilterOptions.Erase();
2285cdf0e10cSrcweir }
2286cdf0e10cSrcweir refreshNames(nFileId);
2287cdf0e10cSrcweir }
2288cdf0e10cSrcweir
setRelativeFileName(sal_uInt16 nFileId,const String & rRelUrl)2289cdf0e10cSrcweir void ScExternalRefManager::setRelativeFileName(sal_uInt16 nFileId, const String& rRelUrl)
2290cdf0e10cSrcweir {
2291cdf0e10cSrcweir if (nFileId >= maSrcFiles.size())
2292cdf0e10cSrcweir return;
2293cdf0e10cSrcweir maSrcFiles[nFileId].maRelativeName = rRelUrl;
2294cdf0e10cSrcweir }
2295cdf0e10cSrcweir
setFilterData(sal_uInt16 nFileId,const String & rFilterName,const String & rOptions)2296cdf0e10cSrcweir void ScExternalRefManager::setFilterData(sal_uInt16 nFileId, const String& rFilterName, const String& rOptions)
2297cdf0e10cSrcweir {
2298cdf0e10cSrcweir if (nFileId >= maSrcFiles.size())
2299cdf0e10cSrcweir return;
2300cdf0e10cSrcweir maSrcFiles[nFileId].maFilterName = rFilterName;
2301cdf0e10cSrcweir maSrcFiles[nFileId].maFilterOptions = rOptions;
2302cdf0e10cSrcweir }
2303cdf0e10cSrcweir
clear()2304cdf0e10cSrcweir void ScExternalRefManager::clear()
2305cdf0e10cSrcweir {
2306cdf0e10cSrcweir DocShellMap::iterator itrEnd = maDocShells.end();
2307cdf0e10cSrcweir for (DocShellMap::iterator itr = maDocShells.begin(); itr != itrEnd; ++itr)
2308cdf0e10cSrcweir itr->second.maShell->DoClose();
2309cdf0e10cSrcweir
2310cdf0e10cSrcweir maDocShells.clear();
2311cdf0e10cSrcweir maSrcDocTimer.Stop();
2312cdf0e10cSrcweir }
2313cdf0e10cSrcweir
hasExternalData() const2314cdf0e10cSrcweir bool ScExternalRefManager::hasExternalData() const
2315cdf0e10cSrcweir {
2316cdf0e10cSrcweir return !maSrcFiles.empty();
2317cdf0e10cSrcweir }
2318cdf0e10cSrcweir
resetSrcFileData(const String & rBaseFileUrl)2319cdf0e10cSrcweir void ScExternalRefManager::resetSrcFileData(const String& rBaseFileUrl)
2320cdf0e10cSrcweir {
2321cdf0e10cSrcweir for (vector<SrcFileData>::iterator itr = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
2322cdf0e10cSrcweir itr != itrEnd; ++itr)
2323cdf0e10cSrcweir {
2324cdf0e10cSrcweir // Re-generate relative file name from the absolute file name.
2325cdf0e10cSrcweir String aAbsName = itr->maRealFileName;
2326cdf0e10cSrcweir if (!aAbsName.Len())
2327cdf0e10cSrcweir aAbsName = itr->maFileName;
2328cdf0e10cSrcweir
2329cdf0e10cSrcweir itr->maRelativeName = URIHelper::simpleNormalizedMakeRelative(
2330cdf0e10cSrcweir rBaseFileUrl, aAbsName);
2331cdf0e10cSrcweir }
2332cdf0e10cSrcweir }
2333cdf0e10cSrcweir
updateAbsAfterLoad()2334cdf0e10cSrcweir void ScExternalRefManager::updateAbsAfterLoad()
2335cdf0e10cSrcweir {
2336cdf0e10cSrcweir String aOwn( getOwnDocumentName() );
2337cdf0e10cSrcweir for (vector<SrcFileData>::iterator itr = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
2338cdf0e10cSrcweir itr != itrEnd; ++itr)
2339cdf0e10cSrcweir {
2340cdf0e10cSrcweir // update maFileName to the real file name,
2341cdf0e10cSrcweir // to be called when the original name is no longer needed (after CompileXML)
2342cdf0e10cSrcweir
2343cdf0e10cSrcweir itr->maybeCreateRealFileName( aOwn );
2344cdf0e10cSrcweir String aReal = itr->maRealFileName;
2345cdf0e10cSrcweir if (aReal.Len())
2346cdf0e10cSrcweir itr->maFileName = aReal;
2347cdf0e10cSrcweir }
2348cdf0e10cSrcweir }
2349cdf0e10cSrcweir
removeRefCell(ScFormulaCell * pCell)2350cdf0e10cSrcweir void ScExternalRefManager::removeRefCell(ScFormulaCell* pCell)
2351cdf0e10cSrcweir {
2352cdf0e10cSrcweir for_each(maRefCells.begin(), maRefCells.end(), RemoveFormulaCell(pCell));
2353cdf0e10cSrcweir }
2354cdf0e10cSrcweir
addLinkListener(sal_uInt16 nFileId,LinkListener * pListener)2355cdf0e10cSrcweir void ScExternalRefManager::addLinkListener(sal_uInt16 nFileId, LinkListener* pListener)
2356cdf0e10cSrcweir {
2357cdf0e10cSrcweir LinkListenerMap::iterator itr = maLinkListeners.find(nFileId);
2358cdf0e10cSrcweir if (itr == maLinkListeners.end())
2359cdf0e10cSrcweir {
2360cdf0e10cSrcweir pair<LinkListenerMap::iterator, bool> r = maLinkListeners.insert(
2361cdf0e10cSrcweir LinkListenerMap::value_type(nFileId, LinkListeners()));
2362cdf0e10cSrcweir if (!r.second)
2363cdf0e10cSrcweir {
2364cdf0e10cSrcweir DBG_ERROR("insertion of new link listener list failed");
2365cdf0e10cSrcweir return;
2366cdf0e10cSrcweir }
2367cdf0e10cSrcweir
2368cdf0e10cSrcweir itr = r.first;
2369cdf0e10cSrcweir }
2370cdf0e10cSrcweir
2371cdf0e10cSrcweir LinkListeners& rList = itr->second;
2372cdf0e10cSrcweir rList.insert(pListener);
2373cdf0e10cSrcweir }
2374cdf0e10cSrcweir
removeLinkListener(sal_uInt16 nFileId,LinkListener * pListener)2375cdf0e10cSrcweir void ScExternalRefManager::removeLinkListener(sal_uInt16 nFileId, LinkListener* pListener)
2376cdf0e10cSrcweir {
2377cdf0e10cSrcweir LinkListenerMap::iterator itr = maLinkListeners.find(nFileId);
2378cdf0e10cSrcweir if (itr == maLinkListeners.end())
2379cdf0e10cSrcweir // no listeners for a specified file.
2380cdf0e10cSrcweir return;
2381cdf0e10cSrcweir
2382cdf0e10cSrcweir LinkListeners& rList = itr->second;
2383cdf0e10cSrcweir rList.erase(pListener);
2384cdf0e10cSrcweir
2385cdf0e10cSrcweir if (rList.empty())
2386cdf0e10cSrcweir // No more listeners for this file. Remove its entry.
2387cdf0e10cSrcweir maLinkListeners.erase(itr);
2388cdf0e10cSrcweir }
2389cdf0e10cSrcweir
removeLinkListener(LinkListener * pListener)2390cdf0e10cSrcweir void ScExternalRefManager::removeLinkListener(LinkListener* pListener)
2391cdf0e10cSrcweir {
2392cdf0e10cSrcweir LinkListenerMap::iterator itr = maLinkListeners.begin(), itrEnd = maLinkListeners.end();
2393cdf0e10cSrcweir for (; itr != itrEnd; ++itr)
2394cdf0e10cSrcweir itr->second.erase(pListener);
2395cdf0e10cSrcweir }
2396cdf0e10cSrcweir
notifyAllLinkListeners(sal_uInt16 nFileId,LinkUpdateType eType)2397cdf0e10cSrcweir void ScExternalRefManager::notifyAllLinkListeners(sal_uInt16 nFileId, LinkUpdateType eType)
2398cdf0e10cSrcweir {
2399cdf0e10cSrcweir LinkListenerMap::iterator itr = maLinkListeners.find(nFileId);
2400cdf0e10cSrcweir if (itr == maLinkListeners.end())
2401cdf0e10cSrcweir // no listeners for a specified file.
2402cdf0e10cSrcweir return;
2403cdf0e10cSrcweir
2404cdf0e10cSrcweir LinkListeners& rList = itr->second;
2405cdf0e10cSrcweir for_each(rList.begin(), rList.end(), NotifyLinkListener(nFileId, eType));
2406cdf0e10cSrcweir }
2407cdf0e10cSrcweir
purgeStaleSrcDocument(sal_Int32 nTimeOut)2408cdf0e10cSrcweir void ScExternalRefManager::purgeStaleSrcDocument(sal_Int32 nTimeOut)
2409cdf0e10cSrcweir {
2410cdf0e10cSrcweir DocShellMap aNewDocShells;
2411cdf0e10cSrcweir DocShellMap::iterator itr = maDocShells.begin(), itrEnd = maDocShells.end();
2412cdf0e10cSrcweir for (; itr != itrEnd; ++itr)
2413cdf0e10cSrcweir {
2414cdf0e10cSrcweir // in 100th of a second.
2415cdf0e10cSrcweir sal_Int32 nSinceLastAccess = (Time() - itr->second.maLastAccess).GetTime();
2416cdf0e10cSrcweir if (nSinceLastAccess < nTimeOut)
2417cdf0e10cSrcweir aNewDocShells.insert(*itr);
2418cdf0e10cSrcweir }
2419cdf0e10cSrcweir maDocShells.swap(aNewDocShells);
2420cdf0e10cSrcweir
2421cdf0e10cSrcweir if (maDocShells.empty())
2422cdf0e10cSrcweir maSrcDocTimer.Stop();
2423cdf0e10cSrcweir }
2424cdf0e10cSrcweir
getMappedNumberFormat(sal_uInt16 nFileId,sal_uInt32 nNumFmt,ScDocument * pSrcDoc)2425cdf0e10cSrcweir sal_uInt32 ScExternalRefManager::getMappedNumberFormat(sal_uInt16 nFileId, sal_uInt32 nNumFmt, ScDocument* pSrcDoc)
2426cdf0e10cSrcweir {
2427cdf0e10cSrcweir NumFmtMap::iterator itr = maNumFormatMap.find(nFileId);
2428cdf0e10cSrcweir if (itr == maNumFormatMap.end())
2429cdf0e10cSrcweir {
2430cdf0e10cSrcweir // Number formatter map is not initialized for this external document.
2431cdf0e10cSrcweir pair<NumFmtMap::iterator, bool> r = maNumFormatMap.insert(
2432cdf0e10cSrcweir NumFmtMap::value_type(nFileId, SvNumberFormatterMergeMap()));
2433cdf0e10cSrcweir
2434cdf0e10cSrcweir if (!r.second)
2435cdf0e10cSrcweir // insertion failed.
2436cdf0e10cSrcweir return nNumFmt;
2437cdf0e10cSrcweir
2438cdf0e10cSrcweir itr = r.first;
2439cdf0e10cSrcweir mpDoc->GetFormatTable()->MergeFormatter( *pSrcDoc->GetFormatTable());
2440cdf0e10cSrcweir SvNumberFormatterMergeMap aMap = mpDoc->GetFormatTable()->ConvertMergeTableToMap();
2441cdf0e10cSrcweir itr->second.swap(aMap);
2442cdf0e10cSrcweir }
2443cdf0e10cSrcweir const SvNumberFormatterMergeMap& rMap = itr->second;
2444cdf0e10cSrcweir SvNumberFormatterMergeMap::const_iterator itrNumFmt = rMap.find(nNumFmt);
2445cdf0e10cSrcweir if (itrNumFmt != rMap.end())
2446cdf0e10cSrcweir // mapped value found.
2447cdf0e10cSrcweir return itrNumFmt->second;
2448cdf0e10cSrcweir
2449cdf0e10cSrcweir return nNumFmt;
2450cdf0e10cSrcweir }
2451cdf0e10cSrcweir
IMPL_LINK(ScExternalRefManager,TimeOutHdl,AutoTimer *,pTimer)2452cdf0e10cSrcweir IMPL_LINK(ScExternalRefManager, TimeOutHdl, AutoTimer*, pTimer)
2453cdf0e10cSrcweir {
2454cdf0e10cSrcweir if (pTimer == &maSrcDocTimer)
2455cdf0e10cSrcweir purgeStaleSrcDocument(SRCDOC_LIFE_SPAN);
2456cdf0e10cSrcweir
2457cdf0e10cSrcweir return 0;
2458cdf0e10cSrcweir }
2459cdf0e10cSrcweir
2460