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 
229  void GetFormula( OUString& rFormula,
231  const ScInterpreterContext* pContext = nullptr ) const;
232  void GetFormula( OUStringBuffer& rBuffer,
234  const ScInterpreterContext* pContext = nullptr ) const;
235 
236  OUString GetFormula( sc::CompileFormulaContext& rCxt, const ScInterpreterContext* pContext = nullptr ) const;
237 
238  void SetDirty( bool bDirtyFlag=true );
239  void SetDirtyVar();
240  // If setting entire document dirty after load, no broadcasts but still append to FormulaTree.
241  void SetDirtyAfterLoad();
242  void ResetTableOpDirtyVar();
243  void SetTableOpDirty();
244 
246  {
247  return bDirty || (bTableOpDirty && rDocument.IsInInterpreterTableOp());
248  }
249 
250  bool GetDirty() const { return bDirty; }
251  void ResetDirty();
252  bool NeedsListening() const { return bNeedListening; }
253  void SetNeedsListening( bool bVar );
254  void SetNeedsDirty( bool bVar );
255  void SetNeedNumberFormat( bool bVal );
256  bool NeedsNumberFormat() const { return mbNeedsNumberFormat;}
257  SvNumFormatType GetFormatType() const { return nFormatType; }
258  void Compile(const OUString& rFormula,
259  bool bNoListening,
261  void Compile(
262  sc::CompileFormulaContext& rCxt, const OUString& rFormula, bool bNoListening = false );
263 
264  void CompileTokenArray( bool bNoListening = false );
265  void CompileTokenArray( sc::CompileFormulaContext& rCxt, bool bNoListening = false );
266  void CompileXML( sc::CompileFormulaContext& rCxt, ScProgress& rProgress ); // compile temporary string tokens
267  void CalcAfterLoad( sc::CompileFormulaContext& rCxt, bool bStartListening );
268  bool MarkUsedExternalReferences();
269  bool Interpret(SCROW nStartOffset = -1, SCROW nEndOffset = -1);
270  bool IsIterCell() const { return bIsIterCell; }
271  sal_uInt16 GetSeenInIteration() const { return nSeenInIteration; }
272 
273  bool HasOneReference( ScRange& r ) const;
274  /* Checks if the formula contains reference list that can be
275  expressed by one reference (like A1;A2;A3:A5 -> A1:A5). The
276  reference list is not required to be sorted (i.e. A3;A1;A2 is
277  still recognized as A1:A3), but no overlapping is allowed.
278  If one reference is recognized, the rRange is filled.
279 
280  It is similar to HasOneReference(), but more general.
281  */
282  bool HasRefListExpressibleAsOneReference(ScRange& rRange) const;
283 
284  enum class RelNameRef
285  {
286  NONE,
287  SINGLE,
288  DOUBLE
289  };
290  RelNameRef HasRelNameReference() const;
291 
292  bool UpdateReference(
293  const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc = nullptr, const ScAddress* pUndoCellPos = nullptr );
294 
300  bool UpdatePosOnShift( const sc::RefUpdateContext& rCxt );
301 
305  bool UpdateReferenceOnShift(
306  const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, const ScAddress* pUndoCellPos );
307 
311  bool UpdateReferenceOnMove(
312  const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, const ScAddress* pUndoCellPos );
313 
314  void TransposeReference();
315  void UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
316  ScDocument* pUndoDoc );
317 
318  void UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY );
319 
320  void UpdateInsertTab( const sc::RefUpdateInsertTabContext& rCxt );
321  void UpdateInsertTabAbs(SCTAB nTable);
322  void UpdateDeleteTab( const sc::RefUpdateDeleteTabContext& rCxt );
323  void UpdateMoveTab( const sc::RefUpdateMoveTabContext& rCxt, SCTAB nTabNo );
324  bool TestTabRefAbs(SCTAB nTable);
325  void UpdateCompile( bool bForceIfNameInUse );
326  void FindRangeNamesInUse(sc::UpdatedRangeNames& rIndexes) const;
327  bool IsSubTotal() const { return bSubTotal;}
328  bool IsChanged() const { return bChanged;}
329  void SetChanged(bool b);
330  bool IsEmpty(); // formula::svEmptyCell result
331  // display as empty string if formula::svEmptyCell result
332  bool IsEmptyDisplayedAsString();
333  bool IsValue(); // also true if formula::svEmptyCell
334  bool IsValueNoError();
335  bool IsValueNoError() const;
336  double GetValue();
337  const svl::SharedString & GetString();
338 
342  double GetRawValue() const;
343 
347  const svl::SharedString & GetRawString() const;
348  const ScMatrix* GetMatrix();
349  bool GetMatrixOrigin( const ScDocument& rDoc, ScAddress& rPos ) const;
350  void GetResultDimensions( SCSIZE& rCols, SCSIZE& rRows );
351  sc::MatrixEdge GetMatrixEdge( const ScDocument& rDoc, ScAddress& rOrgPos ) const;
352  FormulaError GetErrCode(); // interpret first if necessary
353  FormulaError GetRawError() const; // don't interpret, just return code or result error
354  bool GetErrorOrValue( FormulaError& rErr, double& rVal );
355  sc::FormulaResultValue GetResult();
356  sc::FormulaResultValue GetResult() const;
357  ScMatrixMode GetMatrixFlag() const { return cMatrixFlag;}
358  ScTokenArray* GetCode() { return pCode;}
359  const ScTokenArray* GetCode() const { return pCode;}
360 
361  void SetCode( std::unique_ptr<ScTokenArray> pNew );
362 
363  bool IsRunning() const { return bRunning;}
364  void SetRunning( bool bVal );
365  void CompileDBFormula( sc::CompileFormulaContext& rCxt );
366  void CompileColRowNameFormula( sc::CompileFormulaContext& rCxt );
367  ScFormulaCell* GetPrevious() const { return pPrevious; }
368  ScFormulaCell* GetNext() const { return pNext; }
369  void SetPrevious( ScFormulaCell* pF );
370  void SetNext( ScFormulaCell* pF );
371  ScFormulaCell* GetPreviousTrack() const { return pPreviousTrack; }
372  ScFormulaCell* GetNextTrack() const { return pNextTrack; }
373  void SetPreviousTrack( ScFormulaCell* pF );
374  void SetNextTrack( ScFormulaCell* pF );
375 
376  virtual void Notify( const SfxHint& rHint ) override;
377  virtual void Query( SvtListener::QueryBase& rQuery ) const override;
378 
379  void SetCompile( bool bVal );
380  ScDocument& GetDocument() const { return rDocument;}
381  void SetMatColsRows( SCCOL nCols, SCROW nRows );
382  void GetMatColsRows( SCCOL& nCols, SCROW& nRows ) const;
383 
384  // cell belongs to ChangeTrack and not to the real document
385  void SetInChangeTrack( bool bVal );
386  bool IsInChangeTrack() const { return bInChangeTrack;}
387 
388  // For import filters!
389  void AddRecalcMode( ScRecalcMode );
391  void SetHybridDouble( double n );
396  void SetHybridString( const svl::SharedString& r );
403  void SetHybridEmptyDisplayedAsString();
408  void SetHybridFormula(
409  const OUString& r, const formula::FormulaGrammar::Grammar eGrammar );
410 
411  const OUString& GetHybridFormula() const;
412 
413  void SetResultMatrix( SCCOL nCols, SCROW nRows, const ScConstMatrixRef& pMat, const formula::FormulaToken* pUL );
414 
420  void SetResultDouble( double n );
421 
422  void SetResultToken( const formula::FormulaToken* pToken );
423 
424  const svl::SharedString & GetResultString() const;
425 
426  bool HasHybridStringResult() const;
427 
428  /* Sets the shared code array to error state in addition to the cell result */
429  void SetErrCode( FormulaError n );
430 
431  /* Sets just the result to error */
432  void SetResultError( FormulaError n );
433 
434  bool IsHyperLinkCell() const;
435  std::unique_ptr<EditTextObject> CreateURLObject();
436  void GetURLResult( OUString& rURL, OUString& rCellText );
437 
439  bool IsMultilineResult();
440 
441  bool NeedsInterpret() const
442  {
443  if (bIsIterCell)
444  // Shortcut to force return of current value and not enter Interpret()
445  // as we're looping over all iteration cells.
446  return false;
447 
448  if (!IsDirtyOrInTableOpDirty())
449  return false;
450 
451  return (rDocument.GetAutoCalc() || (cMatrixFlag != ScMatrixMode::NONE));
452  }
453 
455  {
456  if (NeedsInterpret())
457  {
458  if (bRunning && !rDocument.GetDocOptions().IsIter() && rDocument.IsThreadedGroupCalcInProgress())
459  {
460  // This is actually copied from Interpret()'s if(bRunning)
461  // block that once caught this circular reference but now is
462  // prepended with various threaded group calc things which the
463  // assert() below is supposed to fail on when entering again.
464  // Nevertheless, we need some state here the caller can obtain.
465  aResult.SetResultError( FormulaError::CircularReference );
466  }
467  else
468  {
469  assert(!rDocument.IsThreadedGroupCalcInProgress());
470  Interpret();
471  }
472  }
473  }
474 
478  ScFormulaCellGroupRef CreateCellGroup( SCROW nLen, bool bInvariant );
479  const ScFormulaCellGroupRef& GetCellGroup() const { return mxGroup;}
480  void SetCellGroup( const ScFormulaCellGroupRef &xRef );
481 
482  CompareState CompareByTokenArray( const ScFormulaCell& rOther ) const;
483 
484  bool InterpretFormulaGroup(SCROW nStartOffset = -1, SCROW nEndOffset = -1);
485 
486  // nOnlyNames may be one or more of SC_LISTENING_NAMES_*
487  void StartListeningTo( ScDocument& rDoc );
488  void StartListeningTo( sc::StartListeningContext& rCxt );
489  void EndListeningTo(
490  ScDocument& rDoc, ScTokenArray* pArr = nullptr, ScAddress aPos = ScAddress() );
491  void EndListeningTo( sc::EndListeningContext& rCxt );
492 
493  bool IsShared() const;
494  bool IsSharedTop() const;
495  SCROW GetSharedTopRow() const;
496  SCROW GetSharedLength() const;
497 
498  // An estimate of the number of cells referenced by the formula
499  sal_Int32 GetWeight() const;
500 
501  ScTokenArray* GetSharedCode();
502  const ScTokenArray* GetSharedCode() const;
503 
504  void SyncSharedCode();
505 
506  bool IsPostponedDirty() const { return mbPostponedDirty;}
507 
508  void SetIsExtRef() { mbIsExtRef = true; }
509  bool GetSeenInPath() const { return mbSeenInPath; }
510  void SetSeenInPath(bool bSet) { mbSeenInPath = bSet; }
511 
512 #if DUMP_COLUMN_STORAGE
513  void Dump() const;
514 #endif
515 };
516 
517 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Matrix data type that can store values of mixed types.
Definition: scmatrix.hxx:112
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
bool NeedsInterpret() const
ScCloneFlags
Definition: global.hxx:261
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:2350
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:617
bool IsSubTotal() const
ScFormulaCell * pPreviousTrack
sal_uInt8 meCalcState
Definition: formulacell.hxx:86
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
SC_DLLPUBLIC bool GetAutoCalc() const
Definition: document.hxx:1360