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 "formulalogger.hxx"
31 #include "formularesult.hxx"
35 class CompiledFormula
;
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
;
64 ScFormulaCell
*mpTopCell
;
65 SCROW mnLength
; // How many of these do we have ?
67 SvNumFormatType mnFormatType
;
70 bool mbSeenInPath
:1; // For detecting cycle of formula groups
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( 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 ScFormulaResult aResult
;
112 formula::FormulaGrammar::Grammar eTempGrammar
; // used between string (creation) and (re)compilation
113 ScTokenArray
* pCode
; // The (new) token array
114 ScDocument
* pDocument
;
115 ScFormulaCell
* pPrevious
;
116 ScFormulaCell
* pNext
;
117 ScFormulaCell
* pPreviousTrack
;
118 ScFormulaCell
* pNextTrack
;
119 sal_uInt16 nSeenInIteration
; // Iteration cycle in which the cell was last encountered
120 SvNumFormatType nFormatType
;
121 ScMatrixMode cMatrixFlag
;
122 bool bDirty
: 1; // Must be (re)calculated
123 bool bChanged
: 1; // Whether something changed regarding display/representation
124 bool bRunning
: 1; // Already interpreting right now
125 bool bCompile
: 1; // Must be (re)compiled
126 bool bSubTotal
: 1; // Cell is part of or contains a SubTotal
127 bool bIsIterCell
: 1; // Cell is part of a circular reference
128 bool bInChangeTrack
: 1; // Cell is in ChangeTrack
129 bool bTableOpDirty
: 1; // Dirty flag for TableOp
130 bool bNeedListening
: 1; // Listeners need to be re-established after UpdateReference
131 bool mbNeedsNumberFormat
: 1; // set the calculated number format as hard number format
132 bool mbAllowNumberFormatChange
: 1; /* allow setting further calculated
133 number formats as hard number format */
134 bool mbPostponedDirty
: 1; // if cell needs to be set dirty later
135 bool mbIsExtRef
: 1; // has references in ScExternalRefManager; never cleared after set
138 * Update reference in response to cell copy-n-paste.
140 bool UpdateReferenceOnCopy(
141 const sc::RefUpdateContext
& rCxt
, ScDocument
* pUndoDoc
, const ScAddress
* pUndoCellPos
);
143 ScFormulaCell( const ScFormulaCell
& ) = delete;
145 bool InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope
& aScope
);
146 bool InterpretFormulaGroupOpenCL(sc::FormulaLogger::GroupScope
& aScope
);
147 bool InterpretInvariantFormulaGroup();
152 enum ScInterpretTailParameter
155 SCITP_FROM_ITERATION
,
156 SCITP_CLOSE_ITERATION_CIRCLE
158 void InterpretTail( ScInterpreterContext
&, ScInterpretTailParameter
);
160 void HandleStuffAfterParallelCalculation();
162 enum CompareState
{ NotEqual
= 0, EqualInvariant
, EqualRelativeRef
};
164 DECL_FIXEDMEMPOOL_NEWDEL( ScFormulaCell
)
168 virtual ~ScFormulaCell() override
;
170 ScFormulaCell
* Clone() const;
171 ScFormulaCell
* Clone( const ScAddress
& rPos
) const;
173 ScFormulaCell( ScDocument
* pDoc
, const ScAddress
& rPos
);
176 * Transfer the ownership of the passed token array instance to the
177 * formula cell being constructed. The caller <i>must not</i> pass a NULL
178 * token array pointer.
180 ScFormulaCell( ScDocument
* pDoc
, const ScAddress
& rPos
, ScTokenArray
* pArray
,
181 const formula::FormulaGrammar::Grammar eGrammar
= formula::FormulaGrammar::GRAM_DEFAULT
,
182 ScMatrixMode cMatInd
= ScMatrixMode::NONE
);
184 ScFormulaCell( ScDocument
* pDoc
, const ScAddress
& rPos
, const ScTokenArray
& rArray
,
185 const formula::FormulaGrammar::Grammar eGrammar
= formula::FormulaGrammar::GRAM_DEFAULT
,
186 ScMatrixMode cMatInd
= ScMatrixMode::NONE
);
188 ScFormulaCell( ScDocument
* pDoc
, const ScAddress
& rPos
, const ScFormulaCellGroupRef
& xGroup
,
189 const formula::FormulaGrammar::Grammar
= formula::FormulaGrammar::GRAM_DEFAULT
,
190 ScMatrixMode
= ScMatrixMode::NONE
);
192 /** With formula string and grammar to compile with.
193 formula::FormulaGrammar::GRAM_DEFAULT effectively isformula::FormulaGrammar::GRAM_NATIVE_UI that
194 also includes formula::FormulaGrammar::CONV_UNSPECIFIED, therefore uses the address
195 convention associated with rPos::nTab by default. */
196 ScFormulaCell( ScDocument
* pDoc
, const ScAddress
& rPos
,
197 const OUString
& rFormula
,
198 const formula::FormulaGrammar::Grammar
= formula::FormulaGrammar::GRAM_DEFAULT
,
199 ScMatrixMode cMatInd
= ScMatrixMode::NONE
);
201 ScFormulaCell(const ScFormulaCell
& rCell
, ScDocument
& rDoc
, const ScAddress
& rPos
, ScCloneFlags nCloneFlags
= ScCloneFlags::Default
);
203 size_t GetHash() const;
205 ScFormulaVectorState
GetVectorState() const;
207 void GetFormula( OUString
& rFormula
,
208 const formula::FormulaGrammar::Grammar
= formula::FormulaGrammar::GRAM_DEFAULT
,
209 const ScInterpreterContext
* pContext
= nullptr ) const;
210 void GetFormula( OUStringBuffer
& rBuffer
,
211 const formula::FormulaGrammar::Grammar
= formula::FormulaGrammar::GRAM_DEFAULT
,
212 const ScInterpreterContext
* pContext
= nullptr ) const;
214 OUString
GetFormula( sc::CompileFormulaContext
& rCxt
, const ScInterpreterContext
* pContext
= nullptr ) const;
216 void SetDirty( bool bDirtyFlag
=true );
218 // If setting entire document dirty after load, no broadcasts but still append to FormulaTree.
219 void SetDirtyAfterLoad();
220 void ResetTableOpDirtyVar();
221 void SetTableOpDirty();
222 bool IsDirtyOrInTableOpDirty() const;
223 bool GetDirty() const { return bDirty
; }
225 bool NeedsListening() const { return bNeedListening
; }
226 void SetNeedsListening( bool bVar
);
227 void SetNeedsDirty( bool bVar
);
228 void SetNeedNumberFormat( bool bVal
);
229 bool NeedsNumberFormat() const { return mbNeedsNumberFormat
;}
230 SvNumFormatType
GetFormatType() const { return nFormatType
; }
231 void Compile(const OUString
& rFormula
,
233 const formula::FormulaGrammar::Grammar
);
235 sc::CompileFormulaContext
& rCxt
, const OUString
& rFormula
, bool bNoListening
= false );
237 void CompileTokenArray( bool bNoListening
= false );
238 void CompileTokenArray( sc::CompileFormulaContext
& rCxt
, bool bNoListening
= false );
239 void CompileXML( sc::CompileFormulaContext
& rCxt
, ScProgress
& rProgress
); // compile temporary string tokens
240 void CalcAfterLoad( sc::CompileFormulaContext
& rCxt
, bool bStartListening
);
241 bool MarkUsedExternalReferences();
243 bool IsIterCell() const { return bIsIterCell
; }
244 sal_uInt16
GetSeenInIteration() const { return nSeenInIteration
; }
246 bool HasOneReference( ScRange
& r
) const;
247 /* Checks if the formula contains reference list that can be
248 expressed by one reference (like A1;A2;A3:A5 -> A1:A5). The
249 reference list is not required to be sorted (i.e. A3;A1;A2 is
250 still recognized as A1:A3), but no overlapping is allowed.
251 If one reference is recognized, the rRange is filled.
253 It is similar to HasOneReference(), but more general.
255 bool HasRefListExpressibleAsOneReference(ScRange
& rRange
) const;
257 enum class RelNameRef
259 NONE
, ///< no relative reference from named expression
260 SINGLE
, ///< only single cell relative reference
261 DOUBLE
///< at least one range relative reference from named expression
263 RelNameRef
HasRelNameReference() const;
265 bool UpdateReference(
266 const sc::RefUpdateContext
& rCxt
, ScDocument
* pUndoDoc
= nullptr, const ScAddress
* pUndoCellPos
= nullptr );
269 * Shift the position of formula cell as part of reference update.
271 * @return true if the position has shifted, false otherwise.
273 bool UpdatePosOnShift( const sc::RefUpdateContext
& rCxt
);
276 * Update reference in response to cell insertion or deletion.
278 bool UpdateReferenceOnShift(
279 const sc::RefUpdateContext
& rCxt
, ScDocument
* pUndoDoc
, const ScAddress
* pUndoCellPos
);
282 * Update reference in response to cell move.
284 bool UpdateReferenceOnMove(
285 const sc::RefUpdateContext
& rCxt
, ScDocument
* pUndoDoc
, const ScAddress
* pUndoCellPos
);
287 void TransposeReference();
288 void UpdateTranspose( const ScRange
& rSource
, const ScAddress
& rDest
,
289 ScDocument
* pUndoDoc
);
291 void UpdateGrow( const ScRange
& rArea
, SCCOL nGrowX
, SCROW nGrowY
);
293 void UpdateInsertTab( const sc::RefUpdateInsertTabContext
& rCxt
);
294 void UpdateInsertTabAbs(SCTAB nTable
);
295 void UpdateDeleteTab( const sc::RefUpdateDeleteTabContext
& rCxt
);
296 void UpdateMoveTab( const sc::RefUpdateMoveTabContext
& rCxt
, SCTAB nTabNo
);
297 bool TestTabRefAbs(SCTAB nTable
);
298 void UpdateCompile( bool bForceIfNameInUse
);
299 void FindRangeNamesInUse(sc::UpdatedRangeNames
& rIndexes
) const;
300 bool IsSubTotal() const { return bSubTotal
;}
301 bool IsChanged() const { return bChanged
;}
302 void SetChanged(bool b
);
303 bool IsEmpty(); // formula::svEmptyCell result
304 // display as empty string if formula::svEmptyCell result
305 bool IsEmptyDisplayedAsString();
306 bool IsValue(); // also true if formula::svEmptyCell
307 bool IsValueNoError();
308 bool IsValueNoError() const;
310 svl::SharedString
GetString();
313 * Get a numeric value without potentially triggering re-calculation.
315 double GetRawValue() const;
318 * Get a string value without potentially triggering re-calculation.
320 svl::SharedString
GetRawString() const;
321 const ScMatrix
* GetMatrix();
322 bool GetMatrixOrigin( ScAddress
& rPos
) const;
323 void GetResultDimensions( SCSIZE
& rCols
, SCSIZE
& rRows
);
324 sc::MatrixEdge
GetMatrixEdge( ScAddress
& rOrgPos
) const;
325 FormulaError
GetErrCode(); // interpret first if necessary
326 FormulaError
GetRawError(); // don't interpret, just return code or result error
327 bool GetErrorOrValue( FormulaError
& rErr
, double& rVal
);
328 sc::FormulaResultValue
GetResult();
329 sc::FormulaResultValue
GetResult() const;
330 ScMatrixMode
GetMatrixFlag() const { return cMatrixFlag
;}
331 ScTokenArray
* GetCode() { return pCode
;}
332 const ScTokenArray
* GetCode() const { return pCode
;}
334 void SetCode( ScTokenArray
* pNew
);
336 bool IsRunning() const { return bRunning
;}
337 void SetRunning( bool bVal
);
338 void CompileDBFormula( sc::CompileFormulaContext
& rCxt
);
339 void CompileColRowNameFormula( sc::CompileFormulaContext
& rCxt
);
340 ScFormulaCell
* GetPrevious() const { return pPrevious
; }
341 ScFormulaCell
* GetNext() const { return pNext
; }
342 void SetPrevious( ScFormulaCell
* pF
);
343 void SetNext( ScFormulaCell
* pF
);
344 ScFormulaCell
* GetPreviousTrack() const { return pPreviousTrack
; }
345 ScFormulaCell
* GetNextTrack() const { return pNextTrack
; }
346 void SetPreviousTrack( ScFormulaCell
* pF
);
347 void SetNextTrack( ScFormulaCell
* pF
);
349 virtual void Notify( const SfxHint
& rHint
) override
;
350 virtual void Query( SvtListener::QueryBase
& rQuery
) const override
;
352 void SetCompile( bool bVal
);
353 ScDocument
* GetDocument() const { return pDocument
;}
354 void SetMatColsRows( SCCOL nCols
, SCROW nRows
);
355 void GetMatColsRows( SCCOL
& nCols
, SCROW
& nRows
) const;
357 // cell belongs to ChangeTrack and not to the real document
358 void SetInChangeTrack( bool bVal
);
359 bool IsInChangeTrack() const { return bInChangeTrack
;}
361 // For import filters!
362 void AddRecalcMode( ScRecalcMode
);
363 /** For import only: set a double result. */
364 void SetHybridDouble( double n
);
365 /** For import only: set a string result.
366 If for whatever reason you have to use both, SetHybridDouble() and
367 SetHybridString() or SetHybridFormula(), use SetHybridDouble() first
368 for performance reasons.*/
369 void SetHybridString( const svl::SharedString
& r
);
370 /** For import only: set an empty cell result to be displayed as empty string.
371 If for whatever reason you have to use both, SetHybridDouble() and
372 SetHybridEmptyDisplayedAsString() or SetHybridFormula(), use
373 SetHybridDouble() first for performance reasons and use
374 SetHybridEmptyDisplayedAsString() last because SetHybridDouble() and
375 SetHybridString() will override it.*/
376 void SetHybridEmptyDisplayedAsString();
377 /** For import only: set a temporary formula string to be compiled later.
378 If for whatever reason you have to use both, SetHybridDouble() and
379 SetHybridString() or SetHybridFormula(), use SetHybridDouble() first
380 for performance reasons.*/
381 void SetHybridFormula(
382 const OUString
& r
, const formula::FormulaGrammar::Grammar eGrammar
);
384 const OUString
& GetHybridFormula() const;
386 void SetResultMatrix( SCCOL nCols
, SCROW nRows
, const ScConstMatrixRef
& pMat
, const formula::FormulaToken
* pUL
);
388 /** For import only: set a double result.
389 Use this instead of SetHybridDouble() if there is no (temporary)
390 formula string because the formula is present as a token array, as it
391 is the case for binary Excel import.
393 void SetResultDouble( double n
);
395 void SetResultToken( const formula::FormulaToken
* pToken
);
397 svl::SharedString
GetResultString() const;
399 /* Sets the shared code array to error state in addition to the cell result */
400 void SetErrCode( FormulaError n
);
402 /* Sets just the result to error */
403 void SetResultError( FormulaError n
);
405 bool IsHyperLinkCell() const;
406 std::unique_ptr
<EditTextObject
> CreateURLObject();
407 void GetURLResult( OUString
& rURL
, OUString
& rCellText
);
409 /** Determines whether or not the result string contains more than one paragraph */
410 bool IsMultilineResult();
412 bool NeedsInterpret() const;
414 void MaybeInterpret();
417 * Turn a non-grouped cell into the top of a grouped cell.
419 ScFormulaCellGroupRef
CreateCellGroup( SCROW nLen
, bool bInvariant
);
420 const ScFormulaCellGroupRef
& GetCellGroup() const { return mxGroup
;}
421 void SetCellGroup( const ScFormulaCellGroupRef
&xRef
);
423 CompareState
CompareByTokenArray( const ScFormulaCell
& rOther
) const;
425 bool InterpretFormulaGroup();
427 // nOnlyNames may be one or more of SC_LISTENING_NAMES_*
428 void StartListeningTo( ScDocument
* pDoc
);
429 void StartListeningTo( sc::StartListeningContext
& rCxt
);
431 ScDocument
* pDoc
, ScTokenArray
* pArr
= nullptr, ScAddress aPos
= ScAddress() );
432 void EndListeningTo( sc::EndListeningContext
& rCxt
);
434 bool IsShared() const;
435 bool IsSharedTop() const;
436 SCROW
GetSharedTopRow() const;
437 SCROW
GetSharedLength() const;
439 // An estimate of the number of cells referenced by the formula
440 sal_Int32
GetWeight() const;
442 ScTokenArray
* GetSharedCode();
443 const ScTokenArray
* GetSharedCode() const;
445 void SyncSharedCode();
447 bool IsPostponedDirty() const { return mbPostponedDirty
;}
449 void SetIsExtRef() { mbIsExtRef
= true; }
451 #if DUMP_COLUMN_STORAGE
458 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */