xref: /AOO41X/main/sc/source/core/data/dociter.cxx (revision f689a31b46295f79f8912f1880f5e2691eda3ec3)
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;                    // wird bei GetFirst initialisiert
306 
307     nNumFormat = 0;                 // werden bei GetNumberFormat initialisiert
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;               // 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 
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;                 // 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 
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;                    // 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 
~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;        // 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                             {
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; // Naechste Spalte
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;                                      // nur benutzte Tabellen
989     if (nStartTab>nEndTab)
990         nStartTab = nEndTab;
991 
992     nCol = nStartCol;
993     nRow = nStartRow;
994     nTab = nStartTab;
995     nColRow = 0;                    // wird bei GetFirst initialisiert
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;    // -> Abbruch bei 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;                                      // nur benutzte Tabellen
1031     if (nStartTab>nEndTab)
1032         nStartTab = nEndTab;
1033 
1034     nCol = nStartCol;
1035     nRow = nStartRow;
1036     nTab = nStartTab;
1037     nColRow = 0;                    // wird bei GetFirst initialisiert
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;    // -> Abbruch bei 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;                // Ende und Aus
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-Zeilen nicht
1084                 else
1085                     return pCell;       // gefunden
1086             }
1087             else
1088                 nRow++;
1089         }
1090         else
1091             nRow = nEndRow + 1; // Naechste Spalte
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;                    // wird bei GetFirst initialisiert
1129     SCSIZE i;
1130     if (bMod)                               // sonst schon eingetragen
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;                 // werden bei GetNumberFormat initialisiert
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;                // Ende und Aus
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; // Naechste Spalte
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;       // nichts gefunden
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;        // nichts gefunden
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], "Tabelle nicht da" );
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 kann gleich hier gesetzt werden
1991         }
1992         else
1993             bEmpty = sal_False;                 // Attribute gefunden
1994 
1995         pIndices[nPos] = nIndex;
1996         pNextEnd[nPos] = nThisEnd;
1997         ppPatterns[nPos] = pPattern;
1998     }
1999 
2000     if (bEmpty)
2001         nRow = nSkipTo;                     // bis zum naechsten Bereichsende ueberspringen
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             // in dieser Zeile suchen
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;                 // hochzaehlen fuer naechsten Aufruf
2032                 return pPat;            // gefunden
2033             }
2034         }
2035 
2036         // naechste Zeile
2037 
2038         ++nRow;
2039         if ( nRow > nEndRow )       // schon am Ende?
2040             return NULL;            // nichts gefunden
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;                 // Attribute gefunden
2061 
2062                     pNextEnd[nPos] = nThisEnd;
2063                     ppPatterns[nPos] = pPattern;
2064 
2065                     DBG_ASSERT( pNextEnd[nPos] >= nRow, "Reihenfolge durcheinander" );
2066                 }
2067                 else
2068                 {
2069                     DBG_ERROR("AttrArray reicht nicht bis MAXROW");
2070                     pNextEnd[nPos] = MAXROW;
2071                     ppPatterns[nPos] = NULL;
2072                 }
2073             }
2074             else if ( ppPatterns[nPos] )
2075                 bEmpty = sal_False;                         // Bereich noch nicht zuende
2076         }
2077 
2078         if (bEmpty)
2079         {
2080             SCCOL nCount = nEndCol-nStartCol+1;
2081             SCROW nSkipTo = pNextEnd[0];                // naechstes Bereichsende suchen
2082             for (i=1; i<nCount; i++)
2083                 if ( pNextEnd[i] < nSkipTo )
2084                     nSkipTo = pNextEnd[i];
2085             nRow = nSkipTo;                             // leere Zeilen ueberspringen
2086         }
2087         bRowEmpty = bEmpty;
2088         nCol = nStartCol;           // wieder links anfangen
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     //  Iteratoren weiterzaehlen
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     //  naechsten Abschnitt heraussuchen
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 )        // auch Zelle im Bereich ?
2146                 nFoundEndCol = nCellCol - 1;                            // nur bis vor der Zelle
2147             else
2148                 nFoundEndCol = nAttrCol2;                               // alles
2149         }
2150         else
2151         {
2152             bUseCell = sal_True;
2153             if ( nAttrRow == nCellRow && nAttrCol1 == nCellCol )        // Attribute auf der Zelle ?
2154                 pFoundPattern = pPattern;
2155             else
2156                 pFoundPattern = NULL;
2157         }
2158     }
2159     else if ( pCell )                   // nur Zelle -> direkt uebernehmen
2160     {
2161         pFoundPattern = NULL;
2162         bUseCell = sal_True;                // Position von Zelle
2163     }
2164     else if ( pPattern )                // nur Attribute -> direkt uebernehmen
2165     {
2166         pFoundCell = NULL;
2167         pFoundPattern = pPattern;
2168         nFoundRow = nAttrRow;
2169         nFoundStartCol = nAttrCol1;
2170         nFoundEndCol = nAttrCol2;
2171     }
2172     else                                // gar nichts
2173         bFound = sal_False;
2174 
2175     if ( bUseCell )                     // Position von Zelle
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 nix mehr
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 nix mehr
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