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 <boost/noncopyable.hpp>
27 #include <formula/tokenarray.hxx>
28 #include <osl/conditn.hxx>
29 #include <osl/mutex.hxx>
30 #include <rtl/ref.hxx>
31 #include <svl/listener.hxx>
35 #include "formularesult.hxx"
37 #define ENABLE_THREADED_OPENCL_KERNEL_COMPILATION 0
41 class CLBuildKernelThread
;
42 class CompiledFormula
;
43 class StartListeningContext
;
44 class EndListeningContext
;
45 struct RefUpdateContext
;
46 struct RefUpdateInsertTabContext
;
47 struct RefUpdateDeleteTabContext
;
48 struct RefUpdateMoveTabContext
;
49 class CompileFormulaContext
;
50 class FormulaGroupAreaListener
;
58 struct SC_DLLPUBLIC ScFormulaCellGroup
: boost::noncopyable
66 mutable size_t mnRefCount
;
69 sc::CompiledFormula
* mpCompiledFormula
;
70 ScFormulaCell
*mpTopCell
;
71 SCROW mnLength
; // How many of these do we have ?
76 sal_uInt8 meCalcState
;
77 sal_uInt8 meKernelState
;
80 ~ScFormulaCellGroup();
81 #if ENABLE_THREADED_OPENCL_KERNEL_COMPILATION
82 void scheduleCompilation();
85 void setCode( const ScTokenArray
& rCode
);
86 void setCode( ScTokenArray
* pCode
);
88 ScDocument
& rDoc
, const ScAddress
& rPos
, formula::FormulaGrammar::Grammar eGram
);
89 void compileOpenCLKernel();
91 sc::FormulaGroupAreaListener
* getAreaListener(
92 ScFormulaCell
** ppTopCell
, const ScRange
& rRange
, bool bStartFixed
, bool bEndFixed
);
94 void endAllGroupListening( ScDocument
& rDoc
);
96 #if ENABLE_THREADED_OPENCL_KERNEL_COMPILATION
98 static rtl::Reference
<sc::CLBuildKernelThread
> sxCompilationThread
;
102 inline void intrusive_ptr_add_ref(const ScFormulaCellGroup
*p
)
107 inline void intrusive_ptr_release(const ScFormulaCellGroup
*p
)
109 if( --p
->mnRefCount
== 0 )
114 MM_NONE
= 0, // No matrix formula
115 MM_FORMULA
= 1, // Upper left matrix formula cell
116 MM_REFERENCE
= 2, // Remaining cells, via ocMatRef reference token
117 MM_FAKE
= 3 // Interpret "as-if" matrix formula (legacy)
120 class SC_DLLPUBLIC ScFormulaCell
: public SvtListener
123 ScFormulaCellGroupRef mxGroup
; // re-factoring hack - group of formulae we're part of.
124 ScFormulaResult aResult
;
125 formula::FormulaGrammar::Grammar eTempGrammar
; // used between string (creation) and (re)compilation
126 ScTokenArray
* pCode
; // The (new) token array
127 ScDocument
* pDocument
;
128 ScFormulaCell
* pPrevious
;
129 ScFormulaCell
* pNext
;
130 ScFormulaCell
* pPreviousTrack
;
131 ScFormulaCell
* pNextTrack
;
132 sal_uInt16 nSeenInIteration
; // Iteration cycle in which the cell was last encountered
134 sal_uInt8 cMatrixFlag
: 2; // One of ScMatrixMode
135 bool bDirty
: 1; // Must be (re)calculated
136 bool bChanged
: 1; // Whether something changed regarding display/representation
137 bool bRunning
: 1; // Already interpreting right now
138 bool bCompile
: 1; // Must be (re)compiled
139 bool bSubTotal
: 1; // Cell is part of or contains a SubTotal
140 bool bIsIterCell
: 1; // Cell is part of a circular reference
141 bool bInChangeTrack
: 1; // Cell is in ChangeTrack
142 bool bTableOpDirty
: 1; // Dirty flag for TableOp
143 bool bNeedListening
: 1; // Listeners need to be re-established after UpdateReference
144 bool mbNeedsNumberFormat
: 1; // set the calculated number format as hard number format
145 bool mbPostponedDirty
: 1; // if cell needs to be set dirty later
146 bool mbIsExtRef
: 1; // has references in ScExternalRefManager; never cleared after set
148 enum ScInterpretTailParameter
151 SCITP_FROM_ITERATION
,
152 SCITP_CLOSE_ITERATION_CIRCLE
154 void InterpretTail( ScInterpretTailParameter
);
157 * Update reference in response to cell copy-n-paste.
159 bool UpdateReferenceOnCopy(
160 const sc::RefUpdateContext
& rCxt
, ScDocument
* pUndoDoc
, const ScAddress
* pUndoCellPos
);
162 ScFormulaCell( const ScFormulaCell
& ) SAL_DELETED_FUNCTION
;
165 enum CompareState
{ NotEqual
= 0, EqualInvariant
, EqualRelativeRef
};
168 DECL_FIXEDMEMPOOL_NEWDEL( ScFormulaCell
)
173 virtual ~ScFormulaCell();
175 ScFormulaCell
* Clone() const;
176 ScFormulaCell
* Clone( const ScAddress
& rPos
, int nCloneFlags
) const;
178 ScFormulaCell( ScDocument
* pDoc
, const ScAddress
& rPos
);
181 * Transfer the ownership of the passed token array instance to the
182 * formula cell being constructed. The caller <i>must not</i> pass a NULL
183 * token array pointer.
185 ScFormulaCell( ScDocument
* pDoc
, const ScAddress
& rPos
, ScTokenArray
* pArray
,
186 const formula::FormulaGrammar::Grammar eGrammar
= formula::FormulaGrammar::GRAM_DEFAULT
,
187 sal_uInt8 cMatInd
= MM_NONE
);
189 ScFormulaCell( ScDocument
* pDoc
, const ScAddress
& rPos
, const ScTokenArray
& rArray
,
190 const formula::FormulaGrammar::Grammar eGrammar
= formula::FormulaGrammar::GRAM_DEFAULT
,
191 sal_uInt8 cMatInd
= MM_NONE
);
193 ScFormulaCell( ScDocument
* pDoc
, const ScAddress
& rPos
, const ScFormulaCellGroupRef
& xGroup
,
194 const formula::FormulaGrammar::Grammar
= formula::FormulaGrammar::GRAM_DEFAULT
,
195 sal_uInt8
= MM_NONE
);
197 /** With formula string and grammar to compile with.
198 formula::FormulaGrammar::GRAM_DEFAULT effectively isformula::FormulaGrammar::GRAM_NATIVE_UI that
199 also includes formula::FormulaGrammar::CONV_UNSPECIFIED, therefore uses the address
200 convention associated with rPos::nTab by default. */
201 ScFormulaCell( ScDocument
* pDoc
, const ScAddress
& rPos
,
202 const OUString
& rFormula
,
203 const formula::FormulaGrammar::Grammar
= formula::FormulaGrammar::GRAM_DEFAULT
,
204 sal_uInt8 cMatInd
= MM_NONE
);
206 ScFormulaCell( const ScFormulaCell
& rCell
, ScDocument
& rDoc
, const ScAddress
& rPos
, int nCloneFlags
= SC_CLONECELL_DEFAULT
);
208 size_t GetHash() const;
210 ScFormulaVectorState
GetVectorState() const;
212 void GetFormula( OUString
& rFormula
,
213 const formula::FormulaGrammar::Grammar
= formula::FormulaGrammar::GRAM_DEFAULT
) const;
214 void GetFormula( OUStringBuffer
& rBuffer
,
215 const formula::FormulaGrammar::Grammar
= formula::FormulaGrammar::GRAM_DEFAULT
) const;
217 OUString
GetFormula( sc::CompileFormulaContext
& rCxt
) const;
219 void SetDirty( bool bDirtyFlag
=true );
221 // If setting entire document dirty after load, no broadcasts but still append to FormulaTree.
222 void SetDirtyAfterLoad();
223 void ResetTableOpDirtyVar();
224 void SetTableOpDirty();
225 bool IsDirtyOrInTableOpDirty() const;
226 bool GetDirty() const { return bDirty
; }
228 bool NeedsListening() const { return bNeedListening
; }
229 void SetNeedsListening( bool bVar
);
230 void SetNeedsDirty( bool bVar
);
231 void SetNeedNumberFormat( bool bVal
);
232 bool NeedsNumberFormat() const { return mbNeedsNumberFormat
;}
233 short GetFormatType() const { return nFormatType
; }
234 void Compile(const OUString
& rFormula
,
235 bool bNoListening
= false,
236 const formula::FormulaGrammar::Grammar
= formula::FormulaGrammar::GRAM_DEFAULT
);
238 sc::CompileFormulaContext
& rCxt
, const OUString
& rFormula
, bool bNoListening
= false );
240 void CompileTokenArray( bool bNoListening
= false );
241 void CompileTokenArray( sc::CompileFormulaContext
& rCxt
, bool bNoListening
= false );
242 void CompileXML( sc::CompileFormulaContext
& rCxt
, ScProgress
& rProgress
); // compile temporary string tokens
243 void CalcAfterLoad( sc::CompileFormulaContext
& rCxt
, bool bStartListening
);
244 bool MarkUsedExternalReferences();
246 bool IsIterCell() const { return bIsIterCell
; }
247 sal_uInt16
GetSeenInIteration() const { return nSeenInIteration
; }
249 bool HasOneReference( ScRange
& r
) const;
250 /* Checks if the formula contains reference list that can be
251 expressed by one reference (like A1;A2;A3:A5 -> A1:A5). The
252 reference list is not required to be sorted (i.e. A3;A1;A2 is
253 still recognized as A1:A3), but no overlapping is allowed.
254 If one reference is recognized, the rRange is filled.
256 It is similar to HasOneReference(), but more general.
258 bool HasRefListExpressibleAsOneReference(ScRange
& rRange
) const;
259 bool HasRelNameReference() const;
261 bool UpdateReference(
262 const sc::RefUpdateContext
& rCxt
, ScDocument
* pUndoDoc
= NULL
, const ScAddress
* pUndoCellPos
= NULL
);
265 * Shift the position of formula cell as part of reference update.
267 * @return true if the position has shifted, false otherwise.
269 bool UpdatePosOnShift( const sc::RefUpdateContext
& rCxt
);
272 * Update reference in response to cell insertion or deletion.
274 bool UpdateReferenceOnShift(
275 const sc::RefUpdateContext
& rCxt
, ScDocument
* pUndoDoc
, const ScAddress
* pUndoCellPos
);
278 * Update reference in response to cell move.
280 bool UpdateReferenceOnMove(
281 const sc::RefUpdateContext
& rCxt
, ScDocument
* pUndoDoc
, const ScAddress
* pUndoCellPos
);
283 void TransposeReference();
284 void UpdateTranspose( const ScRange
& rSource
, const ScAddress
& rDest
,
285 ScDocument
* pUndoDoc
);
287 void UpdateGrow( const ScRange
& rArea
, SCCOL nGrowX
, SCROW nGrowY
);
289 void UpdateInsertTab( sc::RefUpdateInsertTabContext
& rCxt
);
290 void UpdateInsertTabAbs(SCTAB nTable
);
291 bool UpdateDeleteTab( sc::RefUpdateDeleteTabContext
& rCxt
);
292 void UpdateMoveTab( sc::RefUpdateMoveTabContext
& rCxt
, SCTAB nTabNo
);
293 void UpdateRenameTab(SCTAB nTable
, const OUString
& rName
);
294 bool TestTabRefAbs(SCTAB nTable
);
295 void UpdateCompile( bool bForceIfNameInUse
= false );
296 void FindRangeNamesInUse(std::set
<sal_uInt16
>& rIndexes
) const;
297 bool IsSubTotal() const { return bSubTotal
;}
298 bool IsChanged() const { return bChanged
;}
299 void SetChanged(bool b
);
300 bool IsEmpty(); // formula::svEmptyCell result
301 // display as empty string if formula::svEmptyCell result
302 bool IsEmptyDisplayedAsString();
303 bool IsValue(); // also true if formula::svEmptyCell
304 bool IsValueNoError();
305 bool IsValueNoError() const;
306 bool IsHybridValueCell(); // for cells after import to deal with inherited number formats
308 svl::SharedString
GetString();
309 const ScMatrix
* GetMatrix();
310 bool GetMatrixOrigin( ScAddress
& rPos
) const;
311 void GetResultDimensions( SCSIZE
& rCols
, SCSIZE
& rRows
);
312 sal_uInt16
GetMatrixEdge( ScAddress
& rOrgPos
) const;
313 sal_uInt16
GetErrCode(); // interpret first if necessary
314 sal_uInt16
GetRawError(); // don't interpret, just return code or result error
315 bool GetErrorOrValue( sal_uInt16
& rErr
, double& rVal
);
316 sc::FormulaResultValue
GetResult();
317 sc::FormulaResultValue
GetResult() const;
318 sal_uInt8
GetMatrixFlag() const { return cMatrixFlag
;}
319 ScTokenArray
* GetCode() { return pCode
;}
320 const ScTokenArray
* GetCode() const { return pCode
;}
322 void SetCode( ScTokenArray
* pNew
);
324 bool IsRunning() const { return bRunning
;}
325 void SetRunning( bool bVal
);
326 void CompileDBFormula( sc::CompileFormulaContext
& rCxt
);
327 void CompileColRowNameFormula( sc::CompileFormulaContext
& rCxt
);
328 ScFormulaCell
* GetPrevious() const { return pPrevious
; }
329 ScFormulaCell
* GetNext() const { return pNext
; }
330 void SetPrevious( ScFormulaCell
* pF
);
331 void SetNext( ScFormulaCell
* pF
);
332 ScFormulaCell
* GetPreviousTrack() const { return pPreviousTrack
; }
333 ScFormulaCell
* GetNextTrack() const { return pNextTrack
; }
334 void SetPreviousTrack( ScFormulaCell
* pF
);
335 void SetNextTrack( ScFormulaCell
* pF
);
337 virtual void Notify( const SfxHint
& rHint
) SAL_OVERRIDE
;
338 virtual void Query( SvtListener::QueryBase
& rQuery
) const SAL_OVERRIDE
;
340 void SetCompile( bool bVal
);
341 ScDocument
* GetDocument() const { return pDocument
;}
342 void SetMatColsRows( SCCOL nCols
, SCROW nRows
, bool bDirtyFlag
=true );
343 void GetMatColsRows( SCCOL
& nCols
, SCROW
& nRows
) const;
345 // cell belongs to ChangeTrack and not to the real document
346 void SetInChangeTrack( bool bVal
);
347 bool IsInChangeTrack() const { return bInChangeTrack
;}
349 // For import filters!
350 void AddRecalcMode( ScRecalcMode
);
351 /** For import only: set a double result. */
352 void SetHybridDouble( double n
);
353 /** For import only: set a string result.
354 If for whatever reason you have to use both, SetHybridDouble() and
355 SetHybridString() or SetHybridFormula(), use SetHybridDouble() first
356 for performance reasons.*/
357 void SetHybridString( const svl::SharedString
& r
);
358 /** For import only: set a temporary formula string to be compiled later.
359 If for whatever reason you have to use both, SetHybridDouble() and
360 SetHybridString() or SetHybridFormula(), use SetHybridDouble() first
361 for performance reasons.*/
362 void SetHybridFormula(
363 const OUString
& r
, const formula::FormulaGrammar::Grammar eGrammar
);
365 OUString
GetHybridFormula() const;
367 void SetResultMatrix( SCCOL nCols
, SCROW nRows
, const ScConstMatrixRef
& pMat
, formula::FormulaToken
* pUL
);
369 /** For import only: set a double result.
370 Use this instead of SetHybridDouble() if there is no (temporary)
371 formula string because the formula is present as a token array, as it
372 is the case for binary Excel import.
374 void SetResultDouble( double n
);
376 void SetResultToken( const formula::FormulaToken
* pToken
);
378 svl::SharedString
GetResultString() const;
380 /* Sets the shared code array to error state in addition to the cell result */
381 void SetErrCode( sal_uInt16 n
);
383 /* Sets just the result to error */
384 void SetResultError( sal_uInt16 n
);
386 bool IsHyperLinkCell() const;
387 EditTextObject
* CreateURLObject();
388 void GetURLResult( OUString
& rURL
, OUString
& rCellText
);
390 /** Determines whether or not the result string contains more than one paragraph */
391 bool IsMultilineResult();
393 bool NeedsInterpret() const;
395 void MaybeInterpret();
398 * Turn a non-grouped cell into the top of a grouped cell.
400 ScFormulaCellGroupRef
CreateCellGroup( SCROW nLen
, bool bInvariant
);
401 ScFormulaCellGroupRef
GetCellGroup() const { return mxGroup
;}
402 void SetCellGroup( const ScFormulaCellGroupRef
&xRef
);
404 CompareState
CompareByTokenArray( ScFormulaCell
& rOther
) const;
406 bool InterpretFormulaGroup();
407 bool InterpretInvariantFormulaGroup();
409 // nOnlyNames may be one or more of SC_LISTENING_NAMES_*
410 void StartListeningTo( ScDocument
* pDoc
);
411 void StartListeningTo( sc::StartListeningContext
& rCxt
);
413 ScDocument
* pDoc
, ScTokenArray
* pArr
= NULL
, ScAddress aPos
= ScAddress() );
414 void EndListeningTo( sc::EndListeningContext
& rCxt
);
416 bool IsShared() const;
417 bool IsSharedTop() const;
418 SCROW
GetSharedTopRow() const;
419 SCROW
GetSharedLength() const;
421 // An estimate of the number of cells referenced by the formula
422 sal_Int32
GetWeight() const;
424 ScTokenArray
* GetSharedCode();
425 const ScTokenArray
* GetSharedCode() const;
427 void SyncSharedCode();
429 bool IsPostponedDirty() const { return mbPostponedDirty
;}
431 void SetIsExtRef() { mbIsExtRef
= true; }
436 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */