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
34 /** Store a variable formula cell result, balancing between runtime performance
35 and memory consumption. */
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;
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
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
68 ATTENTION! Token may get deleted in this call! */
69 inline void ResolveToken( const formula::FormulaToken
* p
);
72 /** Effectively type svUnknown. */
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
),
81 mbEmptyDisplayedAsString( r
.mbEmptyDisplayedAsString
),
82 meMultiline( r
.meMultiline
)
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();
96 mpToken
= new ScMatrixFormulaCellToken( *pMatFormula
);
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
)
115 if (mbToken
&& mpToken
)
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
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
160 inline bool IsValue() const;
162 /** Determines whether or not the result is a string containing more than
164 inline bool IsMultiline() const;
166 /** Get error code if set or GetCellResultType() is formula::svError or svUnknown,
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
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
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()
223 mbEmptyDisplayedAsString
= false;
224 meMultiline
= MULTILINE_UNKNOWN
;
228 inline void ScFormulaResult::ResolveToken( const formula::FormulaToken
* p
)
238 switch (p
->GetType())
240 case formula::svError
:
241 mnError
= p
->GetError();
244 // set in case mnError is 0 now, which shouldn't happen but ...
246 meMultiline
= MULTILINE_FALSE
;
248 case formula::svEmptyCell
:
250 mbEmptyDisplayedAsString
= static_cast<const ScEmptyCellToken
*>(p
)->IsDisplayedAsString();
253 meMultiline
= MULTILINE_FALSE
;
255 case formula::svDouble
:
256 mfValue
= p
->GetDouble();
259 meMultiline
= MULTILINE_FALSE
;
269 inline ScFormulaResult
& ScFormulaResult::operator=( const ScFormulaResult
& r
)
276 inline void ScFormulaResult::Assign( const ScFormulaResult
& r
)
282 if (mbToken
&& mpToken
)
286 mbEmptyDisplayedAsString
= r
.mbEmptyDisplayedAsString
;
287 meMultiline
= r
.meMultiline
;
291 // Matrix formula cell token must be cloned, see copy-ctor.
292 const ScMatrixFormulaCellToken
* pMatFormula
=
293 r
.GetMatrixFormulaCellToken();
295 SetToken( new ScMatrixFormulaCellToken( *pMatFormula
));
297 SetToken( r
.mpToken
);
300 SetDouble( r
.mfValue
);
301 // If there was an error there will be an error, no matter what Set...()
307 inline void ScFormulaResult::SetToken( const formula::FormulaToken
* p
)
312 // Handle a result obtained from the interpreter to be assigned to a matrix
313 // formula cell's ScMatrixFormulaCellToken.
314 ScMatrixFormulaCellToken
* pMatFormula
= GetMatrixFormulaCellTokenNonConst();
317 const ScMatrixCellResultToken
* pMatResult
=
318 (p
&& p
->GetType() == formula::svMatrixCell
?
319 dynamic_cast<const ScMatrixCellResultToken
*>(p
) : NULL
);
322 const ScMatrixFormulaCellToken
* pNewMatFormula
=
323 dynamic_cast<const ScMatrixFormulaCellToken
*>(pMatResult
);
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
);
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
);
343 // NULL result? Well, if you say so ...
344 pMatFormula
->ResetResult();
349 if (mbToken
&& mpToken
)
356 inline void ScFormulaResult::SetDouble( double f
)
359 // Handle a result obtained from the interpreter to be assigned to a matrix
360 // formula cell's ScMatrixFormulaCellToken.
361 ScMatrixFormulaCellToken
* pMatFormula
= GetMatrixFormulaCellTokenNonConst();
363 pMatFormula
->SetUpperLeftDouble( f
);
366 if (mbToken
&& mpToken
)
370 meMultiline
= MULTILINE_FALSE
;
375 inline formula::StackVar
ScFormulaResult::GetType() const
377 // Order is significant.
379 return formula::svError
;
381 return formula::svEmptyCell
;
383 return formula::svDouble
;
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();
400 inline bool ScFormulaResult::IsEmptyDisplayedAsString() const
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->());
411 return p
->IsDisplayedAsString();
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
;
431 const_cast<ScFormulaResult
*>(this)->meMultiline
= MULTILINE_FALSE
;
433 return meMultiline
== MULTILINE_TRUE
;
437 inline USHORT
ScFormulaResult::GetResultError() const
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();
449 return mpToken
->GetError();
455 inline void ScFormulaResult::SetResultError( USHORT nErr
)
461 inline formula::FormulaConstTokenRef
ScFormulaResult::GetToken() const
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();
478 inline double ScFormulaResult::GetDouble() const
482 // Should really not be of type formula::svDouble here.
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();
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();
534 inline ScConstMatrixRef
ScFormulaResult::GetMatrix() const
536 if (GetType() == formula::svMatrixCell
)
537 return static_cast<const ScToken
*>(mpToken
)->GetMatrix();
542 inline const String
& ScFormulaResult::GetHybridFormula() const
544 if (GetType() == formula::svHybridCell
)
546 const ScHybridCellToken
* p
= dynamic_cast<const ScHybridCellToken
*>(mpToken
);
548 return p
->GetFormula();
554 inline void ScFormulaResult::SetHybridDouble( double f
)
557 if (mbToken
&& mpToken
)
559 String
aString( GetString());
560 String
aFormula( GetHybridFormula());
562 mpToken
= new ScHybridCellToken( f
, aString
, aFormula
);
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());
580 if (mbToken
&& mpToken
)
582 mpToken
= new ScHybridCellToken( f
, rStr
, aFormula
);
588 inline void ScFormulaResult::SetHybridFormula( const String
& rFormula
)
590 // Obtain values before changing anything.
591 double f
= GetDouble();
592 String
aStr( GetString());
594 if (mbToken
&& mpToken
)
596 mpToken
= new ScHybridCellToken( f
, aStr
, rFormula
);
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