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