1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sc.hxx" 30 31 32 33 //------------------------------------------------------------------ 34 35 #include "scitems.hxx" 36 #include <sfx2/objsh.hxx> 37 #include <svl/itemset.hxx> 38 #include <svl/zforlist.hxx> 39 #include <rtl/math.hxx> 40 #include <unotools/collatorwrapper.hxx> 41 42 #include "conditio.hxx" 43 #include "cell.hxx" 44 #include "document.hxx" 45 #include "hints.hxx" 46 #include "compiler.hxx" 47 #include "rechead.hxx" 48 #include "rangelst.hxx" 49 #include "stlpool.hxx" 50 #include "rangenam.hxx" 51 52 using namespace formula; 53 //------------------------------------------------------------------------ 54 55 SV_IMPL_OP_PTRARR_SORT( ScConditionalFormats_Impl, ScConditionalFormatPtr ); 56 57 //------------------------------------------------------------------------ 58 59 sal_Bool lcl_HasRelRef( ScDocument* pDoc, ScTokenArray* pFormula, sal_uInt16 nRecursion = 0 ) 60 { 61 if (pFormula) 62 { 63 pFormula->Reset(); 64 FormulaToken* t; 65 for( t = pFormula->Next(); t; t = pFormula->Next() ) 66 { 67 switch( t->GetType() ) 68 { 69 case svDoubleRef: 70 { 71 ScSingleRefData& rRef2 = static_cast<ScToken*>(t)->GetDoubleRef().Ref2; 72 if ( rRef2.IsColRel() || rRef2.IsRowRel() || rRef2.IsTabRel() ) 73 return sal_True; 74 } 75 // fall through 76 77 case svSingleRef: 78 { 79 ScSingleRefData& rRef1 = static_cast<ScToken*>(t)->GetSingleRef(); 80 if ( rRef1.IsColRel() || rRef1.IsRowRel() || rRef1.IsTabRel() ) 81 return sal_True; 82 } 83 break; 84 85 case svIndex: 86 { 87 if( t->GetOpCode() == ocName ) // DB areas always absolute 88 if( ScRangeData* pRangeData = pDoc->GetRangeName()->FindIndex( t->GetIndex() ) ) 89 if( (nRecursion < 42) && lcl_HasRelRef( pDoc, pRangeData->GetCode(), nRecursion + 1 ) ) 90 return sal_True; 91 } 92 break; 93 94 // #i34474# function result dependent on cell position 95 case svByte: 96 { 97 switch( t->GetOpCode() ) 98 { 99 case ocRow: // ROW() returns own row index 100 case ocColumn: // COLUMN() returns own column index 101 case ocTable: // SHEET() returns own sheet index 102 case ocCell: // CELL() may return own cell address 103 return sal_True; 104 // break; 105 default: 106 { 107 // added to avoid warnings 108 } 109 } 110 } 111 break; 112 113 default: 114 { 115 // added to avoid warnings 116 } 117 } 118 } 119 } 120 return sal_False; 121 } 122 123 ScConditionEntry::ScConditionEntry( const ScConditionEntry& r ) : 124 eOp(r.eOp), 125 nOptions(r.nOptions), 126 nVal1(r.nVal1), 127 nVal2(r.nVal2), 128 aStrVal1(r.aStrVal1), 129 aStrVal2(r.aStrVal2), 130 aStrNmsp1(r.aStrNmsp1), 131 aStrNmsp2(r.aStrNmsp2), 132 eTempGrammar1(r.eTempGrammar1), 133 eTempGrammar2(r.eTempGrammar2), 134 bIsStr1(r.bIsStr1), 135 bIsStr2(r.bIsStr2), 136 pFormula1(NULL), 137 pFormula2(NULL), 138 aSrcPos(r.aSrcPos), 139 aSrcString(r.aSrcString), 140 pFCell1(NULL), 141 pFCell2(NULL), 142 pDoc(r.pDoc), 143 bRelRef1(r.bRelRef1), 144 bRelRef2(r.bRelRef2), 145 bFirstRun(sal_True) 146 { 147 // ScTokenArray copy ctor erzeugt flache Kopie 148 149 if (r.pFormula1) 150 pFormula1 = new ScTokenArray( *r.pFormula1 ); 151 if (r.pFormula2) 152 pFormula2 = new ScTokenArray( *r.pFormula2 ); 153 154 // Formelzellen werden erst bei IsValid angelegt 155 } 156 157 ScConditionEntry::ScConditionEntry( ScDocument* pDocument, const ScConditionEntry& r ) : 158 eOp(r.eOp), 159 nOptions(r.nOptions), 160 nVal1(r.nVal1), 161 nVal2(r.nVal2), 162 aStrVal1(r.aStrVal1), 163 aStrVal2(r.aStrVal2), 164 aStrNmsp1(r.aStrNmsp1), 165 aStrNmsp2(r.aStrNmsp2), 166 eTempGrammar1(r.eTempGrammar1), 167 eTempGrammar2(r.eTempGrammar2), 168 bIsStr1(r.bIsStr1), 169 bIsStr2(r.bIsStr2), 170 pFormula1(NULL), 171 pFormula2(NULL), 172 aSrcPos(r.aSrcPos), 173 aSrcString(r.aSrcString), 174 pFCell1(NULL), 175 pFCell2(NULL), 176 pDoc(pDocument), 177 bRelRef1(r.bRelRef1), 178 bRelRef2(r.bRelRef2), 179 bFirstRun(sal_True) 180 { 181 // echte Kopie der Formeln (fuer Ref-Undo) 182 183 if (r.pFormula1) 184 pFormula1 = r.pFormula1->Clone(); 185 if (r.pFormula2) 186 pFormula2 = r.pFormula2->Clone(); 187 188 // Formelzellen werden erst bei IsValid angelegt 189 //! im Clipboard nicht - dann vorher interpretieren !!! 190 } 191 192 ScConditionEntry::ScConditionEntry( ScConditionMode eOper, 193 const String& rExpr1, const String& rExpr2, ScDocument* pDocument, const ScAddress& rPos, 194 const String& rExprNmsp1, const String& rExprNmsp2, 195 FormulaGrammar::Grammar eGrammar1, FormulaGrammar::Grammar eGrammar2 ) : 196 eOp(eOper), 197 nOptions(0), // spaeter... 198 nVal1(0.0), 199 nVal2(0.0), 200 aStrNmsp1(rExprNmsp1), 201 aStrNmsp2(rExprNmsp2), 202 eTempGrammar1(eGrammar1), 203 eTempGrammar2(eGrammar2), 204 bIsStr1(sal_False), 205 bIsStr2(sal_False), 206 pFormula1(NULL), 207 pFormula2(NULL), 208 aSrcPos(rPos), 209 pFCell1(NULL), 210 pFCell2(NULL), 211 pDoc(pDocument), 212 bRelRef1(sal_False), 213 bRelRef2(sal_False), 214 bFirstRun(sal_True) 215 { 216 Compile( rExpr1, rExpr2, rExprNmsp1, rExprNmsp2, eGrammar1, eGrammar2, sal_False ); 217 218 // Formelzellen werden erst bei IsValid angelegt 219 } 220 221 ScConditionEntry::ScConditionEntry( ScConditionMode eOper, 222 const ScTokenArray* pArr1, const ScTokenArray* pArr2, 223 ScDocument* pDocument, const ScAddress& rPos ) : 224 eOp(eOper), 225 nOptions(0), // spaeter... 226 nVal1(0.0), 227 nVal2(0.0), 228 eTempGrammar1(FormulaGrammar::GRAM_DEFAULT), 229 eTempGrammar2(FormulaGrammar::GRAM_DEFAULT), 230 bIsStr1(sal_False), 231 bIsStr2(sal_False), 232 pFormula1(NULL), 233 pFormula2(NULL), 234 aSrcPos(rPos), 235 pFCell1(NULL), 236 pFCell2(NULL), 237 pDoc(pDocument), 238 bRelRef1(sal_False), 239 bRelRef2(sal_False), 240 bFirstRun(sal_True) 241 { 242 if ( pArr1 ) 243 { 244 pFormula1 = new ScTokenArray( *pArr1 ); 245 if ( pFormula1->GetLen() == 1 ) 246 { 247 // einzelne (konstante Zahl) ? 248 FormulaToken* pToken = pFormula1->First(); 249 if ( pToken->GetOpCode() == ocPush ) 250 { 251 if ( pToken->GetType() == svDouble ) 252 { 253 nVal1 = pToken->GetDouble(); 254 DELETEZ(pFormula1); // nicht als Formel merken 255 } 256 else if ( pToken->GetType() == svString ) 257 { 258 bIsStr1 = sal_True; 259 aStrVal1 = pToken->GetString(); 260 DELETEZ(pFormula1); // nicht als Formel merken 261 } 262 } 263 } 264 bRelRef1 = lcl_HasRelRef( pDoc, pFormula1 ); 265 } 266 if ( pArr2 ) 267 { 268 pFormula2 = new ScTokenArray( *pArr2 ); 269 if ( pFormula2->GetLen() == 1 ) 270 { 271 // einzelne (konstante Zahl) ? 272 FormulaToken* pToken = pFormula2->First(); 273 if ( pToken->GetOpCode() == ocPush ) 274 { 275 if ( pToken->GetType() == svDouble ) 276 { 277 nVal2 = pToken->GetDouble(); 278 DELETEZ(pFormula2); // nicht als Formel merken 279 } 280 else if ( pToken->GetType() == svString ) 281 { 282 bIsStr2 = sal_True; 283 aStrVal2 = pToken->GetString(); 284 DELETEZ(pFormula2); // nicht als Formel merken 285 } 286 } 287 } 288 bRelRef2 = lcl_HasRelRef( pDoc, pFormula2 ); 289 } 290 291 // formula cells are created at IsValid 292 } 293 294 ScConditionEntry::~ScConditionEntry() 295 { 296 delete pFCell1; 297 delete pFCell2; 298 299 delete pFormula1; 300 delete pFormula2; 301 } 302 303 void ScConditionEntry::Compile( const String& rExpr1, const String& rExpr2, 304 const String& rExprNmsp1, const String& rExprNmsp2, 305 FormulaGrammar::Grammar eGrammar1, FormulaGrammar::Grammar eGrammar2, sal_Bool bTextToReal ) 306 { 307 if ( rExpr1.Len() || rExpr2.Len() ) 308 { 309 ScCompiler aComp( pDoc, aSrcPos ); 310 311 if ( rExpr1.Len() ) 312 { 313 aComp.SetGrammar( eGrammar1 ); 314 if ( pDoc->IsImportingXML() && !bTextToReal ) 315 { 316 // temporary formula string as string tokens 317 //! merge with lcl_ScDocFunc_CreateTokenArrayXML 318 pFormula1 = new ScTokenArray; 319 pFormula1->AddString( rExpr1 ); 320 // bRelRef1 is set when the formula is compiled again (CompileXML) 321 } 322 else 323 { 324 pFormula1 = aComp.CompileString( rExpr1, rExprNmsp1 ); 325 if ( pFormula1->GetLen() == 1 ) 326 { 327 // einzelne (konstante Zahl) ? 328 FormulaToken* pToken = pFormula1->First(); 329 if ( pToken->GetOpCode() == ocPush ) 330 { 331 if ( pToken->GetType() == svDouble ) 332 { 333 nVal1 = pToken->GetDouble(); 334 DELETEZ(pFormula1); // nicht als Formel merken 335 } 336 else if ( pToken->GetType() == svString ) 337 { 338 bIsStr1 = sal_True; 339 aStrVal1 = pToken->GetString(); 340 DELETEZ(pFormula1); // nicht als Formel merken 341 } 342 } 343 } 344 bRelRef1 = lcl_HasRelRef( pDoc, pFormula1 ); 345 } 346 } 347 348 if ( rExpr2.Len() ) 349 { 350 aComp.SetGrammar( eGrammar2 ); 351 if ( pDoc->IsImportingXML() && !bTextToReal ) 352 { 353 // temporary formula string as string tokens 354 //! merge with lcl_ScDocFunc_CreateTokenArrayXML 355 pFormula2 = new ScTokenArray; 356 pFormula2->AddString( rExpr2 ); 357 // bRelRef2 is set when the formula is compiled again (CompileXML) 358 } 359 else 360 { 361 pFormula2 = aComp.CompileString( rExpr2, rExprNmsp2 ); 362 if ( pFormula2->GetLen() == 1 ) 363 { 364 // einzelne (konstante Zahl) ? 365 FormulaToken* pToken = pFormula2->First(); 366 if ( pToken->GetOpCode() == ocPush ) 367 { 368 if ( pToken->GetType() == svDouble ) 369 { 370 nVal2 = pToken->GetDouble(); 371 DELETEZ(pFormula2); // nicht als Formel merken 372 } 373 else if ( pToken->GetType() == svString ) 374 { 375 bIsStr2 = sal_True; 376 aStrVal2 = pToken->GetString(); 377 DELETEZ(pFormula2); // nicht als Formel merken 378 } 379 } 380 } 381 bRelRef2 = lcl_HasRelRef( pDoc, pFormula2 ); 382 } 383 } 384 } 385 } 386 387 void ScConditionEntry::MakeCells( const ScAddress& rPos ) // Formelzellen anlegen 388 { 389 if ( !pDoc->IsClipOrUndo() ) // nie im Clipboard rechnen! 390 { 391 if ( pFormula1 && !pFCell1 && !bRelRef1 ) 392 { 393 pFCell1 = new ScFormulaCell( pDoc, rPos, pFormula1 ); 394 pFCell1->StartListeningTo( pDoc ); 395 } 396 397 if ( pFormula2 && !pFCell2 && !bRelRef2 ) 398 { 399 pFCell2 = new ScFormulaCell( pDoc, rPos, pFormula2 ); 400 pFCell2->StartListeningTo( pDoc ); 401 } 402 } 403 } 404 405 void ScConditionEntry::SetIgnoreBlank(sal_Bool bSet) 406 { 407 // Das Bit SC_COND_NOBLANKS wird gesetzt, wenn Blanks nicht ignoriert werden 408 // (nur bei Gueltigkeit) 409 410 if (bSet) 411 nOptions &= ~SC_COND_NOBLANKS; 412 else 413 nOptions |= SC_COND_NOBLANKS; 414 } 415 416 void ScConditionEntry::CompileAll() 417 { 418 // Formelzellen loeschen, dann wird beim naechsten IsValid neu kompiliert 419 420 DELETEZ(pFCell1); 421 DELETEZ(pFCell2); 422 } 423 424 void ScConditionEntry::CompileXML() 425 { 426 // #b4974740# First parse the formula source position if it was stored as text 427 428 if ( aSrcString.Len() ) 429 { 430 ScAddress aNew; 431 /* XML is always in OOo:A1 format, although R1C1 would be more amenable 432 * to compression */ 433 if ( aNew.Parse( aSrcString, pDoc ) & SCA_VALID ) 434 aSrcPos = aNew; 435 // if the position is invalid, there isn't much we can do at this time 436 aSrcString.Erase(); 437 } 438 439 // Convert the text tokens that were created during XML import into real tokens. 440 441 Compile( GetExpression(aSrcPos, 0, 0, eTempGrammar1), 442 GetExpression(aSrcPos, 1, 0, eTempGrammar2), 443 aStrNmsp1, aStrNmsp2, eTempGrammar1, eTempGrammar2, sal_True ); 444 } 445 446 void ScConditionEntry::SetSrcString( const String& rNew ) 447 { 448 // aSrcString is only evaluated in CompileXML 449 DBG_ASSERT( pDoc->IsImportingXML(), "SetSrcString is only valid for XML import" ); 450 451 aSrcString = rNew; 452 } 453 454 void ScConditionEntry::SetFormula1( const ScTokenArray& rArray ) 455 { 456 DELETEZ( pFormula1 ); 457 if( rArray.GetLen() > 0 ) 458 { 459 pFormula1 = new ScTokenArray( rArray ); 460 bRelRef1 = lcl_HasRelRef( pDoc, pFormula1 ); 461 } 462 } 463 464 void ScConditionEntry::SetFormula2( const ScTokenArray& rArray ) 465 { 466 DELETEZ( pFormula2 ); 467 if( rArray.GetLen() > 0 ) 468 { 469 pFormula2 = new ScTokenArray( rArray ); 470 bRelRef2 = lcl_HasRelRef( pDoc, pFormula2 ); 471 } 472 } 473 474 void lcl_CondUpdateInsertTab( ScTokenArray& rCode, SCTAB nInsTab, SCTAB nPosTab, sal_Bool& rChanged ) 475 { 476 // Insert table: only update absolute table references. 477 // (Similar to ScCompiler::UpdateInsertTab with bIsName=sal_True, result is the same as for named ranges) 478 // For deleting, ScCompiler::UpdateDeleteTab is used because of the handling of invalid references. 479 480 rCode.Reset(); 481 ScToken* p = static_cast<ScToken*>(rCode.GetNextReference()); 482 while( p ) 483 { 484 ScSingleRefData& rRef1 = p->GetSingleRef(); 485 if ( !rRef1.IsTabRel() && nInsTab <= rRef1.nTab ) 486 { 487 rRef1.nTab += 1; 488 rRef1.nRelTab = rRef1.nTab - nPosTab; 489 rChanged = sal_True; 490 } 491 if( p->GetType() == svDoubleRef ) 492 { 493 ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2; 494 if ( !rRef2.IsTabRel() && nInsTab <= rRef2.nTab ) 495 { 496 rRef2.nTab += 1; 497 rRef2.nRelTab = rRef2.nTab - nPosTab; 498 rChanged = sal_True; 499 } 500 } 501 p = static_cast<ScToken*>(rCode.GetNextReference()); 502 } 503 } 504 505 void ScConditionEntry::UpdateReference( UpdateRefMode eUpdateRefMode, 506 const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz ) 507 { 508 sal_Bool bInsertTab = ( eUpdateRefMode == URM_INSDEL && nDz == 1 ); 509 sal_Bool bDeleteTab = ( eUpdateRefMode == URM_INSDEL && nDz == -1 ); 510 511 sal_Bool bChanged1 = sal_False; 512 sal_Bool bChanged2 = sal_False; 513 514 if (pFormula1) 515 { 516 if ( bInsertTab ) 517 lcl_CondUpdateInsertTab( *pFormula1, rRange.aStart.Tab(), aSrcPos.Tab(), bChanged1 ); 518 else 519 { 520 ScCompiler aComp( pDoc, aSrcPos, *pFormula1 ); 521 aComp.SetGrammar(pDoc->GetGrammar()); 522 if ( bDeleteTab ) 523 aComp.UpdateDeleteTab( rRange.aStart.Tab(), sal_False, sal_True, bChanged1 ); 524 else 525 aComp.UpdateNameReference( eUpdateRefMode, rRange, nDx, nDy, nDz, bChanged1 ); 526 } 527 528 if (bChanged1) 529 DELETEZ(pFCell1); // is created again in IsValid 530 } 531 if (pFormula2) 532 { 533 if ( bInsertTab ) 534 lcl_CondUpdateInsertTab( *pFormula2, rRange.aStart.Tab(), aSrcPos.Tab(), bChanged2 ); 535 else 536 { 537 ScCompiler aComp( pDoc, aSrcPos, *pFormula2); 538 aComp.SetGrammar(pDoc->GetGrammar()); 539 if ( bDeleteTab ) 540 aComp.UpdateDeleteTab( rRange.aStart.Tab(), sal_False, sal_True, bChanged2 ); 541 else 542 aComp.UpdateNameReference( eUpdateRefMode, rRange, nDx, nDy, nDz, bChanged2 ); 543 } 544 545 if (bChanged2) 546 DELETEZ(pFCell2); // is created again in IsValid 547 } 548 } 549 550 void ScConditionEntry::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos ) 551 { 552 if (pFormula1) 553 { 554 ScCompiler aComp( pDoc, aSrcPos, *pFormula1); 555 aComp.SetGrammar(pDoc->GetGrammar()); 556 aComp.UpdateMoveTab(nOldPos, nNewPos, sal_True ); 557 DELETEZ(pFCell1); 558 } 559 if (pFormula2) 560 { 561 ScCompiler aComp( pDoc, aSrcPos, *pFormula2); 562 aComp.SetGrammar(pDoc->GetGrammar()); 563 aComp.UpdateMoveTab(nOldPos, nNewPos, sal_True ); 564 DELETEZ(pFCell2); 565 } 566 } 567 568 //! als Vergleichsoperator ans TokenArray ??? 569 570 sal_Bool lcl_IsEqual( const ScTokenArray* pArr1, const ScTokenArray* pArr2 ) 571 { 572 // verglichen wird nur das nicht-UPN Array 573 574 if ( pArr1 && pArr2 ) 575 { 576 sal_uInt16 nLen = pArr1->GetLen(); 577 if ( pArr2->GetLen() != nLen ) 578 return sal_False; 579 580 FormulaToken** ppToken1 = pArr1->GetArray(); 581 FormulaToken** ppToken2 = pArr2->GetArray(); 582 for (sal_uInt16 i=0; i<nLen; i++) 583 { 584 if ( ppToken1[i] != ppToken2[i] && 585 !(*ppToken1[i] == *ppToken2[i]) ) 586 return sal_False; // Unterschied 587 } 588 return sal_True; // alle Eintraege gleich 589 } 590 else 591 return !pArr1 && !pArr2; // beide 0 -> gleich 592 } 593 594 int ScConditionEntry::operator== ( const ScConditionEntry& r ) const 595 { 596 sal_Bool bEq = (eOp == r.eOp && nOptions == r.nOptions && 597 lcl_IsEqual( pFormula1, r.pFormula1 ) && 598 lcl_IsEqual( pFormula2, r.pFormula2 )); 599 if (bEq) 600 { 601 // for formulas, the reference positions must be compared, too 602 // (including aSrcString, for inserting the entries during XML import) 603 if ( ( pFormula1 || pFormula2 ) && ( aSrcPos != r.aSrcPos || aSrcString != r.aSrcString ) ) 604 bEq = sal_False; 605 606 // wenn keine Formeln, Werte vergleichen 607 if ( !pFormula1 && ( nVal1 != r.nVal1 || aStrVal1 != r.aStrVal1 || bIsStr1 != r.bIsStr1 ) ) 608 bEq = sal_False; 609 if ( !pFormula2 && ( nVal2 != r.nVal2 || aStrVal2 != r.aStrVal2 || bIsStr2 != r.bIsStr2 ) ) 610 bEq = sal_False; 611 } 612 613 return bEq; 614 } 615 616 void ScConditionEntry::Interpret( const ScAddress& rPos ) 617 { 618 // Formelzellen anlegen 619 // dabei koennen neue Broadcaster (Note-Zellen) ins Dokument eingefuegt werden !!!! 620 621 if ( ( pFormula1 && !pFCell1 ) || ( pFormula2 && !pFCell2 ) ) 622 MakeCells( rPos ); 623 624 // Formeln auswerten 625 626 sal_Bool bDirty = sal_False; //! 1 und 2 getrennt ??? 627 628 ScFormulaCell* pTemp1 = NULL; 629 ScFormulaCell* pEff1 = pFCell1; 630 if ( bRelRef1 ) 631 { 632 pTemp1 = new ScFormulaCell( pDoc, rPos, pFormula1 ); // ohne Listening 633 pEff1 = pTemp1; 634 } 635 if ( pEff1 ) 636 { 637 if (!pEff1->IsRunning()) // keine 522 erzeugen 638 { 639 //! Changed statt Dirty abfragen !!! 640 if (pEff1->GetDirty() && !bRelRef1) 641 bDirty = sal_True; 642 if (pEff1->IsValue()) 643 { 644 bIsStr1 = sal_False; 645 nVal1 = pEff1->GetValue(); 646 aStrVal1.Erase(); 647 } 648 else 649 { 650 bIsStr1 = sal_True; 651 pEff1->GetString( aStrVal1 ); 652 nVal1 = 0.0; 653 } 654 } 655 } 656 delete pTemp1; 657 658 ScFormulaCell* pTemp2 = NULL; 659 ScFormulaCell* pEff2 = pFCell2; //@ 1!=2 660 if ( bRelRef2 ) 661 { 662 pTemp2 = new ScFormulaCell( pDoc, rPos, pFormula2 ); // ohne Listening 663 pEff2 = pTemp2; 664 } 665 if ( pEff2 ) 666 { 667 if (!pEff2->IsRunning()) // keine 522 erzeugen 668 { 669 if (pEff2->GetDirty() && !bRelRef2) 670 bDirty = sal_True; 671 if (pEff2->IsValue()) 672 { 673 bIsStr2 = sal_False; 674 nVal2 = pEff2->GetValue(); 675 aStrVal2.Erase(); 676 } 677 else 678 { 679 bIsStr2 = sal_True; 680 pEff2->GetString( aStrVal2 ); 681 nVal2 = 0.0; 682 } 683 } 684 } 685 delete pTemp2; 686 687 // wenn IsRunning, bleiben die letzten Werte erhalten 688 689 if (bDirty && !bFirstRun) 690 { 691 // bei bedingten Formaten neu painten 692 693 DataChanged( NULL ); // alles 694 } 695 696 bFirstRun = sal_False; 697 } 698 699 sal_Bool ScConditionEntry::IsValid( double nArg ) const 700 { 701 // Interpret muss schon gerufen sein 702 703 if ( bIsStr1 ) 704 { 705 // wenn auf String getestet wird, bei Zahlen immer sal_False, ausser bei "ungleich" 706 707 return ( eOp == SC_COND_NOTEQUAL ); 708 } 709 710 if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN ) 711 if ( bIsStr2 ) 712 return sal_False; 713 714 double nComp1 = nVal1; // Kopie, damit vertauscht werden kann 715 double nComp2 = nVal2; 716 717 if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN ) 718 if ( nComp1 > nComp2 ) 719 { 720 // richtige Reihenfolge fuer Wertebereich 721 double nTemp = nComp1; nComp1 = nComp2; nComp2 = nTemp; 722 } 723 724 // Alle Grenzfaelle muessen per ::rtl::math::approxEqual getestet werden! 725 726 sal_Bool bValid = sal_False; 727 switch (eOp) 728 { 729 case SC_COND_NONE: 730 break; // immer sal_False; 731 case SC_COND_EQUAL: 732 bValid = ::rtl::math::approxEqual( nArg, nComp1 ); 733 break; 734 case SC_COND_NOTEQUAL: 735 bValid = !::rtl::math::approxEqual( nArg, nComp1 ); 736 break; 737 case SC_COND_GREATER: 738 bValid = ( nArg > nComp1 ) && !::rtl::math::approxEqual( nArg, nComp1 ); 739 break; 740 case SC_COND_EQGREATER: 741 bValid = ( nArg >= nComp1 ) || ::rtl::math::approxEqual( nArg, nComp1 ); 742 break; 743 case SC_COND_LESS: 744 bValid = ( nArg < nComp1 ) && !::rtl::math::approxEqual( nArg, nComp1 ); 745 break; 746 case SC_COND_EQLESS: 747 bValid = ( nArg <= nComp1 ) || ::rtl::math::approxEqual( nArg, nComp1 ); 748 break; 749 case SC_COND_BETWEEN: 750 bValid = ( nArg >= nComp1 && nArg <= nComp2 ) || 751 ::rtl::math::approxEqual( nArg, nComp1 ) || ::rtl::math::approxEqual( nArg, nComp2 ); 752 break; 753 case SC_COND_NOTBETWEEN: 754 bValid = ( nArg < nComp1 || nArg > nComp2 ) && 755 !::rtl::math::approxEqual( nArg, nComp1 ) && !::rtl::math::approxEqual( nArg, nComp2 ); 756 break; 757 case SC_COND_DIRECT: 758 bValid = !::rtl::math::approxEqual( nComp1, 0.0 ); 759 break; 760 default: 761 DBG_ERROR("unbekannte Operation bei ScConditionEntry"); 762 break; 763 } 764 return bValid; 765 } 766 767 sal_Bool ScConditionEntry::IsValidStr( const String& rArg ) const 768 { 769 // Interpret muss schon gerufen sein 770 771 if ( eOp == SC_COND_DIRECT ) // Formel ist unabhaengig vom Inhalt 772 return !::rtl::math::approxEqual( nVal1, 0.0 ); 773 774 // Wenn Bedingung Zahl enthaelt, immer sal_False, ausser bei "ungleich" 775 776 if ( !bIsStr1 ) 777 return ( eOp == SC_COND_NOTEQUAL ); 778 if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN ) 779 if ( !bIsStr2 ) 780 return sal_False; 781 782 String aUpVal1( aStrVal1 ); //! als Member? (dann auch in Interpret setzen) 783 String aUpVal2( aStrVal2 ); 784 785 if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN ) 786 if ( ScGlobal::GetCollator()->compareString( aUpVal1, aUpVal2 ) 787 == COMPARE_GREATER ) 788 { 789 // richtige Reihenfolge fuer Wertebereich 790 String aTemp( aUpVal1 ); aUpVal1 = aUpVal2; aUpVal2 = aTemp; 791 } 792 793 sal_Bool bValid; 794 switch ( eOp ) 795 { 796 case SC_COND_EQUAL: 797 bValid = (ScGlobal::GetCollator()->compareString( 798 rArg, aUpVal1 ) == COMPARE_EQUAL); 799 break; 800 case SC_COND_NOTEQUAL: 801 bValid = (ScGlobal::GetCollator()->compareString( 802 rArg, aUpVal1 ) != COMPARE_EQUAL); 803 break; 804 default: 805 { 806 sal_Int32 nCompare = ScGlobal::GetCollator()->compareString( 807 rArg, aUpVal1 ); 808 switch ( eOp ) 809 { 810 case SC_COND_GREATER: 811 bValid = ( nCompare == COMPARE_GREATER ); 812 break; 813 case SC_COND_EQGREATER: 814 bValid = ( nCompare == COMPARE_EQUAL || nCompare == COMPARE_GREATER ); 815 break; 816 case SC_COND_LESS: 817 bValid = ( nCompare == COMPARE_LESS ); 818 break; 819 case SC_COND_EQLESS: 820 bValid = ( nCompare == COMPARE_EQUAL || nCompare == COMPARE_LESS ); 821 break; 822 case SC_COND_BETWEEN: 823 case SC_COND_NOTBETWEEN: 824 // Test auf NOTBETWEEN: 825 bValid = ( nCompare == COMPARE_LESS || 826 ScGlobal::GetCollator()->compareString( rArg, 827 aUpVal2 ) == COMPARE_GREATER ); 828 if ( eOp == SC_COND_BETWEEN ) 829 bValid = !bValid; 830 break; 831 // SC_COND_DIRECT schon oben abgefragt 832 default: 833 DBG_ERROR("unbekannte Operation bei ScConditionEntry"); 834 bValid = sal_False; 835 break; 836 } 837 } 838 } 839 return bValid; 840 } 841 842 sal_Bool ScConditionEntry::IsCellValid( ScBaseCell* pCell, const ScAddress& rPos ) const 843 { 844 ((ScConditionEntry*)this)->Interpret(rPos); // Formeln auswerten 845 846 double nArg = 0.0; 847 String aArgStr; 848 sal_Bool bVal = sal_True; 849 850 if ( pCell ) 851 { 852 CellType eType = pCell->GetCellType(); 853 switch (eType) 854 { 855 case CELLTYPE_VALUE: 856 nArg = ((ScValueCell*)pCell)->GetValue(); 857 break; 858 case CELLTYPE_FORMULA: 859 { 860 ScFormulaCell* pFCell = (ScFormulaCell*)pCell; 861 bVal = pFCell->IsValue(); 862 if (bVal) 863 nArg = pFCell->GetValue(); 864 else 865 pFCell->GetString(aArgStr); 866 } 867 break; 868 case CELLTYPE_STRING: 869 case CELLTYPE_EDIT: 870 bVal = sal_False; 871 if ( eType == CELLTYPE_STRING ) 872 ((ScStringCell*)pCell)->GetString(aArgStr); 873 else 874 ((ScEditCell*)pCell)->GetString(aArgStr); 875 break; 876 877 default: 878 pCell = NULL; // Note-Zellen wie leere 879 break; 880 } 881 } 882 883 if (!pCell) 884 if (bIsStr1) 885 bVal = sal_False; // leere Zellen je nach Bedingung 886 887 if (bVal) 888 return IsValid( nArg ); 889 else 890 return IsValidStr( aArgStr ); 891 } 892 893 String ScConditionEntry::GetExpression( const ScAddress& rCursor, sal_uInt16 nIndex, 894 sal_uLong nNumFmt, 895 const FormulaGrammar::Grammar eGrammar ) const 896 { 897 String aRet; 898 899 if ( FormulaGrammar::isEnglish( eGrammar) && nNumFmt == 0 ) 900 nNumFmt = pDoc->GetFormatTable()->GetStandardIndex( LANGUAGE_ENGLISH_US ); 901 902 if ( nIndex==0 ) 903 { 904 if ( pFormula1 ) 905 { 906 ScCompiler aComp(pDoc, rCursor, *pFormula1); 907 aComp.SetGrammar(eGrammar); 908 aComp.CreateStringFromTokenArray( aRet ); 909 } 910 else if (bIsStr1) 911 { 912 aRet = '"'; 913 aRet += aStrVal1; 914 aRet += '"'; 915 } 916 else 917 pDoc->GetFormatTable()->GetInputLineString(nVal1, nNumFmt, aRet); 918 } 919 else if ( nIndex==1 ) 920 { 921 if ( pFormula2 ) 922 { 923 ScCompiler aComp(pDoc, rCursor, *pFormula2); 924 aComp.SetGrammar(eGrammar); 925 aComp.CreateStringFromTokenArray( aRet ); 926 } 927 else if (bIsStr2) 928 { 929 aRet = '"'; 930 aRet += aStrVal2; 931 aRet += '"'; 932 } 933 else 934 pDoc->GetFormatTable()->GetInputLineString(nVal2, nNumFmt, aRet); 935 } 936 else 937 { 938 DBG_ERROR("GetExpression: falscher Index"); 939 } 940 941 return aRet; 942 } 943 944 ScTokenArray* ScConditionEntry::CreateTokenArry( sal_uInt16 nIndex ) const 945 { 946 ScTokenArray* pRet = NULL; 947 ScAddress aAddr; 948 949 if ( nIndex==0 ) 950 { 951 if ( pFormula1 ) 952 pRet = new ScTokenArray( *pFormula1 ); 953 else 954 { 955 pRet = new ScTokenArray(); 956 if (bIsStr1) 957 pRet->AddString( aStrVal1.GetBuffer() ); 958 else 959 pRet->AddDouble( nVal1 ); 960 } 961 } 962 else if ( nIndex==1 ) 963 { 964 if ( pFormula2 ) 965 pRet = new ScTokenArray( *pFormula2 ); 966 else 967 { 968 pRet = new ScTokenArray(); 969 if (bIsStr2) 970 pRet->AddString( aStrVal2.GetBuffer() ); 971 else 972 pRet->AddDouble( nVal2 ); 973 } 974 } 975 else 976 { 977 DBG_ERROR("GetExpression: falscher Index"); 978 } 979 980 return pRet; 981 } 982 983 void ScConditionEntry::SourceChanged( const ScAddress& rChanged ) 984 { 985 for (sal_uInt16 nPass = 0; nPass < 2; nPass++) 986 { 987 ScTokenArray* pFormula = nPass ? pFormula2 : pFormula1; 988 if (pFormula) 989 { 990 pFormula->Reset(); 991 ScToken* t; 992 while ( ( t = static_cast<ScToken*>(pFormula->GetNextReference()) ) != NULL ) 993 { 994 SingleDoubleRefProvider aProv( *t ); 995 if ( aProv.Ref1.IsColRel() || aProv.Ref1.IsRowRel() || aProv.Ref1.IsTabRel() || 996 aProv.Ref2.IsColRel() || aProv.Ref2.IsRowRel() || aProv.Ref2.IsTabRel() ) 997 { 998 // absolut muss getroffen sein, relativ bestimmt Bereich 999 1000 sal_Bool bHit = sal_True; 1001 SCsCOL nCol1; 1002 SCsROW nRow1; 1003 SCsTAB nTab1; 1004 SCsCOL nCol2; 1005 SCsROW nRow2; 1006 SCsTAB nTab2; 1007 1008 if ( aProv.Ref1.IsColRel() ) 1009 nCol2 = rChanged.Col() - aProv.Ref1.nRelCol; 1010 else 1011 { 1012 bHit &= ( rChanged.Col() >= aProv.Ref1.nCol ); 1013 nCol2 = MAXCOL; 1014 } 1015 if ( aProv.Ref1.IsRowRel() ) 1016 nRow2 = rChanged.Row() - aProv.Ref1.nRelRow; 1017 else 1018 { 1019 bHit &= ( rChanged.Row() >= aProv.Ref1.nRow ); 1020 nRow2 = MAXROW; 1021 } 1022 if ( aProv.Ref1.IsTabRel() ) 1023 nTab2 = rChanged.Tab() - aProv.Ref1.nRelTab; 1024 else 1025 { 1026 bHit &= ( rChanged.Tab() >= aProv.Ref1.nTab ); 1027 nTab2 = MAXTAB; 1028 } 1029 1030 if ( aProv.Ref2.IsColRel() ) 1031 nCol1 = rChanged.Col() - aProv.Ref2.nRelCol; 1032 else 1033 { 1034 bHit &= ( rChanged.Col() <= aProv.Ref2.nCol ); 1035 nCol1 = 0; 1036 } 1037 if ( aProv.Ref2.IsRowRel() ) 1038 nRow1 = rChanged.Row() - aProv.Ref2.nRelRow; 1039 else 1040 { 1041 bHit &= ( rChanged.Row() <= aProv.Ref2.nRow ); 1042 nRow1 = 0; 1043 } 1044 if ( aProv.Ref2.IsTabRel() ) 1045 nTab1 = rChanged.Tab() - aProv.Ref2.nRelTab; 1046 else 1047 { 1048 bHit &= ( rChanged.Tab() <= aProv.Ref2.nTab ); 1049 nTab1 = 0; 1050 } 1051 1052 if ( bHit ) 1053 { 1054 //! begrenzen 1055 1056 ScRange aPaint( nCol1,nRow1,nTab1, nCol2,nRow2,nTab2 ); 1057 1058 // kein Paint, wenn es nur die Zelle selber ist 1059 if ( aPaint.aStart != rChanged || aPaint.aEnd != rChanged ) 1060 DataChanged( &aPaint ); 1061 } 1062 } 1063 } 1064 } 1065 } 1066 } 1067 1068 ScAddress ScConditionEntry::GetValidSrcPos() const 1069 { 1070 // return a position that's adjusted to allow textual representation of expressions if possible 1071 1072 SCTAB nMinTab = aSrcPos.Tab(); 1073 SCTAB nMaxTab = nMinTab; 1074 1075 for (sal_uInt16 nPass = 0; nPass < 2; nPass++) 1076 { 1077 ScTokenArray* pFormula = nPass ? pFormula2 : pFormula1; 1078 if (pFormula) 1079 { 1080 pFormula->Reset(); 1081 ScToken* t; 1082 while ( ( t = static_cast<ScToken*>(pFormula->GetNextReference()) ) != NULL ) 1083 { 1084 ScSingleRefData& rRef1 = t->GetSingleRef(); 1085 if ( rRef1.IsTabRel() && !rRef1.IsTabDeleted() ) 1086 { 1087 if ( rRef1.nTab < nMinTab ) 1088 nMinTab = rRef1.nTab; 1089 if ( rRef1.nTab > nMaxTab ) 1090 nMaxTab = rRef1.nTab; 1091 } 1092 if ( t->GetType() == svDoubleRef ) 1093 { 1094 ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2; 1095 if ( rRef2.IsTabRel() && !rRef2.IsTabDeleted() ) 1096 { 1097 if ( rRef2.nTab < nMinTab ) 1098 nMinTab = rRef2.nTab; 1099 if ( rRef2.nTab > nMaxTab ) 1100 nMaxTab = rRef2.nTab; 1101 } 1102 } 1103 } 1104 } 1105 } 1106 1107 ScAddress aValidPos = aSrcPos; 1108 SCTAB nTabCount = pDoc->GetTableCount(); 1109 if ( nMaxTab >= nTabCount && nMinTab > 0 ) 1110 aValidPos.SetTab( aSrcPos.Tab() - nMinTab ); // so the lowest tab ref will be on 0 1111 1112 if ( aValidPos.Tab() >= nTabCount ) 1113 aValidPos.SetTab( nTabCount - 1 ); // ensure a valid position even if some references will be invalid 1114 1115 return aValidPos; 1116 } 1117 1118 void ScConditionEntry::DataChanged( const ScRange* /* pModified */ ) const 1119 { 1120 // nix 1121 } 1122 1123 bool ScConditionEntry::MarkUsedExternalReferences() const 1124 { 1125 bool bAllMarked = false; 1126 for (sal_uInt16 nPass = 0; !bAllMarked && nPass < 2; nPass++) 1127 { 1128 ScTokenArray* pFormula = nPass ? pFormula2 : pFormula1; 1129 if (pFormula) 1130 bAllMarked = pDoc->MarkUsedExternalReferences( *pFormula); 1131 } 1132 return bAllMarked; 1133 } 1134 1135 //------------------------------------------------------------------------ 1136 1137 ScCondFormatEntry::ScCondFormatEntry( ScConditionMode eOper, 1138 const String& rExpr1, const String& rExpr2, 1139 ScDocument* pDocument, const ScAddress& rPos, 1140 const String& rStyle, 1141 const String& rExprNmsp1, const String& rExprNmsp2, 1142 FormulaGrammar::Grammar eGrammar1, 1143 FormulaGrammar::Grammar eGrammar2 ) : 1144 ScConditionEntry( eOper, rExpr1, rExpr2, pDocument, rPos, rExprNmsp1, rExprNmsp2, eGrammar1, eGrammar2 ), 1145 aStyleName( rStyle ), 1146 pParent( NULL ) 1147 { 1148 } 1149 1150 ScCondFormatEntry::ScCondFormatEntry( ScConditionMode eOper, 1151 const ScTokenArray* pArr1, const ScTokenArray* pArr2, 1152 ScDocument* pDocument, const ScAddress& rPos, 1153 const String& rStyle ) : 1154 ScConditionEntry( eOper, pArr1, pArr2, pDocument, rPos ), 1155 aStyleName( rStyle ), 1156 pParent( NULL ) 1157 { 1158 } 1159 1160 ScCondFormatEntry::ScCondFormatEntry( const ScCondFormatEntry& r ) : 1161 ScConditionEntry( r ), 1162 aStyleName( r.aStyleName ), 1163 pParent( NULL ) 1164 { 1165 } 1166 1167 ScCondFormatEntry::ScCondFormatEntry( ScDocument* pDocument, const ScCondFormatEntry& r ) : 1168 ScConditionEntry( pDocument, r ), 1169 aStyleName( r.aStyleName ), 1170 pParent( NULL ) 1171 { 1172 } 1173 1174 int ScCondFormatEntry::operator== ( const ScCondFormatEntry& r ) const 1175 { 1176 return ScConditionEntry::operator==( r ) && 1177 aStyleName == r.aStyleName; 1178 1179 // Range wird nicht verglichen 1180 } 1181 1182 ScCondFormatEntry::~ScCondFormatEntry() 1183 { 1184 } 1185 1186 void ScCondFormatEntry::DataChanged( const ScRange* pModified ) const 1187 { 1188 if ( pParent ) 1189 pParent->DoRepaint( pModified ); 1190 } 1191 1192 //------------------------------------------------------------------------ 1193 1194 ScConditionalFormat::ScConditionalFormat(sal_uInt32 nNewKey, ScDocument* pDocument) : 1195 pDoc( pDocument ), 1196 pAreas( NULL ), 1197 nKey( nNewKey ), 1198 ppEntries( NULL ), 1199 nEntryCount( 0 ) 1200 { 1201 } 1202 1203 ScConditionalFormat::ScConditionalFormat(const ScConditionalFormat& r) : 1204 pDoc( r.pDoc ), 1205 pAreas( NULL ), 1206 nKey( r.nKey ), 1207 ppEntries( NULL ), 1208 nEntryCount( r.nEntryCount ) 1209 { 1210 if (nEntryCount) 1211 { 1212 ppEntries = new ScCondFormatEntry*[nEntryCount]; 1213 for (sal_uInt16 i=0; i<nEntryCount; i++) 1214 { 1215 ppEntries[i] = new ScCondFormatEntry(*r.ppEntries[i]); 1216 ppEntries[i]->SetParent(this); 1217 } 1218 } 1219 } 1220 1221 ScConditionalFormat* ScConditionalFormat::Clone(ScDocument* pNewDoc) const 1222 { 1223 // echte Kopie der Formeln (fuer Ref-Undo / zwischen Dokumenten) 1224 1225 if (!pNewDoc) 1226 pNewDoc = pDoc; 1227 1228 ScConditionalFormat* pNew = new ScConditionalFormat(nKey, pNewDoc); 1229 DBG_ASSERT(!pNew->ppEntries, "wo kommen die Eintraege her?"); 1230 1231 if (nEntryCount) 1232 { 1233 pNew->ppEntries = new ScCondFormatEntry*[nEntryCount]; 1234 for (sal_uInt16 i=0; i<nEntryCount; i++) 1235 { 1236 pNew->ppEntries[i] = new ScCondFormatEntry( pNewDoc, *ppEntries[i] ); 1237 pNew->ppEntries[i]->SetParent(pNew); 1238 } 1239 pNew->nEntryCount = nEntryCount; 1240 } 1241 1242 return pNew; 1243 } 1244 1245 sal_Bool ScConditionalFormat::EqualEntries( const ScConditionalFormat& r ) const 1246 { 1247 if ( nEntryCount != r.nEntryCount ) 1248 return sal_False; 1249 1250 //! auf gleiche Eintraege in anderer Reihenfolge testen ??? 1251 1252 for (sal_uInt16 i=0; i<nEntryCount; i++) 1253 if ( ! (*ppEntries[i] == *r.ppEntries[i]) ) 1254 return sal_False; 1255 1256 return sal_True; 1257 } 1258 1259 void ScConditionalFormat::AddEntry( const ScCondFormatEntry& rNew ) 1260 { 1261 ScCondFormatEntry** ppNew = new ScCondFormatEntry*[nEntryCount+1]; 1262 for (sal_uInt16 i=0; i<nEntryCount; i++) 1263 ppNew[i] = ppEntries[i]; 1264 ppNew[nEntryCount] = new ScCondFormatEntry(rNew); 1265 ppNew[nEntryCount]->SetParent(this); 1266 ++nEntryCount; 1267 delete[] ppEntries; 1268 ppEntries = ppNew; 1269 } 1270 1271 ScConditionalFormat::~ScConditionalFormat() 1272 { 1273 for (sal_uInt16 i=0; i<nEntryCount; i++) 1274 delete ppEntries[i]; 1275 delete[] ppEntries; 1276 1277 delete pAreas; 1278 } 1279 1280 const ScCondFormatEntry* ScConditionalFormat::GetEntry( sal_uInt16 nPos ) const 1281 { 1282 if ( nPos < nEntryCount ) 1283 return ppEntries[nPos]; 1284 else 1285 return NULL; 1286 } 1287 1288 const String& ScConditionalFormat::GetCellStyle( ScBaseCell* pCell, const ScAddress& rPos ) const 1289 { 1290 for (sal_uInt16 i=0; i<nEntryCount; i++) 1291 if ( ppEntries[i]->IsCellValid( pCell, rPos ) ) 1292 return ppEntries[i]->GetStyle(); 1293 1294 return EMPTY_STRING; 1295 } 1296 1297 void lcl_Extend( ScRange& rRange, ScDocument* pDoc, sal_Bool bLines ) 1298 { 1299 SCTAB nTab = rRange.aStart.Tab(); 1300 DBG_ASSERT(rRange.aEnd.Tab() == nTab, "lcl_Extend - mehrere Tabellen?"); 1301 1302 SCCOL nStartCol = rRange.aStart.Col(); 1303 SCROW nStartRow = rRange.aStart.Row(); 1304 SCCOL nEndCol = rRange.aEnd.Col(); 1305 SCROW nEndRow = rRange.aEnd.Row(); 1306 1307 sal_Bool bEx = pDoc->ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, nTab ); 1308 1309 if (bLines) 1310 { 1311 if (nStartCol > 0) --nStartCol; 1312 if (nStartRow > 0) --nStartRow; 1313 if (nEndCol < MAXCOL) ++nEndCol; 1314 if (nEndRow < MAXROW) ++nEndRow; 1315 } 1316 1317 if ( bEx || bLines ) 1318 { 1319 rRange.aStart.Set( nStartCol, nStartRow, nTab ); 1320 rRange.aEnd.Set( nEndCol, nEndRow, nTab ); 1321 } 1322 } 1323 1324 sal_Bool lcl_CutRange( ScRange& rRange, const ScRange& rOther ) 1325 { 1326 rRange.Justify(); 1327 ScRange aCmpRange = rOther; 1328 aCmpRange.Justify(); 1329 1330 if ( rRange.aStart.Col() <= aCmpRange.aEnd.Col() && 1331 rRange.aEnd.Col() >= aCmpRange.aStart.Col() && 1332 rRange.aStart.Row() <= aCmpRange.aEnd.Row() && 1333 rRange.aEnd.Row() >= aCmpRange.aStart.Row() && 1334 rRange.aStart.Tab() <= aCmpRange.aEnd.Tab() && 1335 rRange.aEnd.Tab() >= aCmpRange.aStart.Tab() ) 1336 { 1337 if ( rRange.aStart.Col() < aCmpRange.aStart.Col() ) 1338 rRange.aStart.SetCol( aCmpRange.aStart.Col() ); 1339 if ( rRange.aStart.Row() < aCmpRange.aStart.Row() ) 1340 rRange.aStart.SetRow( aCmpRange.aStart.Row() ); 1341 if ( rRange.aStart.Tab() < aCmpRange.aStart.Tab() ) 1342 rRange.aStart.SetTab( aCmpRange.aStart.Tab() ); 1343 if ( rRange.aEnd.Col() > aCmpRange.aEnd.Col() ) 1344 rRange.aEnd.SetCol( aCmpRange.aEnd.Col() ); 1345 if ( rRange.aEnd.Row() > aCmpRange.aEnd.Row() ) 1346 rRange.aEnd.SetRow( aCmpRange.aEnd.Row() ); 1347 if ( rRange.aEnd.Tab() > aCmpRange.aEnd.Tab() ) 1348 rRange.aEnd.SetTab( aCmpRange.aEnd.Tab() ); 1349 1350 return sal_True; 1351 } 1352 1353 return sal_False; // ausserhalb 1354 } 1355 1356 void ScConditionalFormat::DoRepaint( const ScRange* pModified ) 1357 { 1358 sal_uInt16 i; 1359 SfxObjectShell* pSh = pDoc->GetDocumentShell(); 1360 if (pSh) 1361 { 1362 // Rahmen/Schatten enthalten? 1363 // (alle Bedingungen testen) 1364 sal_Bool bExtend = sal_False; 1365 sal_Bool bRotate = sal_False; 1366 sal_Bool bAttrTested = sal_False; 1367 1368 if (!pAreas) // RangeList ggf. holen 1369 { 1370 pAreas = new ScRangeList; 1371 pDoc->FindConditionalFormat( nKey, *pAreas ); 1372 } 1373 sal_uInt16 nCount = (sal_uInt16) pAreas->Count(); 1374 for (i=0; i<nCount; i++) 1375 { 1376 ScRange aRange = *pAreas->GetObject(i); 1377 sal_Bool bDo = sal_True; 1378 if ( pModified ) 1379 { 1380 if ( !lcl_CutRange( aRange, *pModified ) ) 1381 bDo = sal_False; 1382 } 1383 if (bDo) 1384 { 1385 if ( !bAttrTested ) 1386 { 1387 // #116562# Look at the style's content only if the repaint is necessary 1388 // for any condition, to avoid the time-consuming Find() if there are many 1389 // conditional formats and styles. 1390 for (sal_uInt16 nEntry=0; nEntry<nEntryCount; nEntry++) 1391 { 1392 String aStyle = ppEntries[nEntry]->GetStyle(); 1393 if (aStyle.Len()) 1394 { 1395 SfxStyleSheetBase* pStyleSheet = 1396 pDoc->GetStyleSheetPool()->Find( aStyle, SFX_STYLE_FAMILY_PARA ); 1397 if ( pStyleSheet ) 1398 { 1399 const SfxItemSet& rSet = pStyleSheet->GetItemSet(); 1400 if (rSet.GetItemState( ATTR_BORDER, sal_True ) == SFX_ITEM_SET || 1401 rSet.GetItemState( ATTR_SHADOW, sal_True ) == SFX_ITEM_SET) 1402 { 1403 bExtend = sal_True; 1404 } 1405 if (rSet.GetItemState( ATTR_ROTATE_VALUE, sal_True ) == SFX_ITEM_SET || 1406 rSet.GetItemState( ATTR_ROTATE_MODE, sal_True ) == SFX_ITEM_SET) 1407 { 1408 bRotate = sal_True; 1409 } 1410 } 1411 } 1412 } 1413 bAttrTested = sal_True; 1414 } 1415 1416 lcl_Extend( aRange, pDoc, bExtend ); // zusammengefasste und bExtend 1417 if ( bRotate ) 1418 { 1419 aRange.aStart.SetCol(0); 1420 aRange.aEnd.SetCol(MAXCOL); // gedreht: ganze Zeilen 1421 } 1422 1423 // gedreht -> ganze Zeilen 1424 if ( aRange.aStart.Col() != 0 || aRange.aEnd.Col() != MAXCOL ) 1425 { 1426 if ( pDoc->HasAttrib( 0,aRange.aStart.Row(),aRange.aStart.Tab(), 1427 MAXCOL,aRange.aEnd.Row(),aRange.aEnd.Tab(), 1428 HASATTR_ROTATE ) ) 1429 { 1430 aRange.aStart.SetCol(0); 1431 aRange.aEnd.SetCol(MAXCOL); 1432 } 1433 } 1434 1435 pDoc->RepaintRange( aRange ); 1436 } 1437 } 1438 } 1439 } 1440 1441 void ScConditionalFormat::InvalidateArea() 1442 { 1443 delete pAreas; 1444 pAreas = NULL; 1445 } 1446 1447 void ScConditionalFormat::CompileAll() 1448 { 1449 for (sal_uInt16 i=0; i<nEntryCount; i++) 1450 ppEntries[i]->CompileAll(); 1451 } 1452 1453 void ScConditionalFormat::CompileXML() 1454 { 1455 for (sal_uInt16 i=0; i<nEntryCount; i++) 1456 ppEntries[i]->CompileXML(); 1457 } 1458 1459 void ScConditionalFormat::UpdateReference( UpdateRefMode eUpdateRefMode, 1460 const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz ) 1461 { 1462 for (sal_uInt16 i=0; i<nEntryCount; i++) 1463 ppEntries[i]->UpdateReference(eUpdateRefMode, rRange, nDx, nDy, nDz); 1464 1465 delete pAreas; // aus dem AttrArray kommt beim Einfuegen/Loeschen kein Aufruf 1466 pAreas = NULL; 1467 } 1468 1469 void ScConditionalFormat::RenameCellStyle(const String& rOld, const String& rNew) 1470 { 1471 for (sal_uInt16 i=0; i<nEntryCount; i++) 1472 if ( ppEntries[i]->GetStyle() == rOld ) 1473 ppEntries[i]->UpdateStyleName( rNew ); 1474 } 1475 1476 void ScConditionalFormat::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos ) 1477 { 1478 for (sal_uInt16 i=0; i<nEntryCount; i++) 1479 ppEntries[i]->UpdateMoveTab( nOldPos, nNewPos ); 1480 1481 delete pAreas; // aus dem AttrArray kommt beim Einfuegen/Loeschen kein Aufruf 1482 pAreas = NULL; 1483 } 1484 1485 void ScConditionalFormat::SourceChanged( const ScAddress& rAddr ) 1486 { 1487 for (sal_uInt16 i=0; i<nEntryCount; i++) 1488 ppEntries[i]->SourceChanged( rAddr ); 1489 } 1490 1491 bool ScConditionalFormat::MarkUsedExternalReferences() const 1492 { 1493 bool bAllMarked = false; 1494 for (sal_uInt16 i=0; !bAllMarked && i<nEntryCount; i++) 1495 bAllMarked = ppEntries[i]->MarkUsedExternalReferences(); 1496 return bAllMarked; 1497 } 1498 1499 //------------------------------------------------------------------------ 1500 1501 ScConditionalFormatList::ScConditionalFormatList(const ScConditionalFormatList& rList) : 1502 ScConditionalFormats_Impl() 1503 { 1504 // fuer Ref-Undo - echte Kopie mit neuen Tokens! 1505 1506 sal_uInt16 nCount = rList.Count(); 1507 1508 for (sal_uInt16 i=0; i<nCount; i++) 1509 InsertNew( rList[i]->Clone() ); 1510 1511 //! sortierte Eintraege aus rList schneller einfuegen ??? 1512 } 1513 1514 ScConditionalFormatList::ScConditionalFormatList(ScDocument* pNewDoc, 1515 const ScConditionalFormatList& rList) 1516 { 1517 // fuer neues Dokument - echte Kopie mit neuen Tokens! 1518 1519 sal_uInt16 nCount = rList.Count(); 1520 1521 for (sal_uInt16 i=0; i<nCount; i++) 1522 InsertNew( rList[i]->Clone(pNewDoc) ); 1523 1524 //! sortierte Eintraege aus rList schneller einfuegen ??? 1525 } 1526 1527 sal_Bool ScConditionalFormatList::operator==( const ScConditionalFormatList& r ) const 1528 { 1529 // fuer Ref-Undo - interne Variablen werden nicht verglichen 1530 1531 sal_uInt16 nCount = Count(); 1532 sal_Bool bEqual = ( nCount == r.Count() ); 1533 for (sal_uInt16 i=0; i<nCount && bEqual; i++) // Eintraege sind sortiert 1534 if ( !(*this)[i]->EqualEntries(*r[i]) ) // Eintraege unterschiedlich ? 1535 bEqual = sal_False; 1536 1537 return bEqual; 1538 } 1539 1540 ScConditionalFormat* ScConditionalFormatList::GetFormat( sal_uInt32 nKey ) 1541 { 1542 //! binaer suchen 1543 1544 sal_uInt16 nCount = Count(); 1545 for (sal_uInt16 i=0; i<nCount; i++) 1546 if ((*this)[i]->GetKey() == nKey) 1547 return (*this)[i]; 1548 1549 DBG_ERROR("ScConditionalFormatList: Eintrag nicht gefunden"); 1550 return NULL; 1551 } 1552 1553 void ScConditionalFormatList::CompileAll() 1554 { 1555 sal_uInt16 nCount = Count(); 1556 for (sal_uInt16 i=0; i<nCount; i++) 1557 (*this)[i]->CompileAll(); 1558 } 1559 1560 void ScConditionalFormatList::CompileXML() 1561 { 1562 sal_uInt16 nCount = Count(); 1563 for (sal_uInt16 i=0; i<nCount; i++) 1564 (*this)[i]->CompileXML(); 1565 } 1566 1567 void ScConditionalFormatList::UpdateReference( UpdateRefMode eUpdateRefMode, 1568 const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz ) 1569 { 1570 sal_uInt16 nCount = Count(); 1571 for (sal_uInt16 i=0; i<nCount; i++) 1572 (*this)[i]->UpdateReference( eUpdateRefMode, rRange, nDx, nDy, nDz ); 1573 } 1574 1575 void ScConditionalFormatList::RenameCellStyle( const String& rOld, const String& rNew ) 1576 { 1577 sal_uLong nCount=Count(); 1578 for (sal_uInt16 i=0; i<nCount; i++) 1579 (*this)[i]->RenameCellStyle(rOld,rNew); 1580 } 1581 1582 void ScConditionalFormatList::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos ) 1583 { 1584 sal_uInt16 nCount = Count(); 1585 for (sal_uInt16 i=0; i<nCount; i++) 1586 (*this)[i]->UpdateMoveTab( nOldPos, nNewPos ); 1587 } 1588 1589 void ScConditionalFormatList::SourceChanged( const ScAddress& rAddr ) 1590 { 1591 sal_uInt16 nCount = Count(); 1592 for (sal_uInt16 i=0; i<nCount; i++) 1593 (*this)[i]->SourceChanged( rAddr ); 1594 } 1595 1596 bool ScConditionalFormatList::MarkUsedExternalReferences() const 1597 { 1598 bool bAllMarked = false; 1599 sal_uInt16 nCount = Count(); 1600 for (sal_uInt16 i=0; !bAllMarked && i<nCount; i++) 1601 bAllMarked = (*this)[i]->MarkUsedExternalReferences(); 1602 return bAllMarked; 1603 } 1604