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