1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: formularesult.hxx,v $
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
37 /** Store a variable formula cell result, balancing between runtime performance
38 and memory consumption. */
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;
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
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
71 ATTENTION! Token may get deleted in this call! */
72 inline void ResolveToken( const formula::FormulaToken
* p
);
75 /** Effectively type svUnknown. */
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
),
84 mbEmptyDisplayedAsString( r
.mbEmptyDisplayedAsString
),
85 meMultiline( r
.meMultiline
)
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();
99 mpToken
= new ScMatrixFormulaCellToken( *pMatFormula
);
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
)
118 if (mbToken
&& mpToken
)
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
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
163 inline bool IsValue() const;
165 /** Determines whether or not the result is a string containing more than
167 inline bool IsMultiline() const;
169 /** Get error code if set or GetCellResultType() is formula::svError or svUnknown,
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
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
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()
226 mbEmptyDisplayedAsString
= false;
227 meMultiline
= MULTILINE_UNKNOWN
;
231 inline void ScFormulaResult::ResolveToken( const formula::FormulaToken
* p
)
241 switch (p
->GetType())
243 case formula::svError
:
244 mnError
= p
->GetError();
247 // set in case mnError is 0 now, which shouldn't happen but ...
249 meMultiline
= MULTILINE_FALSE
;
251 case formula::svEmptyCell
:
253 mbEmptyDisplayedAsString
= static_cast<const ScEmptyCellToken
*>(p
)->IsDisplayedAsString();
256 meMultiline
= MULTILINE_FALSE
;
258 case formula::svDouble
:
259 mfValue
= p
->GetDouble();
262 meMultiline
= MULTILINE_FALSE
;
272 inline ScFormulaResult
& ScFormulaResult::operator=( const ScFormulaResult
& r
)
279 inline void ScFormulaResult::Assign( const ScFormulaResult
& r
)
285 if (mbToken
&& mpToken
)
289 mbEmptyDisplayedAsString
= r
.mbEmptyDisplayedAsString
;
290 meMultiline
= r
.meMultiline
;
294 // Matrix formula cell token must be cloned, see copy-ctor.
295 const ScMatrixFormulaCellToken
* pMatFormula
=
296 r
.GetMatrixFormulaCellToken();
298 SetToken( new ScMatrixFormulaCellToken( *pMatFormula
));
300 SetToken( r
.mpToken
);
303 SetDouble( r
.mfValue
);
304 // If there was an error there will be an error, no matter what Set...()
310 inline void ScFormulaResult::SetToken( const formula::FormulaToken
* p
)
315 // Handle a result obtained from the interpreter to be assigned to a matrix
316 // formula cell's ScMatrixFormulaCellToken.
317 ScMatrixFormulaCellToken
* pMatFormula
= GetMatrixFormulaCellTokenNonConst();
320 const ScMatrixCellResultToken
* pMatResult
=
321 (p
&& p
->GetType() == formula::svMatrixCell
?
322 dynamic_cast<const ScMatrixCellResultToken
*>(p
) : NULL
);
325 const ScMatrixFormulaCellToken
* pNewMatFormula
=
326 dynamic_cast<const ScMatrixFormulaCellToken
*>(pMatResult
);
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
);
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
);
346 // NULL result? Well, if you say so ...
347 pMatFormula
->ResetResult();
352 if (mbToken
&& mpToken
)
359 inline void ScFormulaResult::SetDouble( double f
)
362 // Handle a result obtained from the interpreter to be assigned to a matrix
363 // formula cell's ScMatrixFormulaCellToken.
364 ScMatrixFormulaCellToken
* pMatFormula
= GetMatrixFormulaCellTokenNonConst();
366 pMatFormula
->SetUpperLeftDouble( f
);
369 if (mbToken
&& mpToken
)
373 meMultiline
= MULTILINE_FALSE
;
378 inline formula::StackVar
ScFormulaResult::GetType() const
380 // Order is significant.
382 return formula::svError
;
384 return formula::svEmptyCell
;
386 return formula::svDouble
;
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();
403 inline bool ScFormulaResult::IsEmptyDisplayedAsString() const
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->());
414 return p
->IsDisplayedAsString();
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
;
434 const_cast<ScFormulaResult
*>(this)->meMultiline
= MULTILINE_FALSE
;
436 return meMultiline
== MULTILINE_TRUE
;
440 inline USHORT
ScFormulaResult::GetResultError() const
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();
452 return mpToken
->GetError();
458 inline void ScFormulaResult::SetResultError( USHORT nErr
)
464 inline formula::FormulaConstTokenRef
ScFormulaResult::GetToken() const
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();
481 inline double ScFormulaResult::GetDouble() const
485 // Should really not be of type formula::svDouble here.
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();
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();
537 inline ScConstMatrixRef
ScFormulaResult::GetMatrix() const
539 if (GetType() == formula::svMatrixCell
)
540 return static_cast<const ScToken
*>(mpToken
)->GetMatrix();
545 inline const String
& ScFormulaResult::GetHybridFormula() const
547 if (GetType() == formula::svHybridCell
)
549 const ScHybridCellToken
* p
= dynamic_cast<const ScHybridCellToken
*>(mpToken
);
551 return p
->GetFormula();
557 inline void ScFormulaResult::SetHybridDouble( double f
)
560 if (mbToken
&& mpToken
)
562 String
aString( GetString());
563 String
aFormula( GetHybridFormula());
565 mpToken
= new ScHybridCellToken( f
, aString
, aFormula
);
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());
583 if (mbToken
&& mpToken
)
585 mpToken
= new ScHybridCellToken( f
, rStr
, aFormula
);
591 inline void ScFormulaResult::SetHybridFormula( const String
& rFormula
)
593 // Obtain values before changing anything.
594 double f
= GetDouble();
595 String
aStr( GetString());
597 if (mbToken
&& mpToken
)
599 mpToken
= new ScHybridCellToken( f
, aStr
, rFormula
);
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