xref: /AOO41X/main/sc/source/core/data/dociter.cxx (revision 8809db7a87f97847b57a57f4cd2b0104b2b83182)
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 
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 
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 
81 ScDocumentIterator::~ScDocumentIterator()
82 {
83 }
84 
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 
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 
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 
188 sal_Bool ScDocumentIterator::GetNext()
189 {
190     ++nRow;
191 
192     return GetThis();
193 }
194 
195 //------------------------------------------------------------------------
196 
197 ScBaseCell* ScDocumentIterator::GetCell()
198 {
199     return pCell;
200 }
201 
202 const ScPatternAttr* ScDocumentIterator::GetPattern()
203 {
204     return pPattern;
205 }
206 
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 //------------------------------------------------------------------------
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 
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;                    // wird bei GetFirst initialisiert
306 
307     nNumFormat = 0;                 // werden bei GetNumberFormat initialisiert
308     pAttrArray = 0;
309     nAttrEndRow = 0;
310 }
311 
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;               // Ende und Aus
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                         //  wenn in der selben Spalte gleich noch eine Value-Cell folgt, die
365                         //  auch noch im Block liegt, den Wert jetzt schon holen
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;                                    // gefunden
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;                            // gefunden
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;         // naechste Spalte
432     }
433 }
434 
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 
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;                 // werden bei GetNumberFormat initialisiert
479     pAttrArray = 0;
480     nAttrEndRow = 0;
481 
482     return GetThis(rValue, rErr);
483 }
484 
485 /*  ist inline:
486 sal_Bool ScValueIterator::GetNext(double& rValue, sal_uInt16& rErr)
487 {
488     ++nRow;
489     return GetThis(rValue, rErr);
490 }
491 */
492 
493 // ============================================================================
494 
495 ScDBQueryDataIterator::DataAccess::DataAccess(const ScDBQueryDataIterator* pParent) :
496     mpParent(pParent)
497 {
498 }
499 
500 ScDBQueryDataIterator::DataAccess::~DataAccess()
501 {
502 }
503 
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 
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 
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 
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 
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 
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;                    // wird bei GetFirst initialisiert
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;                 // werden bei GetNumberFormat initialisiert
558     pAttrArray = 0;
559     nAttrEndRow = 0;
560 }
561 
562 ScDBQueryDataIterator::DataAccessInternal::~DataAccessInternal()
563 {
564 }
565 
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;        // gefunden
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;    // gefunden
627                             }
628                             else
629                                 nRow++;
630                         }
631                         break;
632                     case CELLTYPE_STRING:
633                     case CELLTYPE_EDIT:
634                         if (mpParam->mbSkipString)
635                             ++nRow;
636                         else
637                         {
638                             rValue.maString = pCell->GetStringData();
639                             rValue.mfValue = 0.0;
640                             rValue.mnError = 0;
641                             rValue.mbIsNumber = false;
642                             return true;
643                         }
644                         break;
645                     default:
646                         nRow++;
647                         break;
648                 }
649             }
650             else
651                 nRow++;
652         }
653         else
654             nRow = mpParam->nRow2 + 1; // Naechste Spalte
655     }
656 // statement unreachable
657 //    return false;
658 }
659 
660 bool ScDBQueryDataIterator::DataAccessInternal::getFirst(Value& rValue)
661 {
662     if (mpParam->bHasHeader)
663         nRow++;
664 
665     nColRow = ScDBQueryDataIterator::SearchColEntryIndex(*mpDoc, nTab, nRow, nCol);
666     return getCurrent(rValue);
667 }
668 
669 bool ScDBQueryDataIterator::DataAccessInternal::getNext(Value& rValue)
670 {
671     ++nRow;
672     return getCurrent(rValue);
673 }
674 
675 // ----------------------------------------------------------------------------
676 
677 ScDBQueryDataIterator::DataAccessMatrix::DataAccessMatrix(const ScDBQueryDataIterator* pParent, ScDBQueryParamMatrix* pParam) :
678     DataAccess(pParent),
679     mpParam(pParam)
680 {
681     SCSIZE nC, nR;
682     mpParam->mpMatrix->GetDimensions(nC, nR);
683     mnRows = static_cast<SCROW>(nR);
684     mnCols = static_cast<SCCOL>(nC);
685 }
686 
687 ScDBQueryDataIterator::DataAccessMatrix::~DataAccessMatrix()
688 {
689 }
690 
691 bool ScDBQueryDataIterator::DataAccessMatrix::getCurrent(Value& rValue)
692 {
693     // Starting from row == mnCurRow, get the first row that satisfies all the
694     // query parameters.
695     for ( ;mnCurRow < mnRows; ++mnCurRow)
696     {
697         const ScMatrix& rMat = *mpParam->mpMatrix;
698         if (rMat.IsEmpty(mpParam->mnField, mnCurRow))
699             // Don't take empty values into account.
700             continue;
701 
702         bool bIsStrVal = rMat.IsString(mpParam->mnField, mnCurRow);
703         if (bIsStrVal && mpParam->mbSkipString)
704             continue;
705 
706         if (isValidQuery(mnCurRow, rMat))
707         {
708             rValue.maString = rMat.GetString(mpParam->mnField, mnCurRow);
709             rValue.mfValue = rMat.GetDouble(mpParam->mnField, mnCurRow);
710             rValue.mbIsNumber = !bIsStrVal;
711             rValue.mnError = 0;
712             return true;
713         }
714     }
715     return false;
716 }
717 
718 bool ScDBQueryDataIterator::DataAccessMatrix::getFirst(Value& rValue)
719 {
720     mnCurRow = mpParam->bHasHeader ? 1 : 0;
721     return getCurrent(rValue);
722 }
723 
724 bool ScDBQueryDataIterator::DataAccessMatrix::getNext(Value& rValue)
725 {
726     ++mnCurRow;
727     return getCurrent(rValue);
728 }
729 
730 namespace {
731 
732 bool lcl_isQueryByValue(const ScQueryEntry& rEntry, const ScMatrix& rMat, SCSIZE nCol, SCSIZE nRow)
733 {
734     if (rEntry.bQueryByString)
735         return false;
736 
737     if (!rMat.IsValueOrEmpty(nCol, nRow))
738         return false;
739 
740     return true;
741 }
742 
743 bool lcl_isQueryByString(const ScQueryEntry& rEntry, const ScMatrix& rMat, SCSIZE nCol, SCSIZE nRow)
744 {
745     switch (rEntry.eOp)
746     {
747         case SC_EQUAL:
748         case SC_NOT_EQUAL:
749         case SC_CONTAINS:
750         case SC_DOES_NOT_CONTAIN:
751         case SC_BEGINS_WITH:
752         case SC_ENDS_WITH:
753         case SC_DOES_NOT_BEGIN_WITH:
754         case SC_DOES_NOT_END_WITH:
755             return true;
756         default:
757             ;
758     }
759 
760     if (rEntry.bQueryByString && rMat.IsString(nCol, nRow))
761         return true;
762 
763     return false;
764 }
765 
766 }
767 
768 bool ScDBQueryDataIterator::DataAccessMatrix::isValidQuery(SCROW nRow, const ScMatrix& rMat) const
769 {
770     SCSIZE nEntryCount = mpParam->GetEntryCount();
771     vector<bool> aResults;
772     aResults.reserve(nEntryCount);
773 
774     const CollatorWrapper& rCollator =
775         mpParam->bCaseSens ? *ScGlobal::GetCaseCollator() : *ScGlobal::GetCollator();
776 
777     for (SCSIZE i = 0; i < nEntryCount; ++i)
778     {
779         const ScQueryEntry& rEntry = mpParam->GetEntry(i);
780         if (!rEntry.bDoQuery)
781             continue;
782 
783         switch (rEntry.eOp)
784         {
785             case SC_EQUAL:
786             case SC_LESS:
787             case SC_GREATER:
788             case SC_LESS_EQUAL:
789             case SC_GREATER_EQUAL:
790             case SC_NOT_EQUAL:
791                 break;
792             default:
793                 // Only the above operators are supported.
794                 continue;
795         }
796 
797         bool bValid = false;
798 
799         SCSIZE nField = static_cast<SCSIZE>(rEntry.nField);
800         if (lcl_isQueryByValue(rEntry, rMat, nField, nRow))
801         {
802             // By value
803             double fMatVal = rMat.GetDouble(nField, nRow);
804             bool bEqual = approxEqual(fMatVal, rEntry.nVal);
805             switch (rEntry.eOp)
806             {
807                 case SC_EQUAL:
808                     bValid = bEqual;
809                 break;
810                 case SC_LESS:
811                     bValid = (fMatVal < rEntry.nVal) && !bEqual;
812                 break;
813                 case SC_GREATER:
814                     bValid = (fMatVal > rEntry.nVal) && !bEqual;
815                 break;
816                 case SC_LESS_EQUAL:
817                     bValid = (fMatVal < rEntry.nVal) || bEqual;
818                 break;
819                 case SC_GREATER_EQUAL:
820                     bValid = (fMatVal > rEntry.nVal) || bEqual;
821                 break;
822                 case SC_NOT_EQUAL:
823                     bValid = !bEqual;
824                 break;
825                 default:
826                     ;
827             }
828         }
829         else if (lcl_isQueryByString(rEntry, rMat, nField, nRow))
830         {
831             // By string
832             do
833             {
834                 if (!rEntry.pStr)
835                     break;
836 
837                 // Equality check first.
838 
839                 OUString aMatStr = rMat.GetString(nField, nRow);
840                 lcl_toUpper(aMatStr);
841                 OUString aQueryStr = *rEntry.pStr;
842                 lcl_toUpper(aQueryStr);
843                 bool bDone = false;
844                 switch (rEntry.eOp)
845                 {
846                     case SC_EQUAL:
847                         bValid = aMatStr.equals(aQueryStr);
848                         bDone = true;
849                     break;
850                     case SC_NOT_EQUAL:
851                         bValid = !aMatStr.equals(aQueryStr);
852                         bDone = true;
853                     break;
854                     default:
855                         ;
856                 }
857 
858                 if (bDone)
859                     break;
860 
861                 // Unequality check using collator.
862 
863                 sal_Int32 nCompare = rCollator.compareString(aMatStr, aQueryStr);
864                 switch (rEntry.eOp)
865                 {
866                     case SC_LESS :
867                         bValid = (nCompare < 0);
868                     break;
869                     case SC_GREATER :
870                         bValid = (nCompare > 0);
871                     break;
872                     case SC_LESS_EQUAL :
873                         bValid = (nCompare <= 0);
874                     break;
875                     case SC_GREATER_EQUAL :
876                         bValid = (nCompare >= 0);
877                     break;
878                     default:
879                         ;
880                 }
881             }
882             while (false);
883         }
884         else if (mpParam->bMixedComparison)
885         {
886             // Not used at the moment.
887         }
888 
889         if (aResults.empty())
890             // First query entry.
891             aResults.push_back(bValid);
892         else if (rEntry.eConnect == SC_AND)
893         {
894             // For AND op, tuck the result into the last result value.
895             size_t n = aResults.size();
896             aResults[n-1] = aResults[n-1] && bValid;
897         }
898         else
899             // For OR op, store its own result.
900             aResults.push_back(bValid);
901     }
902 
903     // Row is valid as long as there is at least one result being true.
904     vector<bool>::const_iterator itr = aResults.begin(), itrEnd = aResults.end();
905     for (; itr != itrEnd; ++itr)
906         if (*itr)
907             return true;
908 
909     return false;
910 }
911 
912 // ----------------------------------------------------------------------------
913 
914 ScDBQueryDataIterator::Value::Value() :
915     mnError(0), mbIsNumber(true)
916 {
917     ::rtl::math::setNan(&mfValue);
918 }
919 
920 // ----------------------------------------------------------------------------
921 
922 ScDBQueryDataIterator::ScDBQueryDataIterator(ScDocument* pDocument, ScDBQueryParamBase* pParam) :
923     mpParam (pParam)
924 {
925     switch (mpParam->GetType())
926     {
927         case ScDBQueryParamBase::INTERNAL:
928         {
929             ScDBQueryParamInternal* p = static_cast<ScDBQueryParamInternal*>(pParam);
930             mpData.reset(new DataAccessInternal(this, p, pDocument));
931         }
932         break;
933         case ScDBQueryParamBase::MATRIX:
934         {
935             ScDBQueryParamMatrix* p = static_cast<ScDBQueryParamMatrix*>(pParam);
936             mpData.reset(new DataAccessMatrix(this, p));
937         }
938     }
939 }
940 
941 bool ScDBQueryDataIterator::GetFirst(Value& rValue)
942 {
943     return mpData->getFirst(rValue);
944 }
945 
946 bool ScDBQueryDataIterator::GetNext(Value& rValue)
947 {
948     return mpData->getNext(rValue);
949 }
950 
951 // ============================================================================
952 
953 ScCellIterator::ScCellIterator( ScDocument* pDocument,
954                                 SCCOL nSCol, SCROW nSRow, SCTAB nSTab,
955                                 SCCOL nECol, SCROW nERow, SCTAB nETab, sal_Bool bSTotal ) :
956     pDoc( pDocument ),
957     nStartCol( nSCol),
958     nStartRow( nSRow),
959     nStartTab( nSTab ),
960     nEndCol( nECol ),
961     nEndRow( nERow),
962     nEndTab( nETab ),
963     bSubTotal(bSTotal)
964 
965 {
966     PutInOrder( nStartCol, nEndCol);
967     PutInOrder( nStartRow, nEndRow);
968     PutInOrder( nStartTab, nEndTab );
969 
970     if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
971     if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
972     if (!ValidRow(nStartRow)) nStartRow = MAXROW;
973     if (!ValidRow(nEndRow)) nEndRow = MAXROW;
974     if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
975     if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
976 
977     while (nEndTab>0 && !pDoc->pTab[nEndTab])
978         --nEndTab;                                      // nur benutzte Tabellen
979     if (nStartTab>nEndTab)
980         nStartTab = nEndTab;
981 
982     nCol = nStartCol;
983     nRow = nStartRow;
984     nTab = nStartTab;
985     nColRow = 0;                    // wird bei GetFirst initialisiert
986 
987     if (!pDoc->pTab[nTab])
988     {
989         DBG_ERROR("Tabelle nicht gefunden");
990         nStartCol = nCol = MAXCOL+1;
991         nStartRow = nRow = MAXROW+1;
992         nStartTab = nTab = MAXTAB+1;    // -> Abbruch bei GetFirst
993     }
994 }
995 
996 ScCellIterator::ScCellIterator
997     ( ScDocument* pDocument, const ScRange& rRange, sal_Bool bSTotal ) :
998     pDoc( pDocument ),
999     nStartCol( rRange.aStart.Col() ),
1000     nStartRow( rRange.aStart.Row() ),
1001     nStartTab( rRange.aStart.Tab() ),
1002     nEndCol( rRange.aEnd.Col() ),
1003     nEndRow( rRange.aEnd.Row() ),
1004     nEndTab( rRange.aEnd.Tab() ),
1005     bSubTotal(bSTotal)
1006 
1007 {
1008     PutInOrder( nStartCol, nEndCol);
1009     PutInOrder( nStartRow, nEndRow);
1010     PutInOrder( nStartTab, nEndTab );
1011 
1012     if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
1013     if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
1014     if (!ValidRow(nStartRow)) nStartRow = MAXROW;
1015     if (!ValidRow(nEndRow)) nEndRow = MAXROW;
1016     if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
1017     if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
1018 
1019     while (nEndTab>0 && !pDoc->pTab[nEndTab])
1020         --nEndTab;                                      // nur benutzte Tabellen
1021     if (nStartTab>nEndTab)
1022         nStartTab = nEndTab;
1023 
1024     nCol = nStartCol;
1025     nRow = nStartRow;
1026     nTab = nStartTab;
1027     nColRow = 0;                    // wird bei GetFirst initialisiert
1028 
1029     if (!pDoc->pTab[nTab])
1030     {
1031         DBG_ERROR("Tabelle nicht gefunden");
1032         nStartCol = nCol = MAXCOL+1;
1033         nStartRow = nRow = MAXROW+1;
1034         nStartTab = nTab = MAXTAB+1;    // -> Abbruch bei GetFirst
1035     }
1036 }
1037 
1038 ScBaseCell* ScCellIterator::GetThis()
1039 {
1040     ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1041     for ( ;; )
1042     {
1043         if ( nRow > nEndRow )
1044         {
1045             nRow = nStartRow;
1046             do
1047             {
1048                 nCol++;
1049                 if ( nCol > nEndCol )
1050                 {
1051                     nCol = nStartCol;
1052                     nTab++;
1053                     if ( nTab > nEndTab )
1054                         return NULL;                // Ende und Aus
1055                 }
1056                 pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1057             } while ( pCol->nCount == 0 );
1058             pCol->Search( nRow, nColRow );
1059         }
1060 
1061         while ( (nColRow < pCol->nCount) && (pCol->pItems[nColRow].nRow < nRow) )
1062             nColRow++;
1063 
1064         if ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow <= nEndRow )
1065         {
1066             nRow = pCol->pItems[nColRow].nRow;
1067             if ( !bSubTotal || !pDoc->pTab[nTab]->RowFiltered( nRow ) )
1068             {
1069                 ScBaseCell* pCell = pCol->pItems[nColRow].pCell;
1070 
1071                 if ( bSubTotal && pCell->GetCellType() == CELLTYPE_FORMULA
1072                                 && ((ScFormulaCell*)pCell)->IsSubTotal() )
1073                     nRow++;             // Sub-Total-Zeilen nicht
1074                 else
1075                     return pCell;       // gefunden
1076             }
1077             else
1078                 nRow++;
1079         }
1080         else
1081             nRow = nEndRow + 1; // Naechste Spalte
1082     }
1083 }
1084 
1085 ScBaseCell* ScCellIterator::GetFirst()
1086 {
1087     if ( !ValidTab(nTab) )
1088         return NULL;
1089     nCol = nStartCol;
1090     nRow = nStartRow;
1091     nTab = nStartTab;
1092 //  nColRow = 0;
1093     ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1094     pCol->Search( nRow, nColRow );
1095     return GetThis();
1096 }
1097 
1098 ScBaseCell* ScCellIterator::GetNext()
1099 {
1100     ++nRow;
1101     return GetThis();
1102 }
1103 
1104 //-------------------------------------------------------------------------------
1105 
1106 ScQueryCellIterator::ScQueryCellIterator(ScDocument* pDocument, SCTAB nTable,
1107              const ScQueryParam& rParam, sal_Bool bMod ) :
1108     aParam (rParam),
1109     pDoc( pDocument ),
1110     nTab( nTable),
1111     nStopOnMismatch( nStopOnMismatchDisabled ),
1112     nTestEqualCondition( nTestEqualConditionDisabled ),
1113     bAdvanceQuery( sal_False ),
1114     bIgnoreMismatchOnLeadingStrings( sal_False )
1115 {
1116     nCol = aParam.nCol1;
1117     nRow = aParam.nRow1;
1118     nColRow = 0;                    // wird bei GetFirst initialisiert
1119     SCSIZE i;
1120     if (bMod)                               // sonst schon eingetragen
1121     {
1122         for (i=0; (i<MAXQUERY) && (aParam.GetEntry(i).bDoQuery); i++)
1123         {
1124             ScQueryEntry& rEntry = aParam.GetEntry(i);
1125             sal_uInt32 nIndex = 0;
1126             rEntry.bQueryByString =
1127                      !(pDoc->GetFormatTable()->IsNumberFormat(*rEntry.pStr,
1128                                                               nIndex, rEntry.nVal));
1129         }
1130     }
1131     nNumFormat = 0;                 // werden bei GetNumberFormat initialisiert
1132     pAttrArray = 0;
1133     nAttrEndRow = 0;
1134 }
1135 
1136 ScBaseCell* ScQueryCellIterator::GetThis()
1137 {
1138     ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1139     const ScQueryEntry& rEntry = aParam.GetEntry(0);
1140     SCCOLROW nFirstQueryField = rEntry.nField;
1141     bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings &&
1142         !rEntry.bQueryByString;
1143     bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
1144         !aParam.bHasHeader && rEntry.bQueryByString &&
1145         ((aParam.bByRow && nRow == aParam.nRow1) ||
1146          (!aParam.bByRow && nCol == aParam.nCol1));
1147     for ( ;; )
1148     {
1149         if ( nRow > aParam.nRow2 )
1150         {
1151             nRow = aParam.nRow1;
1152             if (aParam.bHasHeader && aParam.bByRow)
1153                 nRow++;
1154             do
1155             {
1156                 if ( ++nCol > aParam.nCol2 )
1157                     return NULL;                // Ende und Aus
1158                 if ( bAdvanceQuery )
1159                 {
1160                     AdvanceQueryParamEntryField();
1161                     nFirstQueryField = rEntry.nField;
1162                 }
1163                 pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1164             } while ( pCol->nCount == 0 );
1165             pCol->Search( nRow, nColRow );
1166             bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
1167                 !aParam.bHasHeader && rEntry.bQueryByString &&
1168                 aParam.bByRow;
1169         }
1170 
1171         while ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow < nRow )
1172             nColRow++;
1173 
1174         if ( nColRow < pCol->nCount &&
1175                 (nRow = pCol->pItems[nColRow].nRow) <= aParam.nRow2 )
1176         {
1177             ScBaseCell* pCell = pCol->pItems[nColRow].pCell;
1178             if ( pCell->GetCellType() == CELLTYPE_NOTE )
1179                 ++nRow;
1180             else if (bAllStringIgnore && pCell->HasStringData())
1181                 ++nRow;
1182             else
1183             {
1184                 sal_Bool bTestEqualCondition;
1185                 if ( (pDoc->pTab[nTab])->ValidQuery( nRow, aParam, NULL,
1186                         (nCol == static_cast<SCCOL>(nFirstQueryField) ? pCell : NULL),
1187                         (nTestEqualCondition ? &bTestEqualCondition : NULL) ) )
1188                 {
1189                     if ( nTestEqualCondition && bTestEqualCondition )
1190                         nTestEqualCondition |= nTestEqualConditionMatched;
1191                     return pCell;     // found
1192                 }
1193                 else if ( nStopOnMismatch )
1194                 {
1195                     // Yes, even a mismatch may have a fulfilled equal
1196                     // condition if regular expressions were involved and
1197                     // SC_LESS_EQUAL or SC_GREATER_EQUAL were queried.
1198                     if ( nTestEqualCondition && bTestEqualCondition )
1199                     {
1200                         nTestEqualCondition |= nTestEqualConditionMatched;
1201                         nStopOnMismatch |= nStopOnMismatchOccured;
1202                         return NULL;
1203                     }
1204                     bool bStop;
1205                     if (bFirstStringIgnore)
1206                     {
1207                         if (pCell->HasStringData())
1208                         {
1209                             ++nRow;
1210                             bStop = false;
1211                         }
1212                         else
1213                             bStop = true;
1214                     }
1215                     else
1216                         bStop = true;
1217                     if (bStop)
1218                     {
1219                         nStopOnMismatch |= nStopOnMismatchOccured;
1220                         return NULL;
1221                     }
1222                 }
1223                 else
1224                     nRow++;
1225             }
1226         }
1227         else
1228             nRow = aParam.nRow2 + 1; // Naechste Spalte
1229         bFirstStringIgnore = false;
1230     }
1231 }
1232 
1233 ScBaseCell* ScQueryCellIterator::GetFirst()
1234 {
1235     nCol = aParam.nCol1;
1236     nRow = aParam.nRow1;
1237     if (aParam.bHasHeader)
1238         nRow++;
1239 //  nColRow = 0;
1240     ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1241     pCol->Search( nRow, nColRow );
1242     return GetThis();
1243 }
1244 
1245 ScBaseCell* ScQueryCellIterator::GetNext()
1246 {
1247     ++nRow;
1248     if ( nStopOnMismatch )
1249         nStopOnMismatch = nStopOnMismatchEnabled;
1250     if ( nTestEqualCondition )
1251         nTestEqualCondition = nTestEqualConditionEnabled;
1252     return GetThis();
1253 }
1254 
1255 void ScQueryCellIterator::AdvanceQueryParamEntryField()
1256 {
1257     SCSIZE nEntries = aParam.GetEntryCount();
1258     for ( SCSIZE j = 0; j < nEntries; j++  )
1259     {
1260         ScQueryEntry& rEntry = aParam.GetEntry( j );
1261         if ( rEntry.bDoQuery )
1262         {
1263             if ( rEntry.nField < MAXCOL )
1264                 rEntry.nField++;
1265             else
1266             {
1267                 DBG_ERRORFILE( "AdvanceQueryParamEntryField: ++rEntry.nField > MAXCOL" );
1268             }
1269         }
1270         else
1271             break;  // for
1272     }
1273 }
1274 
1275 
1276 sal_Bool ScQueryCellIterator::FindEqualOrSortedLastInRange( SCCOL& nFoundCol,
1277         SCROW& nFoundRow, sal_Bool bSearchForEqualAfterMismatch,
1278         sal_Bool bIgnoreMismatchOnLeadingStringsP )
1279 {
1280     nFoundCol = MAXCOL+1;
1281     nFoundRow = MAXROW+1;
1282     SetStopOnMismatch( sal_True );      // assume sorted keys
1283     SetTestEqualCondition( sal_True );
1284     bIgnoreMismatchOnLeadingStrings = bIgnoreMismatchOnLeadingStringsP;
1285     bool bRegExp = aParam.bRegExp && aParam.GetEntry(0).bQueryByString;
1286     bool bBinary = !bRegExp && aParam.bByRow && (aParam.GetEntry(0).eOp ==
1287             SC_LESS_EQUAL || aParam.GetEntry(0).eOp == SC_GREATER_EQUAL);
1288     if (bBinary ? (BinarySearch() ? GetThis() : 0) : GetFirst())
1289     {
1290         // First equal entry or last smaller than (greater than) entry.
1291         SCSIZE nColRowSave;
1292         ScBaseCell* pNext = 0;
1293         do
1294         {
1295             nFoundCol = GetCol();
1296             nFoundRow = GetRow();
1297             nColRowSave = nColRow;
1298         } while ( !IsEqualConditionFulfilled() && (pNext = GetNext()) != NULL );
1299         // There may be no pNext but equal condition fulfilled if regular
1300         // expressions are involved. Keep the found entry and proceed.
1301         if (!pNext && !IsEqualConditionFulfilled())
1302         {
1303             // Step back to last in range and adjust position markers for
1304             // GetNumberFormat() or similar.
1305             nCol = nFoundCol;
1306             nRow = nFoundRow;
1307             nColRow = nColRowSave;
1308         }
1309     }
1310     if ( IsEqualConditionFulfilled() )
1311     {
1312         // Position on last equal entry.
1313         SCSIZE nEntries = aParam.GetEntryCount();
1314         for ( SCSIZE j = 0; j < nEntries; j++  )
1315         {
1316             ScQueryEntry& rEntry = aParam.GetEntry( j );
1317             if ( rEntry.bDoQuery )
1318             {
1319                 switch ( rEntry.eOp )
1320                 {
1321                     case SC_LESS_EQUAL :
1322                     case SC_GREATER_EQUAL :
1323                         rEntry.eOp = SC_EQUAL;
1324                     break;
1325                     default:
1326                     {
1327                         // added to avoid warnings
1328                     }
1329                 }
1330             }
1331             else
1332                 break;  // for
1333         }
1334         SCSIZE nColRowSave;
1335         bIgnoreMismatchOnLeadingStrings = sal_False;
1336         SetTestEqualCondition( sal_False );
1337         do
1338         {
1339             nFoundCol = GetCol();
1340             nFoundRow = GetRow();
1341             nColRowSave = nColRow;
1342         } while (GetNext());
1343         // Step back conditions same as above
1344         nCol = nFoundCol;
1345         nRow = nFoundRow;
1346         nColRow = nColRowSave;
1347         return sal_True;
1348     }
1349     if ( (bSearchForEqualAfterMismatch || aParam.bRegExp) &&
1350             StoppedOnMismatch() )
1351     {
1352         // Assume found entry to be the last value less than respectively
1353         // greater than the query. But keep on searching for an equal match.
1354         SCSIZE nEntries = aParam.GetEntryCount();
1355         for ( SCSIZE j = 0; j < nEntries; j++  )
1356         {
1357             ScQueryEntry& rEntry = aParam.GetEntry( j );
1358             if ( rEntry.bDoQuery )
1359             {
1360                 switch ( rEntry.eOp )
1361                 {
1362                     case SC_LESS_EQUAL :
1363                     case SC_GREATER_EQUAL :
1364                         rEntry.eOp = SC_EQUAL;
1365                     break;
1366                     default:
1367                     {
1368                         // added to avoid warnings
1369                     }
1370                 }
1371             }
1372             else
1373                 break;  // for
1374         }
1375         SetStopOnMismatch( sal_False );
1376         SetTestEqualCondition( sal_False );
1377         if (GetNext())
1378         {
1379             // Last of a consecutive area, avoid searching the entire parameter
1380             // range as it is a real performance bottleneck in case of regular
1381             // expressions.
1382             SCSIZE nColRowSave;
1383             do
1384             {
1385                 nFoundCol = GetCol();
1386                 nFoundRow = GetRow();
1387                 nColRowSave = nColRow;
1388                 SetStopOnMismatch( sal_True );
1389             } while (GetNext());
1390             nCol = nFoundCol;
1391             nRow = nFoundRow;
1392             nColRow = nColRowSave;
1393         }
1394     }
1395     return (nFoundCol <= MAXCOL) && (nFoundRow <= MAXROW);
1396 }
1397 
1398 
1399 ScBaseCell* ScQueryCellIterator::BinarySearch()
1400 {
1401     nCol = aParam.nCol1;
1402     ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1403     if (!pCol->nCount)
1404         return 0;
1405 
1406     ScBaseCell* pCell;
1407     SCSIZE nHi, nLo;
1408     CollatorWrapper* pCollator = (aParam.bCaseSens ? ScGlobal::GetCaseCollator() :
1409         ScGlobal::GetCollator());
1410     SvNumberFormatter& rFormatter = *(pDoc->GetFormatTable());
1411     const ScQueryEntry& rEntry = aParam.GetEntry(0);
1412     bool bLessEqual = rEntry.eOp == SC_LESS_EQUAL;
1413     bool bByString = rEntry.bQueryByString;
1414     bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings && !bByString;
1415     bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
1416         !aParam.bHasHeader && bByString;
1417 
1418     nRow = aParam.nRow1;
1419     if (aParam.bHasHeader)
1420         nRow++;
1421     const ColEntry* pItems = pCol->pItems;
1422     if (pCol->Search( nRow, nLo ) && bFirstStringIgnore &&
1423             pItems[nLo].pCell->HasStringData())
1424     {
1425         String aCellStr;
1426         sal_uLong nFormat = pCol->GetNumberFormat( pItems[nLo].nRow);
1427         ScCellFormat::GetInputString( pItems[nLo].pCell, nFormat, aCellStr,
1428                 rFormatter);
1429         sal_Int32 nTmp = pCollator->compareString( aCellStr, *rEntry.pStr);
1430         if ((rEntry.eOp == SC_LESS_EQUAL && nTmp > 0) ||
1431                 (rEntry.eOp == SC_GREATER_EQUAL && nTmp < 0) ||
1432                 (rEntry.eOp == SC_EQUAL && nTmp != 0))
1433             ++nLo;
1434     }
1435     if (!pCol->Search( aParam.nRow2, nHi ) && nHi>0)
1436         --nHi;
1437     while (bAllStringIgnore && nLo <= nHi && nLo < pCol->nCount &&
1438             pItems[nLo].pCell->HasStringData())
1439         ++nLo;
1440 
1441     // Bookkeeping values for breaking up the binary search in case the data
1442     // range isn't strictly sorted.
1443     SCSIZE nLastInRange = nLo;
1444     SCSIZE nFirstLastInRange = nLastInRange;
1445     double fLastInRangeValue = bLessEqual ?
1446         -(::std::numeric_limits<double>::max()) :
1447             ::std::numeric_limits<double>::max();
1448     String aLastInRangeString;
1449     if (!bLessEqual)
1450         aLastInRangeString.Assign( sal_Unicode(0xFFFF));
1451     if (nLastInRange < pCol->nCount)
1452     {
1453         pCell = pItems[nLastInRange].pCell;
1454         if (pCell->HasStringData())
1455         {
1456             sal_uLong nFormat = pCol->GetNumberFormat( pItems[nLastInRange].nRow);
1457             ScCellFormat::GetInputString( pCell, nFormat, aLastInRangeString,
1458                     rFormatter);
1459         }
1460         else
1461         {
1462             switch ( pCell->GetCellType() )
1463             {
1464                 case CELLTYPE_VALUE :
1465                     fLastInRangeValue =
1466                         static_cast<ScValueCell*>(pCell)->GetValue();
1467                     break;
1468                 case CELLTYPE_FORMULA :
1469                     fLastInRangeValue =
1470                         static_cast<ScFormulaCell*>(pCell)->GetValue();
1471                     break;
1472                 default:
1473                 {
1474                     // added to avoid warnings
1475                 }
1476             }
1477         }
1478     }
1479 
1480     sal_Int32 nRes = 0;
1481     bool bFound = false;
1482     bool bDone = false;
1483     while (nLo <= nHi && !bDone)
1484     {
1485         SCSIZE nMid = (nLo+nHi)/2;
1486         SCSIZE i = nMid;
1487         while (i <= nHi && pItems[i].pCell->GetCellType() == CELLTYPE_NOTE)
1488             ++i;
1489         if (i > nHi)
1490         {
1491             if (nMid > 0)
1492                 nHi = nMid - 1;
1493             else
1494                 bDone = true;
1495             continue;   // while
1496         }
1497         sal_Bool bStr = pItems[i].pCell->HasStringData();
1498         nRes = 0;
1499         // compares are content<query:-1, content>query:1
1500         // Cell value comparison similar to ScTable::ValidQuery()
1501         if (!bStr && !bByString)
1502         {
1503             double nCellVal;
1504             pCell = pItems[i].pCell;
1505             switch ( pCell->GetCellType() )
1506             {
1507                 case CELLTYPE_VALUE :
1508                     nCellVal = static_cast<ScValueCell*>(pCell)->GetValue();
1509                     break;
1510                 case CELLTYPE_FORMULA :
1511                     nCellVal = static_cast<ScFormulaCell*>(pCell)->GetValue();
1512                     break;
1513                 default:
1514                     nCellVal = 0.0;
1515             }
1516             if ((nCellVal < rEntry.nVal) && !::rtl::math::approxEqual(
1517                         nCellVal, rEntry.nVal))
1518             {
1519                 nRes = -1;
1520                 if (bLessEqual)
1521                 {
1522                     if (fLastInRangeValue < nCellVal)
1523                     {
1524                         fLastInRangeValue = nCellVal;
1525                         nLastInRange = i;
1526                     }
1527                     else if (fLastInRangeValue > nCellVal)
1528                     {
1529                         // not strictly sorted, continue with GetThis()
1530                         nLastInRange = nFirstLastInRange;
1531                         bDone = true;
1532                     }
1533                 }
1534             }
1535             else if ((nCellVal > rEntry.nVal) && !::rtl::math::approxEqual(
1536                         nCellVal, rEntry.nVal))
1537             {
1538                 nRes = 1;
1539                 if (!bLessEqual)
1540                 {
1541                     if (fLastInRangeValue > nCellVal)
1542                     {
1543                         fLastInRangeValue = nCellVal;
1544                         nLastInRange = i;
1545                     }
1546                     else if (fLastInRangeValue < nCellVal)
1547                     {
1548                         // not strictly sorted, continue with GetThis()
1549                         nLastInRange = nFirstLastInRange;
1550                         bDone = true;
1551                     }
1552                 }
1553             }
1554         }
1555         else if (bStr && bByString)
1556         {
1557             String aCellStr;
1558             sal_uLong nFormat = pCol->GetNumberFormat( pItems[i].nRow);
1559             ScCellFormat::GetInputString( pItems[i].pCell, nFormat, aCellStr,
1560                     rFormatter);
1561             nRes = pCollator->compareString( aCellStr, *rEntry.pStr);
1562             if (nRes < 0 && bLessEqual)
1563             {
1564                 sal_Int32 nTmp = pCollator->compareString( aLastInRangeString,
1565                         aCellStr);
1566                 if (nTmp < 0)
1567                 {
1568                     aLastInRangeString = aCellStr;
1569                     nLastInRange = i;
1570                 }
1571                 else if (nTmp > 0)
1572                 {
1573                     // not strictly sorted, continue with GetThis()
1574                     nLastInRange = nFirstLastInRange;
1575                     bDone = true;
1576                 }
1577             }
1578             else if (nRes > 0 && !bLessEqual)
1579             {
1580                 sal_Int32 nTmp = pCollator->compareString( aLastInRangeString,
1581                         aCellStr);
1582                 if (nTmp > 0)
1583                 {
1584                     aLastInRangeString = aCellStr;
1585                     nLastInRange = i;
1586                 }
1587                 else if (nTmp < 0)
1588                 {
1589                     // not strictly sorted, continue with GetThis()
1590                     nLastInRange = nFirstLastInRange;
1591                     bDone = true;
1592                 }
1593             }
1594         }
1595         else if (!bStr && bByString)
1596         {
1597             nRes = -1;  // numeric < string
1598             if (bLessEqual)
1599                 nLastInRange = i;
1600         }
1601         else // if (bStr && !bByString)
1602         {
1603             nRes = 1;   // string > numeric
1604             if (!bLessEqual)
1605                 nLastInRange = i;
1606         }
1607         if (nRes < 0)
1608         {
1609             if (bLessEqual)
1610                 nLo = nMid + 1;
1611             else    // assumed to be SC_GREATER_EQUAL
1612             {
1613                 if (nMid > 0)
1614                     nHi = nMid - 1;
1615                 else
1616                     bDone = true;
1617             }
1618         }
1619         else if (nRes > 0)
1620         {
1621             if (bLessEqual)
1622             {
1623                 if (nMid > 0)
1624                     nHi = nMid - 1;
1625                 else
1626                     bDone = true;
1627             }
1628             else    // assumed to be SC_GREATER_EQUAL
1629                 nLo = nMid + 1;
1630         }
1631         else
1632         {
1633             nLo = i;
1634             bDone = bFound = true;
1635         }
1636     }
1637     if (!bFound)
1638     {
1639         // If all hits didn't result in a moving limit there's something
1640         // strange, e.g. data range not properly sorted, or only identical
1641         // values encountered, which doesn't mean there aren't any others in
1642         // between.. leave it to GetThis(). The condition for this would be
1643         // if (nLastInRange == nFirstLastInRange) nLo = nFirstLastInRange;
1644         // Else, in case no exact match was found, we step back for a
1645         // subsequent GetThis() to find the last in range. Effectively this is
1646         // --nLo with nLastInRange == nLo-1. Both conditions combined yield:
1647         nLo = nLastInRange;
1648     }
1649     if (nLo < pCol->nCount && pCol->pItems[nLo].nRow <= aParam.nRow2)
1650     {
1651         nRow = pItems[nLo].nRow;
1652         pCell = pItems[nLo].pCell;
1653         nColRow = nLo;
1654     }
1655     else
1656     {
1657         nRow = aParam.nRow2 + 1;
1658         pCell = 0;
1659         nColRow = pCol->nCount - 1;
1660     }
1661     return pCell;
1662 }
1663 
1664 
1665 //-------------------------------------------------------------------------------
1666 
1667 ScHorizontalCellIterator::ScHorizontalCellIterator(ScDocument* pDocument, SCTAB nTable,
1668                                     SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
1669     pDoc( pDocument ),
1670     nTab( nTable ),
1671     nStartCol( nCol1 ),
1672     nEndCol( nCol2 ),
1673     nStartRow( nRow1 ),
1674     nEndRow( nRow2 ),
1675     nCol( nCol1 ),
1676     nRow( nRow1 ),
1677     bMore( sal_True )
1678 {
1679 
1680     pNextRows = new SCROW[ nCol2-nCol1+1 ];
1681     pNextIndices = new SCSIZE[ nCol2-nCol1+1 ];
1682 
1683     SetTab( nTab );
1684 }
1685 
1686 ScHorizontalCellIterator::~ScHorizontalCellIterator()
1687 {
1688     delete [] pNextRows;
1689     delete [] pNextIndices;
1690 }
1691 
1692 void ScHorizontalCellIterator::SetTab( SCTAB nTabP )
1693 {
1694     nTab = nTabP;
1695     nRow = nStartRow;
1696     nCol = nStartCol;
1697     bMore = sal_True;
1698 
1699     for (SCCOL i=nStartCol; i<=nEndCol; i++)
1700     {
1701         ScColumn* pCol = &pDoc->pTab[nTab]->aCol[i];
1702 
1703         SCSIZE nIndex;
1704         pCol->Search( nStartRow, nIndex );
1705         if ( nIndex < pCol->nCount )
1706         {
1707             pNextRows[i-nStartCol] = pCol->pItems[nIndex].nRow;
1708             pNextIndices[i-nStartCol] = nIndex;
1709         }
1710         else
1711         {
1712             pNextRows[i-nStartCol] = MAXROWCOUNT;       // nichts gefunden
1713             pNextIndices[i-nStartCol] = MAXROWCOUNT;
1714         }
1715     }
1716 
1717     if (pNextRows[0] != nStartRow)
1718         Advance();
1719 }
1720 
1721 ScBaseCell* ScHorizontalCellIterator::GetNext( SCCOL& rCol, SCROW& rRow )
1722 {
1723     if ( bMore )
1724     {
1725         rCol = nCol;
1726         rRow = nRow;
1727 
1728         ScColumn* pCol = &pDoc->pTab[nTab]->aCol[nCol];
1729         SCSIZE nIndex = pNextIndices[nCol-nStartCol];
1730         DBG_ASSERT( nIndex < pCol->nCount, "ScHorizontalCellIterator::GetNext: nIndex out of range" );
1731         ScBaseCell* pCell = pCol->pItems[nIndex].pCell;
1732         if ( ++nIndex < pCol->nCount )
1733         {
1734             pNextRows[nCol-nStartCol] = pCol->pItems[nIndex].nRow;
1735             pNextIndices[nCol-nStartCol] = nIndex;
1736         }
1737         else
1738         {
1739             pNextRows[nCol-nStartCol] = MAXROWCOUNT;        // nichts gefunden
1740             pNextIndices[nCol-nStartCol] = MAXROWCOUNT;
1741         }
1742 
1743         Advance();
1744         return pCell;
1745     }
1746     else
1747         return NULL;
1748 }
1749 
1750 sal_Bool ScHorizontalCellIterator::ReturnNext( SCCOL& rCol, SCROW& rRow )
1751 {
1752     rCol = nCol;
1753     rRow = nRow;
1754     return bMore;
1755 }
1756 
1757 void ScHorizontalCellIterator::Advance()
1758 {
1759     sal_Bool bFound = sal_False;
1760     SCCOL i;
1761 
1762     for (i=nCol+1; i<=nEndCol && !bFound; i++)
1763         if (pNextRows[i-nStartCol] == nRow)
1764         {
1765             nCol = i;
1766             bFound = sal_True;
1767         }
1768 
1769     if (!bFound)
1770     {
1771         SCROW nMinRow = MAXROW+1;
1772         for (i=nStartCol; i<=nEndCol; i++)
1773             if (pNextRows[i-nStartCol] < nMinRow)
1774             {
1775                 nCol = i;
1776                 nMinRow = pNextRows[i-nStartCol];
1777             }
1778 
1779         if (nMinRow <= nEndRow)
1780         {
1781             nRow = nMinRow;
1782             bFound = sal_True;
1783         }
1784     }
1785 
1786     if ( !bFound )
1787         bMore = sal_False;
1788 }
1789 
1790 //------------------------------------------------------------------------
1791 
1792 ScHorizontalValueIterator::ScHorizontalValueIterator( ScDocument* pDocument,
1793         const ScRange& rRange, bool bSTotal, bool bTextZero ) :
1794     pDoc( pDocument ),
1795     nNumFmtIndex(0),
1796     nEndTab( rRange.aEnd.Tab() ),
1797     nNumFmtType( NUMBERFORMAT_UNDEFINED ),
1798     bNumValid( false ),
1799     bSubTotal( bSTotal ),
1800     bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ),
1801     bTextAsZero( bTextZero )
1802 {
1803     SCCOL nStartCol = rRange.aStart.Col();
1804     SCROW nStartRow = rRange.aStart.Row();
1805     SCTAB nStartTab = rRange.aStart.Tab();
1806     SCCOL nEndCol = rRange.aEnd.Col();
1807     SCROW nEndRow = rRange.aEnd.Row();
1808     PutInOrder( nStartCol, nEndCol);
1809     PutInOrder( nStartRow, nEndRow);
1810     PutInOrder( nStartTab, nEndTab );
1811 
1812     if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
1813     if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
1814     if (!ValidRow(nStartRow)) nStartRow = MAXROW;
1815     if (!ValidRow(nEndRow)) nEndRow = MAXROW;
1816     if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
1817     if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
1818 
1819     nCurCol = nStartCol;
1820     nCurRow = nStartRow;
1821     nCurTab = nStartTab;
1822 
1823     nNumFormat = 0;                 // will be initialized in GetNumberFormat()
1824     pAttrArray = 0;
1825     nAttrEndRow = 0;
1826 
1827     pCellIter = new ScHorizontalCellIterator( pDoc, nStartTab, nStartCol,
1828             nStartRow, nEndCol, nEndRow );
1829 }
1830 
1831 ScHorizontalValueIterator::~ScHorizontalValueIterator()
1832 {
1833     delete pCellIter;
1834 }
1835 
1836 bool ScHorizontalValueIterator::GetNext( double& rValue, sal_uInt16& rErr )
1837 {
1838     bool bFound = false;
1839     while ( !bFound )
1840     {
1841         ScBaseCell* pCell = pCellIter->GetNext( nCurCol, nCurRow );
1842         while ( !pCell )
1843         {
1844             if ( nCurTab < nEndTab )
1845             {
1846                 pCellIter->SetTab( ++nCurTab);
1847                 pCell = pCellIter->GetNext( nCurCol, nCurRow );
1848             }
1849             else
1850                 return false;
1851         }
1852         if ( !bSubTotal || !pDoc->pTab[nCurTab]->RowFiltered( nCurRow ) )
1853         {
1854             switch (pCell->GetCellType())
1855             {
1856                 case CELLTYPE_VALUE:
1857                     {
1858                         bNumValid = false;
1859                         rValue = ((ScValueCell*)pCell)->GetValue();
1860                         rErr = 0;
1861                         if ( bCalcAsShown )
1862                         {
1863                             ScColumn* pCol = &pDoc->pTab[nCurTab]->aCol[nCurCol];
1864                             lcl_IterGetNumberFormat( nNumFormat, pAttrArray,
1865                                     nAttrEndRow, pCol->pAttrArray, nCurRow, pDoc );
1866                             rValue = pDoc->RoundValueAsShown( rValue, nNumFormat );
1867                         }
1868                         bFound = true;
1869                     }
1870                     break;
1871                 case CELLTYPE_FORMULA:
1872                     {
1873                         if (!bSubTotal || !((ScFormulaCell*)pCell)->IsSubTotal())
1874                         {
1875                             rErr = ((ScFormulaCell*)pCell)->GetErrCode();
1876                             if ( rErr || ((ScFormulaCell*)pCell)->IsValue() )
1877                             {
1878                                 rValue = ((ScFormulaCell*)pCell)->GetValue();
1879                                 bNumValid = false;
1880                                 bFound = true;
1881                             }
1882                             else if ( bTextAsZero )
1883                             {
1884                                 rValue = 0.0;
1885                                 bNumValid = false;
1886                                 bFound = true;
1887                             }
1888                         }
1889                     }
1890                     break;
1891                 case CELLTYPE_STRING :
1892                 case CELLTYPE_EDIT :
1893                     {
1894                         if ( bTextAsZero )
1895                         {
1896                             rErr = 0;
1897                             rValue = 0.0;
1898                             nNumFmtType = NUMBERFORMAT_NUMBER;
1899                             nNumFmtIndex = 0;
1900                             bNumValid = true;
1901                             bFound = true;
1902                         }
1903                     }
1904                     break;
1905                 default:
1906                     ;   // nothing
1907             }
1908         }
1909     }
1910     return bFound;
1911 }
1912 
1913 void ScHorizontalValueIterator::GetCurNumFmtInfo( short& nType, sal_uLong& nIndex )
1914 {
1915     if (!bNumValid)
1916     {
1917         const ScColumn* pCol = &(pDoc->pTab[nCurTab])->aCol[nCurCol];
1918         nNumFmtIndex = pCol->GetNumberFormat( nCurRow );
1919         if ( (nNumFmtIndex % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
1920         {
1921             const ScBaseCell* pCell;
1922             SCSIZE nCurIndex;
1923             if ( pCol->Search( nCurRow, nCurIndex ) )
1924                 pCell = pCol->pItems[nCurIndex].pCell;
1925             else
1926                 pCell = NULL;
1927             if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA )
1928                 ((const ScFormulaCell*)pCell)->GetFormatInfo( nNumFmtType, nNumFmtIndex );
1929             else
1930                 nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex );
1931         }
1932         else
1933             nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex );
1934         bNumValid = true;
1935     }
1936     nType = nNumFmtType;
1937     nIndex = nNumFmtIndex;
1938 }
1939 
1940 //-------------------------------------------------------------------------------
1941 
1942 ScHorizontalAttrIterator::ScHorizontalAttrIterator( ScDocument* pDocument, SCTAB nTable,
1943                             SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
1944     pDoc( pDocument ),
1945     nTab( nTable ),
1946     nStartCol( nCol1 ),
1947     nStartRow( nRow1 ),
1948     nEndCol( nCol2 ),
1949     nEndRow( nRow2 )
1950 {
1951     DBG_ASSERT( pDoc->pTab[nTab], "Tabelle nicht da" );
1952 
1953     SCCOL i;
1954 
1955     nRow = nStartRow;
1956     nCol = nStartCol;
1957     bRowEmpty = sal_False;
1958 
1959     pIndices    = new SCSIZE[nEndCol-nStartCol+1];
1960     pNextEnd    = new SCROW[nEndCol-nStartCol+1];
1961     ppPatterns  = new const ScPatternAttr*[nEndCol-nStartCol+1];
1962 
1963     SCROW nSkipTo = MAXROW;
1964     sal_Bool bEmpty = sal_True;
1965     for (i=nStartCol; i<=nEndCol; i++)
1966     {
1967         SCCOL nPos = i - nStartCol;
1968         ScAttrArray* pArray = pDoc->pTab[nTab]->aCol[i].pAttrArray;
1969         DBG_ASSERT( pArray, "pArray == 0" );
1970 
1971         SCSIZE nIndex;
1972         pArray->Search( nStartRow, nIndex );
1973 
1974         const ScPatternAttr* pPattern = pArray->pData[nIndex].pPattern;
1975         SCROW nThisEnd = pArray->pData[nIndex].nRow;
1976         if ( IsDefaultItem( pPattern ) )
1977         {
1978             pPattern = NULL;
1979             if ( nThisEnd < nSkipTo )
1980                 nSkipTo = nThisEnd;         // nSkipTo kann gleich hier gesetzt werden
1981         }
1982         else
1983             bEmpty = sal_False;                 // Attribute gefunden
1984 
1985         pIndices[nPos] = nIndex;
1986         pNextEnd[nPos] = nThisEnd;
1987         ppPatterns[nPos] = pPattern;
1988     }
1989 
1990     if (bEmpty)
1991         nRow = nSkipTo;                     // bis zum naechsten Bereichsende ueberspringen
1992     bRowEmpty = bEmpty;
1993 }
1994 
1995 ScHorizontalAttrIterator::~ScHorizontalAttrIterator()
1996 {
1997     delete[] (ScPatternAttr**)ppPatterns;
1998     delete[] pNextEnd;
1999     delete[] pIndices;
2000 }
2001 
2002 const ScPatternAttr* ScHorizontalAttrIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2, SCROW& rRow )
2003 {
2004     for (;;)
2005     {
2006         if (!bRowEmpty)
2007         {
2008             // in dieser Zeile suchen
2009 
2010             while ( nCol <= nEndCol && !ppPatterns[nCol-nStartCol] )
2011                 ++nCol;
2012 
2013             if ( nCol <= nEndCol )
2014             {
2015                 const ScPatternAttr* pPat = ppPatterns[nCol-nStartCol];
2016                 rRow = nRow;
2017                 rCol1 = nCol;
2018                 while ( nCol < nEndCol && ppPatterns[nCol+1-nStartCol] == pPat )
2019                     ++nCol;
2020                 rCol2 = nCol;
2021                 ++nCol;                 // hochzaehlen fuer naechsten Aufruf
2022                 return pPat;            // gefunden
2023             }
2024         }
2025 
2026         // naechste Zeile
2027 
2028         ++nRow;
2029         if ( nRow > nEndRow )       // schon am Ende?
2030             return NULL;            // nichts gefunden
2031 
2032         sal_Bool bEmpty = sal_True;
2033         SCCOL i;
2034 
2035         for ( i = nStartCol; i <= nEndCol; i++)
2036         {
2037             SCCOL nPos = i-nStartCol;
2038             if ( pNextEnd[nPos] < nRow )
2039             {
2040                 ScAttrArray* pArray = pDoc->pTab[nTab]->aCol[i].pAttrArray;
2041 
2042                 SCSIZE nIndex = ++pIndices[nPos];
2043                 if ( nIndex < pArray->nCount )
2044                 {
2045                     const ScPatternAttr* pPattern = pArray->pData[nIndex].pPattern;
2046                     SCROW nThisEnd = pArray->pData[nIndex].nRow;
2047                     if ( IsDefaultItem( pPattern ) )
2048                         pPattern = NULL;
2049                     else
2050                         bEmpty = sal_False;                 // Attribute gefunden
2051 
2052                     pNextEnd[nPos] = nThisEnd;
2053                     ppPatterns[nPos] = pPattern;
2054 
2055                     DBG_ASSERT( pNextEnd[nPos] >= nRow, "Reihenfolge durcheinander" );
2056                 }
2057                 else
2058                 {
2059                     DBG_ERROR("AttrArray reicht nicht bis MAXROW");
2060                     pNextEnd[nPos] = MAXROW;
2061                     ppPatterns[nPos] = NULL;
2062                 }
2063             }
2064             else if ( ppPatterns[nPos] )
2065                 bEmpty = sal_False;                         // Bereich noch nicht zuende
2066         }
2067 
2068         if (bEmpty)
2069         {
2070             SCCOL nCount = nEndCol-nStartCol+1;
2071             SCROW nSkipTo = pNextEnd[0];                // naechstes Bereichsende suchen
2072             for (i=1; i<nCount; i++)
2073                 if ( pNextEnd[i] < nSkipTo )
2074                     nSkipTo = pNextEnd[i];
2075             nRow = nSkipTo;                             // leere Zeilen ueberspringen
2076         }
2077         bRowEmpty = bEmpty;
2078         nCol = nStartCol;           // wieder links anfangen
2079     }
2080 
2081 //    return NULL;
2082 }
2083 
2084 //-------------------------------------------------------------------------------
2085 
2086 inline sal_Bool IsGreater( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
2087 {
2088     return ( nRow1 > nRow2 ) || ( nRow1 == nRow2 && nCol1 > nCol2 );
2089 }
2090 
2091 ScUsedAreaIterator::ScUsedAreaIterator( ScDocument* pDocument, SCTAB nTable,
2092                             SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
2093     aCellIter( pDocument, nTable, nCol1, nRow1, nCol2, nRow2 ),
2094     aAttrIter( pDocument, nTable, nCol1, nRow1, nCol2, nRow2 ),
2095     nNextCol( nCol1 ),
2096     nNextRow( nRow1 )
2097 {
2098     pCell    = aCellIter.GetNext( nCellCol, nCellRow );
2099     pPattern = aAttrIter.GetNext( nAttrCol1, nAttrCol2, nAttrRow );
2100 }
2101 
2102 ScUsedAreaIterator::~ScUsedAreaIterator()
2103 {
2104 }
2105 
2106 sal_Bool ScUsedAreaIterator::GetNext()
2107 {
2108     //  Iteratoren weiterzaehlen
2109 
2110     if ( pCell && IsGreater( nNextCol, nNextRow, nCellCol, nCellRow ) )
2111         pCell = aCellIter.GetNext( nCellCol, nCellRow );
2112 
2113     while ( pCell && pCell->IsBlank() )
2114         pCell = aCellIter.GetNext( nCellCol, nCellRow );
2115 
2116     if ( pPattern && IsGreater( nNextCol, nNextRow, nAttrCol2, nAttrRow ) )
2117         pPattern = aAttrIter.GetNext( nAttrCol1, nAttrCol2, nAttrRow );
2118 
2119     if ( pPattern && nAttrRow == nNextRow && nAttrCol1 < nNextCol )
2120         nAttrCol1 = nNextCol;
2121 
2122     //  naechsten Abschnitt heraussuchen
2123 
2124     sal_Bool bFound = sal_True;
2125     sal_Bool bUseCell = sal_False;
2126 
2127     if ( pCell && pPattern )
2128     {
2129         if ( IsGreater( nCellCol, nCellRow, nAttrCol1, nAttrRow ) )     // vorne nur Attribute ?
2130         {
2131             pFoundCell = NULL;
2132             pFoundPattern = pPattern;
2133             nFoundRow = nAttrRow;
2134             nFoundStartCol = nAttrCol1;
2135             if ( nCellRow == nAttrRow && nCellCol <= nAttrCol2 )        // auch Zelle im Bereich ?
2136                 nFoundEndCol = nCellCol - 1;                            // nur bis vor der Zelle
2137             else
2138                 nFoundEndCol = nAttrCol2;                               // alles
2139         }
2140         else
2141         {
2142             bUseCell = sal_True;
2143             if ( nAttrRow == nCellRow && nAttrCol1 == nCellCol )        // Attribute auf der Zelle ?
2144                 pFoundPattern = pPattern;
2145             else
2146                 pFoundPattern = NULL;
2147         }
2148     }
2149     else if ( pCell )                   // nur Zelle -> direkt uebernehmen
2150     {
2151         pFoundPattern = NULL;
2152         bUseCell = sal_True;                // Position von Zelle
2153     }
2154     else if ( pPattern )                // nur Attribute -> direkt uebernehmen
2155     {
2156         pFoundCell = NULL;
2157         pFoundPattern = pPattern;
2158         nFoundRow = nAttrRow;
2159         nFoundStartCol = nAttrCol1;
2160         nFoundEndCol = nAttrCol2;
2161     }
2162     else                                // gar nichts
2163         bFound = sal_False;
2164 
2165     if ( bUseCell )                     // Position von Zelle
2166     {
2167         pFoundCell = pCell;
2168         nFoundRow = nCellRow;
2169         nFoundStartCol = nFoundEndCol = nCellCol;
2170     }
2171 
2172     if (bFound)
2173     {
2174         nNextRow = nFoundRow;
2175         nNextCol = nFoundEndCol + 1;
2176     }
2177 
2178     return bFound;
2179 }
2180 
2181 //-------------------------------------------------------------------------------
2182 
2183 ScDocAttrIterator::ScDocAttrIterator(ScDocument* pDocument, SCTAB nTable,
2184                                     SCCOL nCol1, SCROW nRow1,
2185                                     SCCOL nCol2, SCROW nRow2) :
2186     pDoc( pDocument ),
2187     nTab( nTable ),
2188     nEndCol( nCol2 ),
2189     nStartRow( nRow1 ),
2190     nEndRow( nRow2 ),
2191     nCol( nCol1 )
2192 {
2193     if ( ValidTab(nTab) && pDoc->pTab[nTab] )
2194         pColIter = pDoc->pTab[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow );
2195     else
2196         pColIter = NULL;
2197 }
2198 
2199 ScDocAttrIterator::~ScDocAttrIterator()
2200 {
2201     delete pColIter;
2202 }
2203 
2204 const ScPatternAttr* ScDocAttrIterator::GetNext( SCCOL& rCol, SCROW& rRow1, SCROW& rRow2 )
2205 {
2206     while ( pColIter )
2207     {
2208         const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 );
2209         if ( pPattern )
2210         {
2211             rCol = nCol;
2212             return pPattern;
2213         }
2214 
2215         delete pColIter;
2216         ++nCol;
2217         if ( nCol <= nEndCol )
2218             pColIter = pDoc->pTab[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow );
2219         else
2220             pColIter = NULL;
2221     }
2222     return NULL;        // is nix mehr
2223 }
2224 
2225 //-------------------------------------------------------------------------------
2226 
2227 ScAttrRectIterator::ScAttrRectIterator(ScDocument* pDocument, SCTAB nTable,
2228                                     SCCOL nCol1, SCROW nRow1,
2229                                     SCCOL nCol2, SCROW nRow2) :
2230     pDoc( pDocument ),
2231     nTab( nTable ),
2232     nEndCol( nCol2 ),
2233     nStartRow( nRow1 ),
2234     nEndRow( nRow2 ),
2235     nIterStartCol( nCol1 ),
2236     nIterEndCol( nCol1 )
2237 {
2238     if ( ValidTab(nTab) && pDoc->pTab[nTab] )
2239     {
2240         pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow );
2241         while ( nIterEndCol < nEndCol &&
2242                 pDoc->pTab[nTab]->aCol[nIterEndCol].IsAllAttrEqual(
2243                     pDoc->pTab[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) )
2244             ++nIterEndCol;
2245     }
2246     else
2247         pColIter = NULL;
2248 }
2249 
2250 ScAttrRectIterator::~ScAttrRectIterator()
2251 {
2252     delete pColIter;
2253 }
2254 
2255 void ScAttrRectIterator::DataChanged()
2256 {
2257     if (pColIter)
2258     {
2259         SCROW nNextRow = pColIter->GetNextRow();
2260         delete pColIter;
2261         pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nNextRow, nEndRow );
2262     }
2263 }
2264 
2265 const ScPatternAttr* ScAttrRectIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2,
2266                                                     SCROW& rRow1, SCROW& rRow2 )
2267 {
2268     while ( pColIter )
2269     {
2270         const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 );
2271         if ( pPattern )
2272         {
2273             rCol1 = nIterStartCol;
2274             rCol2 = nIterEndCol;
2275             return pPattern;
2276         }
2277 
2278         delete pColIter;
2279         nIterStartCol = nIterEndCol+1;
2280         if ( nIterStartCol <= nEndCol )
2281         {
2282             nIterEndCol = nIterStartCol;
2283             pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow );
2284             while ( nIterEndCol < nEndCol &&
2285                     pDoc->pTab[nTab]->aCol[nIterEndCol].IsAllAttrEqual(
2286                         pDoc->pTab[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) )
2287                 ++nIterEndCol;
2288         }
2289         else
2290             pColIter = NULL;
2291     }
2292     return NULL;        // is nix mehr
2293 }
2294 
2295 // ============================================================================
2296 
2297 SCROW ScRowBreakIterator::NOT_FOUND = -1;
2298 
2299 ScRowBreakIterator::ScRowBreakIterator(set<SCROW>& rBreaks) :
2300     mrBreaks(rBreaks),
2301     maItr(rBreaks.begin()), maEnd(rBreaks.end())
2302 {
2303 }
2304 
2305 SCROW ScRowBreakIterator::first()
2306 {
2307     maItr = mrBreaks.begin();
2308     return maItr == maEnd ? NOT_FOUND : *maItr;
2309 }
2310 
2311 SCROW ScRowBreakIterator::next()
2312 {
2313     ++maItr;
2314     return maItr == maEnd ? NOT_FOUND : *maItr;
2315 }
2316