1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #ifndef SC_FORMULARESULT_HXX
25 #define SC_FORMULARESULT_HXX
26
27 #include "token.hxx"
28
29
30 /** Store a variable formula cell result, balancing between runtime performance
31 and memory consumption. */
32 class ScFormulaResult
33 {
34 typedef unsigned char Multiline;
35 static const Multiline MULTILINE_UNKNOWN = 0;
36 static const Multiline MULTILINE_FALSE = 1;
37 static const Multiline MULTILINE_TRUE = 2;
38
39 union
40 {
41 double mfValue; // double result direct for performance and memory consumption
42 const formula::FormulaToken* mpToken; // if not, result token obtained from interpreter
43 };
44 sal_uInt16 mnError; // error code
45 bool mbToken :1; // whether content of union is a token
46 bool mbEmpty :1; // empty cell result
47 bool mbEmptyDisplayedAsString :1; // only if mbEmpty
48 Multiline meMultiline :2; // result is multiline
49
50 /** Reset mnError, mbEmpty and mbEmptyDisplayedAsString to their defaults
51 prior to assigning other types */
52 inline void ResetToDefaults();
53
54 /** If token is of formula::svError set error code and decrement RefCount.
55 If token is of formula::svEmptyCell set mbEmpty and mbEmptyAsString and
56 decrement RefCount.
57 If token is of formula::svDouble set mfValue and decrement RefCount.
58 Else assign token to mpToken. NULL is valid => svUnknown.
59 Other member variables are set accordingly.
60 @precondition: Token MUST had been IncRef'ed prior to this call!
61 @precondition: An already existing different mpToken MUST had been
62 DecRef'ed prior to this call, p will be assigned to mpToken if not
63 resolved.
64 ATTENTION! Token may get deleted in this call! */
65 inline void ResolveToken( const formula::FormulaToken * p );
66
67 public:
68 /** Effectively type svUnknown. */
ScFormulaResult()69 ScFormulaResult()
70 : mpToken(NULL), mnError(0), mbToken(true),
71 mbEmpty(false), mbEmptyDisplayedAsString(false),
72 meMultiline(MULTILINE_UNKNOWN) {}
73
ScFormulaResult(const ScFormulaResult & r)74 ScFormulaResult( const ScFormulaResult & r )
75 : mnError( r.mnError), mbToken( r.mbToken),
76 mbEmpty( r.mbEmpty),
77 mbEmptyDisplayedAsString( r.mbEmptyDisplayedAsString),
78 meMultiline( r.meMultiline)
79 {
80 if (mbToken)
81 {
82 mpToken = r.mpToken;
83 if (mpToken)
84 {
85 // Since matrix dimension and
86 // results are assigned to a matrix
87 // cell formula token we have to
88 // clone that instead of sharing it.
89 const ScMatrixFormulaCellToken* pMatFormula =
90 r.GetMatrixFormulaCellToken();
91 if (pMatFormula)
92 mpToken = new ScMatrixFormulaCellToken( *pMatFormula);
93 mpToken->IncRef();
94 }
95 }
96 else
97 mfValue = r.mfValue;
98 }
99
100 /** Same comments as for SetToken() apply! */
ScFormulaResult(const formula::FormulaToken * p)101 explicit ScFormulaResult( const formula::FormulaToken* p )
102 : mnError(0), mbToken(false),
103 mbEmpty(false), mbEmptyDisplayedAsString(false),
104 meMultiline(MULTILINE_UNKNOWN)
105 {
106 SetToken( p);
107 }
108
~ScFormulaResult()109 ~ScFormulaResult()
110 {
111 if (mbToken && mpToken)
112 mpToken->DecRef();
113 }
114
115 /** Well, guess what ... */
116 inline ScFormulaResult & operator=( const ScFormulaResult & r );
117
118 /** Assignment as in operator=() but without return */
119 inline void Assign( const ScFormulaResult & r );
120
121 /** Sets a direct double if token type is formula::svDouble, or mbEmpty if
122 formula::svEmptyCell, else token. If p is NULL, that is set as well, effectively
123 resulting in GetType()==svUnknown. If the already existing result is
124 ScMatrixFormulaCellToken, the upper left ist set to token.
125
126 ATTENTION! formula::FormulaToken had to be allocated using 'new' and if of type
127 formula::svDouble and no RefCount was set may not be used after this call
128 because it was deleted after decrement! */
129 inline void SetToken( const formula::FormulaToken* p );
130
131 /** May be NULL if SetToken() did so, also if type formula::svDouble or formula::svError! */
132 inline formula::FormulaConstTokenRef GetToken() const;
133
134 /** Return upper left token if formula::svMatrixCell, else return GetToken().
135 May be NULL if SetToken() did so, also if type formula::svDouble or formula::svError! */
136 inline formula::FormulaConstTokenRef GetCellResultToken() const;
137
138 /** Return type of result, including formula::svError, formula::svEmptyCell, formula::svDouble and
139 formula::svMatrixCell. */
140 inline formula::StackVar GetType() const;
141
142 /** If type is formula::svMatrixCell return the type of upper left element, else
143 GetType() */
144 inline formula::StackVar GetCellResultType() const;
145
146 /** If type is formula::svEmptyCell (including matrix upper left) and should be
147 displayed as empty string */
148 inline bool IsEmptyDisplayedAsString() const;
149
150 /** Test for cell result type formula::svDouble, including upper left if
151 formula::svMatrixCell. Also included is formula::svError for legacy, because previously
152 an error result was treated like a numeric value at some places in
153 ScFormulaCell. Also included is formula::svEmptyCell as a reference to an empty
154 cell usually is treated as numeric 0. Use GetCellResultType() for
155 details instead. */
156 inline bool IsValue() const;
157
158 /** Determines whether or not the result is a string containing more than
159 one paragraph */
160 inline bool IsMultiline() const;
161
162 /** Get error code if set or GetCellResultType() is formula::svError or svUnknown,
163 else 0. */
164 inline sal_uInt16 GetResultError() const;
165
166 /** Set error code, don't touch token or double. */
167 inline void SetResultError( sal_uInt16 nErr );
168
169 /** Set direct double. Shouldn't be used externally except in
170 ScFormulaCell for rounded CalcAsShown or SetErrCode(). If
171 ScMatrixFormulaCellToken the token isn't replaced but upper left result
172 is modified instead, but only if it was of type formula::svDouble before or not
173 set at all. */
174 inline void SetDouble( double f );
175
176 /** Return value if type formula::svDouble or formula::svHybridCell or formula::svMatrixCell and upper
177 left formula::svDouble, else 0.0 */
178 inline double GetDouble() const;
179
180 /** Return string if type formula::svString or formula::svHybridCell or formula::svMatrixCell and
181 upper left formula::svString, else empty string. */
182 inline const String & GetString() const;
183
184 /** Return matrix if type formula::svMatrixCell and ScMatrix present, else NULL. */
185 inline ScConstMatrixRef GetMatrix() const;
186
187 /** Return formula string if type formula::svHybridCell, else empty string. */
188 inline const String & GetHybridFormula() const;
189
190 /** Should only be used by import filters, best in the order
191 SetHybridDouble(), SetHybridString(), or only SetHybridString() for
192 formula string to be compiled later. */
193 inline void SetHybridDouble( double f );
194
195 /** Should only be used by import filters, best in the order
196 SetHybridDouble(), SetHybridString()/SetHybridFormula(), or only
197 SetHybridFormula() for formula string to be compiled later. */
198 inline void SetHybridString( const String & rStr );
199
200 /** Should only be used by import filters, best in the order
201 SetHybridDouble(), SetHybridString()/SetHybridFormula(), or only
202 SetHybridFormula() for formula string to be compiled later. */
203 inline void SetHybridFormula( const String & rFormula );
204
205 /** Get the const ScMatrixFormulaCellToken* if token is of that type, else
206 NULL. */
207 inline const ScMatrixFormulaCellToken* GetMatrixFormulaCellToken() const;
208
209 /** Get the ScMatrixFormulaCellToken* if token is of that type, else NULL.
210 Shouldn't be used externally except by ScFormulaCell::SetMatColsRows(). */
211 inline ScMatrixFormulaCellToken* GetMatrixFormulaCellTokenNonConst();
212 };
213
214
ResetToDefaults()215 inline void ScFormulaResult::ResetToDefaults()
216 {
217 mnError = 0;
218 mbEmpty = false;
219 mbEmptyDisplayedAsString = false;
220 meMultiline = MULTILINE_UNKNOWN;
221 }
222
223
ResolveToken(const formula::FormulaToken * p)224 inline void ScFormulaResult::ResolveToken( const formula::FormulaToken * p )
225 {
226 ResetToDefaults();
227 if (!p)
228 {
229 mpToken = p;
230 mbToken = true;
231 }
232 else
233 {
234 switch (p->GetType())
235 {
236 case formula::svError:
237 mnError = p->GetError();
238 p->DecRef();
239 mbToken = false;
240 // set in case mnError is 0 now, which shouldn't happen but ...
241 mfValue = 0.0;
242 meMultiline = MULTILINE_FALSE;
243 break;
244 case formula::svEmptyCell:
245 mbEmpty = true;
246 mbEmptyDisplayedAsString = static_cast<const ScEmptyCellToken*>(p)->IsDisplayedAsString();
247 p->DecRef();
248 mbToken = false;
249 meMultiline = MULTILINE_FALSE;
250 break;
251 case formula::svDouble:
252 mfValue = p->GetDouble();
253 p->DecRef();
254 mbToken = false;
255 meMultiline = MULTILINE_FALSE;
256 break;
257 default:
258 mpToken = p;
259 mbToken = true;
260 }
261 }
262 }
263
264
operator =(const ScFormulaResult & r)265 inline ScFormulaResult & ScFormulaResult::operator=( const ScFormulaResult & r )
266 {
267 Assign( r);
268 return *this;
269 }
270
271
Assign(const ScFormulaResult & r)272 inline void ScFormulaResult::Assign( const ScFormulaResult & r )
273 {
274 if (this == &r)
275 return;
276 if (r.mbEmpty)
277 {
278 if (mbToken && mpToken)
279 mpToken->DecRef();
280 mbToken = false;
281 mbEmpty = true;
282 mbEmptyDisplayedAsString = r.mbEmptyDisplayedAsString;
283 meMultiline = r.meMultiline;
284 }
285 else if (r.mbToken)
286 {
287 // Matrix formula cell token must be cloned, see copy-ctor.
288 const ScMatrixFormulaCellToken* pMatFormula =
289 r.GetMatrixFormulaCellToken();
290 if (pMatFormula)
291 SetToken( new ScMatrixFormulaCellToken( *pMatFormula));
292 else
293 SetToken( r.mpToken);
294 }
295 else
296 SetDouble( r.mfValue);
297 // If there was an error there will be an error, no matter what Set...()
298 // methods did.
299 mnError = r.mnError;
300 }
301
302
SetToken(const formula::FormulaToken * p)303 inline void ScFormulaResult::SetToken( const formula::FormulaToken* p )
304 {
305 ResetToDefaults();
306 if (p)
307 p->IncRef();
308 // Handle a result obtained from the interpreter to be assigned to a matrix
309 // formula cell's ScMatrixFormulaCellToken.
310 ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
311 if (pMatFormula)
312 {
313 const ScMatrixCellResultToken* pMatResult =
314 (p && p->GetType() == formula::svMatrixCell ?
315 dynamic_cast<const ScMatrixCellResultToken*>(p) : NULL);
316 if (pMatResult)
317 {
318 const ScMatrixFormulaCellToken* pNewMatFormula =
319 dynamic_cast<const ScMatrixFormulaCellToken*>(pMatResult);
320 if (pNewMatFormula)
321 {
322 DBG_ERRORFILE( "ScFormulaResult::SetToken: pNewMatFormula and pMatFormula, overriding matrix formula dimension; intended?");
323 pMatFormula->SetMatColsRows( pNewMatFormula->GetMatCols(),
324 pNewMatFormula->GetMatRows());
325 }
326 pMatFormula->Assign( *pMatResult);
327 p->DecRef();
328 }
329 else if (p)
330 {
331 // This may be the result of some constant expression like
332 // {="string"} that doesn't result in a matrix but still would
333 // display the result in all cells of this matrix formula.
334 pMatFormula->Assign( *p);
335 p->DecRef();
336 }
337 else
338 {
339 // NULL result? Well, if you say so ...
340 pMatFormula->ResetResult();
341 }
342 }
343 else
344 {
345 if (mbToken && mpToken)
346 mpToken->DecRef();
347 ResolveToken( p);
348 }
349 }
350
351
SetDouble(double f)352 inline void ScFormulaResult::SetDouble( double f )
353 {
354 ResetToDefaults();
355 // Handle a result obtained from the interpreter to be assigned to a matrix
356 // formula cell's ScMatrixFormulaCellToken.
357 ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
358 if (pMatFormula)
359 pMatFormula->SetUpperLeftDouble( f);
360 else
361 {
362 if (mbToken && mpToken)
363 mpToken->DecRef();
364 mfValue = f;
365 mbToken = false;
366 meMultiline = MULTILINE_FALSE;
367 }
368 }
369
370
GetType() const371 inline formula::StackVar ScFormulaResult::GetType() const
372 {
373 // Order is significant.
374 if (mnError)
375 return formula::svError;
376 if (mbEmpty)
377 return formula::svEmptyCell;
378 if (!mbToken)
379 return formula::svDouble;
380 if (mpToken)
381 return mpToken->GetType();
382 return formula::svUnknown;
383 }
384
385
GetCellResultType() const386 inline formula::StackVar ScFormulaResult::GetCellResultType() const
387 {
388 formula::StackVar sv = GetType();
389 if (sv == formula::svMatrixCell)
390 // don't need to test for mpToken here, GetType() already did it
391 sv = static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftType();
392 return sv;
393 }
394
395
IsEmptyDisplayedAsString() const396 inline bool ScFormulaResult::IsEmptyDisplayedAsString() const
397 {
398 if (mbEmpty)
399 return mbEmptyDisplayedAsString;
400 if (GetType() == formula::svMatrixCell)
401 {
402 // don't need to test for mpToken here, GetType() already did it
403 const ScEmptyCellToken* p = dynamic_cast<const ScEmptyCellToken*>(
404 static_cast<const ScMatrixCellResultToken*>(
405 mpToken)->GetUpperLeftToken().operator->());
406 if (p)
407 return p->IsDisplayedAsString();
408 }
409 return false;
410 }
411
412
IsValue() const413 inline bool ScFormulaResult::IsValue() const
414 {
415 formula::StackVar sv = GetCellResultType();
416 return sv == formula::svDouble || sv == formula::svError || sv == formula::svEmptyCell;
417 }
418
IsMultiline() const419 inline bool ScFormulaResult::IsMultiline() const
420 {
421 if (meMultiline == MULTILINE_UNKNOWN)
422 {
423 const String& rStr = GetString();
424 if (rStr.Len() && rStr.Search( _LF ) != STRING_NOTFOUND)
425 const_cast<ScFormulaResult*>(this)->meMultiline = MULTILINE_TRUE;
426 else
427 const_cast<ScFormulaResult*>(this)->meMultiline = MULTILINE_FALSE;
428 }
429 return meMultiline == MULTILINE_TRUE;
430 }
431
432
GetResultError() const433 inline sal_uInt16 ScFormulaResult::GetResultError() const
434 {
435 if (mnError)
436 return mnError;
437 formula::StackVar sv = GetCellResultType();
438 if (sv == formula::svError)
439 {
440 if (GetType() == formula::svMatrixCell)
441 // don't need to test for mpToken here, GetType() already did it
442 return static_cast<const ScMatrixCellResultToken*>(mpToken)->
443 GetUpperLeftToken()->GetError();
444 if (mpToken)
445 return mpToken->GetError();
446 }
447 return 0;
448 }
449
450
SetResultError(sal_uInt16 nErr)451 inline void ScFormulaResult::SetResultError( sal_uInt16 nErr )
452 {
453 mnError = nErr;
454 }
455
456
GetToken() const457 inline formula::FormulaConstTokenRef ScFormulaResult::GetToken() const
458 {
459 if (mbToken)
460 return mpToken;
461 return NULL;
462 }
463
464
GetCellResultToken() const465 inline formula::FormulaConstTokenRef ScFormulaResult::GetCellResultToken() const
466 {
467 if (GetType() == formula::svMatrixCell)
468 // don't need to test for mpToken here, GetType() already did it
469 return static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftToken();
470 return GetToken();
471 }
472
473
GetDouble() const474 inline double ScFormulaResult::GetDouble() const
475 {
476 if (mbToken)
477 {
478 // Should really not be of type formula::svDouble here.
479 if (mpToken)
480 {
481 switch (mpToken->GetType())
482 {
483 case formula::svHybridCell:
484 return mpToken->GetDouble();
485 case formula::svMatrixCell:
486 {
487 const ScMatrixCellResultToken* p =
488 static_cast<const ScMatrixCellResultToken*>(mpToken);
489 if (p->GetUpperLeftType() == formula::svDouble)
490 return p->GetUpperLeftToken()->GetDouble();
491 }
492 break;
493 default:
494 ; // nothing
495 }
496 }
497 return 0.0;
498 }
499 if (mbEmpty)
500 return 0.0;
501 return mfValue;
502 }
503
504
GetString() const505 inline const String & ScFormulaResult::GetString() const
506 {
507 if (mbToken && mpToken)
508 {
509 switch (mpToken->GetType())
510 {
511 case formula::svString:
512 case formula::svHybridCell:
513 return mpToken->GetString();
514 case formula::svMatrixCell:
515 {
516 const ScMatrixCellResultToken* p =
517 static_cast<const ScMatrixCellResultToken*>(mpToken);
518 if (p->GetUpperLeftType() == formula::svString)
519 return p->GetUpperLeftToken()->GetString();
520 }
521 break;
522 default:
523 ; // nothing
524 }
525 }
526 return EMPTY_STRING;
527 }
528
529
GetMatrix() const530 inline ScConstMatrixRef ScFormulaResult::GetMatrix() const
531 {
532 if (GetType() == formula::svMatrixCell)
533 return static_cast<const ScToken*>(mpToken)->GetMatrix();
534 return NULL;
535 }
536
537
GetHybridFormula() const538 inline const String & ScFormulaResult::GetHybridFormula() const
539 {
540 if (GetType() == formula::svHybridCell)
541 {
542 const ScHybridCellToken* p = dynamic_cast<const ScHybridCellToken*>(mpToken);
543 if (p)
544 return p->GetFormula();
545 }
546 return EMPTY_STRING;
547 }
548
549
SetHybridDouble(double f)550 inline void ScFormulaResult::SetHybridDouble( double f )
551 {
552 ResetToDefaults();
553 if (mbToken && mpToken)
554 {
555 String aString( GetString());
556 String aFormula( GetHybridFormula());
557 mpToken->DecRef();
558 mpToken = new ScHybridCellToken( f, aString, aFormula);
559 mpToken->IncRef();
560 }
561 else
562 {
563 mfValue = f;
564 mbToken = false;
565 meMultiline = MULTILINE_FALSE;
566 }
567 }
568
569
SetHybridString(const String & rStr)570 inline void ScFormulaResult::SetHybridString( const String & rStr )
571 {
572 // Obtain values before changing anything.
573 double f = GetDouble();
574 String aFormula( GetHybridFormula());
575 ResetToDefaults();
576 if (mbToken && mpToken)
577 mpToken->DecRef();
578 mpToken = new ScHybridCellToken( f, rStr, aFormula);
579 mpToken->IncRef();
580 mbToken = true;
581 }
582
583
SetHybridFormula(const String & rFormula)584 inline void ScFormulaResult::SetHybridFormula( const String & rFormula )
585 {
586 // Obtain values before changing anything.
587 double f = GetDouble();
588 String aStr( GetString());
589 ResetToDefaults();
590 if (mbToken && mpToken)
591 mpToken->DecRef();
592 mpToken = new ScHybridCellToken( f, aStr, rFormula);
593 mpToken->IncRef();
594 mbToken = true;
595 }
596
597
GetMatrixFormulaCellToken() const598 inline const ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellToken() const
599 {
600 return (GetType() == formula::svMatrixCell ?
601 dynamic_cast<const ScMatrixFormulaCellToken*>(mpToken) : NULL);
602 }
603
604
GetMatrixFormulaCellTokenNonConst()605 inline ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellTokenNonConst()
606 {
607 return const_cast<ScMatrixFormulaCellToken*>( GetMatrixFormulaCellToken());
608 }
609
610
611 #endif // SC_FORMULARESULT_HXX
612