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 // INCLUDE --------------------------------------------------------------- 32 33 #include <svl/zforlist.hxx> 34 35 #include "scitems.hxx" 36 #include "global.hxx" 37 #include "dociter.hxx" 38 #include "document.hxx" 39 #include "table.hxx" 40 #include "column.hxx" 41 #include "cell.hxx" 42 #include "attarray.hxx" 43 #include "patattr.hxx" 44 #include "docoptio.hxx" 45 #include "cellform.hxx" 46 47 #include <vector> 48 49 using ::rtl::math::approxEqual; 50 using ::std::vector; 51 using ::rtl::OUString; 52 using ::std::set; 53 54 // STATIC DATA ----------------------------------------------------------- 55 56 namespace { 57 58 void lcl_toUpper(OUString& rStr) 59 { 60 rStr = ScGlobal::pCharClass->toUpper(rStr.trim(), 0, static_cast<sal_uInt16>(rStr.getLength())); 61 } 62 63 } 64 65 ScDocumentIterator::ScDocumentIterator( ScDocument* pDocument, 66 SCTAB nStartTable, SCTAB nEndTable ) : 67 pDoc( pDocument ), 68 nStartTab( nStartTable ), 69 nEndTab( nEndTable ) 70 { 71 PutInOrder( nStartTab, nEndTab ); 72 if (!ValidTab(nStartTab)) nStartTab = MAXTAB; 73 if (!ValidTab(nEndTab)) nEndTab = MAXTAB; 74 75 pDefPattern = pDoc->GetDefPattern(); 76 77 nCol = 0; 78 nRow = 0; 79 nTab = nStartTab; 80 81 nColPos = 0; 82 nAttrPos = 0; 83 } 84 85 ScDocumentIterator::~ScDocumentIterator() 86 { 87 } 88 89 sal_Bool ScDocumentIterator::GetThisCol() 90 { 91 ScTable* pTab; 92 while ( (pTab = pDoc->pTab[nTab]) == NULL ) 93 { 94 if ( nTab == nEndTab ) 95 { 96 nCol = MAXCOL; 97 nRow = MAXROW; 98 return sal_False; 99 } 100 ++nTab; 101 } 102 ScColumn* pCol = &pTab->aCol[nCol]; 103 ScAttrArray* pAtt = pCol->pAttrArray; 104 105 sal_Bool bFound = sal_False; 106 do 107 { 108 SCROW nColRow; 109 SCROW nAttrEnd; 110 111 do 112 { 113 nAttrEnd = pAtt->pData[nAttrPos].nRow; 114 if (nAttrEnd < nRow) 115 ++nAttrPos; 116 } 117 while (nAttrEnd < nRow); 118 119 do 120 { 121 nColRow = (nColPos < pCol->nCount) ? pCol->pItems[nColPos].nRow : MAXROW+1; 122 if (nColRow < nRow) 123 ++nColPos; 124 } 125 while (nColRow < nRow); 126 127 if (nColRow == nRow) 128 { 129 bFound = sal_True; 130 pCell = pCol->pItems[nColPos].pCell; 131 pPattern = pAtt->pData[nAttrPos].pPattern; 132 } 133 else if ( pAtt->pData[nAttrPos].pPattern != pDefPattern ) 134 { 135 bFound = sal_True; 136 pCell = NULL; 137 pPattern = pAtt->pData[nAttrPos].pPattern; 138 } 139 else 140 { 141 nRow = Min( (SCROW)nColRow, (SCROW)(nAttrEnd+1) ); 142 } 143 } 144 while (!bFound && nRow <= MAXROW); 145 146 return bFound; 147 } 148 149 sal_Bool ScDocumentIterator::GetThis() 150 { 151 sal_Bool bEnd = sal_False; 152 sal_Bool bSuccess = sal_False; 153 154 while ( !bSuccess && !bEnd ) 155 { 156 if ( nRow > MAXROW ) 157 bSuccess = sal_False; 158 else 159 bSuccess = GetThisCol(); 160 161 if ( !bSuccess ) 162 { 163 ++nCol; 164 if (nCol > MAXCOL) 165 { 166 nCol = 0; 167 ++nTab; 168 if (nTab > nEndTab) 169 bEnd = sal_True; 170 } 171 nRow = 0; 172 nColPos = 0; 173 nAttrPos = 0; 174 } 175 } 176 177 return !bEnd; 178 } 179 180 sal_Bool ScDocumentIterator::GetFirst() 181 { 182 nCol = 0; 183 nTab = nStartTab; 184 185 nRow = 0; 186 nColPos = 0; 187 nAttrPos = 0; 188 189 return GetThis(); 190 } 191 192 sal_Bool ScDocumentIterator::GetNext() 193 { 194 ++nRow; 195 196 return GetThis(); 197 } 198 199 //------------------------------------------------------------------------ 200 201 ScBaseCell* ScDocumentIterator::GetCell() 202 { 203 return pCell; 204 } 205 206 const ScPatternAttr* ScDocumentIterator::GetPattern() 207 { 208 return pPattern; 209 } 210 211 void ScDocumentIterator::GetPos( SCCOL& rCol, SCROW& rRow, SCTAB& rTab ) 212 { 213 rCol = nCol; 214 rRow = nRow; 215 rTab = nTab; 216 } 217 218 219 //------------------------------------------------------------------------ 220 //------------------------------------------------------------------------ 221 void lcl_IterGetNumberFormat( sal_uLong& nFormat, const ScAttrArray*& rpArr, 222 SCROW& nAttrEndRow, const ScAttrArray* pNewArr, SCROW nRow, 223 ScDocument* pDoc ) 224 { 225 if ( rpArr != pNewArr || nAttrEndRow < nRow ) 226 { 227 SCSIZE nPos; 228 pNewArr->Search( nRow, nPos ); // nPos 0 gueltig wenn nicht gefunden 229 const ScPatternAttr* pPattern = pNewArr->pData[nPos].pPattern; 230 nFormat = pPattern->GetNumberFormat( pDoc->GetFormatTable() ); 231 rpArr = pNewArr; 232 nAttrEndRow = pNewArr->pData[nPos].nRow; 233 } 234 } 235 236 //UNUSED2008-05 ScValueIterator::ScValueIterator( ScDocument* pDocument, 237 //UNUSED2008-05 SCCOL nSCol, SCROW nSRow, SCTAB nSTab, 238 //UNUSED2008-05 SCCOL nECol, SCROW nERow, SCTAB nETab, 239 //UNUSED2008-05 sal_Bool bSTotal, sal_Bool bTextZero ) : 240 //UNUSED2008-05 pDoc( pDocument ), 241 //UNUSED2008-05 nNumFmtIndex(0), 242 //UNUSED2008-05 nStartCol( nSCol), 243 //UNUSED2008-05 nStartRow( nSRow), 244 //UNUSED2008-05 nStartTab( nSTab ), 245 //UNUSED2008-05 nEndCol( nECol ), 246 //UNUSED2008-05 nEndRow( nERow), 247 //UNUSED2008-05 nEndTab( nETab ), 248 //UNUSED2008-05 nNumFmtType( NUMBERFORMAT_UNDEFINED ), 249 //UNUSED2008-05 bNumValid( sal_False ), 250 //UNUSED2008-05 bSubTotal(bSTotal), 251 //UNUSED2008-05 bNextValid( sal_False ), 252 //UNUSED2008-05 bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ), 253 //UNUSED2008-05 bTextAsZero( bTextZero ) 254 //UNUSED2008-05 { 255 //UNUSED2008-05 PutInOrder( nStartCol, nEndCol); 256 //UNUSED2008-05 PutInOrder( nStartRow, nEndRow); 257 //UNUSED2008-05 PutInOrder( nStartTab, nEndTab ); 258 //UNUSED2008-05 259 //UNUSED2008-05 if (!ValidCol(nStartCol)) nStartCol = MAXCOL; 260 //UNUSED2008-05 if (!ValidCol(nEndCol)) nEndCol = MAXCOL; 261 //UNUSED2008-05 if (!ValidRow(nStartRow)) nStartRow = MAXROW; 262 //UNUSED2008-05 if (!ValidRow(nEndRow)) nEndRow = MAXROW; 263 //UNUSED2008-05 if (!ValidTab(nStartTab)) nStartTab = MAXTAB; 264 //UNUSED2008-05 if (!ValidTab(nEndTab)) nEndTab = MAXTAB; 265 //UNUSED2008-05 266 //UNUSED2008-05 nCol = nStartCol; 267 //UNUSED2008-05 nRow = nStartRow; 268 //UNUSED2008-05 nTab = nStartTab; 269 //UNUSED2008-05 270 //UNUSED2008-05 nColRow = 0; // wird bei GetFirst initialisiert 271 //UNUSED2008-05 272 //UNUSED2008-05 nNumFormat = 0; // werden bei GetNumberFormat initialisiert 273 //UNUSED2008-05 pAttrArray = 0; 274 //UNUSED2008-05 nAttrEndRow = 0; 275 //UNUSED2008-05 } 276 277 ScValueIterator::ScValueIterator( ScDocument* pDocument, const ScRange& rRange, 278 sal_Bool bSTotal, sal_Bool bTextZero ) : 279 pDoc( pDocument ), 280 nNumFmtIndex(0), 281 nStartCol( rRange.aStart.Col() ), 282 nStartRow( rRange.aStart.Row() ), 283 nStartTab( rRange.aStart.Tab() ), 284 nEndCol( rRange.aEnd.Col() ), 285 nEndRow( rRange.aEnd.Row() ), 286 nEndTab( rRange.aEnd.Tab() ), 287 nNumFmtType( NUMBERFORMAT_UNDEFINED ), 288 bNumValid( sal_False ), 289 bSubTotal(bSTotal), 290 bNextValid( sal_False ), 291 bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ), 292 bTextAsZero( bTextZero ) 293 { 294 PutInOrder( nStartCol, nEndCol); 295 PutInOrder( nStartRow, nEndRow); 296 PutInOrder( nStartTab, nEndTab ); 297 298 if (!ValidCol(nStartCol)) nStartCol = MAXCOL; 299 if (!ValidCol(nEndCol)) nEndCol = MAXCOL; 300 if (!ValidRow(nStartRow)) nStartRow = MAXROW; 301 if (!ValidRow(nEndRow)) nEndRow = MAXROW; 302 if (!ValidTab(nStartTab)) nStartTab = MAXTAB; 303 if (!ValidTab(nEndTab)) nEndTab = MAXTAB; 304 305 nCol = nStartCol; 306 nRow = nStartRow; 307 nTab = nStartTab; 308 309 nColRow = 0; // wird bei GetFirst initialisiert 310 311 nNumFormat = 0; // werden bei GetNumberFormat initialisiert 312 pAttrArray = 0; 313 nAttrEndRow = 0; 314 } 315 316 sal_Bool ScValueIterator::GetThis(double& rValue, sal_uInt16& rErr) 317 { 318 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol]; 319 for (;;) 320 { 321 if ( nRow > nEndRow ) 322 { 323 nRow = nStartRow; 324 do 325 { 326 nCol++; 327 if ( nCol > nEndCol ) 328 { 329 nCol = nStartCol; 330 nTab++; 331 if ( nTab > nEndTab ) 332 { 333 // rValue = 0.0; //! do not change caller's value! 334 rErr = 0; 335 return sal_False; // Ende und Aus 336 } 337 } 338 pCol = &(pDoc->pTab[nTab])->aCol[nCol]; 339 } while ( pCol->nCount == 0 ); 340 pCol->Search( nRow, nColRow ); 341 } 342 343 while (( nColRow < pCol->nCount ) && ( pCol->pItems[nColRow].nRow < nRow )) 344 nColRow++; 345 346 if ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow <= nEndRow ) 347 { 348 nRow = pCol->pItems[nColRow].nRow + 1; 349 if ( !bSubTotal || !pDoc->pTab[nTab]->RowFiltered( nRow-1 ) ) 350 { 351 ScBaseCell* pCell = pCol->pItems[nColRow].pCell; 352 ++nColRow; 353 switch (pCell->GetCellType()) 354 { 355 case CELLTYPE_VALUE: 356 { 357 bNumValid = sal_False; 358 rValue = ((ScValueCell*)pCell)->GetValue(); 359 rErr = 0; 360 --nRow; 361 if ( bCalcAsShown ) 362 { 363 lcl_IterGetNumberFormat( nNumFormat, pAttrArray, 364 nAttrEndRow, pCol->pAttrArray, nRow, pDoc ); 365 rValue = pDoc->RoundValueAsShown( rValue, nNumFormat ); 366 } 367 // 368 // wenn in der selben Spalte gleich noch eine Value-Cell folgt, die 369 // auch noch im Block liegt, den Wert jetzt schon holen 370 // 371 if ( nColRow < pCol->nCount && 372 pCol->pItems[nColRow].nRow <= nEndRow && 373 pCol->pItems[nColRow].pCell->GetCellType() == CELLTYPE_VALUE && 374 !bSubTotal ) 375 { 376 fNextValue = ((ScValueCell*)pCol->pItems[nColRow].pCell)->GetValue(); 377 nNextRow = pCol->pItems[nColRow].nRow; 378 bNextValid = sal_True; 379 if ( bCalcAsShown ) 380 { 381 lcl_IterGetNumberFormat( nNumFormat, pAttrArray, 382 nAttrEndRow, pCol->pAttrArray, nNextRow, pDoc ); 383 fNextValue = pDoc->RoundValueAsShown( fNextValue, nNumFormat ); 384 } 385 } 386 387 return sal_True; // gefunden 388 } 389 // break; 390 case CELLTYPE_FORMULA: 391 { 392 if (!bSubTotal || !((ScFormulaCell*)pCell)->IsSubTotal()) 393 { 394 rErr = ((ScFormulaCell*)pCell)->GetErrCode(); 395 if ( rErr || ((ScFormulaCell*)pCell)->IsValue() ) 396 { 397 rValue = ((ScFormulaCell*)pCell)->GetValue(); 398 nRow--; 399 bNumValid = sal_False; 400 return sal_True; // gefunden 401 } 402 else if ( bTextAsZero ) 403 { 404 rValue = 0.0; 405 nRow--; 406 bNumValid = sal_False; 407 return sal_True; 408 } 409 } 410 } 411 break; 412 case CELLTYPE_STRING : 413 case CELLTYPE_EDIT : 414 { 415 if ( bTextAsZero ) 416 { 417 rErr = 0; 418 rValue = 0.0; 419 nNumFmtType = NUMBERFORMAT_NUMBER; 420 nNumFmtIndex = 0; 421 bNumValid = sal_True; 422 --nRow; 423 return sal_True; 424 } 425 } 426 break; 427 default: 428 { 429 // added to avoid warnings 430 } 431 } 432 } 433 } 434 else 435 nRow = nEndRow + 1; // naechste Spalte 436 } 437 } 438 439 void ScValueIterator::GetCurNumFmtInfo( short& nType, sal_uLong& nIndex ) 440 { 441 if (!bNumValid) 442 { 443 const ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol]; 444 nNumFmtIndex = pCol->GetNumberFormat( nRow ); 445 if ( (nNumFmtIndex % SV_COUNTRY_LANGUAGE_OFFSET) == 0 ) 446 { 447 const ScBaseCell* pCell; 448 SCSIZE nIdx = nColRow - 1; 449 // there might be rearranged something, so be on the safe side 450 if ( nIdx < pCol->nCount && pCol->pItems[nIdx].nRow == nRow ) 451 pCell = pCol->pItems[nIdx].pCell; 452 else 453 { 454 if ( pCol->Search( nRow, nIdx ) ) 455 pCell = pCol->pItems[nIdx].pCell; 456 else 457 pCell = NULL; 458 } 459 if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA ) 460 ((const ScFormulaCell*)pCell)->GetFormatInfo( nNumFmtType, nNumFmtIndex ); 461 else 462 nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex ); 463 } 464 else 465 nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex ); 466 bNumValid = sal_True; 467 } 468 nType = nNumFmtType; 469 nIndex = nNumFmtIndex; 470 } 471 472 sal_Bool ScValueIterator::GetFirst(double& rValue, sal_uInt16& rErr) 473 { 474 nCol = nStartCol; 475 nRow = nStartRow; 476 nTab = nStartTab; 477 478 // nColRow = 0; 479 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol]; 480 pCol->Search( nRow, nColRow ); 481 482 nNumFormat = 0; // werden bei GetNumberFormat initialisiert 483 pAttrArray = 0; 484 nAttrEndRow = 0; 485 486 return GetThis(rValue, rErr); 487 } 488 489 /* ist inline: 490 sal_Bool ScValueIterator::GetNext(double& rValue, sal_uInt16& rErr) 491 { 492 ++nRow; 493 return GetThis(rValue, rErr); 494 } 495 */ 496 497 // ============================================================================ 498 499 ScDBQueryDataIterator::DataAccess::DataAccess(const ScDBQueryDataIterator* pParent) : 500 mpParent(pParent) 501 { 502 } 503 504 ScDBQueryDataIterator::DataAccess::~DataAccess() 505 { 506 } 507 508 SCROW ScDBQueryDataIterator::GetRowByColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCCOL nCol, SCSIZE nColRow) 509 { 510 ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol]; 511 return pCol->pItems[nColRow].nRow; 512 } 513 514 ScBaseCell* ScDBQueryDataIterator::GetCellByColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCCOL nCol, SCSIZE nColRow) 515 { 516 ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol]; 517 return pCol->pItems[nColRow].pCell; 518 } 519 520 ScAttrArray* ScDBQueryDataIterator::GetAttrArrayByCol(ScDocument& rDoc, SCTAB nTab, SCCOL nCol) 521 { 522 ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol]; 523 return pCol->pAttrArray; 524 } 525 526 bool ScDBQueryDataIterator::IsQueryValid(ScDocument& rDoc, const ScQueryParam& rParam, SCTAB nTab, SCROW nRow, ScBaseCell* pCell) 527 { 528 return rDoc.pTab[nTab]->ValidQuery(nRow, rParam, NULL, pCell); 529 } 530 531 SCSIZE ScDBQueryDataIterator::SearchColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCROW nRow, SCCOL nCol) 532 { 533 ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol]; 534 SCSIZE nColRow; 535 pCol->Search(nRow, nColRow); 536 return nColRow; 537 } 538 539 // ---------------------------------------------------------------------------- 540 541 ScDBQueryDataIterator::DataAccessInternal::DataAccessInternal(const ScDBQueryDataIterator* pParent, ScDBQueryParamInternal* pParam, ScDocument* pDoc) : 542 DataAccess(pParent), 543 mpParam(pParam), 544 mpDoc(pDoc), 545 bCalcAsShown( pDoc->GetDocOptions().IsCalcAsShown() ) 546 { 547 nCol = mpParam->mnField; 548 nRow = mpParam->nRow1; 549 nTab = mpParam->nTab; 550 551 nColRow = 0; // wird bei GetFirst initialisiert 552 SCSIZE i; 553 SCSIZE nCount = mpParam->GetEntryCount(); 554 for (i=0; (i<nCount) && (mpParam->GetEntry(i).bDoQuery); i++) 555 { 556 ScQueryEntry& rEntry = mpParam->GetEntry(i); 557 sal_uInt32 nIndex = 0; 558 rEntry.bQueryByString = 559 !(mpDoc->GetFormatTable()->IsNumberFormat(*rEntry.pStr, nIndex, rEntry.nVal)); 560 } 561 nNumFormat = 0; // werden bei GetNumberFormat initialisiert 562 pAttrArray = 0; 563 nAttrEndRow = 0; 564 } 565 566 ScDBQueryDataIterator::DataAccessInternal::~DataAccessInternal() 567 { 568 } 569 570 bool ScDBQueryDataIterator::DataAccessInternal::getCurrent(Value& rValue) 571 { 572 SCCOLROW nFirstQueryField = mpParam->GetEntry(0).nField; 573 for ( ;; ) 574 { 575 if (nRow > mpParam->nRow2) 576 { 577 // Bottom of the range reached. Bail out. 578 rValue.mnError = 0; 579 return false; 580 } 581 582 SCSIZE nCellCount = mpDoc->GetCellCount(nTab, nCol); 583 SCROW nThisRow = ScDBQueryDataIterator::GetRowByColEntryIndex(*mpDoc, nTab, nCol, nColRow); 584 while ( (nColRow < nCellCount) && (nThisRow < nRow) ) 585 nThisRow = ScDBQueryDataIterator::GetRowByColEntryIndex(*mpDoc, nTab, nCol, ++nColRow); 586 587 if ( nColRow < nCellCount && nThisRow <= mpParam->nRow2 ) 588 { 589 nRow = nThisRow; 590 ScBaseCell* pCell = NULL; 591 if (nCol == static_cast<SCCOL>(nFirstQueryField)) 592 pCell = ScDBQueryDataIterator::GetCellByColEntryIndex(*mpDoc, nTab, nCol, nColRow); 593 594 if (ScDBQueryDataIterator::IsQueryValid(*mpDoc, *mpParam, nTab, nRow, pCell)) 595 { 596 // #i109812# get cell here if it wasn't done above 597 if (nCol != static_cast<SCCOL>(nFirstQueryField)) 598 pCell = ScDBQueryDataIterator::GetCellByColEntryIndex(*mpDoc, nTab, nCol, nColRow); 599 600 switch (pCell ? pCell->GetCellType() : CELLTYPE_NONE) 601 { 602 case CELLTYPE_VALUE: 603 { 604 rValue.mfValue = ((ScValueCell*)pCell)->GetValue(); 605 rValue.mbIsNumber = true; 606 if ( bCalcAsShown ) 607 { 608 const ScAttrArray* pNewAttrArray = 609 ScDBQueryDataIterator::GetAttrArrayByCol(*mpDoc, nTab, nCol); 610 lcl_IterGetNumberFormat( nNumFormat, pAttrArray, 611 nAttrEndRow, pNewAttrArray, nRow, mpDoc ); 612 rValue.mfValue = mpDoc->RoundValueAsShown( rValue.mfValue, nNumFormat ); 613 } 614 nNumFmtType = NUMBERFORMAT_NUMBER; 615 nNumFmtIndex = 0; 616 rValue.mnError = 0; 617 return sal_True; // gefunden 618 } 619 // break; 620 case CELLTYPE_FORMULA: 621 { 622 if (((ScFormulaCell*)pCell)->IsValue()) 623 { 624 rValue.mfValue = ((ScFormulaCell*)pCell)->GetValue(); 625 rValue.mbIsNumber = true; 626 mpDoc->GetNumberFormatInfo( nNumFmtType, 627 nNumFmtIndex, ScAddress( nCol, nRow, nTab ), 628 pCell ); 629 rValue.mnError = ((ScFormulaCell*)pCell)->GetErrCode(); 630 return sal_True; // gefunden 631 } 632 else 633 nRow++; 634 } 635 break; 636 case CELLTYPE_STRING: 637 case CELLTYPE_EDIT: 638 if (mpParam->mbSkipString) 639 ++nRow; 640 else 641 { 642 rValue.maString = pCell->GetStringData(); 643 rValue.mfValue = 0.0; 644 rValue.mnError = 0; 645 rValue.mbIsNumber = false; 646 return true; 647 } 648 break; 649 default: 650 nRow++; 651 break; 652 } 653 } 654 else 655 nRow++; 656 } 657 else 658 nRow = mpParam->nRow2 + 1; // Naechste Spalte 659 } 660 // statement unreachable 661 // return false; 662 } 663 664 bool ScDBQueryDataIterator::DataAccessInternal::getFirst(Value& rValue) 665 { 666 if (mpParam->bHasHeader) 667 nRow++; 668 669 nColRow = ScDBQueryDataIterator::SearchColEntryIndex(*mpDoc, nTab, nRow, nCol); 670 return getCurrent(rValue); 671 } 672 673 bool ScDBQueryDataIterator::DataAccessInternal::getNext(Value& rValue) 674 { 675 ++nRow; 676 return getCurrent(rValue); 677 } 678 679 // ---------------------------------------------------------------------------- 680 681 ScDBQueryDataIterator::DataAccessMatrix::DataAccessMatrix(const ScDBQueryDataIterator* pParent, ScDBQueryParamMatrix* pParam) : 682 DataAccess(pParent), 683 mpParam(pParam) 684 { 685 SCSIZE nC, nR; 686 mpParam->mpMatrix->GetDimensions(nC, nR); 687 mnRows = static_cast<SCROW>(nR); 688 mnCols = static_cast<SCCOL>(nC); 689 } 690 691 ScDBQueryDataIterator::DataAccessMatrix::~DataAccessMatrix() 692 { 693 } 694 695 bool ScDBQueryDataIterator::DataAccessMatrix::getCurrent(Value& rValue) 696 { 697 // Starting from row == mnCurRow, get the first row that satisfies all the 698 // query parameters. 699 for ( ;mnCurRow < mnRows; ++mnCurRow) 700 { 701 const ScMatrix& rMat = *mpParam->mpMatrix; 702 if (rMat.IsEmpty(mpParam->mnField, mnCurRow)) 703 // Don't take empty values into account. 704 continue; 705 706 bool bIsStrVal = rMat.IsString(mpParam->mnField, mnCurRow); 707 if (bIsStrVal && mpParam->mbSkipString) 708 continue; 709 710 if (isValidQuery(mnCurRow, rMat)) 711 { 712 rValue.maString = rMat.GetString(mpParam->mnField, mnCurRow); 713 rValue.mfValue = rMat.GetDouble(mpParam->mnField, mnCurRow); 714 rValue.mbIsNumber = !bIsStrVal; 715 rValue.mnError = 0; 716 return true; 717 } 718 } 719 return false; 720 } 721 722 bool ScDBQueryDataIterator::DataAccessMatrix::getFirst(Value& rValue) 723 { 724 mnCurRow = mpParam->bHasHeader ? 1 : 0; 725 return getCurrent(rValue); 726 } 727 728 bool ScDBQueryDataIterator::DataAccessMatrix::getNext(Value& rValue) 729 { 730 ++mnCurRow; 731 return getCurrent(rValue); 732 } 733 734 namespace { 735 736 bool lcl_isQueryByValue(const ScQueryEntry& rEntry, const ScMatrix& rMat, SCSIZE nCol, SCSIZE nRow) 737 { 738 if (rEntry.bQueryByString) 739 return false; 740 741 if (!rMat.IsValueOrEmpty(nCol, nRow)) 742 return false; 743 744 return true; 745 } 746 747 bool lcl_isQueryByString(const ScQueryEntry& rEntry, const ScMatrix& rMat, SCSIZE nCol, SCSIZE nRow) 748 { 749 switch (rEntry.eOp) 750 { 751 case SC_EQUAL: 752 case SC_NOT_EQUAL: 753 case SC_CONTAINS: 754 case SC_DOES_NOT_CONTAIN: 755 case SC_BEGINS_WITH: 756 case SC_ENDS_WITH: 757 case SC_DOES_NOT_BEGIN_WITH: 758 case SC_DOES_NOT_END_WITH: 759 return true; 760 default: 761 ; 762 } 763 764 if (rEntry.bQueryByString && rMat.IsString(nCol, nRow)) 765 return true; 766 767 return false; 768 } 769 770 } 771 772 bool ScDBQueryDataIterator::DataAccessMatrix::isValidQuery(SCROW nRow, const ScMatrix& rMat) const 773 { 774 SCSIZE nEntryCount = mpParam->GetEntryCount(); 775 vector<bool> aResults; 776 aResults.reserve(nEntryCount); 777 778 const CollatorWrapper& rCollator = 779 mpParam->bCaseSens ? *ScGlobal::GetCaseCollator() : *ScGlobal::GetCollator(); 780 781 for (SCSIZE i = 0; i < nEntryCount; ++i) 782 { 783 const ScQueryEntry& rEntry = mpParam->GetEntry(i); 784 if (!rEntry.bDoQuery) 785 continue; 786 787 switch (rEntry.eOp) 788 { 789 case SC_EQUAL: 790 case SC_LESS: 791 case SC_GREATER: 792 case SC_LESS_EQUAL: 793 case SC_GREATER_EQUAL: 794 case SC_NOT_EQUAL: 795 break; 796 default: 797 // Only the above operators are supported. 798 continue; 799 } 800 801 bool bValid = false; 802 803 SCSIZE nField = static_cast<SCSIZE>(rEntry.nField); 804 if (lcl_isQueryByValue(rEntry, rMat, nField, nRow)) 805 { 806 // By value 807 double fMatVal = rMat.GetDouble(nField, nRow); 808 bool bEqual = approxEqual(fMatVal, rEntry.nVal); 809 switch (rEntry.eOp) 810 { 811 case SC_EQUAL: 812 bValid = bEqual; 813 break; 814 case SC_LESS: 815 bValid = (fMatVal < rEntry.nVal) && !bEqual; 816 break; 817 case SC_GREATER: 818 bValid = (fMatVal > rEntry.nVal) && !bEqual; 819 break; 820 case SC_LESS_EQUAL: 821 bValid = (fMatVal < rEntry.nVal) || bEqual; 822 break; 823 case SC_GREATER_EQUAL: 824 bValid = (fMatVal > rEntry.nVal) || bEqual; 825 break; 826 case SC_NOT_EQUAL: 827 bValid = !bEqual; 828 break; 829 default: 830 ; 831 } 832 } 833 else if (lcl_isQueryByString(rEntry, rMat, nField, nRow)) 834 { 835 // By string 836 do 837 { 838 if (!rEntry.pStr) 839 break; 840 841 // Equality check first. 842 843 OUString aMatStr = rMat.GetString(nField, nRow); 844 lcl_toUpper(aMatStr); 845 OUString aQueryStr = *rEntry.pStr; 846 lcl_toUpper(aQueryStr); 847 bool bDone = false; 848 switch (rEntry.eOp) 849 { 850 case SC_EQUAL: 851 bValid = aMatStr.equals(aQueryStr); 852 bDone = true; 853 break; 854 case SC_NOT_EQUAL: 855 bValid = !aMatStr.equals(aQueryStr); 856 bDone = true; 857 break; 858 default: 859 ; 860 } 861 862 if (bDone) 863 break; 864 865 // Unequality check using collator. 866 867 sal_Int32 nCompare = rCollator.compareString(aMatStr, aQueryStr); 868 switch (rEntry.eOp) 869 { 870 case SC_LESS : 871 bValid = (nCompare < 0); 872 break; 873 case SC_GREATER : 874 bValid = (nCompare > 0); 875 break; 876 case SC_LESS_EQUAL : 877 bValid = (nCompare <= 0); 878 break; 879 case SC_GREATER_EQUAL : 880 bValid = (nCompare >= 0); 881 break; 882 default: 883 ; 884 } 885 } 886 while (false); 887 } 888 else if (mpParam->bMixedComparison) 889 { 890 // Not used at the moment. 891 } 892 893 if (aResults.empty()) 894 // First query entry. 895 aResults.push_back(bValid); 896 else if (rEntry.eConnect == SC_AND) 897 { 898 // For AND op, tuck the result into the last result value. 899 size_t n = aResults.size(); 900 aResults[n-1] = aResults[n-1] && bValid; 901 } 902 else 903 // For OR op, store its own result. 904 aResults.push_back(bValid); 905 } 906 907 // Row is valid as long as there is at least one result being true. 908 vector<bool>::const_iterator itr = aResults.begin(), itrEnd = aResults.end(); 909 for (; itr != itrEnd; ++itr) 910 if (*itr) 911 return true; 912 913 return false; 914 } 915 916 // ---------------------------------------------------------------------------- 917 918 ScDBQueryDataIterator::Value::Value() : 919 mnError(0), mbIsNumber(true) 920 { 921 ::rtl::math::setNan(&mfValue); 922 } 923 924 // ---------------------------------------------------------------------------- 925 926 ScDBQueryDataIterator::ScDBQueryDataIterator(ScDocument* pDocument, ScDBQueryParamBase* pParam) : 927 mpParam (pParam) 928 { 929 switch (mpParam->GetType()) 930 { 931 case ScDBQueryParamBase::INTERNAL: 932 { 933 ScDBQueryParamInternal* p = static_cast<ScDBQueryParamInternal*>(pParam); 934 mpData.reset(new DataAccessInternal(this, p, pDocument)); 935 } 936 break; 937 case ScDBQueryParamBase::MATRIX: 938 { 939 ScDBQueryParamMatrix* p = static_cast<ScDBQueryParamMatrix*>(pParam); 940 mpData.reset(new DataAccessMatrix(this, p)); 941 } 942 } 943 } 944 945 bool ScDBQueryDataIterator::GetFirst(Value& rValue) 946 { 947 return mpData->getFirst(rValue); 948 } 949 950 bool ScDBQueryDataIterator::GetNext(Value& rValue) 951 { 952 return mpData->getNext(rValue); 953 } 954 955 // ============================================================================ 956 957 ScCellIterator::ScCellIterator( ScDocument* pDocument, 958 SCCOL nSCol, SCROW nSRow, SCTAB nSTab, 959 SCCOL nECol, SCROW nERow, SCTAB nETab, sal_Bool bSTotal ) : 960 pDoc( pDocument ), 961 nStartCol( nSCol), 962 nStartRow( nSRow), 963 nStartTab( nSTab ), 964 nEndCol( nECol ), 965 nEndRow( nERow), 966 nEndTab( nETab ), 967 bSubTotal(bSTotal) 968 969 { 970 PutInOrder( nStartCol, nEndCol); 971 PutInOrder( nStartRow, nEndRow); 972 PutInOrder( nStartTab, nEndTab ); 973 974 if (!ValidCol(nStartCol)) nStartCol = MAXCOL; 975 if (!ValidCol(nEndCol)) nEndCol = MAXCOL; 976 if (!ValidRow(nStartRow)) nStartRow = MAXROW; 977 if (!ValidRow(nEndRow)) nEndRow = MAXROW; 978 if (!ValidTab(nStartTab)) nStartTab = MAXTAB; 979 if (!ValidTab(nEndTab)) nEndTab = MAXTAB; 980 981 while (nEndTab>0 && !pDoc->pTab[nEndTab]) 982 --nEndTab; // nur benutzte Tabellen 983 if (nStartTab>nEndTab) 984 nStartTab = nEndTab; 985 986 nCol = nStartCol; 987 nRow = nStartRow; 988 nTab = nStartTab; 989 nColRow = 0; // wird bei GetFirst initialisiert 990 991 if (!pDoc->pTab[nTab]) 992 { 993 DBG_ERROR("Tabelle nicht gefunden"); 994 nStartCol = nCol = MAXCOL+1; 995 nStartRow = nRow = MAXROW+1; 996 nStartTab = nTab = MAXTAB+1; // -> Abbruch bei GetFirst 997 } 998 } 999 1000 ScCellIterator::ScCellIterator 1001 ( ScDocument* pDocument, const ScRange& rRange, sal_Bool bSTotal ) : 1002 pDoc( pDocument ), 1003 nStartCol( rRange.aStart.Col() ), 1004 nStartRow( rRange.aStart.Row() ), 1005 nStartTab( rRange.aStart.Tab() ), 1006 nEndCol( rRange.aEnd.Col() ), 1007 nEndRow( rRange.aEnd.Row() ), 1008 nEndTab( rRange.aEnd.Tab() ), 1009 bSubTotal(bSTotal) 1010 1011 { 1012 PutInOrder( nStartCol, nEndCol); 1013 PutInOrder( nStartRow, nEndRow); 1014 PutInOrder( nStartTab, nEndTab ); 1015 1016 if (!ValidCol(nStartCol)) nStartCol = MAXCOL; 1017 if (!ValidCol(nEndCol)) nEndCol = MAXCOL; 1018 if (!ValidRow(nStartRow)) nStartRow = MAXROW; 1019 if (!ValidRow(nEndRow)) nEndRow = MAXROW; 1020 if (!ValidTab(nStartTab)) nStartTab = MAXTAB; 1021 if (!ValidTab(nEndTab)) nEndTab = MAXTAB; 1022 1023 while (nEndTab>0 && !pDoc->pTab[nEndTab]) 1024 --nEndTab; // nur benutzte Tabellen 1025 if (nStartTab>nEndTab) 1026 nStartTab = nEndTab; 1027 1028 nCol = nStartCol; 1029 nRow = nStartRow; 1030 nTab = nStartTab; 1031 nColRow = 0; // wird bei GetFirst initialisiert 1032 1033 if (!pDoc->pTab[nTab]) 1034 { 1035 DBG_ERROR("Tabelle nicht gefunden"); 1036 nStartCol = nCol = MAXCOL+1; 1037 nStartRow = nRow = MAXROW+1; 1038 nStartTab = nTab = MAXTAB+1; // -> Abbruch bei GetFirst 1039 } 1040 } 1041 1042 ScBaseCell* ScCellIterator::GetThis() 1043 { 1044 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol]; 1045 for ( ;; ) 1046 { 1047 if ( nRow > nEndRow ) 1048 { 1049 nRow = nStartRow; 1050 do 1051 { 1052 nCol++; 1053 if ( nCol > nEndCol ) 1054 { 1055 nCol = nStartCol; 1056 nTab++; 1057 if ( nTab > nEndTab ) 1058 return NULL; // Ende und Aus 1059 } 1060 pCol = &(pDoc->pTab[nTab])->aCol[nCol]; 1061 } while ( pCol->nCount == 0 ); 1062 pCol->Search( nRow, nColRow ); 1063 } 1064 1065 while ( (nColRow < pCol->nCount) && (pCol->pItems[nColRow].nRow < nRow) ) 1066 nColRow++; 1067 1068 if ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow <= nEndRow ) 1069 { 1070 nRow = pCol->pItems[nColRow].nRow; 1071 if ( !bSubTotal || !pDoc->pTab[nTab]->RowFiltered( nRow ) ) 1072 { 1073 ScBaseCell* pCell = pCol->pItems[nColRow].pCell; 1074 1075 if ( bSubTotal && pCell->GetCellType() == CELLTYPE_FORMULA 1076 && ((ScFormulaCell*)pCell)->IsSubTotal() ) 1077 nRow++; // Sub-Total-Zeilen nicht 1078 else 1079 return pCell; // gefunden 1080 } 1081 else 1082 nRow++; 1083 } 1084 else 1085 nRow = nEndRow + 1; // Naechste Spalte 1086 } 1087 } 1088 1089 ScBaseCell* ScCellIterator::GetFirst() 1090 { 1091 if ( !ValidTab(nTab) ) 1092 return NULL; 1093 nCol = nStartCol; 1094 nRow = nStartRow; 1095 nTab = nStartTab; 1096 // nColRow = 0; 1097 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol]; 1098 pCol->Search( nRow, nColRow ); 1099 return GetThis(); 1100 } 1101 1102 ScBaseCell* ScCellIterator::GetNext() 1103 { 1104 ++nRow; 1105 return GetThis(); 1106 } 1107 1108 //------------------------------------------------------------------------------- 1109 1110 ScQueryCellIterator::ScQueryCellIterator(ScDocument* pDocument, SCTAB nTable, 1111 const ScQueryParam& rParam, sal_Bool bMod ) : 1112 aParam (rParam), 1113 pDoc( pDocument ), 1114 nTab( nTable), 1115 nStopOnMismatch( nStopOnMismatchDisabled ), 1116 nTestEqualCondition( nTestEqualConditionDisabled ), 1117 bAdvanceQuery( sal_False ), 1118 bIgnoreMismatchOnLeadingStrings( sal_False ) 1119 { 1120 nCol = aParam.nCol1; 1121 nRow = aParam.nRow1; 1122 nColRow = 0; // wird bei GetFirst initialisiert 1123 SCSIZE i; 1124 if (bMod) // sonst schon eingetragen 1125 { 1126 for (i=0; (i<MAXQUERY) && (aParam.GetEntry(i).bDoQuery); i++) 1127 { 1128 ScQueryEntry& rEntry = aParam.GetEntry(i); 1129 sal_uInt32 nIndex = 0; 1130 rEntry.bQueryByString = 1131 !(pDoc->GetFormatTable()->IsNumberFormat(*rEntry.pStr, 1132 nIndex, rEntry.nVal)); 1133 } 1134 } 1135 nNumFormat = 0; // werden bei GetNumberFormat initialisiert 1136 pAttrArray = 0; 1137 nAttrEndRow = 0; 1138 } 1139 1140 ScBaseCell* ScQueryCellIterator::GetThis() 1141 { 1142 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol]; 1143 const ScQueryEntry& rEntry = aParam.GetEntry(0); 1144 SCCOLROW nFirstQueryField = rEntry.nField; 1145 bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings && 1146 !rEntry.bQueryByString; 1147 bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings && 1148 !aParam.bHasHeader && rEntry.bQueryByString && 1149 ((aParam.bByRow && nRow == aParam.nRow1) || 1150 (!aParam.bByRow && nCol == aParam.nCol1)); 1151 for ( ;; ) 1152 { 1153 if ( nRow > aParam.nRow2 ) 1154 { 1155 nRow = aParam.nRow1; 1156 if (aParam.bHasHeader && aParam.bByRow) 1157 nRow++; 1158 do 1159 { 1160 if ( ++nCol > aParam.nCol2 ) 1161 return NULL; // Ende und Aus 1162 if ( bAdvanceQuery ) 1163 { 1164 AdvanceQueryParamEntryField(); 1165 nFirstQueryField = rEntry.nField; 1166 } 1167 pCol = &(pDoc->pTab[nTab])->aCol[nCol]; 1168 } while ( pCol->nCount == 0 ); 1169 pCol->Search( nRow, nColRow ); 1170 bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings && 1171 !aParam.bHasHeader && rEntry.bQueryByString && 1172 aParam.bByRow; 1173 } 1174 1175 while ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow < nRow ) 1176 nColRow++; 1177 1178 if ( nColRow < pCol->nCount && 1179 (nRow = pCol->pItems[nColRow].nRow) <= aParam.nRow2 ) 1180 { 1181 ScBaseCell* pCell = pCol->pItems[nColRow].pCell; 1182 if ( pCell->GetCellType() == CELLTYPE_NOTE ) 1183 ++nRow; 1184 else if (bAllStringIgnore && pCell->HasStringData()) 1185 ++nRow; 1186 else 1187 { 1188 sal_Bool bTestEqualCondition; 1189 if ( (pDoc->pTab[nTab])->ValidQuery( nRow, aParam, NULL, 1190 (nCol == static_cast<SCCOL>(nFirstQueryField) ? pCell : NULL), 1191 (nTestEqualCondition ? &bTestEqualCondition : NULL) ) ) 1192 { 1193 if ( nTestEqualCondition && bTestEqualCondition ) 1194 nTestEqualCondition |= nTestEqualConditionMatched; 1195 return pCell; // found 1196 } 1197 else if ( nStopOnMismatch ) 1198 { 1199 // Yes, even a mismatch may have a fulfilled equal 1200 // condition if regular expressions were involved and 1201 // SC_LESS_EQUAL or SC_GREATER_EQUAL were queried. 1202 if ( nTestEqualCondition && bTestEqualCondition ) 1203 { 1204 nTestEqualCondition |= nTestEqualConditionMatched; 1205 nStopOnMismatch |= nStopOnMismatchOccured; 1206 return NULL; 1207 } 1208 bool bStop; 1209 if (bFirstStringIgnore) 1210 { 1211 if (pCell->HasStringData()) 1212 { 1213 ++nRow; 1214 bStop = false; 1215 } 1216 else 1217 bStop = true; 1218 } 1219 else 1220 bStop = true; 1221 if (bStop) 1222 { 1223 nStopOnMismatch |= nStopOnMismatchOccured; 1224 return NULL; 1225 } 1226 } 1227 else 1228 nRow++; 1229 } 1230 } 1231 else 1232 nRow = aParam.nRow2 + 1; // Naechste Spalte 1233 bFirstStringIgnore = false; 1234 } 1235 } 1236 1237 ScBaseCell* ScQueryCellIterator::GetFirst() 1238 { 1239 nCol = aParam.nCol1; 1240 nRow = aParam.nRow1; 1241 if (aParam.bHasHeader) 1242 nRow++; 1243 // nColRow = 0; 1244 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol]; 1245 pCol->Search( nRow, nColRow ); 1246 return GetThis(); 1247 } 1248 1249 ScBaseCell* ScQueryCellIterator::GetNext() 1250 { 1251 ++nRow; 1252 if ( nStopOnMismatch ) 1253 nStopOnMismatch = nStopOnMismatchEnabled; 1254 if ( nTestEqualCondition ) 1255 nTestEqualCondition = nTestEqualConditionEnabled; 1256 return GetThis(); 1257 } 1258 1259 void ScQueryCellIterator::AdvanceQueryParamEntryField() 1260 { 1261 SCSIZE nEntries = aParam.GetEntryCount(); 1262 for ( SCSIZE j = 0; j < nEntries; j++ ) 1263 { 1264 ScQueryEntry& rEntry = aParam.GetEntry( j ); 1265 if ( rEntry.bDoQuery ) 1266 { 1267 if ( rEntry.nField < MAXCOL ) 1268 rEntry.nField++; 1269 else 1270 { 1271 DBG_ERRORFILE( "AdvanceQueryParamEntryField: ++rEntry.nField > MAXCOL" ); 1272 } 1273 } 1274 else 1275 break; // for 1276 } 1277 } 1278 1279 1280 sal_Bool ScQueryCellIterator::FindEqualOrSortedLastInRange( SCCOL& nFoundCol, 1281 SCROW& nFoundRow, sal_Bool bSearchForEqualAfterMismatch, 1282 sal_Bool bIgnoreMismatchOnLeadingStringsP ) 1283 { 1284 nFoundCol = MAXCOL+1; 1285 nFoundRow = MAXROW+1; 1286 SetStopOnMismatch( sal_True ); // assume sorted keys 1287 SetTestEqualCondition( sal_True ); 1288 bIgnoreMismatchOnLeadingStrings = bIgnoreMismatchOnLeadingStringsP; 1289 bool bRegExp = aParam.bRegExp && aParam.GetEntry(0).bQueryByString; 1290 bool bBinary = !bRegExp && aParam.bByRow && (aParam.GetEntry(0).eOp == 1291 SC_LESS_EQUAL || aParam.GetEntry(0).eOp == SC_GREATER_EQUAL); 1292 if (bBinary ? (BinarySearch() ? GetThis() : 0) : GetFirst()) 1293 { 1294 // First equal entry or last smaller than (greater than) entry. 1295 SCSIZE nColRowSave; 1296 ScBaseCell* pNext = 0; 1297 do 1298 { 1299 nFoundCol = GetCol(); 1300 nFoundRow = GetRow(); 1301 nColRowSave = nColRow; 1302 } while ( !IsEqualConditionFulfilled() && (pNext = GetNext()) != NULL ); 1303 // There may be no pNext but equal condition fulfilled if regular 1304 // expressions are involved. Keep the found entry and proceed. 1305 if (!pNext && !IsEqualConditionFulfilled()) 1306 { 1307 // Step back to last in range and adjust position markers for 1308 // GetNumberFormat() or similar. 1309 nCol = nFoundCol; 1310 nRow = nFoundRow; 1311 nColRow = nColRowSave; 1312 } 1313 } 1314 if ( IsEqualConditionFulfilled() ) 1315 { 1316 // Position on last equal entry. 1317 SCSIZE nEntries = aParam.GetEntryCount(); 1318 for ( SCSIZE j = 0; j < nEntries; j++ ) 1319 { 1320 ScQueryEntry& rEntry = aParam.GetEntry( j ); 1321 if ( rEntry.bDoQuery ) 1322 { 1323 switch ( rEntry.eOp ) 1324 { 1325 case SC_LESS_EQUAL : 1326 case SC_GREATER_EQUAL : 1327 rEntry.eOp = SC_EQUAL; 1328 break; 1329 default: 1330 { 1331 // added to avoid warnings 1332 } 1333 } 1334 } 1335 else 1336 break; // for 1337 } 1338 SCSIZE nColRowSave; 1339 bIgnoreMismatchOnLeadingStrings = sal_False; 1340 SetTestEqualCondition( sal_False ); 1341 do 1342 { 1343 nFoundCol = GetCol(); 1344 nFoundRow = GetRow(); 1345 nColRowSave = nColRow; 1346 } while (GetNext()); 1347 // Step back conditions same as above 1348 nCol = nFoundCol; 1349 nRow = nFoundRow; 1350 nColRow = nColRowSave; 1351 return sal_True; 1352 } 1353 if ( (bSearchForEqualAfterMismatch || aParam.bRegExp) && 1354 StoppedOnMismatch() ) 1355 { 1356 // Assume found entry to be the last value less than respectively 1357 // greater than the query. But keep on searching for an equal match. 1358 SCSIZE nEntries = aParam.GetEntryCount(); 1359 for ( SCSIZE j = 0; j < nEntries; j++ ) 1360 { 1361 ScQueryEntry& rEntry = aParam.GetEntry( j ); 1362 if ( rEntry.bDoQuery ) 1363 { 1364 switch ( rEntry.eOp ) 1365 { 1366 case SC_LESS_EQUAL : 1367 case SC_GREATER_EQUAL : 1368 rEntry.eOp = SC_EQUAL; 1369 break; 1370 default: 1371 { 1372 // added to avoid warnings 1373 } 1374 } 1375 } 1376 else 1377 break; // for 1378 } 1379 SetStopOnMismatch( sal_False ); 1380 SetTestEqualCondition( sal_False ); 1381 if (GetNext()) 1382 { 1383 // Last of a consecutive area, avoid searching the entire parameter 1384 // range as it is a real performance bottleneck in case of regular 1385 // expressions. 1386 SCSIZE nColRowSave; 1387 do 1388 { 1389 nFoundCol = GetCol(); 1390 nFoundRow = GetRow(); 1391 nColRowSave = nColRow; 1392 SetStopOnMismatch( sal_True ); 1393 } while (GetNext()); 1394 nCol = nFoundCol; 1395 nRow = nFoundRow; 1396 nColRow = nColRowSave; 1397 } 1398 } 1399 return (nFoundCol <= MAXCOL) && (nFoundRow <= MAXROW); 1400 } 1401 1402 1403 ScBaseCell* ScQueryCellIterator::BinarySearch() 1404 { 1405 nCol = aParam.nCol1; 1406 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol]; 1407 if (!pCol->nCount) 1408 return 0; 1409 1410 ScBaseCell* pCell; 1411 SCSIZE nHi, nLo; 1412 CollatorWrapper* pCollator = (aParam.bCaseSens ? ScGlobal::GetCaseCollator() : 1413 ScGlobal::GetCollator()); 1414 SvNumberFormatter& rFormatter = *(pDoc->GetFormatTable()); 1415 const ScQueryEntry& rEntry = aParam.GetEntry(0); 1416 bool bLessEqual = rEntry.eOp == SC_LESS_EQUAL; 1417 bool bByString = rEntry.bQueryByString; 1418 bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings && !bByString; 1419 bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings && 1420 !aParam.bHasHeader && bByString; 1421 1422 nRow = aParam.nRow1; 1423 if (aParam.bHasHeader) 1424 nRow++; 1425 const ColEntry* pItems = pCol->pItems; 1426 if (pCol->Search( nRow, nLo ) && bFirstStringIgnore && 1427 pItems[nLo].pCell->HasStringData()) 1428 { 1429 String aCellStr; 1430 sal_uLong nFormat = pCol->GetNumberFormat( pItems[nLo].nRow); 1431 ScCellFormat::GetInputString( pItems[nLo].pCell, nFormat, aCellStr, 1432 rFormatter); 1433 sal_Int32 nTmp = pCollator->compareString( aCellStr, *rEntry.pStr); 1434 if ((rEntry.eOp == SC_LESS_EQUAL && nTmp > 0) || 1435 (rEntry.eOp == SC_GREATER_EQUAL && nTmp < 0) || 1436 (rEntry.eOp == SC_EQUAL && nTmp != 0)) 1437 ++nLo; 1438 } 1439 if (!pCol->Search( aParam.nRow2, nHi ) && nHi>0) 1440 --nHi; 1441 while (bAllStringIgnore && nLo <= nHi && nLo < pCol->nCount && 1442 pItems[nLo].pCell->HasStringData()) 1443 ++nLo; 1444 1445 // Bookkeeping values for breaking up the binary search in case the data 1446 // range isn't strictly sorted. 1447 SCSIZE nLastInRange = nLo; 1448 SCSIZE nFirstLastInRange = nLastInRange; 1449 double fLastInRangeValue = bLessEqual ? 1450 -(::std::numeric_limits<double>::max()) : 1451 ::std::numeric_limits<double>::max(); 1452 String aLastInRangeString; 1453 if (!bLessEqual) 1454 aLastInRangeString.Assign( sal_Unicode(0xFFFF)); 1455 if (nLastInRange < pCol->nCount) 1456 { 1457 pCell = pItems[nLastInRange].pCell; 1458 if (pCell->HasStringData()) 1459 { 1460 sal_uLong nFormat = pCol->GetNumberFormat( pItems[nLastInRange].nRow); 1461 ScCellFormat::GetInputString( pCell, nFormat, aLastInRangeString, 1462 rFormatter); 1463 } 1464 else 1465 { 1466 switch ( pCell->GetCellType() ) 1467 { 1468 case CELLTYPE_VALUE : 1469 fLastInRangeValue = 1470 static_cast<ScValueCell*>(pCell)->GetValue(); 1471 break; 1472 case CELLTYPE_FORMULA : 1473 fLastInRangeValue = 1474 static_cast<ScFormulaCell*>(pCell)->GetValue(); 1475 break; 1476 default: 1477 { 1478 // added to avoid warnings 1479 } 1480 } 1481 } 1482 } 1483 1484 sal_Int32 nRes = 0; 1485 bool bFound = false; 1486 bool bDone = false; 1487 while (nLo <= nHi && !bDone) 1488 { 1489 SCSIZE nMid = (nLo+nHi)/2; 1490 SCSIZE i = nMid; 1491 while (i <= nHi && pItems[i].pCell->GetCellType() == CELLTYPE_NOTE) 1492 ++i; 1493 if (i > nHi) 1494 { 1495 if (nMid > 0) 1496 nHi = nMid - 1; 1497 else 1498 bDone = true; 1499 continue; // while 1500 } 1501 sal_Bool bStr = pItems[i].pCell->HasStringData(); 1502 nRes = 0; 1503 // compares are content<query:-1, content>query:1 1504 // Cell value comparison similar to ScTable::ValidQuery() 1505 if (!bStr && !bByString) 1506 { 1507 double nCellVal; 1508 pCell = pItems[i].pCell; 1509 switch ( pCell->GetCellType() ) 1510 { 1511 case CELLTYPE_VALUE : 1512 nCellVal = static_cast<ScValueCell*>(pCell)->GetValue(); 1513 break; 1514 case CELLTYPE_FORMULA : 1515 nCellVal = static_cast<ScFormulaCell*>(pCell)->GetValue(); 1516 break; 1517 default: 1518 nCellVal = 0.0; 1519 } 1520 if ((nCellVal < rEntry.nVal) && !::rtl::math::approxEqual( 1521 nCellVal, rEntry.nVal)) 1522 { 1523 nRes = -1; 1524 if (bLessEqual) 1525 { 1526 if (fLastInRangeValue < nCellVal) 1527 { 1528 fLastInRangeValue = nCellVal; 1529 nLastInRange = i; 1530 } 1531 else if (fLastInRangeValue > nCellVal) 1532 { 1533 // not strictly sorted, continue with GetThis() 1534 nLastInRange = nFirstLastInRange; 1535 bDone = true; 1536 } 1537 } 1538 } 1539 else if ((nCellVal > rEntry.nVal) && !::rtl::math::approxEqual( 1540 nCellVal, rEntry.nVal)) 1541 { 1542 nRes = 1; 1543 if (!bLessEqual) 1544 { 1545 if (fLastInRangeValue > nCellVal) 1546 { 1547 fLastInRangeValue = nCellVal; 1548 nLastInRange = i; 1549 } 1550 else if (fLastInRangeValue < nCellVal) 1551 { 1552 // not strictly sorted, continue with GetThis() 1553 nLastInRange = nFirstLastInRange; 1554 bDone = true; 1555 } 1556 } 1557 } 1558 } 1559 else if (bStr && bByString) 1560 { 1561 String aCellStr; 1562 sal_uLong nFormat = pCol->GetNumberFormat( pItems[i].nRow); 1563 ScCellFormat::GetInputString( pItems[i].pCell, nFormat, aCellStr, 1564 rFormatter); 1565 nRes = pCollator->compareString( aCellStr, *rEntry.pStr); 1566 if (nRes < 0 && bLessEqual) 1567 { 1568 sal_Int32 nTmp = pCollator->compareString( aLastInRangeString, 1569 aCellStr); 1570 if (nTmp < 0) 1571 { 1572 aLastInRangeString = aCellStr; 1573 nLastInRange = i; 1574 } 1575 else if (nTmp > 0) 1576 { 1577 // not strictly sorted, continue with GetThis() 1578 nLastInRange = nFirstLastInRange; 1579 bDone = true; 1580 } 1581 } 1582 else if (nRes > 0 && !bLessEqual) 1583 { 1584 sal_Int32 nTmp = pCollator->compareString( aLastInRangeString, 1585 aCellStr); 1586 if (nTmp > 0) 1587 { 1588 aLastInRangeString = aCellStr; 1589 nLastInRange = i; 1590 } 1591 else if (nTmp < 0) 1592 { 1593 // not strictly sorted, continue with GetThis() 1594 nLastInRange = nFirstLastInRange; 1595 bDone = true; 1596 } 1597 } 1598 } 1599 else if (!bStr && bByString) 1600 { 1601 nRes = -1; // numeric < string 1602 if (bLessEqual) 1603 nLastInRange = i; 1604 } 1605 else // if (bStr && !bByString) 1606 { 1607 nRes = 1; // string > numeric 1608 if (!bLessEqual) 1609 nLastInRange = i; 1610 } 1611 if (nRes < 0) 1612 { 1613 if (bLessEqual) 1614 nLo = nMid + 1; 1615 else // assumed to be SC_GREATER_EQUAL 1616 { 1617 if (nMid > 0) 1618 nHi = nMid - 1; 1619 else 1620 bDone = true; 1621 } 1622 } 1623 else if (nRes > 0) 1624 { 1625 if (bLessEqual) 1626 { 1627 if (nMid > 0) 1628 nHi = nMid - 1; 1629 else 1630 bDone = true; 1631 } 1632 else // assumed to be SC_GREATER_EQUAL 1633 nLo = nMid + 1; 1634 } 1635 else 1636 { 1637 nLo = i; 1638 bDone = bFound = true; 1639 } 1640 } 1641 if (!bFound) 1642 { 1643 // If all hits didn't result in a moving limit there's something 1644 // strange, e.g. data range not properly sorted, or only identical 1645 // values encountered, which doesn't mean there aren't any others in 1646 // between.. leave it to GetThis(). The condition for this would be 1647 // if (nLastInRange == nFirstLastInRange) nLo = nFirstLastInRange; 1648 // Else, in case no exact match was found, we step back for a 1649 // subsequent GetThis() to find the last in range. Effectively this is 1650 // --nLo with nLastInRange == nLo-1. Both conditions combined yield: 1651 nLo = nLastInRange; 1652 } 1653 if (nLo < pCol->nCount && pCol->pItems[nLo].nRow <= aParam.nRow2) 1654 { 1655 nRow = pItems[nLo].nRow; 1656 pCell = pItems[nLo].pCell; 1657 nColRow = nLo; 1658 } 1659 else 1660 { 1661 nRow = aParam.nRow2 + 1; 1662 pCell = 0; 1663 nColRow = pCol->nCount - 1; 1664 } 1665 return pCell; 1666 } 1667 1668 1669 //------------------------------------------------------------------------------- 1670 1671 ScHorizontalCellIterator::ScHorizontalCellIterator(ScDocument* pDocument, SCTAB nTable, 1672 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) : 1673 pDoc( pDocument ), 1674 nTab( nTable ), 1675 nStartCol( nCol1 ), 1676 nEndCol( nCol2 ), 1677 nStartRow( nRow1 ), 1678 nEndRow( nRow2 ), 1679 nCol( nCol1 ), 1680 nRow( nRow1 ), 1681 bMore( sal_True ) 1682 { 1683 1684 pNextRows = new SCROW[ nCol2-nCol1+1 ]; 1685 pNextIndices = new SCSIZE[ nCol2-nCol1+1 ]; 1686 1687 SetTab( nTab ); 1688 } 1689 1690 ScHorizontalCellIterator::~ScHorizontalCellIterator() 1691 { 1692 delete [] pNextRows; 1693 delete [] pNextIndices; 1694 } 1695 1696 void ScHorizontalCellIterator::SetTab( SCTAB nTabP ) 1697 { 1698 nTab = nTabP; 1699 nRow = nStartRow; 1700 nCol = nStartCol; 1701 bMore = sal_True; 1702 1703 for (SCCOL i=nStartCol; i<=nEndCol; i++) 1704 { 1705 ScColumn* pCol = &pDoc->pTab[nTab]->aCol[i]; 1706 1707 SCSIZE nIndex; 1708 pCol->Search( nStartRow, nIndex ); 1709 if ( nIndex < pCol->nCount ) 1710 { 1711 pNextRows[i-nStartCol] = pCol->pItems[nIndex].nRow; 1712 pNextIndices[i-nStartCol] = nIndex; 1713 } 1714 else 1715 { 1716 pNextRows[i-nStartCol] = MAXROWCOUNT; // nichts gefunden 1717 pNextIndices[i-nStartCol] = MAXROWCOUNT; 1718 } 1719 } 1720 1721 if (pNextRows[0] != nStartRow) 1722 Advance(); 1723 } 1724 1725 ScBaseCell* ScHorizontalCellIterator::GetNext( SCCOL& rCol, SCROW& rRow ) 1726 { 1727 if ( bMore ) 1728 { 1729 rCol = nCol; 1730 rRow = nRow; 1731 1732 ScColumn* pCol = &pDoc->pTab[nTab]->aCol[nCol]; 1733 SCSIZE nIndex = pNextIndices[nCol-nStartCol]; 1734 DBG_ASSERT( nIndex < pCol->nCount, "ScHorizontalCellIterator::GetNext: nIndex out of range" ); 1735 ScBaseCell* pCell = pCol->pItems[nIndex].pCell; 1736 if ( ++nIndex < pCol->nCount ) 1737 { 1738 pNextRows[nCol-nStartCol] = pCol->pItems[nIndex].nRow; 1739 pNextIndices[nCol-nStartCol] = nIndex; 1740 } 1741 else 1742 { 1743 pNextRows[nCol-nStartCol] = MAXROWCOUNT; // nichts gefunden 1744 pNextIndices[nCol-nStartCol] = MAXROWCOUNT; 1745 } 1746 1747 Advance(); 1748 return pCell; 1749 } 1750 else 1751 return NULL; 1752 } 1753 1754 sal_Bool ScHorizontalCellIterator::ReturnNext( SCCOL& rCol, SCROW& rRow ) 1755 { 1756 rCol = nCol; 1757 rRow = nRow; 1758 return bMore; 1759 } 1760 1761 void ScHorizontalCellIterator::Advance() 1762 { 1763 sal_Bool bFound = sal_False; 1764 SCCOL i; 1765 1766 for (i=nCol+1; i<=nEndCol && !bFound; i++) 1767 if (pNextRows[i-nStartCol] == nRow) 1768 { 1769 nCol = i; 1770 bFound = sal_True; 1771 } 1772 1773 if (!bFound) 1774 { 1775 SCROW nMinRow = MAXROW+1; 1776 for (i=nStartCol; i<=nEndCol; i++) 1777 if (pNextRows[i-nStartCol] < nMinRow) 1778 { 1779 nCol = i; 1780 nMinRow = pNextRows[i-nStartCol]; 1781 } 1782 1783 if (nMinRow <= nEndRow) 1784 { 1785 nRow = nMinRow; 1786 bFound = sal_True; 1787 } 1788 } 1789 1790 if ( !bFound ) 1791 bMore = sal_False; 1792 } 1793 1794 //------------------------------------------------------------------------ 1795 1796 ScHorizontalValueIterator::ScHorizontalValueIterator( ScDocument* pDocument, 1797 const ScRange& rRange, bool bSTotal, bool bTextZero ) : 1798 pDoc( pDocument ), 1799 nNumFmtIndex(0), 1800 nEndTab( rRange.aEnd.Tab() ), 1801 nNumFmtType( NUMBERFORMAT_UNDEFINED ), 1802 bNumValid( false ), 1803 bSubTotal( bSTotal ), 1804 bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ), 1805 bTextAsZero( bTextZero ) 1806 { 1807 SCCOL nStartCol = rRange.aStart.Col(); 1808 SCROW nStartRow = rRange.aStart.Row(); 1809 SCTAB nStartTab = rRange.aStart.Tab(); 1810 SCCOL nEndCol = rRange.aEnd.Col(); 1811 SCROW nEndRow = rRange.aEnd.Row(); 1812 PutInOrder( nStartCol, nEndCol); 1813 PutInOrder( nStartRow, nEndRow); 1814 PutInOrder( nStartTab, nEndTab ); 1815 1816 if (!ValidCol(nStartCol)) nStartCol = MAXCOL; 1817 if (!ValidCol(nEndCol)) nEndCol = MAXCOL; 1818 if (!ValidRow(nStartRow)) nStartRow = MAXROW; 1819 if (!ValidRow(nEndRow)) nEndRow = MAXROW; 1820 if (!ValidTab(nStartTab)) nStartTab = MAXTAB; 1821 if (!ValidTab(nEndTab)) nEndTab = MAXTAB; 1822 1823 nCurCol = nStartCol; 1824 nCurRow = nStartRow; 1825 nCurTab = nStartTab; 1826 1827 nNumFormat = 0; // will be initialized in GetNumberFormat() 1828 pAttrArray = 0; 1829 nAttrEndRow = 0; 1830 1831 pCellIter = new ScHorizontalCellIterator( pDoc, nStartTab, nStartCol, 1832 nStartRow, nEndCol, nEndRow ); 1833 } 1834 1835 ScHorizontalValueIterator::~ScHorizontalValueIterator() 1836 { 1837 delete pCellIter; 1838 } 1839 1840 bool ScHorizontalValueIterator::GetNext( double& rValue, sal_uInt16& rErr ) 1841 { 1842 bool bFound = false; 1843 while ( !bFound ) 1844 { 1845 ScBaseCell* pCell = pCellIter->GetNext( nCurCol, nCurRow ); 1846 while ( !pCell ) 1847 { 1848 if ( nCurTab < nEndTab ) 1849 { 1850 pCellIter->SetTab( ++nCurTab); 1851 pCell = pCellIter->GetNext( nCurCol, nCurRow ); 1852 } 1853 else 1854 return false; 1855 } 1856 if ( !bSubTotal || !pDoc->pTab[nCurTab]->RowFiltered( nCurRow ) ) 1857 { 1858 switch (pCell->GetCellType()) 1859 { 1860 case CELLTYPE_VALUE: 1861 { 1862 bNumValid = false; 1863 rValue = ((ScValueCell*)pCell)->GetValue(); 1864 rErr = 0; 1865 if ( bCalcAsShown ) 1866 { 1867 ScColumn* pCol = &pDoc->pTab[nCurTab]->aCol[nCurCol]; 1868 lcl_IterGetNumberFormat( nNumFormat, pAttrArray, 1869 nAttrEndRow, pCol->pAttrArray, nCurRow, pDoc ); 1870 rValue = pDoc->RoundValueAsShown( rValue, nNumFormat ); 1871 } 1872 bFound = true; 1873 } 1874 break; 1875 case CELLTYPE_FORMULA: 1876 { 1877 if (!bSubTotal || !((ScFormulaCell*)pCell)->IsSubTotal()) 1878 { 1879 rErr = ((ScFormulaCell*)pCell)->GetErrCode(); 1880 if ( rErr || ((ScFormulaCell*)pCell)->IsValue() ) 1881 { 1882 rValue = ((ScFormulaCell*)pCell)->GetValue(); 1883 bNumValid = false; 1884 bFound = true; 1885 } 1886 else if ( bTextAsZero ) 1887 { 1888 rValue = 0.0; 1889 bNumValid = false; 1890 bFound = true; 1891 } 1892 } 1893 } 1894 break; 1895 case CELLTYPE_STRING : 1896 case CELLTYPE_EDIT : 1897 { 1898 if ( bTextAsZero ) 1899 { 1900 rErr = 0; 1901 rValue = 0.0; 1902 nNumFmtType = NUMBERFORMAT_NUMBER; 1903 nNumFmtIndex = 0; 1904 bNumValid = true; 1905 bFound = true; 1906 } 1907 } 1908 break; 1909 default: 1910 ; // nothing 1911 } 1912 } 1913 } 1914 return bFound; 1915 } 1916 1917 void ScHorizontalValueIterator::GetCurNumFmtInfo( short& nType, sal_uLong& nIndex ) 1918 { 1919 if (!bNumValid) 1920 { 1921 const ScColumn* pCol = &(pDoc->pTab[nCurTab])->aCol[nCurCol]; 1922 nNumFmtIndex = pCol->GetNumberFormat( nCurRow ); 1923 if ( (nNumFmtIndex % SV_COUNTRY_LANGUAGE_OFFSET) == 0 ) 1924 { 1925 const ScBaseCell* pCell; 1926 SCSIZE nCurIndex; 1927 if ( pCol->Search( nCurRow, nCurIndex ) ) 1928 pCell = pCol->pItems[nCurIndex].pCell; 1929 else 1930 pCell = NULL; 1931 if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA ) 1932 ((const ScFormulaCell*)pCell)->GetFormatInfo( nNumFmtType, nNumFmtIndex ); 1933 else 1934 nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex ); 1935 } 1936 else 1937 nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex ); 1938 bNumValid = true; 1939 } 1940 nType = nNumFmtType; 1941 nIndex = nNumFmtIndex; 1942 } 1943 1944 //------------------------------------------------------------------------------- 1945 1946 ScHorizontalAttrIterator::ScHorizontalAttrIterator( ScDocument* pDocument, SCTAB nTable, 1947 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) : 1948 pDoc( pDocument ), 1949 nTab( nTable ), 1950 nStartCol( nCol1 ), 1951 nStartRow( nRow1 ), 1952 nEndCol( nCol2 ), 1953 nEndRow( nRow2 ) 1954 { 1955 DBG_ASSERT( pDoc->pTab[nTab], "Tabelle nicht da" ); 1956 1957 SCCOL i; 1958 1959 nRow = nStartRow; 1960 nCol = nStartCol; 1961 bRowEmpty = sal_False; 1962 1963 pIndices = new SCSIZE[nEndCol-nStartCol+1]; 1964 pNextEnd = new SCROW[nEndCol-nStartCol+1]; 1965 ppPatterns = new const ScPatternAttr*[nEndCol-nStartCol+1]; 1966 1967 SCROW nSkipTo = MAXROW; 1968 sal_Bool bEmpty = sal_True; 1969 for (i=nStartCol; i<=nEndCol; i++) 1970 { 1971 SCCOL nPos = i - nStartCol; 1972 ScAttrArray* pArray = pDoc->pTab[nTab]->aCol[i].pAttrArray; 1973 DBG_ASSERT( pArray, "pArray == 0" ); 1974 1975 SCSIZE nIndex; 1976 pArray->Search( nStartRow, nIndex ); 1977 1978 const ScPatternAttr* pPattern = pArray->pData[nIndex].pPattern; 1979 SCROW nThisEnd = pArray->pData[nIndex].nRow; 1980 if ( IsDefaultItem( pPattern ) ) 1981 { 1982 pPattern = NULL; 1983 if ( nThisEnd < nSkipTo ) 1984 nSkipTo = nThisEnd; // nSkipTo kann gleich hier gesetzt werden 1985 } 1986 else 1987 bEmpty = sal_False; // Attribute gefunden 1988 1989 pIndices[nPos] = nIndex; 1990 pNextEnd[nPos] = nThisEnd; 1991 ppPatterns[nPos] = pPattern; 1992 } 1993 1994 if (bEmpty) 1995 nRow = nSkipTo; // bis zum naechsten Bereichsende ueberspringen 1996 bRowEmpty = bEmpty; 1997 } 1998 1999 ScHorizontalAttrIterator::~ScHorizontalAttrIterator() 2000 { 2001 delete[] (ScPatternAttr**)ppPatterns; 2002 delete[] pNextEnd; 2003 delete[] pIndices; 2004 } 2005 2006 const ScPatternAttr* ScHorizontalAttrIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2, SCROW& rRow ) 2007 { 2008 for (;;) 2009 { 2010 if (!bRowEmpty) 2011 { 2012 // in dieser Zeile suchen 2013 2014 while ( nCol <= nEndCol && !ppPatterns[nCol-nStartCol] ) 2015 ++nCol; 2016 2017 if ( nCol <= nEndCol ) 2018 { 2019 const ScPatternAttr* pPat = ppPatterns[nCol-nStartCol]; 2020 rRow = nRow; 2021 rCol1 = nCol; 2022 while ( nCol < nEndCol && ppPatterns[nCol+1-nStartCol] == pPat ) 2023 ++nCol; 2024 rCol2 = nCol; 2025 ++nCol; // hochzaehlen fuer naechsten Aufruf 2026 return pPat; // gefunden 2027 } 2028 } 2029 2030 // naechste Zeile 2031 2032 ++nRow; 2033 if ( nRow > nEndRow ) // schon am Ende? 2034 return NULL; // nichts gefunden 2035 2036 sal_Bool bEmpty = sal_True; 2037 SCCOL i; 2038 2039 for ( i = nStartCol; i <= nEndCol; i++) 2040 { 2041 SCCOL nPos = i-nStartCol; 2042 if ( pNextEnd[nPos] < nRow ) 2043 { 2044 ScAttrArray* pArray = pDoc->pTab[nTab]->aCol[i].pAttrArray; 2045 2046 SCSIZE nIndex = ++pIndices[nPos]; 2047 if ( nIndex < pArray->nCount ) 2048 { 2049 const ScPatternAttr* pPattern = pArray->pData[nIndex].pPattern; 2050 SCROW nThisEnd = pArray->pData[nIndex].nRow; 2051 if ( IsDefaultItem( pPattern ) ) 2052 pPattern = NULL; 2053 else 2054 bEmpty = sal_False; // Attribute gefunden 2055 2056 pNextEnd[nPos] = nThisEnd; 2057 ppPatterns[nPos] = pPattern; 2058 2059 DBG_ASSERT( pNextEnd[nPos] >= nRow, "Reihenfolge durcheinander" ); 2060 } 2061 else 2062 { 2063 DBG_ERROR("AttrArray reicht nicht bis MAXROW"); 2064 pNextEnd[nPos] = MAXROW; 2065 ppPatterns[nPos] = NULL; 2066 } 2067 } 2068 else if ( ppPatterns[nPos] ) 2069 bEmpty = sal_False; // Bereich noch nicht zuende 2070 } 2071 2072 if (bEmpty) 2073 { 2074 SCCOL nCount = nEndCol-nStartCol+1; 2075 SCROW nSkipTo = pNextEnd[0]; // naechstes Bereichsende suchen 2076 for (i=1; i<nCount; i++) 2077 if ( pNextEnd[i] < nSkipTo ) 2078 nSkipTo = pNextEnd[i]; 2079 nRow = nSkipTo; // leere Zeilen ueberspringen 2080 } 2081 bRowEmpty = bEmpty; 2082 nCol = nStartCol; // wieder links anfangen 2083 } 2084 2085 // return NULL; 2086 } 2087 2088 //------------------------------------------------------------------------------- 2089 2090 inline sal_Bool IsGreater( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) 2091 { 2092 return ( nRow1 > nRow2 ) || ( nRow1 == nRow2 && nCol1 > nCol2 ); 2093 } 2094 2095 ScUsedAreaIterator::ScUsedAreaIterator( ScDocument* pDocument, SCTAB nTable, 2096 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) : 2097 aCellIter( pDocument, nTable, nCol1, nRow1, nCol2, nRow2 ), 2098 aAttrIter( pDocument, nTable, nCol1, nRow1, nCol2, nRow2 ), 2099 nNextCol( nCol1 ), 2100 nNextRow( nRow1 ) 2101 { 2102 pCell = aCellIter.GetNext( nCellCol, nCellRow ); 2103 pPattern = aAttrIter.GetNext( nAttrCol1, nAttrCol2, nAttrRow ); 2104 } 2105 2106 ScUsedAreaIterator::~ScUsedAreaIterator() 2107 { 2108 } 2109 2110 sal_Bool ScUsedAreaIterator::GetNext() 2111 { 2112 // Iteratoren weiterzaehlen 2113 2114 if ( pCell && IsGreater( nNextCol, nNextRow, nCellCol, nCellRow ) ) 2115 pCell = aCellIter.GetNext( nCellCol, nCellRow ); 2116 2117 while ( pCell && pCell->IsBlank() ) 2118 pCell = aCellIter.GetNext( nCellCol, nCellRow ); 2119 2120 if ( pPattern && IsGreater( nNextCol, nNextRow, nAttrCol2, nAttrRow ) ) 2121 pPattern = aAttrIter.GetNext( nAttrCol1, nAttrCol2, nAttrRow ); 2122 2123 if ( pPattern && nAttrRow == nNextRow && nAttrCol1 < nNextCol ) 2124 nAttrCol1 = nNextCol; 2125 2126 // naechsten Abschnitt heraussuchen 2127 2128 sal_Bool bFound = sal_True; 2129 sal_Bool bUseCell = sal_False; 2130 2131 if ( pCell && pPattern ) 2132 { 2133 if ( IsGreater( nCellCol, nCellRow, nAttrCol1, nAttrRow ) ) // vorne nur Attribute ? 2134 { 2135 pFoundCell = NULL; 2136 pFoundPattern = pPattern; 2137 nFoundRow = nAttrRow; 2138 nFoundStartCol = nAttrCol1; 2139 if ( nCellRow == nAttrRow && nCellCol <= nAttrCol2 ) // auch Zelle im Bereich ? 2140 nFoundEndCol = nCellCol - 1; // nur bis vor der Zelle 2141 else 2142 nFoundEndCol = nAttrCol2; // alles 2143 } 2144 else 2145 { 2146 bUseCell = sal_True; 2147 if ( nAttrRow == nCellRow && nAttrCol1 == nCellCol ) // Attribute auf der Zelle ? 2148 pFoundPattern = pPattern; 2149 else 2150 pFoundPattern = NULL; 2151 } 2152 } 2153 else if ( pCell ) // nur Zelle -> direkt uebernehmen 2154 { 2155 pFoundPattern = NULL; 2156 bUseCell = sal_True; // Position von Zelle 2157 } 2158 else if ( pPattern ) // nur Attribute -> direkt uebernehmen 2159 { 2160 pFoundCell = NULL; 2161 pFoundPattern = pPattern; 2162 nFoundRow = nAttrRow; 2163 nFoundStartCol = nAttrCol1; 2164 nFoundEndCol = nAttrCol2; 2165 } 2166 else // gar nichts 2167 bFound = sal_False; 2168 2169 if ( bUseCell ) // Position von Zelle 2170 { 2171 pFoundCell = pCell; 2172 nFoundRow = nCellRow; 2173 nFoundStartCol = nFoundEndCol = nCellCol; 2174 } 2175 2176 if (bFound) 2177 { 2178 nNextRow = nFoundRow; 2179 nNextCol = nFoundEndCol + 1; 2180 } 2181 2182 return bFound; 2183 } 2184 2185 //------------------------------------------------------------------------------- 2186 2187 ScDocAttrIterator::ScDocAttrIterator(ScDocument* pDocument, SCTAB nTable, 2188 SCCOL nCol1, SCROW nRow1, 2189 SCCOL nCol2, SCROW nRow2) : 2190 pDoc( pDocument ), 2191 nTab( nTable ), 2192 nEndCol( nCol2 ), 2193 nStartRow( nRow1 ), 2194 nEndRow( nRow2 ), 2195 nCol( nCol1 ) 2196 { 2197 if ( ValidTab(nTab) && pDoc->pTab[nTab] ) 2198 pColIter = pDoc->pTab[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow ); 2199 else 2200 pColIter = NULL; 2201 } 2202 2203 ScDocAttrIterator::~ScDocAttrIterator() 2204 { 2205 delete pColIter; 2206 } 2207 2208 const ScPatternAttr* ScDocAttrIterator::GetNext( SCCOL& rCol, SCROW& rRow1, SCROW& rRow2 ) 2209 { 2210 while ( pColIter ) 2211 { 2212 const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 ); 2213 if ( pPattern ) 2214 { 2215 rCol = nCol; 2216 return pPattern; 2217 } 2218 2219 delete pColIter; 2220 ++nCol; 2221 if ( nCol <= nEndCol ) 2222 pColIter = pDoc->pTab[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow ); 2223 else 2224 pColIter = NULL; 2225 } 2226 return NULL; // is nix mehr 2227 } 2228 2229 //------------------------------------------------------------------------------- 2230 2231 ScAttrRectIterator::ScAttrRectIterator(ScDocument* pDocument, SCTAB nTable, 2232 SCCOL nCol1, SCROW nRow1, 2233 SCCOL nCol2, SCROW nRow2) : 2234 pDoc( pDocument ), 2235 nTab( nTable ), 2236 nEndCol( nCol2 ), 2237 nStartRow( nRow1 ), 2238 nEndRow( nRow2 ), 2239 nIterStartCol( nCol1 ), 2240 nIterEndCol( nCol1 ) 2241 { 2242 if ( ValidTab(nTab) && pDoc->pTab[nTab] ) 2243 { 2244 pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow ); 2245 while ( nIterEndCol < nEndCol && 2246 pDoc->pTab[nTab]->aCol[nIterEndCol].IsAllAttrEqual( 2247 pDoc->pTab[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) ) 2248 ++nIterEndCol; 2249 } 2250 else 2251 pColIter = NULL; 2252 } 2253 2254 ScAttrRectIterator::~ScAttrRectIterator() 2255 { 2256 delete pColIter; 2257 } 2258 2259 void ScAttrRectIterator::DataChanged() 2260 { 2261 if (pColIter) 2262 { 2263 SCROW nNextRow = pColIter->GetNextRow(); 2264 delete pColIter; 2265 pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nNextRow, nEndRow ); 2266 } 2267 } 2268 2269 const ScPatternAttr* ScAttrRectIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2, 2270 SCROW& rRow1, SCROW& rRow2 ) 2271 { 2272 while ( pColIter ) 2273 { 2274 const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 ); 2275 if ( pPattern ) 2276 { 2277 rCol1 = nIterStartCol; 2278 rCol2 = nIterEndCol; 2279 return pPattern; 2280 } 2281 2282 delete pColIter; 2283 nIterStartCol = nIterEndCol+1; 2284 if ( nIterStartCol <= nEndCol ) 2285 { 2286 nIterEndCol = nIterStartCol; 2287 pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow ); 2288 while ( nIterEndCol < nEndCol && 2289 pDoc->pTab[nTab]->aCol[nIterEndCol].IsAllAttrEqual( 2290 pDoc->pTab[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) ) 2291 ++nIterEndCol; 2292 } 2293 else 2294 pColIter = NULL; 2295 } 2296 return NULL; // is nix mehr 2297 } 2298 2299 // ============================================================================ 2300 2301 SCROW ScRowBreakIterator::NOT_FOUND = -1; 2302 2303 ScRowBreakIterator::ScRowBreakIterator(set<SCROW>& rBreaks) : 2304 mrBreaks(rBreaks), 2305 maItr(rBreaks.begin()), maEnd(rBreaks.end()) 2306 { 2307 } 2308 2309 SCROW ScRowBreakIterator::first() 2310 { 2311 maItr = mrBreaks.begin(); 2312 return maItr == maEnd ? NOT_FOUND : *maItr; 2313 } 2314 2315 SCROW ScRowBreakIterator::next() 2316 { 2317 ++maItr; 2318 return maItr == maEnd ? NOT_FOUND : *maItr; 2319 } 2320