merged tag ooo/OOO330_m14
[LibreOffice.git] / sc / inc / formularesult.hxx
blobbd99cca8f5d92c67fbf8574439d2ec5eed6f7ed8
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 #ifndef SC_FORMULARESULT_HXX
29 #define SC_FORMULARESULT_HXX
31 #include "token.hxx"
34 /** Store a variable formula cell result, balancing between runtime performance
35 and memory consumption. */
36 class ScFormulaResult
38 typedef unsigned char Multiline;
39 static const Multiline MULTILINE_UNKNOWN = 0;
40 static const Multiline MULTILINE_FALSE = 1;
41 static const Multiline MULTILINE_TRUE = 2;
43 union
45 double mfValue; // double result direct for performance and memory consumption
46 const formula::FormulaToken* mpToken; // if not, result token obtained from interpreter
48 USHORT mnError; // error code
49 bool mbToken :1; // whether content of union is a token
50 bool mbEmpty :1; // empty cell result
51 bool mbEmptyDisplayedAsString :1; // only if mbEmpty
52 Multiline meMultiline :2; // result is multiline
54 /** Reset mnError, mbEmpty and mbEmptyDisplayedAsString to their defaults
55 prior to assigning other types */
56 inline void ResetToDefaults();
58 /** If token is of formula::svError set error code and decrement RefCount.
59 If token is of formula::svEmptyCell set mbEmpty and mbEmptyAsString and
60 decrement RefCount.
61 If token is of formula::svDouble set mfValue and decrement RefCount.
62 Else assign token to mpToken. NULL is valid => svUnknown.
63 Other member variables are set accordingly.
64 @precondition: Token MUST had been IncRef'ed prior to this call!
65 @precondition: An already existing different mpToken MUST had been
66 DecRef'ed prior to this call, p will be assigned to mpToken if not
67 resolved.
68 ATTENTION! Token may get deleted in this call! */
69 inline void ResolveToken( const formula::FormulaToken * p );
71 public:
72 /** Effectively type svUnknown. */
73 ScFormulaResult()
74 : mpToken(NULL), mnError(0), mbToken(true),
75 mbEmpty(false), mbEmptyDisplayedAsString(false),
76 meMultiline(MULTILINE_UNKNOWN) {}
78 ScFormulaResult( const ScFormulaResult & r )
79 : mnError( r.mnError), mbToken( r.mbToken),
80 mbEmpty( r.mbEmpty),
81 mbEmptyDisplayedAsString( r.mbEmptyDisplayedAsString),
82 meMultiline( r.meMultiline)
84 if (mbToken)
86 mpToken = r.mpToken;
87 if (mpToken)
89 // Since matrix dimension and
90 // results are assigned to a matrix
91 // cell formula token we have to
92 // clone that instead of sharing it.
93 const ScMatrixFormulaCellToken* pMatFormula =
94 r.GetMatrixFormulaCellToken();
95 if (pMatFormula)
96 mpToken = new ScMatrixFormulaCellToken( *pMatFormula);
97 mpToken->IncRef();
100 else
101 mfValue = r.mfValue;
104 /** Same comments as for SetToken() apply! */
105 explicit ScFormulaResult( const formula::FormulaToken* p )
106 : mnError(0), mbToken(false),
107 mbEmpty(false), mbEmptyDisplayedAsString(false),
108 meMultiline(MULTILINE_UNKNOWN)
110 SetToken( p);
113 ~ScFormulaResult()
115 if (mbToken && mpToken)
116 mpToken->DecRef();
119 /** Well, guess what ... */
120 inline ScFormulaResult & operator=( const ScFormulaResult & r );
122 /** Assignment as in operator=() but without return */
123 inline void Assign( const ScFormulaResult & r );
125 /** Sets a direct double if token type is formula::svDouble, or mbEmpty if
126 formula::svEmptyCell, else token. If p is NULL, that is set as well, effectively
127 resulting in GetType()==svUnknown. If the already existing result is
128 ScMatrixFormulaCellToken, the upper left ist set to token.
130 ATTENTION! formula::FormulaToken had to be allocated using 'new' and if of type
131 formula::svDouble and no RefCount was set may not be used after this call
132 because it was deleted after decrement! */
133 inline void SetToken( const formula::FormulaToken* p );
135 /** May be NULL if SetToken() did so, also if type formula::svDouble or formula::svError! */
136 inline formula::FormulaConstTokenRef GetToken() const;
138 /** Return upper left token if formula::svMatrixCell, else return GetToken().
139 May be NULL if SetToken() did so, also if type formula::svDouble or formula::svError! */
140 inline formula::FormulaConstTokenRef GetCellResultToken() const;
142 /** Return type of result, including formula::svError, formula::svEmptyCell, formula::svDouble and
143 formula::svMatrixCell. */
144 inline formula::StackVar GetType() const;
146 /** If type is formula::svMatrixCell return the type of upper left element, else
147 GetType() */
148 inline formula::StackVar GetCellResultType() const;
150 /** If type is formula::svEmptyCell (including matrix upper left) and should be
151 displayed as empty string */
152 inline bool IsEmptyDisplayedAsString() const;
154 /** Test for cell result type formula::svDouble, including upper left if
155 formula::svMatrixCell. Also included is formula::svError for legacy, because previously
156 an error result was treated like a numeric value at some places in
157 ScFormulaCell. Also included is formula::svEmptyCell as a reference to an empty
158 cell usually is treated as numeric 0. Use GetCellResultType() for
159 details instead. */
160 inline bool IsValue() const;
162 /** Determines whether or not the result is a string containing more than
163 one paragraph */
164 inline bool IsMultiline() const;
166 /** Get error code if set or GetCellResultType() is formula::svError or svUnknown,
167 else 0. */
168 inline USHORT GetResultError() const;
170 /** Set error code, don't touch token or double. */
171 inline void SetResultError( USHORT nErr );
173 /** Set direct double. Shouldn't be used externally except in
174 ScFormulaCell for rounded CalcAsShown or SetErrCode(). If
175 ScMatrixFormulaCellToken the token isn't replaced but upper left result
176 is modified instead, but only if it was of type formula::svDouble before or not
177 set at all. */
178 inline void SetDouble( double f );
180 /** Return value if type formula::svDouble or formula::svHybridCell or formula::svMatrixCell and upper
181 left formula::svDouble, else 0.0 */
182 inline double GetDouble() const;
184 /** Return string if type formula::svString or formula::svHybridCell or formula::svMatrixCell and
185 upper left formula::svString, else empty string. */
186 inline const String & GetString() const;
188 /** Return matrix if type formula::svMatrixCell and ScMatrix present, else NULL. */
189 inline ScConstMatrixRef GetMatrix() const;
191 /** Return formula string if type formula::svHybridCell, else empty string. */
192 inline const String & GetHybridFormula() const;
194 /** Should only be used by import filters, best in the order
195 SetHybridDouble(), SetHybridString(), or only SetHybridString() for
196 formula string to be compiled later. */
197 inline void SetHybridDouble( double f );
199 /** Should only be used by import filters, best in the order
200 SetHybridDouble(), SetHybridString()/SetHybridFormula(), or only
201 SetHybridFormula() for formula string to be compiled later. */
202 inline void SetHybridString( const String & rStr );
204 /** Should only be used by import filters, best in the order
205 SetHybridDouble(), SetHybridString()/SetHybridFormula(), or only
206 SetHybridFormula() for formula string to be compiled later. */
207 inline void SetHybridFormula( const String & rFormula );
209 /** Get the const ScMatrixFormulaCellToken* if token is of that type, else
210 NULL. */
211 inline const ScMatrixFormulaCellToken* GetMatrixFormulaCellToken() const;
213 /** Get the ScMatrixFormulaCellToken* if token is of that type, else NULL.
214 Shouldn't be used externally except by ScFormulaCell::SetMatColsRows(). */
215 inline ScMatrixFormulaCellToken* GetMatrixFormulaCellTokenNonConst();
219 inline void ScFormulaResult::ResetToDefaults()
221 mnError = 0;
222 mbEmpty = false;
223 mbEmptyDisplayedAsString = false;
224 meMultiline = MULTILINE_UNKNOWN;
228 inline void ScFormulaResult::ResolveToken( const formula::FormulaToken * p )
230 ResetToDefaults();
231 if (!p)
233 mpToken = p;
234 mbToken = true;
236 else
238 switch (p->GetType())
240 case formula::svError:
241 mnError = p->GetError();
242 p->DecRef();
243 mbToken = false;
244 // set in case mnError is 0 now, which shouldn't happen but ...
245 mfValue = 0.0;
246 meMultiline = MULTILINE_FALSE;
247 break;
248 case formula::svEmptyCell:
249 mbEmpty = true;
250 mbEmptyDisplayedAsString = static_cast<const ScEmptyCellToken*>(p)->IsDisplayedAsString();
251 p->DecRef();
252 mbToken = false;
253 meMultiline = MULTILINE_FALSE;
254 break;
255 case formula::svDouble:
256 mfValue = p->GetDouble();
257 p->DecRef();
258 mbToken = false;
259 meMultiline = MULTILINE_FALSE;
260 break;
261 default:
262 mpToken = p;
263 mbToken = true;
269 inline ScFormulaResult & ScFormulaResult::operator=( const ScFormulaResult & r )
271 Assign( r);
272 return *this;
276 inline void ScFormulaResult::Assign( const ScFormulaResult & r )
278 if (this == &r)
279 return;
280 if (r.mbEmpty)
282 if (mbToken && mpToken)
283 mpToken->DecRef();
284 mbToken = false;
285 mbEmpty = true;
286 mbEmptyDisplayedAsString = r.mbEmptyDisplayedAsString;
287 meMultiline = r.meMultiline;
289 else if (r.mbToken)
291 // Matrix formula cell token must be cloned, see copy-ctor.
292 const ScMatrixFormulaCellToken* pMatFormula =
293 r.GetMatrixFormulaCellToken();
294 if (pMatFormula)
295 SetToken( new ScMatrixFormulaCellToken( *pMatFormula));
296 else
297 SetToken( r.mpToken);
299 else
300 SetDouble( r.mfValue);
301 // If there was an error there will be an error, no matter what Set...()
302 // methods did.
303 mnError = r.mnError;
307 inline void ScFormulaResult::SetToken( const formula::FormulaToken* p )
309 ResetToDefaults();
310 if (p)
311 p->IncRef();
312 // Handle a result obtained from the interpreter to be assigned to a matrix
313 // formula cell's ScMatrixFormulaCellToken.
314 ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
315 if (pMatFormula)
317 const ScMatrixCellResultToken* pMatResult =
318 (p && p->GetType() == formula::svMatrixCell ?
319 dynamic_cast<const ScMatrixCellResultToken*>(p) : NULL);
320 if (pMatResult)
322 const ScMatrixFormulaCellToken* pNewMatFormula =
323 dynamic_cast<const ScMatrixFormulaCellToken*>(pMatResult);
324 if (pNewMatFormula)
326 DBG_ERRORFILE( "ScFormulaResult::SetToken: pNewMatFormula and pMatFormula, overriding matrix formula dimension; intended?");
327 pMatFormula->SetMatColsRows( pNewMatFormula->GetMatCols(),
328 pNewMatFormula->GetMatRows());
330 pMatFormula->Assign( *pMatResult);
331 p->DecRef();
333 else if (p)
335 // This may be the result of some constant expression like
336 // {="string"} that doesn't result in a matrix but still would
337 // display the result in all cells of this matrix formula.
338 pMatFormula->Assign( *p);
339 p->DecRef();
341 else
343 // NULL result? Well, if you say so ...
344 pMatFormula->ResetResult();
347 else
349 if (mbToken && mpToken)
350 mpToken->DecRef();
351 ResolveToken( p);
356 inline void ScFormulaResult::SetDouble( double f )
358 ResetToDefaults();
359 // Handle a result obtained from the interpreter to be assigned to a matrix
360 // formula cell's ScMatrixFormulaCellToken.
361 ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
362 if (pMatFormula)
363 pMatFormula->SetUpperLeftDouble( f);
364 else
366 if (mbToken && mpToken)
367 mpToken->DecRef();
368 mfValue = f;
369 mbToken = false;
370 meMultiline = MULTILINE_FALSE;
375 inline formula::StackVar ScFormulaResult::GetType() const
377 // Order is significant.
378 if (mnError)
379 return formula::svError;
380 if (mbEmpty)
381 return formula::svEmptyCell;
382 if (!mbToken)
383 return formula::svDouble;
384 if (mpToken)
385 return mpToken->GetType();
386 return formula::svUnknown;
390 inline formula::StackVar ScFormulaResult::GetCellResultType() const
392 formula::StackVar sv = GetType();
393 if (sv == formula::svMatrixCell)
394 // don't need to test for mpToken here, GetType() already did it
395 sv = static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftType();
396 return sv;
400 inline bool ScFormulaResult::IsEmptyDisplayedAsString() const
402 if (mbEmpty)
403 return mbEmptyDisplayedAsString;
404 if (GetType() == formula::svMatrixCell)
406 // don't need to test for mpToken here, GetType() already did it
407 const ScEmptyCellToken* p = dynamic_cast<const ScEmptyCellToken*>(
408 static_cast<const ScMatrixCellResultToken*>(
409 mpToken)->GetUpperLeftToken().operator->());
410 if (p)
411 return p->IsDisplayedAsString();
413 return false;
417 inline bool ScFormulaResult::IsValue() const
419 formula::StackVar sv = GetCellResultType();
420 return sv == formula::svDouble || sv == formula::svError || sv == formula::svEmptyCell;
423 inline bool ScFormulaResult::IsMultiline() const
425 if (meMultiline == MULTILINE_UNKNOWN)
427 const String& rStr = GetString();
428 if (rStr.Len() && rStr.Search( _LF ) != STRING_NOTFOUND)
429 const_cast<ScFormulaResult*>(this)->meMultiline = MULTILINE_TRUE;
430 else
431 const_cast<ScFormulaResult*>(this)->meMultiline = MULTILINE_FALSE;
433 return meMultiline == MULTILINE_TRUE;
437 inline USHORT ScFormulaResult::GetResultError() const
439 if (mnError)
440 return mnError;
441 formula::StackVar sv = GetCellResultType();
442 if (sv == formula::svError)
444 if (GetType() == formula::svMatrixCell)
445 // don't need to test for mpToken here, GetType() already did it
446 return static_cast<const ScMatrixCellResultToken*>(mpToken)->
447 GetUpperLeftToken()->GetError();
448 if (mpToken)
449 return mpToken->GetError();
451 return 0;
455 inline void ScFormulaResult::SetResultError( USHORT nErr )
457 mnError = nErr;
461 inline formula::FormulaConstTokenRef ScFormulaResult::GetToken() const
463 if (mbToken)
464 return mpToken;
465 return NULL;
469 inline formula::FormulaConstTokenRef ScFormulaResult::GetCellResultToken() const
471 if (GetType() == formula::svMatrixCell)
472 // don't need to test for mpToken here, GetType() already did it
473 return static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftToken();
474 return GetToken();
478 inline double ScFormulaResult::GetDouble() const
480 if (mbToken)
482 // Should really not be of type formula::svDouble here.
483 if (mpToken)
485 switch (mpToken->GetType())
487 case formula::svHybridCell:
488 return mpToken->GetDouble();
489 case formula::svMatrixCell:
491 const ScMatrixCellResultToken* p =
492 static_cast<const ScMatrixCellResultToken*>(mpToken);
493 if (p->GetUpperLeftType() == formula::svDouble)
494 return p->GetUpperLeftToken()->GetDouble();
496 break;
497 default:
498 ; // nothing
501 return 0.0;
503 if (mbEmpty)
504 return 0.0;
505 return mfValue;
509 inline const String & ScFormulaResult::GetString() const
511 if (mbToken && mpToken)
513 switch (mpToken->GetType())
515 case formula::svString:
516 case formula::svHybridCell:
517 return mpToken->GetString();
518 case formula::svMatrixCell:
520 const ScMatrixCellResultToken* p =
521 static_cast<const ScMatrixCellResultToken*>(mpToken);
522 if (p->GetUpperLeftType() == formula::svString)
523 return p->GetUpperLeftToken()->GetString();
525 break;
526 default:
527 ; // nothing
530 return EMPTY_STRING;
534 inline ScConstMatrixRef ScFormulaResult::GetMatrix() const
536 if (GetType() == formula::svMatrixCell)
537 return static_cast<const ScToken*>(mpToken)->GetMatrix();
538 return NULL;
542 inline const String & ScFormulaResult::GetHybridFormula() const
544 if (GetType() == formula::svHybridCell)
546 const ScHybridCellToken* p = dynamic_cast<const ScHybridCellToken*>(mpToken);
547 if (p)
548 return p->GetFormula();
550 return EMPTY_STRING;
554 inline void ScFormulaResult::SetHybridDouble( double f )
556 ResetToDefaults();
557 if (mbToken && mpToken)
559 String aString( GetString());
560 String aFormula( GetHybridFormula());
561 mpToken->DecRef();
562 mpToken = new ScHybridCellToken( f, aString, aFormula);
563 mpToken->IncRef();
565 else
567 mfValue = f;
568 mbToken = false;
569 meMultiline = MULTILINE_FALSE;
574 inline void ScFormulaResult::SetHybridString( const String & rStr )
576 // Obtain values before changing anything.
577 double f = GetDouble();
578 String aFormula( GetHybridFormula());
579 ResetToDefaults();
580 if (mbToken && mpToken)
581 mpToken->DecRef();
582 mpToken = new ScHybridCellToken( f, rStr, aFormula);
583 mpToken->IncRef();
584 mbToken = true;
588 inline void ScFormulaResult::SetHybridFormula( const String & rFormula )
590 // Obtain values before changing anything.
591 double f = GetDouble();
592 String aStr( GetString());
593 ResetToDefaults();
594 if (mbToken && mpToken)
595 mpToken->DecRef();
596 mpToken = new ScHybridCellToken( f, aStr, rFormula);
597 mpToken->IncRef();
598 mbToken = true;
602 inline const ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellToken() const
604 return (GetType() == formula::svMatrixCell ?
605 dynamic_cast<const ScMatrixFormulaCellToken*>(mpToken) : NULL);
609 inline ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellTokenNonConst()
611 return const_cast<ScMatrixFormulaCellToken*>( GetMatrixFormulaCellToken());
615 #endif // SC_FORMULARESULT_HXX