xref: /AOO41X/main/sc/source/core/data/table3.cxx (revision ad0f8ea84c1eb6a963fca86eb658249012a15a49)
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