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->Clone(); 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 if ( pDocument->IsClipOrUndo() ) return; 916 sal_Bool bWasInFormulaTree = pDocument->IsInFormulaTree( this ); 917 if ( bWasInFormulaTree ) 918 pDocument->RemoveFromFormulaTree( this ); 919 // pCode darf fuer Abfragen noch nicht geloescht, muss aber leer sein 920 if ( pCode ) 921 pCode->Clear(); 922 ScTokenArray* pCodeOld = pCode; 923 ScCompiler aComp( pDocument, aPos); 924 aComp.SetGrammar(eGrammar); 925 pCode = aComp.CompileString( rFormula ); 926 if ( pCodeOld ) 927 delete pCodeOld; 928 if( !pCode->GetCodeError() ) 929 { 930 if ( !pCode->GetLen() && aResult.GetHybridFormula().Len() && rFormula == aResult.GetHybridFormula() ) 931 { // #65994# nicht rekursiv CompileTokenArray/Compile/CompileTokenArray 932 if ( rFormula.GetChar(0) == '=' ) 933 pCode->AddBad( rFormula.GetBuffer() + 1 ); 934 else 935 pCode->AddBad( rFormula.GetBuffer() ); 936 } 937 bCompile = sal_True; 938 CompileTokenArray( bNoListening ); 939 } 940 else 941 { 942 bChanged = sal_True; 943 SetTextWidth( TEXTWIDTH_DIRTY ); 944 SetScriptType( SC_SCRIPTTYPE_UNKNOWN ); 945 } 946 if ( bWasInFormulaTree ) 947 pDocument->PutInFormulaTree( this ); 948 } 949 950 951 void ScFormulaCell::CompileTokenArray( sal_Bool bNoListening ) 952 { 953 // Not already compiled? 954 if( !pCode->GetLen() && aResult.GetHybridFormula().Len() ) 955 Compile( aResult.GetHybridFormula(), bNoListening, eTempGrammar); 956 else if( bCompile && !pDocument->IsClipOrUndo() && !pCode->GetCodeError() ) 957 { 958 // RPN length may get changed 959 sal_Bool bWasInFormulaTree = pDocument->IsInFormulaTree( this ); 960 if ( bWasInFormulaTree ) 961 pDocument->RemoveFromFormulaTree( this ); 962 963 // Loading from within filter? No listening yet! 964 if( pDocument->IsInsertingFromOtherDoc() ) 965 bNoListening = sal_True; 966 967 if( !bNoListening && pCode->GetCodeLen() ) 968 EndListeningTo( pDocument ); 969 ScCompiler aComp(pDocument, aPos, *pCode); 970 aComp.SetGrammar(pDocument->GetGrammar()); 971 bSubTotal = aComp.CompileTokenArray(); 972 if( !pCode->GetCodeError() ) 973 { 974 nFormatType = aComp.GetNumFormatType(); 975 nFormatIndex = 0; 976 bChanged = sal_True; 977 aResult.SetToken( NULL); 978 bCompile = sal_False; 979 if ( !bNoListening ) 980 StartListeningTo( pDocument ); 981 } 982 if ( bWasInFormulaTree ) 983 pDocument->PutInFormulaTree( this ); 984 } 985 } 986 987 988 void ScFormulaCell::CompileXML( ScProgress& rProgress ) 989 { 990 if ( cMatrixFlag == MM_REFERENCE ) 991 { // is already token code via ScDocFunc::EnterMatrix, ScDocument::InsertMatrixFormula 992 // just establish listeners 993 StartListeningTo( pDocument ); 994 return ; 995 } 996 997 ScCompiler aComp( pDocument, aPos, *pCode); 998 aComp.SetGrammar(eTempGrammar); 999 String aFormula, aFormulaNmsp; 1000 aComp.CreateStringFromXMLTokenArray( aFormula, aFormulaNmsp ); 1001 pDocument->DecXMLImportedFormulaCount( aFormula.Len() ); 1002 rProgress.SetStateCountDownOnPercent( pDocument->GetXMLImportedFormulaCount() ); 1003 // pCode darf fuer Abfragen noch nicht geloescht, muss aber leer sein 1004 if ( pCode ) 1005 pCode->Clear(); 1006 ScTokenArray* pCodeOld = pCode; 1007 pCode = aComp.CompileString( aFormula, aFormulaNmsp ); 1008 delete pCodeOld; 1009 if( !pCode->GetCodeError() ) 1010 { 1011 if ( !pCode->GetLen() ) 1012 { 1013 if ( aFormula.GetChar(0) == '=' ) 1014 pCode->AddBad( aFormula.GetBuffer() + 1 ); 1015 else 1016 pCode->AddBad( aFormula.GetBuffer() ); 1017 } 1018 bSubTotal = aComp.CompileTokenArray(); 1019 if( !pCode->GetCodeError() ) 1020 { 1021 nFormatType = aComp.GetNumFormatType(); 1022 nFormatIndex = 0; 1023 bChanged = sal_True; 1024 bCompile = sal_False; 1025 StartListeningTo( pDocument ); 1026 } 1027 } 1028 else 1029 { 1030 bChanged = sal_True; 1031 SetTextWidth( TEXTWIDTH_DIRTY ); 1032 SetScriptType( SC_SCRIPTTYPE_UNKNOWN ); 1033 } 1034 1035 // Same as in Load: after loading, it must be known if ocMacro is in any formula 1036 // (for macro warning, CompileXML is called at the end of loading XML file) 1037 if ( !pDocument->GetHasMacroFunc() && pCode->HasOpCodeRPN( ocMacro ) ) 1038 pDocument->SetHasMacroFunc( sal_True ); 1039 } 1040 1041 1042 void ScFormulaCell::CalcAfterLoad() 1043 { 1044 sal_Bool bNewCompiled = sal_False; 1045 // Falls ein Calc 1.0-Doc eingelesen wird, haben wir ein Ergebnis, 1046 // aber kein TokenArray 1047 if( !pCode->GetLen() && aResult.GetHybridFormula().Len() ) 1048 { 1049 Compile( aResult.GetHybridFormula(), sal_True, eTempGrammar); 1050 aResult.SetToken( NULL); 1051 bDirty = sal_True; 1052 bNewCompiled = sal_True; 1053 } 1054 // Das UPN-Array wird nicht erzeugt, wenn ein Calc 3.0-Doc eingelesen 1055 // wurde, da die RangeNames erst jetzt existieren. 1056 if( pCode->GetLen() && !pCode->GetCodeLen() && !pCode->GetCodeError() ) 1057 { 1058 ScCompiler aComp(pDocument, aPos, *pCode); 1059 aComp.SetGrammar(pDocument->GetGrammar()); 1060 bSubTotal = aComp.CompileTokenArray(); 1061 nFormatType = aComp.GetNumFormatType(); 1062 nFormatIndex = 0; 1063 bDirty = sal_True; 1064 bCompile = sal_False; 1065 bNewCompiled = sal_True; 1066 } 1067 // irgendwie koennen unter os/2 mit rotter FPU-Exception /0 ohne Err503 1068 // gespeichert werden, woraufhin spaeter im NumberFormatter die BLC Lib 1069 // bei einem fabs(-NAN) abstuerzt (#32739#) 1070 // hier fuer alle Systeme ausbuegeln, damit da auch Err503 steht 1071 if ( aResult.IsValue() && !::rtl::math::isFinite( aResult.GetDouble() ) ) 1072 { 1073 DBG_ERRORFILE("Formelzelle INFINITY !!! Woher kommt das Dokument?"); 1074 aResult.SetResultError( errIllegalFPOperation ); 1075 bDirty = sal_True; 1076 } 1077 // DoubleRefs bei binaeren Operatoren waren vor v5.0 immer Matrix, 1078 // jetzt nur noch wenn in Matrixformel, sonst implizite Schnittmenge 1079 if ( pDocument->GetSrcVersion() < SC_MATRIX_DOUBLEREF && 1080 GetMatrixFlag() == MM_NONE && pCode->HasMatrixDoubleRefOps() ) 1081 { 1082 cMatrixFlag = MM_FORMULA; 1083 SetMatColsRows( 1, 1); 1084 } 1085 // Muss die Zelle berechnet werden? 1086 // Nach Load koennen Zellen einen Fehlercode enthalten, auch dann 1087 // Listener starten und ggbf. neu berechnen wenn nicht RECALCMODE_NORMAL 1088 if( !bNewCompiled || !pCode->GetCodeError() ) 1089 { 1090 StartListeningTo( pDocument ); 1091 if( !pCode->IsRecalcModeNormal() ) 1092 bDirty = sal_True; 1093 } 1094 if ( pCode->IsRecalcModeAlways() ) 1095 { // zufall(), heute(), jetzt() bleiben immer im FormulaTree, damit sie 1096 // auch bei jedem F9 berechnet werden. 1097 bDirty = sal_True; 1098 } 1099 // Noch kein SetDirty weil noch nicht alle Listener bekannt, erst in 1100 // SetDirtyAfterLoad. 1101 } 1102 1103 1104 bool ScFormulaCell::MarkUsedExternalReferences() 1105 { 1106 return pCode && pDocument->MarkUsedExternalReferences( *pCode); 1107 } 1108 1109 1110 // FIXME: set to 0 1111 #define erDEBUGDOT 0 1112 // If set to 1, write output that's suitable for graphviz tools like dot. 1113 // Only node1 -> node2 entries are written, you'll have to manually surround 1114 // the file content with [strict] digraph name { ... } 1115 // The ``strict'' keyword might be necessary in case of multiple identical 1116 // paths like they occur in iterations, otherwise dot may consume too much 1117 // memory when generating the layout, or you'll get unreadable output. On the 1118 // other hand, information about recurring calculation is lost then. 1119 // Generates output only if variable nDebug is set in debugger, see below. 1120 // FIXME: currently doesn't cope with iterations and recursions. Code fragments 1121 // are a leftover from a previous debug session, meant as a pointer. 1122 #if erDEBUGDOT 1123 #include <cstdio> 1124 using ::std::fopen; 1125 using ::std::fprintf; 1126 #include <vector> 1127 static const char aDebugDotFile[] = "ttt_debug.dot"; 1128 #endif 1129 1130 void ScFormulaCell::Interpret() 1131 { 1132 1133 #if erDEBUGDOT 1134 static int nDebug = 0; 1135 static const int erDEBUGDOTRUN = 3; 1136 static FILE* pDebugFile = 0; 1137 static sal_Int32 nDebugRootCount = 0; 1138 static unsigned int nDebugPathCount = 0; 1139 static ScAddress aDebugLastPos( ScAddress::INITIALIZE_INVALID); 1140 static ScAddress aDebugThisPos( ScAddress::INITIALIZE_INVALID); 1141 typedef ::std::vector< ByteString > DebugVector; 1142 static DebugVector aDebugVec; 1143 class DebugElement 1144 { 1145 public: 1146 static void push( ScFormulaCell* pCell ) 1147 { 1148 aDebugThisPos = pCell->aPos; 1149 if (aDebugVec.empty()) 1150 { 1151 ByteString aR( "root_"); 1152 aR += ByteString::CreateFromInt32( ++nDebugRootCount); 1153 aDebugVec.push_back( aR); 1154 } 1155 String aStr; 1156 pCell->aPos.Format( aStr, SCA_VALID | SCA_TAB_3D, pCell->GetDocument(), 1157 pCell->GetDocument()->GetAddressConvention() ); 1158 ByteString aB( aStr, RTL_TEXTENCODING_UTF8); 1159 aDebugVec.push_back( aB); 1160 } 1161 static void pop() 1162 { 1163 aDebugLastPos = aDebugThisPos; 1164 if (!aDebugVec.empty()) 1165 { 1166 aDebugVec.pop_back(); 1167 if (aDebugVec.size() == 1) 1168 { 1169 aDebugVec.pop_back(); 1170 aDebugLastPos = ScAddress( ScAddress::INITIALIZE_INVALID); 1171 } 1172 } 1173 } 1174 DebugElement( ScFormulaCell* p ) { push(p); } 1175 ~DebugElement() { pop(); } 1176 }; 1177 class DebugDot 1178 { 1179 public: 1180 static void out( const char* pColor ) 1181 { 1182 if (nDebug != erDEBUGDOTRUN) 1183 return; 1184 char pColorString[256]; 1185 sprintf( pColorString, (*pColor ? 1186 ",color=\"%s\",fontcolor=\"%s\"" : "%s%s"), pColor, 1187 pColor); 1188 size_t n = aDebugVec.size(); 1189 fprintf( pDebugFile, 1190 "\"%s\" -> \"%s\" [label=\"%u\"%s]; // v:%d\n", 1191 aDebugVec[n-2].GetBuffer(), aDebugVec[n-1].GetBuffer(), 1192 ++nDebugPathCount, pColorString, n-1); 1193 fflush( pDebugFile); 1194 } 1195 }; 1196 #define erDEBUGDOT_OUT( p ) (DebugDot::out(p)) 1197 #define erDEBUGDOT_ELEMENT_PUSH( p ) (DebugElement::push(p)) 1198 #define erDEBUGDOT_ELEMENT_POP() (DebugElement::pop()) 1199 #else 1200 #define erDEBUGDOT_OUT( p ) 1201 #define erDEBUGDOT_ELEMENT_PUSH( p ) 1202 #define erDEBUGDOT_ELEMENT_POP() 1203 #endif 1204 1205 if (!IsDirtyOrInTableOpDirty() || pDocument->GetRecursionHelper().IsInReturn()) 1206 return; // no double/triple processing 1207 1208 //! HACK: 1209 // Wenn der Aufruf aus einem Reschedule im DdeLink-Update kommt, dirty stehenlassen 1210 // Besser: Dde-Link Update ohne Reschedule oder ganz asynchron !!! 1211 1212 if ( pDocument->IsInDdeLinkUpdate() ) 1213 return; 1214 1215 #if erDEBUGDOT 1216 // set nDebug=1 in debugger to init things 1217 if (nDebug == 1) 1218 { 1219 ++nDebug; 1220 pDebugFile = fopen( aDebugDotFile, "a"); 1221 if (!pDebugFile) 1222 nDebug = 0; 1223 else 1224 nDebug = erDEBUGDOTRUN; 1225 } 1226 // set nDebug=3 (erDEBUGDOTRUN) in debugger to get any output 1227 DebugElement aDebugElem( this); 1228 // set nDebug=5 in debugger to close output 1229 if (nDebug == 5) 1230 { 1231 nDebug = 0; 1232 fclose( pDebugFile); 1233 pDebugFile = 0; 1234 } 1235 #endif 1236 1237 if (bRunning) 1238 { 1239 1240 #if erDEBUGDOT 1241 if (!pDocument->GetRecursionHelper().IsDoingIteration() || 1242 aDebugThisPos != aDebugLastPos) 1243 erDEBUGDOT_OUT(aDebugThisPos == aDebugLastPos ? "orange" : 1244 (pDocument->GetRecursionHelper().GetIteration() ? "blue" : 1245 "red")); 1246 #endif 1247 1248 if (!pDocument->GetDocOptions().IsIter()) 1249 { 1250 aResult.SetResultError( errCircularReference ); 1251 return; 1252 } 1253 1254 if (aResult.GetResultError() == errCircularReference) 1255 aResult.SetResultError( 0 ); 1256 1257 // Start or add to iteration list. 1258 if (!pDocument->GetRecursionHelper().IsDoingIteration() || 1259 !pDocument->GetRecursionHelper().GetRecursionInIterationStack().top()->bIsIterCell) 1260 pDocument->GetRecursionHelper().SetInIterationReturn( true); 1261 1262 return; 1263 } 1264 // #63038# no multiple interprets for GetErrCode, IsValue, GetValue and 1265 // different entry point recursions. Would also lead to premature 1266 // convergence in iterations. 1267 if (pDocument->GetRecursionHelper().GetIteration() && nSeenInIteration == 1268 pDocument->GetRecursionHelper().GetIteration()) 1269 return ; 1270 1271 erDEBUGDOT_OUT( pDocument->GetRecursionHelper().GetIteration() ? "magenta" : ""); 1272 1273 ScRecursionHelper& rRecursionHelper = pDocument->GetRecursionHelper(); 1274 sal_Bool bOldRunning = bRunning; 1275 if (rRecursionHelper.GetRecursionCount() > MAXRECURSION) 1276 { 1277 bRunning = sal_True; 1278 rRecursionHelper.SetInRecursionReturn( true); 1279 } 1280 else 1281 { 1282 InterpretTail( SCITP_NORMAL); 1283 } 1284 1285 // While leaving a recursion or iteration stack, insert its cells to the 1286 // recursion list in reverse order. 1287 if (rRecursionHelper.IsInReturn()) 1288 { 1289 if (rRecursionHelper.GetRecursionCount() > 0 || 1290 !rRecursionHelper.IsDoingRecursion()) 1291 rRecursionHelper.Insert( this, bOldRunning, aResult); 1292 bool bIterationFromRecursion = false; 1293 bool bResumeIteration = false; 1294 do 1295 { 1296 if ((rRecursionHelper.IsInIterationReturn() && 1297 rRecursionHelper.GetRecursionCount() == 0 && 1298 !rRecursionHelper.IsDoingIteration()) || 1299 bIterationFromRecursion || bResumeIteration) 1300 { 1301 ScFormulaCell* pIterCell = this; // scope for debug convenience 1302 bool & rDone = rRecursionHelper.GetConvergingReference(); 1303 rDone = false; 1304 if (!bIterationFromRecursion && bResumeIteration) 1305 { 1306 bResumeIteration = false; 1307 // Resuming iteration expands the range. 1308 ScFormulaRecursionList::const_iterator aOldStart( 1309 rRecursionHelper.GetLastIterationStart()); 1310 rRecursionHelper.ResumeIteration(); 1311 // Mark new cells being in iteration. 1312 for (ScFormulaRecursionList::const_iterator aIter( 1313 rRecursionHelper.GetIterationStart()); aIter != 1314 aOldStart; ++aIter) 1315 { 1316 pIterCell = (*aIter).pCell; 1317 pIterCell->bIsIterCell = sal_True; 1318 } 1319 // Mark older cells dirty again, in case they converted 1320 // without accounting for all remaining cells in the circle 1321 // that weren't touched so far, e.g. conditional. Restore 1322 // backuped result. 1323 sal_uInt16 nIteration = rRecursionHelper.GetIteration(); 1324 for (ScFormulaRecursionList::const_iterator aIter( 1325 aOldStart); aIter != 1326 rRecursionHelper.GetIterationEnd(); ++aIter) 1327 { 1328 pIterCell = (*aIter).pCell; 1329 if (pIterCell->nSeenInIteration == nIteration) 1330 { 1331 if (!pIterCell->bDirty || aIter == aOldStart) 1332 { 1333 pIterCell->aResult = (*aIter).aPreviousResult; 1334 } 1335 --pIterCell->nSeenInIteration; 1336 } 1337 pIterCell->bDirty = sal_True; 1338 } 1339 } 1340 else 1341 { 1342 bResumeIteration = false; 1343 // Close circle once. 1344 rRecursionHelper.GetList().back().pCell->InterpretTail( 1345 SCITP_CLOSE_ITERATION_CIRCLE); 1346 // Start at 1, init things. 1347 rRecursionHelper.StartIteration(); 1348 // Mark all cells being in iteration. 1349 for (ScFormulaRecursionList::const_iterator aIter( 1350 rRecursionHelper.GetIterationStart()); aIter != 1351 rRecursionHelper.GetIterationEnd(); ++aIter) 1352 { 1353 pIterCell = (*aIter).pCell; 1354 pIterCell->bIsIterCell = sal_True; 1355 } 1356 } 1357 bIterationFromRecursion = false; 1358 sal_uInt16 nIterMax = pDocument->GetDocOptions().GetIterCount(); 1359 for ( ; rRecursionHelper.GetIteration() <= nIterMax && !rDone; 1360 rRecursionHelper.IncIteration()) 1361 { 1362 rDone = true; 1363 for ( ScFormulaRecursionList::iterator aIter( 1364 rRecursionHelper.GetIterationStart()); aIter != 1365 rRecursionHelper.GetIterationEnd() && 1366 !rRecursionHelper.IsInReturn(); ++aIter) 1367 { 1368 pIterCell = (*aIter).pCell; 1369 if (pIterCell->IsDirtyOrInTableOpDirty() && 1370 rRecursionHelper.GetIteration() != 1371 pIterCell->GetSeenInIteration()) 1372 { 1373 (*aIter).aPreviousResult = pIterCell->aResult; 1374 pIterCell->InterpretTail( SCITP_FROM_ITERATION); 1375 } 1376 rDone = rDone && !pIterCell->IsDirtyOrInTableOpDirty(); 1377 } 1378 if (rRecursionHelper.IsInReturn()) 1379 { 1380 bResumeIteration = true; 1381 break; // for 1382 // Don't increment iteration. 1383 } 1384 } 1385 if (!bResumeIteration) 1386 { 1387 if (rDone) 1388 { 1389 for (ScFormulaRecursionList::const_iterator aIter( 1390 rRecursionHelper.GetIterationStart()); 1391 aIter != rRecursionHelper.GetIterationEnd(); 1392 ++aIter) 1393 { 1394 pIterCell = (*aIter).pCell; 1395 pIterCell->bIsIterCell = sal_False; 1396 pIterCell->nSeenInIteration = 0; 1397 pIterCell->bRunning = (*aIter).bOldRunning; 1398 } 1399 } 1400 else 1401 { 1402 for (ScFormulaRecursionList::const_iterator aIter( 1403 rRecursionHelper.GetIterationStart()); 1404 aIter != rRecursionHelper.GetIterationEnd(); 1405 ++aIter) 1406 { 1407 pIterCell = (*aIter).pCell; 1408 pIterCell->bIsIterCell = sal_False; 1409 pIterCell->nSeenInIteration = 0; 1410 pIterCell->bRunning = (*aIter).bOldRunning; 1411 // If one cell didn't converge, all cells of this 1412 // circular dependency don't, no matter whether 1413 // single cells did. 1414 pIterCell->bDirty = sal_False; 1415 pIterCell->bTableOpDirty = sal_False; 1416 pIterCell->aResult.SetResultError( errNoConvergence); 1417 pIterCell->bChanged = sal_True; 1418 pIterCell->SetTextWidth( TEXTWIDTH_DIRTY); 1419 pIterCell->SetScriptType( SC_SCRIPTTYPE_UNKNOWN); 1420 } 1421 } 1422 // End this iteration and remove entries. 1423 rRecursionHelper.EndIteration(); 1424 bResumeIteration = rRecursionHelper.IsDoingIteration(); 1425 } 1426 } 1427 if (rRecursionHelper.IsInRecursionReturn() && 1428 rRecursionHelper.GetRecursionCount() == 0 && 1429 !rRecursionHelper.IsDoingRecursion()) 1430 { 1431 bIterationFromRecursion = false; 1432 // Iterate over cells known so far, start with the last cell 1433 // encountered, inserting new cells if another recursion limit 1434 // is reached. Repeat until solved. 1435 rRecursionHelper.SetDoingRecursion( true); 1436 do 1437 { 1438 rRecursionHelper.SetInRecursionReturn( false); 1439 for (ScFormulaRecursionList::const_iterator aIter( 1440 rRecursionHelper.GetStart()); 1441 !rRecursionHelper.IsInReturn() && aIter != 1442 rRecursionHelper.GetEnd(); ++aIter) 1443 { 1444 ScFormulaCell* pCell = (*aIter).pCell; 1445 if (pCell->IsDirtyOrInTableOpDirty()) 1446 { 1447 pCell->InterpretTail( SCITP_NORMAL); 1448 if (!pCell->IsDirtyOrInTableOpDirty() && !pCell->IsIterCell()) 1449 pCell->bRunning = (*aIter).bOldRunning; 1450 } 1451 } 1452 } while (rRecursionHelper.IsInRecursionReturn()); 1453 rRecursionHelper.SetDoingRecursion( false); 1454 if (rRecursionHelper.IsInIterationReturn()) 1455 { 1456 if (!bResumeIteration) 1457 bIterationFromRecursion = true; 1458 } 1459 else if (bResumeIteration || 1460 rRecursionHelper.IsDoingIteration()) 1461 rRecursionHelper.GetList().erase( 1462 rRecursionHelper.GetStart(), 1463 rRecursionHelper.GetLastIterationStart()); 1464 else 1465 rRecursionHelper.Clear(); 1466 } 1467 } while (bIterationFromRecursion || bResumeIteration); 1468 } 1469 } 1470 1471 void ScFormulaCell::InterpretTail( ScInterpretTailParameter eTailParam ) 1472 { 1473 class RecursionCounter 1474 { 1475 ScRecursionHelper& rRec; 1476 bool bStackedInIteration; 1477 public: 1478 RecursionCounter( ScRecursionHelper& r, ScFormulaCell* p ) : rRec(r) 1479 { 1480 bStackedInIteration = rRec.IsDoingIteration(); 1481 if (bStackedInIteration) 1482 rRec.GetRecursionInIterationStack().push( p); 1483 rRec.IncRecursionCount(); 1484 } 1485 ~RecursionCounter() 1486 { 1487 rRec.DecRecursionCount(); 1488 if (bStackedInIteration) 1489 rRec.GetRecursionInIterationStack().pop(); 1490 } 1491 } aRecursionCounter( pDocument->GetRecursionHelper(), this); 1492 nSeenInIteration = pDocument->GetRecursionHelper().GetIteration(); 1493 if( !pCode->GetCodeLen() && !pCode->GetCodeError() ) 1494 { 1495 // #i11719# no UPN and no error and no token code but result string present 1496 // => interpretation of this cell during name-compilation and unknown names 1497 // => can't exchange underlying code array in CompileTokenArray() / 1498 // Compile() because interpreter's token iterator would crash. 1499 // This should only be a temporary condition and, since we set an 1500 // error, if ran into it again we'd bump into the dirty-clearing 1501 // condition further down. 1502 if ( !pCode->GetLen() && aResult.GetHybridFormula().Len() ) 1503 { 1504 pCode->SetCodeError( errNoCode ); 1505 // This is worth an assertion; if encountered in daily work 1506 // documents we might need another solution. Or just confirm correctness. 1507 DBG_ERRORFILE( "ScFormulaCell::Interpret: no UPN, no error, no token, but string" ); 1508 return; 1509 } 1510 CompileTokenArray(); 1511 } 1512 1513 if( pCode->GetCodeLen() && pDocument ) 1514 { 1515 class StackCleaner 1516 { 1517 ScDocument* pDoc; 1518 ScInterpreter* pInt; 1519 public: 1520 StackCleaner( ScDocument* pD, ScInterpreter* pI ) 1521 : pDoc(pD), pInt(pI) 1522 {} 1523 ~StackCleaner() 1524 { 1525 delete pInt; 1526 pDoc->DecInterpretLevel(); 1527 } 1528 }; 1529 pDocument->IncInterpretLevel(); 1530 ScInterpreter* p = new ScInterpreter( this, pDocument, aPos, *pCode ); 1531 StackCleaner aStackCleaner( pDocument, p); 1532 sal_uInt16 nOldErrCode = aResult.GetResultError(); 1533 if ( nSeenInIteration == 0 ) 1534 { // Only the first time 1535 // With bChanged=sal_False, if a newly compiled cell has a result of 1536 // 0.0, no change is detected and the cell will not be repainted. 1537 // bChanged = sal_False; 1538 aResult.SetResultError( 0 ); 1539 } 1540 1541 switch ( aResult.GetResultError() ) 1542 { 1543 case errCircularReference : // will be determined again if so 1544 aResult.SetResultError( 0 ); 1545 break; 1546 } 1547 1548 sal_Bool bOldRunning = bRunning; 1549 bRunning = sal_True; 1550 p->Interpret(); 1551 if (pDocument->GetRecursionHelper().IsInReturn() && eTailParam != SCITP_CLOSE_ITERATION_CIRCLE) 1552 { 1553 if (nSeenInIteration > 0) 1554 --nSeenInIteration; // retry when iteration is resumed 1555 return; 1556 } 1557 bRunning = bOldRunning; 1558 1559 // #i102616# For single-sheet saving consider only content changes, not format type, 1560 // because format type isn't set on loading (might be changed later) 1561 sal_Bool bContentChanged = sal_False; 1562 1563 // Do not create a HyperLink() cell if the formula results in an error. 1564 if( p->GetError() && pCode->IsHyperLink()) 1565 pCode->SetHyperLink(sal_False); 1566 1567 if( p->GetError() && p->GetError() != errCircularReference) 1568 { 1569 bDirty = sal_False; 1570 bTableOpDirty = sal_False; 1571 bChanged = sal_True; 1572 } 1573 if (eTailParam == SCITP_FROM_ITERATION && IsDirtyOrInTableOpDirty()) 1574 { 1575 bool bIsValue = aResult.IsValue(); // the previous type 1576 // Did it converge? 1577 if ((bIsValue && p->GetResultType() == svDouble && fabs( 1578 p->GetNumResult() - aResult.GetDouble()) <= 1579 pDocument->GetDocOptions().GetIterEps()) || 1580 (!bIsValue && p->GetResultType() == svString && 1581 p->GetStringResult() == aResult.GetString())) 1582 { 1583 // A convergence in the first iteration doesn't necessarily 1584 // mean that it's done, it may be because not all related cells 1585 // of a circle changed their values yet. If the set really 1586 // converges it will do so also during the next iteration. This 1587 // fixes situations like of #i44115#. If this wasn't wanted an 1588 // initial "uncalculated" value would be needed for all cells 1589 // of a circular dependency => graph needed before calculation. 1590 if (nSeenInIteration > 1 || 1591 pDocument->GetDocOptions().GetIterCount() == 1) 1592 { 1593 bDirty = sal_False; 1594 bTableOpDirty = sal_False; 1595 } 1596 } 1597 } 1598 1599 // New error code? 1600 if( p->GetError() != nOldErrCode ) 1601 { 1602 bChanged = sal_True; 1603 // bContentChanged only has to be set if the file content would be changed 1604 if ( aResult.GetCellResultType() != svUnknown ) 1605 bContentChanged = sal_True; 1606 } 1607 // Different number format? 1608 if( nFormatType != p->GetRetFormatType() ) 1609 { 1610 nFormatType = p->GetRetFormatType(); 1611 bChanged = sal_True; 1612 } 1613 if( nFormatIndex != p->GetRetFormatIndex() ) 1614 { 1615 nFormatIndex = p->GetRetFormatIndex(); 1616 bChanged = sal_True; 1617 } 1618 1619 // In case of changes just obtain the result, no temporary and 1620 // comparison needed anymore. 1621 if (bChanged) 1622 { 1623 // #i102616# Compare anyway if the sheet is still marked unchanged for single-sheet saving 1624 // Also handle special cases of initial results after loading. 1625 1626 if ( !bContentChanged && pDocument->IsStreamValid(aPos.Tab()) ) 1627 { 1628 ScFormulaResult aNewResult( p->GetResultToken()); 1629 StackVar eOld = aResult.GetCellResultType(); 1630 StackVar eNew = aNewResult.GetCellResultType(); 1631 if ( eOld == svUnknown && ( eNew == svError || ( eNew == svDouble && aNewResult.GetDouble() == 0.0 ) ) ) 1632 { 1633 // ScXMLTableRowCellContext::EndElement doesn't call SetFormulaResultDouble for 0 1634 // -> no change 1635 } 1636 else 1637 { 1638 if ( eOld == svHybridCell ) // string result from SetFormulaResultString? 1639 eOld = svString; // ScHybridCellToken has a valid GetString method 1640 1641 // #i106045# use approxEqual to compare with stored value 1642 bContentChanged = (eOld != eNew || 1643 (eNew == svDouble && !rtl::math::approxEqual( aResult.GetDouble(), aNewResult.GetDouble() )) || 1644 (eNew == svString && aResult.GetString() != aNewResult.GetString())); 1645 } 1646 } 1647 1648 aResult.SetToken( p->GetResultToken() ); 1649 } 1650 else 1651 { 1652 ScFormulaResult aNewResult( p->GetResultToken()); 1653 StackVar eOld = aResult.GetCellResultType(); 1654 StackVar eNew = aNewResult.GetCellResultType(); 1655 bChanged = (eOld != eNew || 1656 (eNew == svDouble && aResult.GetDouble() != aNewResult.GetDouble()) || 1657 (eNew == svString && aResult.GetString() != aNewResult.GetString())); 1658 1659 // #i102616# handle special cases of initial results after loading (only if the sheet is still marked unchanged) 1660 if ( bChanged && !bContentChanged && pDocument->IsStreamValid(aPos.Tab()) ) 1661 { 1662 if ( ( eOld == svUnknown && ( eNew == svError || ( eNew == svDouble && aNewResult.GetDouble() == 0.0 ) ) ) || 1663 ( eOld == svHybridCell && eNew == svString && aResult.GetString() == aNewResult.GetString() ) || 1664 ( eOld == svDouble && eNew == svDouble && rtl::math::approxEqual( aResult.GetDouble(), aNewResult.GetDouble() ) ) ) 1665 { 1666 // no change, see above 1667 } 1668 else 1669 bContentChanged = sal_True; 1670 } 1671 1672 aResult.Assign( aNewResult); 1673 } 1674 1675 // Precision as shown? 1676 if ( aResult.IsValue() && !p->GetError() 1677 && pDocument->GetDocOptions().IsCalcAsShown() 1678 && nFormatType != NUMBERFORMAT_DATE 1679 && nFormatType != NUMBERFORMAT_TIME 1680 && nFormatType != NUMBERFORMAT_DATETIME ) 1681 { 1682 sal_uLong nFormat = pDocument->GetNumberFormat( aPos ); 1683 if ( nFormatIndex && (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 ) 1684 nFormat = nFormatIndex; 1685 if ( (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 ) 1686 nFormat = ScGlobal::GetStandardFormat( 1687 *pDocument->GetFormatTable(), nFormat, nFormatType ); 1688 aResult.SetDouble( pDocument->RoundValueAsShown( 1689 aResult.GetDouble(), nFormat)); 1690 } 1691 if (eTailParam == SCITP_NORMAL) 1692 { 1693 bDirty = sal_False; 1694 bTableOpDirty = sal_False; 1695 } 1696 if( aResult.GetMatrix().Is() ) 1697 { 1698 // If the formula wasn't entered as a matrix formula, live on with 1699 // the upper left corner and let reference counting delete the matrix. 1700 if( cMatrixFlag != MM_FORMULA && !pCode->IsHyperLink() ) 1701 aResult.SetToken( aResult.GetCellResultToken()); 1702 } 1703 if ( aResult.IsValue() && !::rtl::math::isFinite( aResult.GetDouble() ) ) 1704 { 1705 // Coded double error may occur via filter import. 1706 sal_uInt16 nErr = GetDoubleErrorValue( aResult.GetDouble()); 1707 aResult.SetResultError( nErr); 1708 bChanged = bContentChanged = true; 1709 } 1710 if( bChanged ) 1711 { 1712 SetTextWidth( TEXTWIDTH_DIRTY ); 1713 SetScriptType( SC_SCRIPTTYPE_UNKNOWN ); 1714 } 1715 if (bContentChanged && pDocument->IsStreamValid(aPos.Tab())) 1716 { 1717 // pass bIgnoreLock=sal_True, because even if called from pending row height update, 1718 // a changed result must still reset the stream flag 1719 pDocument->SetStreamValid(aPos.Tab(), sal_False, sal_True); 1720 } 1721 if ( !pCode->IsRecalcModeAlways() ) 1722 pDocument->RemoveFromFormulaTree( this ); 1723 1724 // FORCED Zellen auch sofort auf Gueltigkeit testen (evtl. Makro starten) 1725 1726 if ( pCode->IsRecalcModeForced() ) 1727 { 1728 sal_uLong nValidation = ((const SfxUInt32Item*) pDocument->GetAttr( 1729 aPos.Col(), aPos.Row(), aPos.Tab(), ATTR_VALIDDATA ))->GetValue(); 1730 if ( nValidation ) 1731 { 1732 const ScValidationData* pData = pDocument->GetValidationEntry( nValidation ); 1733 if ( pData && !pData->IsDataValid( this, aPos ) ) 1734 pData->DoCalcError( this ); 1735 } 1736 } 1737 1738 // Reschedule verlangsamt das ganze erheblich, nur bei Prozentaenderung ausfuehren 1739 ScProgress::GetInterpretProgress()->SetStateCountDownOnPercent( 1740 pDocument->GetFormulaCodeInTree()/MIN_NO_CODES_PER_PROGRESS_UPDATE ); 1741 } 1742 else 1743 { 1744 // Zelle bei Compiler-Fehlern nicht ewig auf dirty stehenlassen 1745 DBG_ASSERT( pCode->GetCodeError(), "kein UPN-Code und kein Fehler ?!?!" ); 1746 bDirty = sal_False; 1747 bTableOpDirty = sal_False; 1748 } 1749 } 1750 1751 1752 void ScFormulaCell::SetMatColsRows( SCCOL nCols, SCROW nRows ) 1753 { 1754 ScMatrixFormulaCellToken* pMat = aResult.GetMatrixFormulaCellTokenNonConst(); 1755 if (pMat) 1756 pMat->SetMatColsRows( nCols, nRows); 1757 else if (nCols || nRows) 1758 aResult.SetToken( new ScMatrixFormulaCellToken( nCols, nRows)); 1759 } 1760 1761 1762 void ScFormulaCell::GetMatColsRows( SCCOL & nCols, SCROW & nRows ) const 1763 { 1764 const ScMatrixFormulaCellToken* pMat = aResult.GetMatrixFormulaCellToken(); 1765 if (pMat) 1766 pMat->GetMatColsRows( nCols, nRows); 1767 else 1768 { 1769 nCols = 0; 1770 nRows = 0; 1771 } 1772 } 1773 1774 1775 sal_uLong ScFormulaCell::GetStandardFormat( SvNumberFormatter& rFormatter, sal_uLong nFormat ) const 1776 { 1777 if ( nFormatIndex && (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 ) 1778 return nFormatIndex; 1779 //! not ScFormulaCell::IsValue(), that could reinterpret the formula again. 1780 if ( aResult.IsValue() ) 1781 return ScGlobal::GetStandardFormat( aResult.GetDouble(), rFormatter, nFormat, nFormatType ); 1782 else 1783 return ScGlobal::GetStandardFormat( rFormatter, nFormat, nFormatType ); 1784 } 1785 1786 1787 void __EXPORT ScFormulaCell::Notify( SvtBroadcaster&, const SfxHint& rHint) 1788 { 1789 if ( !pDocument->IsInDtorClear() && !pDocument->GetHardRecalcState() ) 1790 { 1791 const ScHint* p = PTR_CAST( ScHint, &rHint ); 1792 sal_uLong nHint = (p ? p->GetId() : 0); 1793 if (nHint & (SC_HINT_DATACHANGED | SC_HINT_DYING | SC_HINT_TABLEOPDIRTY)) 1794 { 1795 sal_Bool bForceTrack = sal_False; 1796 if ( nHint & SC_HINT_TABLEOPDIRTY ) 1797 { 1798 bForceTrack = !bTableOpDirty; 1799 if ( !bTableOpDirty ) 1800 { 1801 pDocument->AddTableOpFormulaCell( this ); 1802 bTableOpDirty = sal_True; 1803 } 1804 } 1805 else 1806 { 1807 bForceTrack = !bDirty; 1808 bDirty = sal_True; 1809 } 1810 // #35962# Don't remove from FormulaTree to put in FormulaTrack to 1811 // put in FormulaTree again and again, only if necessary. 1812 // Any other means except RECALCMODE_ALWAYS by which a cell could 1813 // be in FormulaTree if it would notify other cells through 1814 // FormulaTrack which weren't in FormulaTrack/FormulaTree before?!? 1815 // #87866# Yes. The new TableOpDirty made it necessary to have a 1816 // forced mode where formulas may still be in FormulaTree from 1817 // TableOpDirty but have to notify dependents for normal dirty. 1818 if ( (bForceTrack || !pDocument->IsInFormulaTree( this ) 1819 || pCode->IsRecalcModeAlways()) 1820 && !pDocument->IsInFormulaTrack( this ) ) 1821 pDocument->AppendToFormulaTrack( this ); 1822 } 1823 } 1824 } 1825 1826 void ScFormulaCell::SetDirty() 1827 { 1828 if ( !IsInChangeTrack() ) 1829 { 1830 if ( pDocument->GetHardRecalcState() ) 1831 bDirty = sal_True; 1832 else 1833 { 1834 // Mehrfach-FormulaTracking in Load und in CompileAll 1835 // nach CopyScenario und CopyBlockFromClip vermeiden. 1836 // Wenn unbedingtes FormulaTracking noetig, vor SetDirty bDirty=sal_False 1837 // setzen, z.B. in CompileTokenArray 1838 if ( !bDirty || !pDocument->IsInFormulaTree( this ) ) 1839 { 1840 bDirty = sal_True; 1841 pDocument->AppendToFormulaTrack( this ); 1842 pDocument->TrackFormulas(); 1843 } 1844 } 1845 1846 if (pDocument->IsStreamValid(aPos.Tab())) 1847 pDocument->SetStreamValid(aPos.Tab(), sal_False); 1848 } 1849 } 1850 1851 void ScFormulaCell::SetDirtyAfterLoad() 1852 { 1853 bDirty = sal_True; 1854 if ( !pDocument->GetHardRecalcState() ) 1855 pDocument->PutInFormulaTree( this ); 1856 } 1857 1858 void ScFormulaCell::SetTableOpDirty() 1859 { 1860 if ( !IsInChangeTrack() ) 1861 { 1862 if ( pDocument->GetHardRecalcState() ) 1863 bTableOpDirty = sal_True; 1864 else 1865 { 1866 if ( !bTableOpDirty || !pDocument->IsInFormulaTree( this ) ) 1867 { 1868 if ( !bTableOpDirty ) 1869 { 1870 pDocument->AddTableOpFormulaCell( this ); 1871 bTableOpDirty = sal_True; 1872 } 1873 pDocument->AppendToFormulaTrack( this ); 1874 pDocument->TrackFormulas( SC_HINT_TABLEOPDIRTY ); 1875 } 1876 } 1877 } 1878 } 1879 1880 1881 sal_Bool ScFormulaCell::IsDirtyOrInTableOpDirty() const 1882 { 1883 return bDirty || (bTableOpDirty && pDocument->IsInInterpreterTableOp()); 1884 } 1885 1886 1887 void ScFormulaCell::SetErrCode( sal_uInt16 n ) 1888 { 1889 /* FIXME: check the numerous places where ScTokenArray::GetCodeError() is 1890 * used whether it is solely for transport of a simple result error and get 1891 * rid of that abuse. */ 1892 pCode->SetCodeError( n ); 1893 // Hard set errors are transported as result type value per convention, 1894 // e.g. via clipboard. ScFormulaResult::IsValue() and 1895 // ScFormulaResult::GetDouble() handle that. 1896 aResult.SetResultError( n ); 1897 } 1898 1899 void ScFormulaCell::AddRecalcMode( ScRecalcMode nBits ) 1900 { 1901 if ( (nBits & RECALCMODE_EMASK) != RECALCMODE_NORMAL ) 1902 bDirty = sal_True; 1903 if ( nBits & RECALCMODE_ONLOAD_ONCE ) 1904 { // OnLoadOnce nur zum Dirty setzen nach Filter-Import 1905 nBits = (nBits & ~RECALCMODE_EMASK) | RECALCMODE_NORMAL; 1906 } 1907 pCode->AddRecalcMode( nBits ); 1908 } 1909 1910 // Dynamically create the URLField on a mouse-over action on a hyperlink() cell. 1911 void ScFormulaCell::GetURLResult( String& rURL, String& rCellText ) 1912 { 1913 String aCellString; 1914 1915 Color* pColor; 1916 1917 // Cell Text uses the Cell format while the URL uses 1918 // the default format for the type. 1919 sal_uLong nCellFormat = pDocument->GetNumberFormat( aPos ); 1920 SvNumberFormatter* pFormatter = pDocument->GetFormatTable(); 1921 1922 if ( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 ) 1923 nCellFormat = GetStandardFormat( *pFormatter,nCellFormat ); 1924 1925 sal_uLong nURLFormat = ScGlobal::GetStandardFormat( *pFormatter,nCellFormat, NUMBERFORMAT_NUMBER); 1926 1927 if ( IsValue() ) 1928 { 1929 double fValue = GetValue(); 1930 pFormatter->GetOutputString( fValue, nCellFormat, rCellText, &pColor ); 1931 } 1932 else 1933 { 1934 GetString( aCellString ); 1935 pFormatter->GetOutputString( aCellString, nCellFormat, rCellText, &pColor ); 1936 } 1937 ScConstMatrixRef xMat( aResult.GetMatrix()); 1938 if (xMat) 1939 { 1940 ScMatValType nMatValType; 1941 // determine if the matrix result is a string or value. 1942 const ScMatrixValue* pMatVal = xMat->Get(0, 1, nMatValType); 1943 if (pMatVal) 1944 { 1945 if (!ScMatrix::IsValueType( nMatValType)) 1946 rURL = pMatVal->GetString(); 1947 else 1948 pFormatter->GetOutputString( pMatVal->fVal, nURLFormat, rURL, &pColor ); 1949 } 1950 } 1951 1952 if(!rURL.Len()) 1953 { 1954 if(IsValue()) 1955 pFormatter->GetOutputString( GetValue(), nURLFormat, rURL, &pColor ); 1956 else 1957 pFormatter->GetOutputString( aCellString, nURLFormat, rURL, &pColor ); 1958 } 1959 } 1960 1961 bool ScFormulaCell::IsMultilineResult() 1962 { 1963 if (!IsValue()) 1964 return aResult.IsMultiline(); 1965 return false; 1966 } 1967 1968 EditTextObject* ScFormulaCell::CreateURLObject() 1969 { 1970 String aCellText; 1971 String aURL; 1972 GetURLResult( aURL, aCellText ); 1973 1974 SvxURLField aUrlField( aURL, aCellText, SVXURLFORMAT_APPDEFAULT); 1975 EditEngine& rEE = pDocument->GetEditEngine(); 1976 rEE.SetText( EMPTY_STRING ); 1977 rEE.QuickInsertField( SvxFieldItem( aUrlField, EE_FEATURE_FIELD ), ESelection( 0xFFFF, 0xFFFF ) ); 1978 1979 return rEE.CreateTextObject(); 1980 } 1981 1982 // ============================================================================ 1983 1984 ScDetectiveRefIter::ScDetectiveRefIter( ScFormulaCell* pCell ) 1985 { 1986 pCode = pCell->GetCode(); 1987 pCode->Reset(); 1988 aPos = pCell->aPos; 1989 } 1990 1991 sal_Bool lcl_ScDetectiveRefIter_SkipRef( ScToken* p ) 1992 { 1993 ScSingleRefData& rRef1 = p->GetSingleRef(); 1994 if ( rRef1.IsColDeleted() || rRef1.IsRowDeleted() || rRef1.IsTabDeleted() 1995 || !rRef1.Valid() ) 1996 return sal_True; 1997 if ( p->GetType() == svDoubleRef ) 1998 { 1999 ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2; 2000 if ( rRef2.IsColDeleted() || rRef2.IsRowDeleted() || rRef2.IsTabDeleted() 2001 || !rRef2.Valid() ) 2002 return sal_True; 2003 } 2004 return sal_False; 2005 } 2006 2007 sal_Bool ScDetectiveRefIter::GetNextRef( ScRange& rRange ) 2008 { 2009 sal_Bool bRet = sal_False; 2010 2011 ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN()); 2012 if (p) 2013 p->CalcAbsIfRel( aPos ); 2014 2015 while ( p && lcl_ScDetectiveRefIter_SkipRef( p ) ) 2016 { 2017 p = static_cast<ScToken*>(pCode->GetNextReferenceRPN()); 2018 if (p) 2019 p->CalcAbsIfRel( aPos ); 2020 } 2021 2022 if( p ) 2023 { 2024 SingleDoubleRefProvider aProv( *p ); 2025 rRange.aStart.Set( aProv.Ref1.nCol, aProv.Ref1.nRow, aProv.Ref1.nTab ); 2026 rRange.aEnd.Set( aProv.Ref2.nCol, aProv.Ref2.nRow, aProv.Ref2.nTab ); 2027 bRet = sal_True; 2028 } 2029 2030 return bRet; 2031 } 2032 2033 // ============================================================================ 2034