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 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_sc.hxx" 26 27 // INCLUDE --------------------------------------------------------------- 28 29 #include <svl/zforlist.hxx> 30 31 #include "scitems.hxx" 32 #include "attrib.hxx" 33 #include "cell.hxx" 34 #include "compiler.hxx" 35 #include "interpre.hxx" 36 #include "document.hxx" 37 #include "scmatrix.hxx" 38 #include "dociter.hxx" 39 #include "docoptio.hxx" 40 #include "rechead.hxx" 41 #include "rangenam.hxx" 42 #include "brdcst.hxx" 43 #include "ddelink.hxx" 44 #include "validat.hxx" 45 #include "progress.hxx" 46 #include "editutil.hxx" 47 #include "recursionhelper.hxx" 48 #include "postit.hxx" 49 #include "externalrefmgr.hxx" 50 #include <editeng/editobj.hxx> 51 #include <svl/intitem.hxx> 52 #include <editeng/flditem.hxx> 53 #include <svl/broadcast.hxx> 54 55 using namespace formula; 56 // More or less arbitrary, of course all recursions must fit into available 57 // stack space (which is what on all systems we don't know yet?). Choosing a 58 // lower value may be better than trying a much higher value that also isn't 59 // sufficient but temporarily leads to high memory consumption. On the other 60 // hand, if the value fits all recursions, execution is quicker as no resumes 61 // are necessary. Could be made a configurable option. 62 // Allow for a year's calendar (366). 63 const sal_uInt16 MAXRECURSION = 400; 64 65 // STATIC DATA ----------------------------------------------------------- 66 67 #ifdef USE_MEMPOOL 68 // MemPools auf 4k Boundaries - 64 Bytes ausrichten 69 const sal_uInt16 nMemPoolValueCell = (0x8000 - 64) / sizeof(ScValueCell); 70 const sal_uInt16 nMemPoolFormulaCell = (0x8000 - 64) / sizeof(ScFormulaCell); 71 const sal_uInt16 nMemPoolStringCell = (0x4000 - 64) / sizeof(ScStringCell); 72 const sal_uInt16 nMemPoolNoteCell = (0x1000 - 64) / sizeof(ScNoteCell); 73 IMPL_FIXEDMEMPOOL_NEWDEL( ScValueCell, nMemPoolValueCell, nMemPoolValueCell ) 74 IMPL_FIXEDMEMPOOL_NEWDEL( ScFormulaCell, nMemPoolFormulaCell, nMemPoolFormulaCell ) 75 IMPL_FIXEDMEMPOOL_NEWDEL( ScStringCell, nMemPoolStringCell, nMemPoolStringCell ) 76 IMPL_FIXEDMEMPOOL_NEWDEL( ScNoteCell, nMemPoolNoteCell, nMemPoolNoteCell ) 77 #endif 78 79 // ============================================================================ 80 81 ScBaseCell::ScBaseCell( CellType eNewType ) : 82 mpNote( 0 ), 83 mpBroadcaster( 0 ), 84 nTextWidth( TEXTWIDTH_DIRTY ), 85 eCellType( sal::static_int_cast<sal_uInt8>(eNewType) ), 86 nScriptType( SC_SCRIPTTYPE_UNKNOWN ) 87 { 88 } 89 90 ScBaseCell::ScBaseCell( const ScBaseCell& rCell ) : 91 mpNote( 0 ), 92 mpBroadcaster( 0 ), 93 nTextWidth( rCell.nTextWidth ), 94 eCellType( rCell.eCellType ), 95 nScriptType( SC_SCRIPTTYPE_UNKNOWN ) 96 { 97 } 98 99 ScBaseCell::~ScBaseCell() 100 { 101 delete mpNote; 102 delete mpBroadcaster; 103 DBG_ASSERT( eCellType == CELLTYPE_DESTROYED, "BaseCell Destructor" ); 104 } 105 106 namespace { 107 108 ScBaseCell* lclCloneCell( const ScBaseCell& rSrcCell, ScDocument& rDestDoc, const ScAddress& rDestPos, int nCloneFlags ) 109 { 110 switch( rSrcCell.GetCellType() ) 111 { 112 case CELLTYPE_VALUE: 113 return new ScValueCell( static_cast< const ScValueCell& >( rSrcCell ) ); 114 case CELLTYPE_STRING: 115 return new ScStringCell( static_cast< const ScStringCell& >( rSrcCell ) ); 116 case CELLTYPE_EDIT: 117 return new ScEditCell( static_cast< const ScEditCell& >( rSrcCell ), rDestDoc ); 118 case CELLTYPE_FORMULA: 119 return new ScFormulaCell( static_cast< const ScFormulaCell& >( rSrcCell ), rDestDoc, rDestPos, nCloneFlags ); 120 case CELLTYPE_NOTE: 121 return new ScNoteCell; 122 default:; 123 } 124 DBG_ERROR( "lclCloneCell - unknown cell type" ); 125 return 0; 126 } 127 128 } // namespace 129 130 ScBaseCell* ScBaseCell::CloneWithoutNote( ScDocument& rDestDoc, int nCloneFlags ) const 131 { 132 // notes will not be cloned -> cell address only needed for formula cells 133 ScAddress aDestPos; 134 if( eCellType == CELLTYPE_FORMULA ) 135 aDestPos = static_cast< const ScFormulaCell* >( this )->aPos; 136 return lclCloneCell( *this, rDestDoc, aDestPos, nCloneFlags ); 137 } 138 139 ScBaseCell* ScBaseCell::CloneWithoutNote( ScDocument& rDestDoc, const ScAddress& rDestPos, int nCloneFlags ) const 140 { 141 return lclCloneCell( *this, rDestDoc, rDestPos, nCloneFlags ); 142 } 143 144 ScBaseCell* ScBaseCell::CloneWithNote( const ScAddress& rOwnPos, ScDocument& rDestDoc, const ScAddress& rDestPos, int nCloneFlags ) const 145 { 146 ScBaseCell* pNewCell = lclCloneCell( *this, rDestDoc, rDestPos, nCloneFlags ); 147 if( mpNote ) 148 { 149 if( !pNewCell ) 150 pNewCell = new ScNoteCell; 151 bool bCloneCaption = (nCloneFlags & SC_CLONECELL_NOCAPTION) == 0; 152 pNewCell->TakeNote( mpNote->Clone( rOwnPos, rDestDoc, rDestPos, bCloneCaption ) ); 153 } 154 return pNewCell; 155 } 156 157 void ScBaseCell::Delete() 158 { 159 DeleteNote(); 160 switch (eCellType) 161 { 162 case CELLTYPE_VALUE: 163 delete (ScValueCell*) this; 164 break; 165 case CELLTYPE_STRING: 166 delete (ScStringCell*) this; 167 break; 168 case CELLTYPE_EDIT: 169 delete (ScEditCell*) this; 170 break; 171 case CELLTYPE_FORMULA: 172 delete (ScFormulaCell*) this; 173 break; 174 case CELLTYPE_NOTE: 175 delete (ScNoteCell*) this; 176 break; 177 default: 178 DBG_ERROR("Unbekannter Zellentyp"); 179 break; 180 } 181 } 182 183 bool ScBaseCell::IsBlank( bool bIgnoreNotes ) const 184 { 185 return (eCellType == CELLTYPE_NOTE) && (bIgnoreNotes || !mpNote); 186 } 187 188 void ScBaseCell::TakeNote( ScPostIt* pNote ) 189 { 190 delete mpNote; 191 mpNote = pNote; 192 } 193 194 ScPostIt* ScBaseCell::ReleaseNote() 195 { 196 ScPostIt* pNote = mpNote; 197 mpNote = 0; 198 return pNote; 199 } 200 201 void ScBaseCell::DeleteNote() 202 { 203 DELETEZ( mpNote ); 204 } 205 206 void ScBaseCell::TakeBroadcaster( SvtBroadcaster* pBroadcaster ) 207 { 208 delete mpBroadcaster; 209 mpBroadcaster = pBroadcaster; 210 } 211 212 SvtBroadcaster* ScBaseCell::ReleaseBroadcaster() 213 { 214 SvtBroadcaster* pBroadcaster = mpBroadcaster; 215 mpBroadcaster = 0; 216 return pBroadcaster; 217 } 218 219 void ScBaseCell::DeleteBroadcaster() 220 { 221 DELETEZ( mpBroadcaster ); 222 } 223 224 ScBaseCell* ScBaseCell::CreateTextCell( const String& rString, ScDocument* pDoc ) 225 { 226 if ( rString.Search('\n') != STRING_NOTFOUND || rString.Search(CHAR_CR) != STRING_NOTFOUND ) 227 return new ScEditCell( rString, pDoc ); 228 else 229 return new ScStringCell( rString ); 230 } 231 232 void ScBaseCell::StartListeningTo( ScDocument* pDoc ) 233 { 234 if ( eCellType == CELLTYPE_FORMULA && !pDoc->IsClipOrUndo() 235 && !pDoc->GetNoListening() 236 && !((ScFormulaCell*)this)->IsInChangeTrack() 237 ) 238 { 239 pDoc->SetDetectiveDirty(sal_True); // es hat sich was geaendert... 240 241 ScFormulaCell* pFormCell = (ScFormulaCell*)this; 242 ScTokenArray* pArr = pFormCell->GetCode(); 243 if( pArr->IsRecalcModeAlways() ) 244 pDoc->StartListeningArea( BCA_LISTEN_ALWAYS, pFormCell ); 245 else 246 { 247 pArr->Reset(); 248 ScToken* t; 249 while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL ) 250 { 251 StackVar eType = t->GetType(); 252 ScSingleRefData& rRef1 = t->GetSingleRef(); 253 ScSingleRefData& rRef2 = (eType == svDoubleRef ? 254 t->GetDoubleRef().Ref2 : rRef1); 255 switch( eType ) 256 { 257 case svSingleRef: 258 rRef1.CalcAbsIfRel( pFormCell->aPos ); 259 if ( rRef1.Valid() ) 260 { 261 pDoc->StartListeningCell( 262 ScAddress( rRef1.nCol, 263 rRef1.nRow, 264 rRef1.nTab ), pFormCell ); 265 } 266 break; 267 case svDoubleRef: 268 t->CalcAbsIfRel( pFormCell->aPos ); 269 if ( rRef1.Valid() && rRef2.Valid() ) 270 { 271 if ( t->GetOpCode() == ocColRowNameAuto ) 272 { // automagically 273 if ( rRef1.IsColRel() ) 274 { // ColName 275 pDoc->StartListeningArea( ScRange ( 276 rRef1.nCol, 277 rRef1.nRow, 278 rRef1.nTab, 279 rRef2.nCol, 280 MAXROW, 281 rRef2.nTab ), pFormCell ); 282 } 283 else 284 { // RowName 285 pDoc->StartListeningArea( ScRange ( 286 rRef1.nCol, 287 rRef1.nRow, 288 rRef1.nTab, 289 MAXCOL, 290 rRef2.nRow, 291 rRef2.nTab ), pFormCell ); 292 } 293 } 294 else 295 { 296 pDoc->StartListeningArea( ScRange ( 297 rRef1.nCol, 298 rRef1.nRow, 299 rRef1.nTab, 300 rRef2.nCol, 301 rRef2.nRow, 302 rRef2.nTab ), pFormCell ); 303 } 304 } 305 break; 306 default: 307 ; // nothing 308 } 309 } 310 } 311 pFormCell->SetNeedsListening( sal_False); 312 } 313 } 314 315 // pArr gesetzt -> Referenzen von anderer Zelle nehmen 316 // dann muss auch aPos uebergeben werden! 317 318 void ScBaseCell::EndListeningTo( ScDocument* pDoc, ScTokenArray* pArr, 319 ScAddress aPos ) 320 { 321 if ( eCellType == CELLTYPE_FORMULA && !pDoc->IsClipOrUndo() 322 && !((ScFormulaCell*)this)->IsInChangeTrack() 323 ) 324 { 325 pDoc->SetDetectiveDirty(sal_True); // es hat sich was geaendert... 326 327 ScFormulaCell* pFormCell = (ScFormulaCell*)this; 328 if( pFormCell->GetCode()->IsRecalcModeAlways() ) 329 pDoc->EndListeningArea( BCA_LISTEN_ALWAYS, pFormCell ); 330 else 331 { 332 if (!pArr) 333 { 334 pArr = pFormCell->GetCode(); 335 aPos = pFormCell->aPos; 336 } 337 pArr->Reset(); 338 ScToken* t; 339 while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL ) 340 { 341 StackVar eType = t->GetType(); 342 ScSingleRefData& rRef1 = t->GetSingleRef(); 343 ScSingleRefData& rRef2 = (eType == svDoubleRef ? 344 t->GetDoubleRef().Ref2 : rRef1); 345 switch( eType ) 346 { 347 case svSingleRef: 348 rRef1.CalcAbsIfRel( aPos ); 349 if ( rRef1.Valid() ) 350 { 351 pDoc->EndListeningCell( 352 ScAddress( rRef1.nCol, 353 rRef1.nRow, 354 rRef1.nTab ), pFormCell ); 355 } 356 break; 357 case svDoubleRef: 358 t->CalcAbsIfRel( aPos ); 359 if ( rRef1.Valid() && rRef2.Valid() ) 360 { 361 if ( t->GetOpCode() == ocColRowNameAuto ) 362 { // automagically 363 if ( rRef1.IsColRel() ) 364 { // ColName 365 pDoc->EndListeningArea( ScRange ( 366 rRef1.nCol, 367 rRef1.nRow, 368 rRef1.nTab, 369 rRef2.nCol, 370 MAXROW, 371 rRef2.nTab ), pFormCell ); 372 } 373 else 374 { // RowName 375 pDoc->EndListeningArea( ScRange ( 376 rRef1.nCol, 377 rRef1.nRow, 378 rRef1.nTab, 379 MAXCOL, 380 rRef2.nRow, 381 rRef2.nTab ), pFormCell ); 382 } 383 } 384 else 385 { 386 pDoc->EndListeningArea( ScRange ( 387 rRef1.nCol, 388 rRef1.nRow, 389 rRef1.nTab, 390 rRef2.nCol, 391 rRef2.nRow, 392 rRef2.nTab ), pFormCell ); 393 } 394 } 395 break; 396 default: 397 ; // nothing 398 } 399 } 400 } 401 } 402 } 403 404 405 sal_uInt16 ScBaseCell::GetErrorCode() const 406 { 407 switch ( eCellType ) 408 { 409 case CELLTYPE_FORMULA : 410 return ((ScFormulaCell*)this)->GetErrCode(); 411 default: 412 return 0; 413 } 414 } 415 416 417 sal_Bool ScBaseCell::HasEmptyData() const 418 { 419 switch ( eCellType ) 420 { 421 case CELLTYPE_NOTE : 422 return sal_True; 423 case CELLTYPE_FORMULA : 424 return ((ScFormulaCell*)this)->IsEmpty(); 425 default: 426 return sal_False; 427 } 428 } 429 430 431 sal_Bool ScBaseCell::HasValueData() const 432 { 433 switch ( eCellType ) 434 { 435 case CELLTYPE_VALUE : 436 return sal_True; 437 case CELLTYPE_FORMULA : 438 return ((ScFormulaCell*)this)->IsValue(); 439 default: 440 return sal_False; 441 } 442 } 443 444 445 sal_Bool ScBaseCell::HasStringData() const 446 { 447 switch ( eCellType ) 448 { 449 case CELLTYPE_STRING : 450 case CELLTYPE_EDIT : 451 return sal_True; 452 case CELLTYPE_FORMULA : 453 return !((ScFormulaCell*)this)->IsValue(); 454 default: 455 return sal_False; 456 } 457 } 458 459 String ScBaseCell::GetStringData() const 460 { 461 String aStr; 462 switch ( eCellType ) 463 { 464 case CELLTYPE_STRING: 465 ((const ScStringCell*)this)->GetString( aStr ); 466 break; 467 case CELLTYPE_EDIT: 468 ((const ScEditCell*)this)->GetString( aStr ); 469 break; 470 case CELLTYPE_FORMULA: 471 ((ScFormulaCell*)this)->GetString( aStr ); // an der Formelzelle nicht-const 472 break; 473 } 474 return aStr; 475 } 476 477 // static 478 sal_Bool ScBaseCell::CellEqual( const ScBaseCell* pCell1, const ScBaseCell* pCell2 ) 479 { 480 CellType eType1 = CELLTYPE_NONE; 481 CellType eType2 = CELLTYPE_NONE; 482 if ( pCell1 ) 483 { 484 eType1 = pCell1->GetCellType(); 485 if (eType1 == CELLTYPE_EDIT) 486 eType1 = CELLTYPE_STRING; 487 else if (eType1 == CELLTYPE_NOTE) 488 eType1 = CELLTYPE_NONE; 489 } 490 if ( pCell2 ) 491 { 492 eType2 = pCell2->GetCellType(); 493 if (eType2 == CELLTYPE_EDIT) 494 eType2 = CELLTYPE_STRING; 495 else if (eType2 == CELLTYPE_NOTE) 496 eType2 = CELLTYPE_NONE; 497 } 498 if ( eType1 != eType2 ) 499 return sal_False; 500 501 switch ( eType1 ) // beide Typen gleich 502 { 503 case CELLTYPE_NONE: // beide leer 504 return sal_True; 505 case CELLTYPE_VALUE: // wirklich Value-Zellen 506 return ( ((const ScValueCell*)pCell1)->GetValue() == 507 ((const ScValueCell*)pCell2)->GetValue() ); 508 case CELLTYPE_STRING: // String oder Edit 509 { 510 String aText1; 511 if ( pCell1->GetCellType() == CELLTYPE_STRING ) 512 ((const ScStringCell*)pCell1)->GetString(aText1); 513 else 514 ((const ScEditCell*)pCell1)->GetString(aText1); 515 String aText2; 516 if ( pCell2->GetCellType() == CELLTYPE_STRING ) 517 ((const ScStringCell*)pCell2)->GetString(aText2); 518 else 519 ((const ScEditCell*)pCell2)->GetString(aText2); 520 return ( aText1 == aText2 ); 521 } 522 case CELLTYPE_FORMULA: 523 { 524 //! eingefuegte Zeilen / Spalten beruecksichtigen !!!!! 525 //! Vergleichsfunktion an der Formelzelle ??? 526 //! Abfrage mit ScColumn::SwapRow zusammenfassen! 527 528 ScTokenArray* pCode1 = ((ScFormulaCell*)pCell1)->GetCode(); 529 ScTokenArray* pCode2 = ((ScFormulaCell*)pCell2)->GetCode(); 530 531 if (pCode1->GetLen() == pCode2->GetLen()) // nicht-UPN 532 { 533 sal_Bool bEqual = sal_True; 534 sal_uInt16 nLen = pCode1->GetLen(); 535 FormulaToken** ppToken1 = pCode1->GetArray(); 536 FormulaToken** ppToken2 = pCode2->GetArray(); 537 for (sal_uInt16 i=0; i<nLen; i++) 538 if ( !ppToken1[i]->TextEqual(*(ppToken2[i])) ) 539 { 540 bEqual = sal_False; 541 break; 542 } 543 544 if (bEqual) 545 return sal_True; 546 } 547 548 return sal_False; // unterschiedlich lang oder unterschiedliche Tokens 549 } 550 default: 551 DBG_ERROR("huch, was fuer Zellen???"); 552 } 553 return sal_False; 554 } 555 556 // ============================================================================ 557 558 ScNoteCell::ScNoteCell( SvtBroadcaster* pBC ) : 559 ScBaseCell( CELLTYPE_NOTE ) 560 { 561 TakeBroadcaster( pBC ); 562 } 563 564 ScNoteCell::ScNoteCell( ScPostIt* pNote, SvtBroadcaster* pBC ) : 565 ScBaseCell( CELLTYPE_NOTE ) 566 { 567 TakeNote( pNote ); 568 TakeBroadcaster( pBC ); 569 } 570 571 #ifdef DBG_UTIL 572 ScNoteCell::~ScNoteCell() 573 { 574 eCellType = CELLTYPE_DESTROYED; 575 } 576 #endif 577 578 // ============================================================================ 579 580 ScValueCell::ScValueCell() : 581 ScBaseCell( CELLTYPE_VALUE ), 582 mfValue( 0.0 ) 583 { 584 } 585 586 ScValueCell::ScValueCell( double fValue ) : 587 ScBaseCell( CELLTYPE_VALUE ), 588 mfValue( fValue ) 589 { 590 } 591 592 #ifdef DBG_UTIL 593 ScValueCell::~ScValueCell() 594 { 595 eCellType = CELLTYPE_DESTROYED; 596 } 597 #endif 598 599 // ============================================================================ 600 601 ScStringCell::ScStringCell() : 602 ScBaseCell( CELLTYPE_STRING ) 603 { 604 } 605 606 ScStringCell::ScStringCell( const String& rString ) : 607 ScBaseCell( CELLTYPE_STRING ), 608 maString( rString.intern() ) 609 { 610 } 611 612 #ifdef DBG_UTIL 613 ScStringCell::~ScStringCell() 614 { 615 eCellType = CELLTYPE_DESTROYED; 616 } 617 #endif 618 619 // ============================================================================ 620 621 // 622 // ScFormulaCell 623 // 624 625 ScFormulaCell::ScFormulaCell() : 626 ScBaseCell( CELLTYPE_FORMULA ), 627 eTempGrammar( FormulaGrammar::GRAM_DEFAULT), 628 pCode( NULL ), 629 pDocument( NULL ), 630 pPrevious(0), 631 pNext(0), 632 pPreviousTrack(0), 633 pNextTrack(0), 634 nFormatIndex(0), 635 nFormatType( NUMBERFORMAT_NUMBER ), 636 nSeenInIteration(0), 637 cMatrixFlag ( MM_NONE ), 638 bDirty( sal_False ), 639 bChanged( sal_False ), 640 bRunning( sal_False ), 641 bCompile( sal_False ), 642 bSubTotal( sal_False ), 643 bIsIterCell( sal_False ), 644 bInChangeTrack( sal_False ), 645 bTableOpDirty( sal_False ), 646 bNeedListening( sal_False ), 647 aPos(0,0,0) 648 { 649 } 650 651 ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos, 652 const String& rFormula, 653 const FormulaGrammar::Grammar eGrammar, 654 sal_uInt8 cMatInd ) : 655 ScBaseCell( CELLTYPE_FORMULA ), 656 eTempGrammar( eGrammar), 657 pCode( NULL ), 658 pDocument( pDoc ), 659 pPrevious(0), 660 pNext(0), 661 pPreviousTrack(0), 662 pNextTrack(0), 663 nFormatIndex(0), 664 nFormatType( NUMBERFORMAT_NUMBER ), 665 nSeenInIteration(0), 666 cMatrixFlag ( cMatInd ), 667 bDirty( sal_True ), // -> wg. Benutzung im Fkt.AutoPiloten, war: cMatInd != 0 668 bChanged( sal_False ), 669 bRunning( sal_False ), 670 bCompile( sal_False ), 671 bSubTotal( sal_False ), 672 bIsIterCell( sal_False ), 673 bInChangeTrack( sal_False ), 674 bTableOpDirty( sal_False ), 675 bNeedListening( sal_False ), 676 aPos( rPos ) 677 { 678 Compile( rFormula, sal_True, eGrammar ); // bNoListening, Insert does that 679 } 680 681 // Wird von den Importfiltern verwendet 682 683 ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos, 684 const ScTokenArray* pArr, 685 const FormulaGrammar::Grammar eGrammar, sal_uInt8 cInd ) : 686 ScBaseCell( CELLTYPE_FORMULA ), 687 eTempGrammar( eGrammar), 688 pCode( pArr ? new ScTokenArray( *pArr ) : new ScTokenArray ), 689 pDocument( pDoc ), 690 pPrevious(0), 691 pNext(0), 692 pPreviousTrack(0), 693 pNextTrack(0), 694 nFormatIndex(0), 695 nFormatType( NUMBERFORMAT_NUMBER ), 696 nSeenInIteration(0), 697 cMatrixFlag ( cInd ), 698 bDirty( NULL != pArr ), // -> wg. Benutzung im Fkt.AutoPiloten, war: cInd != 0 699 bChanged( sal_False ), 700 bRunning( sal_False ), 701 bCompile( sal_False ), 702 bSubTotal( sal_False ), 703 bIsIterCell( sal_False ), 704 bInChangeTrack( sal_False ), 705 bTableOpDirty( sal_False ), 706 bNeedListening( sal_False ), 707 aPos( rPos ) 708 { 709 // UPN-Array erzeugen 710 if( pCode->GetLen() && !pCode->GetCodeError() && !pCode->GetCodeLen() ) 711 { 712 ScCompiler aComp( pDocument, aPos, *pCode); 713 aComp.SetGrammar(eTempGrammar); 714 bSubTotal = aComp.CompileTokenArray(); 715 nFormatType = aComp.GetNumFormatType(); 716 } 717 else 718 { 719 pCode->Reset(); 720 if ( pCode->GetNextOpCodeRPN( ocSubTotal ) ) 721 bSubTotal = sal_True; 722 } 723 } 724 725 ScFormulaCell::ScFormulaCell( const ScFormulaCell& rCell, ScDocument& rDoc, const ScAddress& rPos, int nCloneFlags ) : 726 ScBaseCell( rCell ), 727 SvtListener(), 728 aResult( rCell.aResult ), 729 eTempGrammar( rCell.eTempGrammar), 730 pDocument( &rDoc ), 731 pPrevious(0), 732 pNext(0), 733 pPreviousTrack(0), 734 pNextTrack(0), 735 nFormatIndex( &rDoc == rCell.pDocument ? rCell.nFormatIndex : 0 ), 736 nFormatType( rCell.nFormatType ), 737 nSeenInIteration(0), 738 cMatrixFlag ( rCell.cMatrixFlag ), 739 bDirty( rCell.bDirty ), 740 bChanged( rCell.bChanged ), 741 bRunning( sal_False ), 742 bCompile( rCell.bCompile ), 743 bSubTotal( rCell.bSubTotal ), 744 bIsIterCell( sal_False ), 745 bInChangeTrack( sal_False ), 746 bTableOpDirty( sal_False ), 747 bNeedListening( sal_False ), 748 aPos( rPos ) 749 { 750 pCode = (rCell.pCode) ? rCell.pCode->Clone() : NULL; 751 752 if ( nCloneFlags & SC_CLONECELL_ADJUST3DREL ) 753 pCode->ReadjustRelative3DReferences( rCell.aPos, aPos ); 754 755 // evtl. Fehler zuruecksetzen und neu kompilieren 756 // nicht im Clipboard - da muss das Fehlerflag erhalten bleiben 757 // Spezialfall Laenge=0: als Fehlerzelle erzeugt, dann auch Fehler behalten 758 if ( pCode->GetCodeError() && !pDocument->IsClipboard() && pCode->GetLen() ) 759 { 760 pCode->SetCodeError( 0 ); 761 bCompile = sal_True; 762 } 763 //! Compile ColRowNames on URM_MOVE/URM_COPY _after_ UpdateReference 764 sal_Bool bCompileLater = sal_False; 765 sal_Bool bClipMode = rCell.pDocument->IsClipboard(); 766 if( !bCompile ) 767 { // Name references with references and ColRowNames 768 pCode->Reset(); 769 ScToken* t; 770 while ( ( t = static_cast<ScToken*>(pCode->GetNextReferenceOrName()) ) != NULL && !bCompile ) 771 { 772 if ( t->GetOpCode() == ocExternalRef ) 773 { 774 // External name, cell, and area references. 775 bCompile = true; 776 } 777 else if ( t->GetType() == svIndex ) 778 { 779 ScRangeData* pRangeData = rDoc.GetRangeName()->FindIndex( t->GetIndex() ); 780 if( pRangeData ) 781 { 782 if( pRangeData->HasReferences() ) 783 bCompile = sal_True; 784 } 785 else 786 bCompile = sal_True; // invalid reference! 787 } 788 else if ( t->GetOpCode() == ocColRowName ) 789 { 790 bCompile = sal_True; // new lookup needed 791 bCompileLater = bClipMode; 792 } 793 } 794 } 795 if( bCompile ) 796 { 797 if ( !bCompileLater && bClipMode ) 798 { 799 // Merging ranges needs the actual positions after UpdateReference. 800 // ColRowNames need new lookup after positions are adjusted. 801 bCompileLater = pCode->HasOpCode( ocRange) || pCode->HasOpCode( ocColRowName); 802 } 803 if ( !bCompileLater ) 804 { 805 // bNoListening, not at all if in Clipboard/Undo, 806 // and not from Clipboard either, instead after Insert(Clone) and UpdateReference. 807 CompileTokenArray( sal_True ); 808 } 809 } 810 811 if( nCloneFlags & SC_CLONECELL_STARTLISTENING ) 812 StartListeningTo( &rDoc ); 813 } 814 815 ScFormulaCell::~ScFormulaCell() 816 { 817 pDocument->RemoveFromFormulaTree( this ); 818 819 if (pDocument->HasExternalRefManager()) 820 pDocument->GetExternalRefManager()->removeRefCell(this); 821 822 delete pCode; 823 #ifdef DBG_UTIL 824 eCellType = CELLTYPE_DESTROYED; 825 #endif 826 } 827 828 void ScFormulaCell::GetFormula( rtl::OUStringBuffer& rBuffer, 829 const FormulaGrammar::Grammar eGrammar ) const 830 { 831 if( pCode->GetCodeError() && !pCode->GetLen() ) 832 { 833 rBuffer = rtl::OUStringBuffer( ScGlobal::GetErrorString( pCode->GetCodeError())); 834 return; 835 } 836 else if( cMatrixFlag == MM_REFERENCE ) 837 { 838 // Reference to another cell that contains a matrix formula. 839 pCode->Reset(); 840 ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN()); 841 if( p ) 842 { 843 /* FIXME: original GetFormula() code obtained 844 * pCell only if (!this->IsInChangeTrack()), 845 * GetEnglishFormula() omitted that test. 846 * Can we live without in all cases? */ 847 ScBaseCell* pCell; 848 ScSingleRefData& rRef = p->GetSingleRef(); 849 rRef.CalcAbsIfRel( aPos ); 850 if ( rRef.Valid() ) 851 pCell = pDocument->GetCell( ScAddress( rRef.nCol, 852 rRef.nRow, rRef.nTab ) ); 853 else 854 pCell = NULL; 855 if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA) 856 { 857 ((ScFormulaCell*)pCell)->GetFormula( rBuffer, eGrammar); 858 return; 859 } 860 else 861 { 862 ScCompiler aComp( pDocument, aPos, *pCode); 863 aComp.SetGrammar(eGrammar); 864 aComp.CreateStringFromTokenArray( rBuffer ); 865 } 866 } 867 else 868 { 869 DBG_ERROR("ScFormulaCell::GetFormula: not a matrix"); 870 } 871 } 872 else 873 { 874 ScCompiler aComp( pDocument, aPos, *pCode); 875 aComp.SetGrammar(eGrammar); 876 aComp.CreateStringFromTokenArray( rBuffer ); 877 } 878 879 sal_Unicode ch('='); 880 rBuffer.insert( 0, &ch, 1 ); 881 if( cMatrixFlag ) 882 { 883 sal_Unicode ch2('{'); 884 rBuffer.insert( 0, &ch2, 1); 885 rBuffer.append( sal_Unicode('}')); 886 } 887 } 888 889 void ScFormulaCell::GetFormula( String& rFormula, const FormulaGrammar::Grammar eGrammar ) const 890 { 891 rtl::OUStringBuffer rBuffer( rFormula ); 892 GetFormula( rBuffer, eGrammar ); 893 rFormula = rBuffer; 894 } 895 896 void ScFormulaCell::GetResultDimensions( SCSIZE& rCols, SCSIZE& rRows ) 897 { 898 if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc()) 899 Interpret(); 900 901 const ScMatrix* pMat = NULL; 902 if (!pCode->GetCodeError() && aResult.GetType() == svMatrixCell && 903 ((pMat = static_cast<const ScToken*>(aResult.GetToken().get())->GetMatrix()) != 0)) 904 pMat->GetDimensions( rCols, rRows ); 905 else 906 { 907 rCols = 0; 908 rRows = 0; 909 } 910 } 911 912 void ScFormulaCell::Compile( const String& rFormula, sal_Bool bNoListening, 913 const FormulaGrammar::Grammar eGrammar ) 914 { 915 //#118851#, the initialization code for pCode after it can not be gnored if it is still NULL 916 if ( pCode && pDocument->IsClipOrUndo() ) return; 917 sal_Bool bWasInFormulaTree = pDocument->IsInFormulaTree( this ); 918 if ( bWasInFormulaTree ) 919 pDocument->RemoveFromFormulaTree( this ); 920 // pCode darf fuer Abfragen noch nicht geloescht, muss aber leer sein 921 if ( pCode ) 922 pCode->Clear(); 923 ScTokenArray* pCodeOld = pCode; 924 ScCompiler aComp( pDocument, aPos); 925 aComp.SetGrammar(eGrammar); 926 pCode = aComp.CompileString( rFormula ); 927 if ( pCodeOld ) 928 delete pCodeOld; 929 if( !pCode->GetCodeError() ) 930 { 931 if ( !pCode->GetLen() && aResult.GetHybridFormula().Len() && rFormula == aResult.GetHybridFormula() ) 932 { // #65994# nicht rekursiv CompileTokenArray/Compile/CompileTokenArray 933 if ( rFormula.GetChar(0) == '=' ) 934 pCode->AddBad( rFormula.GetBuffer() + 1 ); 935 else 936 pCode->AddBad( rFormula.GetBuffer() ); 937 } 938 bCompile = sal_True; 939 CompileTokenArray( bNoListening ); 940 } 941 else 942 { 943 bChanged = sal_True; 944 SetTextWidth( TEXTWIDTH_DIRTY ); 945 SetScriptType( SC_SCRIPTTYPE_UNKNOWN ); 946 } 947 if ( bWasInFormulaTree ) 948 pDocument->PutInFormulaTree( this ); 949 } 950 951 952 void ScFormulaCell::CompileTokenArray( sal_Bool bNoListening ) 953 { 954 // Not already compiled? 955 if( !pCode->GetLen() && aResult.GetHybridFormula().Len() ) 956 Compile( aResult.GetHybridFormula(), bNoListening, eTempGrammar); 957 else if( bCompile && !pDocument->IsClipOrUndo() && !pCode->GetCodeError() ) 958 { 959 // RPN length may get changed 960 sal_Bool bWasInFormulaTree = pDocument->IsInFormulaTree( this ); 961 if ( bWasInFormulaTree ) 962 pDocument->RemoveFromFormulaTree( this ); 963 964 // Loading from within filter? No listening yet! 965 if( pDocument->IsInsertingFromOtherDoc() ) 966 bNoListening = sal_True; 967 968 if( !bNoListening && pCode->GetCodeLen() ) 969 EndListeningTo( pDocument ); 970 ScCompiler aComp(pDocument, aPos, *pCode); 971 aComp.SetGrammar(pDocument->GetGrammar()); 972 bSubTotal = aComp.CompileTokenArray(); 973 if( !pCode->GetCodeError() ) 974 { 975 nFormatType = aComp.GetNumFormatType(); 976 nFormatIndex = 0; 977 bChanged = sal_True; 978 aResult.SetToken( NULL); 979 bCompile = sal_False; 980 if ( !bNoListening ) 981 StartListeningTo( pDocument ); 982 } 983 if ( bWasInFormulaTree ) 984 pDocument->PutInFormulaTree( this ); 985 } 986 } 987 988 989 void ScFormulaCell::CompileXML( ScProgress& rProgress ) 990 { 991 if ( cMatrixFlag == MM_REFERENCE ) 992 { // is already token code via ScDocFunc::EnterMatrix, ScDocument::InsertMatrixFormula 993 // just establish listeners 994 StartListeningTo( pDocument ); 995 return ; 996 } 997 998 ScCompiler aComp( pDocument, aPos, *pCode); 999 aComp.SetGrammar(eTempGrammar); 1000 String aFormula, aFormulaNmsp; 1001 aComp.CreateStringFromXMLTokenArray( aFormula, aFormulaNmsp ); 1002 pDocument->DecXMLImportedFormulaCount( aFormula.Len() ); 1003 rProgress.SetStateCountDownOnPercent( pDocument->GetXMLImportedFormulaCount() ); 1004 // pCode darf fuer Abfragen noch nicht geloescht, muss aber leer sein 1005 if ( pCode ) 1006 pCode->Clear(); 1007 ScTokenArray* pCodeOld = pCode; 1008 pCode = aComp.CompileString( aFormula, aFormulaNmsp ); 1009 delete pCodeOld; 1010 if( !pCode->GetCodeError() ) 1011 { 1012 if ( !pCode->GetLen() ) 1013 { 1014 if ( aFormula.GetChar(0) == '=' ) 1015 pCode->AddBad( aFormula.GetBuffer() + 1 ); 1016 else 1017 pCode->AddBad( aFormula.GetBuffer() ); 1018 } 1019 bSubTotal = aComp.CompileTokenArray(); 1020 if( !pCode->GetCodeError() ) 1021 { 1022 nFormatType = aComp.GetNumFormatType(); 1023 nFormatIndex = 0; 1024 bChanged = sal_True; 1025 bCompile = sal_False; 1026 StartListeningTo( pDocument ); 1027 } 1028 } 1029 else 1030 { 1031 bChanged = sal_True; 1032 SetTextWidth( TEXTWIDTH_DIRTY ); 1033 SetScriptType( SC_SCRIPTTYPE_UNKNOWN ); 1034 } 1035 1036 // Same as in Load: after loading, it must be known if ocMacro is in any formula 1037 // (for macro warning, CompileXML is called at the end of loading XML file) 1038 if ( !pDocument->GetHasMacroFunc() && pCode->HasOpCodeRPN( ocMacro ) ) 1039 pDocument->SetHasMacroFunc( sal_True ); 1040 } 1041 1042 1043 void ScFormulaCell::CalcAfterLoad() 1044 { 1045 sal_Bool bNewCompiled = sal_False; 1046 // Falls ein Calc 1.0-Doc eingelesen wird, haben wir ein Ergebnis, 1047 // aber kein TokenArray 1048 if( !pCode->GetLen() && aResult.GetHybridFormula().Len() ) 1049 { 1050 Compile( aResult.GetHybridFormula(), sal_True, eTempGrammar); 1051 aResult.SetToken( NULL); 1052 bDirty = sal_True; 1053 bNewCompiled = sal_True; 1054 } 1055 // Das UPN-Array wird nicht erzeugt, wenn ein Calc 3.0-Doc eingelesen 1056 // wurde, da die RangeNames erst jetzt existieren. 1057 if( pCode->GetLen() && !pCode->GetCodeLen() && !pCode->GetCodeError() ) 1058 { 1059 ScCompiler aComp(pDocument, aPos, *pCode); 1060 aComp.SetGrammar(pDocument->GetGrammar()); 1061 bSubTotal = aComp.CompileTokenArray(); 1062 nFormatType = aComp.GetNumFormatType(); 1063 nFormatIndex = 0; 1064 bDirty = sal_True; 1065 bCompile = sal_False; 1066 bNewCompiled = sal_True; 1067 } 1068 // irgendwie koennen unter os/2 mit rotter FPU-Exception /0 ohne Err503 1069 // gespeichert werden, woraufhin spaeter im NumberFormatter die BLC Lib 1070 // bei einem fabs(-NAN) abstuerzt (#32739#) 1071 // hier fuer alle Systeme ausbuegeln, damit da auch Err503 steht 1072 if ( aResult.IsValue() && !::rtl::math::isFinite( aResult.GetDouble() ) ) 1073 { 1074 DBG_ERRORFILE("Formelzelle INFINITY !!! Woher kommt das Dokument?"); 1075 aResult.SetResultError( errIllegalFPOperation ); 1076 bDirty = sal_True; 1077 } 1078 // DoubleRefs bei binaeren Operatoren waren vor v5.0 immer Matrix, 1079 // jetzt nur noch wenn in Matrixformel, sonst implizite Schnittmenge 1080 if ( pDocument->GetSrcVersion() < SC_MATRIX_DOUBLEREF && 1081 GetMatrixFlag() == MM_NONE && pCode->HasMatrixDoubleRefOps() ) 1082 { 1083 cMatrixFlag = MM_FORMULA; 1084 SetMatColsRows( 1, 1); 1085 } 1086 // Muss die Zelle berechnet werden? 1087 // Nach Load koennen Zellen einen Fehlercode enthalten, auch dann 1088 // Listener starten und ggbf. neu berechnen wenn nicht RECALCMODE_NORMAL 1089 if( !bNewCompiled || !pCode->GetCodeError() ) 1090 { 1091 StartListeningTo( pDocument ); 1092 if( !pCode->IsRecalcModeNormal() ) 1093 bDirty = sal_True; 1094 } 1095 if ( pCode->IsRecalcModeAlways() ) 1096 { // zufall(), heute(), jetzt() bleiben immer im FormulaTree, damit sie 1097 // auch bei jedem F9 berechnet werden. 1098 bDirty = sal_True; 1099 } 1100 // Noch kein SetDirty weil noch nicht alle Listener bekannt, erst in 1101 // SetDirtyAfterLoad. 1102 } 1103 1104 1105 bool ScFormulaCell::MarkUsedExternalReferences() 1106 { 1107 return pCode && pDocument->MarkUsedExternalReferences( *pCode); 1108 } 1109 1110 1111 // FIXME: set to 0 1112 #define erDEBUGDOT 0 1113 // If set to 1, write output that's suitable for graphviz tools like dot. 1114 // Only node1 -> node2 entries are written, you'll have to manually surround 1115 // the file content with [strict] digraph name { ... } 1116 // The ``strict'' keyword might be necessary in case of multiple identical 1117 // paths like they occur in iterations, otherwise dot may consume too much 1118 // memory when generating the layout, or you'll get unreadable output. On the 1119 // other hand, information about recurring calculation is lost then. 1120 // Generates output only if variable nDebug is set in debugger, see below. 1121 // FIXME: currently doesn't cope with iterations and recursions. Code fragments 1122 // are a leftover from a previous debug session, meant as a pointer. 1123 #if erDEBUGDOT 1124 #include <cstdio> 1125 using ::std::fopen; 1126 using ::std::fprintf; 1127 #include <vector> 1128 static const char aDebugDotFile[] = "ttt_debug.dot"; 1129 #endif 1130 1131 void ScFormulaCell::Interpret() 1132 { 1133 1134 #if erDEBUGDOT 1135 static int nDebug = 0; 1136 static const int erDEBUGDOTRUN = 3; 1137 static FILE* pDebugFile = 0; 1138 static sal_Int32 nDebugRootCount = 0; 1139 static unsigned int nDebugPathCount = 0; 1140 static ScAddress aDebugLastPos( ScAddress::INITIALIZE_INVALID); 1141 static ScAddress aDebugThisPos( ScAddress::INITIALIZE_INVALID); 1142 typedef ::std::vector< ByteString > DebugVector; 1143 static DebugVector aDebugVec; 1144 class DebugElement 1145 { 1146 public: 1147 static void push( ScFormulaCell* pCell ) 1148 { 1149 aDebugThisPos = pCell->aPos; 1150 if (aDebugVec.empty()) 1151 { 1152 ByteString aR( "root_"); 1153 aR += ByteString::CreateFromInt32( ++nDebugRootCount); 1154 aDebugVec.push_back( aR); 1155 } 1156 String aStr; 1157 pCell->aPos.Format( aStr, SCA_VALID | SCA_TAB_3D, pCell->GetDocument(), 1158 pCell->GetDocument()->GetAddressConvention() ); 1159 ByteString aB( aStr, RTL_TEXTENCODING_UTF8); 1160 aDebugVec.push_back( aB); 1161 } 1162 static void pop() 1163 { 1164 aDebugLastPos = aDebugThisPos; 1165 if (!aDebugVec.empty()) 1166 { 1167 aDebugVec.pop_back(); 1168 if (aDebugVec.size() == 1) 1169 { 1170 aDebugVec.pop_back(); 1171 aDebugLastPos = ScAddress( ScAddress::INITIALIZE_INVALID); 1172 } 1173 } 1174 } 1175 DebugElement( ScFormulaCell* p ) { push(p); } 1176 ~DebugElement() { pop(); } 1177 }; 1178 class DebugDot 1179 { 1180 public: 1181 static void out( const char* pColor ) 1182 { 1183 if (nDebug != erDEBUGDOTRUN) 1184 return; 1185 char pColorString[256]; 1186 sprintf( pColorString, (*pColor ? 1187 ",color=\"%s\",fontcolor=\"%s\"" : "%s%s"), pColor, 1188 pColor); 1189 size_t n = aDebugVec.size(); 1190 fprintf( pDebugFile, 1191 "\"%s\" -> \"%s\" [label=\"%u\"%s]; // v:%d\n", 1192 aDebugVec[n-2].GetBuffer(), aDebugVec[n-1].GetBuffer(), 1193 ++nDebugPathCount, pColorString, n-1); 1194 fflush( pDebugFile); 1195 } 1196 }; 1197 #define erDEBUGDOT_OUT( p ) (DebugDot::out(p)) 1198 #define erDEBUGDOT_ELEMENT_PUSH( p ) (DebugElement::push(p)) 1199 #define erDEBUGDOT_ELEMENT_POP() (DebugElement::pop()) 1200 #else 1201 #define erDEBUGDOT_OUT( p ) 1202 #define erDEBUGDOT_ELEMENT_PUSH( p ) 1203 #define erDEBUGDOT_ELEMENT_POP() 1204 #endif 1205 1206 if (!IsDirtyOrInTableOpDirty() || pDocument->GetRecursionHelper().IsInReturn()) 1207 return; // no double/triple processing 1208 1209 //! HACK: 1210 // Wenn der Aufruf aus einem Reschedule im DdeLink-Update kommt, dirty stehenlassen 1211 // Besser: Dde-Link Update ohne Reschedule oder ganz asynchron !!! 1212 1213 if ( pDocument->IsInDdeLinkUpdate() ) 1214 return; 1215 1216 #if erDEBUGDOT 1217 // set nDebug=1 in debugger to init things 1218 if (nDebug == 1) 1219 { 1220 ++nDebug; 1221 pDebugFile = fopen( aDebugDotFile, "a"); 1222 if (!pDebugFile) 1223 nDebug = 0; 1224 else 1225 nDebug = erDEBUGDOTRUN; 1226 } 1227 // set nDebug=3 (erDEBUGDOTRUN) in debugger to get any output 1228 DebugElement aDebugElem( this); 1229 // set nDebug=5 in debugger to close output 1230 if (nDebug == 5) 1231 { 1232 nDebug = 0; 1233 fclose( pDebugFile); 1234 pDebugFile = 0; 1235 } 1236 #endif 1237 1238 if (bRunning) 1239 { 1240 1241 #if erDEBUGDOT 1242 if (!pDocument->GetRecursionHelper().IsDoingIteration() || 1243 aDebugThisPos != aDebugLastPos) 1244 erDEBUGDOT_OUT(aDebugThisPos == aDebugLastPos ? "orange" : 1245 (pDocument->GetRecursionHelper().GetIteration() ? "blue" : 1246 "red")); 1247 #endif 1248 1249 if (!pDocument->GetDocOptions().IsIter()) 1250 { 1251 aResult.SetResultError( errCircularReference ); 1252 return; 1253 } 1254 1255 if (aResult.GetResultError() == errCircularReference) 1256 aResult.SetResultError( 0 ); 1257 1258 // Start or add to iteration list. 1259 if (!pDocument->GetRecursionHelper().IsDoingIteration() || 1260 !pDocument->GetRecursionHelper().GetRecursionInIterationStack().top()->bIsIterCell) 1261 pDocument->GetRecursionHelper().SetInIterationReturn( true); 1262 1263 return; 1264 } 1265 // #63038# no multiple interprets for GetErrCode, IsValue, GetValue and 1266 // different entry point recursions. Would also lead to premature 1267 // convergence in iterations. 1268 if (pDocument->GetRecursionHelper().GetIteration() && nSeenInIteration == 1269 pDocument->GetRecursionHelper().GetIteration()) 1270 return ; 1271 1272 erDEBUGDOT_OUT( pDocument->GetRecursionHelper().GetIteration() ? "magenta" : ""); 1273 1274 ScRecursionHelper& rRecursionHelper = pDocument->GetRecursionHelper(); 1275 sal_Bool bOldRunning = bRunning; 1276 if (rRecursionHelper.GetRecursionCount() > MAXRECURSION) 1277 { 1278 bRunning = sal_True; 1279 rRecursionHelper.SetInRecursionReturn( true); 1280 } 1281 else 1282 { 1283 InterpretTail( SCITP_NORMAL); 1284 } 1285 1286 // While leaving a recursion or iteration stack, insert its cells to the 1287 // recursion list in reverse order. 1288 if (rRecursionHelper.IsInReturn()) 1289 { 1290 if (rRecursionHelper.GetRecursionCount() > 0 || 1291 !rRecursionHelper.IsDoingRecursion()) 1292 rRecursionHelper.Insert( this, bOldRunning, aResult); 1293 bool bIterationFromRecursion = false; 1294 bool bResumeIteration = false; 1295 do 1296 { 1297 if ((rRecursionHelper.IsInIterationReturn() && 1298 rRecursionHelper.GetRecursionCount() == 0 && 1299 !rRecursionHelper.IsDoingIteration()) || 1300 bIterationFromRecursion || bResumeIteration) 1301 { 1302 ScFormulaCell* pIterCell = this; // scope for debug convenience 1303 bool & rDone = rRecursionHelper.GetConvergingReference(); 1304 rDone = false; 1305 if (!bIterationFromRecursion && bResumeIteration) 1306 { 1307 bResumeIteration = false; 1308 // Resuming iteration expands the range. 1309 ScFormulaRecursionList::const_iterator aOldStart( 1310 rRecursionHelper.GetLastIterationStart()); 1311 rRecursionHelper.ResumeIteration(); 1312 // Mark new cells being in iteration. 1313 for (ScFormulaRecursionList::const_iterator aIter( 1314 rRecursionHelper.GetIterationStart()); aIter != 1315 aOldStart; ++aIter) 1316 { 1317 pIterCell = (*aIter).pCell; 1318 pIterCell->bIsIterCell = sal_True; 1319 } 1320 // Mark older cells dirty again, in case they converted 1321 // without accounting for all remaining cells in the circle 1322 // that weren't touched so far, e.g. conditional. Restore 1323 // backuped result. 1324 sal_uInt16 nIteration = rRecursionHelper.GetIteration(); 1325 for (ScFormulaRecursionList::const_iterator aIter( 1326 aOldStart); aIter != 1327 rRecursionHelper.GetIterationEnd(); ++aIter) 1328 { 1329 pIterCell = (*aIter).pCell; 1330 if (pIterCell->nSeenInIteration == nIteration) 1331 { 1332 if (!pIterCell->bDirty || aIter == aOldStart) 1333 { 1334 pIterCell->aResult = (*aIter).aPreviousResult; 1335 } 1336 --pIterCell->nSeenInIteration; 1337 } 1338 pIterCell->bDirty = sal_True; 1339 } 1340 } 1341 else 1342 { 1343 bResumeIteration = false; 1344 // Close circle once. 1345 rRecursionHelper.GetList().back().pCell->InterpretTail( 1346 SCITP_CLOSE_ITERATION_CIRCLE); 1347 // Start at 1, init things. 1348 rRecursionHelper.StartIteration(); 1349 // Mark all cells being in iteration. 1350 for (ScFormulaRecursionList::const_iterator aIter( 1351 rRecursionHelper.GetIterationStart()); aIter != 1352 rRecursionHelper.GetIterationEnd(); ++aIter) 1353 { 1354 pIterCell = (*aIter).pCell; 1355 pIterCell->bIsIterCell = sal_True; 1356 } 1357 } 1358 bIterationFromRecursion = false; 1359 sal_uInt16 nIterMax = pDocument->GetDocOptions().GetIterCount(); 1360 for ( ; rRecursionHelper.GetIteration() <= nIterMax && !rDone; 1361 rRecursionHelper.IncIteration()) 1362 { 1363 rDone = true; 1364 for ( ScFormulaRecursionList::iterator aIter( 1365 rRecursionHelper.GetIterationStart()); aIter != 1366 rRecursionHelper.GetIterationEnd() && 1367 !rRecursionHelper.IsInReturn(); ++aIter) 1368 { 1369 pIterCell = (*aIter).pCell; 1370 if (pIterCell->IsDirtyOrInTableOpDirty() && 1371 rRecursionHelper.GetIteration() != 1372 pIterCell->GetSeenInIteration()) 1373 { 1374 (*aIter).aPreviousResult = pIterCell->aResult; 1375 pIterCell->InterpretTail( SCITP_FROM_ITERATION); 1376 } 1377 rDone = rDone && !pIterCell->IsDirtyOrInTableOpDirty(); 1378 } 1379 if (rRecursionHelper.IsInReturn()) 1380 { 1381 bResumeIteration = true; 1382 break; // for 1383 // Don't increment iteration. 1384 } 1385 } 1386 if (!bResumeIteration) 1387 { 1388 if (rDone) 1389 { 1390 for (ScFormulaRecursionList::const_iterator aIter( 1391 rRecursionHelper.GetIterationStart()); 1392 aIter != rRecursionHelper.GetIterationEnd(); 1393 ++aIter) 1394 { 1395 pIterCell = (*aIter).pCell; 1396 pIterCell->bIsIterCell = sal_False; 1397 pIterCell->nSeenInIteration = 0; 1398 pIterCell->bRunning = (*aIter).bOldRunning; 1399 } 1400 } 1401 else 1402 { 1403 for (ScFormulaRecursionList::const_iterator aIter( 1404 rRecursionHelper.GetIterationStart()); 1405 aIter != rRecursionHelper.GetIterationEnd(); 1406 ++aIter) 1407 { 1408 pIterCell = (*aIter).pCell; 1409 pIterCell->bIsIterCell = sal_False; 1410 pIterCell->nSeenInIteration = 0; 1411 pIterCell->bRunning = (*aIter).bOldRunning; 1412 // If one cell didn't converge, all cells of this 1413 // circular dependency don't, no matter whether 1414 // single cells did. 1415 pIterCell->bDirty = sal_False; 1416 pIterCell->bTableOpDirty = sal_False; 1417 pIterCell->aResult.SetResultError( errNoConvergence); 1418 pIterCell->bChanged = sal_True; 1419 pIterCell->SetTextWidth( TEXTWIDTH_DIRTY); 1420 pIterCell->SetScriptType( SC_SCRIPTTYPE_UNKNOWN); 1421 } 1422 } 1423 // End this iteration and remove entries. 1424 rRecursionHelper.EndIteration(); 1425 bResumeIteration = rRecursionHelper.IsDoingIteration(); 1426 } 1427 } 1428 if (rRecursionHelper.IsInRecursionReturn() && 1429 rRecursionHelper.GetRecursionCount() == 0 && 1430 !rRecursionHelper.IsDoingRecursion()) 1431 { 1432 bIterationFromRecursion = false; 1433 // Iterate over cells known so far, start with the last cell 1434 // encountered, inserting new cells if another recursion limit 1435 // is reached. Repeat until solved. 1436 rRecursionHelper.SetDoingRecursion( true); 1437 do 1438 { 1439 rRecursionHelper.SetInRecursionReturn( false); 1440 for (ScFormulaRecursionList::const_iterator aIter( 1441 rRecursionHelper.GetStart()); 1442 !rRecursionHelper.IsInReturn() && aIter != 1443 rRecursionHelper.GetEnd(); ++aIter) 1444 { 1445 ScFormulaCell* pCell = (*aIter).pCell; 1446 if (pCell->IsDirtyOrInTableOpDirty()) 1447 { 1448 pCell->InterpretTail( SCITP_NORMAL); 1449 if (!pCell->IsDirtyOrInTableOpDirty() && !pCell->IsIterCell()) 1450 pCell->bRunning = (*aIter).bOldRunning; 1451 } 1452 } 1453 } while (rRecursionHelper.IsInRecursionReturn()); 1454 rRecursionHelper.SetDoingRecursion( false); 1455 if (rRecursionHelper.IsInIterationReturn()) 1456 { 1457 if (!bResumeIteration) 1458 bIterationFromRecursion = true; 1459 } 1460 else if (bResumeIteration || 1461 rRecursionHelper.IsDoingIteration()) 1462 rRecursionHelper.GetList().erase( 1463 rRecursionHelper.GetStart(), 1464 rRecursionHelper.GetLastIterationStart()); 1465 else 1466 rRecursionHelper.Clear(); 1467 } 1468 } while (bIterationFromRecursion || bResumeIteration); 1469 } 1470 } 1471 1472 void ScFormulaCell::InterpretTail( ScInterpretTailParameter eTailParam ) 1473 { 1474 class RecursionCounter 1475 { 1476 ScRecursionHelper& rRec; 1477 bool bStackedInIteration; 1478 public: 1479 RecursionCounter( ScRecursionHelper& r, ScFormulaCell* p ) : rRec(r) 1480 { 1481 bStackedInIteration = rRec.IsDoingIteration(); 1482 if (bStackedInIteration) 1483 rRec.GetRecursionInIterationStack().push( p); 1484 rRec.IncRecursionCount(); 1485 } 1486 ~RecursionCounter() 1487 { 1488 rRec.DecRecursionCount(); 1489 if (bStackedInIteration) 1490 rRec.GetRecursionInIterationStack().pop(); 1491 } 1492 } aRecursionCounter( pDocument->GetRecursionHelper(), this); 1493 nSeenInIteration = pDocument->GetRecursionHelper().GetIteration(); 1494 if( !pCode->GetCodeLen() && !pCode->GetCodeError() ) 1495 { 1496 // #i11719# no UPN and no error and no token code but result string present 1497 // => interpretation of this cell during name-compilation and unknown names 1498 // => can't exchange underlying code array in CompileTokenArray() / 1499 // Compile() because interpreter's token iterator would crash. 1500 // This should only be a temporary condition and, since we set an 1501 // error, if ran into it again we'd bump into the dirty-clearing 1502 // condition further down. 1503 if ( !pCode->GetLen() && aResult.GetHybridFormula().Len() ) 1504 { 1505 pCode->SetCodeError( errNoCode ); 1506 // This is worth an assertion; if encountered in daily work 1507 // documents we might need another solution. Or just confirm correctness. 1508 DBG_ERRORFILE( "ScFormulaCell::Interpret: no UPN, no error, no token, but string" ); 1509 return; 1510 } 1511 CompileTokenArray(); 1512 } 1513 1514 if( pCode->GetCodeLen() && pDocument ) 1515 { 1516 class StackCleaner 1517 { 1518 ScDocument* pDoc; 1519 ScInterpreter* pInt; 1520 public: 1521 StackCleaner( ScDocument* pD, ScInterpreter* pI ) 1522 : pDoc(pD), pInt(pI) 1523 {} 1524 ~StackCleaner() 1525 { 1526 delete pInt; 1527 pDoc->DecInterpretLevel(); 1528 } 1529 }; 1530 pDocument->IncInterpretLevel(); 1531 ScInterpreter* p = new ScInterpreter( this, pDocument, aPos, *pCode ); 1532 StackCleaner aStackCleaner( pDocument, p); 1533 sal_uInt16 nOldErrCode = aResult.GetResultError(); 1534 if ( nSeenInIteration == 0 ) 1535 { // Only the first time 1536 // With bChanged=sal_False, if a newly compiled cell has a result of 1537 // 0.0, no change is detected and the cell will not be repainted. 1538 // bChanged = sal_False; 1539 aResult.SetResultError( 0 ); 1540 } 1541 1542 switch ( aResult.GetResultError() ) 1543 { 1544 case errCircularReference : // will be determined again if so 1545 aResult.SetResultError( 0 ); 1546 break; 1547 } 1548 1549 sal_Bool bOldRunning = bRunning; 1550 bRunning = sal_True; 1551 p->Interpret(); 1552 if (pDocument->GetRecursionHelper().IsInReturn() && eTailParam != SCITP_CLOSE_ITERATION_CIRCLE) 1553 { 1554 if (nSeenInIteration > 0) 1555 --nSeenInIteration; // retry when iteration is resumed 1556 return; 1557 } 1558 bRunning = bOldRunning; 1559 1560 // #i102616# For single-sheet saving consider only content changes, not format type, 1561 // because format type isn't set on loading (might be changed later) 1562 sal_Bool bContentChanged = sal_False; 1563 1564 // Do not create a HyperLink() cell if the formula results in an error. 1565 if( p->GetError() && pCode->IsHyperLink()) 1566 pCode->SetHyperLink(sal_False); 1567 1568 if( p->GetError() && p->GetError() != errCircularReference) 1569 { 1570 bDirty = sal_False; 1571 bTableOpDirty = sal_False; 1572 bChanged = sal_True; 1573 } 1574 if (eTailParam == SCITP_FROM_ITERATION && IsDirtyOrInTableOpDirty()) 1575 { 1576 bool bIsValue = aResult.IsValue(); // the previous type 1577 // Did it converge? 1578 if ((bIsValue && p->GetResultType() == svDouble && fabs( 1579 p->GetNumResult() - aResult.GetDouble()) <= 1580 pDocument->GetDocOptions().GetIterEps()) || 1581 (!bIsValue && p->GetResultType() == svString && 1582 p->GetStringResult() == aResult.GetString())) 1583 { 1584 // A convergence in the first iteration doesn't necessarily 1585 // mean that it's done, it may be because not all related cells 1586 // of a circle changed their values yet. If the set really 1587 // converges it will do so also during the next iteration. This 1588 // fixes situations like of #i44115#. If this wasn't wanted an 1589 // initial "uncalculated" value would be needed for all cells 1590 // of a circular dependency => graph needed before calculation. 1591 if (nSeenInIteration > 1 || 1592 pDocument->GetDocOptions().GetIterCount() == 1) 1593 { 1594 bDirty = sal_False; 1595 bTableOpDirty = sal_False; 1596 } 1597 } 1598 } 1599 1600 // New error code? 1601 if( p->GetError() != nOldErrCode ) 1602 { 1603 bChanged = sal_True; 1604 // bContentChanged only has to be set if the file content would be changed 1605 if ( aResult.GetCellResultType() != svUnknown ) 1606 bContentChanged = sal_True; 1607 } 1608 // Different number format? 1609 if( nFormatType != p->GetRetFormatType() ) 1610 { 1611 nFormatType = p->GetRetFormatType(); 1612 bChanged = sal_True; 1613 } 1614 if( nFormatIndex != p->GetRetFormatIndex() ) 1615 { 1616 nFormatIndex = p->GetRetFormatIndex(); 1617 bChanged = sal_True; 1618 } 1619 1620 // In case of changes just obtain the result, no temporary and 1621 // comparison needed anymore. 1622 if (bChanged) 1623 { 1624 // #i102616# Compare anyway if the sheet is still marked unchanged for single-sheet saving 1625 // Also handle special cases of initial results after loading. 1626 1627 if ( !bContentChanged && pDocument->IsStreamValid(aPos.Tab()) ) 1628 { 1629 ScFormulaResult aNewResult( p->GetResultToken()); 1630 StackVar eOld = aResult.GetCellResultType(); 1631 StackVar eNew = aNewResult.GetCellResultType(); 1632 if ( eOld == svUnknown && ( eNew == svError || ( eNew == svDouble && aNewResult.GetDouble() == 0.0 ) ) ) 1633 { 1634 // ScXMLTableRowCellContext::EndElement doesn't call SetFormulaResultDouble for 0 1635 // -> no change 1636 } 1637 else 1638 { 1639 if ( eOld == svHybridCell ) // string result from SetFormulaResultString? 1640 eOld = svString; // ScHybridCellToken has a valid GetString method 1641 1642 // #i106045# use approxEqual to compare with stored value 1643 bContentChanged = (eOld != eNew || 1644 (eNew == svDouble && !rtl::math::approxEqual( aResult.GetDouble(), aNewResult.GetDouble() )) || 1645 (eNew == svString && aResult.GetString() != aNewResult.GetString())); 1646 } 1647 } 1648 1649 aResult.SetToken( p->GetResultToken() ); 1650 } 1651 else 1652 { 1653 ScFormulaResult aNewResult( p->GetResultToken()); 1654 StackVar eOld = aResult.GetCellResultType(); 1655 StackVar eNew = aNewResult.GetCellResultType(); 1656 bChanged = (eOld != eNew || 1657 (eNew == svDouble && aResult.GetDouble() != aNewResult.GetDouble()) || 1658 (eNew == svString && aResult.GetString() != aNewResult.GetString())); 1659 1660 // #i102616# handle special cases of initial results after loading (only if the sheet is still marked unchanged) 1661 if ( bChanged && !bContentChanged && pDocument->IsStreamValid(aPos.Tab()) ) 1662 { 1663 if ( ( eOld == svUnknown && ( eNew == svError || ( eNew == svDouble && aNewResult.GetDouble() == 0.0 ) ) ) || 1664 ( eOld == svHybridCell && eNew == svString && aResult.GetString() == aNewResult.GetString() ) || 1665 ( eOld == svDouble && eNew == svDouble && rtl::math::approxEqual( aResult.GetDouble(), aNewResult.GetDouble() ) ) ) 1666 { 1667 // no change, see above 1668 } 1669 else 1670 bContentChanged = sal_True; 1671 } 1672 1673 aResult.Assign( aNewResult); 1674 } 1675 1676 // Precision as shown? 1677 if ( aResult.IsValue() && !p->GetError() 1678 && pDocument->GetDocOptions().IsCalcAsShown() 1679 && nFormatType != NUMBERFORMAT_DATE 1680 && nFormatType != NUMBERFORMAT_TIME 1681 && nFormatType != NUMBERFORMAT_DATETIME ) 1682 { 1683 sal_uLong nFormat = pDocument->GetNumberFormat( aPos ); 1684 if ( nFormatIndex && (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 ) 1685 nFormat = nFormatIndex; 1686 if ( (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 ) 1687 nFormat = ScGlobal::GetStandardFormat( 1688 *pDocument->GetFormatTable(), nFormat, nFormatType ); 1689 aResult.SetDouble( pDocument->RoundValueAsShown( 1690 aResult.GetDouble(), nFormat)); 1691 } 1692 if (eTailParam == SCITP_NORMAL) 1693 { 1694 bDirty = sal_False; 1695 bTableOpDirty = sal_False; 1696 } 1697 if( aResult.GetMatrix().Is() ) 1698 { 1699 // If the formula wasn't entered as a matrix formula, live on with 1700 // the upper left corner and let reference counting delete the matrix. 1701 if( cMatrixFlag != MM_FORMULA && !pCode->IsHyperLink() ) 1702 aResult.SetToken( aResult.GetCellResultToken()); 1703 } 1704 if ( aResult.IsValue() && !::rtl::math::isFinite( aResult.GetDouble() ) ) 1705 { 1706 // Coded double error may occur via filter import. 1707 sal_uInt16 nErr = GetDoubleErrorValue( aResult.GetDouble()); 1708 aResult.SetResultError( nErr); 1709 bChanged = bContentChanged = true; 1710 } 1711 if( bChanged ) 1712 { 1713 SetTextWidth( TEXTWIDTH_DIRTY ); 1714 SetScriptType( SC_SCRIPTTYPE_UNKNOWN ); 1715 } 1716 if (bContentChanged && pDocument->IsStreamValid(aPos.Tab())) 1717 { 1718 // pass bIgnoreLock=sal_True, because even if called from pending row height update, 1719 // a changed result must still reset the stream flag 1720 pDocument->SetStreamValid(aPos.Tab(), sal_False, sal_True); 1721 } 1722 if ( !pCode->IsRecalcModeAlways() ) 1723 pDocument->RemoveFromFormulaTree( this ); 1724 1725 // FORCED Zellen auch sofort auf Gueltigkeit testen (evtl. Makro starten) 1726 1727 if ( pCode->IsRecalcModeForced() ) 1728 { 1729 sal_uLong nValidation = ((const SfxUInt32Item*) pDocument->GetAttr( 1730 aPos.Col(), aPos.Row(), aPos.Tab(), ATTR_VALIDDATA ))->GetValue(); 1731 if ( nValidation ) 1732 { 1733 const ScValidationData* pData = pDocument->GetValidationEntry( nValidation ); 1734 if ( pData && !pData->IsDataValid( this, aPos ) ) 1735 pData->DoCalcError( this ); 1736 } 1737 } 1738 1739 // Reschedule verlangsamt das ganze erheblich, nur bei Prozentaenderung ausfuehren 1740 ScProgress::GetInterpretProgress()->SetStateCountDownOnPercent( 1741 pDocument->GetFormulaCodeInTree()/MIN_NO_CODES_PER_PROGRESS_UPDATE ); 1742 } 1743 else 1744 { 1745 // Zelle bei Compiler-Fehlern nicht ewig auf dirty stehenlassen 1746 DBG_ASSERT( pCode->GetCodeError(), "kein UPN-Code und kein Fehler ?!?!" ); 1747 bDirty = sal_False; 1748 bTableOpDirty = sal_False; 1749 } 1750 } 1751 1752 1753 void ScFormulaCell::SetMatColsRows( SCCOL nCols, SCROW nRows ) 1754 { 1755 ScMatrixFormulaCellToken* pMat = aResult.GetMatrixFormulaCellTokenNonConst(); 1756 if (pMat) 1757 pMat->SetMatColsRows( nCols, nRows); 1758 else if (nCols || nRows) 1759 aResult.SetToken( new ScMatrixFormulaCellToken( nCols, nRows)); 1760 } 1761 1762 1763 void ScFormulaCell::GetMatColsRows( SCCOL & nCols, SCROW & nRows ) const 1764 { 1765 const ScMatrixFormulaCellToken* pMat = aResult.GetMatrixFormulaCellToken(); 1766 if (pMat) 1767 pMat->GetMatColsRows( nCols, nRows); 1768 else 1769 { 1770 nCols = 0; 1771 nRows = 0; 1772 } 1773 } 1774 1775 1776 sal_uLong ScFormulaCell::GetStandardFormat( SvNumberFormatter& rFormatter, sal_uLong nFormat ) const 1777 { 1778 if ( nFormatIndex && (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 ) 1779 return nFormatIndex; 1780 //! not ScFormulaCell::IsValue(), that could reinterpret the formula again. 1781 if ( aResult.IsValue() ) 1782 return ScGlobal::GetStandardFormat( aResult.GetDouble(), rFormatter, nFormat, nFormatType ); 1783 else 1784 return ScGlobal::GetStandardFormat( rFormatter, nFormat, nFormatType ); 1785 } 1786 1787 1788 void __EXPORT ScFormulaCell::Notify( SvtBroadcaster&, const SfxHint& rHint) 1789 { 1790 if ( !pDocument->IsInDtorClear() && !pDocument->GetHardRecalcState() ) 1791 { 1792 const ScHint* p = PTR_CAST( ScHint, &rHint ); 1793 sal_uLong nHint = (p ? p->GetId() : 0); 1794 if (nHint & (SC_HINT_DATACHANGED | SC_HINT_DYING | SC_HINT_TABLEOPDIRTY)) 1795 { 1796 sal_Bool bForceTrack = sal_False; 1797 if ( nHint & SC_HINT_TABLEOPDIRTY ) 1798 { 1799 bForceTrack = !bTableOpDirty; 1800 if ( !bTableOpDirty ) 1801 { 1802 pDocument->AddTableOpFormulaCell( this ); 1803 bTableOpDirty = sal_True; 1804 } 1805 } 1806 else 1807 { 1808 bForceTrack = !bDirty; 1809 bDirty = sal_True; 1810 } 1811 // #35962# Don't remove from FormulaTree to put in FormulaTrack to 1812 // put in FormulaTree again and again, only if necessary. 1813 // Any other means except RECALCMODE_ALWAYS by which a cell could 1814 // be in FormulaTree if it would notify other cells through 1815 // FormulaTrack which weren't in FormulaTrack/FormulaTree before?!? 1816 // #87866# Yes. The new TableOpDirty made it necessary to have a 1817 // forced mode where formulas may still be in FormulaTree from 1818 // TableOpDirty but have to notify dependents for normal dirty. 1819 if ( (bForceTrack || !pDocument->IsInFormulaTree( this ) 1820 || pCode->IsRecalcModeAlways()) 1821 && !pDocument->IsInFormulaTrack( this ) ) 1822 pDocument->AppendToFormulaTrack( this ); 1823 } 1824 } 1825 } 1826 1827 void ScFormulaCell::SetDirty() 1828 { 1829 if ( !IsInChangeTrack() ) 1830 { 1831 if ( pDocument->GetHardRecalcState() ) 1832 bDirty = sal_True; 1833 else 1834 { 1835 // Mehrfach-FormulaTracking in Load und in CompileAll 1836 // nach CopyScenario und CopyBlockFromClip vermeiden. 1837 // Wenn unbedingtes FormulaTracking noetig, vor SetDirty bDirty=sal_False 1838 // setzen, z.B. in CompileTokenArray 1839 if ( !bDirty || !pDocument->IsInFormulaTree( this ) ) 1840 { 1841 bDirty = sal_True; 1842 pDocument->AppendToFormulaTrack( this ); 1843 pDocument->TrackFormulas(); 1844 } 1845 } 1846 1847 if (pDocument->IsStreamValid(aPos.Tab())) 1848 pDocument->SetStreamValid(aPos.Tab(), sal_False); 1849 } 1850 } 1851 1852 void ScFormulaCell::SetDirtyAfterLoad() 1853 { 1854 bDirty = sal_True; 1855 if ( !pDocument->GetHardRecalcState() ) 1856 pDocument->PutInFormulaTree( this ); 1857 } 1858 1859 void ScFormulaCell::SetTableOpDirty() 1860 { 1861 if ( !IsInChangeTrack() ) 1862 { 1863 if ( pDocument->GetHardRecalcState() ) 1864 bTableOpDirty = sal_True; 1865 else 1866 { 1867 if ( !bTableOpDirty || !pDocument->IsInFormulaTree( this ) ) 1868 { 1869 if ( !bTableOpDirty ) 1870 { 1871 pDocument->AddTableOpFormulaCell( this ); 1872 bTableOpDirty = sal_True; 1873 } 1874 pDocument->AppendToFormulaTrack( this ); 1875 pDocument->TrackFormulas( SC_HINT_TABLEOPDIRTY ); 1876 } 1877 } 1878 } 1879 } 1880 1881 1882 sal_Bool ScFormulaCell::IsDirtyOrInTableOpDirty() const 1883 { 1884 return bDirty || (bTableOpDirty && pDocument->IsInInterpreterTableOp()); 1885 } 1886 1887 1888 void ScFormulaCell::SetErrCode( sal_uInt16 n ) 1889 { 1890 /* FIXME: check the numerous places where ScTokenArray::GetCodeError() is 1891 * used whether it is solely for transport of a simple result error and get 1892 * rid of that abuse. */ 1893 pCode->SetCodeError( n ); 1894 // Hard set errors are transported as result type value per convention, 1895 // e.g. via clipboard. ScFormulaResult::IsValue() and 1896 // ScFormulaResult::GetDouble() handle that. 1897 aResult.SetResultError( n ); 1898 } 1899 1900 void ScFormulaCell::AddRecalcMode( ScRecalcMode nBits ) 1901 { 1902 if ( (nBits & RECALCMODE_EMASK) != RECALCMODE_NORMAL ) 1903 bDirty = sal_True; 1904 if ( nBits & RECALCMODE_ONLOAD_ONCE ) 1905 { // OnLoadOnce nur zum Dirty setzen nach Filter-Import 1906 nBits = (nBits & ~RECALCMODE_EMASK) | RECALCMODE_NORMAL; 1907 } 1908 pCode->AddRecalcMode( nBits ); 1909 } 1910 1911 // Dynamically create the URLField on a mouse-over action on a hyperlink() cell. 1912 void ScFormulaCell::GetURLResult( String& rURL, String& rCellText ) 1913 { 1914 String aCellString; 1915 1916 Color* pColor; 1917 1918 // Cell Text uses the Cell format while the URL uses 1919 // the default format for the type. 1920 sal_uLong nCellFormat = pDocument->GetNumberFormat( aPos ); 1921 SvNumberFormatter* pFormatter = pDocument->GetFormatTable(); 1922 1923 if ( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 ) 1924 nCellFormat = GetStandardFormat( *pFormatter,nCellFormat ); 1925 1926 sal_uLong nURLFormat = ScGlobal::GetStandardFormat( *pFormatter,nCellFormat, NUMBERFORMAT_NUMBER); 1927 1928 if ( IsValue() ) 1929 { 1930 double fValue = GetValue(); 1931 pFormatter->GetOutputString( fValue, nCellFormat, rCellText, &pColor ); 1932 } 1933 else 1934 { 1935 GetString( aCellString ); 1936 pFormatter->GetOutputString( aCellString, nCellFormat, rCellText, &pColor ); 1937 } 1938 ScConstMatrixRef xMat( aResult.GetMatrix()); 1939 if (xMat) 1940 { 1941 ScMatValType nMatValType; 1942 // determine if the matrix result is a string or value. 1943 const ScMatrixValue* pMatVal = xMat->Get(0, 1, nMatValType); 1944 if (pMatVal) 1945 { 1946 if (!ScMatrix::IsValueType( nMatValType)) 1947 rURL = pMatVal->GetString(); 1948 else 1949 pFormatter->GetOutputString( pMatVal->fVal, nURLFormat, rURL, &pColor ); 1950 } 1951 } 1952 1953 if(!rURL.Len()) 1954 { 1955 if(IsValue()) 1956 pFormatter->GetOutputString( GetValue(), nURLFormat, rURL, &pColor ); 1957 else 1958 pFormatter->GetOutputString( aCellString, nURLFormat, rURL, &pColor ); 1959 } 1960 } 1961 1962 bool ScFormulaCell::IsMultilineResult() 1963 { 1964 if (!IsValue()) 1965 return aResult.IsMultiline(); 1966 return false; 1967 } 1968 1969 EditTextObject* ScFormulaCell::CreateURLObject() 1970 { 1971 String aCellText; 1972 String aURL; 1973 GetURLResult( aURL, aCellText ); 1974 1975 SvxURLField aUrlField( aURL, aCellText, SVXURLFORMAT_APPDEFAULT); 1976 EditEngine& rEE = pDocument->GetEditEngine(); 1977 rEE.SetText( EMPTY_STRING ); 1978 rEE.QuickInsertField( SvxFieldItem( aUrlField, EE_FEATURE_FIELD ), ESelection( 0xFFFF, 0xFFFF ) ); 1979 1980 return rEE.CreateTextObject(); 1981 } 1982 1983 // ============================================================================ 1984 1985 ScDetectiveRefIter::ScDetectiveRefIter( ScFormulaCell* pCell ) 1986 { 1987 pCode = pCell->GetCode(); 1988 pCode->Reset(); 1989 aPos = pCell->aPos; 1990 } 1991 1992 sal_Bool lcl_ScDetectiveRefIter_SkipRef( ScToken* p ) 1993 { 1994 ScSingleRefData& rRef1 = p->GetSingleRef(); 1995 if ( rRef1.IsColDeleted() || rRef1.IsRowDeleted() || rRef1.IsTabDeleted() 1996 || !rRef1.Valid() ) 1997 return sal_True; 1998 if ( p->GetType() == svDoubleRef ) 1999 { 2000 ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2; 2001 if ( rRef2.IsColDeleted() || rRef2.IsRowDeleted() || rRef2.IsTabDeleted() 2002 || !rRef2.Valid() ) 2003 return sal_True; 2004 } 2005 return sal_False; 2006 } 2007 2008 sal_Bool ScDetectiveRefIter::GetNextRef( ScRange& rRange ) 2009 { 2010 sal_Bool bRet = sal_False; 2011 2012 ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN()); 2013 if (p) 2014 p->CalcAbsIfRel( aPos ); 2015 2016 while ( p && lcl_ScDetectiveRefIter_SkipRef( p ) ) 2017 { 2018 p = static_cast<ScToken*>(pCode->GetNextReferenceRPN()); 2019 if (p) 2020 p->CalcAbsIfRel( aPos ); 2021 } 2022 2023 if( p ) 2024 { 2025 SingleDoubleRefProvider aProv( *p ); 2026 rRange.aStart.Set( aProv.Ref1.nCol, aProv.Ref1.nRow, aProv.Ref1.nTab ); 2027 rRange.aEnd.Set( aProv.Ref2.nCol, aProv.Ref2.nRow, aProv.Ref2.nTab ); 2028 bRet = sal_True; 2029 } 2030 2031 return bRet; 2032 } 2033 2034 // ============================================================================ 2035