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