Update ooo320-m1
[ooovba.git] / sc / inc / formularesult.hxx
blobab1318f8c725bff20c59ef871f4b8e57b380604c
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: formularesult.hxx,v $
10 * $Revision: 1.3 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #ifndef SC_FORMULARESULT_HXX
32 #define SC_FORMULARESULT_HXX
34 #include "token.hxx"
37 /** Store a variable formula cell result, balancing between runtime performance
38 and memory consumption. */
39 class ScFormulaResult
41 typedef unsigned char Multiline;
42 static const Multiline MULTILINE_UNKNOWN = 0;
43 static const Multiline MULTILINE_FALSE = 1;
44 static const Multiline MULTILINE_TRUE = 2;
46 union
48 double mfValue; // double result direct for performance and memory consumption
49 const formula::FormulaToken* mpToken; // if not, result token obtained from interpreter
51 USHORT mnError; // error code
52 bool mbToken :1; // whether content of union is a token
53 bool mbEmpty :1; // empty cell result
54 bool mbEmptyDisplayedAsString :1; // only if mbEmpty
55 Multiline meMultiline :2; // result is multiline
57 /** Reset mnError, mbEmpty and mbEmptyDisplayedAsString to their defaults
58 prior to assigning other types */
59 inline void ResetToDefaults();
61 /** If token is of formula::svError set error code and decrement RefCount.
62 If token is of formula::svEmptyCell set mbEmpty and mbEmptyAsString and
63 decrement RefCount.
64 If token is of formula::svDouble set mfValue and decrement RefCount.
65 Else assign token to mpToken. NULL is valid => svUnknown.
66 Other member variables are set accordingly.
67 @precondition: Token MUST had been IncRef'ed prior to this call!
68 @precondition: An already existing different mpToken MUST had been
69 DecRef'ed prior to this call, p will be assigned to mpToken if not
70 resolved.
71 ATTENTION! Token may get deleted in this call! */
72 inline void ResolveToken( const formula::FormulaToken * p );
74 public:
75 /** Effectively type svUnknown. */
76 ScFormulaResult()
77 : mpToken(NULL), mnError(0), mbToken(true),
78 mbEmpty(false), mbEmptyDisplayedAsString(false),
79 meMultiline(MULTILINE_UNKNOWN) {}
81 ScFormulaResult( const ScFormulaResult & r )
82 : mnError( r.mnError), mbToken( r.mbToken),
83 mbEmpty( r.mbEmpty),
84 mbEmptyDisplayedAsString( r.mbEmptyDisplayedAsString),
85 meMultiline( r.meMultiline)
87 if (mbToken)
89 mpToken = r.mpToken;
90 if (mpToken)
92 // Since matrix dimension and
93 // results are assigned to a matrix
94 // cell formula token we have to
95 // clone that instead of sharing it.
96 const ScMatrixFormulaCellToken* pMatFormula =
97 r.GetMatrixFormulaCellToken();
98 if (pMatFormula)
99 mpToken = new ScMatrixFormulaCellToken( *pMatFormula);
100 mpToken->IncRef();
103 else
104 mfValue = r.mfValue;
107 /** Same comments as for SetToken() apply! */
108 explicit ScFormulaResult( const formula::FormulaToken* p )
109 : mnError(0), mbToken(false),
110 mbEmpty(false), mbEmptyDisplayedAsString(false),
111 meMultiline(MULTILINE_UNKNOWN)
113 SetToken( p);
116 ~ScFormulaResult()
118 if (mbToken && mpToken)
119 mpToken->DecRef();
122 /** Well, guess what ... */
123 inline ScFormulaResult & operator=( const ScFormulaResult & r );
125 /** Assignment as in operator=() but without return */
126 inline void Assign( const ScFormulaResult & r );
128 /** Sets a direct double if token type is formula::svDouble, or mbEmpty if
129 formula::svEmptyCell, else token. If p is NULL, that is set as well, effectively
130 resulting in GetType()==svUnknown. If the already existing result is
131 ScMatrixFormulaCellToken, the upper left ist set to token.
133 ATTENTION! formula::FormulaToken had to be allocated using 'new' and if of type
134 formula::svDouble and no RefCount was set may not be used after this call
135 because it was deleted after decrement! */
136 inline void SetToken( const formula::FormulaToken* p );
138 /** May be NULL if SetToken() did so, also if type formula::svDouble or formula::svError! */
139 inline formula::FormulaConstTokenRef GetToken() const;
141 /** Return upper left token if formula::svMatrixCell, else return GetToken().
142 May be NULL if SetToken() did so, also if type formula::svDouble or formula::svError! */
143 inline formula::FormulaConstTokenRef GetCellResultToken() const;
145 /** Return type of result, including formula::svError, formula::svEmptyCell, formula::svDouble and
146 formula::svMatrixCell. */
147 inline formula::StackVar GetType() const;
149 /** If type is formula::svMatrixCell return the type of upper left element, else
150 GetType() */
151 inline formula::StackVar GetCellResultType() const;
153 /** If type is formula::svEmptyCell (including matrix upper left) and should be
154 displayed as empty string */
155 inline bool IsEmptyDisplayedAsString() const;
157 /** Test for cell result type formula::svDouble, including upper left if
158 formula::svMatrixCell. Also included is formula::svError for legacy, because previously
159 an error result was treated like a numeric value at some places in
160 ScFormulaCell. Also included is formula::svEmptyCell as a reference to an empty
161 cell usually is treated as numeric 0. Use GetCellResultType() for
162 details instead. */
163 inline bool IsValue() const;
165 /** Determines whether or not the result is a string containing more than
166 one paragraph */
167 inline bool IsMultiline() const;
169 /** Get error code if set or GetCellResultType() is formula::svError or svUnknown,
170 else 0. */
171 inline USHORT GetResultError() const;
173 /** Set error code, don't touch token or double. */
174 inline void SetResultError( USHORT nErr );
176 /** Set direct double. Shouldn't be used externally except in
177 ScFormulaCell for rounded CalcAsShown or SetErrCode(). If
178 ScMatrixFormulaCellToken the token isn't replaced but upper left result
179 is modified instead, but only if it was of type formula::svDouble before or not
180 set at all. */
181 inline void SetDouble( double f );
183 /** Return value if type formula::svDouble or formula::svHybridCell or formula::svMatrixCell and upper
184 left formula::svDouble, else 0.0 */
185 inline double GetDouble() const;
187 /** Return string if type formula::svString or formula::svHybridCell or formula::svMatrixCell and
188 upper left formula::svString, else empty string. */
189 inline const String & GetString() const;
191 /** Return matrix if type formula::svMatrixCell and ScMatrix present, else NULL. */
192 inline ScConstMatrixRef GetMatrix() const;
194 /** Return formula string if type formula::svHybridCell, else empty string. */
195 inline const String & GetHybridFormula() const;
197 /** Should only be used by import filters, best in the order
198 SetHybridDouble(), SetHybridString(), or only SetHybridString() for
199 formula string to be compiled later. */
200 inline void SetHybridDouble( double f );
202 /** Should only be used by import filters, best in the order
203 SetHybridDouble(), SetHybridString()/SetHybridFormula(), or only
204 SetHybridFormula() for formula string to be compiled later. */
205 inline void SetHybridString( const String & rStr );
207 /** Should only be used by import filters, best in the order
208 SetHybridDouble(), SetHybridString()/SetHybridFormula(), or only
209 SetHybridFormula() for formula string to be compiled later. */
210 inline void SetHybridFormula( const String & rFormula );
212 /** Get the const ScMatrixFormulaCellToken* if token is of that type, else
213 NULL. */
214 inline const ScMatrixFormulaCellToken* GetMatrixFormulaCellToken() const;
216 /** Get the ScMatrixFormulaCellToken* if token is of that type, else NULL.
217 Shouldn't be used externally except by ScFormulaCell::SetMatColsRows(). */
218 inline ScMatrixFormulaCellToken* GetMatrixFormulaCellTokenNonConst();
222 inline void ScFormulaResult::ResetToDefaults()
224 mnError = 0;
225 mbEmpty = false;
226 mbEmptyDisplayedAsString = false;
227 meMultiline = MULTILINE_UNKNOWN;
231 inline void ScFormulaResult::ResolveToken( const formula::FormulaToken * p )
233 ResetToDefaults();
234 if (!p)
236 mpToken = p;
237 mbToken = true;
239 else
241 switch (p->GetType())
243 case formula::svError:
244 mnError = p->GetError();
245 p->DecRef();
246 mbToken = false;
247 // set in case mnError is 0 now, which shouldn't happen but ...
248 mfValue = 0.0;
249 meMultiline = MULTILINE_FALSE;
250 break;
251 case formula::svEmptyCell:
252 mbEmpty = true;
253 mbEmptyDisplayedAsString = static_cast<const ScEmptyCellToken*>(p)->IsDisplayedAsString();
254 p->DecRef();
255 mbToken = false;
256 meMultiline = MULTILINE_FALSE;
257 break;
258 case formula::svDouble:
259 mfValue = p->GetDouble();
260 p->DecRef();
261 mbToken = false;
262 meMultiline = MULTILINE_FALSE;
263 break;
264 default:
265 mpToken = p;
266 mbToken = true;
272 inline ScFormulaResult & ScFormulaResult::operator=( const ScFormulaResult & r )
274 Assign( r);
275 return *this;
279 inline void ScFormulaResult::Assign( const ScFormulaResult & r )
281 if (this == &r)
282 return;
283 if (r.mbEmpty)
285 if (mbToken && mpToken)
286 mpToken->DecRef();
287 mbToken = false;
288 mbEmpty = true;
289 mbEmptyDisplayedAsString = r.mbEmptyDisplayedAsString;
290 meMultiline = r.meMultiline;
292 else if (r.mbToken)
294 // Matrix formula cell token must be cloned, see copy-ctor.
295 const ScMatrixFormulaCellToken* pMatFormula =
296 r.GetMatrixFormulaCellToken();
297 if (pMatFormula)
298 SetToken( new ScMatrixFormulaCellToken( *pMatFormula));
299 else
300 SetToken( r.mpToken);
302 else
303 SetDouble( r.mfValue);
304 // If there was an error there will be an error, no matter what Set...()
305 // methods did.
306 mnError = r.mnError;
310 inline void ScFormulaResult::SetToken( const formula::FormulaToken* p )
312 ResetToDefaults();
313 if (p)
314 p->IncRef();
315 // Handle a result obtained from the interpreter to be assigned to a matrix
316 // formula cell's ScMatrixFormulaCellToken.
317 ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
318 if (pMatFormula)
320 const ScMatrixCellResultToken* pMatResult =
321 (p && p->GetType() == formula::svMatrixCell ?
322 dynamic_cast<const ScMatrixCellResultToken*>(p) : NULL);
323 if (pMatResult)
325 const ScMatrixFormulaCellToken* pNewMatFormula =
326 dynamic_cast<const ScMatrixFormulaCellToken*>(pMatResult);
327 if (pNewMatFormula)
329 DBG_ERRORFILE( "ScFormulaResult::SetToken: pNewMatFormula and pMatFormula, overriding matrix formula dimension; intended?");
330 pMatFormula->SetMatColsRows( pNewMatFormula->GetMatCols(),
331 pNewMatFormula->GetMatRows());
333 pMatFormula->Assign( *pMatResult);
334 p->DecRef();
336 else if (p)
338 // This may be the result of some constant expression like
339 // {="string"} that doesn't result in a matrix but still would
340 // display the result in all cells of this matrix formula.
341 pMatFormula->Assign( *p);
342 p->DecRef();
344 else
346 // NULL result? Well, if you say so ...
347 pMatFormula->ResetResult();
350 else
352 if (mbToken && mpToken)
353 mpToken->DecRef();
354 ResolveToken( p);
359 inline void ScFormulaResult::SetDouble( double f )
361 ResetToDefaults();
362 // Handle a result obtained from the interpreter to be assigned to a matrix
363 // formula cell's ScMatrixFormulaCellToken.
364 ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
365 if (pMatFormula)
366 pMatFormula->SetUpperLeftDouble( f);
367 else
369 if (mbToken && mpToken)
370 mpToken->DecRef();
371 mfValue = f;
372 mbToken = false;
373 meMultiline = MULTILINE_FALSE;
378 inline formula::StackVar ScFormulaResult::GetType() const
380 // Order is significant.
381 if (mnError)
382 return formula::svError;
383 if (mbEmpty)
384 return formula::svEmptyCell;
385 if (!mbToken)
386 return formula::svDouble;
387 if (mpToken)
388 return mpToken->GetType();
389 return formula::svUnknown;
393 inline formula::StackVar ScFormulaResult::GetCellResultType() const
395 formula::StackVar sv = GetType();
396 if (sv == formula::svMatrixCell)
397 // don't need to test for mpToken here, GetType() already did it
398 sv = static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftType();
399 return sv;
403 inline bool ScFormulaResult::IsEmptyDisplayedAsString() const
405 if (mbEmpty)
406 return mbEmptyDisplayedAsString;
407 if (GetType() == formula::svMatrixCell)
409 // don't need to test for mpToken here, GetType() already did it
410 const ScEmptyCellToken* p = dynamic_cast<const ScEmptyCellToken*>(
411 static_cast<const ScMatrixCellResultToken*>(
412 mpToken)->GetUpperLeftToken().operator->());
413 if (p)
414 return p->IsDisplayedAsString();
416 return false;
420 inline bool ScFormulaResult::IsValue() const
422 formula::StackVar sv = GetCellResultType();
423 return sv == formula::svDouble || sv == formula::svError || sv == formula::svEmptyCell;
426 inline bool ScFormulaResult::IsMultiline() const
428 if (meMultiline == MULTILINE_UNKNOWN)
430 const String& rStr = GetString();
431 if (rStr.Len() && rStr.Search( _LF ) != STRING_NOTFOUND)
432 const_cast<ScFormulaResult*>(this)->meMultiline = MULTILINE_TRUE;
433 else
434 const_cast<ScFormulaResult*>(this)->meMultiline = MULTILINE_FALSE;
436 return meMultiline == MULTILINE_TRUE;
440 inline USHORT ScFormulaResult::GetResultError() const
442 if (mnError)
443 return mnError;
444 formula::StackVar sv = GetCellResultType();
445 if (sv == formula::svError)
447 if (GetType() == formula::svMatrixCell)
448 // don't need to test for mpToken here, GetType() already did it
449 return static_cast<const ScMatrixCellResultToken*>(mpToken)->
450 GetUpperLeftToken()->GetError();
451 if (mpToken)
452 return mpToken->GetError();
454 return 0;
458 inline void ScFormulaResult::SetResultError( USHORT nErr )
460 mnError = nErr;
464 inline formula::FormulaConstTokenRef ScFormulaResult::GetToken() const
466 if (mbToken)
467 return mpToken;
468 return NULL;
472 inline formula::FormulaConstTokenRef ScFormulaResult::GetCellResultToken() const
474 if (GetType() == formula::svMatrixCell)
475 // don't need to test for mpToken here, GetType() already did it
476 return static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftToken();
477 return GetToken();
481 inline double ScFormulaResult::GetDouble() const
483 if (mbToken)
485 // Should really not be of type formula::svDouble here.
486 if (mpToken)
488 switch (mpToken->GetType())
490 case formula::svHybridCell:
491 return mpToken->GetDouble();
492 case formula::svMatrixCell:
494 const ScMatrixCellResultToken* p =
495 static_cast<const ScMatrixCellResultToken*>(mpToken);
496 if (p->GetUpperLeftType() == formula::svDouble)
497 return p->GetUpperLeftToken()->GetDouble();
499 break;
500 default:
501 ; // nothing
504 return 0.0;
506 if (mbEmpty)
507 return 0.0;
508 return mfValue;
512 inline const String & ScFormulaResult::GetString() const
514 if (mbToken && mpToken)
516 switch (mpToken->GetType())
518 case formula::svString:
519 case formula::svHybridCell:
520 return mpToken->GetString();
521 case formula::svMatrixCell:
523 const ScMatrixCellResultToken* p =
524 static_cast<const ScMatrixCellResultToken*>(mpToken);
525 if (p->GetUpperLeftType() == formula::svString)
526 return p->GetUpperLeftToken()->GetString();
528 break;
529 default:
530 ; // nothing
533 return EMPTY_STRING;
537 inline ScConstMatrixRef ScFormulaResult::GetMatrix() const
539 if (GetType() == formula::svMatrixCell)
540 return static_cast<const ScToken*>(mpToken)->GetMatrix();
541 return NULL;
545 inline const String & ScFormulaResult::GetHybridFormula() const
547 if (GetType() == formula::svHybridCell)
549 const ScHybridCellToken* p = dynamic_cast<const ScHybridCellToken*>(mpToken);
550 if (p)
551 return p->GetFormula();
553 return EMPTY_STRING;
557 inline void ScFormulaResult::SetHybridDouble( double f )
559 ResetToDefaults();
560 if (mbToken && mpToken)
562 String aString( GetString());
563 String aFormula( GetHybridFormula());
564 mpToken->DecRef();
565 mpToken = new ScHybridCellToken( f, aString, aFormula);
566 mpToken->IncRef();
568 else
570 mfValue = f;
571 mbToken = false;
572 meMultiline = MULTILINE_FALSE;
577 inline void ScFormulaResult::SetHybridString( const String & rStr )
579 // Obtain values before changing anything.
580 double f = GetDouble();
581 String aFormula( GetHybridFormula());
582 ResetToDefaults();
583 if (mbToken && mpToken)
584 mpToken->DecRef();
585 mpToken = new ScHybridCellToken( f, rStr, aFormula);
586 mpToken->IncRef();
587 mbToken = true;
591 inline void ScFormulaResult::SetHybridFormula( const String & rFormula )
593 // Obtain values before changing anything.
594 double f = GetDouble();
595 String aStr( GetString());
596 ResetToDefaults();
597 if (mbToken && mpToken)
598 mpToken->DecRef();
599 mpToken = new ScHybridCellToken( f, aStr, rFormula);
600 mpToken->IncRef();
601 mbToken = true;
605 inline const ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellToken() const
607 return (GetType() == formula::svMatrixCell ?
608 dynamic_cast<const ScMatrixFormulaCellToken*>(mpToken) : NULL);
612 inline ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellTokenNonConst()
614 return const_cast<ScMatrixFormulaCellToken*>( GetMatrixFormulaCellToken());
618 #endif // SC_FORMULARESULT_HXX