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 :
51 : }
52 :
53 : class ScFormulaCell;
54 : class ScProgress;
55 : class ScTokenArray;
56 : struct ScSimilarFormulaDelta;
57 :
58 : struct SC_DLLPUBLIC ScFormulaCellGroup : boost::noncopyable
59 : {
60 : mutable size_t mnRefCount;
61 :
62 : ScTokenArray* mpCode;
63 : sc::CompiledFormula* mpCompiledFormula;
64 : ScFormulaCell *mpTopCell;
65 : SCROW mnLength; // How many of these do we have ?
66 : short mnFormatType;
67 : bool mbInvariant:1;
68 : bool mbSubTotal:1;
69 :
70 : sal_uInt8 meCalcState;
71 : sal_uInt8 meKernelState;
72 :
73 : ScFormulaCellGroup();
74 : ~ScFormulaCellGroup();
75 :
76 : void scheduleCompilation();
77 :
78 : void setCode( const ScTokenArray& rCode );
79 : void setCode( ScTokenArray* pCode );
80 : void compileCode(
81 : ScDocument& rDoc, const ScAddress& rPos, formula::FormulaGrammar::Grammar eGram );
82 : void compileOpenCLKernel();
83 :
84 : #if ENABLE_THREADED_OPENCL_KERNEL_COMPILATION
85 : static int snCount;
86 : static rtl::Reference<sc::CLBuildKernelThread> sxCompilationThread;
87 : #endif
88 : };
89 :
90 26846 : inline void intrusive_ptr_add_ref(const ScFormulaCellGroup *p)
91 : {
92 26846 : p->mnRefCount++;
93 26846 : }
94 :
95 26846 : inline void intrusive_ptr_release(const ScFormulaCellGroup *p)
96 : {
97 26846 : if( --p->mnRefCount == 0 )
98 2042 : delete p;
99 26846 : }
100 :
101 : enum ScMatrixMode {
102 : MM_NONE = 0, // No matrix formula
103 : MM_FORMULA = 1, // Upper left matrix formula cell
104 : MM_REFERENCE = 2, // Remaining cells, via ocMatRef reference token
105 : MM_FAKE = 3 // Interpret "as-if" matrix formula (legacy)
106 : };
107 :
108 : class SC_DLLPUBLIC ScFormulaCell : public SvtListener
109 : {
110 : private:
111 : ScFormulaCellGroupRef mxGroup; // re-factoring hack - group of formulae we're part of.
112 : ScFormulaResult aResult;
113 : formula::FormulaGrammar::Grammar eTempGrammar; // used between string (creation) and (re)compilation
114 : ScTokenArray* pCode; // The (new) token array
115 : ScDocument* pDocument;
116 : ScFormulaCell* pPrevious;
117 : ScFormulaCell* pNext;
118 : ScFormulaCell* pPreviousTrack;
119 : ScFormulaCell* pNextTrack;
120 : sal_uInt16 nSeenInIteration; // Iteration cycle in which the cell was last encountered
121 : sal_uInt8 cMatrixFlag; // One of ScMatrixMode
122 : short nFormatType;
123 : bool bDirty : 1; // Must be (re)calculated
124 : bool bChanged : 1; // Whether something changed regarding display/representation
125 : bool bRunning : 1; // Already interpreting right now
126 : bool bCompile : 1; // Must be (re)compiled
127 : bool bSubTotal : 1; // Cell is part of or contains a SubTotal
128 : bool bIsIterCell : 1; // Cell is part of a circular reference
129 : bool bInChangeTrack : 1; // Cell is in ChangeTrack
130 : bool bTableOpDirty : 1; // Dirty flag for TableOp
131 : bool bNeedListening : 1; // Listeners need to be re-established after UpdateReference
132 : bool mbNeedsNumberFormat : 1; // set the calculated number format as hard number format
133 : bool mbPostponedDirty : 1; // if cell needs to be set dirty later
134 :
135 : enum ScInterpretTailParameter
136 : {
137 : SCITP_NORMAL,
138 : SCITP_FROM_ITERATION,
139 : SCITP_CLOSE_ITERATION_CIRCLE
140 : };
141 : void InterpretTail( ScInterpretTailParameter );
142 :
143 : /**
144 : * Update reference in response to cell copy-n-paste.
145 : */
146 : bool UpdateReferenceOnCopy(
147 : const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, const ScAddress* pUndoCellPos );
148 :
149 : ScFormulaCell( const ScFormulaCell& );
150 : public:
151 :
152 : enum CompareState { NotEqual = 0, EqualInvariant, EqualRelativeRef };
153 :
154 : #ifdef USE_MEMPOOL
155 : DECL_FIXEDMEMPOOL_NEWDEL( ScFormulaCell )
156 : #endif
157 :
158 : ScAddress aPos;
159 :
160 : virtual ~ScFormulaCell();
161 :
162 : ScFormulaCell* Clone() const;
163 : ScFormulaCell* Clone( const ScAddress& rPos, int nCloneFlags ) const;
164 :
165 : ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos );
166 :
167 : /**
168 : * Transfer the ownership of the passed token array instance to the
169 : * formula cell being constructed. The caller <i>must not</i> pass a NULL
170 : * token array pointer.
171 : */
172 : ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos, ScTokenArray* pArray,
173 : const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_DEFAULT,
174 : sal_uInt8 cMatInd = MM_NONE );
175 :
176 : ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos, const ScTokenArray& rArray,
177 : const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_DEFAULT,
178 : sal_uInt8 cMatInd = MM_NONE );
179 :
180 : ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos, const ScFormulaCellGroupRef& xGroup,
181 : const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT,
182 : sal_uInt8 = MM_NONE );
183 :
184 : /** With formula string and grammar to compile with.
185 : formula::FormulaGrammar::GRAM_DEFAULT effectively isformula::FormulaGrammar::GRAM_NATIVE_UI that
186 : also includes formula::FormulaGrammar::CONV_UNSPECIFIED, therefore uses the address
187 : convention associated with rPos::nTab by default. */
188 : ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos,
189 : const OUString& rFormula,
190 : const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT,
191 : sal_uInt8 cMatInd = MM_NONE );
192 :
193 : ScFormulaCell( const ScFormulaCell& rCell, ScDocument& rDoc, const ScAddress& rPos, int nCloneFlags = SC_CLONECELL_DEFAULT );
194 :
195 : size_t GetHash() const;
196 :
197 : ScFormulaVectorState GetVectorState() const;
198 :
199 : void GetFormula( OUString& rFormula,
200 : const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT ) const;
201 : void GetFormula( OUStringBuffer& rBuffer,
202 : const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT ) const;
203 :
204 : OUString GetFormula( sc::CompileFormulaContext& rCxt ) const;
205 :
206 : void SetDirty( bool bDirtyFlag=true );
207 : void SetDirtyVar();
208 : // If setting entire document dirty after load, no broadcasts but still append to FormulaTree.
209 : void SetDirtyAfterLoad();
210 : void ResetTableOpDirtyVar();
211 : void SetTableOpDirty();
212 : bool IsDirtyOrInTableOpDirty() const;
213 15387 : bool GetDirty() const { return bDirty; }
214 : void ResetDirty();
215 572 : bool NeedsListening() const { return bNeedListening; }
216 : void SetNeedsListening( bool bVar );
217 : void SetNeedsDirty( bool bVar );
218 : void SetNeedNumberFormat( bool bVal );
219 1220 : bool NeedsNumberFormat() const { return mbNeedsNumberFormat;}
220 3312 : short GetFormatType() const { return nFormatType; }
221 : void Compile(const OUString& rFormula,
222 : bool bNoListening = false,
223 : const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT );
224 : void Compile(
225 : sc::CompileFormulaContext& rCxt, const OUString& rFormula, bool bNoListening = false );
226 :
227 : void CompileTokenArray( bool bNoListening = false );
228 : void CompileTokenArray( sc::CompileFormulaContext& rCxt, bool bNoListening = false );
229 : void CompileXML( sc::CompileFormulaContext& rCxt, ScProgress& rProgress ); // compile temporary string tokens
230 : void CalcAfterLoad( sc::CompileFormulaContext& rCxt );
231 : bool MarkUsedExternalReferences();
232 : void Interpret();
233 0 : bool IsIterCell() const { return bIsIterCell; }
234 0 : sal_uInt16 GetSeenInIteration() const { return nSeenInIteration; }
235 :
236 : bool HasOneReference( ScRange& r ) const;
237 : /* Checks if the formula contains reference list that can be
238 : expressed by one reference (like A1;A2;A3:A5 -> A1:A5). The
239 : reference list is not required to be sorted (i.e. A3;A1;A2 is
240 : still recognized as A1:A3), but no overlapping is allowed.
241 : If one reference is recognized, the rRange is filled.
242 :
243 : It is similar to HasOneReference(), but more general.
244 : */
245 : bool HasRefListExpressibleAsOneReference(ScRange& rRange) const;
246 : bool HasRelNameReference() const;
247 :
248 : bool UpdateReference(
249 : const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc = NULL, const ScAddress* pUndoCellPos = NULL );
250 :
251 : /**
252 : * Shift the position of formula cell as part of reference update.
253 : *
254 : * @return true if the position has shifted, false otherwise.
255 : */
256 : bool UpdatePosOnShift( const sc::RefUpdateContext& rCxt );
257 :
258 : /**
259 : * Update reference in response to cell insertion or deletion.
260 : */
261 : bool UpdateReferenceOnShift(
262 : const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, const ScAddress* pUndoCellPos );
263 :
264 : /**
265 : * Update reference in response to cell move.
266 : */
267 : bool UpdateReferenceOnMove(
268 : const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc, const ScAddress* pUndoCellPos );
269 :
270 : void TransposeReference();
271 : void UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
272 : ScDocument* pUndoDoc );
273 :
274 : void UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY );
275 :
276 : void UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt );
277 : void UpdateInsertTabAbs(SCTAB nTable);
278 : bool UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt );
279 : void UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt, SCTAB nTabNo );
280 : void UpdateRenameTab(SCTAB nTable, const OUString& rName);
281 : bool TestTabRefAbs(SCTAB nTable);
282 : void UpdateCompile( bool bForceIfNameInUse = false );
283 : void FindRangeNamesInUse(std::set<sal_uInt16>& rIndexes) const;
284 3066 : bool IsSubTotal() const { return bSubTotal;}
285 7972 : bool IsChanged() const { return bChanged;}
286 : void SetChanged(bool b);
287 : bool IsEmpty(); // formula::svEmptyCell result
288 : // display as empty string if formula::svEmptyCell result
289 : bool IsEmptyDisplayedAsString();
290 : bool IsValue(); // also true if formula::svEmptyCell
291 : bool IsValueNoError();
292 : bool IsValueNoError() const;
293 : bool IsHybridValueCell(); // for cells after import to deal with inherited number formats
294 : double GetValue();
295 : svl::SharedString GetString();
296 : const ScMatrix* GetMatrix();
297 : bool GetMatrixOrigin( ScAddress& rPos ) const;
298 : void GetResultDimensions( SCSIZE& rCols, SCSIZE& rRows );
299 : sal_uInt16 GetMatrixEdge( ScAddress& rOrgPos ) const;
300 : sal_uInt16 GetErrCode(); // interpret first if necessary
301 : sal_uInt16 GetRawError(); // don't interpret, just return code or result error
302 : bool GetErrorOrValue( sal_uInt16& rErr, double& rVal );
303 : sc::FormulaResultValue GetResult();
304 : sc::FormulaResultValue GetResult() const;
305 38217 : sal_uInt8 GetMatrixFlag() const { return cMatrixFlag;}
306 206886 : ScTokenArray* GetCode() { return pCode;}
307 5269 : const ScTokenArray* GetCode() const { return pCode;}
308 :
309 : void SetCode( ScTokenArray* pNew );
310 :
311 12471 : bool IsRunning() const { return bRunning;}
312 : void SetRunning( bool bVal );
313 : void CompileDBFormula( sc::CompileFormulaContext& rCxt );
314 : void CompileColRowNameFormula( sc::CompileFormulaContext& rCxt );
315 303292 : ScFormulaCell* GetPrevious() const { return pPrevious; }
316 58432 : ScFormulaCell* GetNext() const { return pNext; }
317 : void SetPrevious( ScFormulaCell* pF );
318 : void SetNext( ScFormulaCell* pF );
319 139398 : ScFormulaCell* GetPreviousTrack() const { return pPreviousTrack; }
320 144018 : ScFormulaCell* GetNextTrack() const { return pNextTrack; }
321 : void SetPreviousTrack( ScFormulaCell* pF );
322 : void SetNextTrack( ScFormulaCell* pF );
323 :
324 : virtual void Notify( const SfxHint& rHint ) SAL_OVERRIDE;
325 : virtual void Query( SvtListener::QueryBase& rQuery ) const SAL_OVERRIDE;
326 :
327 : void SetCompile( bool bVal );
328 5139 : ScDocument* GetDocument() const { return pDocument;}
329 : void SetMatColsRows( SCCOL nCols, SCROW nRows, bool bDirtyFlag=true );
330 : void GetMatColsRows( SCCOL& nCols, SCROW& nRows ) const;
331 :
332 : // cell belongs to ChangeTrack and not to the real document
333 : void SetInChangeTrack( bool bVal );
334 118364 : bool IsInChangeTrack() const { return bInChangeTrack;}
335 :
336 : // For import filters!
337 : void AddRecalcMode( formula::ScRecalcMode );
338 : /** For import only: set a double result. */
339 : void SetHybridDouble( double n );
340 : /** For import only: set a string result.
341 : If for whatever reason you have to use both, SetHybridDouble() and
342 : SetHybridString() or SetHybridFormula(), use SetHybridDouble() first
343 : for performance reasons.*/
344 : void SetHybridString( const svl::SharedString& r );
345 : /** For import only: set a temporary formula string to be compiled later.
346 : If for whatever reason you have to use both, SetHybridDouble() and
347 : SetHybridString() or SetHybridFormula(), use SetHybridDouble() first
348 : for performance reasons.*/
349 : void SetHybridFormula(
350 : const OUString& r, const formula::FormulaGrammar::Grammar eGrammar );
351 :
352 : OUString GetHybridFormula() const;
353 :
354 : void SetResultMatrix( SCCOL nCols, SCROW nRows, const ScConstMatrixRef& pMat, formula::FormulaToken* pUL );
355 :
356 : /** For import only: set a double result.
357 : Use this instead of SetHybridDouble() if there is no (temporary)
358 : formula string because the formula is present as a token array, as it
359 : is the case for binary Excel import.
360 : */
361 : void SetResultDouble( double n );
362 :
363 : void SetResultToken( const formula::FormulaToken* pToken );
364 :
365 : svl::SharedString GetResultString() const;
366 :
367 : void SetErrCode( sal_uInt16 n );
368 : bool IsHyperLinkCell() const;
369 : EditTextObject* CreateURLObject();
370 : void GetURLResult( OUString& rURL, OUString& rCellText );
371 :
372 : /** Determines whether or not the result string contains more than one paragraph */
373 : bool IsMultilineResult();
374 :
375 : bool NeedsInterpret() const;
376 :
377 : void MaybeInterpret();
378 :
379 : /**
380 : * Turn a non-grouped cell into the top of a grouped cell.
381 : */
382 : ScFormulaCellGroupRef CreateCellGroup( SCROW nLen, bool bInvariant );
383 19062 : ScFormulaCellGroupRef GetCellGroup() const { return mxGroup;}
384 : void SetCellGroup( const ScFormulaCellGroupRef &xRef );
385 :
386 : CompareState CompareByTokenArray( ScFormulaCell& rOther ) const;
387 :
388 : bool InterpretFormulaGroup();
389 : bool InterpretInvariantFormulaGroup();
390 :
391 : // nOnlyNames may be one or more of SC_LISTENING_NAMES_*
392 : void StartListeningTo( ScDocument* pDoc );
393 : void StartListeningTo( sc::StartListeningContext& rCxt );
394 : void EndListeningTo(
395 : ScDocument* pDoc, ScTokenArray* pArr = NULL, ScAddress aPos = ScAddress() );
396 : void EndListeningTo( sc::EndListeningContext& rCxt );
397 :
398 : bool IsShared() const;
399 : bool IsSharedTop() const;
400 : SCROW GetSharedTopRow() const;
401 : SCROW GetSharedLength() const;
402 : ScTokenArray* GetSharedCode();
403 : const ScTokenArray* GetSharedCode() const;
404 :
405 : void SyncSharedCode();
406 :
407 572 : bool IsPostponedDirty() const { return mbPostponedDirty;}
408 : };
409 :
410 : #endif
411 :
412 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|