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. */ 69 ScFormulaResult() 70 : mpToken(NULL), mnError(0), mbToken(true), 71 mbEmpty(false), mbEmptyDisplayedAsString(false), 72 meMultiline(MULTILINE_UNKNOWN) {} 73 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! */ 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 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 215 inline void ScFormulaResult::ResetToDefaults() 216 { 217 mnError = 0; 218 mbEmpty = false; 219 mbEmptyDisplayedAsString = false; 220 meMultiline = MULTILINE_UNKNOWN; 221 } 222 223 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 265 inline ScFormulaResult & ScFormulaResult::operator=( const ScFormulaResult & r ) 266 { 267 Assign( r); 268 return *this; 269 } 270 271 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 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 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 371 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 386 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 396 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 413 inline bool ScFormulaResult::IsValue() const 414 { 415 formula::StackVar sv = GetCellResultType(); 416 return sv == formula::svDouble || sv == formula::svError || sv == formula::svEmptyCell; 417 } 418 419 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 433 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 451 inline void ScFormulaResult::SetResultError( sal_uInt16 nErr ) 452 { 453 mnError = nErr; 454 } 455 456 457 inline formula::FormulaConstTokenRef ScFormulaResult::GetToken() const 458 { 459 if (mbToken) 460 return mpToken; 461 return NULL; 462 } 463 464 465 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 474 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 505 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 530 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 538 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 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 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 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 598 inline const ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellToken() const 599 { 600 return (GetType() == formula::svMatrixCell ? 601 dynamic_cast<const ScMatrixFormulaCellToken*>(mpToken) : NULL); 602 } 603 604 605 inline ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellTokenNonConst() 606 { 607 return const_cast<ScMatrixFormulaCellToken*>( GetMatrixFormulaCellToken()); 608 } 609 610 611 #endif // SC_FORMULARESULT_HXX 612