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