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 SC_FORMULACELL_HXX
21 : #define SC_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 0 : inline void intrusive_ptr_add_ref(const ScFormulaCellGroup *p)
91 : {
92 0 : p->mnRefCount++;
93 0 : }
94 :
95 0 : inline void intrusive_ptr_release(const ScFormulaCellGroup *p)
96 : {
97 0 : if( --p->mnRefCount == 0 )
98 0 : delete p;
99 0 : }
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 :
164 : ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos );
165 :
166 : /**
167 : * Transfer the ownership of the passed token array instance to the
168 : * formula cell being constructed. The caller <i>must not</i> pass a NULL
169 : * token array pointer.
170 : */
171 : ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos, ScTokenArray* pArray,
172 : const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_DEFAULT,
173 : sal_uInt8 cMatInd = MM_NONE );
174 :
175 : ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos, const ScTokenArray& rArray,
176 : const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_DEFAULT,
177 : sal_uInt8 cMatInd = MM_NONE );
178 :
179 : ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos, const ScFormulaCellGroupRef& xGroup,
180 : const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT,
181 : sal_uInt8 = MM_NONE );
182 :
183 : /** With formula string and grammar to compile with.
184 : formula::FormulaGrammar::GRAM_DEFAULT effectively isformula::FormulaGrammar::GRAM_NATIVE_UI that
185 : also includes formula::FormulaGrammar::CONV_UNSPECIFIED, therefor uses the address
186 : convention associated with rPos::nTab by default. */
187 : ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos,
188 : const OUString& rFormula,
189 : const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT,
190 : sal_uInt8 cMatInd = MM_NONE );
191 :
192 : ScFormulaCell( const ScFormulaCell& rCell, ScDocument& rDoc, const ScAddress& rPos, int nCloneFlags = SC_CLONECELL_DEFAULT );
193 :
194 : size_t GetHash() const;
195 :
196 : ScFormulaVectorState GetVectorState() const;
197 :
198 : void GetFormula( OUString& rFormula,
199 : const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT ) const;
200 : void GetFormula( OUStringBuffer& rBuffer,
201 : const formula::FormulaGrammar::Grammar = formula::FormulaGrammar::GRAM_DEFAULT ) const;
202 :
203 : OUString GetFormula( sc::CompileFormulaContext& rCxt ) const;
204 :
205 : void SetDirty( bool bDirtyFlag=true );
206 : void SetDirtyVar();
207 : // If setting entire document dirty after load, no broadcasts but still append to FormulaTree.
208 : void SetDirtyAfterLoad();
209 : void ResetTableOpDirtyVar();
210 : void SetTableOpDirty();
211 : bool SwapWithinGroup( ScFormulaCell *pSwap );
212 : bool IsDirtyOrInTableOpDirty() const;
213 : bool GetDirty() const;
214 : void ResetDirty();
215 : bool NeedsListening() const;
216 : void SetNeedsListening( bool bVar );
217 : void SetNeedsDirty( bool bVar );
218 : void SetNeedNumberFormat( bool bVal );
219 : bool NeedsNumberFormat() const;
220 : short GetFormatType() const;
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 : bool IsIterCell() const;
234 : sal_uInt16 GetSeenInIteration() const;
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 : bool IsSubTotal() const;
285 : bool IsChanged() const;
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 IsHybridValueCell(); // for cells after import to deal with inherited number formats
293 : double GetValue();
294 : svl::SharedString GetString();
295 : const ScMatrix* GetMatrix();
296 : bool GetMatrixOrigin( ScAddress& rPos ) const;
297 : void GetResultDimensions( SCSIZE& rCols, SCSIZE& rRows );
298 : sal_uInt16 GetMatrixEdge( ScAddress& rOrgPos ) const;
299 : sal_uInt16 GetErrCode(); // interpret first if necessary
300 : sal_uInt16 GetRawError(); // don't interpret, just return code or result error
301 : bool GetErrorOrValue( sal_uInt16& rErr, double& rVal );
302 : sc::FormulaResultValue GetResult();
303 : sal_uInt8 GetMatrixFlag() const;
304 : ScTokenArray* GetCode();
305 : const ScTokenArray* GetCode() const;
306 :
307 : void SetCode( ScTokenArray* pNew );
308 :
309 : bool IsRunning() const;
310 : void SetRunning( bool bVal );
311 : void CompileDBFormula( sc::CompileFormulaContext& rCxt );
312 : void CompileDBFormula( sc::CompileFormulaContext& rCxt, bool bCreateFormulaString );
313 : void CompileColRowNameFormula( sc::CompileFormulaContext& rCxt );
314 : ScFormulaCell* GetPrevious() const;
315 : ScFormulaCell* GetNext() const;
316 : void SetPrevious( ScFormulaCell* pF );
317 : void SetNext( ScFormulaCell* pF );
318 : ScFormulaCell* GetPreviousTrack() const;
319 : ScFormulaCell* GetNextTrack() const;
320 : void SetPreviousTrack( ScFormulaCell* pF );
321 : void SetNextTrack( ScFormulaCell* pF );
322 :
323 : virtual void Notify( const SfxHint& rHint ) SAL_OVERRIDE;
324 : void SetCompile( bool bVal );
325 : ScDocument* GetDocument() const;
326 : void SetMatColsRows( SCCOL nCols, SCROW nRows, bool bDirtyFlag=true );
327 : void GetMatColsRows( SCCOL& nCols, SCROW& nRows ) const;
328 :
329 : // cell belongs to ChangeTrack and not to the real document
330 : void SetInChangeTrack( bool bVal );
331 : bool IsInChangeTrack() const;
332 :
333 : // For import filters!
334 : void AddRecalcMode( formula::ScRecalcMode );
335 : /** For import only: set a double result. */
336 : void SetHybridDouble( double n );
337 : /** For import only: set a string result.
338 : If for whatever reason you have to use both, SetHybridDouble() and
339 : SetHybridString() or SetHybridFormula(), use SetHybridDouble() first
340 : for performance reasons.*/
341 : void SetHybridString( const OUString& r );
342 : /** For import only: set a temporary formula string to be compiled later.
343 : If for whatever reason you have to use both, SetHybridDouble() and
344 : SetHybridString() or SetHybridFormula(), use SetHybridDouble() first
345 : for performance reasons.*/
346 : void SetHybridFormula(
347 : const OUString& r, const formula::FormulaGrammar::Grammar eGrammar );
348 :
349 : OUString GetHybridFormula() const;
350 :
351 : void SetResultMatrix( SCCOL nCols, SCROW nRows, const ScConstMatrixRef& pMat, formula::FormulaToken* pUL );
352 :
353 : /** For import only: set a double result.
354 : Use this instead of SetHybridDouble() if there is no (temporary)
355 : formula string because the formula is present as a token array, as it
356 : is the case for binary Excel import.
357 : */
358 : void SetResultDouble( double n );
359 :
360 : void SetResultToken( const formula::FormulaToken* pToken );
361 :
362 : svl::SharedString GetResultString() const;
363 :
364 : void SetErrCode( sal_uInt16 n );
365 : bool IsHyperLinkCell() const;
366 : EditTextObject* CreateURLObject();
367 : void GetURLResult( OUString& rURL, OUString& rCellText );
368 :
369 : /** Determines whether or not the result string contains more than one paragraph */
370 : bool IsMultilineResult();
371 :
372 : void MaybeInterpret();
373 :
374 : /**
375 : * Turn a non-grouped cell into the top of a grouped cell.
376 : */
377 : ScFormulaCellGroupRef CreateCellGroup( SCROW nLen, bool bInvariant );
378 : ScFormulaCellGroupRef GetCellGroup();
379 : void SetCellGroup( const ScFormulaCellGroupRef &xRef );
380 :
381 : CompareState CompareByTokenArray( ScFormulaCell& rOther ) const;
382 :
383 : bool InterpretFormulaGroup();
384 : bool InterpretInvariantFormulaGroup();
385 :
386 : // nOnlyNames may be one or more of SC_LISTENING_NAMES_*
387 : void StartListeningTo( ScDocument* pDoc );
388 : void StartListeningTo( sc::StartListeningContext& rCxt );
389 : void EndListeningTo(
390 : ScDocument* pDoc, ScTokenArray* pArr = NULL, ScAddress aPos = ScAddress() );
391 : void EndListeningTo( sc::EndListeningContext& rCxt );
392 :
393 : bool IsShared() const;
394 : bool IsSharedTop() const;
395 : SCROW GetSharedTopRow() const;
396 : SCROW GetSharedLength() const;
397 : ScTokenArray* GetSharedCode();
398 : const ScTokenArray* GetSharedCode() const;
399 :
400 : void SyncSharedCode();
401 :
402 : bool IsPostponedDirty() const;
403 : };
404 :
405 : #endif
406 :
407 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|