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