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 { 630 if (mpParam->mbSkipString) 631 ++nRow; 632 else 633 { 634 rValue.maString = ((ScFormulaCell*)pCell)->GetStringData(); 635 rValue.mbIsNumber = false; 636 rValue.mnError = ((ScFormulaCell*)pCell)->GetErrCode(); 637 return sal_True; 638 } 639 } 640 } 641 break; 642 case CELLTYPE_STRING: 643 case CELLTYPE_EDIT: 644 if (mpParam->mbSkipString) 645 ++nRow; 646 else 647 { 648 rValue.maString = pCell->GetStringData(); 649 rValue.mfValue = 0.0; 650 rValue.mnError = 0; 651 rValue.mbIsNumber = false; 652 return true; 653 } 654 break; 655 default: 656 nRow++; 657 break; 658 } 659 } 660 else 661 nRow++; 662 } 663 else 664 nRow = mpParam->nRow2 + 1; // Naechste Spalte 665 } 666 // statement unreachable 667 // return false; 668 } 669 670 bool ScDBQueryDataIterator::DataAccessInternal::getFirst(Value& rValue) 671 { 672 if (mpParam->bHasHeader) 673 nRow++; 674 675 nColRow = ScDBQueryDataIterator::SearchColEntryIndex(*mpDoc, nTab, nRow, nCol); 676 return getCurrent(rValue); 677 } 678 679 bool ScDBQueryDataIterator::DataAccessInternal::getNext(Value& rValue) 680 { 681 ++nRow; 682 return getCurrent(rValue); 683 } 684 685 // ---------------------------------------------------------------------------- 686 687 ScDBQueryDataIterator::DataAccessMatrix::DataAccessMatrix(const ScDBQueryDataIterator* pParent, ScDBQueryParamMatrix* pParam) : 688 DataAccess(pParent), 689 mpParam(pParam) 690 { 691 SCSIZE nC, nR; 692 mpParam->mpMatrix->GetDimensions(nC, nR); 693 mnRows = static_cast<SCROW>(nR); 694 mnCols = static_cast<SCCOL>(nC); 695 } 696 697 ScDBQueryDataIterator::DataAccessMatrix::~DataAccessMatrix() 698 { 699 } 700 701 bool ScDBQueryDataIterator::DataAccessMatrix::getCurrent(Value& rValue) 702 { 703 // Starting from row == mnCurRow, get the first row that satisfies all the 704 // query parameters. 705 for ( ;mnCurRow < mnRows; ++mnCurRow) 706 { 707 const ScMatrix& rMat = *mpParam->mpMatrix; 708 if (rMat.IsEmpty(mpParam->mnField, mnCurRow)) 709 // Don't take empty values into account. 710 continue; 711 712 bool bIsStrVal = rMat.IsString(mpParam->mnField, mnCurRow); 713 if (bIsStrVal && mpParam->mbSkipString) 714 continue; 715 716 if (isValidQuery(mnCurRow, rMat)) 717 { 718 rValue.maString = rMat.GetString(mpParam->mnField, mnCurRow); 719 rValue.mfValue = rMat.GetDouble(mpParam->mnField, mnCurRow); 720 rValue.mbIsNumber = !bIsStrVal; 721 rValue.mnError = 0; 722 return true; 723 } 724 } 725 return false; 726 } 727 728 bool ScDBQueryDataIterator::DataAccessMatrix::getFirst(Value& rValue) 729 { 730 mnCurRow = mpParam->bHasHeader ? 1 : 0; 731 return getCurrent(rValue); 732 } 733 734 bool ScDBQueryDataIterator::DataAccessMatrix::getNext(Value& rValue) 735 { 736 ++mnCurRow; 737 return getCurrent(rValue); 738 } 739 740 namespace { 741 742 bool lcl_isQueryByValue(const ScQueryEntry& rEntry, const ScMatrix& rMat, SCSIZE nCol, SCSIZE nRow) 743 { 744 if (rEntry.bQueryByString) 745 return false; 746 747 if (!rMat.IsValueOrEmpty(nCol, nRow)) 748 return false; 749 750 return true; 751 } 752 753 bool lcl_isQueryByString(const ScQueryEntry& rEntry, const ScMatrix& rMat, SCSIZE nCol, SCSIZE nRow) 754 { 755 switch (rEntry.eOp) 756 { 757 case SC_EQUAL: 758 case SC_NOT_EQUAL: 759 case SC_CONTAINS: 760 case SC_DOES_NOT_CONTAIN: 761 case SC_BEGINS_WITH: 762 case SC_ENDS_WITH: 763 case SC_DOES_NOT_BEGIN_WITH: 764 case SC_DOES_NOT_END_WITH: 765 return true; 766 default: 767 ; 768 } 769 770 if (rEntry.bQueryByString && rMat.IsString(nCol, nRow)) 771 return true; 772 773 return false; 774 } 775 776 } 777 778 bool ScDBQueryDataIterator::DataAccessMatrix::isValidQuery(SCROW nRow, const ScMatrix& rMat) const 779 { 780 SCSIZE nEntryCount = mpParam->GetEntryCount(); 781 vector<bool> aResults; 782 aResults.reserve(nEntryCount); 783 784 const CollatorWrapper& rCollator = 785 mpParam->bCaseSens ? *ScGlobal::GetCaseCollator() : *ScGlobal::GetCollator(); 786 787 for (SCSIZE i = 0; i < nEntryCount; ++i) 788 { 789 const ScQueryEntry& rEntry = mpParam->GetEntry(i); 790 if (!rEntry.bDoQuery) 791 continue; 792 793 switch (rEntry.eOp) 794 { 795 case SC_EQUAL: 796 case SC_LESS: 797 case SC_GREATER: 798 case SC_LESS_EQUAL: 799 case SC_GREATER_EQUAL: 800 case SC_NOT_EQUAL: 801 break; 802 default: 803 // Only the above operators are supported. 804 continue; 805 } 806 807 bool bValid = false; 808 809 SCSIZE nField = static_cast<SCSIZE>(rEntry.nField); 810 if (lcl_isQueryByValue(rEntry, rMat, nField, nRow)) 811 { 812 // By value 813 double fMatVal = rMat.GetDouble(nField, nRow); 814 bool bEqual = approxEqual(fMatVal, rEntry.nVal); 815 switch (rEntry.eOp) 816 { 817 case SC_EQUAL: 818 bValid = bEqual; 819 break; 820 case SC_LESS: 821 bValid = (fMatVal < rEntry.nVal) && !bEqual; 822 break; 823 case SC_GREATER: 824 bValid = (fMatVal > rEntry.nVal) && !bEqual; 825 break; 826 case SC_LESS_EQUAL: 827 bValid = (fMatVal < rEntry.nVal) || bEqual; 828 break; 829 case SC_GREATER_EQUAL: 830 bValid = (fMatVal > rEntry.nVal) || bEqual; 831 break; 832 case SC_NOT_EQUAL: 833 bValid = !bEqual; 834 break; 835 default: 836 ; 837 } 838 } 839 else if (lcl_isQueryByString(rEntry, rMat, nField, nRow)) 840 { 841 // By string 842 do 843 { 844 if (!rEntry.pStr) 845 break; 846 847 // Equality check first. 848 849 OUString aMatStr = rMat.GetString(nField, nRow); 850 lcl_toUpper(aMatStr); 851 OUString aQueryStr = *rEntry.pStr; 852 lcl_toUpper(aQueryStr); 853 bool bDone = false; 854 switch (rEntry.eOp) 855 { 856 case SC_EQUAL: 857 bValid = aMatStr.equals(aQueryStr); 858 bDone = true; 859 break; 860 case SC_NOT_EQUAL: 861 bValid = !aMatStr.equals(aQueryStr); 862 bDone = true; 863 break; 864 default: 865 ; 866 } 867 868 if (bDone) 869 break; 870 871 // Unequality check using collator. 872 873 sal_Int32 nCompare = rCollator.compareString(aMatStr, aQueryStr); 874 switch (rEntry.eOp) 875 { 876 case SC_LESS : 877 bValid = (nCompare < 0); 878 break; 879 case SC_GREATER : 880 bValid = (nCompare > 0); 881 break; 882 case SC_LESS_EQUAL : 883 bValid = (nCompare <= 0); 884 break; 885 case SC_GREATER_EQUAL : 886 bValid = (nCompare >= 0); 887 break; 888 default: 889 ; 890 } 891 } 892 while (false); 893 } 894 else if (mpParam->bMixedComparison) 895 { 896 // Not used at the moment. 897 } 898 899 if (aResults.empty()) 900 // First query entry. 901 aResults.push_back(bValid); 902 else if (rEntry.eConnect == SC_AND) 903 { 904 // For AND op, tuck the result into the last result value. 905 size_t n = aResults.size(); 906 aResults[n-1] = aResults[n-1] && bValid; 907 } 908 else 909 // For OR op, store its own result. 910 aResults.push_back(bValid); 911 } 912 913 // Row is valid as long as there is at least one result being true. 914 vector<bool>::const_iterator itr = aResults.begin(), itrEnd = aResults.end(); 915 for (; itr != itrEnd; ++itr) 916 if (*itr) 917 return true; 918 919 return false; 920 } 921 922 // ---------------------------------------------------------------------------- 923 924 ScDBQueryDataIterator::Value::Value() : 925 mnError(0), mbIsNumber(true) 926 { 927 ::rtl::math::setNan(&mfValue); 928 } 929 930 // ---------------------------------------------------------------------------- 931 932 ScDBQueryDataIterator::ScDBQueryDataIterator(ScDocument* pDocument, ScDBQueryParamBase* pParam) : 933 mpParam (pParam) 934 { 935 switch (mpParam->GetType()) 936 { 937 case ScDBQueryParamBase::INTERNAL: 938 { 939 ScDBQueryParamInternal* p = static_cast<ScDBQueryParamInternal*>(pParam); 940 mpData.reset(new DataAccessInternal(this, p, pDocument)); 941 } 942 break; 943 case ScDBQueryParamBase::MATRIX: 944 { 945 ScDBQueryParamMatrix* p = static_cast<ScDBQueryParamMatrix*>(pParam); 946 mpData.reset(new DataAccessMatrix(this, p)); 947 } 948 } 949 } 950 951 bool ScDBQueryDataIterator::GetFirst(Value& rValue) 952 { 953 return mpData->getFirst(rValue); 954 } 955 956 bool ScDBQueryDataIterator::GetNext(Value& rValue) 957 { 958 return mpData->getNext(rValue); 959 } 960 961 // ============================================================================ 962 963 ScCellIterator::ScCellIterator( ScDocument* pDocument, 964 SCCOL nSCol, SCROW nSRow, SCTAB nSTab, 965 SCCOL nECol, SCROW nERow, SCTAB nETab, sal_Bool bSTotal ) : 966 pDoc( pDocument ), 967 nStartCol( nSCol), 968 nStartRow( nSRow), 969 nStartTab( nSTab ), 970 nEndCol( nECol ), 971 nEndRow( nERow), 972 nEndTab( nETab ), 973 bSubTotal(bSTotal) 974 975 { 976 PutInOrder( nStartCol, nEndCol); 977 PutInOrder( nStartRow, nEndRow); 978 PutInOrder( nStartTab, nEndTab ); 979 980 if (!ValidCol(nStartCol)) nStartCol = MAXCOL; 981 if (!ValidCol(nEndCol)) nEndCol = MAXCOL; 982 if (!ValidRow(nStartRow)) nStartRow = MAXROW; 983 if (!ValidRow(nEndRow)) nEndRow = MAXROW; 984 if (!ValidTab(nStartTab)) nStartTab = MAXTAB; 985 if (!ValidTab(nEndTab)) nEndTab = MAXTAB; 986 987 while (nEndTab>0 && !pDoc->pTab[nEndTab]) 988 --nEndTab; // nur benutzte Tabellen 989 if (nStartTab>nEndTab) 990 nStartTab = nEndTab; 991 992 nCol = nStartCol; 993 nRow = nStartRow; 994 nTab = nStartTab; 995 nColRow = 0; // wird bei GetFirst initialisiert 996 997 if (!pDoc->pTab[nTab]) 998 { 999 DBG_ERROR("Tabelle nicht gefunden"); 1000 nStartCol = nCol = MAXCOL+1; 1001 nStartRow = nRow = MAXROW+1; 1002 nStartTab = nTab = MAXTAB+1; // -> Abbruch bei GetFirst 1003 } 1004 } 1005 1006 ScCellIterator::ScCellIterator 1007 ( ScDocument* pDocument, const ScRange& rRange, sal_Bool bSTotal ) : 1008 pDoc( pDocument ), 1009 nStartCol( rRange.aStart.Col() ), 1010 nStartRow( rRange.aStart.Row() ), 1011 nStartTab( rRange.aStart.Tab() ), 1012 nEndCol( rRange.aEnd.Col() ), 1013 nEndRow( rRange.aEnd.Row() ), 1014 nEndTab( rRange.aEnd.Tab() ), 1015 bSubTotal(bSTotal) 1016 1017 { 1018 PutInOrder( nStartCol, nEndCol); 1019 PutInOrder( nStartRow, nEndRow); 1020 PutInOrder( nStartTab, nEndTab ); 1021 1022 if (!ValidCol(nStartCol)) nStartCol = MAXCOL; 1023 if (!ValidCol(nEndCol)) nEndCol = MAXCOL; 1024 if (!ValidRow(nStartRow)) nStartRow = MAXROW; 1025 if (!ValidRow(nEndRow)) nEndRow = MAXROW; 1026 if (!ValidTab(nStartTab)) nStartTab = MAXTAB; 1027 if (!ValidTab(nEndTab)) nEndTab = MAXTAB; 1028 1029 while (nEndTab>0 && !pDoc->pTab[nEndTab]) 1030 --nEndTab; // nur benutzte Tabellen 1031 if (nStartTab>nEndTab) 1032 nStartTab = nEndTab; 1033 1034 nCol = nStartCol; 1035 nRow = nStartRow; 1036 nTab = nStartTab; 1037 nColRow = 0; // wird bei GetFirst initialisiert 1038 1039 if (!pDoc->pTab[nTab]) 1040 { 1041 DBG_ERROR("Tabelle nicht gefunden"); 1042 nStartCol = nCol = MAXCOL+1; 1043 nStartRow = nRow = MAXROW+1; 1044 nStartTab = nTab = MAXTAB+1; // -> Abbruch bei GetFirst 1045 } 1046 } 1047 1048 ScBaseCell* ScCellIterator::GetThis() 1049 { 1050 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol]; 1051 for ( ;; ) 1052 { 1053 if ( nRow > nEndRow ) 1054 { 1055 nRow = nStartRow; 1056 do 1057 { 1058 nCol++; 1059 if ( nCol > nEndCol ) 1060 { 1061 nCol = nStartCol; 1062 nTab++; 1063 if ( nTab > nEndTab ) 1064 return NULL; // Ende und Aus 1065 } 1066 pCol = &(pDoc->pTab[nTab])->aCol[nCol]; 1067 } while ( pCol->nCount == 0 ); 1068 pCol->Search( nRow, nColRow ); 1069 } 1070 1071 while ( (nColRow < pCol->nCount) && (pCol->pItems[nColRow].nRow < nRow) ) 1072 nColRow++; 1073 1074 if ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow <= nEndRow ) 1075 { 1076 nRow = pCol->pItems[nColRow].nRow; 1077 if ( !bSubTotal || !pDoc->pTab[nTab]->RowFiltered( nRow ) ) 1078 { 1079 ScBaseCell* pCell = pCol->pItems[nColRow].pCell; 1080 1081 if ( bSubTotal && pCell->GetCellType() == CELLTYPE_FORMULA 1082 && ((ScFormulaCell*)pCell)->IsSubTotal() ) 1083 nRow++; // Sub-Total-Zeilen nicht 1084 else 1085 return pCell; // gefunden 1086 } 1087 else 1088 nRow++; 1089 } 1090 else 1091 nRow = nEndRow + 1; // Naechste Spalte 1092 } 1093 } 1094 1095 ScBaseCell* ScCellIterator::GetFirst() 1096 { 1097 if ( !ValidTab(nTab) ) 1098 return NULL; 1099 nCol = nStartCol; 1100 nRow = nStartRow; 1101 nTab = nStartTab; 1102 // nColRow = 0; 1103 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol]; 1104 pCol->Search( nRow, nColRow ); 1105 return GetThis(); 1106 } 1107 1108 ScBaseCell* ScCellIterator::GetNext() 1109 { 1110 ++nRow; 1111 return GetThis(); 1112 } 1113 1114 //------------------------------------------------------------------------------- 1115 1116 ScQueryCellIterator::ScQueryCellIterator(ScDocument* pDocument, SCTAB nTable, 1117 const ScQueryParam& rParam, sal_Bool bMod ) : 1118 aParam (rParam), 1119 pDoc( pDocument ), 1120 nTab( nTable), 1121 nStopOnMismatch( nStopOnMismatchDisabled ), 1122 nTestEqualCondition( nTestEqualConditionDisabled ), 1123 bAdvanceQuery( sal_False ), 1124 bIgnoreMismatchOnLeadingStrings( sal_False ) 1125 { 1126 nCol = aParam.nCol1; 1127 nRow = aParam.nRow1; 1128 nColRow = 0; // wird bei GetFirst initialisiert 1129 SCSIZE i; 1130 if (bMod) // sonst schon eingetragen 1131 { 1132 for (i=0; (i<MAXQUERY) && (aParam.GetEntry(i).bDoQuery); i++) 1133 { 1134 ScQueryEntry& rEntry = aParam.GetEntry(i); 1135 sal_uInt32 nIndex = 0; 1136 rEntry.bQueryByString = 1137 !(pDoc->GetFormatTable()->IsNumberFormat(*rEntry.pStr, 1138 nIndex, rEntry.nVal)); 1139 } 1140 } 1141 nNumFormat = 0; // werden bei GetNumberFormat initialisiert 1142 pAttrArray = 0; 1143 nAttrEndRow = 0; 1144 } 1145 1146 ScBaseCell* ScQueryCellIterator::GetThis() 1147 { 1148 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol]; 1149 const ScQueryEntry& rEntry = aParam.GetEntry(0); 1150 SCCOLROW nFirstQueryField = rEntry.nField; 1151 bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings && 1152 !rEntry.bQueryByString; 1153 bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings && 1154 !aParam.bHasHeader && rEntry.bQueryByString && 1155 ((aParam.bByRow && nRow == aParam.nRow1) || 1156 (!aParam.bByRow && nCol == aParam.nCol1)); 1157 for ( ;; ) 1158 { 1159 if ( nRow > aParam.nRow2 ) 1160 { 1161 nRow = aParam.nRow1; 1162 if (aParam.bHasHeader && aParam.bByRow) 1163 nRow++; 1164 do 1165 { 1166 if ( ++nCol > aParam.nCol2 ) 1167 return NULL; // Ende und Aus 1168 if ( bAdvanceQuery ) 1169 { 1170 AdvanceQueryParamEntryField(); 1171 nFirstQueryField = rEntry.nField; 1172 } 1173 pCol = &(pDoc->pTab[nTab])->aCol[nCol]; 1174 } while ( pCol->nCount == 0 ); 1175 pCol->Search( nRow, nColRow ); 1176 bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings && 1177 !aParam.bHasHeader && rEntry.bQueryByString && 1178 aParam.bByRow; 1179 } 1180 1181 while ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow < nRow ) 1182 nColRow++; 1183 1184 if ( nColRow < pCol->nCount && 1185 (nRow = pCol->pItems[nColRow].nRow) <= aParam.nRow2 ) 1186 { 1187 ScBaseCell* pCell = pCol->pItems[nColRow].pCell; 1188 if ( pCell->GetCellType() == CELLTYPE_NOTE ) 1189 ++nRow; 1190 else if (bAllStringIgnore && pCell->HasStringData()) 1191 ++nRow; 1192 else 1193 { 1194 sal_Bool bTestEqualCondition; 1195 if ( (pDoc->pTab[nTab])->ValidQuery( nRow, aParam, NULL, 1196 (nCol == static_cast<SCCOL>(nFirstQueryField) ? pCell : NULL), 1197 (nTestEqualCondition ? &bTestEqualCondition : NULL) ) ) 1198 { 1199 if ( nTestEqualCondition && bTestEqualCondition ) 1200 nTestEqualCondition |= nTestEqualConditionMatched; 1201 return pCell; // found 1202 } 1203 else if ( nStopOnMismatch ) 1204 { 1205 // Yes, even a mismatch may have a fulfilled equal 1206 // condition if regular expressions were involved and 1207 // SC_LESS_EQUAL or SC_GREATER_EQUAL were queried. 1208 if ( nTestEqualCondition && bTestEqualCondition ) 1209 { 1210 nTestEqualCondition |= nTestEqualConditionMatched; 1211 nStopOnMismatch |= nStopOnMismatchOccured; 1212 return NULL; 1213 } 1214 bool bStop; 1215 if (bFirstStringIgnore) 1216 { 1217 if (pCell->HasStringData()) 1218 { 1219 ++nRow; 1220 bStop = false; 1221 } 1222 else 1223 bStop = true; 1224 } 1225 else 1226 bStop = true; 1227 if (bStop) 1228 { 1229 nStopOnMismatch |= nStopOnMismatchOccured; 1230 return NULL; 1231 } 1232 } 1233 else 1234 nRow++; 1235 } 1236 } 1237 else 1238 nRow = aParam.nRow2 + 1; // Naechste Spalte 1239 bFirstStringIgnore = false; 1240 } 1241 } 1242 1243 ScBaseCell* ScQueryCellIterator::GetFirst() 1244 { 1245 nCol = aParam.nCol1; 1246 nRow = aParam.nRow1; 1247 if (aParam.bHasHeader) 1248 nRow++; 1249 // nColRow = 0; 1250 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol]; 1251 pCol->Search( nRow, nColRow ); 1252 return GetThis(); 1253 } 1254 1255 ScBaseCell* ScQueryCellIterator::GetNext() 1256 { 1257 ++nRow; 1258 if ( nStopOnMismatch ) 1259 nStopOnMismatch = nStopOnMismatchEnabled; 1260 if ( nTestEqualCondition ) 1261 nTestEqualCondition = nTestEqualConditionEnabled; 1262 return GetThis(); 1263 } 1264 1265 void ScQueryCellIterator::AdvanceQueryParamEntryField() 1266 { 1267 SCSIZE nEntries = aParam.GetEntryCount(); 1268 for ( SCSIZE j = 0; j < nEntries; j++ ) 1269 { 1270 ScQueryEntry& rEntry = aParam.GetEntry( j ); 1271 if ( rEntry.bDoQuery ) 1272 { 1273 if ( rEntry.nField < MAXCOL ) 1274 rEntry.nField++; 1275 else 1276 { 1277 DBG_ERRORFILE( "AdvanceQueryParamEntryField: ++rEntry.nField > MAXCOL" ); 1278 } 1279 } 1280 else 1281 break; // for 1282 } 1283 } 1284 1285 1286 sal_Bool ScQueryCellIterator::FindEqualOrSortedLastInRange( SCCOL& nFoundCol, 1287 SCROW& nFoundRow, sal_Bool bSearchForEqualAfterMismatch, 1288 sal_Bool bIgnoreMismatchOnLeadingStringsP ) 1289 { 1290 nFoundCol = MAXCOL+1; 1291 nFoundRow = MAXROW+1; 1292 SetStopOnMismatch( sal_True ); // assume sorted keys 1293 SetTestEqualCondition( sal_True ); 1294 bIgnoreMismatchOnLeadingStrings = bIgnoreMismatchOnLeadingStringsP; 1295 bool bRegExp = aParam.bRegExp && aParam.GetEntry(0).bQueryByString; 1296 bool bBinary = !bRegExp && aParam.bByRow && (aParam.GetEntry(0).eOp == 1297 SC_LESS_EQUAL || aParam.GetEntry(0).eOp == SC_GREATER_EQUAL); 1298 if (bBinary ? (BinarySearch() ? GetThis() : 0) : GetFirst()) 1299 { 1300 // First equal entry or last smaller than (greater than) entry. 1301 SCSIZE nColRowSave; 1302 ScBaseCell* pNext = 0; 1303 do 1304 { 1305 nFoundCol = GetCol(); 1306 nFoundRow = GetRow(); 1307 nColRowSave = nColRow; 1308 } while ( !IsEqualConditionFulfilled() && (pNext = GetNext()) != NULL ); 1309 // There may be no pNext but equal condition fulfilled if regular 1310 // expressions are involved. Keep the found entry and proceed. 1311 if (!pNext && !IsEqualConditionFulfilled()) 1312 { 1313 // Step back to last in range and adjust position markers for 1314 // GetNumberFormat() or similar. 1315 nCol = nFoundCol; 1316 nRow = nFoundRow; 1317 nColRow = nColRowSave; 1318 } 1319 } 1320 if ( IsEqualConditionFulfilled() ) 1321 { 1322 // Position on last equal entry. 1323 SCSIZE nEntries = aParam.GetEntryCount(); 1324 for ( SCSIZE j = 0; j < nEntries; j++ ) 1325 { 1326 ScQueryEntry& rEntry = aParam.GetEntry( j ); 1327 if ( rEntry.bDoQuery ) 1328 { 1329 switch ( rEntry.eOp ) 1330 { 1331 case SC_LESS_EQUAL : 1332 case SC_GREATER_EQUAL : 1333 rEntry.eOp = SC_EQUAL; 1334 break; 1335 default: 1336 { 1337 // added to avoid warnings 1338 } 1339 } 1340 } 1341 else 1342 break; // for 1343 } 1344 SCSIZE nColRowSave; 1345 bIgnoreMismatchOnLeadingStrings = sal_False; 1346 SetTestEqualCondition( sal_False ); 1347 do 1348 { 1349 nFoundCol = GetCol(); 1350 nFoundRow = GetRow(); 1351 nColRowSave = nColRow; 1352 } while (GetNext()); 1353 // Step back conditions same as above 1354 nCol = nFoundCol; 1355 nRow = nFoundRow; 1356 nColRow = nColRowSave; 1357 return sal_True; 1358 } 1359 if ( (bSearchForEqualAfterMismatch || aParam.bRegExp) && 1360 StoppedOnMismatch() ) 1361 { 1362 // Assume found entry to be the last value less than respectively 1363 // greater than the query. But keep on searching for an equal match. 1364 SCSIZE nEntries = aParam.GetEntryCount(); 1365 for ( SCSIZE j = 0; j < nEntries; j++ ) 1366 { 1367 ScQueryEntry& rEntry = aParam.GetEntry( j ); 1368 if ( rEntry.bDoQuery ) 1369 { 1370 switch ( rEntry.eOp ) 1371 { 1372 case SC_LESS_EQUAL : 1373 case SC_GREATER_EQUAL : 1374 rEntry.eOp = SC_EQUAL; 1375 break; 1376 default: 1377 { 1378 // added to avoid warnings 1379 } 1380 } 1381 } 1382 else 1383 break; // for 1384 } 1385 SetStopOnMismatch( sal_False ); 1386 SetTestEqualCondition( sal_False ); 1387 if (GetNext()) 1388 { 1389 // Last of a consecutive area, avoid searching the entire parameter 1390 // range as it is a real performance bottleneck in case of regular 1391 // expressions. 1392 SCSIZE nColRowSave; 1393 do 1394 { 1395 nFoundCol = GetCol(); 1396 nFoundRow = GetRow(); 1397 nColRowSave = nColRow; 1398 SetStopOnMismatch( sal_True ); 1399 } while (GetNext()); 1400 nCol = nFoundCol; 1401 nRow = nFoundRow; 1402 nColRow = nColRowSave; 1403 } 1404 } 1405 return (nFoundCol <= MAXCOL) && (nFoundRow <= MAXROW); 1406 } 1407 1408 1409 ScBaseCell* ScQueryCellIterator::BinarySearch() 1410 { 1411 nCol = aParam.nCol1; 1412 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol]; 1413 if (!pCol->nCount) 1414 return 0; 1415 1416 ScBaseCell* pCell; 1417 SCSIZE nHi, nLo; 1418 CollatorWrapper* pCollator = (aParam.bCaseSens ? ScGlobal::GetCaseCollator() : 1419 ScGlobal::GetCollator()); 1420 SvNumberFormatter& rFormatter = *(pDoc->GetFormatTable()); 1421 const ScQueryEntry& rEntry = aParam.GetEntry(0); 1422 bool bLessEqual = rEntry.eOp == SC_LESS_EQUAL; 1423 bool bByString = rEntry.bQueryByString; 1424 bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings && !bByString; 1425 bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings && 1426 !aParam.bHasHeader && bByString; 1427 1428 nRow = aParam.nRow1; 1429 if (aParam.bHasHeader) 1430 nRow++; 1431 const ColEntry* pItems = pCol->pItems; 1432 if (pCol->Search( nRow, nLo ) && bFirstStringIgnore && 1433 pItems[nLo].pCell->HasStringData()) 1434 { 1435 String aCellStr; 1436 sal_uLong nFormat = pCol->GetNumberFormat( pItems[nLo].nRow); 1437 ScCellFormat::GetInputString( pItems[nLo].pCell, nFormat, aCellStr, 1438 rFormatter); 1439 sal_Int32 nTmp = pCollator->compareString( aCellStr, *rEntry.pStr); 1440 if ((rEntry.eOp == SC_LESS_EQUAL && nTmp > 0) || 1441 (rEntry.eOp == SC_GREATER_EQUAL && nTmp < 0) || 1442 (rEntry.eOp == SC_EQUAL && nTmp != 0)) 1443 ++nLo; 1444 } 1445 if (!pCol->Search( aParam.nRow2, nHi ) && nHi>0) 1446 --nHi; 1447 while (bAllStringIgnore && nLo <= nHi && nLo < pCol->nCount && 1448 pItems[nLo].pCell->HasStringData()) 1449 ++nLo; 1450 1451 // Bookkeeping values for breaking up the binary search in case the data 1452 // range isn't strictly sorted. 1453 SCSIZE nLastInRange = nLo; 1454 SCSIZE nFirstLastInRange = nLastInRange; 1455 double fLastInRangeValue = bLessEqual ? 1456 -(::std::numeric_limits<double>::max()) : 1457 ::std::numeric_limits<double>::max(); 1458 String aLastInRangeString; 1459 if (!bLessEqual) 1460 aLastInRangeString.Assign( sal_Unicode(0xFFFF)); 1461 if (nLastInRange < pCol->nCount) 1462 { 1463 pCell = pItems[nLastInRange].pCell; 1464 if (pCell->HasStringData()) 1465 { 1466 sal_uLong nFormat = pCol->GetNumberFormat( pItems[nLastInRange].nRow); 1467 ScCellFormat::GetInputString( pCell, nFormat, aLastInRangeString, 1468 rFormatter); 1469 } 1470 else 1471 { 1472 switch ( pCell->GetCellType() ) 1473 { 1474 case CELLTYPE_VALUE : 1475 fLastInRangeValue = 1476 static_cast<ScValueCell*>(pCell)->GetValue(); 1477 break; 1478 case CELLTYPE_FORMULA : 1479 fLastInRangeValue = 1480 static_cast<ScFormulaCell*>(pCell)->GetValue(); 1481 break; 1482 default: 1483 { 1484 // added to avoid warnings 1485 } 1486 } 1487 } 1488 } 1489 1490 sal_Int32 nRes = 0; 1491 bool bFound = false; 1492 bool bDone = false; 1493 while (nLo <= nHi && !bDone) 1494 { 1495 SCSIZE nMid = (nLo+nHi)/2; 1496 SCSIZE i = nMid; 1497 while (i <= nHi && pItems[i].pCell->GetCellType() == CELLTYPE_NOTE) 1498 ++i; 1499 if (i > nHi) 1500 { 1501 if (nMid > 0) 1502 nHi = nMid - 1; 1503 else 1504 bDone = true; 1505 continue; // while 1506 } 1507 sal_Bool bStr = pItems[i].pCell->HasStringData(); 1508 nRes = 0; 1509 // compares are content<query:-1, content>query:1 1510 // Cell value comparison similar to ScTable::ValidQuery() 1511 if (!bStr && !bByString) 1512 { 1513 double nCellVal; 1514 pCell = pItems[i].pCell; 1515 switch ( pCell->GetCellType() ) 1516 { 1517 case CELLTYPE_VALUE : 1518 nCellVal = static_cast<ScValueCell*>(pCell)->GetValue(); 1519 break; 1520 case CELLTYPE_FORMULA : 1521 nCellVal = static_cast<ScFormulaCell*>(pCell)->GetValue(); 1522 break; 1523 default: 1524 nCellVal = 0.0; 1525 } 1526 if ((nCellVal < rEntry.nVal) && !::rtl::math::approxEqual( 1527 nCellVal, rEntry.nVal)) 1528 { 1529 nRes = -1; 1530 if (bLessEqual) 1531 { 1532 if (fLastInRangeValue < nCellVal) 1533 { 1534 fLastInRangeValue = nCellVal; 1535 nLastInRange = i; 1536 } 1537 else if (fLastInRangeValue > nCellVal) 1538 { 1539 // not strictly sorted, continue with GetThis() 1540 nLastInRange = nFirstLastInRange; 1541 bDone = true; 1542 } 1543 } 1544 } 1545 else if ((nCellVal > rEntry.nVal) && !::rtl::math::approxEqual( 1546 nCellVal, rEntry.nVal)) 1547 { 1548 nRes = 1; 1549 if (!bLessEqual) 1550 { 1551 if (fLastInRangeValue > nCellVal) 1552 { 1553 fLastInRangeValue = nCellVal; 1554 nLastInRange = i; 1555 } 1556 else if (fLastInRangeValue < nCellVal) 1557 { 1558 // not strictly sorted, continue with GetThis() 1559 nLastInRange = nFirstLastInRange; 1560 bDone = true; 1561 } 1562 } 1563 } 1564 } 1565 else if (bStr && bByString) 1566 { 1567 String aCellStr; 1568 sal_uLong nFormat = pCol->GetNumberFormat( pItems[i].nRow); 1569 ScCellFormat::GetInputString( pItems[i].pCell, nFormat, aCellStr, 1570 rFormatter); 1571 nRes = pCollator->compareString( aCellStr, *rEntry.pStr); 1572 if (nRes < 0 && bLessEqual) 1573 { 1574 sal_Int32 nTmp = pCollator->compareString( aLastInRangeString, 1575 aCellStr); 1576 if (nTmp < 0) 1577 { 1578 aLastInRangeString = aCellStr; 1579 nLastInRange = i; 1580 } 1581 else if (nTmp > 0) 1582 { 1583 // not strictly sorted, continue with GetThis() 1584 nLastInRange = nFirstLastInRange; 1585 bDone = true; 1586 } 1587 } 1588 else if (nRes > 0 && !bLessEqual) 1589 { 1590 sal_Int32 nTmp = pCollator->compareString( aLastInRangeString, 1591 aCellStr); 1592 if (nTmp > 0) 1593 { 1594 aLastInRangeString = aCellStr; 1595 nLastInRange = i; 1596 } 1597 else if (nTmp < 0) 1598 { 1599 // not strictly sorted, continue with GetThis() 1600 nLastInRange = nFirstLastInRange; 1601 bDone = true; 1602 } 1603 } 1604 } 1605 else if (!bStr && bByString) 1606 { 1607 nRes = -1; // numeric < string 1608 if (bLessEqual) 1609 nLastInRange = i; 1610 } 1611 else // if (bStr && !bByString) 1612 { 1613 nRes = 1; // string > numeric 1614 if (!bLessEqual) 1615 nLastInRange = i; 1616 } 1617 if (nRes < 0) 1618 { 1619 if (bLessEqual) 1620 nLo = nMid + 1; 1621 else // assumed to be SC_GREATER_EQUAL 1622 { 1623 if (nMid > 0) 1624 nHi = nMid - 1; 1625 else 1626 bDone = true; 1627 } 1628 } 1629 else if (nRes > 0) 1630 { 1631 if (bLessEqual) 1632 { 1633 if (nMid > 0) 1634 nHi = nMid - 1; 1635 else 1636 bDone = true; 1637 } 1638 else // assumed to be SC_GREATER_EQUAL 1639 nLo = nMid + 1; 1640 } 1641 else 1642 { 1643 nLo = i; 1644 bDone = bFound = true; 1645 } 1646 } 1647 if (!bFound) 1648 { 1649 // If all hits didn't result in a moving limit there's something 1650 // strange, e.g. data range not properly sorted, or only identical 1651 // values encountered, which doesn't mean there aren't any others in 1652 // between.. leave it to GetThis(). The condition for this would be 1653 // if (nLastInRange == nFirstLastInRange) nLo = nFirstLastInRange; 1654 // Else, in case no exact match was found, we step back for a 1655 // subsequent GetThis() to find the last in range. Effectively this is 1656 // --nLo with nLastInRange == nLo-1. Both conditions combined yield: 1657 nLo = nLastInRange; 1658 } 1659 if (nLo < pCol->nCount && pCol->pItems[nLo].nRow <= aParam.nRow2) 1660 { 1661 nRow = pItems[nLo].nRow; 1662 pCell = pItems[nLo].pCell; 1663 nColRow = nLo; 1664 } 1665 else 1666 { 1667 nRow = aParam.nRow2 + 1; 1668 pCell = 0; 1669 nColRow = pCol->nCount - 1; 1670 } 1671 return pCell; 1672 } 1673 1674 1675 //------------------------------------------------------------------------------- 1676 1677 ScHorizontalCellIterator::ScHorizontalCellIterator(ScDocument* pDocument, SCTAB nTable, 1678 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) : 1679 pDoc( pDocument ), 1680 nTab( nTable ), 1681 nStartCol( nCol1 ), 1682 nEndCol( nCol2 ), 1683 nStartRow( nRow1 ), 1684 nEndRow( nRow2 ), 1685 nCol( nCol1 ), 1686 nRow( nRow1 ), 1687 bMore( sal_True ) 1688 { 1689 1690 pNextRows = new SCROW[ nCol2-nCol1+1 ]; 1691 pNextIndices = new SCSIZE[ nCol2-nCol1+1 ]; 1692 1693 SetTab( nTab ); 1694 } 1695 1696 ScHorizontalCellIterator::~ScHorizontalCellIterator() 1697 { 1698 delete [] pNextRows; 1699 delete [] pNextIndices; 1700 } 1701 1702 void ScHorizontalCellIterator::SetTab( SCTAB nTabP ) 1703 { 1704 nTab = nTabP; 1705 nRow = nStartRow; 1706 nCol = nStartCol; 1707 bMore = sal_True; 1708 1709 for (SCCOL i=nStartCol; i<=nEndCol; i++) 1710 { 1711 ScColumn* pCol = &pDoc->pTab[nTab]->aCol[i]; 1712 1713 SCSIZE nIndex; 1714 pCol->Search( nStartRow, nIndex ); 1715 if ( nIndex < pCol->nCount ) 1716 { 1717 pNextRows[i-nStartCol] = pCol->pItems[nIndex].nRow; 1718 pNextIndices[i-nStartCol] = nIndex; 1719 } 1720 else 1721 { 1722 pNextRows[i-nStartCol] = MAXROWCOUNT; // nichts gefunden 1723 pNextIndices[i-nStartCol] = MAXROWCOUNT; 1724 } 1725 } 1726 1727 if (pNextRows[0] != nStartRow) 1728 Advance(); 1729 } 1730 1731 ScBaseCell* ScHorizontalCellIterator::GetNext( SCCOL& rCol, SCROW& rRow ) 1732 { 1733 if ( bMore ) 1734 { 1735 rCol = nCol; 1736 rRow = nRow; 1737 1738 ScColumn* pCol = &pDoc->pTab[nTab]->aCol[nCol]; 1739 SCSIZE nIndex = pNextIndices[nCol-nStartCol]; 1740 DBG_ASSERT( nIndex < pCol->nCount, "ScHorizontalCellIterator::GetNext: nIndex out of range" ); 1741 ScBaseCell* pCell = pCol->pItems[nIndex].pCell; 1742 if ( ++nIndex < pCol->nCount ) 1743 { 1744 pNextRows[nCol-nStartCol] = pCol->pItems[nIndex].nRow; 1745 pNextIndices[nCol-nStartCol] = nIndex; 1746 } 1747 else 1748 { 1749 pNextRows[nCol-nStartCol] = MAXROWCOUNT; // nichts gefunden 1750 pNextIndices[nCol-nStartCol] = MAXROWCOUNT; 1751 } 1752 1753 Advance(); 1754 return pCell; 1755 } 1756 else 1757 return NULL; 1758 } 1759 1760 sal_Bool ScHorizontalCellIterator::ReturnNext( SCCOL& rCol, SCROW& rRow ) 1761 { 1762 rCol = nCol; 1763 rRow = nRow; 1764 return bMore; 1765 } 1766 1767 void ScHorizontalCellIterator::Advance() 1768 { 1769 sal_Bool bFound = sal_False; 1770 SCCOL i; 1771 1772 for (i=nCol+1; i<=nEndCol && !bFound; i++) 1773 if (pNextRows[i-nStartCol] == nRow) 1774 { 1775 nCol = i; 1776 bFound = sal_True; 1777 } 1778 1779 if (!bFound) 1780 { 1781 SCROW nMinRow = MAXROW+1; 1782 for (i=nStartCol; i<=nEndCol; i++) 1783 if (pNextRows[i-nStartCol] < nMinRow) 1784 { 1785 nCol = i; 1786 nMinRow = pNextRows[i-nStartCol]; 1787 } 1788 1789 if (nMinRow <= nEndRow) 1790 { 1791 nRow = nMinRow; 1792 bFound = sal_True; 1793 } 1794 } 1795 1796 if ( !bFound ) 1797 bMore = sal_False; 1798 } 1799 1800 //------------------------------------------------------------------------ 1801 1802 ScHorizontalValueIterator::ScHorizontalValueIterator( ScDocument* pDocument, 1803 const ScRange& rRange, bool bSTotal, bool bTextZero ) : 1804 pDoc( pDocument ), 1805 nNumFmtIndex(0), 1806 nEndTab( rRange.aEnd.Tab() ), 1807 nNumFmtType( NUMBERFORMAT_UNDEFINED ), 1808 bNumValid( false ), 1809 bSubTotal( bSTotal ), 1810 bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ), 1811 bTextAsZero( bTextZero ) 1812 { 1813 SCCOL nStartCol = rRange.aStart.Col(); 1814 SCROW nStartRow = rRange.aStart.Row(); 1815 SCTAB nStartTab = rRange.aStart.Tab(); 1816 SCCOL nEndCol = rRange.aEnd.Col(); 1817 SCROW nEndRow = rRange.aEnd.Row(); 1818 PutInOrder( nStartCol, nEndCol); 1819 PutInOrder( nStartRow, nEndRow); 1820 PutInOrder( nStartTab, nEndTab ); 1821 1822 if (!ValidCol(nStartCol)) nStartCol = MAXCOL; 1823 if (!ValidCol(nEndCol)) nEndCol = MAXCOL; 1824 if (!ValidRow(nStartRow)) nStartRow = MAXROW; 1825 if (!ValidRow(nEndRow)) nEndRow = MAXROW; 1826 if (!ValidTab(nStartTab)) nStartTab = MAXTAB; 1827 if (!ValidTab(nEndTab)) nEndTab = MAXTAB; 1828 1829 nCurCol = nStartCol; 1830 nCurRow = nStartRow; 1831 nCurTab = nStartTab; 1832 1833 nNumFormat = 0; // will be initialized in GetNumberFormat() 1834 pAttrArray = 0; 1835 nAttrEndRow = 0; 1836 1837 pCellIter = new ScHorizontalCellIterator( pDoc, nStartTab, nStartCol, 1838 nStartRow, nEndCol, nEndRow ); 1839 } 1840 1841 ScHorizontalValueIterator::~ScHorizontalValueIterator() 1842 { 1843 delete pCellIter; 1844 } 1845 1846 bool ScHorizontalValueIterator::GetNext( double& rValue, sal_uInt16& rErr ) 1847 { 1848 bool bFound = false; 1849 while ( !bFound ) 1850 { 1851 ScBaseCell* pCell = pCellIter->GetNext( nCurCol, nCurRow ); 1852 while ( !pCell ) 1853 { 1854 if ( nCurTab < nEndTab ) 1855 { 1856 pCellIter->SetTab( ++nCurTab); 1857 pCell = pCellIter->GetNext( nCurCol, nCurRow ); 1858 } 1859 else 1860 return false; 1861 } 1862 if ( !bSubTotal || !pDoc->pTab[nCurTab]->RowFiltered( nCurRow ) ) 1863 { 1864 switch (pCell->GetCellType()) 1865 { 1866 case CELLTYPE_VALUE: 1867 { 1868 bNumValid = false; 1869 rValue = ((ScValueCell*)pCell)->GetValue(); 1870 rErr = 0; 1871 if ( bCalcAsShown ) 1872 { 1873 ScColumn* pCol = &pDoc->pTab[nCurTab]->aCol[nCurCol]; 1874 lcl_IterGetNumberFormat( nNumFormat, pAttrArray, 1875 nAttrEndRow, pCol->pAttrArray, nCurRow, pDoc ); 1876 rValue = pDoc->RoundValueAsShown( rValue, nNumFormat ); 1877 } 1878 bFound = true; 1879 } 1880 break; 1881 case CELLTYPE_FORMULA: 1882 { 1883 if (!bSubTotal || !((ScFormulaCell*)pCell)->IsSubTotal()) 1884 { 1885 rErr = ((ScFormulaCell*)pCell)->GetErrCode(); 1886 if ( rErr || ((ScFormulaCell*)pCell)->IsValue() ) 1887 { 1888 rValue = ((ScFormulaCell*)pCell)->GetValue(); 1889 bNumValid = false; 1890 bFound = true; 1891 } 1892 else if ( bTextAsZero ) 1893 { 1894 rValue = 0.0; 1895 bNumValid = false; 1896 bFound = true; 1897 } 1898 } 1899 } 1900 break; 1901 case CELLTYPE_STRING : 1902 case CELLTYPE_EDIT : 1903 { 1904 if ( bTextAsZero ) 1905 { 1906 rErr = 0; 1907 rValue = 0.0; 1908 nNumFmtType = NUMBERFORMAT_NUMBER; 1909 nNumFmtIndex = 0; 1910 bNumValid = true; 1911 bFound = true; 1912 } 1913 } 1914 break; 1915 default: 1916 ; // nothing 1917 } 1918 } 1919 } 1920 return bFound; 1921 } 1922 1923 void ScHorizontalValueIterator::GetCurNumFmtInfo( short& nType, sal_uLong& nIndex ) 1924 { 1925 if (!bNumValid) 1926 { 1927 const ScColumn* pCol = &(pDoc->pTab[nCurTab])->aCol[nCurCol]; 1928 nNumFmtIndex = pCol->GetNumberFormat( nCurRow ); 1929 if ( (nNumFmtIndex % SV_COUNTRY_LANGUAGE_OFFSET) == 0 ) 1930 { 1931 const ScBaseCell* pCell; 1932 SCSIZE nCurIndex; 1933 if ( pCol->Search( nCurRow, nCurIndex ) ) 1934 pCell = pCol->pItems[nCurIndex].pCell; 1935 else 1936 pCell = NULL; 1937 if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA ) 1938 ((const ScFormulaCell*)pCell)->GetFormatInfo( nNumFmtType, nNumFmtIndex ); 1939 else 1940 nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex ); 1941 } 1942 else 1943 nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex ); 1944 bNumValid = true; 1945 } 1946 nType = nNumFmtType; 1947 nIndex = nNumFmtIndex; 1948 } 1949 1950 //------------------------------------------------------------------------------- 1951 1952 ScHorizontalAttrIterator::ScHorizontalAttrIterator( ScDocument* pDocument, SCTAB nTable, 1953 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) : 1954 pDoc( pDocument ), 1955 nTab( nTable ), 1956 nStartCol( nCol1 ), 1957 nStartRow( nRow1 ), 1958 nEndCol( nCol2 ), 1959 nEndRow( nRow2 ) 1960 { 1961 DBG_ASSERT( pDoc->pTab[nTab], "Tabelle nicht da" ); 1962 1963 SCCOL i; 1964 1965 nRow = nStartRow; 1966 nCol = nStartCol; 1967 bRowEmpty = sal_False; 1968 1969 pIndices = new SCSIZE[nEndCol-nStartCol+1]; 1970 pNextEnd = new SCROW[nEndCol-nStartCol+1]; 1971 ppPatterns = new const ScPatternAttr*[nEndCol-nStartCol+1]; 1972 1973 SCROW nSkipTo = MAXROW; 1974 sal_Bool bEmpty = sal_True; 1975 for (i=nStartCol; i<=nEndCol; i++) 1976 { 1977 SCCOL nPos = i - nStartCol; 1978 ScAttrArray* pArray = pDoc->pTab[nTab]->aCol[i].pAttrArray; 1979 DBG_ASSERT( pArray, "pArray == 0" ); 1980 1981 SCSIZE nIndex; 1982 pArray->Search( nStartRow, nIndex ); 1983 1984 const ScPatternAttr* pPattern = pArray->pData[nIndex].pPattern; 1985 SCROW nThisEnd = pArray->pData[nIndex].nRow; 1986 if ( IsDefaultItem( pPattern ) ) 1987 { 1988 pPattern = NULL; 1989 if ( nThisEnd < nSkipTo ) 1990 nSkipTo = nThisEnd; // nSkipTo kann gleich hier gesetzt werden 1991 } 1992 else 1993 bEmpty = sal_False; // Attribute gefunden 1994 1995 pIndices[nPos] = nIndex; 1996 pNextEnd[nPos] = nThisEnd; 1997 ppPatterns[nPos] = pPattern; 1998 } 1999 2000 if (bEmpty) 2001 nRow = nSkipTo; // bis zum naechsten Bereichsende ueberspringen 2002 bRowEmpty = bEmpty; 2003 } 2004 2005 ScHorizontalAttrIterator::~ScHorizontalAttrIterator() 2006 { 2007 delete[] (ScPatternAttr**)ppPatterns; 2008 delete[] pNextEnd; 2009 delete[] pIndices; 2010 } 2011 2012 const ScPatternAttr* ScHorizontalAttrIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2, SCROW& rRow ) 2013 { 2014 for (;;) 2015 { 2016 if (!bRowEmpty) 2017 { 2018 // in dieser Zeile suchen 2019 2020 while ( nCol <= nEndCol && !ppPatterns[nCol-nStartCol] ) 2021 ++nCol; 2022 2023 if ( nCol <= nEndCol ) 2024 { 2025 const ScPatternAttr* pPat = ppPatterns[nCol-nStartCol]; 2026 rRow = nRow; 2027 rCol1 = nCol; 2028 while ( nCol < nEndCol && ppPatterns[nCol+1-nStartCol] == pPat ) 2029 ++nCol; 2030 rCol2 = nCol; 2031 ++nCol; // hochzaehlen fuer naechsten Aufruf 2032 return pPat; // gefunden 2033 } 2034 } 2035 2036 // naechste Zeile 2037 2038 ++nRow; 2039 if ( nRow > nEndRow ) // schon am Ende? 2040 return NULL; // nichts gefunden 2041 2042 sal_Bool bEmpty = sal_True; 2043 SCCOL i; 2044 2045 for ( i = nStartCol; i <= nEndCol; i++) 2046 { 2047 SCCOL nPos = i-nStartCol; 2048 if ( pNextEnd[nPos] < nRow ) 2049 { 2050 ScAttrArray* pArray = pDoc->pTab[nTab]->aCol[i].pAttrArray; 2051 2052 SCSIZE nIndex = ++pIndices[nPos]; 2053 if ( nIndex < pArray->nCount ) 2054 { 2055 const ScPatternAttr* pPattern = pArray->pData[nIndex].pPattern; 2056 SCROW nThisEnd = pArray->pData[nIndex].nRow; 2057 if ( IsDefaultItem( pPattern ) ) 2058 pPattern = NULL; 2059 else 2060 bEmpty = sal_False; // Attribute gefunden 2061 2062 pNextEnd[nPos] = nThisEnd; 2063 ppPatterns[nPos] = pPattern; 2064 2065 DBG_ASSERT( pNextEnd[nPos] >= nRow, "Reihenfolge durcheinander" ); 2066 } 2067 else 2068 { 2069 DBG_ERROR("AttrArray reicht nicht bis MAXROW"); 2070 pNextEnd[nPos] = MAXROW; 2071 ppPatterns[nPos] = NULL; 2072 } 2073 } 2074 else if ( ppPatterns[nPos] ) 2075 bEmpty = sal_False; // Bereich noch nicht zuende 2076 } 2077 2078 if (bEmpty) 2079 { 2080 SCCOL nCount = nEndCol-nStartCol+1; 2081 SCROW nSkipTo = pNextEnd[0]; // naechstes Bereichsende suchen 2082 for (i=1; i<nCount; i++) 2083 if ( pNextEnd[i] < nSkipTo ) 2084 nSkipTo = pNextEnd[i]; 2085 nRow = nSkipTo; // leere Zeilen ueberspringen 2086 } 2087 bRowEmpty = bEmpty; 2088 nCol = nStartCol; // wieder links anfangen 2089 } 2090 2091 // return NULL; 2092 } 2093 2094 //------------------------------------------------------------------------------- 2095 2096 inline sal_Bool IsGreater( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) 2097 { 2098 return ( nRow1 > nRow2 ) || ( nRow1 == nRow2 && nCol1 > nCol2 ); 2099 } 2100 2101 ScUsedAreaIterator::ScUsedAreaIterator( ScDocument* pDocument, SCTAB nTable, 2102 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) : 2103 aCellIter( pDocument, nTable, nCol1, nRow1, nCol2, nRow2 ), 2104 aAttrIter( pDocument, nTable, nCol1, nRow1, nCol2, nRow2 ), 2105 nNextCol( nCol1 ), 2106 nNextRow( nRow1 ) 2107 { 2108 pCell = aCellIter.GetNext( nCellCol, nCellRow ); 2109 pPattern = aAttrIter.GetNext( nAttrCol1, nAttrCol2, nAttrRow ); 2110 } 2111 2112 ScUsedAreaIterator::~ScUsedAreaIterator() 2113 { 2114 } 2115 2116 sal_Bool ScUsedAreaIterator::GetNext() 2117 { 2118 // Iteratoren weiterzaehlen 2119 2120 if ( pCell && IsGreater( nNextCol, nNextRow, nCellCol, nCellRow ) ) 2121 pCell = aCellIter.GetNext( nCellCol, nCellRow ); 2122 2123 while ( pCell && pCell->IsBlank() ) 2124 pCell = aCellIter.GetNext( nCellCol, nCellRow ); 2125 2126 if ( pPattern && IsGreater( nNextCol, nNextRow, nAttrCol2, nAttrRow ) ) 2127 pPattern = aAttrIter.GetNext( nAttrCol1, nAttrCol2, nAttrRow ); 2128 2129 if ( pPattern && nAttrRow == nNextRow && nAttrCol1 < nNextCol ) 2130 nAttrCol1 = nNextCol; 2131 2132 // naechsten Abschnitt heraussuchen 2133 2134 sal_Bool bFound = sal_True; 2135 sal_Bool bUseCell = sal_False; 2136 2137 if ( pCell && pPattern ) 2138 { 2139 if ( IsGreater( nCellCol, nCellRow, nAttrCol1, nAttrRow ) ) // vorne nur Attribute ? 2140 { 2141 pFoundCell = NULL; 2142 pFoundPattern = pPattern; 2143 nFoundRow = nAttrRow; 2144 nFoundStartCol = nAttrCol1; 2145 if ( nCellRow == nAttrRow && nCellCol <= nAttrCol2 ) // auch Zelle im Bereich ? 2146 nFoundEndCol = nCellCol - 1; // nur bis vor der Zelle 2147 else 2148 nFoundEndCol = nAttrCol2; // alles 2149 } 2150 else 2151 { 2152 bUseCell = sal_True; 2153 if ( nAttrRow == nCellRow && nAttrCol1 == nCellCol ) // Attribute auf der Zelle ? 2154 pFoundPattern = pPattern; 2155 else 2156 pFoundPattern = NULL; 2157 } 2158 } 2159 else if ( pCell ) // nur Zelle -> direkt uebernehmen 2160 { 2161 pFoundPattern = NULL; 2162 bUseCell = sal_True; // Position von Zelle 2163 } 2164 else if ( pPattern ) // nur Attribute -> direkt uebernehmen 2165 { 2166 pFoundCell = NULL; 2167 pFoundPattern = pPattern; 2168 nFoundRow = nAttrRow; 2169 nFoundStartCol = nAttrCol1; 2170 nFoundEndCol = nAttrCol2; 2171 } 2172 else // gar nichts 2173 bFound = sal_False; 2174 2175 if ( bUseCell ) // Position von Zelle 2176 { 2177 pFoundCell = pCell; 2178 nFoundRow = nCellRow; 2179 nFoundStartCol = nFoundEndCol = nCellCol; 2180 } 2181 2182 if (bFound) 2183 { 2184 nNextRow = nFoundRow; 2185 nNextCol = nFoundEndCol + 1; 2186 } 2187 2188 return bFound; 2189 } 2190 2191 //------------------------------------------------------------------------------- 2192 2193 ScDocAttrIterator::ScDocAttrIterator(ScDocument* pDocument, SCTAB nTable, 2194 SCCOL nCol1, SCROW nRow1, 2195 SCCOL nCol2, SCROW nRow2) : 2196 pDoc( pDocument ), 2197 nTab( nTable ), 2198 nEndCol( nCol2 ), 2199 nStartRow( nRow1 ), 2200 nEndRow( nRow2 ), 2201 nCol( nCol1 ) 2202 { 2203 if ( ValidTab(nTab) && pDoc->pTab[nTab] ) 2204 pColIter = pDoc->pTab[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow ); 2205 else 2206 pColIter = NULL; 2207 } 2208 2209 ScDocAttrIterator::~ScDocAttrIterator() 2210 { 2211 delete pColIter; 2212 } 2213 2214 const ScPatternAttr* ScDocAttrIterator::GetNext( SCCOL& rCol, SCROW& rRow1, SCROW& rRow2 ) 2215 { 2216 while ( pColIter ) 2217 { 2218 const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 ); 2219 if ( pPattern ) 2220 { 2221 rCol = nCol; 2222 return pPattern; 2223 } 2224 2225 delete pColIter; 2226 ++nCol; 2227 if ( nCol <= nEndCol ) 2228 pColIter = pDoc->pTab[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow ); 2229 else 2230 pColIter = NULL; 2231 } 2232 return NULL; // is nix mehr 2233 } 2234 2235 //------------------------------------------------------------------------------- 2236 2237 ScAttrRectIterator::ScAttrRectIterator(ScDocument* pDocument, SCTAB nTable, 2238 SCCOL nCol1, SCROW nRow1, 2239 SCCOL nCol2, SCROW nRow2) : 2240 pDoc( pDocument ), 2241 nTab( nTable ), 2242 nEndCol( nCol2 ), 2243 nStartRow( nRow1 ), 2244 nEndRow( nRow2 ), 2245 nIterStartCol( nCol1 ), 2246 nIterEndCol( nCol1 ) 2247 { 2248 if ( ValidTab(nTab) && pDoc->pTab[nTab] ) 2249 { 2250 pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow ); 2251 while ( nIterEndCol < nEndCol && 2252 pDoc->pTab[nTab]->aCol[nIterEndCol].IsAllAttrEqual( 2253 pDoc->pTab[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) ) 2254 ++nIterEndCol; 2255 } 2256 else 2257 pColIter = NULL; 2258 } 2259 2260 ScAttrRectIterator::~ScAttrRectIterator() 2261 { 2262 delete pColIter; 2263 } 2264 2265 void ScAttrRectIterator::DataChanged() 2266 { 2267 if (pColIter) 2268 { 2269 SCROW nNextRow = pColIter->GetNextRow(); 2270 delete pColIter; 2271 pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nNextRow, nEndRow ); 2272 } 2273 } 2274 2275 const ScPatternAttr* ScAttrRectIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2, 2276 SCROW& rRow1, SCROW& rRow2 ) 2277 { 2278 while ( pColIter ) 2279 { 2280 const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 ); 2281 if ( pPattern ) 2282 { 2283 rCol1 = nIterStartCol; 2284 rCol2 = nIterEndCol; 2285 return pPattern; 2286 } 2287 2288 delete pColIter; 2289 nIterStartCol = nIterEndCol+1; 2290 if ( nIterStartCol <= nEndCol ) 2291 { 2292 nIterEndCol = nIterStartCol; 2293 pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow ); 2294 while ( nIterEndCol < nEndCol && 2295 pDoc->pTab[nTab]->aCol[nIterEndCol].IsAllAttrEqual( 2296 pDoc->pTab[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) ) 2297 ++nIterEndCol; 2298 } 2299 else 2300 pColIter = NULL; 2301 } 2302 return NULL; // is nix mehr 2303 } 2304 2305 // ============================================================================ 2306 2307 SCROW ScRowBreakIterator::NOT_FOUND = -1; 2308 2309 ScRowBreakIterator::ScRowBreakIterator(set<SCROW>& rBreaks) : 2310 mrBreaks(rBreaks), 2311 maItr(rBreaks.begin()), maEnd(rBreaks.end()) 2312 { 2313 } 2314 2315 SCROW ScRowBreakIterator::first() 2316 { 2317 maItr = mrBreaks.begin(); 2318 return maItr == maEnd ? NOT_FOUND : *maItr; 2319 } 2320 2321 SCROW ScRowBreakIterator::next() 2322 { 2323 ++maItr; 2324 return maItr == maEnd ? NOT_FOUND : *maItr; 2325 } 2326