LibreOffice Module sc (master)  1
formulacell.hxx
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  * 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 <map>
23 #include <memory>
24 #include <optional>
25 
26 #include <formula/tokenarray.hxx>
27 #include <formula/errorcodes.hxx>
28 #include <svl/listener.hxx>
29 
30 #include "types.hxx"
31 #include "interpretercontext.hxx"
32 #include "document.hxx"
33 #include "docoptio.hxx"
34 #include "formulalogger.hxx"
35 #include "formularesult.hxx"
36 #include "tokenarray.hxx"
37 
38 namespace sc {
39 
40 class StartListeningContext;
41 class EndListeningContext;
42 struct RefUpdateContext;
43 struct RefUpdateInsertTabContext;
44 struct RefUpdateDeleteTabContext;
45 struct RefUpdateMoveTabContext;
46 class CompileFormulaContext;
47 class FormulaGroupAreaListener;
48 class UpdatedRangeNames;
49 
50 }
51 
52 class ScFormulaCell;
53 class ScProgress;
54 enum class SvNumFormatType : sal_Int16;
55 
57 {
60  bool mbEndFixed;
61 
62  AreaListenerKey( const ScRange& rRange, bool bStartFixed, bool bEndFixed ) :
63  maRange(rRange), mbStartFixed(bStartFixed), mbEndFixed(bEndFixed) {}
64 
65  bool operator < ( const AreaListenerKey& r ) const;
66 };
67 
68 typedef std::map<AreaListenerKey, std::unique_ptr<sc::FormulaGroupAreaListener>> AreaListenersType;
69 
71 {
73 public:
74 
75  mutable size_t mnRefCount;
76 
77  std::optional<ScTokenArray> mpCode;
79  SCROW mnLength; // How many of these do we have ?
80  sal_Int32 mnWeight;
82  bool mbInvariant:1;
83  bool mbSubTotal:1;
84  bool mbPartOfCycle:1; // To flag FG's part of a cycle
85 
87 
89  ScFormulaCellGroup(const ScFormulaCellGroup&) = delete;
90  const ScFormulaCellGroup& operator=(const ScFormulaCellGroup&) = delete;
92 
93  void setCode( const ScTokenArray& rCode );
94  void compileCode(
95  ScDocument& rDoc, const ScAddress& rPos, formula::FormulaGrammar::Grammar eGram );
96 
97  sc::FormulaGroupAreaListener* getAreaListener(
98  ScFormulaCell** ppTopCell, const ScRange& rRange, bool bStartFixed, bool bEndFixed );
99 
100  void endAllGroupListening( ScDocument& rDoc );
101 };
102 
104 {
105  p->mnRefCount++;
106 }
107 
109 {
110  if( --p->mnRefCount == 0 )
111  delete p;
112 }
113 
114 enum class ScMatrixMode : sal_uInt8 {
115  NONE = 0, // No matrix formula
116  Formula = 1, // Upper left matrix formula cell
117  Reference = 2 // Remaining cells, via ocMatRef reference token
118 };
119 
121 {
122 private:
123  ScFormulaCellGroupRef mxGroup; // Group of formulae we're part of
124  bool bDirty : 1; // Must be (re)calculated
125  bool bTableOpDirty : 1; // Dirty flag for TableOp
126  bool bChanged : 1; // Whether something changed regarding display/representation
127  bool bRunning : 1; // Already interpreting right now
128  bool bCompile : 1; // Must be (re)compiled
129  bool bSubTotal : 1; // Cell is part of or contains a SubTotal
130  bool bIsIterCell : 1; // Cell is part of a circular reference
131  bool bInChangeTrack : 1; // Cell is in ChangeTrack
132  bool bNeedListening : 1; // Listeners need to be re-established after UpdateReference
133  bool mbNeedsNumberFormat : 1; // set the calculated number format as hard number format
134  bool mbAllowNumberFormatChange : 1; /* allow setting further calculated
135  number formats as hard number format */
136  bool mbPostponedDirty : 1; // if cell needs to be set dirty later
137  bool mbIsExtRef : 1; // has references in ScExternalRefManager; never cleared after set
138  bool mbSeenInPath : 1; // For detecting cycle involving formula groups and singleton formulacells
139  bool mbFreeFlying : 1; // Cell is out of sheets interpreted, like in conditional format
140  ScMatrixMode cMatrixFlag : 8;
141  sal_uInt16 nSeenInIteration : 16; // Iteration cycle in which the cell was last encountered
142  SvNumFormatType nFormatType : 16;
144  formula::FormulaGrammar::Grammar eTempGrammar; // used between string (creation) and (re)compilation
145  // If this cell is in a cell group (mxGroup!=nullptr), then this pCode is a not-owning pointer
146  // to the mxGroup's mpCode, which owns the array. If the cell is not in a group, this is an owning pointer.
147  ScTokenArray* pCode; // The token array
153 
157  bool UpdateReferenceOnCopy(
158  const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, const ScAddress* pUndoCellPos );
159 
160  ScFormulaCell( const ScFormulaCell& ) = delete;
161 
162  bool CheckComputeDependencies(sc::FormulaLogger::GroupScope& rScope, bool fromFirstRow,
163  SCROW nStartOffset, SCROW nEndOffset, bool bCalcDependencyOnly = false);
164  bool InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope& aScope,
165  bool& bDependencyComputed,
166  bool& bDependencyCheckFailed,
167  SCROW nStartOffset, SCROW nEndOffset);
168  bool InterpretFormulaGroupOpenCL(sc::FormulaLogger::GroupScope& aScope,
169  bool& bDependencyComputed,
170  bool& bDependencyCheckFailed);
171  bool InterpretInvariantFormulaGroup();
172 
173 public:
174 
175 
177  {
180  SCITP_CLOSE_ITERATION_CIRCLE
181  };
182  void InterpretTail( ScInterpreterContext&, ScInterpretTailParameter );
183 
184  void HandleStuffAfterParallelCalculation(ScInterpreter* pInterpreter);
185 
186  enum CompareState { NotEqual = 0, EqualInvariant, EqualRelativeRef };
187 
189 
190  virtual ~ScFormulaCell() override;
191 
192  ScFormulaCell* Clone() const;
193  ScFormulaCell* Clone( const ScAddress& rPos ) const;
194 
195  ScFormulaCell( ScDocument& rDoc, const ScAddress& rPos );
196 
202  ScFormulaCell( ScDocument& rDoc, const ScAddress& rPos, std::unique_ptr<ScTokenArray> pArray,
204  ScMatrixMode cMatInd = ScMatrixMode::NONE );
205 
206  ScFormulaCell( ScDocument& rDoc, const ScAddress& rPos, const ScTokenArray& rArray,
208  ScMatrixMode cMatInd = ScMatrixMode::NONE );
209 
210  ScFormulaCell( ScDocument& rDoc, const ScAddress& rPos, const ScFormulaCellGroupRef& xGroup,
213 
218  ScFormulaCell( ScDocument& rDoc, const ScAddress& rPos,
219  const OUString& rFormula,
221  ScMatrixMode cMatInd = ScMatrixMode::NONE );
222 
223  ScFormulaCell(const ScFormulaCell& rCell, ScDocument& rDoc, const ScAddress& rPos, ScCloneFlags nCloneFlags = ScCloneFlags::Default);
224 
225  void SetFreeFlying( bool b ) { mbFreeFlying = b; }
226 
227  size_t GetHash() const;
228 
230  const ScInterpreterContext* pContext = nullptr ) const;
231  OUString GetFormula( sc::CompileFormulaContext& rCxt, const ScInterpreterContext* pContext = nullptr ) const;
232 
233  void SetDirty( bool bDirtyFlag=true );
234  void SetDirtyVar();
235  // If setting entire document dirty after load, no broadcasts but still append to FormulaTree.
236  void SetDirtyAfterLoad();
237  void ResetTableOpDirtyVar();
238  void SetTableOpDirty();
239 
241  {
242  return bDirty || (bTableOpDirty && rDocument.IsInInterpreterTableOp());
243  }
244 
245  bool GetDirty() const { return bDirty; }
246  void ResetDirty();
247  bool NeedsListening() const { return bNeedListening; }
248  void SetNeedsListening( bool bVar );
249  void SetNeedsDirty( bool bVar );
250  void SetNeedNumberFormat( bool bVal );
251  bool NeedsNumberFormat() const { return mbNeedsNumberFormat;}
252  SvNumFormatType GetFormatType() const { return nFormatType; }
253  void Compile(const OUString& rFormula,
254  bool bNoListening,
256  void Compile(
257  sc::CompileFormulaContext& rCxt, const OUString& rFormula, bool bNoListening = false );
258 
259  void CompileTokenArray( bool bNoListening = false );
260  void CompileTokenArray( sc::CompileFormulaContext& rCxt, bool bNoListening = false );
261  void CompileXML( sc::CompileFormulaContext& rCxt, ScProgress& rProgress ); // compile temporary string tokens
262  void CalcAfterLoad( sc::CompileFormulaContext& rCxt, bool bStartListening );
263  bool MarkUsedExternalReferences();
264  bool Interpret(SCROW nStartOffset = -1, SCROW nEndOffset = -1);
265  bool IsIterCell() const { return bIsIterCell; }
266  sal_uInt16 GetSeenInIteration() const { return nSeenInIteration; }
267 
268  bool HasOneReference( ScRange& r ) const;
269  /* Checks if the formula contains reference list that can be
270  expressed by one reference (like A1;A2;A3:A5 -> A1:A5). The
271  reference list is not required to be sorted (i.e. A3;A1;A2 is
272  still recognized as A1:A3), but no overlapping is allowed.
273  If one reference is recognized, the rRange is filled.
274 
275  It is similar to HasOneReference(), but more general.
276  */
277  bool HasRefListExpressibleAsOneReference(ScRange& rRange) const;
278 
279  enum class RelNameRef
280  {
281  NONE,
282  SINGLE,
283  DOUBLE
284  };
285  RelNameRef HasRelNameReference() const;
286 
287  bool UpdateReference(
288  const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc = nullptr, const ScAddress* pUndoCellPos = nullptr );
289 
295  bool UpdatePosOnShift( const sc::RefUpdateContext& rCxt );
296 
300  bool UpdateReferenceOnShift(
301  const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, const ScAddress* pUndoCellPos );
302 
306  bool UpdateReferenceOnMove(
307  const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, const ScAddress* pUndoCellPos );
308 
309  void TransposeReference();
310  void UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
311  ScDocument* pUndoDoc );
312 
313  void UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY );
314 
315  void UpdateInsertTab( const sc::RefUpdateInsertTabContext& rCxt );
316  void UpdateInsertTabAbs(SCTAB nTable);
317  void UpdateDeleteTab( const sc::RefUpdateDeleteTabContext& rCxt );
318  void UpdateMoveTab( const sc::RefUpdateMoveTabContext& rCxt, SCTAB nTabNo );
319  bool TestTabRefAbs(SCTAB nTable);
320  void UpdateCompile( bool bForceIfNameInUse );
321  void FindRangeNamesInUse(sc::UpdatedRangeNames& rIndexes) const;
322  bool IsSubTotal() const { return bSubTotal;}
323  bool IsChanged() const { return bChanged;}
324  void SetChanged(bool b);
325  bool IsEmpty(); // formula::svEmptyCell result
326  // display as empty string if formula::svEmptyCell result
327  bool IsEmptyDisplayedAsString();
328  bool IsValue(); // also true if formula::svEmptyCell
329  bool IsValueNoError();
330  bool IsValueNoError() const;
331  double GetValue();
332  const svl::SharedString & GetString();
333 
337  double GetRawValue() const;
338 
342  const svl::SharedString & GetRawString() const;
343  const ScMatrix* GetMatrix();
344  bool GetMatrixOrigin( const ScDocument& rDoc, ScAddress& rPos ) const;
345  void GetResultDimensions( SCSIZE& rCols, SCSIZE& rRows );
346  sc::MatrixEdge GetMatrixEdge( const ScDocument& rDoc, ScAddress& rOrgPos ) const;
347  FormulaError GetErrCode(); // interpret first if necessary
348  FormulaError GetRawError() const; // don't interpret, just return code or result error
349  bool GetErrorOrValue( FormulaError& rErr, double& rVal );
350  sc::FormulaResultValue GetResult();
351  sc::FormulaResultValue GetResult() const;
352  ScMatrixMode GetMatrixFlag() const { return cMatrixFlag;}
353  ScTokenArray* GetCode() { return pCode;}
354  const ScTokenArray* GetCode() const { return pCode;}
355 
356  void SetCode( std::unique_ptr<ScTokenArray> pNew );
357 
358  bool IsRunning() const { return bRunning;}
359  void SetRunning( bool bVal );
360  void CompileDBFormula( sc::CompileFormulaContext& rCxt );
361  void CompileColRowNameFormula( sc::CompileFormulaContext& rCxt );
362  ScFormulaCell* GetPrevious() const { return pPrevious; }
363  ScFormulaCell* GetNext() const { return pNext; }
364  void SetPrevious( ScFormulaCell* pF );
365  void SetNext( ScFormulaCell* pF );
366  ScFormulaCell* GetPreviousTrack() const { return pPreviousTrack; }
367  ScFormulaCell* GetNextTrack() const { return pNextTrack; }
368  void SetPreviousTrack( ScFormulaCell* pF );
369  void SetNextTrack( ScFormulaCell* pF );
370 
371  virtual void Notify( const SfxHint& rHint ) override;
372  virtual void Query( SvtListener::QueryBase& rQuery ) const override;
373 
374  void SetCompile( bool bVal );
375  ScDocument& GetDocument() const { return rDocument;}
376  void SetMatColsRows( SCCOL nCols, SCROW nRows );
377  void GetMatColsRows( SCCOL& nCols, SCROW& nRows ) const;
378 
379  // cell belongs to ChangeTrack and not to the real document
380  void SetInChangeTrack( bool bVal );
381  bool IsInChangeTrack() const { return bInChangeTrack;}
382 
383  // For import filters!
384  void AddRecalcMode( ScRecalcMode );
386  void SetHybridDouble( double n );
391  void SetHybridString( const svl::SharedString& r );
398  void SetHybridEmptyDisplayedAsString();
403  void SetHybridFormula(
404  const OUString& r, const formula::FormulaGrammar::Grammar eGrammar );
405 
406  OUString GetHybridFormula() const;
407 
408  void SetResultMatrix( SCCOL nCols, SCROW nRows, const ScConstMatrixRef& pMat, const formula::FormulaToken* pUL );
409 
415  void SetResultDouble( double n );
416 
417  void SetResultToken( const formula::FormulaToken* pToken );
418 
419  const svl::SharedString & GetResultString() const;
420 
421  bool HasHybridStringResult() const;
422 
423  /* Sets the shared code array to error state in addition to the cell result */
424  void SetErrCode( FormulaError n );
425 
426  /* Sets just the result to error */
427  void SetResultError( FormulaError n );
428 
429  bool IsHyperLinkCell() const;
430  std::unique_ptr<EditTextObject> CreateURLObject();
431  void GetURLResult( OUString& rURL, OUString& rCellText );
432 
434  bool IsMultilineResult();
435 
436  bool NeedsInterpret() const
437  {
438  if (bIsIterCell)
439  // Shortcut to force return of current value and not enter Interpret()
440  // as we're looping over all iteration cells.
441  return false;
442 
443  if (!IsDirtyOrInTableOpDirty())
444  return false;
445 
446  return (rDocument.GetAutoCalc() || (cMatrixFlag != ScMatrixMode::NONE));
447  }
448 
450  {
451  if (NeedsInterpret())
452  {
453  if (bRunning && !rDocument.GetDocOptions().IsIter() && rDocument.IsThreadedGroupCalcInProgress())
454  {
455  // This is actually copied from Interpret()'s if(bRunning)
456  // block that once caught this circular reference but now is
457  // prepended with various threaded group calc things which the
458  // assert() below is supposed to fail on when entering again.
459  // Nevertheless, we need some state here the caller can obtain.
460  aResult.SetResultError( FormulaError::CircularReference );
461  }
462  else
463  {
464  assert(!rDocument.IsThreadedGroupCalcInProgress());
465  Interpret();
466  }
467  }
468  }
469 
473  ScFormulaCellGroupRef CreateCellGroup( SCROW nLen, bool bInvariant );
474  const ScFormulaCellGroupRef& GetCellGroup() const { return mxGroup;}
475  void SetCellGroup( const ScFormulaCellGroupRef &xRef );
476 
477  CompareState CompareByTokenArray( const ScFormulaCell& rOther ) const;
478 
479  bool InterpretFormulaGroup(SCROW nStartOffset = -1, SCROW nEndOffset = -1);
480 
481  // nOnlyNames may be one or more of SC_LISTENING_NAMES_*
482  void StartListeningTo( ScDocument& rDoc );
483  void StartListeningTo( sc::StartListeningContext& rCxt );
484  void EndListeningTo(
485  ScDocument& rDoc, ScTokenArray* pArr = nullptr, ScAddress aPos = ScAddress() );
486  void EndListeningTo( sc::EndListeningContext& rCxt );
487 
488  bool IsShared() const;
489  bool IsSharedTop() const;
490  SCROW GetSharedTopRow() const;
491  SCROW GetSharedLength() const;
492 
493  // An estimate of the number of cells referenced by the formula
494  sal_Int32 GetWeight() const;
495 
496  ScTokenArray* GetSharedCode();
497  const ScTokenArray* GetSharedCode() const;
498 
499  void SyncSharedCode();
500 
501  bool IsPostponedDirty() const { return mbPostponedDirty;}
502 
503  void SetIsExtRef() { mbIsExtRef = true; }
504  bool GetSeenInPath() const { return mbSeenInPath; }
505  void SetSeenInPath(bool bSet) { mbSeenInPath = bSet; }
506 
507 #if DUMP_COLUMN_STORAGE
508  void Dump() const;
509 #endif
510 };
511 
512 inline bool ScDocument::IsInFormulaTree( const ScFormulaCell* pCell ) const { return pCell->GetPrevious() || pFormulaTree == pCell; }
513 inline bool ScDocument::IsInFormulaTrack( const ScFormulaCell* pCell ) const { return pCell->GetPreviousTrack() || pFormulaTrack == pCell; }
514 
515 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Matrix data type that can store values of mixed types.
Definition: scmatrix.hxx:112
bool IsInFormulaTree(const ScFormulaCell *pCell) const
Default cell clone flags: do not start listening, do not adjust 3D refs to old position, clone note captions of cell notes.
::boost::intrusive_ptr< ScFormulaCellGroup > ScFormulaCellGroupRef
Definition: types.hxx:43
bool GetSeenInPath() const
ScFormulaCell * pFormulaTree
Definition: document.hxx:384
bool NeedsInterpret() const
ScCloneFlags
Definition: global.hxx:248
bool NeedsListening() const
std::string GetValue
ScRecalcMode
ScDocument & rDocument
AreaListenersType m_AreaListeners
Definition: formulacell.hxx:72
ScTokenArray * GetCode()
bool GetDirty() const
std::map< AreaListenerKey, std::unique_ptr< sc::FormulaGroupAreaListener > > AreaListenersType
Definition: formulacell.hxx:68
Context for reference update during shifting, moving or copying of cell ranges.
ScFormulaCell * GetPreviousTrack() const
bool IsIterCell() const
sal_uInt16 GetSeenInIteration() const
bool IsIter() const
Definition: docoptio.hxx:59
void SetIsExtRef()
formula::FormulaGrammar::Grammar eTempGrammar
void SetResultError(FormulaError nErr)
Set error code, don't touch token or double.
AreaListenerKey(const ScRange &rRange, bool bStartFixed, bool bEndFixed)
Definition: formulacell.hxx:62
ScDocument & GetDocument() const
NONE
OUString GetString(int nId)
const ScFormulaCellGroupRef & GetCellGroup() const
std::optional< ScTokenArray > mpCode
Definition: formulacell.hxx:77
bool IsPostponedDirty() const
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
Definition: address.hxx:44
Store a variable formula cell result, balancing between runtime performance and memory consumption...
virtual void Query(QueryBase &rQuery) const
ScAddress aPos
SvNumFormatType GetFormatType() const
bool IsChanged() const
SC_DLLPUBLIC const ScDocOptions & GetDocOptions() const
Definition: documen3.cxx:1947
Keep track of all named expressions that have been updated during reference update.
ScTokenArray * pCode
Reference< XAnimationNode > Clone(const Reference< XAnimationNode > &xSourceNode, const SdPage *pSource, const SdPage *pTarget)
bool NeedsNumberFormat() const
void SetSeenInPath(bool bSet)
sal_Int16 SCCOL
Definition: types.hxx:21
void intrusive_ptr_release(const ScFormulaCellGroup *p)
ScFormulaCell * GetNextTrack() const
bool IsInInterpreterTableOp() const
Definition: document.hxx:2356
ScFormulaCell * pNext
SvNumFormatType
bool IsDirtyOrInTableOpDirty() const
bool IsRunning() const
ScFormulaCell * GetNext() const
#define DOUBLE
FormulaError
void SetFreeFlying(bool b)
ScFormulaCellGroupRef mxGroup
ScFormulaCell * GetPrevious() const
const ScTokenArray * GetCode() const
sal_Int32 SCROW
Definition: types.hxx:17
bool IsThreadedGroupCalcInProgress() const
Definition: document.hxx:623
bool IsSubTotal() const
ScFormulaCell * pPreviousTrack
sal_uInt8 meCalcState
Definition: formulacell.hxx:86
bool IsInFormulaTrack(const ScFormulaCell *pCell) const
unsigned char sal_uInt8
::boost::intrusive_ptr< const ScMatrix > ScConstMatrixRef
Definition: types.hxx:26
virtual void Notify(const SfxHint &rHint)
ScMatrixMode
ScFormulaResult aResult
bool IsInChangeTrack() const
void MaybeInterpret()
ScFormulaCell * pPrevious
ScFormulaCell * mpTopCell
Definition: formulacell.hxx:78
void intrusive_ptr_add_ref(const ScFormulaCellGroup *p)
MatrixEdge
Definition: types.hxx:65
SvNumFormatType mnFormatType
Definition: formulacell.hxx:81
ScMatrixMode GetMatrixFlag() const
bool operator<(const AreaListenerKey &r) const
#define SC_DLLPUBLIC
Definition: scdllapi.h:27
ScFormulaCell * pNextTrack
sal_Int16 SCTAB
Definition: types.hxx:22
ScFormulaCell * pFormulaTrack
Definition: document.hxx:386
SC_DLLPUBLIC bool GetAutoCalc() const
Definition: document.hxx:1366