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