1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #ifndef INCLUDED_SC_INC_FORMULACELL_HXX
21 #define INCLUDED_SC_INC_FORMULACELL_HXX
25 #include <formula/tokenarray.hxx>
26 #include <svl/listener.hxx>
29 #include "interpretercontext.hxx"
30 #include "document.hxx"
31 #include "formulalogger.hxx"
32 #include "formularesult.hxx"
36 class StartListeningContext
;
37 class EndListeningContext
;
38 struct RefUpdateContext
;
39 struct RefUpdateInsertTabContext
;
40 struct RefUpdateDeleteTabContext
;
41 struct RefUpdateMoveTabContext
;
42 class CompileFormulaContext
;
43 class FormulaGroupAreaListener
;
44 class UpdatedRangeNames
;
51 enum class SvNumFormatType
: sal_Int16
;
53 struct SC_DLLPUBLIC ScFormulaCellGroup
57 std::unique_ptr
<Impl
> mpImpl
;
61 mutable size_t mnRefCount
;
63 std::unique_ptr
<ScTokenArray
> mpCode
;
64 ScFormulaCell
*mpTopCell
;
65 SCROW mnLength
; // How many of these do we have ?
67 SvNumFormatType mnFormatType
;
70 bool mbPartOfCycle
:1; // To flag FG's part of a cycle
72 sal_uInt8 meCalcState
;
75 ScFormulaCellGroup(const ScFormulaCellGroup
&) = delete;
76 const ScFormulaCellGroup
& operator=(const ScFormulaCellGroup
&) = delete;
77 ~ScFormulaCellGroup();
79 void setCode( const ScTokenArray
& rCode
);
80 void setCode( std::unique_ptr
<ScTokenArray
> pCode
);
82 ScDocument
& rDoc
, const ScAddress
& rPos
, formula::FormulaGrammar::Grammar eGram
);
84 sc::FormulaGroupAreaListener
* getAreaListener(
85 ScFormulaCell
** ppTopCell
, const ScRange
& rRange
, bool bStartFixed
, bool bEndFixed
);
87 void endAllGroupListening( ScDocument
& rDoc
);
90 inline void intrusive_ptr_add_ref(const ScFormulaCellGroup
*p
)
95 inline void intrusive_ptr_release(const ScFormulaCellGroup
*p
)
97 if( --p
->mnRefCount
== 0 )
101 enum class ScMatrixMode
: sal_uInt8
{
102 NONE
= 0, // No matrix formula
103 Formula
= 1, // Upper left matrix formula cell
104 Reference
= 2 // Remaining cells, via ocMatRef reference token
107 class SC_DLLPUBLIC ScFormulaCell
: public SvtListener
110 ScFormulaCellGroupRef mxGroup
; // Group of formulae we're part of
111 bool bDirty
: 1; // Must be (re)calculated
112 bool bTableOpDirty
: 1; // Dirty flag for TableOp
113 bool bChanged
: 1; // Whether something changed regarding display/representation
114 bool bRunning
: 1; // Already interpreting right now
115 bool bCompile
: 1; // Must be (re)compiled
116 bool bSubTotal
: 1; // Cell is part of or contains a SubTotal
117 bool bIsIterCell
: 1; // Cell is part of a circular reference
118 bool bInChangeTrack
: 1; // Cell is in ChangeTrack
119 bool bNeedListening
: 1; // Listeners need to be re-established after UpdateReference
120 bool mbNeedsNumberFormat
: 1; // set the calculated number format as hard number format
121 bool mbAllowNumberFormatChange
: 1; /* allow setting further calculated
122 number formats as hard number format */
123 bool mbPostponedDirty
: 1; // if cell needs to be set dirty later
124 bool mbIsExtRef
: 1; // has references in ScExternalRefManager; never cleared after set
125 bool mbSeenInPath
: 1; // For detecting cycle involving formula groups and singleton formulacells
126 ScMatrixMode cMatrixFlag
: 8;
127 sal_uInt16 nSeenInIteration
: 16; // Iteration cycle in which the cell was last encountered
128 SvNumFormatType nFormatType
: 16;
129 ScFormulaResult aResult
;
130 formula::FormulaGrammar::Grammar eTempGrammar
; // used between string (creation) and (re)compilation
131 // If this cell is in a cell group (mxGroup!=nullptr), then this pCode is a not-owning pointer
132 // to the mxGroup's mpCode, which owns the array. If the cell is not in a group, this is an owning pointer.
133 ScTokenArray
* pCode
; // The token array
134 ScDocument
* pDocument
;
135 ScFormulaCell
* pPrevious
;
136 ScFormulaCell
* pNext
;
137 ScFormulaCell
* pPreviousTrack
;
138 ScFormulaCell
* pNextTrack
;
141 * Update reference in response to cell copy-n-paste.
143 bool UpdateReferenceOnCopy(
144 const sc::RefUpdateContext
& rCxt
, ScDocument
* pUndoDoc
, const ScAddress
* pUndoCellPos
);
146 ScFormulaCell( const ScFormulaCell
& ) = delete;
148 bool CheckComputeDependencies(sc::FormulaLogger::GroupScope
& rScope
, bool fromFirstRow
,
149 SCROW nStartOffset
, SCROW nEndOffset
, bool bCalcDependencyOnly
= false);
150 bool InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope
& aScope
,
151 bool& bDependencyComputed
,
152 bool& bDependencyCheckFailed
,
153 SCROW nStartOffset
, SCROW nEndOffset
);
154 bool InterpretFormulaGroupOpenCL(sc::FormulaLogger::GroupScope
& aScope
,
155 bool& bDependencyComputed
,
156 bool& bDependencyCheckFailed
);
157 bool InterpretInvariantFormulaGroup();
162 enum ScInterpretTailParameter
165 SCITP_FROM_ITERATION
,
166 SCITP_CLOSE_ITERATION_CIRCLE
168 void InterpretTail( ScInterpreterContext
&, ScInterpretTailParameter
);
170 void HandleStuffAfterParallelCalculation(ScInterpreter
* pInterpreter
);
172 enum CompareState
{ NotEqual
= 0, EqualInvariant
, EqualRelativeRef
};
176 virtual ~ScFormulaCell() override
;
178 ScFormulaCell
* Clone() const;
179 ScFormulaCell
* Clone( const ScAddress
& rPos
) const;
181 ScFormulaCell( ScDocument
* pDoc
, const ScAddress
& rPos
);
184 * Transfer the ownership of the passed token array instance to the
185 * formula cell being constructed. The caller <i>must not</i> pass a NULL
186 * token array pointer.
188 ScFormulaCell( ScDocument
* pDoc
, const ScAddress
& rPos
, std::unique_ptr
<ScTokenArray
> pArray
,
189 const formula::FormulaGrammar::Grammar eGrammar
= formula::FormulaGrammar::GRAM_DEFAULT
,
190 ScMatrixMode cMatInd
= ScMatrixMode::NONE
);
192 ScFormulaCell( ScDocument
* pDoc
, const ScAddress
& rPos
, const ScTokenArray
& rArray
,
193 const formula::FormulaGrammar::Grammar eGrammar
= formula::FormulaGrammar::GRAM_DEFAULT
,
194 ScMatrixMode cMatInd
= ScMatrixMode::NONE
);
196 ScFormulaCell( ScDocument
* pDoc
, const ScAddress
& rPos
, const ScFormulaCellGroupRef
& xGroup
,
197 const formula::FormulaGrammar::Grammar
= formula::FormulaGrammar::GRAM_DEFAULT
,
198 ScMatrixMode
= ScMatrixMode::NONE
);
200 /** With formula string and grammar to compile with.
201 formula::FormulaGrammar::GRAM_DEFAULT effectively isformula::FormulaGrammar::GRAM_NATIVE_UI that
202 also includes formula::FormulaGrammar::CONV_UNSPECIFIED, therefore uses the address
203 convention associated with rPos::nTab by default. */
204 ScFormulaCell( ScDocument
* pDoc
, const ScAddress
& rPos
,
205 const OUString
& rFormula
,
206 const formula::FormulaGrammar::Grammar
= formula::FormulaGrammar::GRAM_DEFAULT
,
207 ScMatrixMode cMatInd
= ScMatrixMode::NONE
);
209 ScFormulaCell(const ScFormulaCell
& rCell
, ScDocument
& rDoc
, const ScAddress
& rPos
, ScCloneFlags nCloneFlags
= ScCloneFlags::Default
);
211 size_t GetHash() const;
213 ScFormulaVectorState
GetVectorState() const;
215 void GetFormula( OUString
& rFormula
,
216 const formula::FormulaGrammar::Grammar
= formula::FormulaGrammar::GRAM_DEFAULT
,
217 const ScInterpreterContext
* pContext
= nullptr ) const;
218 void GetFormula( OUStringBuffer
& rBuffer
,
219 const formula::FormulaGrammar::Grammar
= formula::FormulaGrammar::GRAM_DEFAULT
,
220 const ScInterpreterContext
* pContext
= nullptr ) const;
222 OUString
GetFormula( sc::CompileFormulaContext
& rCxt
, const ScInterpreterContext
* pContext
= nullptr ) const;
224 void SetDirty( bool bDirtyFlag
=true );
226 // If setting entire document dirty after load, no broadcasts but still append to FormulaTree.
227 void SetDirtyAfterLoad();
228 void ResetTableOpDirtyVar();
229 void SetTableOpDirty();
231 bool IsDirtyOrInTableOpDirty() const
233 return bDirty
|| (bTableOpDirty
&& pDocument
->IsInInterpreterTableOp());
236 bool GetDirty() const { return bDirty
; }
238 bool NeedsListening() const { return bNeedListening
; }
239 void SetNeedsListening( bool bVar
);
240 void SetNeedsDirty( bool bVar
);
241 void SetNeedNumberFormat( bool bVal
);
242 bool NeedsNumberFormat() const { return mbNeedsNumberFormat
;}
243 SvNumFormatType
GetFormatType() const { return nFormatType
; }
244 void Compile(const OUString
& rFormula
,
246 const formula::FormulaGrammar::Grammar
);
248 sc::CompileFormulaContext
& rCxt
, const OUString
& rFormula
, bool bNoListening
= false );
250 void CompileTokenArray( bool bNoListening
= false );
251 void CompileTokenArray( sc::CompileFormulaContext
& rCxt
, bool bNoListening
= false );
252 void CompileXML( sc::CompileFormulaContext
& rCxt
, ScProgress
& rProgress
); // compile temporary string tokens
253 void CalcAfterLoad( sc::CompileFormulaContext
& rCxt
, bool bStartListening
);
254 bool MarkUsedExternalReferences();
255 bool Interpret(SCROW nStartOffset
= -1, SCROW nEndOffset
= -1);
256 bool IsIterCell() const { return bIsIterCell
; }
257 sal_uInt16
GetSeenInIteration() const { return nSeenInIteration
; }
259 bool HasOneReference( ScRange
& r
) const;
260 /* Checks if the formula contains reference list that can be
261 expressed by one reference (like A1;A2;A3:A5 -> A1:A5). The
262 reference list is not required to be sorted (i.e. A3;A1;A2 is
263 still recognized as A1:A3), but no overlapping is allowed.
264 If one reference is recognized, the rRange is filled.
266 It is similar to HasOneReference(), but more general.
268 bool HasRefListExpressibleAsOneReference(ScRange
& rRange
) const;
270 enum class RelNameRef
272 NONE
, ///< no relative reference from named expression
273 SINGLE
, ///< only single cell relative reference
274 DOUBLE
///< at least one range relative reference from named expression
276 RelNameRef
HasRelNameReference() const;
278 bool UpdateReference(
279 const sc::RefUpdateContext
& rCxt
, ScDocument
* pUndoDoc
= nullptr, const ScAddress
* pUndoCellPos
= nullptr );
282 * Shift the position of formula cell as part of reference update.
284 * @return true if the position has shifted, false otherwise.
286 bool UpdatePosOnShift( const sc::RefUpdateContext
& rCxt
);
289 * Update reference in response to cell insertion or deletion.
291 bool UpdateReferenceOnShift(
292 const sc::RefUpdateContext
& rCxt
, ScDocument
* pUndoDoc
, const ScAddress
* pUndoCellPos
);
295 * Update reference in response to cell move.
297 bool UpdateReferenceOnMove(
298 const sc::RefUpdateContext
& rCxt
, ScDocument
* pUndoDoc
, const ScAddress
* pUndoCellPos
);
300 void TransposeReference();
301 void UpdateTranspose( const ScRange
& rSource
, const ScAddress
& rDest
,
302 ScDocument
* pUndoDoc
);
304 void UpdateGrow( const ScRange
& rArea
, SCCOL nGrowX
, SCROW nGrowY
);
306 void UpdateInsertTab( const sc::RefUpdateInsertTabContext
& rCxt
);
307 void UpdateInsertTabAbs(SCTAB nTable
);
308 void UpdateDeleteTab( const sc::RefUpdateDeleteTabContext
& rCxt
);
309 void UpdateMoveTab( const sc::RefUpdateMoveTabContext
& rCxt
, SCTAB nTabNo
);
310 bool TestTabRefAbs(SCTAB nTable
);
311 void UpdateCompile( bool bForceIfNameInUse
);
312 void FindRangeNamesInUse(sc::UpdatedRangeNames
& rIndexes
) const;
313 bool IsSubTotal() const { return bSubTotal
;}
314 bool IsChanged() const { return bChanged
;}
315 void SetChanged(bool b
);
316 bool IsEmpty(); // formula::svEmptyCell result
317 // display as empty string if formula::svEmptyCell result
318 bool IsEmptyDisplayedAsString();
319 bool IsValue(); // also true if formula::svEmptyCell
320 bool IsValueNoError();
321 bool IsValueNoError() const;
323 svl::SharedString
GetString();
326 * Get a numeric value without potentially triggering re-calculation.
328 double GetRawValue() const;
331 * Get a string value without potentially triggering re-calculation.
333 svl::SharedString
GetRawString() const;
334 const ScMatrix
* GetMatrix();
335 bool GetMatrixOrigin( ScAddress
& rPos
) const;
336 void GetResultDimensions( SCSIZE
& rCols
, SCSIZE
& rRows
);
337 sc::MatrixEdge
GetMatrixEdge( ScAddress
& rOrgPos
) const;
338 FormulaError
GetErrCode(); // interpret first if necessary
339 FormulaError
GetRawError() const; // don't interpret, just return code or result error
340 bool GetErrorOrValue( FormulaError
& rErr
, double& rVal
);
341 sc::FormulaResultValue
GetResult();
342 sc::FormulaResultValue
GetResult() const;
343 ScMatrixMode
GetMatrixFlag() const { return cMatrixFlag
;}
344 ScTokenArray
* GetCode() { return pCode
;}
345 const ScTokenArray
* GetCode() const { return pCode
;}
347 void SetCode( std::unique_ptr
<ScTokenArray
> pNew
);
349 bool IsRunning() const { return bRunning
;}
350 void SetRunning( bool bVal
);
351 void CompileDBFormula( sc::CompileFormulaContext
& rCxt
);
352 void CompileColRowNameFormula( sc::CompileFormulaContext
& rCxt
);
353 ScFormulaCell
* GetPrevious() const { return pPrevious
; }
354 ScFormulaCell
* GetNext() const { return pNext
; }
355 void SetPrevious( ScFormulaCell
* pF
);
356 void SetNext( ScFormulaCell
* pF
);
357 ScFormulaCell
* GetPreviousTrack() const { return pPreviousTrack
; }
358 ScFormulaCell
* GetNextTrack() const { return pNextTrack
; }
359 void SetPreviousTrack( ScFormulaCell
* pF
);
360 void SetNextTrack( ScFormulaCell
* pF
);
362 virtual void Notify( const SfxHint
& rHint
) override
;
363 virtual void Query( SvtListener::QueryBase
& rQuery
) const override
;
365 void SetCompile( bool bVal
);
366 ScDocument
* GetDocument() const { return pDocument
;}
367 void SetMatColsRows( SCCOL nCols
, SCROW nRows
);
368 void GetMatColsRows( SCCOL
& nCols
, SCROW
& nRows
) const;
370 // cell belongs to ChangeTrack and not to the real document
371 void SetInChangeTrack( bool bVal
);
372 bool IsInChangeTrack() const { return bInChangeTrack
;}
374 // For import filters!
375 void AddRecalcMode( ScRecalcMode
);
376 /** For import only: set a double result. */
377 void SetHybridDouble( double n
);
378 /** For import only: set a string result.
379 If for whatever reason you have to use both, SetHybridDouble() and
380 SetHybridString() or SetHybridFormula(), use SetHybridDouble() first
381 for performance reasons.*/
382 void SetHybridString( const svl::SharedString
& r
);
383 /** For import only: set an empty cell result to be displayed as empty string.
384 If for whatever reason you have to use both, SetHybridDouble() and
385 SetHybridEmptyDisplayedAsString() or SetHybridFormula(), use
386 SetHybridDouble() first for performance reasons and use
387 SetHybridEmptyDisplayedAsString() last because SetHybridDouble() and
388 SetHybridString() will override it.*/
389 void SetHybridEmptyDisplayedAsString();
390 /** For import only: set a temporary formula string to be compiled later.
391 If for whatever reason you have to use both, SetHybridDouble() and
392 SetHybridString() or SetHybridFormula(), use SetHybridDouble() first
393 for performance reasons.*/
394 void SetHybridFormula(
395 const OUString
& r
, const formula::FormulaGrammar::Grammar eGrammar
);
397 const OUString
& GetHybridFormula() const;
399 void SetResultMatrix( SCCOL nCols
, SCROW nRows
, const ScConstMatrixRef
& pMat
, const formula::FormulaToken
* pUL
);
401 /** For import only: set a double result.
402 Use this instead of SetHybridDouble() if there is no (temporary)
403 formula string because the formula is present as a token array, as it
404 is the case for binary Excel import.
406 void SetResultDouble( double n
);
408 void SetResultToken( const formula::FormulaToken
* pToken
);
410 svl::SharedString
GetResultString() const;
412 bool HasHybridStringResult() const;
414 /* Sets the shared code array to error state in addition to the cell result */
415 void SetErrCode( FormulaError n
);
417 /* Sets just the result to error */
418 void SetResultError( FormulaError n
);
420 bool IsHyperLinkCell() const;
421 std::unique_ptr
<EditTextObject
> CreateURLObject();
422 void GetURLResult( OUString
& rURL
, OUString
& rCellText
);
424 /** Determines whether or not the result string contains more than one paragraph */
425 bool IsMultilineResult();
427 bool NeedsInterpret() const
430 // Shortcut to force return of current value and not enter Interpret()
431 // as we're looping over all iteration cells.
434 if (!IsDirtyOrInTableOpDirty())
437 return (pDocument
->GetAutoCalc() || (cMatrixFlag
!= ScMatrixMode::NONE
));
440 bool MaybeInterpret()
442 if (NeedsInterpret())
444 assert(!pDocument
->IsThreadedGroupCalcInProgress());
452 * Turn a non-grouped cell into the top of a grouped cell.
454 ScFormulaCellGroupRef
CreateCellGroup( SCROW nLen
, bool bInvariant
);
455 const ScFormulaCellGroupRef
& GetCellGroup() const { return mxGroup
;}
456 void SetCellGroup( const ScFormulaCellGroupRef
&xRef
);
458 CompareState
CompareByTokenArray( const ScFormulaCell
& rOther
) const;
460 bool InterpretFormulaGroup(SCROW nStartOffset
= -1, SCROW nEndOffset
= -1);
462 // nOnlyNames may be one or more of SC_LISTENING_NAMES_*
463 void StartListeningTo( ScDocument
* pDoc
);
464 void StartListeningTo( sc::StartListeningContext
& rCxt
);
466 ScDocument
* pDoc
, ScTokenArray
* pArr
= nullptr, ScAddress aPos
= ScAddress() );
467 void EndListeningTo( sc::EndListeningContext
& rCxt
);
469 bool IsShared() const;
470 bool IsSharedTop() const;
471 SCROW
GetSharedTopRow() const;
472 SCROW
GetSharedLength() const;
474 // An estimate of the number of cells referenced by the formula
475 sal_Int32
GetWeight() const;
477 ScTokenArray
* GetSharedCode();
478 const ScTokenArray
* GetSharedCode() const;
480 void SyncSharedCode();
482 bool IsPostponedDirty() const { return mbPostponedDirty
;}
484 void SetIsExtRef() { mbIsExtRef
= true; }
485 bool GetSeenInPath() const { return mbSeenInPath
; }
486 void SetSeenInPath(bool bSet
) { mbSeenInPath
= bSet
; }
488 #if DUMP_COLUMN_STORAGE
495 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */