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