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