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