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