xref: /aoo42x/main/sc/inc/formularesult.hxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
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.
14  *
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).
20  *
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.
25  *
26  ************************************************************************/
27 
28 #ifndef SC_FORMULARESULT_HXX
29 #define SC_FORMULARESULT_HXX
30 
31 #include "token.hxx"
32 
33 
34 /** Store a variable formula cell result, balancing between runtime performance
35     and memory consumption. */
36 class ScFormulaResult
37 {
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;
42 
43     union
44     {
45         double          mfValue;    // double result direct for performance and memory consumption
46         const formula::FormulaToken*  mpToken;    // if not, result token obtained from interpreter
47     };
48     sal_uInt16              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
53 
54     /** Reset mnError, mbEmpty and mbEmptyDisplayedAsString to their defaults
55         prior to assigning other types */
56     inline  void                ResetToDefaults();
57 
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 );
70 
71 public:
72                                 /** Effectively type svUnknown. */
73                                 ScFormulaResult()
74                                     : mpToken(NULL), mnError(0), mbToken(true),
75                                     mbEmpty(false), mbEmptyDisplayedAsString(false),
76                                     meMultiline(MULTILINE_UNKNOWN) {}
77 
78                                 ScFormulaResult( const ScFormulaResult & r )
79                                     : mnError( r.mnError), mbToken( r.mbToken),
80                                     mbEmpty( r.mbEmpty),
81                                     mbEmptyDisplayedAsString( r.mbEmptyDisplayedAsString),
82                                     meMultiline( r.meMultiline)
83                                 {
84                                     if (mbToken)
85                                     {
86                                         mpToken = r.mpToken;
87                                         if (mpToken)
88                                         {
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();
98                                         }
99                                     }
100                                     else
101                                         mfValue = r.mfValue;
102                                 }
103 
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)
109                                 {
110                                     SetToken( p);
111                                 }
112 
113                                 ~ScFormulaResult()
114                                 {
115                                     if (mbToken && mpToken)
116                                         mpToken->DecRef();
117                                 }
118 
119     /** Well, guess what ... */
120     inline  ScFormulaResult &   operator=( const ScFormulaResult & r );
121 
122     /** Assignment as in operator=() but without return */
123     inline  void                Assign( const ScFormulaResult & r );
124 
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.
129 
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 );
134 
135     /** May be NULL if SetToken() did so, also if type formula::svDouble or formula::svError! */
136     inline  formula::FormulaConstTokenRef     GetToken() const;
137 
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;
141 
142     /** Return type of result, including formula::svError, formula::svEmptyCell, formula::svDouble and
143         formula::svMatrixCell. */
144     inline  formula::StackVar            GetType() const;
145 
146     /** If type is formula::svMatrixCell return the type of upper left element, else
147         GetType() */
148     inline  formula::StackVar            GetCellResultType() const;
149 
150     /** If type is formula::svEmptyCell (including matrix upper left) and should be
151         displayed as empty string */
152     inline  bool                IsEmptyDisplayedAsString() const;
153 
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;
161 
162     /** Determines whether or not the result is a string containing more than
163         one paragraph */
164     inline  bool                IsMultiline() const;
165 
166     /** Get error code if set or GetCellResultType() is formula::svError or svUnknown,
167         else 0. */
168     inline  sal_uInt16              GetResultError() const;
169 
170     /** Set error code, don't touch token or double. */
171     inline  void                SetResultError( sal_uInt16 nErr );
172 
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 );
179 
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;
183 
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;
187 
188     /** Return matrix if type formula::svMatrixCell and ScMatrix present, else NULL. */
189     inline  ScConstMatrixRef    GetMatrix() const;
190 
191     /** Return formula string if type formula::svHybridCell, else empty string. */
192     inline  const String &      GetHybridFormula() const;
193 
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 );
198 
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 );
203 
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 );
208 
209     /** Get the const ScMatrixFormulaCellToken* if token is of that type, else
210         NULL. */
211     inline const ScMatrixFormulaCellToken* GetMatrixFormulaCellToken() const;
212 
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();
216 };
217 
218 
219 inline void ScFormulaResult::ResetToDefaults()
220 {
221     mnError = 0;
222     mbEmpty = false;
223     mbEmptyDisplayedAsString = false;
224     meMultiline = MULTILINE_UNKNOWN;
225 }
226 
227 
228 inline void ScFormulaResult::ResolveToken( const formula::FormulaToken * p )
229 {
230     ResetToDefaults();
231     if (!p)
232     {
233         mpToken = p;
234         mbToken = true;
235     }
236     else
237     {
238         switch (p->GetType())
239         {
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;
264         }
265     }
266 }
267 
268 
269 inline ScFormulaResult & ScFormulaResult::operator=( const ScFormulaResult & r )
270 {
271     Assign( r);
272     return *this;
273 }
274 
275 
276 inline void ScFormulaResult::Assign( const ScFormulaResult & r )
277 {
278     if (this == &r)
279         return;
280     if (r.mbEmpty)
281     {
282         if (mbToken && mpToken)
283             mpToken->DecRef();
284         mbToken = false;
285         mbEmpty = true;
286         mbEmptyDisplayedAsString = r.mbEmptyDisplayedAsString;
287         meMultiline = r.meMultiline;
288     }
289     else if (r.mbToken)
290     {
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);
298     }
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;
304 }
305 
306 
307 inline void ScFormulaResult::SetToken( const formula::FormulaToken* p )
308 {
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)
316     {
317         const ScMatrixCellResultToken* pMatResult =
318             (p && p->GetType() == formula::svMatrixCell ?
319              dynamic_cast<const ScMatrixCellResultToken*>(p) : NULL);
320         if (pMatResult)
321         {
322             const ScMatrixFormulaCellToken* pNewMatFormula =
323                 dynamic_cast<const ScMatrixFormulaCellToken*>(pMatResult);
324             if (pNewMatFormula)
325             {
326                 DBG_ERRORFILE( "ScFormulaResult::SetToken: pNewMatFormula and pMatFormula, overriding matrix formula dimension; intended?");
327                 pMatFormula->SetMatColsRows( pNewMatFormula->GetMatCols(),
328                         pNewMatFormula->GetMatRows());
329             }
330             pMatFormula->Assign( *pMatResult);
331             p->DecRef();
332         }
333         else if (p)
334         {
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();
340         }
341         else
342         {
343             // NULL result? Well, if you say so ...
344             pMatFormula->ResetResult();
345         }
346     }
347     else
348     {
349         if (mbToken && mpToken)
350             mpToken->DecRef();
351         ResolveToken( p);
352     }
353 }
354 
355 
356 inline void ScFormulaResult::SetDouble( double f )
357 {
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
365     {
366         if (mbToken && mpToken)
367             mpToken->DecRef();
368         mfValue = f;
369         mbToken = false;
370         meMultiline = MULTILINE_FALSE;
371     }
372 }
373 
374 
375 inline formula::StackVar ScFormulaResult::GetType() const
376 {
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;
387 }
388 
389 
390 inline formula::StackVar ScFormulaResult::GetCellResultType() const
391 {
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;
397 }
398 
399 
400 inline bool ScFormulaResult::IsEmptyDisplayedAsString() const
401 {
402     if (mbEmpty)
403         return mbEmptyDisplayedAsString;
404     if (GetType() == formula::svMatrixCell)
405     {
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();
412     }
413     return false;
414 }
415 
416 
417 inline bool ScFormulaResult::IsValue() const
418 {
419     formula::StackVar sv = GetCellResultType();
420     return sv == formula::svDouble || sv == formula::svError || sv == formula::svEmptyCell;
421 }
422 
423 inline bool ScFormulaResult::IsMultiline() const
424 {
425     if (meMultiline == MULTILINE_UNKNOWN)
426     {
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;
432     }
433     return meMultiline == MULTILINE_TRUE;
434 }
435 
436 
437 inline sal_uInt16 ScFormulaResult::GetResultError() const
438 {
439     if (mnError)
440         return mnError;
441     formula::StackVar sv = GetCellResultType();
442     if (sv == formula::svError)
443     {
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();
450     }
451     return 0;
452 }
453 
454 
455 inline void ScFormulaResult::SetResultError( sal_uInt16 nErr )
456 {
457     mnError = nErr;
458 }
459 
460 
461 inline formula::FormulaConstTokenRef ScFormulaResult::GetToken() const
462 {
463     if (mbToken)
464         return mpToken;
465     return NULL;
466 }
467 
468 
469 inline formula::FormulaConstTokenRef ScFormulaResult::GetCellResultToken() const
470 {
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();
475 }
476 
477 
478 inline double ScFormulaResult::GetDouble() const
479 {
480     if (mbToken)
481     {
482         // Should really not be of type formula::svDouble here.
483         if (mpToken)
484         {
485             switch (mpToken->GetType())
486             {
487                 case formula::svHybridCell:
488                     return mpToken->GetDouble();
489                 case formula::svMatrixCell:
490                     {
491                         const ScMatrixCellResultToken* p =
492                             static_cast<const ScMatrixCellResultToken*>(mpToken);
493                         if (p->GetUpperLeftType() == formula::svDouble)
494                             return p->GetUpperLeftToken()->GetDouble();
495                     }
496                     break;
497                 default:
498                     ;   // nothing
499             }
500         }
501         return 0.0;
502     }
503     if (mbEmpty)
504         return 0.0;
505     return mfValue;
506 }
507 
508 
509 inline const String & ScFormulaResult::GetString() const
510 {
511     if (mbToken && mpToken)
512     {
513         switch (mpToken->GetType())
514         {
515             case formula::svString:
516             case formula::svHybridCell:
517                 return mpToken->GetString();
518             case formula::svMatrixCell:
519                 {
520                     const ScMatrixCellResultToken* p =
521                         static_cast<const ScMatrixCellResultToken*>(mpToken);
522                     if (p->GetUpperLeftType() == formula::svString)
523                         return p->GetUpperLeftToken()->GetString();
524                 }
525                 break;
526             default:
527                 ;   // nothing
528         }
529     }
530     return EMPTY_STRING;
531 }
532 
533 
534 inline ScConstMatrixRef ScFormulaResult::GetMatrix() const
535 {
536     if (GetType() == formula::svMatrixCell)
537         return static_cast<const ScToken*>(mpToken)->GetMatrix();
538     return NULL;
539 }
540 
541 
542 inline const String & ScFormulaResult::GetHybridFormula() const
543 {
544     if (GetType() == formula::svHybridCell)
545     {
546         const ScHybridCellToken* p = dynamic_cast<const ScHybridCellToken*>(mpToken);
547         if (p)
548             return p->GetFormula();
549     }
550     return EMPTY_STRING;
551 }
552 
553 
554 inline void ScFormulaResult::SetHybridDouble( double f )
555 {
556     ResetToDefaults();
557     if (mbToken && mpToken)
558     {
559         String aString( GetString());
560         String aFormula( GetHybridFormula());
561         mpToken->DecRef();
562         mpToken = new ScHybridCellToken( f, aString, aFormula);
563         mpToken->IncRef();
564     }
565     else
566     {
567         mfValue = f;
568         mbToken = false;
569         meMultiline = MULTILINE_FALSE;
570     }
571 }
572 
573 
574 inline void ScFormulaResult::SetHybridString( const String & rStr )
575 {
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;
585 }
586 
587 
588 inline void ScFormulaResult::SetHybridFormula( const String & rFormula )
589 {
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;
599 }
600 
601 
602 inline const ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellToken() const
603 {
604     return (GetType() == formula::svMatrixCell ?
605             dynamic_cast<const ScMatrixFormulaCellToken*>(mpToken) : NULL);
606 }
607 
608 
609 inline ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellTokenNonConst()
610 {
611     return const_cast<ScMatrixFormulaCellToken*>( GetMatrixFormulaCellToken());
612 }
613 
614 
615 #endif // SC_FORMULARESULT_HXX
616