Line data Source code
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 : #ifndef INCLUDED_SC_INC_FORMULACELL_HXX
21 : #define INCLUDED_SC_INC_FORMULACELL_HXX
22 :
23 : #include <set>
24 :
25 : #include <boost/noncopyable.hpp>
26 :
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>
32 :
33 : #include "types.hxx"
34 :
35 : #include "formularesult.hxx"
36 :
37 : #define ENABLE_THREADED_OPENCL_KERNEL_COMPILATION 0
38 :
39 : namespace sc {
40 :
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;
51 :
52 : }
53 :
54 : class ScFormulaCell;
55 : class ScProgress;
56 : class ScTokenArray;
57 :
58 : struct SC_DLLPUBLIC ScFormulaCellGroup : boost::noncopyable
59 : {
60 : private:
61 : struct Impl;
62 : Impl* mpImpl;
63 :
64 : public:
65 :
66 : mutable size_t mnRefCount;
67 :
68 : ScTokenArray* mpCode;
69 : sc::CompiledFormula* mpCompiledFormula;
70 : ScFormulaCell *mpTopCell;
71 : SCROW mnLength; // How many of these do we have ?
72 : short mnFormatType;
73 : bool mbInvariant:1;
74 : bool mbSubTotal:1;
75 :
76 : sal_uInt8 meCalcState;
77 : sal_uInt8 meKernelState;
78 :
79 : ScFormulaCellGroup();
80 : ~ScFormulaCellGroup();
81 : #if ENABLE_THREADED_OPENCL_KERNEL_COMPILATION
82 : void scheduleCompilation();
83 : #endif
84 :
85 : void setCode( const ScTokenArray& rCode );
86 : void setCode( ScTokenArray* pCode );
87 : void compileCode(
88 : ScDocument& rDoc, const ScAddress& rPos, formula::FormulaGrammar::Grammar eGram );
89 : void compileOpenCLKernel();
90 :
91 : sc::FormulaGroupAreaListener* getAreaListener(
92 : ScFormulaCell** ppTopCell, const ScRange& rRange, bool bStartFixed, bool bEndFixed );
93 :
94 : void endAllGroupListening( ScDocument& rDoc );
95 :
96 : #if ENABLE_THREADED_OPENCL_KERNEL_COMPILATION
97 : static int snCount;
98 : static rtl::Reference<sc::CLBuildKernelThread> sxCompilationThread;
99 : #endif
100 : };
101 :
102 15309 : inline void intrusive_ptr_add_ref(const ScFormulaCellGroup *p)
103 : {
104 15309 : p->mnRefCount++;
105 15309 : }
106 :
107 15305 : inline void intrusive_ptr_release(const ScFormulaCellGroup *p)
108 : {
109 15305 : if( --p->mnRefCount == 0 )
110 1070 : delete p;
111 15305 : }
112 :
113 : enum ScMatrixMode {
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)
118 : };
119 :
120 : class SC_DLLPUBLIC ScFormulaCell : public SvtListener
121 : {
122 : private:
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
133 : short nFormatType;
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
147 :
148 : enum ScInterpretTailParameter
149 : {
150 : SCITP_NORMAL,
151 : SCITP_FROM_ITERATION,
152 : SCITP_CLOSE_ITERATION_CIRCLE
153 : };
154 : void InterpretTail( ScInterpretTailParameter );
155 :
156 : /**
157 : * Update reference in response to cell copy-n-paste.
158 : */
159 : bool UpdateReferenceOnCopy(
160 : const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, const ScAddress* pUndoCellPos );
161 :
162 : ScFormulaCell( const ScFormulaCell& ) SAL_DELETED_FUNCTION;
163 : public:
164 :
165 : enum CompareState { NotEqual = 0, EqualInvariant, EqualRelativeRef };
166 :
167 : #ifdef USE_MEMPOOL
168 : DECL_FIXEDMEMPOOL_NEWDEL( ScFormulaCell )
169 : #endif
170 :
171 : ScAddress aPos;
172 :
173 : virtual ~ScFormulaCell();
174 :
175 : ScFormulaCell* Clone() const;
176 : ScFormulaCell* Clone( const ScAddress& rPos, int nCloneFlags ) const;
177 :
178 : ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos );
179 :
180 : /**
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.
184 : */
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 );
188 :
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 );
192 :
193 : ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos, const ScFormulaCellGroupRef& xGroup,
194 : const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT,
195 : sal_uInt8 = MM_NONE );
196 :
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 );
205 :
206 : ScFormulaCell( const ScFormulaCell& rCell, ScDocument& rDoc, const ScAddress& rPos, int nCloneFlags = SC_CLONECELL_DEFAULT );
207 :
208 : size_t GetHash() const;
209 :
210 : ScFormulaVectorState GetVectorState() const;
211 :
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;
216 :
217 : OUString GetFormula( sc::CompileFormulaContext& rCxt ) const;
218 :
219 : void SetDirty( bool bDirtyFlag=true );
220 : void SetDirtyVar();
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 12673 : bool GetDirty() const { return bDirty; }
227 : void ResetDirty();
228 618 : bool NeedsListening() const { return bNeedListening; }
229 : void SetNeedsListening( bool bVar );
230 : void SetNeedsDirty( bool bVar );
231 : void SetNeedNumberFormat( bool bVal );
232 1275 : bool NeedsNumberFormat() const { return mbNeedsNumberFormat;}
233 1672 : short GetFormatType() const { return nFormatType; }
234 : void Compile(const OUString& rFormula,
235 : bool bNoListening = false,
236 : const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT );
237 : void Compile(
238 : sc::CompileFormulaContext& rCxt, const OUString& rFormula, bool bNoListening = false );
239 :
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();
245 : void Interpret();
246 0 : bool IsIterCell() const { return bIsIterCell; }
247 0 : sal_uInt16 GetSeenInIteration() const { return nSeenInIteration; }
248 :
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.
255 :
256 : It is similar to HasOneReference(), but more general.
257 : */
258 : bool HasRefListExpressibleAsOneReference(ScRange& rRange) const;
259 : bool HasRelNameReference() const;
260 :
261 : bool UpdateReference(
262 : const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc = NULL, const ScAddress* pUndoCellPos = NULL );
263 :
264 : /**
265 : * Shift the position of formula cell as part of reference update.
266 : *
267 : * @return true if the position has shifted, false otherwise.
268 : */
269 : bool UpdatePosOnShift( const sc::RefUpdateContext& rCxt );
270 :
271 : /**
272 : * Update reference in response to cell insertion or deletion.
273 : */
274 : bool UpdateReferenceOnShift(
275 : const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, const ScAddress* pUndoCellPos );
276 :
277 : /**
278 : * Update reference in response to cell move.
279 : */
280 : bool UpdateReferenceOnMove(
281 : const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, const ScAddress* pUndoCellPos );
282 :
283 : void TransposeReference();
284 : void UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
285 : ScDocument* pUndoDoc );
286 :
287 : void UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY );
288 :
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 1533 : bool IsSubTotal() const { return bSubTotal;}
298 3980 : 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
307 : double GetValue();
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 22997 : sal_uInt8 GetMatrixFlag() const { return cMatrixFlag;}
319 102081 : ScTokenArray* GetCode() { return pCode;}
320 2521 : const ScTokenArray* GetCode() const { return pCode;}
321 :
322 : void SetCode( ScTokenArray* pNew );
323 :
324 11172 : bool IsRunning() const { return bRunning;}
325 : void SetRunning( bool bVal );
326 : void CompileDBFormula( sc::CompileFormulaContext& rCxt );
327 : void CompileColRowNameFormula( sc::CompileFormulaContext& rCxt );
328 158008 : ScFormulaCell* GetPrevious() const { return pPrevious; }
329 29719 : ScFormulaCell* GetNext() const { return pNext; }
330 : void SetPrevious( ScFormulaCell* pF );
331 : void SetNext( ScFormulaCell* pF );
332 66025 : ScFormulaCell* GetPreviousTrack() const { return pPreviousTrack; }
333 73793 : ScFormulaCell* GetNextTrack() const { return pNextTrack; }
334 : void SetPreviousTrack( ScFormulaCell* pF );
335 : void SetNextTrack( ScFormulaCell* pF );
336 :
337 : virtual void Notify( const SfxHint& rHint ) SAL_OVERRIDE;
338 : virtual void Query( SvtListener::QueryBase& rQuery ) const SAL_OVERRIDE;
339 :
340 : void SetCompile( bool bVal );
341 3763 : ScDocument* GetDocument() const { return pDocument;}
342 : void SetMatColsRows( SCCOL nCols, SCROW nRows, bool bDirtyFlag=true );
343 : void GetMatColsRows( SCCOL& nCols, SCROW& nRows ) const;
344 :
345 : // cell belongs to ChangeTrack and not to the real document
346 : void SetInChangeTrack( bool bVal );
347 53853 : bool IsInChangeTrack() const { return bInChangeTrack;}
348 :
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 );
364 :
365 : OUString GetHybridFormula() const;
366 :
367 : void SetResultMatrix( SCCOL nCols, SCROW nRows, const ScConstMatrixRef& pMat, formula::FormulaToken* pUL );
368 :
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.
373 : */
374 : void SetResultDouble( double n );
375 :
376 : void SetResultToken( const formula::FormulaToken* pToken );
377 :
378 : svl::SharedString GetResultString() const;
379 :
380 : /* Sets the shared code array to error state in addition to the cell result */
381 : void SetErrCode( sal_uInt16 n );
382 :
383 : /* Sets just the result to error */
384 : void SetResultError( sal_uInt16 n );
385 :
386 : bool IsHyperLinkCell() const;
387 : EditTextObject* CreateURLObject();
388 : void GetURLResult( OUString& rURL, OUString& rCellText );
389 :
390 : /** Determines whether or not the result string contains more than one paragraph */
391 : bool IsMultilineResult();
392 :
393 : bool NeedsInterpret() const;
394 :
395 : void MaybeInterpret();
396 :
397 : /**
398 : * Turn a non-grouped cell into the top of a grouped cell.
399 : */
400 : ScFormulaCellGroupRef CreateCellGroup( SCROW nLen, bool bInvariant );
401 12563 : ScFormulaCellGroupRef GetCellGroup() const { return mxGroup;}
402 : void SetCellGroup( const ScFormulaCellGroupRef &xRef );
403 :
404 : CompareState CompareByTokenArray( ScFormulaCell& rOther ) const;
405 :
406 : bool InterpretFormulaGroup();
407 : bool InterpretInvariantFormulaGroup();
408 :
409 : // nOnlyNames may be one or more of SC_LISTENING_NAMES_*
410 : void StartListeningTo( ScDocument* pDoc );
411 : void StartListeningTo( sc::StartListeningContext& rCxt );
412 : void EndListeningTo(
413 : ScDocument* pDoc, ScTokenArray* pArr = NULL, ScAddress aPos = ScAddress() );
414 : void EndListeningTo( sc::EndListeningContext& rCxt );
415 :
416 : bool IsShared() const;
417 : bool IsSharedTop() const;
418 : SCROW GetSharedTopRow() const;
419 : SCROW GetSharedLength() const;
420 :
421 : // An estimate of the number of cells referenced by the formula
422 : sal_Int32 GetWeight() const;
423 :
424 : ScTokenArray* GetSharedCode();
425 : const ScTokenArray* GetSharedCode() const;
426 :
427 : void SyncSharedCode();
428 :
429 314 : bool IsPostponedDirty() const { return mbPostponedDirty;}
430 :
431 247 : void SetIsExtRef() { mbIsExtRef = true; }
432 : };
433 :
434 : #endif
435 :
436 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|