xref: /aoo42x/main/sc/source/core/data/dociter.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 // INCLUDE ---------------------------------------------------------------
32 
33 #include <svl/zforlist.hxx>
34 
35 #include "scitems.hxx"
36 #include "global.hxx"
37 #include "dociter.hxx"
38 #include "document.hxx"
39 #include "table.hxx"
40 #include "column.hxx"
41 #include "cell.hxx"
42 #include "attarray.hxx"
43 #include "patattr.hxx"
44 #include "docoptio.hxx"
45 #include "cellform.hxx"
46 
47 #include <vector>
48 
49 using ::rtl::math::approxEqual;
50 using ::std::vector;
51 using ::rtl::OUString;
52 using ::std::set;
53 
54 // STATIC DATA -----------------------------------------------------------
55 
56 namespace {
57 
58 void lcl_toUpper(OUString& rStr)
59 {
60     rStr = ScGlobal::pCharClass->toUpper(rStr.trim(), 0, static_cast<sal_uInt16>(rStr.getLength()));
61 }
62 
63 }
64 
65 ScDocumentIterator::ScDocumentIterator( ScDocument* pDocument,
66 							SCTAB nStartTable, SCTAB nEndTable ) :
67 	pDoc( pDocument ),
68 	nStartTab( nStartTable ),
69 	nEndTab( nEndTable )
70 {
71 	PutInOrder( nStartTab, nEndTab );
72 	if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
73 	if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
74 
75 	pDefPattern = pDoc->GetDefPattern();
76 
77 	nCol = 0;
78 	nRow = 0;
79 	nTab = nStartTab;
80 
81 	nColPos = 0;
82 	nAttrPos = 0;
83 }
84 
85 ScDocumentIterator::~ScDocumentIterator()
86 {
87 }
88 
89 sal_Bool ScDocumentIterator::GetThisCol()
90 {
91 	ScTable*		pTab;
92 	while ( (pTab = pDoc->pTab[nTab]) == NULL )
93 	{
94 		if ( nTab == nEndTab )
95 		{
96 			nCol = MAXCOL;
97 			nRow = MAXROW;
98 			return sal_False;
99 		}
100 		++nTab;
101 	}
102 	ScColumn*		pCol = &pTab->aCol[nCol];
103 	ScAttrArray*	pAtt = pCol->pAttrArray;
104 
105 	sal_Bool bFound = sal_False;
106 	do
107 	{
108 		SCROW nColRow;
109 		SCROW nAttrEnd;
110 
111 		do
112 		{
113 			nAttrEnd = pAtt->pData[nAttrPos].nRow;
114 			if (nAttrEnd < nRow)
115 				++nAttrPos;
116 		}
117 		while (nAttrEnd < nRow);
118 
119 		do
120 		{
121 			nColRow = (nColPos < pCol->nCount) ? pCol->pItems[nColPos].nRow : MAXROW+1;
122 			if (nColRow < nRow)
123 				++nColPos;
124 		}
125 		while (nColRow < nRow);
126 
127 		if (nColRow == nRow)
128 		{
129 			bFound	 = sal_True;
130 			pCell	 = pCol->pItems[nColPos].pCell;
131 			pPattern = pAtt->pData[nAttrPos].pPattern;
132 		}
133 		else if ( pAtt->pData[nAttrPos].pPattern != pDefPattern )
134 		{
135 			bFound = sal_True;
136 			pCell = NULL;
137 			pPattern = pAtt->pData[nAttrPos].pPattern;
138 		}
139 		else
140 		{
141 			nRow = Min( (SCROW)nColRow, (SCROW)(nAttrEnd+1) );
142 		}
143 	}
144 	while (!bFound && nRow <= MAXROW);
145 
146 	return bFound;
147 }
148 
149 sal_Bool ScDocumentIterator::GetThis()
150 {
151 	sal_Bool bEnd = sal_False;
152 	sal_Bool bSuccess = sal_False;
153 
154 	while ( !bSuccess && !bEnd )
155 	{
156 		if ( nRow > MAXROW )
157 			bSuccess = sal_False;
158 		else
159 			bSuccess = GetThisCol();
160 
161 		if ( !bSuccess )
162 		{
163 			++nCol;
164 			if (nCol > MAXCOL)
165 			{
166 				nCol = 0;
167 				++nTab;
168 				if (nTab > nEndTab)
169 					bEnd = sal_True;
170 			}
171 			nRow = 0;
172 			nColPos = 0;
173 			nAttrPos = 0;
174 		}
175 	}
176 
177 	return !bEnd;
178 }
179 
180 sal_Bool ScDocumentIterator::GetFirst()
181 {
182 	nCol = 0;
183 	nTab = nStartTab;
184 
185 	nRow = 0;
186 	nColPos = 0;
187 	nAttrPos = 0;
188 
189 	return GetThis();
190 }
191 
192 sal_Bool ScDocumentIterator::GetNext()
193 {
194 	++nRow;
195 
196 	return GetThis();
197 }
198 
199 //------------------------------------------------------------------------
200 
201 ScBaseCell* ScDocumentIterator::GetCell()
202 {
203 	return pCell;
204 }
205 
206 const ScPatternAttr* ScDocumentIterator::GetPattern()
207 {
208 	return pPattern;
209 }
210 
211 void ScDocumentIterator::GetPos( SCCOL& rCol, SCROW& rRow, SCTAB& rTab )
212 {
213 	rCol = nCol;
214 	rRow = nRow;
215 	rTab = nTab;
216 }
217 
218 
219 //------------------------------------------------------------------------
220 //------------------------------------------------------------------------
221 void lcl_IterGetNumberFormat( sal_uLong& nFormat, const ScAttrArray*& rpArr,
222 		SCROW& nAttrEndRow, const ScAttrArray* pNewArr, SCROW nRow,
223 		ScDocument* pDoc )
224 {
225 	if ( rpArr != pNewArr || nAttrEndRow < nRow )
226 	{
227 		SCSIZE nPos;
228 		pNewArr->Search( nRow, nPos );	// nPos 0 gueltig wenn nicht gefunden
229 		const ScPatternAttr* pPattern = pNewArr->pData[nPos].pPattern;
230 		nFormat = pPattern->GetNumberFormat( pDoc->GetFormatTable() );
231 		rpArr = pNewArr;
232 		nAttrEndRow = pNewArr->pData[nPos].nRow;
233 	}
234 }
235 
236 //UNUSED2008-05  ScValueIterator::ScValueIterator( ScDocument* pDocument,
237 //UNUSED2008-05                                    SCCOL nSCol, SCROW nSRow, SCTAB nSTab,
238 //UNUSED2008-05                                    SCCOL nECol, SCROW nERow, SCTAB nETab,
239 //UNUSED2008-05                                    sal_Bool bSTotal, sal_Bool bTextZero ) :
240 //UNUSED2008-05  pDoc( pDocument ),
241 //UNUSED2008-05  nNumFmtIndex(0),
242 //UNUSED2008-05  nStartCol( nSCol),
243 //UNUSED2008-05  nStartRow( nSRow),
244 //UNUSED2008-05  nStartTab( nSTab ),
245 //UNUSED2008-05  nEndCol( nECol ),
246 //UNUSED2008-05  nEndRow( nERow),
247 //UNUSED2008-05  nEndTab( nETab ),
248 //UNUSED2008-05  nNumFmtType( NUMBERFORMAT_UNDEFINED ),
249 //UNUSED2008-05  bNumValid( sal_False ),
250 //UNUSED2008-05  bSubTotal(bSTotal),
251 //UNUSED2008-05  bNextValid( sal_False ),
252 //UNUSED2008-05  bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ),
253 //UNUSED2008-05  bTextAsZero( bTextZero )
254 //UNUSED2008-05  {
255 //UNUSED2008-05      PutInOrder( nStartCol, nEndCol);
256 //UNUSED2008-05      PutInOrder( nStartRow, nEndRow);
257 //UNUSED2008-05      PutInOrder( nStartTab, nEndTab );
258 //UNUSED2008-05
259 //UNUSED2008-05      if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
260 //UNUSED2008-05      if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
261 //UNUSED2008-05      if (!ValidRow(nStartRow)) nStartRow = MAXROW;
262 //UNUSED2008-05      if (!ValidRow(nEndRow)) nEndRow = MAXROW;
263 //UNUSED2008-05      if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
264 //UNUSED2008-05      if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
265 //UNUSED2008-05
266 //UNUSED2008-05      nCol = nStartCol;
267 //UNUSED2008-05      nRow = nStartRow;
268 //UNUSED2008-05      nTab = nStartTab;
269 //UNUSED2008-05
270 //UNUSED2008-05      nColRow = 0;                    // wird bei GetFirst initialisiert
271 //UNUSED2008-05
272 //UNUSED2008-05      nNumFormat = 0;                 // werden bei GetNumberFormat initialisiert
273 //UNUSED2008-05      pAttrArray = 0;
274 //UNUSED2008-05      nAttrEndRow = 0;
275 //UNUSED2008-05  }
276 
277 ScValueIterator::ScValueIterator( ScDocument* pDocument, const ScRange& rRange,
278 			sal_Bool bSTotal, sal_Bool bTextZero ) :
279 	pDoc( pDocument ),
280 	nNumFmtIndex(0),
281 	nStartCol( rRange.aStart.Col() ),
282 	nStartRow( rRange.aStart.Row() ),
283 	nStartTab( rRange.aStart.Tab() ),
284 	nEndCol( rRange.aEnd.Col() ),
285 	nEndRow( rRange.aEnd.Row() ),
286 	nEndTab( rRange.aEnd.Tab() ),
287 	nNumFmtType( NUMBERFORMAT_UNDEFINED ),
288 	bNumValid( sal_False ),
289 	bSubTotal(bSTotal),
290 	bNextValid( sal_False ),
291 	bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ),
292 	bTextAsZero( bTextZero )
293 {
294 	PutInOrder( nStartCol, nEndCol);
295 	PutInOrder( nStartRow, nEndRow);
296 	PutInOrder( nStartTab, nEndTab );
297 
298 	if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
299 	if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
300 	if (!ValidRow(nStartRow)) nStartRow = MAXROW;
301 	if (!ValidRow(nEndRow)) nEndRow = MAXROW;
302 	if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
303 	if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
304 
305 	nCol = nStartCol;
306 	nRow = nStartRow;
307 	nTab = nStartTab;
308 
309 	nColRow = 0;					// wird bei GetFirst initialisiert
310 
311 	nNumFormat = 0;					// werden bei GetNumberFormat initialisiert
312 	pAttrArray = 0;
313 	nAttrEndRow = 0;
314 }
315 
316 sal_Bool ScValueIterator::GetThis(double& rValue, sal_uInt16& rErr)
317 {
318 	ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
319 	for (;;)
320 	{
321 		if ( nRow > nEndRow )
322 		{
323 			nRow = nStartRow;
324 			do
325 			{
326 				nCol++;
327 				if ( nCol > nEndCol )
328 				{
329 					nCol = nStartCol;
330 					nTab++;
331 					if ( nTab > nEndTab )
332 					{
333 						// rValue = 0.0;    //! do not change caller's value!
334 						rErr = 0;
335 						return sal_False;				// Ende und Aus
336 					}
337 				}
338 				pCol = &(pDoc->pTab[nTab])->aCol[nCol];
339 			} while ( pCol->nCount == 0 );
340 			pCol->Search( nRow, nColRow );
341 		}
342 
343 		while (( nColRow < pCol->nCount ) && ( pCol->pItems[nColRow].nRow < nRow ))
344 			nColRow++;
345 
346 		if ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow <= nEndRow )
347 		{
348 			nRow = pCol->pItems[nColRow].nRow + 1;
349 			if ( !bSubTotal || !pDoc->pTab[nTab]->RowFiltered( nRow-1 ) )
350 			{
351 				ScBaseCell* pCell = pCol->pItems[nColRow].pCell;
352 				++nColRow;
353 				switch (pCell->GetCellType())
354 				{
355 					case CELLTYPE_VALUE:
356 					{
357 						bNumValid = sal_False;
358 						rValue = ((ScValueCell*)pCell)->GetValue();
359 						rErr = 0;
360 						--nRow;
361 						if ( bCalcAsShown )
362 						{
363 							lcl_IterGetNumberFormat( nNumFormat, pAttrArray,
364 								nAttrEndRow, pCol->pAttrArray, nRow, pDoc );
365 							rValue = pDoc->RoundValueAsShown( rValue, nNumFormat );
366 						}
367 						//
368 						//	wenn in der selben Spalte gleich noch eine Value-Cell folgt, die
369 						//	auch noch im Block liegt, den Wert jetzt schon holen
370 						//
371 						if ( nColRow < pCol->nCount &&
372 							 pCol->pItems[nColRow].nRow <= nEndRow &&
373 							 pCol->pItems[nColRow].pCell->GetCellType() == CELLTYPE_VALUE &&
374 							 !bSubTotal )
375 						{
376 							fNextValue = ((ScValueCell*)pCol->pItems[nColRow].pCell)->GetValue();
377 							nNextRow = pCol->pItems[nColRow].nRow;
378 							bNextValid = sal_True;
379 							if ( bCalcAsShown )
380 							{
381 								lcl_IterGetNumberFormat( nNumFormat, pAttrArray,
382 									nAttrEndRow, pCol->pAttrArray, nNextRow, pDoc );
383 								fNextValue = pDoc->RoundValueAsShown( fNextValue, nNumFormat );
384 							}
385 						}
386 
387 						return sal_True;									// gefunden
388 					}
389 //                    break;
390 					case CELLTYPE_FORMULA:
391 					{
392 						if (!bSubTotal || !((ScFormulaCell*)pCell)->IsSubTotal())
393 						{
394 							rErr = ((ScFormulaCell*)pCell)->GetErrCode();
395 							if ( rErr || ((ScFormulaCell*)pCell)->IsValue() )
396 							{
397 								rValue = ((ScFormulaCell*)pCell)->GetValue();
398 								nRow--;
399 								bNumValid = sal_False;
400 								return sal_True;							// gefunden
401 							}
402                             else if ( bTextAsZero )
403                             {
404                                 rValue = 0.0;
405                                 nRow--;
406                                 bNumValid = sal_False;
407                                 return sal_True;
408                             }
409 						}
410 					}
411 					break;
412 					case CELLTYPE_STRING :
413 					case CELLTYPE_EDIT :
414 					{
415 						if ( bTextAsZero )
416 						{
417 							rErr = 0;
418 							rValue = 0.0;
419 							nNumFmtType = NUMBERFORMAT_NUMBER;
420 							nNumFmtIndex = 0;
421 							bNumValid = sal_True;
422 							--nRow;
423 							return sal_True;
424 						}
425 					}
426 					break;
427                     default:
428                     {
429                         // added to avoid warnings
430                     }
431 				}
432 			}
433 		}
434 		else
435 			nRow = nEndRow + 1;			// naechste Spalte
436 	}
437 }
438 
439 void ScValueIterator::GetCurNumFmtInfo( short& nType, sal_uLong& nIndex )
440 {
441 	if (!bNumValid)
442 	{
443 		const ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
444 		nNumFmtIndex = pCol->GetNumberFormat( nRow );
445 		if ( (nNumFmtIndex % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
446 		{
447 			const ScBaseCell* pCell;
448 			SCSIZE nIdx = nColRow - 1;
449 			// there might be rearranged something, so be on the safe side
450 			if ( nIdx < pCol->nCount && pCol->pItems[nIdx].nRow == nRow )
451 				pCell = pCol->pItems[nIdx].pCell;
452 			else
453 			{
454 				if ( pCol->Search( nRow, nIdx ) )
455 					pCell = pCol->pItems[nIdx].pCell;
456 				else
457 					pCell = NULL;
458 			}
459 			if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA )
460 				((const ScFormulaCell*)pCell)->GetFormatInfo( nNumFmtType, nNumFmtIndex );
461 			else
462 				nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex );
463 		}
464 		else
465 			nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex );
466 		bNumValid = sal_True;
467 	}
468 	nType = nNumFmtType;
469 	nIndex = nNumFmtIndex;
470 }
471 
472 sal_Bool ScValueIterator::GetFirst(double& rValue, sal_uInt16& rErr)
473 {
474 	nCol = nStartCol;
475 	nRow = nStartRow;
476 	nTab = nStartTab;
477 
478 //	nColRow = 0;
479 	ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
480 	pCol->Search( nRow, nColRow );
481 
482 	nNumFormat = 0;					// werden bei GetNumberFormat initialisiert
483 	pAttrArray = 0;
484 	nAttrEndRow = 0;
485 
486 	return GetThis(rValue, rErr);
487 }
488 
489 /*	ist inline:
490 sal_Bool ScValueIterator::GetNext(double& rValue, sal_uInt16& rErr)
491 {
492 	++nRow;
493 	return GetThis(rValue, rErr);
494 }
495 */
496 
497 // ============================================================================
498 
499 ScDBQueryDataIterator::DataAccess::DataAccess(const ScDBQueryDataIterator* pParent) :
500     mpParent(pParent)
501 {
502 }
503 
504 ScDBQueryDataIterator::DataAccess::~DataAccess()
505 {
506 }
507 
508 SCROW ScDBQueryDataIterator::GetRowByColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCCOL nCol, SCSIZE nColRow)
509 {
510     ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol];
511     return pCol->pItems[nColRow].nRow;
512 }
513 
514 ScBaseCell* ScDBQueryDataIterator::GetCellByColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCCOL nCol, SCSIZE nColRow)
515 {
516     ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol];
517     return pCol->pItems[nColRow].pCell;
518 }
519 
520 ScAttrArray* ScDBQueryDataIterator::GetAttrArrayByCol(ScDocument& rDoc, SCTAB nTab, SCCOL nCol)
521 {
522     ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol];
523     return pCol->pAttrArray;
524 }
525 
526 bool ScDBQueryDataIterator::IsQueryValid(ScDocument& rDoc, const ScQueryParam& rParam, SCTAB nTab, SCROW nRow, ScBaseCell* pCell)
527 {
528     return rDoc.pTab[nTab]->ValidQuery(nRow, rParam, NULL, pCell);
529 }
530 
531 SCSIZE ScDBQueryDataIterator::SearchColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCROW nRow, SCCOL nCol)
532 {
533     ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol];
534     SCSIZE nColRow;
535     pCol->Search(nRow, nColRow);
536     return nColRow;
537 }
538 
539 // ----------------------------------------------------------------------------
540 
541 ScDBQueryDataIterator::DataAccessInternal::DataAccessInternal(const ScDBQueryDataIterator* pParent, ScDBQueryParamInternal* pParam, ScDocument* pDoc) :
542     DataAccess(pParent),
543     mpParam(pParam),
544     mpDoc(pDoc),
545     bCalcAsShown( pDoc->GetDocOptions().IsCalcAsShown() )
546 {
547     nCol = mpParam->mnField;
548     nRow = mpParam->nRow1;
549     nTab = mpParam->nTab;
550 
551 	nColRow = 0;					// wird bei GetFirst initialisiert
552 	SCSIZE i;
553 	SCSIZE nCount = mpParam->GetEntryCount();
554 	for (i=0; (i<nCount) && (mpParam->GetEntry(i).bDoQuery); i++)
555 	{
556         ScQueryEntry& rEntry = mpParam->GetEntry(i);
557 		sal_uInt32 nIndex = 0;
558 		rEntry.bQueryByString =
559             !(mpDoc->GetFormatTable()->IsNumberFormat(*rEntry.pStr, nIndex, rEntry.nVal));
560 	}
561 	nNumFormat = 0;					// werden bei GetNumberFormat initialisiert
562 	pAttrArray = 0;
563     nAttrEndRow = 0;
564 }
565 
566 ScDBQueryDataIterator::DataAccessInternal::~DataAccessInternal()
567 {
568 }
569 
570 bool ScDBQueryDataIterator::DataAccessInternal::getCurrent(Value& rValue)
571 {
572     SCCOLROW nFirstQueryField = mpParam->GetEntry(0).nField;
573 	for ( ;; )
574 	{
575         if (nRow > mpParam->nRow2)
576 		{
577             // Bottom of the range reached.  Bail out.
578             rValue.mnError = 0;
579             return false;
580 		}
581 
582         SCSIZE nCellCount = mpDoc->GetCellCount(nTab, nCol);
583         SCROW nThisRow = ScDBQueryDataIterator::GetRowByColEntryIndex(*mpDoc, nTab, nCol, nColRow);
584         while ( (nColRow < nCellCount) && (nThisRow < nRow) )
585             nThisRow = ScDBQueryDataIterator::GetRowByColEntryIndex(*mpDoc, nTab, nCol, ++nColRow);
586 
587         if ( nColRow < nCellCount && nThisRow <= mpParam->nRow2 )
588 		{
589             nRow = nThisRow;
590             ScBaseCell* pCell = NULL;
591             if (nCol == static_cast<SCCOL>(nFirstQueryField))
592                 pCell = ScDBQueryDataIterator::GetCellByColEntryIndex(*mpDoc, nTab, nCol, nColRow);
593 
594             if (ScDBQueryDataIterator::IsQueryValid(*mpDoc, *mpParam, nTab, nRow, pCell))
595 			{
596                 // #i109812# get cell here if it wasn't done above
597                 if (nCol != static_cast<SCCOL>(nFirstQueryField))
598                     pCell = ScDBQueryDataIterator::GetCellByColEntryIndex(*mpDoc, nTab, nCol, nColRow);
599 
600                 switch (pCell ? pCell->GetCellType() : CELLTYPE_NONE)
601 				{
602 					case CELLTYPE_VALUE:
603 						{
604                             rValue.mfValue = ((ScValueCell*)pCell)->GetValue();
605                             rValue.mbIsNumber = true;
606 							if ( bCalcAsShown )
607 							{
608                                 const ScAttrArray* pNewAttrArray =
609                                     ScDBQueryDataIterator::GetAttrArrayByCol(*mpDoc, nTab, nCol);
610                                 lcl_IterGetNumberFormat( nNumFormat, pAttrArray,
611                                     nAttrEndRow, pNewAttrArray, nRow, mpDoc );
612                                 rValue.mfValue = mpDoc->RoundValueAsShown( rValue.mfValue, nNumFormat );
613 							}
614 							nNumFmtType = NUMBERFORMAT_NUMBER;
615 							nNumFmtIndex = 0;
616                             rValue.mnError = 0;
617 							return sal_True;		// gefunden
618 						}
619 //                        break;
620 					case CELLTYPE_FORMULA:
621 						{
622 							if (((ScFormulaCell*)pCell)->IsValue())
623 							{
624                                 rValue.mfValue = ((ScFormulaCell*)pCell)->GetValue();
625                                 rValue.mbIsNumber = true;
626                                 mpDoc->GetNumberFormatInfo( nNumFmtType,
627 									nNumFmtIndex, ScAddress( nCol, nRow, nTab ),
628 									pCell );
629                                 rValue.mnError = ((ScFormulaCell*)pCell)->GetErrCode();
630 								return sal_True;	// gefunden
631 							}
632 							else
633 								nRow++;
634 						}
635 						break;
636                     case CELLTYPE_STRING:
637                     case CELLTYPE_EDIT:
638                         if (mpParam->mbSkipString)
639                             ++nRow;
640                         else
641                         {
642                             rValue.maString = pCell->GetStringData();
643                             rValue.mfValue = 0.0;
644                             rValue.mnError = 0;
645                             rValue.mbIsNumber = false;
646                             return true;
647                         }
648                         break;
649 					default:
650 						nRow++;
651 						break;
652 				}
653 			}
654 			else
655 				nRow++;
656 		}
657 		else
658             nRow = mpParam->nRow2 + 1; // Naechste Spalte
659 	}
660 // statement unreachable
661 //    return false;
662 }
663 
664 bool ScDBQueryDataIterator::DataAccessInternal::getFirst(Value& rValue)
665 {
666     if (mpParam->bHasHeader)
667         nRow++;
668 
669     nColRow = ScDBQueryDataIterator::SearchColEntryIndex(*mpDoc, nTab, nRow, nCol);
670     return getCurrent(rValue);
671 }
672 
673 bool ScDBQueryDataIterator::DataAccessInternal::getNext(Value& rValue)
674 {
675     ++nRow;
676     return getCurrent(rValue);
677 }
678 
679 // ----------------------------------------------------------------------------
680 
681 ScDBQueryDataIterator::DataAccessMatrix::DataAccessMatrix(const ScDBQueryDataIterator* pParent, ScDBQueryParamMatrix* pParam) :
682     DataAccess(pParent),
683     mpParam(pParam)
684 {
685     SCSIZE nC, nR;
686     mpParam->mpMatrix->GetDimensions(nC, nR);
687     mnRows = static_cast<SCROW>(nR);
688     mnCols = static_cast<SCCOL>(nC);
689 }
690 
691 ScDBQueryDataIterator::DataAccessMatrix::~DataAccessMatrix()
692 {
693 }
694 
695 bool ScDBQueryDataIterator::DataAccessMatrix::getCurrent(Value& rValue)
696 {
697     // Starting from row == mnCurRow, get the first row that satisfies all the
698     // query parameters.
699     for ( ;mnCurRow < mnRows; ++mnCurRow)
700     {
701         const ScMatrix& rMat = *mpParam->mpMatrix;
702         if (rMat.IsEmpty(mpParam->mnField, mnCurRow))
703             // Don't take empty values into account.
704             continue;
705 
706         bool bIsStrVal = rMat.IsString(mpParam->mnField, mnCurRow);
707         if (bIsStrVal && mpParam->mbSkipString)
708             continue;
709 
710         if (isValidQuery(mnCurRow, rMat))
711         {
712             rValue.maString = rMat.GetString(mpParam->mnField, mnCurRow);
713             rValue.mfValue = rMat.GetDouble(mpParam->mnField, mnCurRow);
714             rValue.mbIsNumber = !bIsStrVal;
715             rValue.mnError = 0;
716             return true;
717         }
718     }
719     return false;
720 }
721 
722 bool ScDBQueryDataIterator::DataAccessMatrix::getFirst(Value& rValue)
723 {
724     mnCurRow = mpParam->bHasHeader ? 1 : 0;
725     return getCurrent(rValue);
726 }
727 
728 bool ScDBQueryDataIterator::DataAccessMatrix::getNext(Value& rValue)
729 {
730     ++mnCurRow;
731     return getCurrent(rValue);
732 }
733 
734 namespace {
735 
736 bool lcl_isQueryByValue(const ScQueryEntry& rEntry, const ScMatrix& rMat, SCSIZE nCol, SCSIZE nRow)
737 {
738     if (rEntry.bQueryByString)
739         return false;
740 
741     if (!rMat.IsValueOrEmpty(nCol, nRow))
742         return false;
743 
744     return true;
745 }
746 
747 bool lcl_isQueryByString(const ScQueryEntry& rEntry, const ScMatrix& rMat, SCSIZE nCol, SCSIZE nRow)
748 {
749     switch (rEntry.eOp)
750     {
751         case SC_EQUAL:
752         case SC_NOT_EQUAL:
753         case SC_CONTAINS:
754         case SC_DOES_NOT_CONTAIN:
755         case SC_BEGINS_WITH:
756         case SC_ENDS_WITH:
757         case SC_DOES_NOT_BEGIN_WITH:
758         case SC_DOES_NOT_END_WITH:
759             return true;
760         default:
761             ;
762     }
763 
764     if (rEntry.bQueryByString && rMat.IsString(nCol, nRow))
765         return true;
766 
767     return false;
768 }
769 
770 }
771 
772 bool ScDBQueryDataIterator::DataAccessMatrix::isValidQuery(SCROW nRow, const ScMatrix& rMat) const
773 {
774     SCSIZE nEntryCount = mpParam->GetEntryCount();
775     vector<bool> aResults;
776     aResults.reserve(nEntryCount);
777 
778     const CollatorWrapper& rCollator =
779         mpParam->bCaseSens ? *ScGlobal::GetCaseCollator() : *ScGlobal::GetCollator();
780 
781     for (SCSIZE i = 0; i < nEntryCount; ++i)
782     {
783         const ScQueryEntry& rEntry = mpParam->GetEntry(i);
784         if (!rEntry.bDoQuery)
785             continue;
786 
787         switch (rEntry.eOp)
788         {
789             case SC_EQUAL:
790             case SC_LESS:
791             case SC_GREATER:
792             case SC_LESS_EQUAL:
793             case SC_GREATER_EQUAL:
794             case SC_NOT_EQUAL:
795                 break;
796             default:
797                 // Only the above operators are supported.
798                 continue;
799         }
800 
801         bool bValid = false;
802 
803         SCSIZE nField = static_cast<SCSIZE>(rEntry.nField);
804         if (lcl_isQueryByValue(rEntry, rMat, nField, nRow))
805         {
806             // By value
807             double fMatVal = rMat.GetDouble(nField, nRow);
808             bool bEqual = approxEqual(fMatVal, rEntry.nVal);
809             switch (rEntry.eOp)
810             {
811                 case SC_EQUAL:
812                     bValid = bEqual;
813                 break;
814                 case SC_LESS:
815                     bValid = (fMatVal < rEntry.nVal) && !bEqual;
816                 break;
817                 case SC_GREATER:
818                     bValid = (fMatVal > rEntry.nVal) && !bEqual;
819                 break;
820                 case SC_LESS_EQUAL:
821                     bValid = (fMatVal < rEntry.nVal) || bEqual;
822                 break;
823                 case SC_GREATER_EQUAL:
824                     bValid = (fMatVal > rEntry.nVal) || bEqual;
825                 break;
826                 case SC_NOT_EQUAL:
827                     bValid = !bEqual;
828                 break;
829                 default:
830                     ;
831             }
832         }
833         else if (lcl_isQueryByString(rEntry, rMat, nField, nRow))
834         {
835             // By string
836             do
837             {
838                 if (!rEntry.pStr)
839                     break;
840 
841                 // Equality check first.
842 
843                 OUString aMatStr = rMat.GetString(nField, nRow);
844                 lcl_toUpper(aMatStr);
845                 OUString aQueryStr = *rEntry.pStr;
846                 lcl_toUpper(aQueryStr);
847                 bool bDone = false;
848                 switch (rEntry.eOp)
849                 {
850                     case SC_EQUAL:
851                         bValid = aMatStr.equals(aQueryStr);
852                         bDone = true;
853                     break;
854                     case SC_NOT_EQUAL:
855                         bValid = !aMatStr.equals(aQueryStr);
856                         bDone = true;
857                     break;
858                     default:
859                         ;
860                 }
861 
862                 if (bDone)
863                     break;
864 
865                 // Unequality check using collator.
866 
867                 sal_Int32 nCompare = rCollator.compareString(aMatStr, aQueryStr);
868                 switch (rEntry.eOp)
869                 {
870                     case SC_LESS :
871                         bValid = (nCompare < 0);
872                     break;
873                     case SC_GREATER :
874                         bValid = (nCompare > 0);
875                     break;
876                     case SC_LESS_EQUAL :
877                         bValid = (nCompare <= 0);
878                     break;
879                     case SC_GREATER_EQUAL :
880                         bValid = (nCompare >= 0);
881                     break;
882                     default:
883                         ;
884                 }
885             }
886             while (false);
887         }
888         else if (mpParam->bMixedComparison)
889         {
890             // Not used at the moment.
891         }
892 
893         if (aResults.empty())
894             // First query entry.
895             aResults.push_back(bValid);
896         else if (rEntry.eConnect == SC_AND)
897         {
898             // For AND op, tuck the result into the last result value.
899             size_t n = aResults.size();
900             aResults[n-1] = aResults[n-1] && bValid;
901         }
902         else
903             // For OR op, store its own result.
904             aResults.push_back(bValid);
905     }
906 
907     // Row is valid as long as there is at least one result being true.
908     vector<bool>::const_iterator itr = aResults.begin(), itrEnd = aResults.end();
909     for (; itr != itrEnd; ++itr)
910         if (*itr)
911             return true;
912 
913     return false;
914 }
915 
916 // ----------------------------------------------------------------------------
917 
918 ScDBQueryDataIterator::Value::Value() :
919     mnError(0), mbIsNumber(true)
920 {
921     ::rtl::math::setNan(&mfValue);
922 }
923 
924 // ----------------------------------------------------------------------------
925 
926 ScDBQueryDataIterator::ScDBQueryDataIterator(ScDocument* pDocument, ScDBQueryParamBase* pParam) :
927     mpParam (pParam)
928 {
929     switch (mpParam->GetType())
930     {
931         case ScDBQueryParamBase::INTERNAL:
932         {
933             ScDBQueryParamInternal* p = static_cast<ScDBQueryParamInternal*>(pParam);
934             mpData.reset(new DataAccessInternal(this, p, pDocument));
935         }
936         break;
937         case ScDBQueryParamBase::MATRIX:
938         {
939             ScDBQueryParamMatrix* p = static_cast<ScDBQueryParamMatrix*>(pParam);
940             mpData.reset(new DataAccessMatrix(this, p));
941         }
942     }
943 }
944 
945 bool ScDBQueryDataIterator::GetFirst(Value& rValue)
946 {
947     return mpData->getFirst(rValue);
948 }
949 
950 bool ScDBQueryDataIterator::GetNext(Value& rValue)
951 {
952     return mpData->getNext(rValue);
953 }
954 
955 // ============================================================================
956 
957 ScCellIterator::ScCellIterator( ScDocument* pDocument,
958 								SCCOL nSCol, SCROW nSRow, SCTAB nSTab,
959 								SCCOL nECol, SCROW nERow, SCTAB nETab, sal_Bool bSTotal ) :
960 	pDoc( pDocument ),
961 	nStartCol( nSCol),
962 	nStartRow( nSRow),
963 	nStartTab( nSTab ),
964 	nEndCol( nECol ),
965 	nEndRow( nERow),
966 	nEndTab( nETab ),
967 	bSubTotal(bSTotal)
968 
969 {
970 	PutInOrder( nStartCol, nEndCol);
971 	PutInOrder( nStartRow, nEndRow);
972 	PutInOrder( nStartTab, nEndTab );
973 
974 	if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
975 	if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
976 	if (!ValidRow(nStartRow)) nStartRow = MAXROW;
977 	if (!ValidRow(nEndRow)) nEndRow = MAXROW;
978 	if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
979 	if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
980 
981 	while (nEndTab>0 && !pDoc->pTab[nEndTab])
982 		--nEndTab;										// nur benutzte Tabellen
983 	if (nStartTab>nEndTab)
984 		nStartTab = nEndTab;
985 
986 	nCol = nStartCol;
987 	nRow = nStartRow;
988 	nTab = nStartTab;
989 	nColRow = 0;					// wird bei GetFirst initialisiert
990 
991 	if (!pDoc->pTab[nTab])
992 	{
993 		DBG_ERROR("Tabelle nicht gefunden");
994 		nStartCol = nCol = MAXCOL+1;
995 		nStartRow = nRow = MAXROW+1;
996 		nStartTab = nTab = MAXTAB+1;	// -> Abbruch bei GetFirst
997 	}
998 }
999 
1000 ScCellIterator::ScCellIterator
1001 	( ScDocument* pDocument, const ScRange& rRange, sal_Bool bSTotal ) :
1002 	pDoc( pDocument ),
1003 	nStartCol( rRange.aStart.Col() ),
1004 	nStartRow( rRange.aStart.Row() ),
1005 	nStartTab( rRange.aStart.Tab() ),
1006 	nEndCol( rRange.aEnd.Col() ),
1007 	nEndRow( rRange.aEnd.Row() ),
1008 	nEndTab( rRange.aEnd.Tab() ),
1009 	bSubTotal(bSTotal)
1010 
1011 {
1012 	PutInOrder( nStartCol, nEndCol);
1013 	PutInOrder( nStartRow, nEndRow);
1014 	PutInOrder( nStartTab, nEndTab );
1015 
1016 	if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
1017 	if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
1018 	if (!ValidRow(nStartRow)) nStartRow = MAXROW;
1019 	if (!ValidRow(nEndRow)) nEndRow = MAXROW;
1020 	if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
1021 	if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
1022 
1023 	while (nEndTab>0 && !pDoc->pTab[nEndTab])
1024 		--nEndTab;										// nur benutzte Tabellen
1025 	if (nStartTab>nEndTab)
1026 		nStartTab = nEndTab;
1027 
1028 	nCol = nStartCol;
1029 	nRow = nStartRow;
1030 	nTab = nStartTab;
1031 	nColRow = 0;					// wird bei GetFirst initialisiert
1032 
1033 	if (!pDoc->pTab[nTab])
1034 	{
1035 		DBG_ERROR("Tabelle nicht gefunden");
1036 		nStartCol = nCol = MAXCOL+1;
1037 		nStartRow = nRow = MAXROW+1;
1038 		nStartTab = nTab = MAXTAB+1;	// -> Abbruch bei GetFirst
1039 	}
1040 }
1041 
1042 ScBaseCell* ScCellIterator::GetThis()
1043 {
1044 	ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1045 	for ( ;; )
1046 	{
1047 		if ( nRow > nEndRow )
1048 		{
1049 			nRow = nStartRow;
1050 			do
1051 			{
1052 				nCol++;
1053 				if ( nCol > nEndCol )
1054 				{
1055 					nCol = nStartCol;
1056 					nTab++;
1057 					if ( nTab > nEndTab )
1058 						return NULL;				// Ende und Aus
1059 				}
1060 				pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1061 			} while ( pCol->nCount == 0 );
1062 			pCol->Search( nRow, nColRow );
1063 		}
1064 
1065 		while ( (nColRow < pCol->nCount) && (pCol->pItems[nColRow].nRow < nRow) )
1066 			nColRow++;
1067 
1068 		if ( nColRow < pCol->nCount	&& pCol->pItems[nColRow].nRow <= nEndRow )
1069 		{
1070 			nRow = pCol->pItems[nColRow].nRow;
1071 			if ( !bSubTotal || !pDoc->pTab[nTab]->RowFiltered( nRow ) )
1072 			{
1073 				ScBaseCell* pCell = pCol->pItems[nColRow].pCell;
1074 
1075 				if ( bSubTotal && pCell->GetCellType() == CELLTYPE_FORMULA
1076 								&& ((ScFormulaCell*)pCell)->IsSubTotal() )
1077 					nRow++;				// Sub-Total-Zeilen nicht
1078 				else
1079 					return pCell;		// gefunden
1080 			}
1081 			else
1082 				nRow++;
1083 		}
1084 		else
1085 			nRow = nEndRow + 1; // Naechste Spalte
1086 	}
1087 }
1088 
1089 ScBaseCell* ScCellIterator::GetFirst()
1090 {
1091 	if ( !ValidTab(nTab) )
1092 		return NULL;
1093 	nCol = nStartCol;
1094 	nRow = nStartRow;
1095 	nTab = nStartTab;
1096 //	nColRow = 0;
1097 	ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1098 	pCol->Search( nRow, nColRow );
1099 	return GetThis();
1100 }
1101 
1102 ScBaseCell* ScCellIterator::GetNext()
1103 {
1104 	++nRow;
1105 	return GetThis();
1106 }
1107 
1108 //-------------------------------------------------------------------------------
1109 
1110 ScQueryCellIterator::ScQueryCellIterator(ScDocument* pDocument, SCTAB nTable,
1111 			 const ScQueryParam& rParam, sal_Bool bMod ) :
1112 	aParam (rParam),
1113 	pDoc( pDocument ),
1114 	nTab( nTable),
1115     nStopOnMismatch( nStopOnMismatchDisabled ),
1116     nTestEqualCondition( nTestEqualConditionDisabled ),
1117     bAdvanceQuery( sal_False ),
1118     bIgnoreMismatchOnLeadingStrings( sal_False )
1119 {
1120 	nCol = aParam.nCol1;
1121 	nRow = aParam.nRow1;
1122 	nColRow = 0;					// wird bei GetFirst initialisiert
1123 	SCSIZE i;
1124 	if (bMod)								// sonst schon eingetragen
1125 	{
1126 		for (i=0; (i<MAXQUERY) && (aParam.GetEntry(i).bDoQuery); i++)
1127 		{
1128 			ScQueryEntry& rEntry = aParam.GetEntry(i);
1129 			sal_uInt32 nIndex = 0;
1130 			rEntry.bQueryByString =
1131 					 !(pDoc->GetFormatTable()->IsNumberFormat(*rEntry.pStr,
1132 															  nIndex, rEntry.nVal));
1133 		}
1134 	}
1135 	nNumFormat = 0;					// werden bei GetNumberFormat initialisiert
1136 	pAttrArray = 0;
1137 	nAttrEndRow = 0;
1138 }
1139 
1140 ScBaseCell* ScQueryCellIterator::GetThis()
1141 {
1142 	ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1143     const ScQueryEntry& rEntry = aParam.GetEntry(0);
1144     SCCOLROW nFirstQueryField = rEntry.nField;
1145     bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings &&
1146         !rEntry.bQueryByString;
1147     bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
1148         !aParam.bHasHeader && rEntry.bQueryByString &&
1149         ((aParam.bByRow && nRow == aParam.nRow1) ||
1150          (!aParam.bByRow && nCol == aParam.nCol1));
1151 	for ( ;; )
1152 	{
1153 		if ( nRow > aParam.nRow2 )
1154 		{
1155 			nRow = aParam.nRow1;
1156 			if (aParam.bHasHeader && aParam.bByRow)
1157 				nRow++;
1158 			do
1159 			{
1160 				if ( ++nCol > aParam.nCol2 )
1161 					return NULL;				// Ende und Aus
1162 				if ( bAdvanceQuery )
1163                 {
1164 					AdvanceQueryParamEntryField();
1165                     nFirstQueryField = rEntry.nField;
1166                 }
1167 				pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1168 			} while ( pCol->nCount == 0 );
1169 			pCol->Search( nRow, nColRow );
1170             bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
1171                 !aParam.bHasHeader && rEntry.bQueryByString &&
1172                 aParam.bByRow;
1173 		}
1174 
1175 		while ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow < nRow )
1176 			nColRow++;
1177 
1178         if ( nColRow < pCol->nCount &&
1179                 (nRow = pCol->pItems[nColRow].nRow) <= aParam.nRow2 )
1180 		{
1181             ScBaseCell* pCell = pCol->pItems[nColRow].pCell;
1182             if ( pCell->GetCellType() == CELLTYPE_NOTE )
1183                 ++nRow;
1184             else if (bAllStringIgnore && pCell->HasStringData())
1185                 ++nRow;
1186 			else
1187 			{
1188                 sal_Bool bTestEqualCondition;
1189                 if ( (pDoc->pTab[nTab])->ValidQuery( nRow, aParam, NULL,
1190                         (nCol == static_cast<SCCOL>(nFirstQueryField) ? pCell : NULL),
1191                         (nTestEqualCondition ? &bTestEqualCondition : NULL) ) )
1192                 {
1193                     if ( nTestEqualCondition && bTestEqualCondition )
1194                         nTestEqualCondition |= nTestEqualConditionMatched;
1195                     return pCell;     // found
1196                 }
1197                 else if ( nStopOnMismatch )
1198                 {
1199                     // Yes, even a mismatch may have a fulfilled equal
1200                     // condition if regular expressions were involved and
1201                     // SC_LESS_EQUAL or SC_GREATER_EQUAL were queried.
1202                     if ( nTestEqualCondition && bTestEqualCondition )
1203                     {
1204                         nTestEqualCondition |= nTestEqualConditionMatched;
1205                         nStopOnMismatch |= nStopOnMismatchOccured;
1206                         return NULL;
1207                     }
1208                     bool bStop;
1209                     if (bFirstStringIgnore)
1210                     {
1211                         if (pCell->HasStringData())
1212                         {
1213                             ++nRow;
1214                             bStop = false;
1215                         }
1216                         else
1217                             bStop = true;
1218                     }
1219                     else
1220                         bStop = true;
1221                     if (bStop)
1222                     {
1223                         nStopOnMismatch |= nStopOnMismatchOccured;
1224                         return NULL;
1225                     }
1226                 }
1227 				else
1228 					nRow++;
1229 			}
1230 		}
1231 		else
1232 			nRow = aParam.nRow2 + 1; // Naechste Spalte
1233         bFirstStringIgnore = false;
1234 	}
1235 }
1236 
1237 ScBaseCell* ScQueryCellIterator::GetFirst()
1238 {
1239 	nCol = aParam.nCol1;
1240 	nRow = aParam.nRow1;
1241 	if (aParam.bHasHeader)
1242 		nRow++;
1243 //	nColRow = 0;
1244 	ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1245 	pCol->Search( nRow, nColRow );
1246 	return GetThis();
1247 }
1248 
1249 ScBaseCell* ScQueryCellIterator::GetNext()
1250 {
1251 	++nRow;
1252     if ( nStopOnMismatch )
1253         nStopOnMismatch = nStopOnMismatchEnabled;
1254     if ( nTestEqualCondition )
1255         nTestEqualCondition = nTestEqualConditionEnabled;
1256 	return GetThis();
1257 }
1258 
1259 void ScQueryCellIterator::AdvanceQueryParamEntryField()
1260 {
1261 	SCSIZE nEntries = aParam.GetEntryCount();
1262 	for ( SCSIZE j = 0; j < nEntries; j++  )
1263 	{
1264 		ScQueryEntry& rEntry = aParam.GetEntry( j );
1265 		if ( rEntry.bDoQuery )
1266 		{
1267 			if ( rEntry.nField < MAXCOL )
1268 				rEntry.nField++;
1269 			else
1270 			{
1271 				DBG_ERRORFILE( "AdvanceQueryParamEntryField: ++rEntry.nField > MAXCOL" );
1272 			}
1273 		}
1274 		else
1275 			break;	// for
1276 	}
1277 }
1278 
1279 
1280 sal_Bool ScQueryCellIterator::FindEqualOrSortedLastInRange( SCCOL& nFoundCol,
1281         SCROW& nFoundRow, sal_Bool bSearchForEqualAfterMismatch,
1282         sal_Bool bIgnoreMismatchOnLeadingStringsP )
1283 {
1284     nFoundCol = MAXCOL+1;
1285     nFoundRow = MAXROW+1;
1286     SetStopOnMismatch( sal_True );      // assume sorted keys
1287     SetTestEqualCondition( sal_True );
1288     bIgnoreMismatchOnLeadingStrings = bIgnoreMismatchOnLeadingStringsP;
1289     bool bRegExp = aParam.bRegExp && aParam.GetEntry(0).bQueryByString;
1290     bool bBinary = !bRegExp && aParam.bByRow && (aParam.GetEntry(0).eOp ==
1291             SC_LESS_EQUAL || aParam.GetEntry(0).eOp == SC_GREATER_EQUAL);
1292     if (bBinary ? (BinarySearch() ? GetThis() : 0) : GetFirst())
1293     {
1294         // First equal entry or last smaller than (greater than) entry.
1295         SCSIZE nColRowSave;
1296         ScBaseCell* pNext = 0;
1297         do
1298         {
1299             nFoundCol = GetCol();
1300             nFoundRow = GetRow();
1301             nColRowSave = nColRow;
1302         } while ( !IsEqualConditionFulfilled() && (pNext = GetNext()) != NULL );
1303         // There may be no pNext but equal condition fulfilled if regular
1304         // expressions are involved. Keep the found entry and proceed.
1305         if (!pNext && !IsEqualConditionFulfilled())
1306         {
1307             // Step back to last in range and adjust position markers for
1308             // GetNumberFormat() or similar.
1309             nCol = nFoundCol;
1310             nRow = nFoundRow;
1311             nColRow = nColRowSave;
1312         }
1313     }
1314     if ( IsEqualConditionFulfilled() )
1315     {
1316         // Position on last equal entry.
1317         SCSIZE nEntries = aParam.GetEntryCount();
1318         for ( SCSIZE j = 0; j < nEntries; j++  )
1319         {
1320             ScQueryEntry& rEntry = aParam.GetEntry( j );
1321             if ( rEntry.bDoQuery )
1322             {
1323                 switch ( rEntry.eOp )
1324                 {
1325                     case SC_LESS_EQUAL :
1326                     case SC_GREATER_EQUAL :
1327                         rEntry.eOp = SC_EQUAL;
1328                     break;
1329                     default:
1330                     {
1331                         // added to avoid warnings
1332                     }
1333                 }
1334             }
1335             else
1336                 break;  // for
1337         }
1338         SCSIZE nColRowSave;
1339         bIgnoreMismatchOnLeadingStrings = sal_False;
1340         SetTestEqualCondition( sal_False );
1341         do
1342         {
1343             nFoundCol = GetCol();
1344             nFoundRow = GetRow();
1345             nColRowSave = nColRow;
1346         } while (GetNext());
1347         // Step back conditions same as above
1348         nCol = nFoundCol;
1349         nRow = nFoundRow;
1350         nColRow = nColRowSave;
1351         return sal_True;
1352     }
1353     if ( (bSearchForEqualAfterMismatch || aParam.bRegExp) &&
1354             StoppedOnMismatch() )
1355     {
1356         // Assume found entry to be the last value less than respectively
1357         // greater than the query. But keep on searching for an equal match.
1358         SCSIZE nEntries = aParam.GetEntryCount();
1359         for ( SCSIZE j = 0; j < nEntries; j++  )
1360         {
1361             ScQueryEntry& rEntry = aParam.GetEntry( j );
1362             if ( rEntry.bDoQuery )
1363             {
1364                 switch ( rEntry.eOp )
1365                 {
1366                     case SC_LESS_EQUAL :
1367                     case SC_GREATER_EQUAL :
1368                         rEntry.eOp = SC_EQUAL;
1369                     break;
1370                     default:
1371                     {
1372                         // added to avoid warnings
1373                     }
1374                 }
1375             }
1376             else
1377                 break;  // for
1378         }
1379         SetStopOnMismatch( sal_False );
1380         SetTestEqualCondition( sal_False );
1381         if (GetNext())
1382         {
1383             // Last of a consecutive area, avoid searching the entire parameter
1384             // range as it is a real performance bottleneck in case of regular
1385             // expressions.
1386             SCSIZE nColRowSave;
1387             do
1388             {
1389                 nFoundCol = GetCol();
1390                 nFoundRow = GetRow();
1391                 nColRowSave = nColRow;
1392                 SetStopOnMismatch( sal_True );
1393             } while (GetNext());
1394             nCol = nFoundCol;
1395             nRow = nFoundRow;
1396             nColRow = nColRowSave;
1397         }
1398     }
1399     return (nFoundCol <= MAXCOL) && (nFoundRow <= MAXROW);
1400 }
1401 
1402 
1403 ScBaseCell* ScQueryCellIterator::BinarySearch()
1404 {
1405 	nCol = aParam.nCol1;
1406 	ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1407     if (!pCol->nCount)
1408         return 0;
1409 
1410     ScBaseCell* pCell;
1411     SCSIZE nHi, nLo;
1412 	CollatorWrapper* pCollator = (aParam.bCaseSens ? ScGlobal::GetCaseCollator() :
1413 		ScGlobal::GetCollator());
1414     SvNumberFormatter& rFormatter = *(pDoc->GetFormatTable());
1415     const ScQueryEntry& rEntry = aParam.GetEntry(0);
1416     bool bLessEqual = rEntry.eOp == SC_LESS_EQUAL;
1417     bool bByString = rEntry.bQueryByString;
1418     bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings && !bByString;
1419     bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
1420         !aParam.bHasHeader && bByString;
1421 
1422 	nRow = aParam.nRow1;
1423 	if (aParam.bHasHeader)
1424 		nRow++;
1425     const ColEntry* pItems = pCol->pItems;
1426     if (pCol->Search( nRow, nLo ) && bFirstStringIgnore &&
1427             pItems[nLo].pCell->HasStringData())
1428     {
1429         String aCellStr;
1430         sal_uLong nFormat = pCol->GetNumberFormat( pItems[nLo].nRow);
1431         ScCellFormat::GetInputString( pItems[nLo].pCell, nFormat, aCellStr,
1432                 rFormatter);
1433         sal_Int32 nTmp = pCollator->compareString( aCellStr, *rEntry.pStr);
1434         if ((rEntry.eOp == SC_LESS_EQUAL && nTmp > 0) ||
1435                 (rEntry.eOp == SC_GREATER_EQUAL && nTmp < 0) ||
1436                 (rEntry.eOp == SC_EQUAL && nTmp != 0))
1437             ++nLo;
1438     }
1439 	if (!pCol->Search( aParam.nRow2, nHi ) && nHi>0)
1440         --nHi;
1441     while (bAllStringIgnore && nLo <= nHi && nLo < pCol->nCount &&
1442             pItems[nLo].pCell->HasStringData())
1443         ++nLo;
1444 
1445     // Bookkeeping values for breaking up the binary search in case the data
1446     // range isn't strictly sorted.
1447     SCSIZE nLastInRange = nLo;
1448     SCSIZE nFirstLastInRange = nLastInRange;
1449     double fLastInRangeValue = bLessEqual ?
1450         -(::std::numeric_limits<double>::max()) :
1451             ::std::numeric_limits<double>::max();
1452     String aLastInRangeString;
1453     if (!bLessEqual)
1454         aLastInRangeString.Assign( sal_Unicode(0xFFFF));
1455     if (nLastInRange < pCol->nCount)
1456     {
1457         pCell = pItems[nLastInRange].pCell;
1458         if (pCell->HasStringData())
1459         {
1460             sal_uLong nFormat = pCol->GetNumberFormat( pItems[nLastInRange].nRow);
1461             ScCellFormat::GetInputString( pCell, nFormat, aLastInRangeString,
1462                     rFormatter);
1463         }
1464         else
1465         {
1466             switch ( pCell->GetCellType() )
1467             {
1468                 case CELLTYPE_VALUE :
1469                     fLastInRangeValue =
1470                         static_cast<ScValueCell*>(pCell)->GetValue();
1471                     break;
1472                 case CELLTYPE_FORMULA :
1473                     fLastInRangeValue =
1474                         static_cast<ScFormulaCell*>(pCell)->GetValue();
1475                     break;
1476                 default:
1477                 {
1478                     // added to avoid warnings
1479                 }
1480             }
1481         }
1482     }
1483 
1484     sal_Int32 nRes = 0;
1485     bool bFound = false;
1486     bool bDone = false;
1487     while (nLo <= nHi && !bDone)
1488     {
1489         SCSIZE nMid = (nLo+nHi)/2;
1490         SCSIZE i = nMid;
1491         while (i <= nHi && pItems[i].pCell->GetCellType() == CELLTYPE_NOTE)
1492             ++i;
1493         if (i > nHi)
1494         {
1495             if (nMid > 0)
1496                 nHi = nMid - 1;
1497             else
1498                 bDone = true;
1499             continue;   // while
1500         }
1501         sal_Bool bStr = pItems[i].pCell->HasStringData();
1502         nRes = 0;
1503         // compares are content<query:-1, content>query:1
1504         // Cell value comparison similar to ScTable::ValidQuery()
1505         if (!bStr && !bByString)
1506         {
1507             double nCellVal;
1508             pCell = pItems[i].pCell;
1509             switch ( pCell->GetCellType() )
1510             {
1511                 case CELLTYPE_VALUE :
1512                     nCellVal = static_cast<ScValueCell*>(pCell)->GetValue();
1513                     break;
1514                 case CELLTYPE_FORMULA :
1515                     nCellVal = static_cast<ScFormulaCell*>(pCell)->GetValue();
1516                     break;
1517                 default:
1518                     nCellVal = 0.0;
1519             }
1520             if ((nCellVal < rEntry.nVal) && !::rtl::math::approxEqual(
1521                         nCellVal, rEntry.nVal))
1522             {
1523                 nRes = -1;
1524                 if (bLessEqual)
1525                 {
1526                     if (fLastInRangeValue < nCellVal)
1527                     {
1528                         fLastInRangeValue = nCellVal;
1529                         nLastInRange = i;
1530                     }
1531                     else if (fLastInRangeValue > nCellVal)
1532                     {
1533                         // not strictly sorted, continue with GetThis()
1534                         nLastInRange = nFirstLastInRange;
1535                         bDone = true;
1536                     }
1537                 }
1538             }
1539             else if ((nCellVal > rEntry.nVal) && !::rtl::math::approxEqual(
1540                         nCellVal, rEntry.nVal))
1541             {
1542                 nRes = 1;
1543                 if (!bLessEqual)
1544                 {
1545                     if (fLastInRangeValue > nCellVal)
1546                     {
1547                         fLastInRangeValue = nCellVal;
1548                         nLastInRange = i;
1549                     }
1550                     else if (fLastInRangeValue < nCellVal)
1551                     {
1552                         // not strictly sorted, continue with GetThis()
1553                         nLastInRange = nFirstLastInRange;
1554                         bDone = true;
1555                     }
1556                 }
1557             }
1558         }
1559         else if (bStr && bByString)
1560         {
1561             String aCellStr;
1562             sal_uLong nFormat = pCol->GetNumberFormat( pItems[i].nRow);
1563             ScCellFormat::GetInputString( pItems[i].pCell, nFormat, aCellStr,
1564                     rFormatter);
1565             nRes = pCollator->compareString( aCellStr, *rEntry.pStr);
1566             if (nRes < 0 && bLessEqual)
1567             {
1568                 sal_Int32 nTmp = pCollator->compareString( aLastInRangeString,
1569                         aCellStr);
1570                 if (nTmp < 0)
1571                 {
1572                     aLastInRangeString = aCellStr;
1573                     nLastInRange = i;
1574                 }
1575                 else if (nTmp > 0)
1576                 {
1577                     // not strictly sorted, continue with GetThis()
1578                     nLastInRange = nFirstLastInRange;
1579                     bDone = true;
1580                 }
1581             }
1582             else if (nRes > 0 && !bLessEqual)
1583             {
1584                 sal_Int32 nTmp = pCollator->compareString( aLastInRangeString,
1585                         aCellStr);
1586                 if (nTmp > 0)
1587                 {
1588                     aLastInRangeString = aCellStr;
1589                     nLastInRange = i;
1590                 }
1591                 else if (nTmp < 0)
1592                 {
1593                     // not strictly sorted, continue with GetThis()
1594                     nLastInRange = nFirstLastInRange;
1595                     bDone = true;
1596                 }
1597             }
1598         }
1599         else if (!bStr && bByString)
1600         {
1601             nRes = -1;  // numeric < string
1602             if (bLessEqual)
1603                 nLastInRange = i;
1604         }
1605         else // if (bStr && !bByString)
1606         {
1607             nRes = 1;   // string > numeric
1608             if (!bLessEqual)
1609                 nLastInRange = i;
1610         }
1611         if (nRes < 0)
1612         {
1613             if (bLessEqual)
1614                 nLo = nMid + 1;
1615             else    // assumed to be SC_GREATER_EQUAL
1616             {
1617                 if (nMid > 0)
1618                     nHi = nMid - 1;
1619                 else
1620                     bDone = true;
1621             }
1622         }
1623         else if (nRes > 0)
1624         {
1625             if (bLessEqual)
1626             {
1627                 if (nMid > 0)
1628                     nHi = nMid - 1;
1629                 else
1630                     bDone = true;
1631             }
1632             else    // assumed to be SC_GREATER_EQUAL
1633                 nLo = nMid + 1;
1634         }
1635         else
1636         {
1637             nLo = i;
1638             bDone = bFound = true;
1639         }
1640     }
1641     if (!bFound)
1642     {
1643         // If all hits didn't result in a moving limit there's something
1644         // strange, e.g. data range not properly sorted, or only identical
1645         // values encountered, which doesn't mean there aren't any others in
1646         // between.. leave it to GetThis(). The condition for this would be
1647         // if (nLastInRange == nFirstLastInRange) nLo = nFirstLastInRange;
1648         // Else, in case no exact match was found, we step back for a
1649         // subsequent GetThis() to find the last in range. Effectively this is
1650         // --nLo with nLastInRange == nLo-1. Both conditions combined yield:
1651         nLo = nLastInRange;
1652     }
1653     if (nLo < pCol->nCount && pCol->pItems[nLo].nRow <= aParam.nRow2)
1654     {
1655         nRow = pItems[nLo].nRow;
1656         pCell = pItems[nLo].pCell;
1657         nColRow = nLo;
1658     }
1659     else
1660     {
1661         nRow = aParam.nRow2 + 1;
1662         pCell = 0;
1663         nColRow = pCol->nCount - 1;
1664     }
1665     return pCell;
1666 }
1667 
1668 
1669 //-------------------------------------------------------------------------------
1670 
1671 ScHorizontalCellIterator::ScHorizontalCellIterator(ScDocument* pDocument, SCTAB nTable,
1672 									SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
1673 	pDoc( pDocument ),
1674 	nTab( nTable ),
1675 	nStartCol( nCol1 ),
1676 	nEndCol( nCol2 ),
1677 	nStartRow( nRow1 ),
1678 	nEndRow( nRow2 ),
1679 	nCol( nCol1 ),
1680 	nRow( nRow1 ),
1681 	bMore( sal_True )
1682 {
1683 
1684 	pNextRows = new SCROW[ nCol2-nCol1+1 ];
1685 	pNextIndices = new SCSIZE[ nCol2-nCol1+1 ];
1686 
1687 	SetTab( nTab );
1688 }
1689 
1690 ScHorizontalCellIterator::~ScHorizontalCellIterator()
1691 {
1692 	delete [] pNextRows;
1693 	delete [] pNextIndices;
1694 }
1695 
1696 void ScHorizontalCellIterator::SetTab( SCTAB nTabP )
1697 {
1698 	nTab = nTabP;
1699 	nRow = nStartRow;
1700 	nCol = nStartCol;
1701 	bMore = sal_True;
1702 
1703 	for (SCCOL i=nStartCol; i<=nEndCol; i++)
1704 	{
1705 		ScColumn* pCol = &pDoc->pTab[nTab]->aCol[i];
1706 
1707 		SCSIZE nIndex;
1708 		pCol->Search( nStartRow, nIndex );
1709 		if ( nIndex < pCol->nCount )
1710 		{
1711 			pNextRows[i-nStartCol] = pCol->pItems[nIndex].nRow;
1712 			pNextIndices[i-nStartCol] = nIndex;
1713 		}
1714 		else
1715 		{
1716 			pNextRows[i-nStartCol] = MAXROWCOUNT;		// nichts gefunden
1717 			pNextIndices[i-nStartCol] = MAXROWCOUNT;
1718 		}
1719 	}
1720 
1721 	if (pNextRows[0] != nStartRow)
1722 		Advance();
1723 }
1724 
1725 ScBaseCell* ScHorizontalCellIterator::GetNext( SCCOL& rCol, SCROW& rRow )
1726 {
1727 	if ( bMore )
1728 	{
1729 		rCol = nCol;
1730 		rRow = nRow;
1731 
1732 		ScColumn* pCol = &pDoc->pTab[nTab]->aCol[nCol];
1733 		SCSIZE nIndex = pNextIndices[nCol-nStartCol];
1734 		DBG_ASSERT( nIndex < pCol->nCount, "ScHorizontalCellIterator::GetNext: nIndex out of range" );
1735 		ScBaseCell* pCell = pCol->pItems[nIndex].pCell;
1736 		if ( ++nIndex < pCol->nCount )
1737 		{
1738 			pNextRows[nCol-nStartCol] = pCol->pItems[nIndex].nRow;
1739 			pNextIndices[nCol-nStartCol] = nIndex;
1740 		}
1741 		else
1742 		{
1743 			pNextRows[nCol-nStartCol] = MAXROWCOUNT;		// nichts gefunden
1744 			pNextIndices[nCol-nStartCol] = MAXROWCOUNT;
1745 		}
1746 
1747 		Advance();
1748 		return pCell;
1749 	}
1750 	else
1751 		return NULL;
1752 }
1753 
1754 sal_Bool ScHorizontalCellIterator::ReturnNext( SCCOL& rCol, SCROW& rRow )
1755 {
1756 	rCol = nCol;
1757 	rRow = nRow;
1758 	return bMore;
1759 }
1760 
1761 void ScHorizontalCellIterator::Advance()
1762 {
1763 	sal_Bool bFound = sal_False;
1764 	SCCOL i;
1765 
1766 	for (i=nCol+1; i<=nEndCol && !bFound; i++)
1767 		if (pNextRows[i-nStartCol] == nRow)
1768 		{
1769 			nCol = i;
1770 			bFound = sal_True;
1771 		}
1772 
1773 	if (!bFound)
1774 	{
1775 		SCROW nMinRow = MAXROW+1;
1776 		for (i=nStartCol; i<=nEndCol; i++)
1777 			if (pNextRows[i-nStartCol] < nMinRow)
1778 			{
1779 				nCol = i;
1780 				nMinRow = pNextRows[i-nStartCol];
1781 			}
1782 
1783 		if (nMinRow <= nEndRow)
1784 		{
1785 			nRow = nMinRow;
1786 			bFound = sal_True;
1787 		}
1788 	}
1789 
1790 	if ( !bFound )
1791 		bMore = sal_False;
1792 }
1793 
1794 //------------------------------------------------------------------------
1795 
1796 ScHorizontalValueIterator::ScHorizontalValueIterator( ScDocument* pDocument,
1797         const ScRange& rRange, bool bSTotal, bool bTextZero ) :
1798     pDoc( pDocument ),
1799     nNumFmtIndex(0),
1800     nEndTab( rRange.aEnd.Tab() ),
1801     nNumFmtType( NUMBERFORMAT_UNDEFINED ),
1802     bNumValid( false ),
1803     bSubTotal( bSTotal ),
1804     bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ),
1805     bTextAsZero( bTextZero )
1806 {
1807 	SCCOL nStartCol = rRange.aStart.Col();
1808     SCROW nStartRow = rRange.aStart.Row();
1809     SCTAB nStartTab = rRange.aStart.Tab();
1810     SCCOL nEndCol = rRange.aEnd.Col();
1811     SCROW nEndRow = rRange.aEnd.Row();
1812     PutInOrder( nStartCol, nEndCol);
1813     PutInOrder( nStartRow, nEndRow);
1814     PutInOrder( nStartTab, nEndTab );
1815 
1816     if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
1817     if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
1818     if (!ValidRow(nStartRow)) nStartRow = MAXROW;
1819     if (!ValidRow(nEndRow)) nEndRow = MAXROW;
1820     if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
1821     if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
1822 
1823     nCurCol = nStartCol;
1824     nCurRow = nStartRow;
1825     nCurTab = nStartTab;
1826 
1827     nNumFormat = 0;                 // will be initialized in GetNumberFormat()
1828     pAttrArray = 0;
1829     nAttrEndRow = 0;
1830 
1831     pCellIter = new ScHorizontalCellIterator( pDoc, nStartTab, nStartCol,
1832             nStartRow, nEndCol, nEndRow );
1833 }
1834 
1835 ScHorizontalValueIterator::~ScHorizontalValueIterator()
1836 {
1837     delete pCellIter;
1838 }
1839 
1840 bool ScHorizontalValueIterator::GetNext( double& rValue, sal_uInt16& rErr )
1841 {
1842     bool bFound = false;
1843     while ( !bFound )
1844     {
1845         ScBaseCell* pCell = pCellIter->GetNext( nCurCol, nCurRow );
1846         while ( !pCell )
1847         {
1848             if ( nCurTab < nEndTab )
1849             {
1850                 pCellIter->SetTab( ++nCurTab);
1851                 pCell = pCellIter->GetNext( nCurCol, nCurRow );
1852             }
1853             else
1854                 return false;
1855         }
1856         if ( !bSubTotal || !pDoc->pTab[nCurTab]->RowFiltered( nCurRow ) )
1857         {
1858             switch (pCell->GetCellType())
1859             {
1860                 case CELLTYPE_VALUE:
1861                     {
1862                         bNumValid = false;
1863                         rValue = ((ScValueCell*)pCell)->GetValue();
1864                         rErr = 0;
1865                         if ( bCalcAsShown )
1866                         {
1867                             ScColumn* pCol = &pDoc->pTab[nCurTab]->aCol[nCurCol];
1868                             lcl_IterGetNumberFormat( nNumFormat, pAttrArray,
1869                                     nAttrEndRow, pCol->pAttrArray, nCurRow, pDoc );
1870                             rValue = pDoc->RoundValueAsShown( rValue, nNumFormat );
1871                         }
1872                         bFound = true;
1873                     }
1874                     break;
1875                 case CELLTYPE_FORMULA:
1876                     {
1877                         if (!bSubTotal || !((ScFormulaCell*)pCell)->IsSubTotal())
1878                         {
1879                             rErr = ((ScFormulaCell*)pCell)->GetErrCode();
1880                             if ( rErr || ((ScFormulaCell*)pCell)->IsValue() )
1881                             {
1882                                 rValue = ((ScFormulaCell*)pCell)->GetValue();
1883                                 bNumValid = false;
1884                                 bFound = true;
1885                             }
1886                             else if ( bTextAsZero )
1887                             {
1888                                 rValue = 0.0;
1889                                 bNumValid = false;
1890                                 bFound = true;
1891                             }
1892                         }
1893                     }
1894                     break;
1895                 case CELLTYPE_STRING :
1896                 case CELLTYPE_EDIT :
1897                     {
1898                         if ( bTextAsZero )
1899                         {
1900                             rErr = 0;
1901                             rValue = 0.0;
1902                             nNumFmtType = NUMBERFORMAT_NUMBER;
1903                             nNumFmtIndex = 0;
1904                             bNumValid = true;
1905                             bFound = true;
1906                         }
1907                     }
1908                     break;
1909                 default:
1910                     ;   // nothing
1911             }
1912         }
1913     }
1914     return bFound;
1915 }
1916 
1917 void ScHorizontalValueIterator::GetCurNumFmtInfo( short& nType, sal_uLong& nIndex )
1918 {
1919     if (!bNumValid)
1920     {
1921         const ScColumn* pCol = &(pDoc->pTab[nCurTab])->aCol[nCurCol];
1922         nNumFmtIndex = pCol->GetNumberFormat( nCurRow );
1923         if ( (nNumFmtIndex % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
1924         {
1925             const ScBaseCell* pCell;
1926             SCSIZE nCurIndex;
1927             if ( pCol->Search( nCurRow, nCurIndex ) )
1928                 pCell = pCol->pItems[nCurIndex].pCell;
1929             else
1930                 pCell = NULL;
1931             if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA )
1932                 ((const ScFormulaCell*)pCell)->GetFormatInfo( nNumFmtType, nNumFmtIndex );
1933             else
1934                 nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex );
1935         }
1936         else
1937             nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex );
1938         bNumValid = true;
1939     }
1940     nType = nNumFmtType;
1941     nIndex = nNumFmtIndex;
1942 }
1943 
1944 //-------------------------------------------------------------------------------
1945 
1946 ScHorizontalAttrIterator::ScHorizontalAttrIterator( ScDocument* pDocument, SCTAB nTable,
1947 							SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
1948 	pDoc( pDocument ),
1949 	nTab( nTable ),
1950 	nStartCol( nCol1 ),
1951 	nStartRow( nRow1 ),
1952 	nEndCol( nCol2 ),
1953 	nEndRow( nRow2 )
1954 {
1955 	DBG_ASSERT( pDoc->pTab[nTab], "Tabelle nicht da" );
1956 
1957 	SCCOL i;
1958 
1959 	nRow = nStartRow;
1960 	nCol = nStartCol;
1961 	bRowEmpty = sal_False;
1962 
1963 	pIndices	= new SCSIZE[nEndCol-nStartCol+1];
1964 	pNextEnd	= new SCROW[nEndCol-nStartCol+1];
1965 	ppPatterns	= new const ScPatternAttr*[nEndCol-nStartCol+1];
1966 
1967 	SCROW nSkipTo = MAXROW;
1968 	sal_Bool bEmpty = sal_True;
1969 	for (i=nStartCol; i<=nEndCol; i++)
1970 	{
1971 		SCCOL nPos = i - nStartCol;
1972 		ScAttrArray* pArray = pDoc->pTab[nTab]->aCol[i].pAttrArray;
1973 		DBG_ASSERT( pArray, "pArray == 0" );
1974 
1975 		SCSIZE nIndex;
1976 		pArray->Search( nStartRow, nIndex );
1977 
1978 		const ScPatternAttr* pPattern = pArray->pData[nIndex].pPattern;
1979 		SCROW nThisEnd = pArray->pData[nIndex].nRow;
1980 		if ( IsDefaultItem( pPattern ) )
1981 		{
1982 			pPattern = NULL;
1983 			if ( nThisEnd < nSkipTo )
1984 				nSkipTo = nThisEnd;			// nSkipTo kann gleich hier gesetzt werden
1985 		}
1986 		else
1987 			bEmpty = sal_False;					// Attribute gefunden
1988 
1989 		pIndices[nPos] = nIndex;
1990 		pNextEnd[nPos] = nThisEnd;
1991 		ppPatterns[nPos] = pPattern;
1992 	}
1993 
1994 	if (bEmpty)
1995 		nRow = nSkipTo;						// bis zum naechsten Bereichsende ueberspringen
1996 	bRowEmpty = bEmpty;
1997 }
1998 
1999 ScHorizontalAttrIterator::~ScHorizontalAttrIterator()
2000 {
2001 	delete[] (ScPatternAttr**)ppPatterns;
2002 	delete[] pNextEnd;
2003 	delete[] pIndices;
2004 }
2005 
2006 const ScPatternAttr* ScHorizontalAttrIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2, SCROW& rRow )
2007 {
2008 	for (;;)
2009 	{
2010 		if (!bRowEmpty)
2011 		{
2012 			// in dieser Zeile suchen
2013 
2014 			while ( nCol <= nEndCol && !ppPatterns[nCol-nStartCol] )
2015 				++nCol;
2016 
2017 			if ( nCol <= nEndCol )
2018 			{
2019 				const ScPatternAttr* pPat = ppPatterns[nCol-nStartCol];
2020 				rRow = nRow;
2021 				rCol1 = nCol;
2022 				while ( nCol < nEndCol && ppPatterns[nCol+1-nStartCol] == pPat )
2023 					++nCol;
2024 				rCol2 = nCol;
2025 				++nCol;					// hochzaehlen fuer naechsten Aufruf
2026 				return pPat;			// gefunden
2027 			}
2028 		}
2029 
2030 		// naechste Zeile
2031 
2032 		++nRow;
2033 		if ( nRow > nEndRow )		// schon am Ende?
2034 			return NULL;			// nichts gefunden
2035 
2036 		sal_Bool bEmpty = sal_True;
2037 		SCCOL i;
2038 
2039 		for ( i = nStartCol; i <= nEndCol; i++)
2040 		{
2041 			SCCOL nPos = i-nStartCol;
2042 			if ( pNextEnd[nPos] < nRow )
2043 			{
2044 				ScAttrArray* pArray = pDoc->pTab[nTab]->aCol[i].pAttrArray;
2045 
2046 				SCSIZE nIndex = ++pIndices[nPos];
2047 				if ( nIndex < pArray->nCount )
2048 				{
2049 					const ScPatternAttr* pPattern = pArray->pData[nIndex].pPattern;
2050 					SCROW nThisEnd = pArray->pData[nIndex].nRow;
2051 					if ( IsDefaultItem( pPattern ) )
2052 						pPattern = NULL;
2053 					else
2054 						bEmpty = sal_False;					// Attribute gefunden
2055 
2056 					pNextEnd[nPos] = nThisEnd;
2057 					ppPatterns[nPos] = pPattern;
2058 
2059 					DBG_ASSERT( pNextEnd[nPos] >= nRow, "Reihenfolge durcheinander" );
2060 				}
2061 				else
2062 				{
2063 					DBG_ERROR("AttrArray reicht nicht bis MAXROW");
2064 					pNextEnd[nPos] = MAXROW;
2065 					ppPatterns[nPos] = NULL;
2066 				}
2067 			}
2068 			else if ( ppPatterns[nPos] )
2069 				bEmpty = sal_False;							// Bereich noch nicht zuende
2070 		}
2071 
2072 		if (bEmpty)
2073 		{
2074 			SCCOL nCount = nEndCol-nStartCol+1;
2075 			SCROW nSkipTo = pNextEnd[0];				// naechstes Bereichsende suchen
2076 			for (i=1; i<nCount; i++)
2077 				if ( pNextEnd[i] < nSkipTo )
2078 					nSkipTo = pNextEnd[i];
2079 			nRow = nSkipTo;								// leere Zeilen ueberspringen
2080 		}
2081 		bRowEmpty = bEmpty;
2082 		nCol = nStartCol;			// wieder links anfangen
2083 	}
2084 
2085 //    return NULL;
2086 }
2087 
2088 //-------------------------------------------------------------------------------
2089 
2090 inline sal_Bool IsGreater( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
2091 {
2092 	return ( nRow1 > nRow2 ) || ( nRow1 == nRow2 && nCol1 > nCol2 );
2093 }
2094 
2095 ScUsedAreaIterator::ScUsedAreaIterator( ScDocument* pDocument, SCTAB nTable,
2096 							SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
2097 	aCellIter( pDocument, nTable, nCol1, nRow1, nCol2, nRow2 ),
2098 	aAttrIter( pDocument, nTable, nCol1, nRow1, nCol2, nRow2 ),
2099 	nNextCol( nCol1 ),
2100 	nNextRow( nRow1 )
2101 {
2102 	pCell    = aCellIter.GetNext( nCellCol, nCellRow );
2103 	pPattern = aAttrIter.GetNext( nAttrCol1, nAttrCol2, nAttrRow );
2104 }
2105 
2106 ScUsedAreaIterator::~ScUsedAreaIterator()
2107 {
2108 }
2109 
2110 sal_Bool ScUsedAreaIterator::GetNext()
2111 {
2112 	//	Iteratoren weiterzaehlen
2113 
2114 	if ( pCell && IsGreater( nNextCol, nNextRow, nCellCol, nCellRow ) )
2115 		pCell = aCellIter.GetNext( nCellCol, nCellRow );
2116 
2117     while ( pCell && pCell->IsBlank() )
2118 		pCell = aCellIter.GetNext( nCellCol, nCellRow );
2119 
2120 	if ( pPattern && IsGreater( nNextCol, nNextRow, nAttrCol2, nAttrRow ) )
2121 		pPattern = aAttrIter.GetNext( nAttrCol1, nAttrCol2, nAttrRow );
2122 
2123 	if ( pPattern && nAttrRow == nNextRow && nAttrCol1 < nNextCol )
2124 		nAttrCol1 = nNextCol;
2125 
2126 	//	naechsten Abschnitt heraussuchen
2127 
2128 	sal_Bool bFound = sal_True;
2129 	sal_Bool bUseCell = sal_False;
2130 
2131 	if ( pCell && pPattern )
2132 	{
2133 		if ( IsGreater( nCellCol, nCellRow, nAttrCol1, nAttrRow ) )		// vorne nur Attribute ?
2134 		{
2135 			pFoundCell = NULL;
2136 			pFoundPattern = pPattern;
2137 			nFoundRow = nAttrRow;
2138 			nFoundStartCol = nAttrCol1;
2139 			if ( nCellRow == nAttrRow && nCellCol <= nAttrCol2 )		// auch Zelle im Bereich ?
2140 				nFoundEndCol = nCellCol - 1;							// nur bis vor der Zelle
2141 			else
2142 				nFoundEndCol = nAttrCol2;								// alles
2143 		}
2144 		else
2145 		{
2146 			bUseCell = sal_True;
2147 			if ( nAttrRow == nCellRow && nAttrCol1 == nCellCol )		// Attribute auf der Zelle ?
2148 				pFoundPattern = pPattern;
2149 			else
2150 				pFoundPattern = NULL;
2151 		}
2152 	}
2153 	else if ( pCell )					// nur Zelle -> direkt uebernehmen
2154 	{
2155 		pFoundPattern = NULL;
2156 		bUseCell = sal_True;				// Position von Zelle
2157 	}
2158 	else if ( pPattern )				// nur Attribute -> direkt uebernehmen
2159 	{
2160 		pFoundCell = NULL;
2161 		pFoundPattern = pPattern;
2162 		nFoundRow = nAttrRow;
2163 		nFoundStartCol = nAttrCol1;
2164 		nFoundEndCol = nAttrCol2;
2165 	}
2166 	else								// gar nichts
2167 		bFound = sal_False;
2168 
2169 	if ( bUseCell )						// Position von Zelle
2170 	{
2171 		pFoundCell = pCell;
2172 		nFoundRow = nCellRow;
2173 		nFoundStartCol = nFoundEndCol = nCellCol;
2174 	}
2175 
2176 	if (bFound)
2177 	{
2178 		nNextRow = nFoundRow;
2179 		nNextCol = nFoundEndCol + 1;
2180 	}
2181 
2182 	return bFound;
2183 }
2184 
2185 //-------------------------------------------------------------------------------
2186 
2187 ScDocAttrIterator::ScDocAttrIterator(ScDocument* pDocument, SCTAB nTable,
2188 									SCCOL nCol1, SCROW nRow1,
2189 									SCCOL nCol2, SCROW nRow2) :
2190 	pDoc( pDocument ),
2191 	nTab( nTable ),
2192 	nEndCol( nCol2 ),
2193 	nStartRow( nRow1 ),
2194 	nEndRow( nRow2 ),
2195 	nCol( nCol1 )
2196 {
2197 	if ( ValidTab(nTab) && pDoc->pTab[nTab] )
2198 		pColIter = pDoc->pTab[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow );
2199 	else
2200 		pColIter = NULL;
2201 }
2202 
2203 ScDocAttrIterator::~ScDocAttrIterator()
2204 {
2205 	delete pColIter;
2206 }
2207 
2208 const ScPatternAttr* ScDocAttrIterator::GetNext( SCCOL& rCol, SCROW& rRow1, SCROW& rRow2 )
2209 {
2210 	while ( pColIter )
2211 	{
2212 		const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 );
2213 		if ( pPattern )
2214 		{
2215 			rCol = nCol;
2216 			return pPattern;
2217 		}
2218 
2219 		delete pColIter;
2220 		++nCol;
2221 		if ( nCol <= nEndCol )
2222 			pColIter = pDoc->pTab[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow );
2223 		else
2224 			pColIter = NULL;
2225 	}
2226 	return NULL;		// is nix mehr
2227 }
2228 
2229 //-------------------------------------------------------------------------------
2230 
2231 ScAttrRectIterator::ScAttrRectIterator(ScDocument* pDocument, SCTAB nTable,
2232 									SCCOL nCol1, SCROW nRow1,
2233 									SCCOL nCol2, SCROW nRow2) :
2234 	pDoc( pDocument ),
2235 	nTab( nTable ),
2236 	nEndCol( nCol2 ),
2237 	nStartRow( nRow1 ),
2238 	nEndRow( nRow2 ),
2239 	nIterStartCol( nCol1 ),
2240 	nIterEndCol( nCol1 )
2241 {
2242 	if ( ValidTab(nTab) && pDoc->pTab[nTab] )
2243 	{
2244 		pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow );
2245 		while ( nIterEndCol < nEndCol &&
2246 				pDoc->pTab[nTab]->aCol[nIterEndCol].IsAllAttrEqual(
2247 					pDoc->pTab[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) )
2248 			++nIterEndCol;
2249 	}
2250 	else
2251 		pColIter = NULL;
2252 }
2253 
2254 ScAttrRectIterator::~ScAttrRectIterator()
2255 {
2256 	delete pColIter;
2257 }
2258 
2259 void ScAttrRectIterator::DataChanged()
2260 {
2261 	if (pColIter)
2262 	{
2263 		SCROW nNextRow = pColIter->GetNextRow();
2264 		delete pColIter;
2265 		pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nNextRow, nEndRow );
2266 	}
2267 }
2268 
2269 const ScPatternAttr* ScAttrRectIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2,
2270 													SCROW& rRow1, SCROW& rRow2 )
2271 {
2272 	while ( pColIter )
2273 	{
2274 		const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 );
2275 		if ( pPattern )
2276 		{
2277 			rCol1 = nIterStartCol;
2278 			rCol2 = nIterEndCol;
2279 			return pPattern;
2280 		}
2281 
2282 		delete pColIter;
2283 		nIterStartCol = nIterEndCol+1;
2284 		if ( nIterStartCol <= nEndCol )
2285 		{
2286 			nIterEndCol = nIterStartCol;
2287 			pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow );
2288 			while ( nIterEndCol < nEndCol &&
2289 					pDoc->pTab[nTab]->aCol[nIterEndCol].IsAllAttrEqual(
2290 						pDoc->pTab[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) )
2291 				++nIterEndCol;
2292 		}
2293 		else
2294 			pColIter = NULL;
2295 	}
2296 	return NULL;		// is nix mehr
2297 }
2298 
2299 // ============================================================================
2300 
2301 SCROW ScRowBreakIterator::NOT_FOUND = -1;
2302 
2303 ScRowBreakIterator::ScRowBreakIterator(set<SCROW>& rBreaks) :
2304     mrBreaks(rBreaks),
2305     maItr(rBreaks.begin()), maEnd(rBreaks.end())
2306 {
2307 }
2308 
2309 SCROW ScRowBreakIterator::first()
2310 {
2311     maItr = mrBreaks.begin();
2312     return maItr == maEnd ? NOT_FOUND : *maItr;
2313 }
2314 
2315 SCROW ScRowBreakIterator::next()
2316 {
2317     ++maItr;
2318     return maItr == maEnd ? NOT_FOUND : *maItr;
2319 }
2320