1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #pragma once
21 
22 #include "address.hxx"
23 #include "document.hxx"
24 #include <sfx2/objsh.hxx>
25 #include <sfx2/lnkbase.hxx>
26 #include <tools/time.hxx>
27 #include <vcl/timer.hxx>
28 #include <svl/zforlist.hxx>
29 #include <svl/lstner.hxx>
30 #include "types.hxx"
31 #include "rangelst.hxx"
32 #include <osl/mutex.hxx>
33 #include <formula/types.hxx>
34 #include <tools/solar.h>
35 
36 #include <memory>
37 #include <unordered_map>
38 #include <unordered_set>
39 #include <vector>
40 #include <set>
41 #include <o3tl/sorted_vector.hxx>
42 #include <formula/ExternalReferenceHelper.hxx>
43 
44 class ScTokenArray;
45 namespace weld { class Window; }
46 
47 class ScFormulaCell;
48 
49 namespace sc {
50 
51 class ColumnSpanSet;
52 
53 }
54 
55 class ScExternalRefLink final : public ::sfx2::SvBaseLink
56 {
57 public:
58     ScExternalRefLink(ScDocument& rDoc, sal_uInt16 nFileId);
59     virtual ~ScExternalRefLink() override;
60 
61     virtual void Closed() override;
62     virtual ::sfx2::SvBaseLink::UpdateResult DataChanged(
63         const OUString& rMimeType, const css::uno::Any & rValue) override;
64     virtual void Edit(weld::Window* pParent, const Link<SvBaseLink&,void>& rEndEditHdl) override;
65 
66     void SetDoRefresh(bool b);
67 
68 private:
69     ScExternalRefLink() = delete;
70     ScExternalRefLink(const ScExternalRefLink&) = delete;
71 
72     sal_uInt16  mnFileId;
73     ScDocument& mrDoc;
74     bool        mbDoRefresh;
75 };
76 
77 /**
78  * Cache table for external reference data.
79  */
80 class ScExternalRefCache
81 {
82 public:
83     typedef ::formula::FormulaTokenRef          TokenRef;
84     typedef std::shared_ptr<ScTokenArray>   TokenArrayRef;
85 
86     struct TableName
87     {
88         OUString maUpperName;
89         OUString maRealName;
90 
91         explicit TableName(const OUString& rUpper, const OUString& rReal);
92     };
93 
94     struct CellFormat
95     {
96         bool      mbIsSet;
97         SvNumFormatType mnType;
98         sal_uLong mnIndex;
99 
100         explicit CellFormat();
101     };
102 
103 private:
104     /** individual cell within cached external ref table. */
105     struct Cell
106     {
107         TokenRef   mxToken;
108         sal_uLong  mnFmtIndex;
109     };
110     typedef std::unordered_map<SCCOL, Cell>            RowDataType;
111     typedef std::unordered_map<SCROW, RowDataType>     RowsDataType;
112 
113 public:
114     /**
115      * Represents a single cached table in an external document.  It only
116      * stores non-empty cells; empty cells should never be stored in the data
117      * cache. Instead, cached ranges should be used to determine whether or
118      * not a cell is empty or needs fetching from the source document.  If a
119      * cell's value is not stored but its address is within the cached ranges,
120      * that cell is already queried in the source document and we know it's
121      * empty.
122      */
123     class Table
124     {
125     public:
126 
127         Table();
128         ~Table();
129 
130         void clear();
131 
132         /**
133          * Add cell value to the cache.
134          *
135          * @param bSetCacheRange if true, mark this cell 'cached'.  This is
136          *                       false _only when_ adding a range of cell
137          *                       values, for performance reasons.
138          */
139         SC_DLLPUBLIC void setCell(SCCOL nCol, SCROW nRow, TokenRef const & pToken, sal_uLong nFmtIndex = 0, bool bSetCacheRange = true);
140         SC_DLLPUBLIC TokenRef getCell(SCCOL nCol, SCROW nRow, sal_uInt32* pnFmtIndex = nullptr) const;
141         bool hasRow( SCROW nRow ) const;
142         /** Set/clear referenced status flag only if current status is not
143             REFERENCED_PERMANENT. */
144         void setReferenced( bool bReferenced );
145         bool isReferenced() const;
146         /// Obtain a sorted vector of rows.
147         void getAllRows(::std::vector<SCROW>& rRows, SCROW nLow = 0, SCROW nHigh = MAXROW) const;
148         /// Returns the half-open range of used rows in this table. Returns [0,0) if table is empty.
149         SC_DLLPUBLIC ::std::pair< SCROW, SCROW > getRowRange() const;
150         /// Obtain a sorted vector of columns.
151         void getAllCols(SCROW nRow, ::std::vector<SCCOL>& rCols, SCCOL nLow = 0, SCCOL nHigh = MAXCOL) const;
152         /// Returns the half-open range of used columns in the specified row. Returns [0,0) if row is empty.
153         SC_DLLPUBLIC ::std::pair< SCCOL, SCCOL > getColRange( SCROW nRow ) const;
154         void getAllNumberFormats(::std::vector<sal_uInt32>& rNumFmts) const;
155         bool isRangeCached(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const;
156 
157         void setCachedCell(SCCOL nCol, SCROW nRow);
158         void setCachedCellRange(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2);
159 
160         /**
161          * Call this to mark the entire table "cached".  This will prevent all
162          * future attempts to access the source document even when non-cached
163          * cells are queried.  In such case, non-cached cells are treated as
164          * empty cells.  Useful when loading a document with own external data
165          * cache.
166          */
167         SC_DLLPUBLIC void setWholeTableCached();
168     private:
169         bool isInCachedRanges(SCCOL nCol, SCROW nRow) const;
170         TokenRef getEmptyOrNullToken(SCCOL nCol, SCROW nRow) const;
171 
172     private:
173         /** Data cache */
174         RowsDataType                    maRows;
175         /** Collection of individual cached ranges.  The table ranges are
176          *  not used & always zero. */
177         ScRangeList                     maCachedRanges;
178         bool                            mbReferenced;
179     };
180 
181     typedef std::shared_ptr<Table> TableTypeRef;
182     typedef std::unordered_map< OUString, size_t>
183         TableNameIndexMap;
184 
185     ScExternalRefCache();
186     ~ScExternalRefCache();
187 
188     const OUString* getRealTableName(sal_uInt16 nFileId, const OUString& rTabName) const;
189     const OUString* getRealRangeName(sal_uInt16 nFileId, const OUString& rRangeName) const;
190 
191     /**
192      * Get a cached cell data at specified cell location.
193      *
194      * @param nFileId file ID of an external document
195      * @param rTabName sheet name
196      * @param nCol
197      * @param nRow
198      *
199      * @return pointer to the token instance in the cache.
200      */
201     ScExternalRefCache::TokenRef getCellData(
202         sal_uInt16 nFileId, const OUString& rTabName, SCCOL nCol, SCROW nRow, sal_uInt32* pnFmtIndex);
203 
204     /**
205      * Get a cached cell range data.
206      *
207      * @return a new token array instance.  Note that <i>the caller must
208      *         manage the life cycle of the returned instance</i>, which is
209      *         guaranteed if the TokenArrayRef is properly used...
210      */
211     ScExternalRefCache::TokenArrayRef getCellRangeData(
212         sal_uInt16 nFileId, const OUString& rTabName, const ScRange& rRange);
213 
214     ScExternalRefCache::TokenArrayRef getRangeNameTokens(sal_uInt16 nFileId, const OUString& rName);
215     void setRangeNameTokens(sal_uInt16 nFileId, const OUString& rName, TokenArrayRef pArray);
216     bool isValidRangeName(sal_uInt16 nFileId, const OUString& rName) const;
217     void setRangeName(sal_uInt16 nFileId, const OUString& rName);
218 
219     void setCellData(sal_uInt16 nFileId, const OUString& rTabName,
220                      SCCOL nCol, SCROW nRow, TokenRef const & pToken, sal_uLong nFmtIndex);
221 
222     struct SingleRangeData
223     {
224         /** This name must be in upper-case. */
225         OUString maTableName;
226         ScMatrixRef mpRangeData;
227     };
228     void setCellRangeData(sal_uInt16 nFileId, const ScRange& rRange, const ::std::vector<SingleRangeData>& rData,
229                           const TokenArrayRef& pArray);
230 
231     bool isDocInitialized(sal_uInt16 nFileId);
232     void initializeDoc(sal_uInt16 nFileId, const ::std::vector<OUString>& rTabNames, const OUString& rBaseName);
233     OUString getTableName(sal_uInt16 nFileId, size_t nCacheId) const;
234     void getAllTableNames(sal_uInt16 nFileId, ::std::vector<OUString>& rTabNames) const;
235     SCTAB getTabSpan( sal_uInt16 nFileId, const OUString& rStartTabName, const OUString& rEndTabName ) const;
236     void getAllNumberFormats(::std::vector<sal_uInt32>& rNumFmts) const;
237 
238     /**
239      * Set all tables of a document as referenced, used only during
240      * store-to-file.
241      * @returns <TRUE/> if ALL tables of ALL documents are marked.
242      */
243     bool setCacheDocReferenced( sal_uInt16 nFileId );
244 
245     /**
246      * Set a table as referenced, used only during store-to-file.
247      * @returns <TRUE/> if ALL tables of ALL documents are marked.
248      */
249     bool setCacheTableReferenced( sal_uInt16 nFileId, const OUString& rTabName, size_t nSheets );
250     void setAllCacheTableReferencedStati( bool bReferenced );
areAllCacheTablesReferenced() const251     bool areAllCacheTablesReferenced() const { return maReferenced.mbAllReferenced;}
252 
253     /**
254      * Collect all cached non-empty cell positions, inferred directly from the
255      * cached data, not the cached range metadata stored separately in the
256      * Table.
257      */
258     void getAllCachedDataSpans( const ScDocument& rSrcDoc, sal_uInt16 nFileId, sc::ColumnSpanSet& rSet ) const;
259 
260     bool getSrcDocTable( const ScDocument& rSrcDoc, const OUString& rTabName, SCTAB& rTab, sal_uInt16 nFileId ) const;
261 
262 private:
263     struct ReferencedStatus
264     {
265         struct DocReferenced
266         {
267             ::std::vector<bool> maTables;
268             bool                mbAllTablesReferenced;
269             // Initially, documents have no tables but all referenced.
DocReferencedScExternalRefCache::ReferencedStatus::DocReferenced270             DocReferenced() : mbAllTablesReferenced(true) {}
271         };
272         typedef ::std::vector<DocReferenced> DocReferencedVec;
273 
274         DocReferencedVec maDocs;
275         bool             mbAllReferenced;
276 
277                     ReferencedStatus();
278         void        reset( size_t nDocs );
279         void        checkAllDocs();
280 
281     } maReferenced;
282     void addCacheTableToReferenced( sal_uInt16 nFileId, size_t nIndex );
283     void addCacheDocToReferenced( sal_uInt16 nFileId );
284 public:
285 
286     ScExternalRefCache::TableTypeRef getCacheTable(sal_uInt16 nFileId, size_t nTabIndex) const;
287     ScExternalRefCache::TableTypeRef getCacheTable(sal_uInt16 nFileId, const OUString& rTabName, bool bCreateNew,
288             size_t* pnIndex, const OUString* pExtUrl);
289 
290     /**
291      * Clear all caches including the cache tables.
292      */
293     void clearCache(sal_uInt16 nFileId);
294 
295     /**
296      * Clear all caches but keep the tables.  All cache tables will be empty
297      * after the call, but the tables will not be removed.
298      */
299     void clearCacheTables(sal_uInt16 nFileId);
300 
301     // Get the fake doc used to pass to methods that need an ScDocument in order to do row/col validation
getFakeDoc() const302     const ScDocument* getFakeDoc() const { return mxFakeDoc.get(); }
303 
304 private:
305     struct RangeHash
306     {
operator ()ScExternalRefCache::RangeHash307         size_t operator()(const ScRange& rRange) const
308         {
309             const ScAddress& s = rRange.aStart;
310             const ScAddress& e = rRange.aEnd;
311             size_t hash = 17;
312             hash = hash * 37 + s.Tab();
313             hash = hash * 37 + s.Col();
314             hash = hash * 37 + s.Row();
315             hash = hash * 37 + e.Tab();
316             hash = hash * 37 + e.Col();
317             hash = hash * 37 + e.Row();
318             return hash;
319         }
320     };
321 
322     typedef std::unordered_map<OUString, TokenArrayRef> RangeNameMap;
323     typedef std::unordered_map<ScRange, TokenArrayRef, RangeHash> RangeArrayMap;
324     typedef std::unordered_map<OUString, OUString> NamePairMap;
325 
326     /** Represents data cached for a single external document. */
327     struct DocItem
328     {
329         /** The raw cache tables. */
330         ::std::vector<TableTypeRef> maTables;
331         /** Table name list in correct order, in both upper- and real-case. */
332         ::std::vector<TableName>    maTableNames;
333         /** Table name to index map.  The names must be stored upper-case. */
334         TableNameIndexMap           maTableNameIndex;
335         /** Range name cache. */
336         RangeNameMap                maRangeNames;
337         /** Token array cache for cell ranges. */
338         RangeArrayMap               maRangeArrays;
339         /** Upper- to real-case mapping for range names. */
340         NamePairMap                 maRealRangeNameMap;
341 
342         /** Either the base name that was stored as sheet name for CSV files if
343             sheet name is Sheet1, or Sheet1 name if sheet name is base name.
344          */
345         OUString                    maSingleTableNameAlias;
346 
347         bool mbInitFromSource;
348 
DocItemScExternalRefCache::DocItem349         DocItem() : mbInitFromSource(false) {}
350 
351         TableNameIndexMap::const_iterator findTableNameIndex( const OUString& rTabName ) const;
352         bool getTableDataIndex( const OUString& rTabName, size_t& rIndex ) const;
353         bool getSingleTableNameAlternative( OUString& rTabName ) const;
354     };
355     typedef std::unordered_map<sal_uInt16, DocItem>  DocDataType;
356     DocItem* getDocItem(sal_uInt16 nFileId) const;
357 
358 private:
359     mutable osl::Mutex maMtxDocs;
360     mutable DocDataType maDocs;
361     ScDocumentUniquePtr mxFakeDoc; // just to have something to pass to the methods that need to validate columns/rows
362 };
363 
364 class SC_DLLPUBLIC ScExternalRefManager final : public formula::ExternalReferenceHelper, public SfxListener
365 {
366 public:
367 
368     typedef std::set<ScFormulaCell*>                      RefCellSet;
369     typedef std::unordered_map<sal_uInt16, RefCellSet>         RefCellMap;
370 
371     enum LinkUpdateType { LINK_MODIFIED, LINK_BROKEN };
372 
373     /**
374      * Base class for objects that need to listen to link updates.  When a
375      * link to a certain external file is updated, the notify() method gets
376      * called.
377      */
378     class SAL_DLLPRIVATE LinkListener
379     {
380     public:
381         LinkListener();
382         virtual ~LinkListener() COVERITY_NOEXCEPT_FALSE = 0;
383         virtual void notify(sal_uInt16 nFileId, LinkUpdateType eType) = 0;
384     };
385 
386     /**
387      * Use this guard when performing something from the API that might query
388      * values from external references.  Interpreting formula strings is one
389      * such example.
390      */
391     class SC_DLLPUBLIC ApiGuard
392     {
393     public:
394         ApiGuard(const ScDocument& rDoc);
395         ~ApiGuard();
396     private:
397         ScExternalRefManager* mpMgr;
398         bool mbOldInteractionEnabled;
399     };
400 
401 private:
402     /** Shell instance for a source document. */
403     struct SrcShell
404     {
405         SfxObjectShellRef   maShell;
406         tools::Time         maLastAccess;
407 
SrcShellScExternalRefManager::SrcShell408         SrcShell() : maLastAccess( tools::Time::SYSTEM ) {}
409     };
410 
411     typedef std::unordered_map<sal_uInt16, SrcShell>           DocShellMap;
412     typedef std::unordered_map<sal_uInt16, bool>               LinkedDocMap;
413 
414     typedef std::unordered_map<sal_uInt16, SvNumberFormatterMergeMap> NumFmtMap;
415 
416     typedef o3tl::sorted_vector<LinkListener*>                     LinkListeners;
417     typedef std::unordered_map<sal_uInt16, LinkListeners>          LinkListenerMap;
418 
419 public:
420     /** Source document meta-data container. */
421     struct SAL_DLLPRIVATE SrcFileData
422     {
423         OUString maFileName;      /// original file name as loaded from the file.
424         OUString maRealFileName;  /// file name created from the relative name.
425         OUString maRelativeName;
426         OUString maFilterName;
427         OUString maFilterOptions;
428 
429         void maybeCreateRealFileName(const OUString& rOwnDocName);
430     };
431 
432 public:
433     explicit ScExternalRefManager(ScDocument& rDoc);
434     virtual ~ScExternalRefManager() override;
435 
436     virtual OUString getCacheTableName(sal_uInt16 nFileId, size_t nTabIndex) const override;
437 
438     /**
439      * Get a cache table instance for specified table and table index.  Unlike
440      * the other method that takes a table name, this method does not create a
441      * new table when a table is not available for specified index.
442      *
443      * @param nFileId file ID
444      * @param nTabIndex cache table index
445      *
446      * @return shared_ptr to the cache table instance
447      */
448     ScExternalRefCache::TableTypeRef getCacheTable(sal_uInt16 nFileId, size_t nTabIndex) const;
449 
450     /**
451      * Get a cache table instance for specified file and table name.  If the
452      * table instance is not already present, it'll instantiate a new one and
453      * append it to the end of the table array.  <I>It's important to be
454      * aware of this fact especially for multi-table ranges for which
455      * table orders are critical.</I>
456      *
457      * Excel filter calls this method to populate the cache table from the
458      * XCT/CRN records. ODF import calls it for cached tables for external
459      * references.
460      *
461      * @param nFileId file ID
462      * @param rTabName table name
463      * @param bCreateNew if true, create a new table instance if it's not
464      *                   already present.  If false, it returns NULL if the
465      *                   specified table's cache doesn't exist.
466      * @param pnIndex if non-NULL pointer is passed, it stores the internal
467      *                index of a cache table instance.
468      * @param pExtUrl if non-NULL and bCreateNew==true, the base name will be
469      *                propagated as an alias for the first table (and removed
470      *                later if further tables are created).
471      *
472      * @return shared_ptr to the cache table instance
473      */
474     ScExternalRefCache::TableTypeRef getCacheTable(sal_uInt16 nFileId, const OUString& rTabName, bool bCreateNew,
475             size_t* pnIndex = nullptr, const OUString* pExtUrl = nullptr);
476 
477     /** Returns a vector containing all (real) table names and cache tables of
478         the specified file.
479 
480         The index in the returned vector corresponds to the table index used to
481         access the cache table, e.g. in getCacheTable().
482      */
483     void getAllCachedTableNames(sal_uInt16 nFileId, ::std::vector<OUString>& rTabNames) const;
484 
485     /**
486      * Get the span (distance+sign(distance)) of two sheets of a specified
487      * file.
488      *
489      * @param nFileId file ID
490      * @param rStartTabName name of first sheet (sheet1)
491      * @param rEndTabName name of second sheet (sheet2)
492      *
493      * @return span
494      *         1 if sheet2 == sheet1
495      *      >  1 if sheet2 > sheet1
496      *      < -1 if sheet2 < sheet1
497      *        -1 if nFileId or rStartTabName not found
498      *         0 if rEndTabName not found
499      */
500     SCTAB getCachedTabSpan(
501         sal_uInt16 nFileId, const OUString& rStartTabName, const OUString& rEndTabName) const;
502 
503     /**
504      * Get all unique number format indices that are used in the cache tables.
505      * The retrieved indices are sorted in ascending order.
506      *
507      * @param rNumFmts (reference) all unique number format indices.
508      */
509     void getAllCachedNumberFormats(::std::vector<sal_uInt32>& rNumFmts) const;
510 
511     sal_uInt16 getExternalFileCount() const;
512 
513     /**
514      * Mark all tables as referenced that are used by any LinkListener, used
515      * only during store-to-file.
516      */
517     void markUsedByLinkListeners();
518 
519     void markUsedExternalRefCells();
520 
521     /**
522      * Set a table as referenced, used only during store-to-file.
523      * @returns <TRUE/> if ALL tables of ALL external documents are marked.
524      */
525     bool setCacheTableReferenced( sal_uInt16 nFileId, const OUString& rTabName, size_t nSheets );
526     void setAllCacheTableReferencedStati( bool bReferenced );
527 
528     /**
529      * @returns <TRUE/> if setAllCacheTableReferencedStati(false) was called,
530      * <FALSE/> if setAllCacheTableReferencedStati(true) was called.
531      */
isInReferenceMarking() const532     bool isInReferenceMarking() const   { return mbInReferenceMarking; }
533 
534     void storeRangeNameTokens(sal_uInt16 nFileId, const OUString& rName, const ScTokenArray& rArray);
535 
536     ScExternalRefCache::TokenRef getSingleRefToken(
537         sal_uInt16 nFileId, const OUString& rTabName, const ScAddress& rCell,
538         const ScAddress* pCurPos, SCTAB* pTab, ScExternalRefCache::CellFormat* pFmt = nullptr);
539 
540     /**
541      * Get an array of tokens that consist of the specified external cell
542      * range.
543      *
544      * @param nFileId file ID for an external document
545      * @param rTabName referenced sheet name
546      * @param rRange referenced cell range
547      * @param pCurPos current cursor position to keep track of cells that
548      *                reference an external data.
549      *
550      * @return shared_ptr to a token array instance.  <i>The caller must not
551      *         delete the instance returned by this method.</i>
552      */
553     ScExternalRefCache::TokenArrayRef getDoubleRefTokens(
554         sal_uInt16 nFileId, const OUString& rTabName, const ScRange& rRange, const ScAddress* pCurPos);
555 
556     /**
557      * Get an array of tokens corresponding with a specified name in a
558      * specified file.
559      *
560      * @param pCurPos current cell address where this name token is used.
561      *                This is purely to keep track of all cells containing
562      *                external names for refreshing purposes.  If this is
563      *                NULL, then the cell will not be added to the list.
564      *
565      * @return shared_ptr to array of tokens composing the name
566      */
567     ScExternalRefCache::TokenArrayRef getRangeNameTokens(
568         sal_uInt16 nFileId, const OUString& rName, const ScAddress* pCurPos = nullptr);
569 
570     bool isValidRangeName(sal_uInt16 nFileId, const OUString& rName);
571 
572     OUString getOwnDocumentName() const;
573     bool isOwnDocument(std::u16string_view rFile) const;
574 
575     /**
576      * Takes a flat file name, and convert it to an absolute URL path.  An
577      * absolute URL path begins with 'file:///.
578      *
579      * @param rFile file name to convert
580      */
581     void convertToAbsName(OUString& rFile) const;
582     sal_uInt16 getExternalFileId(const OUString& rFile);
583 
584     /**
585      * It returns a pointer to the name of the URI associated with a given
586      * external file ID.  In case the original document has moved, it returns
587      * a URI adjusted for the relocation.
588      *
589      * @param nFileId file ID for an external document
590      * @param bForceOriginal If true, it always returns the original document
591      *                       URI even if the referring document has relocated.
592      *                       If false, it returns a URI adjusted for
593      *                       relocated document.
594      *
595      * @return const OUString* external document URI.
596      */
597     const OUString* getExternalFileName(sal_uInt16 nFileId, bool bForceOriginal = false);
598 
599     /**
600      * Reindex external file references to skip unused files, if skipping is enabled.
601      */
602     sal_uInt16 convertFileIdToUsedFileId(sal_uInt16 nFileId);
603     void setSkipUnusedFileIds(std::vector<sal_uInt16>& pExternFileIds);
604     void disableSkipUnusedFileIds();
605 
606     /**
607      * Get all cached external file names as an array. Array indices of the
608      * returned name array correspond with external file ID's.
609      */
610     std::vector<OUString> getAllCachedExternalFileNames() const;
611 
612     bool hasExternalFile(sal_uInt16 nFileId) const;
613     bool hasExternalFile(const OUString& rFile) const;
614     const SrcFileData* getExternalFileData(sal_uInt16 nFileId) const;
615 
616     const OUString* getRealTableName(sal_uInt16 nFileId, const OUString& rTabName) const;
617     const OUString* getRealRangeName(sal_uInt16 nFileId, const OUString& rRangeName) const;
618     void clearCache(sal_uInt16 nFileId);
619     bool refreshSrcDocument(sal_uInt16 nFileId);
620     void breakLink(sal_uInt16 nFileId);
621     void switchSrcFile(sal_uInt16 nFileId, const OUString& rNewFile, const OUString& rNewFilter);
622 
623     /**
624      * Set a relative file path for the specified file ID.  Note that the
625      * caller must ensure that the passed URL is a valid relative URL.
626      *
627      * @param nFileId file ID for an external document
628      * @param rRelUrl relative URL
629      */
630     void setRelativeFileName(sal_uInt16 nFileId, const OUString& rRelUrl);
631 
632     /**
633      * Set the filter name and options if any for a given source document.
634      * These values get reset when the source document ever gets reloaded.
635      *
636      * @param nFileId
637      * @param rFilterName
638      * @param rOptions
639      */
640     void setFilterData(sal_uInt16 nFileId, const OUString& rFilterName, const OUString& rOptions);
641 
642     void clear();
643 
644     bool hasExternalData() const;
645 
646     /**
647      * Re-generates relative names for all stored source files.  This is
648      * necessary when exporting to an ods document, to ensure that all source
649      * files have their respective relative names for xlink:href export.
650      *
651      * @param rBaseFileUrl Absolute URL of the content.xml fragment of the
652      *                     document being exported.
653      */
654     void resetSrcFileData(const OUString& rBaseFileUrl);
655 
656     /**
657      * Replace the original URL with the real URL that was generated from the relative URL.
658      */
659     void updateAbsAfterLoad();
660 
661     /**
662      * Stop tracking a specific formula cell.
663      *
664      * @param pCell pointer to cell that formerly contained external
665      *              reference.
666      */
667     void removeRefCell(ScFormulaCell* pCell);
668 
669     /**
670      * Register a new link listener to a specified external document.  Note
671      * that the caller is responsible for managing the life cycle of the
672      * listener object.
673      */
674     void addLinkListener(sal_uInt16 nFileId, LinkListener* pListener);
675 
676     /**
677      * Remove an existing link listener.  Note that removing a listener
678      * pointer here does not delete the listener object instance.
679      */
680     void removeLinkListener(sal_uInt16 nFileId, LinkListener* pListener);
681 
682     void removeLinkListener(LinkListener* pListener);
683 
684     /**
685      * Notify all listeners that are listening to a specified external
686      * document.
687      *
688      * @param nFileId file ID for an external document.
689      */
690     void notifyAllLinkListeners(sal_uInt16 nFileId, LinkUpdateType eType);
691 
692     /**
693      * Check if the file specified by the path is a legitimate file that
694      * exists & can be loaded.
695      */
696     bool isFileLoadable(const OUString& rFile) const;
697 
698     virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
699 
700     /**
701      * If we still contain unsaved files we should warn the user before saving
702      *
703      * @return true if the document still contains references to an unsaved file
704      */
containsUnsavedReferences() const705     bool containsUnsavedReferences() const { return !maUnsavedDocShells.empty(); }
706 
707     void insertRefCell(sal_uInt16 nFileId, const ScAddress& rCell);
708     /**
709      * Add a cell to reference the same files as the template cell.
710      */
711     void insertRefCellFromTemplate( ScFormulaCell* pTemplateCell, ScFormulaCell* pCell );
712 
713     bool hasCellExternalReference(const ScAddress& rCell);
714 
715     void enableDocTimer( bool bEnable );
716 
717     /** Add all known external files to the LinkManager. */
718     void addFilesToLinkManager();
719 
720 private:
721     ScExternalRefManager(const ScExternalRefManager&) = delete;
722 
723     void refreshAllRefCells(sal_uInt16 nFileId);
724 
725     void fillCellFormat(sal_uLong nFmtIndex, ScExternalRefCache::CellFormat* pFmt) const;
726 
727     bool getSrcDocTable( const ScDocument& rSrcDoc, const OUString& rTabName, SCTAB& rTab, sal_uInt16 nFileId ) const;
728 
729     ScExternalRefCache::TokenRef getSingleRefTokenFromSrcDoc(
730         sal_uInt16 nFileId, ScDocument& rSrcDoc, const ScAddress& rPos,
731         ScExternalRefCache::CellFormat* pFmt);
732 
733     /**
734      * Retrieve a range token array from a source document instance.
735      *
736      * @param rSrcDoc reference to the source document instance.
737      * @param rTabName name of the first table.
738      * @param rRange range specified.  Upon successful retrieval, this range
739      *               gets modified to contain the correct table IDs, and in
740      *               case the range is larger than the data area of the source
741      *               document, it gets reduced to the data area.
742      * @param rCacheData an array of structs, with each struct containing the
743      *                   table name and the data in the specified range.
744      *
745      * @return range token array
746      */
747     ScExternalRefCache::TokenArrayRef getDoubleRefTokensFromSrcDoc(
748         const ScDocument& rSrcDoc, const OUString& rTabName, ScRange& rRange,
749         ::std::vector<ScExternalRefCache::SingleRangeData>& rCacheData);
750 
751     /**
752      * Retrieve range name token array from a source document instance.
753      *
754      * @param nFileId file ID of the source document.
755      * @param rSrcDoc reference to the source document instance
756      * @param rName range name to retrieve.  Note that the range name lookup
757      *              is case <i>in</i>-sensitive, and upon successful retrieval
758      *              of the range name array, this name gets updated to the
759      *              actual range name with the correct casing.
760      *
761      * @return range name token array
762      */
763     static ScExternalRefCache::TokenArrayRef getRangeNameTokensFromSrcDoc(
764         sal_uInt16 nFileId, const ScDocument& rSrcDoc, OUString& rName);
765 
766     ScDocument* getInMemorySrcDocument(sal_uInt16 nFileId);
767     ScDocument* getSrcDocument(sal_uInt16 nFileId);
768     SfxObjectShellRef loadSrcDocument(sal_uInt16 nFileId, OUString& rFilter);
769 
770     /**
771      * Caller must ensure that the passed shell is not already stored.
772      */
773     ScDocument& cacheNewDocShell( sal_uInt16 nFileId, SrcShell& rSrcShell );
774 
775     void maybeLinkExternalFile( sal_uInt16 nFileId, bool bDeferFilterDetection = false );
776 
777     /**
778      * Try to create a "real" file name from the relative path.  The original
779      * file name may not point to the real document when the referencing and
780      * referenced documents have been moved.
781      *
782      * For the real file name to be created, the relative name should not be
783      * empty before calling this method, or the real file name will not be
784      * created.
785      *
786      * @param nFileId file ID for an external document
787      */
788     void maybeCreateRealFileName(sal_uInt16 nFileId);
789 
790     /**
791      * Purge those source document instances that have not been accessed for
792      * the specified duration.
793      *
794      * @param nTimeOut time out value in 100th of a second
795      */
796     void purgeStaleSrcDocument(sal_Int32 nTimeOut);
797 
798     sal_uInt32 getMappedNumberFormat(sal_uInt16 nFileId, sal_uInt32 nNumFmt, const ScDocument& rSrcDoc);
799 
800     /**
801      * If in maUnsavedDocShells move it to maDocShells and create a correct
802      * external reference entry
803      *
804      * @param Pointer to the newly saved DocumentShell
805      */
806     void transformUnsavedRefToSavedRef( SfxObjectShell* pShell );
807 
808 private:
809     ScDocument& mrDoc;
810 
811     /** cache of referenced ranges and names from source documents. */
812     ScExternalRefCache maRefCache;
813 
814     /**
815      * Source document cache.  This stores the original source document shell
816      * instances.  They get purged after a certain period of time.
817      */
818     DocShellMap maDocShells;
819 
820     /**
821      * DocShells to unsaved but referenced documents. If not empty ask before saving!
822      * Move to maDocShells if document referenced here is saved
823      */
824     DocShellMap maUnsavedDocShells;
825 
826     /** list of source documents that are managed by the link manager. */
827     LinkedDocMap maLinkedDocs;
828 
829     /**
830      * List of referencing cells that may contain external names.  There is
831      * one list per source document.
832      */
833     RefCellMap maRefCells;
834 
835     LinkListenerMap maLinkListeners;
836 
837     NumFmtMap maNumFormatMap;
838 
839     /**
840      * List of external source document meta-data, used to keep track of
841      * external document identifiers.
842      */
843     std::vector<SrcFileData> maSrcFiles;
844 
845     /** Status whether in reference marking state. See isInReferenceMarking(). */
846     bool mbInReferenceMarking:1;
847 
848     /**
849      * Controls whether or not to allow user interaction.  We don't want any
850      * user interaction when calling from the API.
851      */
852     bool mbUserInteractionEnabled:1;
853 
854     bool mbSkipUnusedFileIds = false;
855     std::vector<sal_uInt16> maConvertFileIdToUsedFileId;
856 
857     bool mbDocTimerEnabled:1;
858 
859     AutoTimer maSrcDocTimer;
860     DECL_LINK(TimeOutHdl, Timer*, void);
861 };
862 
863 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
864