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