LibreOffice Module sc (master)  1
formulabuffer.cxx
Go to the documentation of this file.
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 
10 #include <formulabuffer.hxx>
11 #include <externallinkbuffer.hxx>
12 #include <formulacell.hxx>
13 #include <document.hxx>
14 #include <documentimport.hxx>
15 
16 #include <autonamecache.hxx>
17 #include <tokenarray.hxx>
18 #include <sharedformulagroups.hxx>
19 #include <externalrefmgr.hxx>
20 #include <tokenstringcontext.hxx>
21 #include <o3tl/safeint.hxx>
22 #include <oox/token/tokens.hxx>
24 #include <svl/sharedstringpool.hxx>
25 #include <sal/log.hxx>
26 
27 using namespace ::com::sun::star::uno;
28 using namespace ::com::sun::star::sheet;
29 
30 #include <memory>
31 
32 namespace oox::xls {
33 
34 namespace {
35 
40 class CachedTokenArray
41 {
42 public:
43  CachedTokenArray(const CachedTokenArray&) = delete;
44  const CachedTokenArray& operator=(const CachedTokenArray&) = delete;
45 
46  struct Item
47  {
50 
51  Item(const Item&) = delete;
52  const Item& operator=(const Item&) = delete;
53 
54  Item() : mnRow(-1), mpCell(nullptr) {}
55  };
56 
57  explicit CachedTokenArray( const ScDocument& rDoc ) :
58  maCxt(rDoc, formula::FormulaGrammar::GRAM_OOXML) {}
59 
60  Item* get( const ScAddress& rPos, std::u16string_view rFormula )
61  {
62  // Check if a token array is cached for this column.
63  ColCacheType::iterator it = maCache.find(rPos.Col());
64  if (it == maCache.end())
65  return nullptr;
66 
67  Item& rCached = *it->second;
68  const ScTokenArray& rCode = *rCached.mpCell->GetCode();
69  OUString aPredicted = rCode.CreateString(maCxt, rPos);
70  if (rFormula == aPredicted)
71  return &rCached;
72 
73  return nullptr;
74  }
75 
76  void store( const ScAddress& rPos, ScFormulaCell* pCell )
77  {
78  ColCacheType::iterator it = maCache.find(rPos.Col());
79  if (it == maCache.end())
80  {
81  // Create an entry for this column.
82  std::pair<ColCacheType::iterator,bool> r =
83  maCache.emplace(rPos.Col(), std::make_unique<Item>());
84  if (!r.second)
85  // Insertion failed.
86  return;
87 
88  it = r.first;
89  }
90 
91  Item& rItem = *it->second;
92  rItem.mnRow = rPos.Row();
93  rItem.mpCell = pCell;
94  }
95 
96 private:
97  typedef std::unordered_map<SCCOL, std::unique_ptr<Item>> ColCacheType;
98  ColCacheType maCache;
100 };
101 
102 void applySharedFormulas(
103  ScDocumentImport& rDoc,
104  SvNumberFormatter& rFormatter,
105  std::vector<FormulaBuffer::SharedFormulaEntry>& rSharedFormulas,
106  std::vector<FormulaBuffer::SharedFormulaDesc>& rCells,
107  bool bGeneratorKnownGood)
108 {
109  sc::SharedFormulaGroups aGroups;
110  {
111  // Process shared formulas first.
112  for (const FormulaBuffer::SharedFormulaEntry& rEntry : rSharedFormulas)
113  {
114  const ScAddress& aPos = rEntry.maAddress;
115  sal_Int32 nId = rEntry.mnSharedId;
116  const OUString& rTokenStr = rEntry.maTokenStr;
117 
118  ScCompiler aComp(rDoc.getDoc(), aPos, formula::FormulaGrammar::GRAM_OOXML, true, false);
119  aComp.SetNumberFormatter(&rFormatter);
120  std::unique_ptr<ScTokenArray> pArray = aComp.CompileString(rTokenStr);
121  if (pArray)
122  {
123  aComp.CompileTokenArray(); // Generate RPN tokens.
124  aGroups.set(nId, std::move(pArray), aPos);
125  }
126  }
127  }
128 
129  {
130  svl::SharedStringPool& rStrPool = rDoc.getDoc().GetSharedStringPool();
131  // Process formulas that use shared formulas.
132  for (const FormulaBuffer::SharedFormulaDesc& rDesc : rCells)
133  {
134  const ScAddress& aPos = rDesc.maAddress;
135  const sc::SharedFormulaGroupEntry* pEntry = aGroups.getEntry(rDesc.mnSharedId);
136  if (!pEntry)
137  continue;
138 
139  const ScTokenArray* pArray = pEntry->getTokenArray();
140  assert(pArray);
141  const ScAddress& rOrigin = pEntry->getOrigin();
142  assert(rOrigin.IsValid());
143 
144  ScFormulaCell* pCell;
145  // In case of shared-formula along a row, do not let
146  // these cells share the same token objects.
147  // If we do, any reference-updates on these cells
148  // (while editing) will mess things up. Pass the cloned array as a
149  // pointer and not as reference to avoid any further allocation.
150  if (rOrigin.Col() != aPos.Col())
151  pCell = new ScFormulaCell(rDoc.getDoc(), aPos, pArray->Clone());
152  else
153  pCell = new ScFormulaCell(rDoc.getDoc(), aPos, *pArray);
154 
155  rDoc.setFormulaCell(aPos, pCell);
156  if (rDoc.getDoc().GetNumberFormat(aPos.Col(), aPos.Row(), aPos.Tab()) % SV_COUNTRY_LANGUAGE_OFFSET == 0)
157  pCell->SetNeedNumberFormat(true);
158 
159  if (rDesc.maCellValue.isEmpty())
160  {
161  // No cached cell value. Mark it for re-calculation.
162  pCell->SetDirty();
163  continue;
164  }
165 
166  // Set cached formula results. For now, we only use numeric and string-formula
167  // results. Find out how to utilize cached results of other types.
168  switch (rDesc.mnValueType)
169  {
170  case XML_n:
171  // numeric value.
172  pCell->SetResultDouble(rDesc.maCellValue.toDouble());
173  /* TODO: is it on purpose that we never reset dirty here
174  * and thus recalculate anyway if cell was dirty? Or is it
175  * never dirty and therefore set dirty below otherwise? This
176  * is different from the non-shared case in
177  * applyCellFormulaValues(). */
178  break;
179  case XML_str:
180  if (bGeneratorKnownGood)
181  {
182  // See applyCellFormulaValues
183  svl::SharedString aSS = rStrPool.intern(rDesc.maCellValue);
184  pCell->SetResultToken(new formula::FormulaStringToken(aSS));
185  // If we don't reset dirty, then e.g. disabling macros makes all cells
186  // that use macro functions to show #VALUE!
187  pCell->ResetDirty();
188  pCell->SetChanged(false);
189  break;
190  }
191  [[fallthrough]];
192  default:
193  // Mark it for re-calculation.
194  pCell->SetDirty();
195  }
196  }
197  }
198 }
199 
200 void applyCellFormulas(
201  ScDocumentImport& rDoc, CachedTokenArray& rCache, SvNumberFormatter& rFormatter,
202  const Sequence<ExternalLinkInfo>& rExternalLinks,
203  const std::vector<FormulaBuffer::TokenAddressItem>& rCells )
204 {
205  for (const FormulaBuffer::TokenAddressItem& rItem : rCells)
206  {
207  const ScAddress& aPos = rItem.maAddress;
208  CachedTokenArray::Item* p = rCache.get(aPos, rItem.maTokenStr);
209  if (p)
210  {
211  // Use the cached version to avoid re-compilation.
212 
213  ScFormulaCell* pCell = nullptr;
214  if (p->mnRow + 1 == aPos.Row())
215  {
216  // Put them in the same formula group.
217  ScFormulaCell& rPrev = *p->mpCell;
218  ScFormulaCellGroupRef xGroup = rPrev.GetCellGroup();
219  if (!xGroup)
220  {
221  // Last cell is not grouped yet. Start a new group.
222  assert(rPrev.aPos.Row() == p->mnRow);
223  xGroup = rPrev.CreateCellGroup(1, false);
224  }
225  ++xGroup->mnLength;
226 
227  pCell = new ScFormulaCell(rDoc.getDoc(), aPos, xGroup);
228  }
229  else
230  pCell = new ScFormulaCell(rDoc.getDoc(), aPos, p->mpCell->GetCode()->Clone());
231 
232  rDoc.setFormulaCell(aPos, pCell);
233  if (rDoc.getDoc().GetNumberFormat(aPos.Col(), aPos.Row(), aPos.Tab()) % SV_COUNTRY_LANGUAGE_OFFSET == 0)
234  pCell->SetNeedNumberFormat(true);
235 
236  // Update the cache.
237  p->mnRow = aPos.Row();
238  p->mpCell = pCell;
239  continue;
240  }
241 
242  ScCompiler aCompiler(rDoc.getDoc(), aPos, formula::FormulaGrammar::GRAM_OOXML, true, false);
243  aCompiler.SetNumberFormatter(&rFormatter);
244  aCompiler.SetExternalLinks(rExternalLinks);
245  std::unique_ptr<ScTokenArray> pCode = aCompiler.CompileString(rItem.maTokenStr);
246  if (!pCode)
247  continue;
248 
249  aCompiler.CompileTokenArray(); // Generate RPN tokens.
250 
251  ScFormulaCell* pCell = new ScFormulaCell(rDoc.getDoc(), aPos, std::move(pCode));
252  rDoc.setFormulaCell(aPos, pCell);
253  if (rDoc.getDoc().GetNumberFormat(aPos.Col(), aPos.Row(), aPos.Tab()) % SV_COUNTRY_LANGUAGE_OFFSET == 0)
254  pCell->SetNeedNumberFormat(true);
255  rCache.store(aPos, pCell);
256  }
257 }
258 
259 void applyArrayFormulas(
260  ScDocumentImport& rDoc, SvNumberFormatter& rFormatter,
261  const Sequence<ExternalLinkInfo>& rExternalLinks,
262  const std::vector<FormulaBuffer::TokenRangeAddressItem>& rArrays )
263 {
264  for (const FormulaBuffer::TokenRangeAddressItem& rAddressItem : rArrays)
265  {
266  const ScAddress& aPos = rAddressItem.maTokenAndAddress.maAddress;
267 
269  aComp.SetNumberFormatter(&rFormatter);
270  aComp.SetExternalLinks(rExternalLinks);
271  std::unique_ptr<ScTokenArray> pArray(aComp.CompileString(rAddressItem.maTokenAndAddress.maTokenStr));
272  if (pArray)
273  rDoc.setMatrixCells(rAddressItem.maRange, *pArray, formula::FormulaGrammar::GRAM_OOXML);
274  }
275 }
276 
277 void applyCellFormulaValues(
278  ScDocumentImport& rDoc, const std::vector<FormulaBuffer::FormulaValue>& rVector, bool bGeneratorKnownGood )
279 {
280  svl::SharedStringPool& rStrPool = rDoc.getDoc().GetSharedStringPool();
281 
282  for (const FormulaBuffer::FormulaValue& rValue : rVector)
283  {
284  const ScAddress& aCellPos = rValue.maAddress;
285  ScFormulaCell* pCell = rDoc.getDoc().GetFormulaCell(aCellPos);
286  const OUString& rValueStr = rValue.maValueStr;
287  if (!pCell)
288  continue;
289 
290  switch (rValue.mnCellType)
291  {
292  case XML_n:
293  {
294  pCell->SetResultDouble(rValueStr.toDouble());
295  pCell->ResetDirty();
296  pCell->SetChanged(false);
297  }
298  break;
299  case XML_str:
300  // Excel uses t="str" for string results (per definition
301  // ECMA-376 18.18.11 ST_CellType (Cell Type) "Cell containing a
302  // formula string.", but that 't' Cell Data Type attribute, "an
303  // enumeration representing the cell's data type", is meant for
304  // the content of the <v> element). We follow that. Other
305  // applications might not and instead use t="str" for the cell
306  // content if formula. Setting an otherwise numeric result as
307  // string result fouls things up, set result strings only for
308  // documents claiming to be generated by a known good
309  // generator. See tdf#98481
310  if (bGeneratorKnownGood)
311  {
312  svl::SharedString aSS = rStrPool.intern(rValueStr);
314  pCell->ResetDirty();
315  pCell->SetChanged(false);
316  }
317  break;
318  default:
319  ;
320  }
321  }
322 }
323 
324 void processSheetFormulaCells(
325  ScDocumentImport& rDoc, FormulaBuffer::SheetItem& rItem, SvNumberFormatter& rFormatter,
326  const Sequence<ExternalLinkInfo>& rExternalLinks, bool bGeneratorKnownGood )
327 {
328  if (rItem.mpSharedFormulaEntries && rItem.mpSharedFormulaIDs)
329  applySharedFormulas(rDoc, rFormatter, *rItem.mpSharedFormulaEntries,
330  *rItem.mpSharedFormulaIDs, bGeneratorKnownGood);
331 
332  if (rItem.mpCellFormulas)
333  {
334  CachedTokenArray aCache(rDoc.getDoc());
335  applyCellFormulas(rDoc, aCache, rFormatter, rExternalLinks, *rItem.mpCellFormulas);
336  }
337 
338  if (rItem.mpArrayFormulas)
339  applyArrayFormulas(rDoc, rFormatter, rExternalLinks, *rItem.mpArrayFormulas);
340 
341  if (rItem.mpCellFormulaValues)
342  applyCellFormulaValues(rDoc, *rItem.mpCellFormulaValues, bGeneratorKnownGood);
343 }
344 
345 }
346 
348  const ScAddress& rAddr,
349  const OUString& rTokenStr, sal_Int32 nSharedId ) :
350  maAddress(rAddr), maTokenStr(rTokenStr), mnSharedId(nSharedId) {}
351 
353  const ScAddress& rAddr, sal_Int32 nSharedId,
354  const OUString& rCellValue, sal_Int32 nValueType ) :
355  maAddress(rAddr), maCellValue(rCellValue), mnSharedId(nSharedId), mnValueType(nValueType) {}
356 
358  mpCellFormulas(nullptr),
359  mpArrayFormulas(nullptr),
360  mpCellFormulaValues(nullptr),
361  mpSharedFormulaEntries(nullptr),
362  mpSharedFormulaIDs(nullptr) {}
363 
365 {
366 }
367 
369 {
370  maCellFormulas.resize( nSheets );
371  maCellArrayFormulas.resize( nSheets );
372  maSharedFormulas.resize( nSheets );
373  maSharedFormulaIds.resize( nSheets );
374  maCellFormulaValues.resize( nSheets );
375 }
376 
378 {
379  ISegmentProgressBarRef xFormulaBar = getProgressBar().createSegment( getProgressBar().getFreeLength() );
380 
381  ScDocumentImport& rDoc = getDocImport();
382  rDoc.getDoc().SetAutoNameCache(std::make_unique<ScAutoNameCache>(rDoc.getDoc()));
383  ScExternalRefManager::ApiGuard aExtRefGuard(rDoc.getDoc());
384 
385  SCTAB nTabCount = rDoc.getDoc().GetTableCount();
386 
387  // Fetch all the formulas to process first.
388  std::vector<SheetItem> aSheetItems;
389  aSheetItems.reserve(nTabCount);
390  for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
391  aSheetItems.push_back(getSheetItem(nTab));
392 
393  for (SheetItem& rItem : aSheetItems)
394  processSheetFormulaCells(rDoc, rItem, *rDoc.getDoc().GetFormatTable(), getExternalLinks().getLinkInfos(),
396 
397  // With formula results being set and not recalculated we need to
398  // force-trigger adding all linked external files to the LinkManager.
400 
401  rDoc.getDoc().SetAutoNameCache(nullptr);
402 
403  xFormulaBar->setPosition( 1.0 );
404 }
405 
407 {
408  std::scoped_lock aGuard(maMtxData);
409 
410  SheetItem aItem;
411 
412  if( o3tl::make_unsigned(nTab) >= maCellFormulas.size() )
413  {
414  SAL_WARN( "sc", "Tab " << nTab << " out of bounds " << maCellFormulas.size() );
415  return aItem;
416  }
417 
418  if( !maCellFormulas[ nTab ].empty() )
419  aItem.mpCellFormulas = &maCellFormulas[ nTab ];
420  if( !maCellArrayFormulas[ nTab ].empty() )
421  aItem.mpArrayFormulas = &maCellArrayFormulas[ nTab ];
422  if( !maCellFormulaValues[ nTab ].empty() )
423  aItem.mpCellFormulaValues = &maCellFormulaValues[ nTab ];
424  if( !maSharedFormulas[ nTab ].empty() )
425  aItem.mpSharedFormulaEntries = &maSharedFormulas[ nTab ];
426  if( !maSharedFormulaIds[ nTab ].empty() )
427  aItem.mpSharedFormulaIDs = &maSharedFormulaIds[ nTab ];
428 
429  return aItem;
430 }
431 
433  const ScAddress& rAddress,
434  sal_Int32 nSharedId, const OUString& rTokens )
435 {
436  assert( rAddress.Tab() >= 0 && o3tl::make_unsigned(rAddress.Tab()) < maSharedFormulas.size() );
437  std::vector<SharedFormulaEntry>& rSharedFormulas = maSharedFormulas[ rAddress.Tab() ];
438  SharedFormulaEntry aEntry(rAddress, rTokens, nSharedId);
439  rSharedFormulas.push_back( aEntry );
440 }
441 
442 void FormulaBuffer::setCellFormula( const ScAddress& rAddress, const OUString& rTokenStr )
443 {
444  assert( rAddress.Tab() >= 0 && o3tl::make_unsigned(rAddress.Tab()) < maCellFormulas.size() );
445  maCellFormulas[ rAddress.Tab() ].emplace_back( rTokenStr, rAddress );
446 }
447 
449  const ScAddress& rAddress, sal_Int32 nSharedId, const OUString& rCellValue, sal_Int32 nValueType )
450 {
451  assert( rAddress.Tab() >= 0 && o3tl::make_unsigned(rAddress.Tab()) < maSharedFormulaIds.size() );
452  maSharedFormulaIds[rAddress.Tab()].emplace_back(rAddress, nSharedId, rCellValue, nValueType);
453 }
454 
455 void FormulaBuffer::setCellArrayFormula( const ScRange& rRangeAddress, const ScAddress& rTokenAddress, const OUString& rTokenStr )
456 {
457 
458  TokenAddressItem tokenPair( rTokenStr, rTokenAddress );
459  assert( rRangeAddress.aStart.Tab() >= 0 && o3tl::make_unsigned(rRangeAddress.aStart.Tab()) < maCellArrayFormulas.size() );
460  maCellArrayFormulas[ rRangeAddress.aStart.Tab() ].emplace_back( tokenPair, rRangeAddress );
461 }
462 
464  const ScAddress& rAddress, const OUString& rValueStr, sal_Int32 nCellType )
465 {
466  assert( rAddress.Tab() >= 0 && o3tl::make_unsigned(rAddress.Tab()) < maCellFormulaValues.size() );
467  FormulaValue aVal;
468  aVal.maAddress = rAddress;
469  aVal.maValueStr = rValueStr;
470  aVal.mnCellType = nCellType;
471  maCellFormulaValues[rAddress.Tab()].push_back(aVal);
472 }
473 
474 }
475 
476 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Helper class to provide access to global workbook data.
::boost::intrusive_ptr< ScFormulaCellGroup > ScFormulaCellGroupRef
Definition: types.hxx:43
ScAddress aStart
Definition: address.hxx:497
ScDocumentImport & getDocImport()
SharedString intern(const OUString &rStr)
SC_DLLPUBLIC svl::SharedStringPool & GetSharedStringPool()
Definition: documen2.cxx:584
SharedFormulaDesc(const ScAddress &rAddr, sal_Int32 nSharedId, const OUString &rCellValue, sal_Int32 nValueType)
SCROW Row() const
Definition: address.hxx:274
sal_Int16 mnValueType
bool isGeneratorKnownGood() const
Returns true when reading a file generated by a known good generator.
SC_DLLPUBLIC const ScFormulaCell * GetFormulaCell(const ScAddress &rPos) const
Definition: document.cxx:3757
std::vector< TokenAddressItem > * mpCellFormulas
sal_Int16 nId
Accessor class to ScDocument.
ColCacheType maCache
const ScAddress & getOrigin() const
std::vector< FormulaValue > * mpCellFormulaValues
std::vector< std::vector< TokenRangeAddressItem > > maCellArrayFormulas
FormulaBuffer(const WorkbookHelper &rHelper)
std::vector< std::vector< TokenAddressItem > > maCellFormulas
const ScTokenArray * getTokenArray() const
const ScFormulaCellGroupRef & GetCellGroup() const
std::vector< SharedFormulaDesc > * mpSharedFormulaIDs
void SetResultToken(const formula::FormulaToken *pToken)
SC_DLLPUBLIC SCTAB GetTableCount() const
Definition: document.cxx:315
ScFormulaCell * mpCell
void SetNumberFormatter(SvNumberFormatter *pFormatter)
Definition: compiler.cxx:279
sc::TokenStringContext maCxt
SC_DLLPUBLIC ScExternalRefManager * GetExternalRefManager() const
Definition: documen3.cxx:627
SCTAB Tab() const
Definition: address.hxx:283
ScAddress aPos
void SetNeedNumberFormat(bool bVal)
std::vector< SharedFormulaEntry > * mpSharedFormulaEntries
void setMatrixCells(const ScRange &rRange, const ScTokenArray &rArray, formula::FormulaGrammar::Grammar eGrammar)
bool IsValid() const
Definition: address.hxx:305
SC_DLLPUBLIC void SetAutoNameCache(std::unique_ptr< ScAutoNameCache > pCache)
Definition: document.cxx:7025
OUString CreateString(sc::TokenStringContext &rCxt, const ScAddress &rPos) const
Create a string representation of formula token array without modifying the internal state of the tok...
Definition: token.cxx:5217
void createSharedFormulaMapEntry(const ScAddress &rAddress, sal_Int32 nSharedId, const OUString &rTokens)
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:459
std::vector< std::vector< SharedFormulaDesc > > maSharedFormulaIds
std::vector< std::vector< SharedFormulaEntry > > maSharedFormulas
void setCellFormula(const ScAddress &rAddress, const OUString &)
ExternalLinkBuffer & getExternalLinks() const
Returns the external links read from the external links substream.
std::shared_ptr< ISegmentProgressBar > ISegmentProgressBarRef
const SharedFormulaGroupEntry * getEntry(size_t nSharedId) const
constexpr std::enable_if_t< std::is_signed_v< T >, std::make_unsigned_t< T > > make_unsigned(T value)
SegmentProgressBar & getProgressBar() const
Returns the filter progress bar.
virtual ISegmentProgressBarRef createSegment(double fLength) override
Context for creating string from an array of formula tokens, used in ScTokenArray::CreateString().
SharedFormulaEntry(const ScAddress &rAddress, const OUString &rTokenStr, sal_Int32 nSharedId)
void SetSheetCount(SCTAB nSheets)
ensure sizes of vectors matches the number of sheets
SCCOL Col() const
Definition: address.hxx:279
void setFormulaCell(const ScAddress &rPos, const OUString &rFormula, formula::FormulaGrammar::Grammar eGrammar, const double *pResult=nullptr)
sal_Int32 SCROW
Definition: types.hxx:17
css::uno::Sequence< css::sheet::ExternalLinkInfo > getLinkInfos() const
Returns the sequence of link infos needed by the XML formula parser.
void setCellArrayFormula(const ScRange &rRangeAddress, const ScAddress &rTokenAddress, const OUString &)
void SetResultDouble(double n)
For import only: set a double result.
SCROW mnRow
void addFilesToLinkManager()
Add all known external files to the LinkManager.
std::vector< std::vector< FormulaValue > > maCellFormulaValues
Represents a shared formula definition.
void set(size_t nSharedId, std::unique_ptr< ScTokenArray > pArray)
void setCellFormulaValue(const ScAddress &rAddress, const OUString &rValueStr, sal_Int32 nCellType)
void * p
ScFormulaCellGroupRef CreateCellGroup(SCROW nLen, bool bInvariant)
Turn a non-grouped cell into the top of a grouped cell.
std::vector< TokenRangeAddressItem > * mpArrayFormulas
#define SAL_WARN(area, stream)
void SetChanged(bool b)
SheetItem getSheetItem(SCTAB nTab)
std::unique_ptr< ScTokenArray > Clone() const
Definition: token.cxx:1930
sal_Int16 SCTAB
Definition: types.hxx:22
Use this guard when performing something from the API that might query values from external reference...
SC_DLLPUBLIC sal_uInt32 GetNumberFormat(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:3677
ScDocument & getDoc()