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