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 <rtl/math.hxx> 28 #include <unotools/textsearch.hxx> 29 #include <svl/zforlist.hxx> 30 #include <svl/zformat.hxx> 31 #include <unotools/charclass.hxx> 32 #include <unotools/collatorwrapper.hxx> 33 #include <com/sun/star/i18n/CollatorOptions.hpp> 34 #include <stdlib.h> 35 #include <unotools/transliterationwrapper.hxx> 36 37 #include "table.hxx" 38 #include "scitems.hxx" 39 #include "collect.hxx" 40 #include "attrib.hxx" 41 #include "cell.hxx" 42 #include "document.hxx" 43 #include "globstr.hrc" 44 #include "global.hxx" 45 #include "stlpool.hxx" 46 #include "compiler.hxx" 47 #include "patattr.hxx" 48 #include "subtotal.hxx" 49 #include "docoptio.hxx" 50 #include "markdata.hxx" 51 #include "rangelst.hxx" 52 #include "attarray.hxx" 53 #include "userlist.hxx" 54 #include "progress.hxx" 55 #include "cellform.hxx" 56 #include "postit.hxx" 57 #include "queryparam.hxx" 58 #include "segmenttree.hxx" 59 #include "drwlayer.hxx" 60 61 #include <vector> 62 63 // STATIC DATA ----------------------------------------------------------- 64 65 const sal_uInt16 nMaxSorts = 3; // maximale Anzahl Sortierkriterien in aSortParam 66 67 struct ScSortInfo 68 { 69 ScBaseCell* pCell; 70 SCCOLROW nOrg; 71 DECL_FIXEDMEMPOOL_NEWDEL( ScSortInfo ); 72 }; 73 const sal_uInt16 nMemPoolSortInfo = (0x8000 - 64) / sizeof(ScSortInfo); 74 IMPL_FIXEDMEMPOOL_NEWDEL( ScSortInfo, nMemPoolSortInfo, nMemPoolSortInfo ) 75 76 // END OF STATIC DATA ----------------------------------------------------- 77 78 79 class ScSortInfoArray 80 { 81 private: 82 ScSortInfo** pppInfo[nMaxSorts]; 83 SCSIZE nCount; 84 SCCOLROW nStart; 85 sal_uInt16 nUsedSorts; 86 87 public: 88 ScSortInfoArray( sal_uInt16 nSorts, SCCOLROW nInd1, SCCOLROW nInd2 ) : 89 nCount( nInd2 - nInd1 + 1 ), nStart( nInd1 ), 90 nUsedSorts( Min( nSorts, nMaxSorts ) ) 91 { 92 for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ ) 93 { 94 ScSortInfo** ppInfo = new ScSortInfo* [nCount]; 95 for ( SCSIZE j = 0; j < nCount; j++ ) 96 ppInfo[j] = new ScSortInfo; 97 pppInfo[nSort] = ppInfo; 98 } 99 } 100 ~ScSortInfoArray() 101 { 102 for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ ) 103 { 104 ScSortInfo** ppInfo = pppInfo[nSort]; 105 for ( SCSIZE j = 0; j < nCount; j++ ) 106 delete ppInfo[j]; 107 delete [] ppInfo; 108 } 109 } 110 ScSortInfo* Get( sal_uInt16 nSort, SCCOLROW nInd ) 111 { return (pppInfo[nSort])[ nInd - nStart ]; } 112 void Swap( SCCOLROW nInd1, SCCOLROW nInd2 ) 113 { 114 SCSIZE n1 = static_cast<SCSIZE>(nInd1 - nStart); 115 SCSIZE n2 = static_cast<SCSIZE>(nInd2 - nStart); 116 for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ ) 117 { 118 ScSortInfo** ppInfo = pppInfo[nSort]; 119 ScSortInfo* pTmp = ppInfo[n1]; 120 ppInfo[n1] = ppInfo[n2]; 121 ppInfo[n2] = pTmp; 122 } 123 } 124 sal_uInt16 GetUsedSorts() { return nUsedSorts; } 125 ScSortInfo** GetFirstArray() { return pppInfo[0]; } 126 SCCOLROW GetStart() { return nStart; } 127 SCSIZE GetCount() { return nCount; } 128 }; 129 130 ScSortInfoArray* ScTable::CreateSortInfoArray( SCCOLROW nInd1, SCCOLROW nInd2 ) 131 { 132 sal_uInt16 nUsedSorts = 1; 133 while ( nUsedSorts < nMaxSorts && aSortParam.bDoSort[nUsedSorts] ) 134 nUsedSorts++; 135 ScSortInfoArray* pArray = new ScSortInfoArray( nUsedSorts, nInd1, nInd2 ); 136 if ( aSortParam.bByRow ) 137 { 138 for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ ) 139 { 140 SCCOL nCol = static_cast<SCCOL>(aSortParam.nField[nSort]); 141 ScColumn* pCol = &aCol[nCol]; 142 for ( SCROW nRow = nInd1; nRow <= nInd2; nRow++ ) 143 { 144 //2do: FillSortInfo an ScColumn und Array abklappern statt Search in GetCell 145 ScSortInfo* pInfo = pArray->Get( nSort, nRow ); 146 pInfo->pCell = pCol->GetCell( nRow ); 147 pInfo->nOrg = nRow; 148 } 149 } 150 } 151 else 152 { 153 for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ ) 154 { 155 SCROW nRow = aSortParam.nField[nSort]; 156 for ( SCCOL nCol = static_cast<SCCOL>(nInd1); 157 nCol <= static_cast<SCCOL>(nInd2); nCol++ ) 158 { 159 ScSortInfo* pInfo = pArray->Get( nSort, nCol ); 160 pInfo->pCell = GetCell( nCol, nRow ); 161 pInfo->nOrg = nCol; 162 } 163 } 164 } 165 return pArray; 166 } 167 168 169 sal_Bool ScTable::IsSortCollatorGlobal() const 170 { 171 return pSortCollator == ScGlobal::GetCollator() || 172 pSortCollator == ScGlobal::GetCaseCollator(); 173 } 174 175 176 void ScTable::InitSortCollator( const ScSortParam& rPar ) 177 { 178 if ( rPar.aCollatorLocale.Language.getLength() ) 179 { 180 if ( !pSortCollator || IsSortCollatorGlobal() ) 181 pSortCollator = new CollatorWrapper( pDocument->GetServiceManager() ); 182 pSortCollator->loadCollatorAlgorithm( rPar.aCollatorAlgorithm, 183 rPar.aCollatorLocale, (rPar.bCaseSens ? 0 : SC_COLLATOR_IGNORES) ); 184 } 185 else 186 { // SYSTEM 187 DestroySortCollator(); 188 pSortCollator = (rPar.bCaseSens ? ScGlobal::GetCaseCollator() : 189 ScGlobal::GetCollator()); 190 } 191 } 192 193 194 void ScTable::DestroySortCollator() 195 { 196 if ( pSortCollator ) 197 { 198 if ( !IsSortCollatorGlobal() ) 199 delete pSortCollator; 200 pSortCollator = NULL; 201 } 202 } 203 204 205 void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress& rProgress ) 206 { 207 sal_Bool bByRow = aSortParam.bByRow; 208 SCSIZE nCount = pArray->GetCount(); 209 SCCOLROW nStart = pArray->GetStart(); 210 ScSortInfo** ppInfo = pArray->GetFirstArray(); 211 ::std::vector<ScSortInfo*> aTable(nCount); 212 SCSIZE nPos; 213 for ( nPos = 0; nPos < nCount; nPos++ ) 214 aTable[ppInfo[nPos]->nOrg - nStart] = ppInfo[nPos]; 215 216 SCCOLROW nDest = nStart; 217 for ( nPos = 0; nPos < nCount; nPos++, nDest++ ) 218 { 219 SCCOLROW nOrg = ppInfo[nPos]->nOrg; 220 if ( nDest != nOrg ) 221 { 222 if ( bByRow ) 223 SwapRow( nDest, nOrg ); 224 else 225 SwapCol( static_cast<SCCOL>(nDest), static_cast<SCCOL>(nOrg) ); 226 // neue Position des weggeswapten eintragen 227 ScSortInfo* p = ppInfo[nPos]; 228 p->nOrg = nDest; 229 ::std::swap(p, aTable[nDest-nStart]); 230 p->nOrg = nOrg; 231 ::std::swap(p, aTable[nOrg-nStart]); 232 DBG_ASSERT( p == ppInfo[nPos], "SortReorder: nOrg MisMatch" ); 233 } 234 rProgress.SetStateOnPercent( nPos ); 235 } 236 } 237 238 short ScTable::CompareCell( sal_uInt16 nSort, 239 ScBaseCell* pCell1, SCCOL nCell1Col, SCROW nCell1Row, 240 ScBaseCell* pCell2, SCCOL nCell2Col, SCROW nCell2Row ) 241 { 242 short nRes = 0; 243 244 CellType eType1 = CELLTYPE_NONE, eType2 = CELLTYPE_NONE; 245 if (pCell1) 246 { 247 eType1 = pCell1->GetCellType(); 248 if (eType1 == CELLTYPE_NOTE) 249 pCell1 = NULL; 250 } 251 if (pCell2) 252 { 253 eType2 = pCell2->GetCellType(); 254 if (eType2 == CELLTYPE_NOTE) 255 pCell2 = NULL; 256 } 257 258 if (pCell1) 259 { 260 if (pCell2) 261 { 262 sal_Bool bStr1 = ( eType1 != CELLTYPE_VALUE ); 263 if ( eType1 == CELLTYPE_FORMULA && ((ScFormulaCell*)pCell1)->IsValue() ) 264 bStr1 = sal_False; 265 sal_Bool bStr2 = ( eType2 != CELLTYPE_VALUE ); 266 if ( eType2 == CELLTYPE_FORMULA && ((ScFormulaCell*)pCell2)->IsValue() ) 267 bStr2 = sal_False; 268 269 if ( bStr1 && bStr2 ) // nur Strings untereinander als String vergleichen! 270 { 271 String aStr1; 272 String aStr2; 273 if (eType1 == CELLTYPE_STRING) 274 ((ScStringCell*)pCell1)->GetString(aStr1); 275 else 276 GetString(nCell1Col, nCell1Row, aStr1); 277 if (eType2 == CELLTYPE_STRING) 278 ((ScStringCell*)pCell2)->GetString(aStr2); 279 else 280 GetString(nCell2Col, nCell2Row, aStr2); 281 sal_Bool bUserDef = aSortParam.bUserDef; 282 if (bUserDef) 283 { 284 ScUserListData* pData = 285 (ScUserListData*)(ScGlobal::GetUserList()->At( 286 aSortParam.nUserIndex)); 287 if (pData) 288 { 289 if ( aSortParam.bCaseSens ) 290 nRes = sal::static_int_cast<short>( pData->Compare(aStr1, aStr2) ); 291 else 292 nRes = sal::static_int_cast<short>( pData->ICompare(aStr1, aStr2) ); 293 } 294 else 295 bUserDef = sal_False; 296 297 } 298 if (!bUserDef) 299 nRes = (short) pSortCollator->compareString( aStr1, aStr2 ); 300 } 301 else if ( bStr1 ) // String <-> Zahl 302 nRes = 1; // Zahl vorne 303 else if ( bStr2 ) // Zahl <-> String 304 nRes = -1; // Zahl vorne 305 else // Zahlen untereinander 306 { 307 double nVal1; 308 double nVal2; 309 if (eType1 == CELLTYPE_VALUE) 310 nVal1 = ((ScValueCell*)pCell1)->GetValue(); 311 else if (eType1 == CELLTYPE_FORMULA) 312 nVal1 = ((ScFormulaCell*)pCell1)->GetValue(); 313 else 314 nVal1 = 0; 315 if (eType2 == CELLTYPE_VALUE) 316 nVal2 = ((ScValueCell*)pCell2)->GetValue(); 317 else if (eType2 == CELLTYPE_FORMULA) 318 nVal2 = ((ScFormulaCell*)pCell2)->GetValue(); 319 else 320 nVal2 = 0; 321 if (nVal1 < nVal2) 322 nRes = -1; 323 else if (nVal1 > nVal2) 324 nRes = 1; 325 } 326 if ( !aSortParam.bAscending[nSort] ) 327 nRes = -nRes; 328 } 329 else 330 nRes = -1; 331 } 332 else 333 { 334 if ( pCell2 ) 335 nRes = 1; 336 else 337 nRes = 0; // beide leer 338 } 339 return nRes; 340 } 341 342 short ScTable::Compare( ScSortInfoArray* pArray, SCCOLROW nIndex1, SCCOLROW nIndex2 ) 343 { 344 short nRes; 345 sal_uInt16 nSort = 0; 346 do 347 { 348 ScSortInfo* pInfo1 = pArray->Get( nSort, nIndex1 ); 349 ScSortInfo* pInfo2 = pArray->Get( nSort, nIndex2 ); 350 if ( aSortParam.bByRow ) 351 nRes = CompareCell( nSort, 352 pInfo1->pCell, static_cast<SCCOL>(aSortParam.nField[nSort]), pInfo1->nOrg, 353 pInfo2->pCell, static_cast<SCCOL>(aSortParam.nField[nSort]), pInfo2->nOrg ); 354 else 355 nRes = CompareCell( nSort, 356 pInfo1->pCell, static_cast<SCCOL>(pInfo1->nOrg), aSortParam.nField[nSort], 357 pInfo2->pCell, static_cast<SCCOL>(pInfo2->nOrg), aSortParam.nField[nSort] ); 358 } while ( nRes == 0 && ++nSort < pArray->GetUsedSorts() ); 359 if( nRes == 0 ) 360 { 361 ScSortInfo* pInfo1 = pArray->Get( 0, nIndex1 ); 362 ScSortInfo* pInfo2 = pArray->Get( 0, nIndex2 ); 363 if( pInfo1->nOrg < pInfo2->nOrg ) 364 nRes = -1; 365 else if( pInfo1->nOrg > pInfo2->nOrg ) 366 nRes = 1; 367 } 368 return nRes; 369 } 370 371 void ScTable::QuickSort( ScSortInfoArray* pArray, SCsCOLROW nLo, SCsCOLROW nHi ) 372 { 373 if ((nHi - nLo) == 1) 374 { 375 if (Compare(pArray, nLo, nHi) > 0) 376 pArray->Swap( nLo, nHi ); 377 } 378 else 379 { 380 SCsCOLROW ni = nLo; 381 SCsCOLROW nj = nHi; 382 do 383 { 384 while ((ni <= nHi) && (Compare(pArray, ni, nLo)) < 0) 385 ni++; 386 while ((nj >= nLo) && (Compare(pArray, nLo, nj)) < 0) 387 nj--; 388 if (ni <= nj) 389 { 390 if (ni != nj) 391 pArray->Swap( ni, nj ); 392 ni++; 393 nj--; 394 } 395 } while (ni < nj); 396 if ((nj - nLo) < (nHi - ni)) 397 { 398 if (nLo < nj) 399 QuickSort(pArray, nLo, nj); 400 if (ni < nHi) 401 QuickSort(pArray, ni, nHi); 402 } 403 else 404 { 405 if (ni < nHi) 406 QuickSort(pArray, ni, nHi); 407 if (nLo < nj) 408 QuickSort(pArray, nLo, nj); 409 } 410 } 411 } 412 413 void ScTable::SwapCol(SCCOL nCol1, SCCOL nCol2) 414 { 415 for (SCROW nRow = aSortParam.nRow1; nRow <= aSortParam.nRow2; nRow++) 416 { 417 aCol[nCol1].SwapCell(nRow, aCol[nCol2]); 418 if (aSortParam.bIncludePattern) 419 { 420 const ScPatternAttr* pPat1 = GetPattern(nCol1, nRow); 421 const ScPatternAttr* pPat2 = GetPattern(nCol2, nRow); 422 if (pPat1 != pPat2) 423 { 424 //maybe the content is the same 425 if (!(*pPat1 == *pPat2)) 426 { 427 SetPattern(nCol1, nRow, *pPat2, sal_True); 428 SetPattern(nCol2, nRow, *pPat1, sal_True); 429 } 430 } 431 } 432 } 433 } 434 435 void ScTable::SwapRow(SCROW nRow1, SCROW nRow2) 436 { 437 for (SCCOL nCol = aSortParam.nCol1; nCol <= aSortParam.nCol2; nCol++) 438 { 439 aCol[nCol].SwapRow(nRow1, nRow2); 440 if (aSortParam.bIncludePattern) 441 { 442 const ScPatternAttr* pPat1 = GetPattern(nCol, nRow1); 443 const ScPatternAttr* pPat2 = GetPattern(nCol, nRow2); 444 if (pPat1 != pPat2) 445 { 446 //maybe the content is the same 447 if (!(*pPat1 == *pPat2)) 448 { 449 SetPattern(nCol, nRow1, *pPat2, sal_True); 450 SetPattern(nCol, nRow2, *pPat1, sal_True); 451 } 452 } 453 } 454 } 455 if (bGlobalKeepQuery) 456 { 457 bool bRow1Hidden = RowHidden(nRow1); 458 bool bRow2Hidden = RowHidden(nRow2); 459 SetRowHidden(nRow1, nRow1, bRow2Hidden); 460 SetRowHidden(nRow2, nRow2, bRow1Hidden); 461 462 bool bRow1Filtered = RowFiltered(nRow1); 463 bool bRow2Filtered = RowFiltered(nRow2); 464 SetRowFiltered(nRow1, nRow1, bRow2Filtered); 465 SetRowFiltered(nRow2, nRow2, bRow1Filtered); 466 } 467 } 468 469 short ScTable::Compare(SCCOLROW nIndex1, SCCOLROW nIndex2) 470 { 471 short nRes; 472 sal_uInt16 nSort = 0; 473 if (aSortParam.bByRow) 474 { 475 do 476 { 477 SCCOL nCol = static_cast<SCCOL>(aSortParam.nField[nSort]); 478 ScBaseCell* pCell1 = aCol[nCol].GetCell( nIndex1 ); 479 ScBaseCell* pCell2 = aCol[nCol].GetCell( nIndex2 ); 480 nRes = CompareCell( nSort, pCell1, nCol, nIndex1, pCell2, nCol, nIndex2 ); 481 } while ( nRes == 0 && ++nSort < nMaxSorts && aSortParam.bDoSort[nSort] ); 482 } 483 else 484 { 485 do 486 { 487 SCROW nRow = aSortParam.nField[nSort]; 488 ScBaseCell* pCell1 = aCol[nIndex1].GetCell( nRow ); 489 ScBaseCell* pCell2 = aCol[nIndex2].GetCell( nRow ); 490 nRes = CompareCell( nSort, pCell1, static_cast<SCCOL>(nIndex1), 491 nRow, pCell2, static_cast<SCCOL>(nIndex2), nRow ); 492 } while ( nRes == 0 && ++nSort < nMaxSorts && aSortParam.bDoSort[nSort] ); 493 } 494 return nRes; 495 } 496 497 sal_Bool ScTable::IsSorted( SCCOLROW nStart, SCCOLROW nEnd ) // ueber aSortParam 498 { 499 for (SCCOLROW i=nStart; i<nEnd; i++) 500 { 501 if (Compare( i, i+1 ) > 0) 502 return sal_False; 503 } 504 return sal_True; 505 } 506 507 void ScTable::DecoladeRow( ScSortInfoArray* pArray, SCROW nRow1, SCROW nRow2 ) 508 { 509 SCROW nRow; 510 SCROW nMax = nRow2 - nRow1; 511 for (SCROW i = nRow1; (i + 4) <= nRow2; i += 4) 512 { 513 nRow = rand() % nMax; 514 pArray->Swap(i, nRow1 + nRow); 515 } 516 } 517 518 void ScTable::Sort(const ScSortParam& rSortParam, sal_Bool bKeepQuery) 519 { 520 aSortParam = rSortParam; 521 InitSortCollator( rSortParam ); 522 bGlobalKeepQuery = bKeepQuery; 523 if (rSortParam.bByRow) 524 { 525 SCROW nLastRow = 0; 526 for (SCCOL nCol = aSortParam.nCol1; nCol <= aSortParam.nCol2; nCol++) 527 nLastRow = Max(nLastRow, aCol[nCol].GetLastDataPos()); 528 nLastRow = Min(nLastRow, aSortParam.nRow2); 529 SCROW nRow1 = (rSortParam.bHasHeader ? 530 aSortParam.nRow1 + 1 : aSortParam.nRow1); 531 if (!IsSorted(nRow1, nLastRow)) 532 { 533 ScProgress aProgress( pDocument->GetDocumentShell(), 534 ScGlobal::GetRscString(STR_PROGRESS_SORTING), nLastRow - nRow1 ); 535 ScSortInfoArray* pArray = CreateSortInfoArray( nRow1, nLastRow ); 536 if ( nLastRow - nRow1 > 255 ) 537 DecoladeRow( pArray, nRow1, nLastRow ); 538 QuickSort( pArray, nRow1, nLastRow ); 539 SortReorder( pArray, aProgress ); 540 delete pArray; 541 // #158377# #i59745# update position of caption objects of cell notes 542 ScNoteUtil::UpdateCaptionPositions( *pDocument, ScRange( aSortParam.nCol1, nRow1, nTab, aSortParam.nCol2, nLastRow, nTab ) ); 543 } 544 } 545 else 546 { 547 SCCOL nLastCol; 548 for (nLastCol = aSortParam.nCol2; 549 (nLastCol > aSortParam.nCol1) && aCol[nLastCol].IsEmptyBlock(aSortParam.nRow1, aSortParam.nRow2); nLastCol--) 550 { 551 } 552 SCCOL nCol1 = (rSortParam.bHasHeader ? 553 aSortParam.nCol1 + 1 : aSortParam.nCol1); 554 if (!IsSorted(nCol1, nLastCol)) 555 { 556 ScProgress aProgress( pDocument->GetDocumentShell(), 557 ScGlobal::GetRscString(STR_PROGRESS_SORTING), nLastCol - nCol1 ); 558 ScSortInfoArray* pArray = CreateSortInfoArray( nCol1, nLastCol ); 559 QuickSort( pArray, nCol1, nLastCol ); 560 SortReorder( pArray, aProgress ); 561 delete pArray; 562 // #158377# #i59745# update position of caption objects of cell notes 563 ScNoteUtil::UpdateCaptionPositions( *pDocument, ScRange( nCol1, aSortParam.nRow1, nTab, nLastCol, aSortParam.nRow2, nTab ) ); 564 } 565 } 566 DestroySortCollator(); 567 } 568 569 570 // Testen, ob beim Loeschen von Zwischenergebnissen andere Daten mit geloescht werden 571 // (fuer Hinweis-Box) 572 573 sal_Bool ScTable::TestRemoveSubTotals( const ScSubTotalParam& rParam ) 574 { 575 SCCOL nStartCol = rParam.nCol1; 576 SCROW nStartRow = rParam.nRow1 + 1; // Header 577 SCCOL nEndCol = rParam.nCol2; 578 SCROW nEndRow = rParam.nRow2; 579 580 SCCOL nCol; 581 SCROW nRow; 582 ScBaseCell* pCell; 583 584 sal_Bool bWillDelete = sal_False; 585 for ( nCol=nStartCol; nCol<=nEndCol && !bWillDelete; nCol++ ) 586 { 587 ScColumnIterator aIter( &aCol[nCol],nStartRow,nEndRow ); 588 while ( aIter.Next( nRow, pCell ) && !bWillDelete ) 589 { 590 if ( pCell->GetCellType() == CELLTYPE_FORMULA ) 591 if (((ScFormulaCell*)pCell)->IsSubTotal()) 592 { 593 for (SCCOL nTestCol=0; nTestCol<=MAXCOL; nTestCol++) 594 if (nTestCol<nStartCol || nTestCol>nEndCol) 595 if (aCol[nTestCol].HasDataAt(nRow)) 596 bWillDelete = sal_True; 597 } 598 } 599 } 600 return bWillDelete; 601 } 602 603 // alte Ergebnisse loeschen 604 // rParam.nRow2 wird veraendert ! 605 606 void ScTable::RemoveSubTotals( ScSubTotalParam& rParam ) 607 { 608 SCCOL nStartCol = rParam.nCol1; 609 SCROW nStartRow = rParam.nRow1 + 1; // Header 610 SCCOL nEndCol = rParam.nCol2; 611 SCROW nEndRow = rParam.nRow2; // wird veraendert 612 613 SCCOL nCol; 614 SCROW nRow; 615 ScBaseCell* pCell; 616 617 for ( nCol=nStartCol; nCol<=nEndCol; nCol++ ) 618 { 619 ScColumnIterator aIter( &aCol[nCol],nStartRow,nEndRow ); 620 while ( aIter.Next( nRow, pCell ) ) 621 { 622 if ( pCell->GetCellType() == CELLTYPE_FORMULA ) 623 if (((ScFormulaCell*)pCell)->IsSubTotal()) 624 { 625 RemoveRowBreak(nRow+1, false, true); 626 pDocument->DeleteRow( 0,nTab, MAXCOL,nTab, nRow, 1 ); 627 --nEndRow; 628 aIter = ScColumnIterator( &aCol[nCol],nRow,nEndRow ); 629 } 630 } 631 } 632 633 rParam.nRow2 = nEndRow; // neues Ende 634 } 635 636 // harte Zahlenformate loeschen (fuer Ergebnisformeln) 637 638 void lcl_RemoveNumberFormat( ScTable* pTab, SCCOL nCol, SCROW nRow ) 639 { 640 const ScPatternAttr* pPattern = pTab->GetPattern( nCol, nRow ); 641 if ( pPattern->GetItemSet().GetItemState( ATTR_VALUE_FORMAT, sal_False ) 642 == SFX_ITEM_SET ) 643 { 644 ScPatternAttr aNewPattern( *pPattern ); 645 SfxItemSet& rSet = aNewPattern.GetItemSet(); 646 rSet.ClearItem( ATTR_VALUE_FORMAT ); 647 rSet.ClearItem( ATTR_LANGUAGE_FORMAT ); 648 pTab->SetPattern( nCol, nRow, aNewPattern, sal_True ); 649 } 650 } 651 652 653 // at least MSC needs this at linkage level to be able to use it in a template 654 typedef struct lcl_ScTable_DoSubTotals_RowEntry 655 { 656 sal_uInt16 nGroupNo; 657 SCROW nSubStartRow; 658 SCROW nDestRow; 659 SCROW nFuncStart; 660 SCROW nFuncEnd; 661 } RowEntry; 662 663 // neue Zwischenergebnisse 664 // rParam.nRow2 wird veraendert ! 665 666 sal_Bool ScTable::DoSubTotals( ScSubTotalParam& rParam ) 667 { 668 SCCOL nStartCol = rParam.nCol1; 669 SCROW nStartRow = rParam.nRow1 + 1; // Header 670 SCCOL nEndCol = rParam.nCol2; 671 SCROW nEndRow = rParam.nRow2; // wird veraendert 672 sal_uInt16 i; 673 674 // Leerzeilen am Ende weglassen, 675 // damit alle Ueberlaeufe (MAXROW) bei InsertRow gefunden werden (#35180#) 676 // Wenn sortiert wurde, sind alle Leerzeilen am Ende. 677 SCSIZE nEmpty = GetEmptyLinesInBlock( nStartCol, nStartRow, nEndCol, nEndRow, DIR_BOTTOM ); 678 nEndRow -= nEmpty; 679 680 sal_uInt16 nLevelCount = 0; // Anzahl Gruppierungen 681 sal_Bool bDoThis = sal_True; 682 for (i=0; i<MAXSUBTOTAL && bDoThis; i++) 683 if (rParam.bGroupActive[i]) 684 nLevelCount = i+1; 685 else 686 bDoThis = sal_False; 687 688 if (nLevelCount==0) // nichts tun 689 return sal_True; 690 691 SCCOL* nGroupCol = rParam.nField; // Spalten nach denen 692 // gruppiert wird 693 694 // #44444# Durch (leer) als eigene Kategorie muss immer auf 695 // Teilergebniszeilen aus den anderen Spalten getestet werden 696 // (frueher nur, wenn eine Spalte mehrfach vorkam) 697 sal_Bool bTestPrevSub = ( nLevelCount > 1 ); 698 699 String aSubString; 700 String aOutString; 701 702 sal_Bool bIgnoreCase = !rParam.bCaseSens; 703 704 String *pCompString[MAXSUBTOTAL]; // Pointer wegen Compiler-Problemen 705 for (i=0; i<MAXSUBTOTAL; i++) 706 pCompString[i] = new String; 707 708 //! sortieren? 709 710 ScStyleSheet* pStyle = (ScStyleSheet*) pDocument->GetStyleSheetPool()->Find( 711 ScGlobal::GetRscString(STR_STYLENAME_RESULT), SFX_STYLE_FAMILY_PARA ); 712 713 sal_Bool bSpaceLeft = sal_True; // Erfolg beim Einfuegen? 714 715 // #90279# For performance reasons collect formula entries so their 716 // references don't have to be tested for updates each time a new row is 717 // inserted 718 RowEntry aRowEntry; 719 ::std::vector< RowEntry > aRowVector; 720 721 for (sal_uInt16 nLevel=0; nLevel<=nLevelCount && bSpaceLeft; nLevel++) // incl. Gesamtergebnis 722 { 723 sal_Bool bTotal = ( nLevel == nLevelCount ); 724 aRowEntry.nGroupNo = bTotal ? 0 : (nLevelCount-nLevel-1); 725 726 // how many results per level 727 SCCOL nResCount = rParam.nSubTotals[aRowEntry.nGroupNo]; 728 // result functions 729 ScSubTotalFunc* eResFunc = rParam.pFunctions[aRowEntry.nGroupNo]; 730 731 if (nResCount > 0) // sonst nur sortieren 732 { 733 for (i=0; i<=aRowEntry.nGroupNo; i++) 734 { 735 GetString( nGroupCol[i], nStartRow, aSubString ); 736 if ( bIgnoreCase ) 737 *pCompString[i] = ScGlobal::pCharClass->upper( aSubString ); 738 else 739 *pCompString[i] = aSubString; 740 } // aSubString bleibt auf dem letzten stehen 741 742 sal_Bool bBlockVis = sal_False; // Gruppe eingeblendet? 743 aRowEntry.nSubStartRow = nStartRow; 744 for (SCROW nRow=nStartRow; nRow<=nEndRow+1 && bSpaceLeft; nRow++) 745 { 746 sal_Bool bChanged; 747 if (nRow>nEndRow) 748 bChanged = sal_True; 749 else 750 { 751 bChanged = sal_False; 752 if (!bTotal) 753 { 754 String aString; 755 for (i=0; i<=aRowEntry.nGroupNo && !bChanged; i++) 756 { 757 GetString( nGroupCol[i], nRow, aString ); 758 if (bIgnoreCase) 759 ScGlobal::pCharClass->toUpper( aString ); 760 // #41427# wenn sortiert, ist "leer" eine eigene Gruppe 761 // sonst sind leere Zellen unten erlaubt 762 bChanged = ( ( aString.Len() || rParam.bDoSort ) && 763 aString != *pCompString[i] ); 764 } 765 if ( bChanged && bTestPrevSub ) 766 { 767 // No group change on rows that will contain subtotal formulas 768 for ( ::std::vector< RowEntry >::const_iterator 769 iEntry( aRowVector.begin()); 770 iEntry != aRowVector.end(); ++iEntry) 771 { 772 if ( iEntry->nDestRow == nRow ) 773 { 774 bChanged = sal_False; 775 break; 776 } 777 } 778 } 779 } 780 } 781 if ( bChanged ) 782 { 783 aRowEntry.nDestRow = nRow; 784 aRowEntry.nFuncStart = aRowEntry.nSubStartRow; 785 aRowEntry.nFuncEnd = nRow-1; 786 787 bSpaceLeft = pDocument->InsertRow( 0, nTab, MAXCOL, nTab, 788 aRowEntry.nDestRow, 1 ); 789 DBShowRow( aRowEntry.nDestRow, bBlockVis ); 790 bBlockVis = sal_False; 791 if ( rParam.bPagebreak && nRow < MAXROW && 792 aRowEntry.nSubStartRow != nStartRow && nLevel == 0) 793 SetRowBreak(aRowEntry.nSubStartRow, false, true); 794 795 if (bSpaceLeft) 796 { 797 for ( ::std::vector< RowEntry >::iterator iMove( 798 aRowVector.begin() ); 799 iMove != aRowVector.end(); ++iMove) 800 { 801 if ( aRowEntry.nDestRow <= iMove->nSubStartRow ) 802 ++iMove->nSubStartRow; 803 if ( aRowEntry.nDestRow <= iMove->nDestRow ) 804 ++iMove->nDestRow; 805 if ( aRowEntry.nDestRow <= iMove->nFuncStart ) 806 ++iMove->nFuncStart; 807 if ( aRowEntry.nDestRow <= iMove->nFuncEnd ) 808 ++iMove->nFuncEnd; 809 } 810 // collect formula positions 811 aRowVector.push_back( aRowEntry ); 812 813 if (bTotal) // "Gesamtergebnis" 814 aOutString = ScGlobal::GetRscString( STR_TABLE_GESAMTERGEBNIS ); 815 else 816 { // " Ergebnis" 817 aOutString = aSubString; 818 if (!aOutString.Len()) 819 aOutString = ScGlobal::GetRscString( STR_EMPTYDATA ); 820 aOutString += ' '; 821 sal_uInt16 nStrId = STR_TABLE_ERGEBNIS; 822 if ( nResCount == 1 ) 823 switch ( eResFunc[0] ) 824 { 825 case SUBTOTAL_FUNC_AVE: nStrId = STR_FUN_TEXT_AVG; break; 826 case SUBTOTAL_FUNC_CNT: 827 case SUBTOTAL_FUNC_CNT2: nStrId = STR_FUN_TEXT_COUNT; break; 828 case SUBTOTAL_FUNC_MAX: nStrId = STR_FUN_TEXT_MAX; break; 829 case SUBTOTAL_FUNC_MIN: nStrId = STR_FUN_TEXT_MIN; break; 830 case SUBTOTAL_FUNC_PROD: nStrId = STR_FUN_TEXT_PRODUCT; break; 831 case SUBTOTAL_FUNC_STD: 832 case SUBTOTAL_FUNC_STDP: nStrId = STR_FUN_TEXT_STDDEV; break; 833 case SUBTOTAL_FUNC_SUM: nStrId = STR_FUN_TEXT_SUM; break; 834 case SUBTOTAL_FUNC_VAR: 835 case SUBTOTAL_FUNC_VARP: nStrId = STR_FUN_TEXT_VAR; break; 836 default: 837 { 838 // added to avoid warnings 839 } 840 } 841 aOutString += ScGlobal::GetRscString( nStrId ); 842 } 843 SetString( nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, nTab, aOutString ); 844 ApplyStyle( nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, *pStyle ); 845 846 ++nRow; 847 ++nEndRow; 848 aRowEntry.nSubStartRow = nRow; 849 for (i=0; i<=aRowEntry.nGroupNo; i++) 850 { 851 GetString( nGroupCol[i], nRow, aSubString ); 852 if ( bIgnoreCase ) 853 *pCompString[i] = ScGlobal::pCharClass->upper( aSubString ); 854 else 855 *pCompString[i] = aSubString; 856 } 857 } 858 } 859 bBlockVis = !RowFiltered(nRow); 860 } 861 } 862 else 863 { 864 // DBG_ERROR( "nSubTotals==0 bei DoSubTotals" ); 865 } 866 } 867 868 // now insert the formulas 869 ScComplexRefData aRef; 870 aRef.InitFlags(); 871 aRef.Ref1.nTab = nTab; 872 aRef.Ref2.nTab = nTab; 873 for ( ::std::vector< RowEntry >::const_iterator iEntry( aRowVector.begin()); 874 iEntry != aRowVector.end(); ++iEntry) 875 { 876 SCCOL nResCount = rParam.nSubTotals[iEntry->nGroupNo]; 877 SCCOL* nResCols = rParam.pSubTotals[iEntry->nGroupNo]; 878 ScSubTotalFunc* eResFunc = rParam.pFunctions[iEntry->nGroupNo]; 879 for ( SCCOL nResult=0; nResult < nResCount; ++nResult ) 880 { 881 aRef.Ref1.nCol = nResCols[nResult]; 882 aRef.Ref1.nRow = iEntry->nFuncStart; 883 aRef.Ref2.nCol = nResCols[nResult]; 884 aRef.Ref2.nRow = iEntry->nFuncEnd; 885 886 ScTokenArray aArr; 887 aArr.AddOpCode( ocSubTotal ); 888 aArr.AddOpCode( ocOpen ); 889 aArr.AddDouble( (double) eResFunc[nResult] ); 890 aArr.AddOpCode( ocSep ); 891 aArr.AddDoubleReference( aRef ); 892 aArr.AddOpCode( ocClose ); 893 aArr.AddOpCode( ocStop ); 894 ScBaseCell* pCell = new ScFormulaCell( pDocument, ScAddress( 895 nResCols[nResult], iEntry->nDestRow, nTab), &aArr ); 896 PutCell( nResCols[nResult], iEntry->nDestRow, pCell ); 897 898 if ( nResCols[nResult] != nGroupCol[iEntry->nGroupNo] ) 899 { 900 ApplyStyle( nResCols[nResult], iEntry->nDestRow, *pStyle ); 901 902 // Zahlformat loeschen 903 lcl_RemoveNumberFormat( this, nResCols[nResult], iEntry->nDestRow ); 904 } 905 } 906 907 } 908 909 //! je nach Einstellung Zwischensummen-Zeilen nach oben verschieben ? 910 911 //! Outlines direkt erzeugen? 912 913 if (bSpaceLeft) 914 DoAutoOutline( nStartCol, nStartRow, nEndCol, nEndRow ); 915 916 for (i=0; i<MAXSUBTOTAL; i++) 917 delete pCompString[i]; 918 919 rParam.nRow2 = nEndRow; // neues Ende 920 return bSpaceLeft; 921 } 922 923 924 sal_Bool ScTable::ValidQuery(SCROW nRow, const ScQueryParam& rParam, 925 sal_Bool* pSpecial /* =NULL */ , ScBaseCell* pCell /* =NULL */ , 926 sal_Bool* pbTestEqualCondition /* = NULL */ ) 927 { 928 if (!rParam.GetEntry(0).bDoQuery) 929 return sal_True; 930 931 //--------------------------------------------------------------- 932 933 const SCSIZE nFixedBools = 32; 934 sal_Bool aBool[nFixedBools]; 935 sal_Bool aTest[nFixedBools]; 936 SCSIZE nEntryCount = rParam.GetEntryCount(); 937 sal_Bool* pPasst = ( nEntryCount <= nFixedBools ? &aBool[0] : new sal_Bool[nEntryCount] ); 938 sal_Bool* pTest = ( nEntryCount <= nFixedBools ? &aTest[0] : new sal_Bool[nEntryCount] ); 939 940 long nPos = -1; 941 SCSIZE i = 0; 942 sal_Bool bMatchWholeCell = pDocument->GetDocOptions().IsMatchWholeCell(); 943 CollatorWrapper* pCollator = (rParam.bCaseSens ? ScGlobal::GetCaseCollator() : 944 ScGlobal::GetCollator()); 945 ::utl::TransliterationWrapper* pTransliteration = (rParam.bCaseSens ? 946 ScGlobal::GetCaseTransliteration() : ScGlobal::GetpTransliteration()); 947 948 while ( (i < nEntryCount) && rParam.GetEntry(i).bDoQuery ) 949 { 950 ScQueryEntry& rEntry = rParam.GetEntry(i); 951 // we can only handle one single direct query 952 if ( !pCell || i > 0 ) 953 pCell = GetCell( static_cast<SCCOL>(rEntry.nField), nRow ); 954 955 sal_Bool bOk = sal_False; 956 sal_Bool bTestEqual = sal_False; 957 958 if ( pSpecial && pSpecial[i] ) 959 { 960 if (rEntry.nVal == SC_EMPTYFIELDS) 961 bOk = !( aCol[rEntry.nField].HasDataAt( nRow ) ); 962 else // if (rEntry.nVal == SC_NONEMPTYFIELDS) 963 bOk = aCol[rEntry.nField].HasDataAt( nRow ); 964 } 965 else if ( !rEntry.bQueryByString && (pCell ? pCell->HasValueData() : 966 HasValueData( static_cast<SCCOL>(rEntry.nField), nRow))) 967 { // by Value 968 double nCellVal; 969 if ( pCell ) 970 { 971 switch ( pCell->GetCellType() ) 972 { 973 case CELLTYPE_VALUE : 974 nCellVal = ((ScValueCell*)pCell)->GetValue(); 975 break; 976 case CELLTYPE_FORMULA : 977 nCellVal = ((ScFormulaCell*)pCell)->GetValue(); 978 break; 979 default: 980 nCellVal = 0.0; 981 } 982 983 } 984 else 985 nCellVal = GetValue( static_cast<SCCOL>(rEntry.nField), nRow ); 986 987 /* NOTE: lcl_PrepareQuery() prepares a filter query such that if a 988 * date+time format was queried rEntry.bQueryByDate is not set. In 989 * case other queries wanted to use this mechanism they should do 990 * the same, in other words only if rEntry.nVal is an integer value 991 * rEntry.bQueryByDate should be true and the time fraction be 992 * stripped here. */ 993 if (rEntry.bQueryByDate) 994 { 995 sal_uInt32 nNumFmt = GetNumberFormat(static_cast<SCCOL>(rEntry.nField), nRow); 996 const SvNumberformat* pEntry = pDocument->GetFormatTable()->GetEntry(nNumFmt); 997 if (pEntry) 998 { 999 short nNumFmtType = pEntry->GetType(); 1000 /* NOTE: Omitting the check for absence of 1001 * NUMBERFORMAT_TIME would include also date+time formatted 1002 * values of the same day. That may be desired in some 1003 * cases, querying all time values of a day, but confusing 1004 * in other cases. A user can always setup a standard 1005 * filter query for x >= date AND x < date+1 */ 1006 if ((nNumFmtType & NUMBERFORMAT_DATE) && !(nNumFmtType & NUMBERFORMAT_TIME)) 1007 { 1008 // The format is of date type. Strip off the time 1009 // element. 1010 nCellVal = ::rtl::math::approxFloor(nCellVal); 1011 } 1012 } 1013 } 1014 1015 switch (rEntry.eOp) 1016 { 1017 case SC_EQUAL : 1018 bOk = ::rtl::math::approxEqual( nCellVal, rEntry.nVal ); 1019 break; 1020 case SC_LESS : 1021 bOk = (nCellVal < rEntry.nVal) && !::rtl::math::approxEqual( nCellVal, rEntry.nVal ); 1022 break; 1023 case SC_GREATER : 1024 bOk = (nCellVal > rEntry.nVal) && !::rtl::math::approxEqual( nCellVal, rEntry.nVal ); 1025 break; 1026 case SC_LESS_EQUAL : 1027 bOk = (nCellVal < rEntry.nVal) || ::rtl::math::approxEqual( nCellVal, rEntry.nVal ); 1028 if ( bOk && pbTestEqualCondition ) 1029 bTestEqual = ::rtl::math::approxEqual( nCellVal, rEntry.nVal ); 1030 break; 1031 case SC_GREATER_EQUAL : 1032 bOk = (nCellVal > rEntry.nVal) || ::rtl::math::approxEqual( nCellVal, rEntry.nVal ); 1033 if ( bOk && pbTestEqualCondition ) 1034 bTestEqual = ::rtl::math::approxEqual( nCellVal, rEntry.nVal ); 1035 break; 1036 case SC_NOT_EQUAL : 1037 bOk = !::rtl::math::approxEqual( nCellVal, rEntry.nVal ); 1038 break; 1039 default: 1040 { 1041 // added to avoid warnings 1042 } 1043 } 1044 } 1045 else if ( (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL) || 1046 (rEntry.eOp == SC_CONTAINS || rEntry.eOp == SC_DOES_NOT_CONTAIN || 1047 rEntry.eOp == SC_BEGINS_WITH || rEntry.eOp == SC_ENDS_WITH || 1048 rEntry.eOp == SC_DOES_NOT_BEGIN_WITH || rEntry.eOp == SC_DOES_NOT_END_WITH) || 1049 (rEntry.bQueryByString && (pCell ? pCell->HasStringData() : 1050 HasStringData( 1051 static_cast<SCCOL>(rEntry.nField), 1052 nRow)))) 1053 { // by String 1054 String aCellStr; 1055 if( rEntry.eOp == SC_CONTAINS || rEntry.eOp == SC_DOES_NOT_CONTAIN 1056 || rEntry.eOp == SC_BEGINS_WITH || rEntry.eOp == SC_ENDS_WITH 1057 || rEntry.eOp == SC_DOES_NOT_BEGIN_WITH || rEntry.eOp == SC_DOES_NOT_END_WITH ) 1058 bMatchWholeCell = sal_False; 1059 if ( pCell ) 1060 { 1061 if (pCell->GetCellType() != CELLTYPE_NOTE) 1062 { 1063 sal_uLong nFormat = GetNumberFormat( static_cast<SCCOL>(rEntry.nField), nRow ); 1064 ScCellFormat::GetInputString( pCell, nFormat, aCellStr, *(pDocument->GetFormatTable()) ); 1065 } 1066 } 1067 else 1068 GetInputString( static_cast<SCCOL>(rEntry.nField), nRow, aCellStr ); 1069 1070 sal_Bool bRealRegExp = (rParam.bRegExp && ((rEntry.eOp == SC_EQUAL) 1071 || (rEntry.eOp == SC_NOT_EQUAL) || (rEntry.eOp == SC_CONTAINS) 1072 || (rEntry.eOp == SC_DOES_NOT_CONTAIN) || (rEntry.eOp == SC_BEGINS_WITH) 1073 || (rEntry.eOp == SC_ENDS_WITH) || (rEntry.eOp == SC_DOES_NOT_BEGIN_WITH) 1074 || (rEntry.eOp == SC_DOES_NOT_END_WITH))); 1075 sal_Bool bTestRegExp = (pbTestEqualCondition && rParam.bRegExp 1076 && ((rEntry.eOp == SC_LESS_EQUAL) 1077 || (rEntry.eOp == SC_GREATER_EQUAL))); 1078 if ( bRealRegExp || bTestRegExp ) 1079 { 1080 xub_StrLen nStart = 0; 1081 xub_StrLen nEnd = aCellStr.Len(); 1082 1083 // from 614 on, nEnd is behind the found text 1084 sal_Bool bMatch = sal_False; 1085 if ( rEntry.eOp == SC_ENDS_WITH || rEntry.eOp == SC_DOES_NOT_END_WITH ) 1086 { 1087 nEnd = 0; 1088 nStart = aCellStr.Len(); 1089 bMatch = (sal_Bool) rEntry.GetSearchTextPtr( rParam.bCaseSens ) 1090 ->SearchBkwrd( aCellStr, &nStart, &nEnd ); 1091 } 1092 else 1093 { 1094 bMatch = (sal_Bool) rEntry.GetSearchTextPtr( rParam.bCaseSens ) 1095 ->SearchFrwrd( aCellStr, &nStart, &nEnd ); 1096 } 1097 if ( bMatch && bMatchWholeCell 1098 && (nStart != 0 || nEnd != aCellStr.Len()) ) 1099 bMatch = sal_False; // RegExp must match entire cell string 1100 if ( bRealRegExp ) 1101 switch (rEntry.eOp) 1102 { 1103 case SC_EQUAL: 1104 case SC_CONTAINS: 1105 bOk = bMatch; 1106 break; 1107 case SC_NOT_EQUAL: 1108 case SC_DOES_NOT_CONTAIN: 1109 bOk = !bMatch; 1110 break; 1111 case SC_BEGINS_WITH: 1112 bOk = ( bMatch && (nStart == 0) ); 1113 break; 1114 case SC_DOES_NOT_BEGIN_WITH: 1115 bOk = !( bMatch && (nStart == 0) ); 1116 break; 1117 case SC_ENDS_WITH: 1118 bOk = ( bMatch && (nEnd == aCellStr.Len()) ); 1119 break; 1120 case SC_DOES_NOT_END_WITH: 1121 bOk = !( bMatch && (nEnd == aCellStr.Len()) ); 1122 break; 1123 default: 1124 { 1125 // added to avoid warnings 1126 } 1127 } 1128 else 1129 bTestEqual = bMatch; 1130 } 1131 if ( !bRealRegExp ) 1132 { 1133 if ( rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL 1134 || rEntry.eOp == SC_CONTAINS || rEntry.eOp == SC_DOES_NOT_CONTAIN 1135 || rEntry.eOp == SC_BEGINS_WITH || rEntry.eOp == SC_ENDS_WITH 1136 || rEntry.eOp == SC_DOES_NOT_BEGIN_WITH || rEntry.eOp == SC_DOES_NOT_END_WITH ) 1137 { 1138 if ( !rEntry.bQueryByString && rEntry.pStr->Len() == 0 ) 1139 { 1140 // #i18374# When used from functions (match, countif, sumif, vlookup, hlookup, lookup), 1141 // the query value is assigned directly, and the string is empty. In that case, 1142 // don't find any string (isEqual would find empty string results in formula cells). 1143 bOk = sal_False; 1144 if ( rEntry.eOp == SC_NOT_EQUAL ) 1145 bOk = !bOk; 1146 } 1147 else if ( bMatchWholeCell ) 1148 { 1149 bOk = pTransliteration->isEqual( aCellStr, *rEntry.pStr ); 1150 if ( rEntry.eOp == SC_NOT_EQUAL ) 1151 bOk = !bOk; 1152 } 1153 else 1154 { 1155 String aCell( pTransliteration->transliterate( 1156 aCellStr, ScGlobal::eLnge, 0, aCellStr.Len(), 1157 NULL ) ); 1158 String aQuer( pTransliteration->transliterate( 1159 *rEntry.pStr, ScGlobal::eLnge, 0, rEntry.pStr->Len(), 1160 NULL ) ); 1161 xub_StrLen nIndex = (rEntry.eOp == SC_ENDS_WITH 1162 || rEntry.eOp == SC_DOES_NOT_END_WITH)? (aCell.Len()-aQuer.Len()):0; 1163 xub_StrLen nStrPos = aCell.Search( aQuer, nIndex ); 1164 switch (rEntry.eOp) 1165 { 1166 case SC_EQUAL: 1167 case SC_CONTAINS: 1168 bOk = ( nStrPos != STRING_NOTFOUND ); 1169 break; 1170 case SC_NOT_EQUAL: 1171 case SC_DOES_NOT_CONTAIN: 1172 bOk = ( nStrPos == STRING_NOTFOUND ); 1173 break; 1174 case SC_BEGINS_WITH: 1175 bOk = ( nStrPos == 0 ); 1176 break; 1177 case SC_DOES_NOT_BEGIN_WITH: 1178 bOk = ( nStrPos != 0 ); 1179 break; 1180 case SC_ENDS_WITH: 1181 bOk = ( nStrPos + aQuer.Len() == aCell.Len() ); 1182 break; 1183 case SC_DOES_NOT_END_WITH: 1184 bOk = ( nStrPos + aQuer.Len() != aCell.Len() ); 1185 break; 1186 default: 1187 { 1188 // added to avoid warnings 1189 } 1190 } 1191 } 1192 } 1193 else 1194 { // use collator here because data was probably sorted 1195 sal_Int32 nCompare = pCollator->compareString( 1196 aCellStr, *rEntry.pStr ); 1197 switch (rEntry.eOp) 1198 { 1199 case SC_LESS : 1200 bOk = (nCompare < 0); 1201 break; 1202 case SC_GREATER : 1203 bOk = (nCompare > 0); 1204 break; 1205 case SC_LESS_EQUAL : 1206 bOk = (nCompare <= 0); 1207 if ( bOk && pbTestEqualCondition && !bTestEqual ) 1208 bTestEqual = (nCompare == 0); 1209 break; 1210 case SC_GREATER_EQUAL : 1211 bOk = (nCompare >= 0); 1212 if ( bOk && pbTestEqualCondition && !bTestEqual ) 1213 bTestEqual = (nCompare == 0); 1214 break; 1215 default: 1216 { 1217 // added to avoid warnings 1218 } 1219 } 1220 } 1221 } 1222 } 1223 else if (rParam.bMixedComparison) 1224 { 1225 if (rEntry.bQueryByString && 1226 (rEntry.eOp == SC_LESS || rEntry.eOp == SC_LESS_EQUAL) && 1227 (pCell ? pCell->HasValueData() : 1228 HasValueData( static_cast<SCCOL>(rEntry.nField), nRow))) 1229 { 1230 bOk = sal_True; 1231 } 1232 else if (!rEntry.bQueryByString && 1233 (rEntry.eOp == SC_GREATER || rEntry.eOp == SC_GREATER_EQUAL) && 1234 (pCell ? pCell->HasStringData() : 1235 HasStringData( static_cast<SCCOL>(rEntry.nField), nRow))) 1236 { 1237 bOk = sal_True; 1238 } 1239 } 1240 1241 if (nPos == -1) 1242 { 1243 nPos++; 1244 pPasst[nPos] = bOk; 1245 pTest[nPos] = bTestEqual; 1246 } 1247 else 1248 { 1249 if (rEntry.eConnect == SC_AND) 1250 { 1251 pPasst[nPos] = pPasst[nPos] && bOk; 1252 pTest[nPos] = pTest[nPos] && bTestEqual; 1253 } 1254 else 1255 { 1256 nPos++; 1257 pPasst[nPos] = bOk; 1258 pTest[nPos] = bTestEqual; 1259 } 1260 } 1261 i++; 1262 } 1263 1264 for ( long j=1; j <= nPos; j++ ) 1265 { 1266 pPasst[0] = pPasst[0] || pPasst[j]; 1267 pTest[0] = pTest[0] || pTest[j]; 1268 } 1269 1270 sal_Bool bRet = pPasst[0]; 1271 if ( pPasst != &aBool[0] ) 1272 delete [] pPasst; 1273 if ( pbTestEqualCondition ) 1274 *pbTestEqualCondition = pTest[0]; 1275 if ( pTest != &aTest[0] ) 1276 delete [] pTest; 1277 1278 return bRet; 1279 } 1280 1281 void ScTable::TopTenQuery( ScQueryParam& rParam ) 1282 { 1283 sal_Bool bSortCollatorInitialized = sal_False; 1284 SCSIZE nEntryCount = rParam.GetEntryCount(); 1285 SCROW nRow1 = (rParam.bHasHeader ? rParam.nRow1 + 1 : rParam.nRow1); 1286 SCSIZE nCount = static_cast<SCSIZE>(rParam.nRow2 - nRow1 + 1); 1287 for ( SCSIZE i=0; (i<nEntryCount) && (rParam.GetEntry(i).bDoQuery); i++ ) 1288 { 1289 ScQueryEntry& rEntry = rParam.GetEntry(i); 1290 switch ( rEntry.eOp ) 1291 { 1292 case SC_TOPVAL: 1293 case SC_BOTVAL: 1294 case SC_TOPPERC: 1295 case SC_BOTPERC: 1296 { 1297 ScSortParam aLocalSortParam( rParam, static_cast<SCCOL>(rEntry.nField) ); 1298 aSortParam = aLocalSortParam; // used in CreateSortInfoArray, Compare 1299 if ( !bSortCollatorInitialized ) 1300 { 1301 bSortCollatorInitialized = sal_True; 1302 InitSortCollator( aLocalSortParam ); 1303 } 1304 ScSortInfoArray* pArray = CreateSortInfoArray( nRow1, rParam.nRow2 ); 1305 DecoladeRow( pArray, nRow1, rParam.nRow2 ); 1306 QuickSort( pArray, nRow1, rParam.nRow2 ); 1307 ScSortInfo** ppInfo = pArray->GetFirstArray(); 1308 SCSIZE nValidCount = nCount; 1309 // keine Note-/Leerzellen zaehlen, sind ans Ende sortiert 1310 while ( nValidCount > 0 && ( ppInfo[nValidCount-1]->pCell == NULL || 1311 ppInfo[nValidCount-1]->pCell->GetCellType() == CELLTYPE_NOTE ) ) 1312 nValidCount--; 1313 // keine Strings zaehlen, sind zwischen Value und Leer 1314 while ( nValidCount > 0 1315 && ppInfo[nValidCount-1]->pCell->HasStringData() ) 1316 nValidCount--; 1317 if ( nValidCount > 0 ) 1318 { 1319 if ( rEntry.bQueryByString ) 1320 { // dat wird nix 1321 rEntry.bQueryByString = sal_False; 1322 rEntry.nVal = 10; // 10 bzw. 10% 1323 } 1324 SCSIZE nVal = (rEntry.nVal >= 1 ? static_cast<SCSIZE>(rEntry.nVal) : 1); 1325 SCSIZE nOffset = 0; 1326 switch ( rEntry.eOp ) 1327 { 1328 case SC_TOPVAL: 1329 { 1330 rEntry.eOp = SC_GREATER_EQUAL; 1331 if ( nVal > nValidCount ) 1332 nVal = nValidCount; 1333 nOffset = nValidCount - nVal; // 1 <= nVal <= nValidCount 1334 } 1335 break; 1336 case SC_BOTVAL: 1337 { 1338 rEntry.eOp = SC_LESS_EQUAL; 1339 if ( nVal > nValidCount ) 1340 nVal = nValidCount; 1341 nOffset = nVal - 1; // 1 <= nVal <= nValidCount 1342 } 1343 break; 1344 case SC_TOPPERC: 1345 { 1346 rEntry.eOp = SC_GREATER_EQUAL; 1347 if ( nVal > 100 ) 1348 nVal = 100; 1349 nOffset = nValidCount - (nValidCount * nVal / 100); 1350 if ( nOffset >= nValidCount ) 1351 nOffset = nValidCount - 1; 1352 } 1353 break; 1354 case SC_BOTPERC: 1355 { 1356 rEntry.eOp = SC_LESS_EQUAL; 1357 if ( nVal > 100 ) 1358 nVal = 100; 1359 nOffset = (nValidCount * nVal / 100); 1360 if ( nOffset >= nValidCount ) 1361 nOffset = nValidCount - 1; 1362 } 1363 break; 1364 default: 1365 { 1366 // added to avoid warnings 1367 } 1368 } 1369 ScBaseCell* pCell = ppInfo[nOffset]->pCell; 1370 if ( pCell->HasValueData() ) 1371 { 1372 if ( pCell->GetCellType() == CELLTYPE_VALUE ) 1373 rEntry.nVal = ((ScValueCell*)pCell)->GetValue(); 1374 else 1375 rEntry.nVal = ((ScFormulaCell*)pCell)->GetValue(); 1376 } 1377 else 1378 { 1379 DBG_ERRORFILE( "TopTenQuery: pCell kein ValueData" ); 1380 rEntry.eOp = SC_GREATER_EQUAL; 1381 rEntry.nVal = 0; 1382 } 1383 } 1384 else 1385 { 1386 rEntry.eOp = SC_GREATER_EQUAL; 1387 rEntry.bQueryByString = sal_False; 1388 rEntry.nVal = 0; 1389 } 1390 delete pArray; 1391 } 1392 break; 1393 default: 1394 { 1395 // added to avoid warnings 1396 } 1397 } 1398 } 1399 if ( bSortCollatorInitialized ) 1400 DestroySortCollator(); 1401 } 1402 1403 static void lcl_PrepareQuery( ScDocument* pDoc, ScTable* pTab, ScQueryParam& rParam, sal_Bool* pSpecial ) 1404 { 1405 bool bTopTen = false; 1406 SCSIZE nEntryCount = rParam.GetEntryCount(); 1407 1408 for ( SCSIZE i = 0; i < nEntryCount; ++i ) 1409 { 1410 pSpecial[i] = sal_False; 1411 ScQueryEntry& rEntry = rParam.GetEntry(i); 1412 if ( rEntry.bDoQuery ) 1413 { 1414 if ( rEntry.bQueryByString ) 1415 { 1416 sal_uInt32 nIndex = 0; 1417 rEntry.bQueryByString = !( pDoc->GetFormatTable()-> 1418 IsNumberFormat( *rEntry.pStr, nIndex, rEntry.nVal ) ); 1419 if (rEntry.bQueryByDate) 1420 { 1421 if (!rEntry.bQueryByString && ((nIndex % SV_COUNTRY_LANGUAGE_OFFSET) != 0)) 1422 { 1423 const SvNumberformat* pEntry = pDoc->GetFormatTable()->GetEntry(nIndex); 1424 if (pEntry) 1425 { 1426 short nNumFmtType = pEntry->GetType(); 1427 if (!((nNumFmtType & NUMBERFORMAT_DATE) && !(nNumFmtType & NUMBERFORMAT_TIME))) 1428 rEntry.bQueryByDate = false; // not a date only 1429 } 1430 else 1431 rEntry.bQueryByDate = false; // what the ... not a date 1432 } 1433 else 1434 rEntry.bQueryByDate = false; // not a date 1435 } 1436 } 1437 else 1438 { 1439 // #58736# call from UNO or second call from autofilter 1440 if ( rEntry.nVal == SC_EMPTYFIELDS || rEntry.nVal == SC_NONEMPTYFIELDS ) 1441 { 1442 pSpecial[i] = sal_True; 1443 } 1444 } 1445 if ( !bTopTen ) 1446 { 1447 switch ( rEntry.eOp ) 1448 { 1449 case SC_TOPVAL: 1450 case SC_BOTVAL: 1451 case SC_TOPPERC: 1452 case SC_BOTPERC: 1453 { 1454 bTopTen = true; 1455 } 1456 break; 1457 default: 1458 { 1459 } 1460 } 1461 } 1462 } 1463 } 1464 1465 if ( bTopTen ) 1466 { 1467 pTab->TopTenQuery( rParam ); 1468 } 1469 } 1470 1471 SCSIZE ScTable::Query(ScQueryParam& rParamOrg, sal_Bool bKeepSub) 1472 { 1473 ScQueryParam aParam( rParamOrg ); 1474 ScStrCollection aScStrCollection; 1475 StrData* pStrData = NULL; 1476 1477 sal_Bool bStarted = sal_False; 1478 sal_Bool bOldResult = sal_True; 1479 SCROW nOldStart = 0; 1480 SCROW nOldEnd = 0; 1481 1482 SCSIZE nCount = 0; 1483 SCROW nOutRow = 0; 1484 SCROW nHeader = aParam.bHasHeader ? 1 : 0; 1485 1486 SCSIZE nEntryCount = aParam.GetEntryCount(); 1487 sal_Bool* pSpecial = new sal_Bool[nEntryCount]; 1488 lcl_PrepareQuery( pDocument, this, aParam, pSpecial ); 1489 1490 if (!aParam.bInplace) 1491 { 1492 nOutRow = aParam.nDestRow + nHeader; 1493 if (nHeader > 0) 1494 CopyData( aParam.nCol1, aParam.nRow1, aParam.nCol2, aParam.nRow1, 1495 aParam.nDestCol, aParam.nDestRow, aParam.nDestTab ); 1496 } 1497 1498 if (aParam.bInplace) 1499 IncRecalcLevel(); // #i116164# once for all entries 1500 1501 // #i116164# If there are no drawing objects within the area, call SetRowHidden/SetRowFiltered for all rows at the end 1502 std::vector<ScShowRowsEntry> aEntries; 1503 ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer(); 1504 bool bHasObjects = pDrawLayer && pDrawLayer->HasObjectsInRows( nTab, aParam.nRow1 + nHeader, aParam.nRow2, false ); 1505 1506 for (SCROW j=aParam.nRow1 + nHeader; j<=aParam.nRow2; j++) 1507 { 1508 sal_Bool bResult; // Filterergebnis 1509 sal_Bool bValid = ValidQuery(j, aParam, pSpecial); 1510 if (!bValid && bKeepSub) // Subtotals stehenlassen 1511 { 1512 for (SCCOL nCol=aParam.nCol1; nCol<=aParam.nCol2 && !bValid; nCol++) 1513 { 1514 ScBaseCell* pCell; 1515 pCell = GetCell( nCol, j ); 1516 if ( pCell ) 1517 if ( pCell->GetCellType() == CELLTYPE_FORMULA ) 1518 if (((ScFormulaCell*)pCell)->IsSubTotal()) 1519 if (RefVisible((ScFormulaCell*)pCell)) 1520 bValid = sal_True; 1521 } 1522 } 1523 if (bValid) 1524 { 1525 if (aParam.bDuplicate) 1526 bResult = sal_True; 1527 else 1528 { 1529 String aStr; 1530 for (SCCOL k=aParam.nCol1; k <= aParam.nCol2; k++) 1531 { 1532 String aCellStr; 1533 GetString(k, j, aCellStr); 1534 aStr += aCellStr; 1535 aStr += (sal_Unicode)1; 1536 } 1537 pStrData = new StrData(aStr); 1538 1539 sal_Bool bIsUnique = sal_True; 1540 if (pStrData) 1541 bIsUnique = aScStrCollection.Insert(pStrData); 1542 if (bIsUnique) 1543 bResult = sal_True; 1544 else 1545 { 1546 delete pStrData; 1547 bResult = sal_False; 1548 } 1549 } 1550 } 1551 else 1552 bResult = sal_False; 1553 1554 if (aParam.bInplace) 1555 { 1556 if (bResult == bOldResult && bStarted) 1557 nOldEnd = j; 1558 else 1559 { 1560 if (bStarted) 1561 { 1562 DBShowRows(nOldStart,nOldEnd, bOldResult, bHasObjects); 1563 if (!bHasObjects) 1564 aEntries.push_back(ScShowRowsEntry(nOldStart, nOldEnd, bOldResult)); 1565 } 1566 nOldStart = nOldEnd = j; 1567 bOldResult = bResult; 1568 } 1569 bStarted = sal_True; 1570 } 1571 else 1572 { 1573 if (bResult) 1574 { 1575 CopyData( aParam.nCol1,j, aParam.nCol2,j, aParam.nDestCol,nOutRow,aParam.nDestTab ); 1576 ++nOutRow; 1577 } 1578 } 1579 if (bResult) 1580 ++nCount; 1581 } 1582 1583 if (aParam.bInplace && bStarted) 1584 { 1585 DBShowRows(nOldStart,nOldEnd, bOldResult, bHasObjects); 1586 if (!bHasObjects) 1587 aEntries.push_back(ScShowRowsEntry(nOldStart, nOldEnd, bOldResult)); 1588 } 1589 1590 // #i116164# execute the collected SetRowHidden/SetRowFiltered calls 1591 if (!bHasObjects) 1592 { 1593 std::vector<ScShowRowsEntry>::const_iterator aEnd = aEntries.end(); 1594 std::vector<ScShowRowsEntry>::const_iterator aIter = aEntries.begin(); 1595 if ( aIter != aEnd ) 1596 { 1597 // do only one HeightChanged call with the final difference in heights 1598 long nOldHeight = 0; 1599 if ( pDrawLayer ) 1600 nOldHeight = static_cast<long>(GetRowHeight(aParam.nRow1 + nHeader, aParam.nRow2)); 1601 1602 // clear the range first instead of many changes in the middle of the filled array 1603 SetRowHidden(aParam.nRow1 + nHeader, aParam.nRow2, false); 1604 SetRowFiltered(aParam.nRow1 + nHeader, aParam.nRow2, false); 1605 1606 // insert from back, in case the filter range is large 1607 mpHiddenRows->setInsertFromBack(true); 1608 mpFilteredRows->setInsertFromBack(true); 1609 1610 while (aIter != aEnd) 1611 { 1612 if (!aIter->mbShow) 1613 { 1614 SCROW nStartRow = aIter->mnRow1; 1615 SCROW nEndRow = aIter->mnRow2; 1616 SetRowHidden(nStartRow, nEndRow, true); 1617 SetRowFiltered(nStartRow, nEndRow, true); 1618 } 1619 ++aIter; 1620 } 1621 1622 mpHiddenRows->setInsertFromBack(false); 1623 mpFilteredRows->setInsertFromBack(false); 1624 1625 if ( pDrawLayer ) 1626 { 1627 // if there are no objects in the filtered range, a single HeightChanged call is enough 1628 long nNewHeight = static_cast<long>(GetRowHeight(aParam.nRow1 + nHeader, aParam.nRow2)); 1629 pDrawLayer->HeightChanged( nTab, aParam.nRow1 + nHeader, nNewHeight - nOldHeight ); 1630 } 1631 } 1632 } 1633 1634 if (aParam.bInplace) 1635 DecRecalcLevel(); 1636 1637 delete[] pSpecial; 1638 1639 return nCount; 1640 } 1641 1642 sal_Bool ScTable::CreateExcelQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam) 1643 { 1644 sal_Bool bValid = sal_True; 1645 SCCOL* pFields = new SCCOL[nCol2-nCol1+1]; 1646 String aCellStr; 1647 SCCOL nCol = nCol1; 1648 DBG_ASSERT( rQueryParam.nTab != SCTAB_MAX, "rQueryParam.nTab no value, not bad but no good" ); 1649 SCTAB nDBTab = (rQueryParam.nTab == SCTAB_MAX ? nTab : rQueryParam.nTab); 1650 SCROW nDBRow1 = rQueryParam.nRow1; 1651 SCCOL nDBCol2 = rQueryParam.nCol2; 1652 // Erste Zeile muessen Spaltenkoepfe sein 1653 while (bValid && (nCol <= nCol2)) 1654 { 1655 String aQueryStr; 1656 GetUpperCellString(nCol, nRow1, aQueryStr); 1657 sal_Bool bFound = sal_False; 1658 SCCOL i = rQueryParam.nCol1; 1659 while (!bFound && (i <= nDBCol2)) 1660 { 1661 if ( nTab == nDBTab ) 1662 GetUpperCellString(i, nDBRow1, aCellStr); 1663 else 1664 pDocument->GetUpperCellString(i, nDBRow1, nDBTab, aCellStr); 1665 bFound = (aCellStr == aQueryStr); 1666 if (!bFound) i++; 1667 } 1668 if (bFound) 1669 pFields[nCol - nCol1] = i; 1670 else 1671 bValid = sal_False; 1672 nCol++; 1673 } 1674 if (bValid) 1675 { 1676 sal_uLong nVisible = 0; 1677 for ( nCol=nCol1; nCol<=nCol2; nCol++ ) 1678 nVisible += aCol[nCol].VisibleCount( nRow1+1, nRow2 ); 1679 1680 if ( nVisible > SCSIZE_MAX / sizeof(void*) ) 1681 { 1682 DBG_ERROR("zu viele Filterkritierien"); 1683 nVisible = 0; 1684 } 1685 1686 SCSIZE nNewEntries = nVisible; 1687 rQueryParam.Resize( nNewEntries ); 1688 1689 SCSIZE nIndex = 0; 1690 SCROW nRow = nRow1 + 1; 1691 while (nRow <= nRow2) 1692 { 1693 nCol = nCol1; 1694 while (nCol <= nCol2) 1695 { 1696 GetInputString( nCol, nRow, aCellStr ); 1697 ScGlobal::pCharClass->toUpper( aCellStr ); 1698 if (aCellStr.Len() > 0) 1699 { 1700 if (nIndex < nNewEntries) 1701 { 1702 rQueryParam.GetEntry(nIndex).nField = pFields[nCol - nCol1]; 1703 rQueryParam.FillInExcelSyntax(aCellStr, nIndex); 1704 nIndex++; 1705 if (nIndex < nNewEntries) 1706 rQueryParam.GetEntry(nIndex).eConnect = SC_AND; 1707 } 1708 else 1709 bValid = sal_False; 1710 } 1711 nCol++; 1712 } 1713 nRow++; 1714 if (nIndex < nNewEntries) 1715 rQueryParam.GetEntry(nIndex).eConnect = SC_OR; 1716 } 1717 } 1718 delete [] pFields; 1719 return bValid; 1720 } 1721 1722 sal_Bool ScTable::CreateStarQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam) 1723 { 1724 // A valid StarQuery must be at least 4 columns wide. To be precise it 1725 // should be exactly 4 columns ... 1726 // Additionally, if this wasn't checked, a formula pointing to a valid 1-3 1727 // column Excel style query range immediately left to itself would result 1728 // in a circular reference when the field name or operator or value (first 1729 // to third query range column) is obtained (#i58354#). Furthermore, if the 1730 // range wasn't sufficiently specified data changes wouldn't flag formula 1731 // cells for recalculation. 1732 if (nCol2 - nCol1 < 3) 1733 return sal_False; 1734 1735 sal_Bool bValid; 1736 sal_Bool bFound; 1737 String aCellStr; 1738 SCSIZE nIndex = 0; 1739 SCROW nRow = nRow1; 1740 DBG_ASSERT( rQueryParam.nTab != SCTAB_MAX, "rQueryParam.nTab no value, not bad but no good" ); 1741 SCTAB nDBTab = (rQueryParam.nTab == SCTAB_MAX ? nTab : rQueryParam.nTab); 1742 SCROW nDBRow1 = rQueryParam.nRow1; 1743 SCCOL nDBCol2 = rQueryParam.nCol2; 1744 1745 SCSIZE nNewEntries = static_cast<SCSIZE>(nRow2-nRow1+1); 1746 rQueryParam.Resize( nNewEntries ); 1747 1748 do 1749 { 1750 ScQueryEntry& rEntry = rQueryParam.GetEntry(nIndex); 1751 1752 bValid = sal_False; 1753 // Erste Spalte UND/ODER 1754 if (nIndex > 0) 1755 { 1756 GetUpperCellString(nCol1, nRow, aCellStr); 1757 if ( aCellStr == ScGlobal::GetRscString(STR_TABLE_UND) ) 1758 { 1759 rEntry.eConnect = SC_AND; 1760 bValid = sal_True; 1761 } 1762 else if ( aCellStr == ScGlobal::GetRscString(STR_TABLE_ODER) ) 1763 { 1764 rEntry.eConnect = SC_OR; 1765 bValid = sal_True; 1766 } 1767 } 1768 // Zweite Spalte FeldName 1769 if ((nIndex < 1) || bValid) 1770 { 1771 bFound = sal_False; 1772 GetUpperCellString(nCol1 + 1, nRow, aCellStr); 1773 for (SCCOL i=rQueryParam.nCol1; (i <= nDBCol2) && (!bFound); i++) 1774 { 1775 String aFieldStr; 1776 if ( nTab == nDBTab ) 1777 GetUpperCellString(i, nDBRow1, aFieldStr); 1778 else 1779 pDocument->GetUpperCellString(i, nDBRow1, nDBTab, aFieldStr); 1780 bFound = (aCellStr == aFieldStr); 1781 if (bFound) 1782 { 1783 rEntry.nField = i; 1784 bValid = sal_True; 1785 } 1786 else 1787 bValid = sal_False; 1788 } 1789 } 1790 // Dritte Spalte Operator =<>... 1791 if (bValid) 1792 { 1793 bFound = sal_False; 1794 GetUpperCellString(nCol1 + 2, nRow, aCellStr); 1795 if (aCellStr.GetChar(0) == '<') 1796 { 1797 if (aCellStr.GetChar(1) == '>') 1798 rEntry.eOp = SC_NOT_EQUAL; 1799 else if (aCellStr.GetChar(1) == '=') 1800 rEntry.eOp = SC_LESS_EQUAL; 1801 else 1802 rEntry.eOp = SC_LESS; 1803 } 1804 else if (aCellStr.GetChar(0) == '>') 1805 { 1806 if (aCellStr.GetChar(1) == '=') 1807 rEntry.eOp = SC_GREATER_EQUAL; 1808 else 1809 rEntry.eOp = SC_GREATER; 1810 } 1811 else if (aCellStr.GetChar(0) == '=') 1812 rEntry.eOp = SC_EQUAL; 1813 1814 } 1815 // Vierte Spalte Wert 1816 if (bValid) 1817 { 1818 GetString(nCol1 + 3, nRow, *rEntry.pStr); 1819 rEntry.bDoQuery = sal_True; 1820 } 1821 nIndex++; 1822 nRow++; 1823 } 1824 while (bValid && (nRow <= nRow2) /* && (nIndex < MAXQUERY) */ ); 1825 return bValid; 1826 } 1827 1828 sal_Bool ScTable::CreateQueryParam(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam) 1829 { 1830 SCSIZE i, nCount; 1831 PutInOrder(nCol1, nCol2); 1832 PutInOrder(nRow1, nRow2); 1833 1834 nCount = rQueryParam.GetEntryCount(); 1835 for (i=0; i < nCount; i++) 1836 rQueryParam.GetEntry(i).Clear(); 1837 1838 // Standard QueryTabelle 1839 sal_Bool bValid = CreateStarQuery(nCol1, nRow1, nCol2, nRow2, rQueryParam); 1840 // Excel QueryTabelle 1841 if (!bValid) 1842 bValid = CreateExcelQuery(nCol1, nRow1, nCol2, nRow2, rQueryParam); 1843 1844 nCount = rQueryParam.GetEntryCount(); 1845 if (bValid) 1846 { 1847 // bQueryByString muss gesetzt sein 1848 for (i=0; i < nCount; i++) 1849 rQueryParam.GetEntry(i).bQueryByString = sal_True; 1850 } 1851 else 1852 { 1853 // nix 1854 for (i=0; i < nCount; i++) 1855 rQueryParam.GetEntry(i).Clear(); 1856 } 1857 return bValid; 1858 } 1859 1860 sal_Bool ScTable::HasColHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW /* nEndRow */ ) 1861 { 1862 for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++) 1863 { 1864 CellType eType = GetCellType( nCol, nStartRow ); 1865 if (eType != CELLTYPE_STRING && eType != CELLTYPE_EDIT) 1866 return sal_False; 1867 } 1868 return sal_True; 1869 } 1870 1871 sal_Bool ScTable::HasRowHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL /* nEndCol */, SCROW nEndRow ) 1872 { 1873 for (SCROW nRow=nStartRow; nRow<=nEndRow; nRow++) 1874 { 1875 CellType eType = GetCellType( nStartCol, nRow ); 1876 if (eType != CELLTYPE_STRING && eType != CELLTYPE_EDIT) 1877 return sal_False; 1878 } 1879 return sal_True; 1880 } 1881 1882 void ScTable::GetFilterEntries(SCCOL nCol, SCROW nRow1, SCROW nRow2, TypedScStrCollection& rStrings, bool& rHasDates) 1883 { 1884 aCol[nCol].GetFilterEntries( nRow1, nRow2, rStrings, rHasDates ); 1885 } 1886 1887 void ScTable::GetFilteredFilterEntries( 1888 SCCOL nCol, SCROW nRow1, SCROW nRow2, const ScQueryParam& rParam, TypedScStrCollection& rStrings, bool& rHasDates ) 1889 { 1890 // remove the entry for this column from the query parameter 1891 ScQueryParam aParam( rParam ); 1892 SCSIZE nEntryCount = aParam.GetEntryCount(); 1893 for ( SCSIZE i = 0; i < nEntryCount && aParam.GetEntry(i).bDoQuery; ++i ) 1894 { 1895 ScQueryEntry& rEntry = aParam.GetEntry(i); 1896 if ( rEntry.nField == nCol ) 1897 { 1898 aParam.DeleteQuery(i); 1899 break; 1900 } 1901 } 1902 nEntryCount = aParam.GetEntryCount(); 1903 1904 sal_Bool* pSpecial = new sal_Bool[nEntryCount]; 1905 lcl_PrepareQuery( pDocument, this, aParam, pSpecial ); 1906 bool bHasDates = false; 1907 for ( SCROW j = nRow1; j <= nRow2; ++j ) 1908 { 1909 if ( ValidQuery( j, aParam, pSpecial ) ) 1910 { 1911 bool bThisHasDates = false; 1912 aCol[nCol].GetFilterEntries( j, j, rStrings, bThisHasDates ); 1913 bHasDates |= bThisHasDates; 1914 } 1915 } 1916 1917 rHasDates = bHasDates; 1918 delete[] pSpecial; 1919 } 1920 1921 sal_Bool ScTable::GetDataEntries(SCCOL nCol, SCROW nRow, TypedScStrCollection& rStrings, sal_Bool bLimit) 1922 { 1923 return aCol[nCol].GetDataEntries( nRow, rStrings, bLimit ); 1924 } 1925 1926 SCSIZE ScTable::GetCellCount(SCCOL nCol) const 1927 { 1928 return aCol[nCol].GetCellCount(); 1929 } 1930 1931 sal_uLong ScTable::GetCellCount() const 1932 { 1933 sal_uLong nCellCount = 0; 1934 1935 for ( SCCOL nCol=0; nCol<=MAXCOL; nCol++ ) 1936 nCellCount += aCol[nCol].GetCellCount(); 1937 1938 return nCellCount; 1939 } 1940 1941 sal_uLong ScTable::GetWeightedCount() const 1942 { 1943 sal_uLong nCellCount = 0; 1944 1945 for ( SCCOL nCol=0; nCol<=MAXCOL; nCol++ ) 1946 if ( aCol[nCol].GetCellCount() ) // GetCellCount ist inline 1947 nCellCount += aCol[nCol].GetWeightedCount(); 1948 1949 return nCellCount; 1950 } 1951 1952 sal_uLong ScTable::GetCodeCount() const 1953 { 1954 sal_uLong nCodeCount = 0; 1955 1956 for ( SCCOL nCol=0; nCol<=MAXCOL; nCol++ ) 1957 if ( aCol[nCol].GetCellCount() ) // GetCellCount ist inline 1958 nCodeCount += aCol[nCol].GetCodeCount(); 1959 1960 return nCodeCount; 1961 } 1962 1963 sal_Int32 ScTable::GetMaxStringLen( SCCOL nCol, SCROW nRowStart, 1964 SCROW nRowEnd, CharSet eCharSet ) const 1965 { 1966 if ( ValidCol(nCol) ) 1967 return aCol[nCol].GetMaxStringLen( nRowStart, nRowEnd, eCharSet ); 1968 else 1969 return 0; 1970 } 1971 1972 xub_StrLen ScTable::GetMaxNumberStringLen( 1973 sal_uInt16& nPrecision, SCCOL nCol, SCROW nRowStart, SCROW nRowEnd ) const 1974 { 1975 if ( ValidCol(nCol) ) 1976 return aCol[nCol].GetMaxNumberStringLen( nPrecision, nRowStart, nRowEnd ); 1977 else 1978 return 0; 1979 } 1980 1981 void ScTable::UpdateSelectionFunction( ScFunctionData& rData, 1982 SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, 1983 const ScMarkData& rMark ) 1984 { 1985 // Cursor neben einer Markierung nicht beruecksichtigen: 1986 //! nur noch MarkData uebergeben, Cursorposition ggf. hineinselektieren!!! 1987 sal_Bool bSingle = ( rMark.IsMarked() || !rMark.IsMultiMarked() ); 1988 1989 // Mehrfachselektion: 1990 1991 SCCOL nCol; 1992 if ( rMark.IsMultiMarked() ) 1993 for (nCol=0; nCol<=MAXCOL && !rData.bError; nCol++) 1994 if ( !pColFlags || !ColHidden(nCol) ) 1995 aCol[nCol].UpdateSelectionFunction( rMark, rData, *mpHiddenRows, 1996 bSingle && ( nCol >= nStartCol && nCol <= nEndCol ), 1997 nStartRow, nEndRow ); 1998 1999 // Einfachselektion (oder Cursor) nur wenn nicht negativ (und s.o.): 2000 2001 if ( bSingle && !rMark.IsMarkNegative() ) 2002 for (nCol=nStartCol; nCol<=nEndCol && !rData.bError; nCol++) 2003 if ( !pColFlags || !ColHidden(nCol) ) 2004 aCol[nCol].UpdateAreaFunction( rData, *mpHiddenRows, nStartRow, nEndRow ); 2005 } 2006 2007 void ScTable::FindConditionalFormat( sal_uLong nKey, ScRangeList& rList ) 2008 { 2009 SCROW nStartRow = 0, nEndRow = 0; 2010 for (SCCOL nCol=0; nCol<=MAXCOL; nCol++) 2011 { 2012 ScAttrIterator* pIter = aCol[nCol].CreateAttrIterator( 0, MAXROW ); 2013 const ScPatternAttr* pPattern = pIter->Next( nStartRow, nEndRow ); 2014 while (pPattern) 2015 { 2016 if (((SfxUInt32Item&)pPattern->GetItem(ATTR_CONDITIONAL)).GetValue() == nKey) 2017 rList.Join( ScRange(nCol,nStartRow,nTab, nCol,nEndRow,nTab) ); 2018 pPattern = pIter->Next( nStartRow, nEndRow ); 2019 } 2020 delete pIter; 2021 } 2022 } 2023 2024 2025 2026 2027