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