LCOV - code coverage report
Current view: top level - sc/source/core/data - dociter.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 957 1332 71.8 %
Date: 2014-04-11 Functions: 91 114 79.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <svl/zforlist.hxx>
      21             : 
      22             : #include "scitems.hxx"
      23             : #include "global.hxx"
      24             : #include "dociter.hxx"
      25             : #include "document.hxx"
      26             : #include "table.hxx"
      27             : #include "column.hxx"
      28             : #include "formulacell.hxx"
      29             : #include "attarray.hxx"
      30             : #include "patattr.hxx"
      31             : #include "docoptio.hxx"
      32             : #include "cellform.hxx"
      33             : #include "segmenttree.hxx"
      34             : #include "progress.hxx"
      35             : #include "queryparam.hxx"
      36             : #include "queryentry.hxx"
      37             : #include "globstr.hrc"
      38             : #include "editutil.hxx"
      39             : #include "cellvalue.hxx"
      40             : #include "scmatrix.hxx"
      41             : #include <rowheightcontext.hxx>
      42             : 
      43             : #include "tools/fract.hxx"
      44             : #include "editeng/editobj.hxx"
      45             : #include "svl/sharedstring.hxx"
      46             : 
      47             : #include <vector>
      48             : 
      49             : using ::rtl::math::approxEqual;
      50             : using ::std::vector;
      51             : using ::std::set;
      52             : 
      53             : // iterators have very high frequency use -> custom debug.
      54             : // #define debugiter(...) fprintf(stderr, __VA_ARGS__)
      55             : #define debugiter(...)
      56             : 
      57             : // STATIC DATA -----------------------------------------------------------
      58             : 
      59             : namespace {
      60             : 
      61             : template<typename _Iter>
      62          18 : void incBlock(std::pair<_Iter, size_t>& rPos)
      63             : {
      64             :     // Move to the next block.
      65          18 :     ++rPos.first;
      66          18 :     rPos.second = 0;
      67          18 : }
      68             : 
      69             : template<typename _Iter>
      70           3 : void decBlock(std::pair<_Iter, size_t>& rPos)
      71             : {
      72             :     // Move to the last element of the previous block.
      73           3 :     --rPos.first;
      74           3 :     rPos.second = rPos.first->size - 1;
      75           3 : }
      76             : 
      77             : template<typename _Iter>
      78             : void incPos(std::pair<_Iter, size_t>& rPos)
      79             : {
      80             :     if (rPos.second + 1 < rPos.first->size)
      81             :         // Increment within the block.
      82             :         ++rPos.second;
      83             :     else
      84             :         incBlock(rPos);
      85             : }
      86             : 
      87             : template<typename _Iter>
      88             : size_t toLogicalPos(const std::pair<_Iter, size_t>& rPos)
      89             : {
      90             :     return rPos.first->position + rPos.second;
      91             : }
      92             : 
      93             : }
      94             : 
      95           3 : void ScAttrArray_IterGetNumberFormat( sal_uLong& nFormat, const ScAttrArray*& rpArr,
      96             :         SCROW& nAttrEndRow, const ScAttrArray* pNewArr, SCROW nRow,
      97             :         ScDocument* pDoc )
      98             : {
      99           3 :     if ( rpArr != pNewArr || nAttrEndRow < nRow )
     100             :     {
     101           3 :         SCROW nRowStart = 0;
     102           3 :         SCROW nRowEnd = MAXROW;
     103             :         const ScPatternAttr* pPattern;
     104           3 :         if( !(pPattern = pNewArr->GetPatternRange( nRowStart, nRowEnd, nRow ) ) )
     105             :         {
     106           0 :             pPattern = pDoc->GetDefPattern();
     107           0 :             nRowEnd = MAXROW;
     108             :         }
     109             : 
     110           3 :         nFormat = pPattern->GetNumberFormat( pDoc->GetFormatTable() );
     111           3 :         rpArr = pNewArr;
     112           3 :         nAttrEndRow = nRowEnd;
     113             :     }
     114           3 : }
     115             : 
     116          34 : ScValueIterator::ScValueIterator( ScDocument* pDocument, const ScRange& rRange,
     117             :             bool bSTotal, bool bTextZero )
     118             :     : pDoc(pDocument)
     119             :     , pAttrArray(NULL)
     120             :     , nNumFormat(0) // Initialized in GetNumberFormat
     121             :     , nNumFmtIndex(0)
     122             :     , maStartPos(rRange.aStart)
     123             :     , maEndPos(rRange.aEnd)
     124             :     , mnCol(0)
     125             :     , mnTab(0)
     126             :     , nAttrEndRow(0)
     127             :     , nNumFmtType(NUMBERFORMAT_UNDEFINED)
     128             :     , bNumValid(false)
     129             :     , bSubTotal(bSTotal)
     130          34 :     , bCalcAsShown(pDocument->GetDocOptions().IsCalcAsShown())
     131             :     , bTextAsZero(bTextZero)
     132          68 :     , mpCells(NULL)
     133             : {
     134          34 :     SCTAB nDocMaxTab = pDocument->GetTableCount() - 1;
     135             : 
     136          34 :     if (!ValidCol(maStartPos.Col())) maStartPos.SetCol(MAXCOL);
     137          34 :     if (!ValidCol(maEndPos.Col())) maEndPos.SetCol(MAXCOL);
     138          34 :     if (!ValidRow(maStartPos.Row())) maStartPos.SetRow(MAXROW);
     139          34 :     if (!ValidRow(maEndPos.Row())) maEndPos.SetRow(MAXROW);
     140          34 :     if (!ValidTab(maStartPos.Tab()) || maStartPos.Tab() > nDocMaxTab) maStartPos.SetTab(nDocMaxTab);
     141          34 :     if (!ValidTab(maEndPos.Tab()) || maEndPos.Tab() > nDocMaxTab) maEndPos.SetTab(nDocMaxTab);
     142          34 : }
     143             : 
     144        3401 : SCROW ScValueIterator::GetRow() const
     145             : {
     146             :     // Position of the head of the current block + offset within the block
     147             :     // equals the logical element position.
     148        3401 :     return maCurPos.first->position + maCurPos.second;
     149             : }
     150             : 
     151          50 : void ScValueIterator::IncBlock()
     152             : {
     153          50 :     ++maCurPos.first;
     154          50 :     maCurPos.second = 0;
     155          50 : }
     156             : 
     157        1680 : void ScValueIterator::IncPos()
     158             : {
     159        1680 :     if (maCurPos.second + 1 < maCurPos.first->size)
     160             :         // Move within the same block.
     161        1630 :         ++maCurPos.second;
     162             :     else
     163             :         // Move to the next block.
     164          50 :         IncBlock();
     165        1680 : }
     166             : 
     167           0 : void ScValueIterator::SetPos(size_t nPos)
     168             : {
     169           0 :     maCurPos = mpCells->position(maCurPos.first, nPos);
     170           0 : }
     171             : 
     172        1714 : bool ScValueIterator::GetThis(double& rValue, sal_uInt16& rErr)
     173             : {
     174             :     while (true)
     175             :     {
     176        1714 :         bool bNextColumn = maCurPos.first == mpCells->end();
     177        1714 :         if (!bNextColumn)
     178             :         {
     179        1714 :             if (GetRow() > maEndPos.Row())
     180          40 :                 bNextColumn = true;
     181             :         }
     182             : 
     183        1714 :         ScColumn* pCol = &(pDoc->maTabs[mnTab])->aCol[mnCol];
     184        1714 :         if (bNextColumn)
     185             :         {
     186             :             // Find the next available column.
     187           7 :             do
     188             :             {
     189          40 :                 ++mnCol;
     190          40 :                 if (mnCol > maEndPos.Col())
     191             :                 {
     192          33 :                     mnCol = maStartPos.Col();
     193          33 :                     ++mnTab;
     194          33 :                     if (mnTab > maEndPos.Tab())
     195             :                     {
     196          33 :                         rErr = 0;
     197        1747 :                         return false; // Over and out
     198             :                     }
     199             :                 }
     200           7 :                 pCol = &(pDoc->maTabs[mnTab])->aCol[mnCol];
     201             :             }
     202             :             while (pCol->IsEmptyData());
     203             : 
     204           7 :             mpCells = &pCol->maCells;
     205           7 :             maCurPos = mpCells->position(maStartPos.Row());
     206             :         }
     207             : 
     208        1681 :         SCROW nCurRow = GetRow();
     209             :         SCROW nLastRow;
     210        1681 :         if (bSubTotal && pDoc->maTabs[mnTab]->RowFiltered(nCurRow, NULL, &nLastRow))
     211             :         {
     212             :             // Skip all filtered rows for subtotal mode.
     213           0 :             SetPos(nLastRow+1);
     214           0 :             continue;
     215             :         }
     216             : 
     217        1681 :         switch (maCurPos.first->type)
     218             :         {
     219             :             case sc::element_type_numeric:
     220             :             {
     221        1662 :                 bNumValid = false;
     222        1662 :                 rValue = sc::numeric_block::at(*maCurPos.first->data, maCurPos.second);
     223        1662 :                 rErr = 0;
     224        1662 :                 if (bCalcAsShown)
     225             :                 {
     226             :                     ScAttrArray_IterGetNumberFormat(nNumFormat, pAttrArray,
     227           3 :                         nAttrEndRow, pCol->pAttrArray, nCurRow, pDoc);
     228           3 :                     rValue = pDoc->RoundValueAsShown(rValue, nNumFormat);
     229             :                 }
     230        1662 :                 return true; // Found it!
     231             :             }
     232             :             break;
     233             :             case sc::element_type_formula:
     234             :             {
     235          19 :                 ScFormulaCell& rCell = *sc::formula_block::at(*maCurPos.first->data, maCurPos.second);
     236          19 :                 if (bSubTotal && rCell.IsSubTotal())
     237             :                 {
     238             :                     // Skip subtotal formula cells.
     239           0 :                     IncPos();
     240           0 :                     break;
     241             :                 }
     242             : 
     243          19 :                 if (rCell.GetErrorOrValue(rErr, rValue))
     244             :                 {
     245          19 :                     bNumValid = false;
     246          19 :                     return true; // Found it!
     247             :                 }
     248           0 :                 else if (bTextAsZero)
     249             :                 {
     250           0 :                     rValue = 0.0;
     251           0 :                     bNumValid = false;
     252           0 :                     return true;
     253             :                 }
     254           0 :                 IncPos();
     255             :             }
     256           0 :             break;
     257             :             case sc::element_type_string :
     258             :             case sc::element_type_edittext :
     259             :             {
     260           0 :                 if (bTextAsZero)
     261             :                 {
     262           0 :                     rErr = 0;
     263           0 :                     rValue = 0.0;
     264           0 :                     nNumFmtType = NUMBERFORMAT_NUMBER;
     265           0 :                     nNumFmtIndex = 0;
     266           0 :                     bNumValid = true;
     267           0 :                     return true;
     268             :                 }
     269           0 :                 IncBlock();
     270             :             }
     271           0 :             break;
     272             :             case sc::element_type_empty:
     273             :             default:
     274             :                 // Skip the whole block.
     275           0 :                 IncBlock();
     276             :         }
     277           0 :     }
     278             : }
     279             : 
     280           6 : void ScValueIterator::GetCurNumFmtInfo( short& nType, sal_uLong& nIndex )
     281             : {
     282           6 :     if (!bNumValid && mnTab < pDoc->GetTableCount())
     283             :     {
     284           6 :         SCROW nCurRow = GetRow();
     285           6 :         const ScColumn* pCol = &(pDoc->maTabs[mnTab])->aCol[mnCol];
     286           6 :         nNumFmtIndex = pCol->GetNumberFormat(nCurRow);
     287           6 :         nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex );
     288           6 :         bNumValid = true;
     289             :     }
     290             : 
     291           6 :     nType = nNumFmtType;
     292           6 :     nIndex = nNumFmtIndex;
     293           6 : }
     294             : 
     295          34 : bool ScValueIterator::GetFirst(double& rValue, sal_uInt16& rErr)
     296             : {
     297          34 :     mnCol = maStartPos.Col();
     298          34 :     mnTab = maStartPos.Tab();
     299             : 
     300          34 :     ScTable* pTab = pDoc->FetchTable(mnTab);
     301          34 :     if (!pTab)
     302           0 :         return false;
     303             : 
     304          34 :     nNumFormat = 0; // Initialized in GetNumberFormat
     305          34 :     pAttrArray = 0;
     306          34 :     nAttrEndRow = 0;
     307             : 
     308          34 :     mpCells = &pTab->aCol[maStartPos.Col()].maCells;
     309          34 :     maCurPos = mpCells->position(maStartPos.Row());
     310          34 :     return GetThis(rValue, rErr);
     311             : }
     312             : 
     313        1680 : bool ScValueIterator::GetNext(double& rValue, sal_uInt16& rErr)
     314             : {
     315        1680 :     IncPos();
     316        1680 :     return GetThis(rValue, rErr);
     317             : }
     318             : 
     319          15 : ScDBQueryDataIterator::DataAccess::DataAccess(const ScDBQueryDataIterator* pParent) :
     320          15 :     mpParent(pParent)
     321             : {
     322          15 : }
     323             : 
     324          15 : ScDBQueryDataIterator::DataAccess::~DataAccess()
     325             : {
     326          15 : }
     327             : 
     328          15 : const sc::CellStoreType* ScDBQueryDataIterator::GetColumnCellStore(ScDocument& rDoc, SCTAB nTab, SCCOL nCol)
     329             : {
     330          15 :     ScTable* pTab = rDoc.FetchTable(nTab);
     331          15 :     if (!pTab)
     332           0 :         return NULL;
     333             : 
     334          15 :     return &pTab->aCol[nCol].maCells;
     335             : }
     336             : 
     337           0 : const ScAttrArray* ScDBQueryDataIterator::GetAttrArrayByCol(ScDocument& rDoc, SCTAB nTab, SCCOL nCol)
     338             : {
     339           0 :     if (nTab >= rDoc.GetTableCount())
     340             :         OSL_FAIL("try to access index out of bounds, FIX IT");
     341           0 :     ScColumn* pCol = &rDoc.maTabs[nTab]->aCol[nCol];
     342           0 :     return pCol->pAttrArray;
     343             : }
     344             : 
     345         123 : bool ScDBQueryDataIterator::IsQueryValid(
     346             :     ScDocument& rDoc, const ScQueryParam& rParam, SCTAB nTab, SCROW nRow, ScRefCellValue* pCell)
     347             : {
     348         123 :     if (nTab >= rDoc.GetTableCount())
     349             :         OSL_FAIL("try to access index out of bounds, FIX IT");
     350         123 :     return rDoc.maTabs[nTab]->ValidQuery(nRow, rParam, pCell);
     351             : }
     352             : 
     353          15 : ScDBQueryDataIterator::DataAccessInternal::DataAccessInternal(const ScDBQueryDataIterator* pParent, ScDBQueryParamInternal* pParam, ScDocument* pDoc)
     354             :     : DataAccess(pParent)
     355             :     , mpCells(NULL)
     356             :     , mpParam(pParam)
     357             :     , mpDoc(pDoc)
     358             :     , pAttrArray(0)
     359             :     , nNumFormat(0) // Initialized in GetNumberFormat
     360             :     , nCol(mpParam->mnField)
     361             :     , nRow(mpParam->nRow1)
     362             :     , nAttrEndRow(0)
     363             :     , nTab(mpParam->nTab)
     364          15 :     , bCalcAsShown(pDoc->GetDocOptions().IsCalcAsShown())
     365             : {
     366             :     SCSIZE i;
     367          15 :     SCSIZE nCount = mpParam->GetEntryCount();
     368          37 :     for (i=0; (i<nCount) && (mpParam->GetEntry(i).bDoQuery); i++)
     369             :     {
     370          22 :         ScQueryEntry& rEntry = mpParam->GetEntry(i);
     371          22 :         ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
     372          22 :         rItems.resize(1);
     373          22 :         ScQueryEntry::Item& rItem = rItems.front();
     374          22 :         sal_uInt32 nIndex = 0;
     375             :         bool bNumber = mpDoc->GetFormatTable()->IsNumberFormat(
     376          22 :             rItem.maString.getString(), nIndex, rItem.mfVal);
     377          22 :         rItem.meType = bNumber ? ScQueryEntry::ByValue : ScQueryEntry::ByString;
     378             :     }
     379          15 : }
     380             : 
     381          30 : ScDBQueryDataIterator::DataAccessInternal::~DataAccessInternal()
     382             : {
     383          30 : }
     384             : 
     385          71 : bool ScDBQueryDataIterator::DataAccessInternal::getCurrent(Value& rValue)
     386             : {
     387             :     // Start with the current row position, and find the first row position
     388             :     // that satisfies the query.
     389             : 
     390             :     // If the query starts in the same column as the result vector we can
     391             :     // prefetch the cell which saves us one fetch in the success case.
     392          71 :     SCCOLROW nFirstQueryField = mpParam->GetEntry(0).nField;
     393          71 :     ScRefCellValue aCell;
     394             : 
     395             :     while (true)
     396             :     {
     397         138 :         if (maCurPos.first == mpCells->end() || nRow > mpParam->nRow2)
     398             :         {
     399             :             // Bottom of the range reached. Bail out.
     400          15 :             rValue.mnError = 0;
     401          15 :             return false;
     402             :         }
     403             : 
     404         123 :         if (maCurPos.first->type == sc::element_type_empty)
     405             :         {
     406             :             // Skip the whole empty block.
     407           0 :             incBlock();
     408           0 :             continue;
     409             :         }
     410             : 
     411         123 :         ScRefCellValue* pCell = NULL;
     412         123 :         if (nCol == static_cast<SCCOL>(nFirstQueryField))
     413             :         {
     414          33 :             aCell = sc::toRefCell(maCurPos.first, maCurPos.second);
     415          33 :             pCell = &aCell;
     416             :         }
     417             : 
     418         123 :         if (ScDBQueryDataIterator::IsQueryValid(*mpDoc, *mpParam, nTab, nRow, pCell))
     419             :         {
     420          56 :             if (!pCell)
     421          35 :                 aCell = sc::toRefCell(maCurPos.first, maCurPos.second);
     422          56 :             switch (aCell.meType)
     423             :             {
     424             :                 case CELLTYPE_VALUE:
     425             :                 {
     426          51 :                     rValue.mfValue = aCell.mfValue;
     427          51 :                     rValue.mbIsNumber = true;
     428          51 :                     if ( bCalcAsShown )
     429             :                     {
     430             :                         const ScAttrArray* pNewAttrArray =
     431           0 :                             ScDBQueryDataIterator::GetAttrArrayByCol(*mpDoc, nTab, nCol);
     432             :                         ScAttrArray_IterGetNumberFormat( nNumFormat, pAttrArray,
     433           0 :                             nAttrEndRow, pNewAttrArray, nRow, mpDoc );
     434           0 :                         rValue.mfValue = mpDoc->RoundValueAsShown( rValue.mfValue, nNumFormat );
     435             :                     }
     436          51 :                     nNumFmtType = NUMBERFORMAT_NUMBER;
     437          51 :                     nNumFmtIndex = 0;
     438          51 :                     rValue.mnError = 0;
     439          51 :                     return true; // Found it!
     440             :                 }
     441             : 
     442             :                 case CELLTYPE_FORMULA:
     443             :                 {
     444           0 :                     if (aCell.mpFormula->IsValue())
     445             :                     {
     446           0 :                         rValue.mfValue = aCell.mpFormula->GetValue();
     447           0 :                         rValue.mbIsNumber = true;
     448             :                         mpDoc->GetNumberFormatInfo(
     449           0 :                             nNumFmtType, nNumFmtIndex, ScAddress(nCol, nRow, nTab));
     450           0 :                         rValue.mnError = aCell.mpFormula->GetErrCode();
     451           0 :                         return true; // Found it!
     452             :                     }
     453           0 :                     else if(mpParam->mbSkipString)
     454           0 :                         incPos();
     455             :                     else
     456             :                     {
     457           0 :                         rValue.maString = aCell.mpFormula->GetString().getString();
     458           0 :                         rValue.mfValue = 0.0;
     459           0 :                         rValue.mnError = aCell.mpFormula->GetErrCode();
     460           0 :                         rValue.mbIsNumber = false;
     461           0 :                         return true;
     462             :                     }
     463             :                 }
     464           0 :                 break;
     465             :                 case CELLTYPE_STRING:
     466             :                 case CELLTYPE_EDIT:
     467           5 :                     if (mpParam->mbSkipString)
     468           0 :                         incPos();
     469             :                     else
     470             :                     {
     471           5 :                         rValue.maString = aCell.getString(mpDoc);
     472           5 :                         rValue.mfValue = 0.0;
     473           5 :                         rValue.mnError = 0;
     474           5 :                         rValue.mbIsNumber = false;
     475           5 :                         return true;
     476             :                     }
     477           0 :                 break;
     478             :                 default:
     479           0 :                     incPos();
     480             :             }
     481             :         }
     482             :         else
     483          67 :             incPos();
     484          71 :     }
     485             : // statement unreachable
     486             : }
     487             : 
     488          15 : bool ScDBQueryDataIterator::DataAccessInternal::getFirst(Value& rValue)
     489             : {
     490          15 :     if (mpParam->bHasHeader)
     491          15 :         ++nRow;
     492             : 
     493          15 :     mpCells = ScDBQueryDataIterator::GetColumnCellStore(*mpDoc, nTab, nCol);
     494          15 :     if (!mpCells)
     495           0 :         return false;
     496             : 
     497          15 :     maCurPos = mpCells->position(nRow);
     498          15 :     return getCurrent(rValue);
     499             : }
     500             : 
     501          56 : bool ScDBQueryDataIterator::DataAccessInternal::getNext(Value& rValue)
     502             : {
     503          56 :     if (!mpCells || maCurPos.first == mpCells->end())
     504           0 :         return false;
     505             : 
     506          56 :     incPos();
     507          56 :     return getCurrent(rValue);
     508             : }
     509             : 
     510          15 : void ScDBQueryDataIterator::DataAccessInternal::incBlock()
     511             : {
     512          15 :     ++maCurPos.first;
     513          15 :     maCurPos.second = 0;
     514             : 
     515          15 :     nRow = maCurPos.first->position;
     516          15 : }
     517             : 
     518         123 : void ScDBQueryDataIterator::DataAccessInternal::incPos()
     519             : {
     520         123 :     if (maCurPos.second + 1 < maCurPos.first->size)
     521             :     {
     522             :         // Move within the same block.
     523         108 :         ++maCurPos.second;
     524         108 :         ++nRow;
     525             :     }
     526             :     else
     527             :         // Move to the next block.
     528          15 :         incBlock();
     529         123 : }
     530             : 
     531           0 : ScDBQueryDataIterator::DataAccessMatrix::DataAccessMatrix(const ScDBQueryDataIterator* pParent, ScDBQueryParamMatrix* pParam)
     532             :     : DataAccess(pParent)
     533             :     , mpParam(pParam)
     534           0 :     , mnCurRow(0)
     535             : {
     536             :     SCSIZE nC, nR;
     537           0 :     mpParam->mpMatrix->GetDimensions(nC, nR);
     538           0 :     mnRows = static_cast<SCROW>(nR);
     539           0 :     mnCols = static_cast<SCCOL>(nC);
     540           0 : }
     541             : 
     542           0 : ScDBQueryDataIterator::DataAccessMatrix::~DataAccessMatrix()
     543             : {
     544           0 : }
     545             : 
     546           0 : bool ScDBQueryDataIterator::DataAccessMatrix::getCurrent(Value& rValue)
     547             : {
     548             :     // Starting from row == mnCurRow, get the first row that satisfies all the
     549             :     // query parameters.
     550           0 :     for ( ;mnCurRow < mnRows; ++mnCurRow)
     551             :     {
     552           0 :         const ScMatrix& rMat = *mpParam->mpMatrix;
     553           0 :         if (rMat.IsEmpty(mpParam->mnField, mnCurRow))
     554             :             // Don't take empty values into account.
     555           0 :             continue;
     556             : 
     557           0 :         bool bIsStrVal = rMat.IsString(mpParam->mnField, mnCurRow);
     558           0 :         if (bIsStrVal && mpParam->mbSkipString)
     559           0 :             continue;
     560             : 
     561           0 :         if (isValidQuery(mnCurRow, rMat))
     562             :         {
     563           0 :             rValue.maString = rMat.GetString(mpParam->mnField, mnCurRow).getString();
     564           0 :             rValue.mfValue = rMat.GetDouble(mpParam->mnField, mnCurRow);
     565           0 :             rValue.mbIsNumber = !bIsStrVal;
     566           0 :             rValue.mnError = 0;
     567           0 :             return true;
     568             :         }
     569             :     }
     570           0 :     return false;
     571             : }
     572             : 
     573           0 : bool ScDBQueryDataIterator::DataAccessMatrix::getFirst(Value& rValue)
     574             : {
     575           0 :     mnCurRow = mpParam->bHasHeader ? 1 : 0;
     576           0 :     return getCurrent(rValue);
     577             : }
     578             : 
     579           0 : bool ScDBQueryDataIterator::DataAccessMatrix::getNext(Value& rValue)
     580             : {
     581           0 :     ++mnCurRow;
     582           0 :     return getCurrent(rValue);
     583             : }
     584             : 
     585             : namespace {
     586             : 
     587           0 : bool isQueryByValue(const ScQueryEntry::Item& rItem, const ScMatrix& rMat, SCSIZE nCol, SCSIZE nRow)
     588             : {
     589           0 :     if (rItem.meType == ScQueryEntry::ByString)
     590           0 :         return false;
     591             : 
     592           0 :     if (!rMat.IsValueOrEmpty(nCol, nRow))
     593           0 :         return false;
     594             : 
     595           0 :     return true;
     596             : }
     597             : 
     598           0 : bool isQueryByString(const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem, const ScMatrix& rMat, SCSIZE nCol, SCSIZE nRow)
     599             : {
     600           0 :     switch (rEntry.eOp)
     601             :     {
     602             :         case SC_EQUAL:
     603             :         case SC_NOT_EQUAL:
     604             :         case SC_CONTAINS:
     605             :         case SC_DOES_NOT_CONTAIN:
     606             :         case SC_BEGINS_WITH:
     607             :         case SC_ENDS_WITH:
     608             :         case SC_DOES_NOT_BEGIN_WITH:
     609             :         case SC_DOES_NOT_END_WITH:
     610           0 :             return true;
     611             :         default:
     612             :             ;
     613             :     }
     614             : 
     615           0 :     if (rItem.meType == ScQueryEntry::ByString && rMat.IsString(nCol, nRow))
     616           0 :         return true;
     617             : 
     618           0 :     return false;
     619             : }
     620             : 
     621             : }
     622             : 
     623           0 : bool ScDBQueryDataIterator::DataAccessMatrix::isValidQuery(SCROW nRow, const ScMatrix& rMat) const
     624             : {
     625           0 :     SCSIZE nEntryCount = mpParam->GetEntryCount();
     626           0 :     vector<bool> aResults;
     627           0 :     aResults.reserve(nEntryCount);
     628             : 
     629             :     const CollatorWrapper& rCollator =
     630           0 :         mpParam->bCaseSens ? *ScGlobal::GetCaseCollator() : *ScGlobal::GetCollator();
     631             : 
     632           0 :     for (SCSIZE i = 0; i < nEntryCount; ++i)
     633             :     {
     634           0 :         const ScQueryEntry& rEntry = mpParam->GetEntry(i);
     635           0 :         const ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
     636           0 :         if (!rEntry.bDoQuery)
     637           0 :             continue;
     638             : 
     639           0 :         switch (rEntry.eOp)
     640             :         {
     641             :             case SC_EQUAL:
     642             :             case SC_LESS:
     643             :             case SC_GREATER:
     644             :             case SC_LESS_EQUAL:
     645             :             case SC_GREATER_EQUAL:
     646             :             case SC_NOT_EQUAL:
     647           0 :                 break;
     648             :             default:
     649             :                 // Only the above operators are supported.
     650           0 :                 continue;
     651             :         }
     652             : 
     653           0 :         bool bValid = false;
     654             : 
     655           0 :         SCSIZE nField = static_cast<SCSIZE>(rEntry.nField);
     656           0 :         if (isQueryByValue(rItem, rMat, nField, nRow))
     657             :         {
     658             :             // By value
     659           0 :             double fMatVal = rMat.GetDouble(nField, nRow);
     660           0 :             bool bEqual = approxEqual(fMatVal, rItem.mfVal);
     661           0 :             switch (rEntry.eOp)
     662             :             {
     663             :                 case SC_EQUAL:
     664           0 :                     bValid = bEqual;
     665           0 :                 break;
     666             :                 case SC_LESS:
     667           0 :                     bValid = (fMatVal < rItem.mfVal) && !bEqual;
     668           0 :                 break;
     669             :                 case SC_GREATER:
     670           0 :                     bValid = (fMatVal > rItem.mfVal) && !bEqual;
     671           0 :                 break;
     672             :                 case SC_LESS_EQUAL:
     673           0 :                     bValid = (fMatVal < rItem.mfVal) || bEqual;
     674           0 :                 break;
     675             :                 case SC_GREATER_EQUAL:
     676           0 :                     bValid = (fMatVal > rItem.mfVal) || bEqual;
     677           0 :                 break;
     678             :                 case SC_NOT_EQUAL:
     679           0 :                     bValid = !bEqual;
     680           0 :                 break;
     681             :                 default:
     682             :                     ;
     683             :             }
     684             :         }
     685           0 :         else if (isQueryByString(rEntry, rItem, rMat, nField, nRow))
     686             :         {
     687             :             // By string
     688             :             do
     689             :             {
     690             :                 // Equality check first.
     691           0 :                 svl::SharedString aMatStr = rMat.GetString(nField, nRow);
     692           0 :                 svl::SharedString aQueryStr = rEntry.GetQueryItem().maString;
     693           0 :                 bool bDone = false;
     694           0 :                 rtl_uString* p1 = mpParam->bCaseSens ? aMatStr.getData() : aMatStr.getDataIgnoreCase();
     695           0 :                 rtl_uString* p2 = mpParam->bCaseSens ? aQueryStr.getData() : aQueryStr.getDataIgnoreCase();
     696           0 :                 switch (rEntry.eOp)
     697             :                 {
     698             :                     case SC_EQUAL:
     699           0 :                         bValid = (p1 == p2);
     700           0 :                         bDone = true;
     701           0 :                     break;
     702             :                     case SC_NOT_EQUAL:
     703           0 :                         bValid = (p1 != p2);
     704           0 :                         bDone = true;
     705           0 :                     break;
     706             :                     default:
     707             :                         ;
     708             :                 }
     709             : 
     710           0 :                 if (bDone)
     711           0 :                     break;
     712             : 
     713             :                 // Unequality check using collator.
     714           0 :                 sal_Int32 nCompare = rCollator.compareString(aMatStr.getString(), aQueryStr.getString());
     715           0 :                 switch (rEntry.eOp)
     716             :                 {
     717             :                     case SC_LESS :
     718           0 :                         bValid = (nCompare < 0);
     719           0 :                     break;
     720             :                     case SC_GREATER :
     721           0 :                         bValid = (nCompare > 0);
     722           0 :                     break;
     723             :                     case SC_LESS_EQUAL :
     724           0 :                         bValid = (nCompare <= 0);
     725           0 :                     break;
     726             :                     case SC_GREATER_EQUAL :
     727           0 :                         bValid = (nCompare >= 0);
     728           0 :                     break;
     729             :                     default:
     730             :                         ;
     731           0 :                 }
     732             :             }
     733             :             while (false);
     734             :         }
     735             : 
     736           0 :         if (aResults.empty())
     737             :             // First query entry.
     738           0 :             aResults.push_back(bValid);
     739           0 :         else if (rEntry.eConnect == SC_AND)
     740             :         {
     741             :             // For AND op, tuck the result into the last result value.
     742           0 :             size_t n = aResults.size();
     743           0 :             aResults[n-1] = aResults[n-1] && bValid;
     744             :         }
     745             :         else
     746             :             // For OR op, store its own result.
     747           0 :             aResults.push_back(bValid);
     748             :     }
     749             : 
     750             :     // Row is valid as long as there is at least one result being true.
     751           0 :     vector<bool>::const_iterator itr = aResults.begin(), itrEnd = aResults.end();
     752           0 :     for (; itr != itrEnd; ++itr)
     753           0 :         if (*itr)
     754           0 :             return true;
     755             : 
     756           0 :     return false;
     757             : }
     758             : 
     759          16 : ScDBQueryDataIterator::Value::Value() :
     760          16 :     mnError(0), mbIsNumber(true)
     761             : {
     762          16 :     ::rtl::math::setNan(&mfValue);
     763          16 : }
     764             : 
     765          15 : ScDBQueryDataIterator::ScDBQueryDataIterator(ScDocument* pDocument, ScDBQueryParamBase* pParam) :
     766          15 :     mpParam (pParam)
     767             : {
     768          15 :     switch (mpParam->GetType())
     769             :     {
     770             :         case ScDBQueryParamBase::INTERNAL:
     771             :         {
     772          15 :             ScDBQueryParamInternal* p = static_cast<ScDBQueryParamInternal*>(pParam);
     773          15 :             mpData.reset(new DataAccessInternal(this, p, pDocument));
     774             :         }
     775          15 :         break;
     776             :         case ScDBQueryParamBase::MATRIX:
     777             :         {
     778           0 :             ScDBQueryParamMatrix* p = static_cast<ScDBQueryParamMatrix*>(pParam);
     779           0 :             mpData.reset(new DataAccessMatrix(this, p));
     780             :         }
     781             :     }
     782          15 : }
     783             : 
     784          15 : bool ScDBQueryDataIterator::GetFirst(Value& rValue)
     785             : {
     786          15 :     return mpData->getFirst(rValue);
     787             : }
     788             : 
     789          56 : bool ScDBQueryDataIterator::GetNext(Value& rValue)
     790             : {
     791          56 :     return mpData->getNext(rValue);
     792             : }
     793             : 
     794         113 : ScCellIterator::ScCellIterator( ScDocument* pDoc, const ScRange& rRange, bool bSTotal ) :
     795             :     mpDoc(pDoc),
     796             :     maStartPos(rRange.aStart),
     797             :     maEndPos(rRange.aEnd),
     798         113 :     mbSubTotal(bSTotal)
     799             : {
     800         113 :     init();
     801         113 : }
     802             : 
     803         640 : void ScCellIterator::incBlock()
     804             : {
     805         640 :     ++maCurColPos.first;
     806         640 :     maCurColPos.second = 0;
     807             : 
     808         640 :     maCurPos.SetRow(maCurColPos.first->position);
     809         640 : }
     810             : 
     811        1357 : void ScCellIterator::incPos()
     812             : {
     813        1357 :     if (maCurColPos.second + 1 < maCurColPos.first->size)
     814             :     {
     815             :         // Move within the same block.
     816         995 :         ++maCurColPos.second;
     817         995 :         maCurPos.IncRow();
     818             :     }
     819             :     else
     820             :         // Move to the next block.
     821         362 :         incBlock();
     822        1357 : }
     823             : 
     824           0 : void ScCellIterator::setPos(size_t nPos)
     825             : {
     826           0 :     maCurColPos = getColumn()->maCells.position(maCurColPos.first, nPos);
     827           0 :     maCurPos.SetRow(nPos);
     828           0 : }
     829             : 
     830       24223 : const ScColumn* ScCellIterator::getColumn() const
     831             : {
     832       24223 :     return &mpDoc->maTabs[maCurPos.Tab()]->aCol[maCurPos.Col()];
     833             : }
     834             : 
     835         113 : void ScCellIterator::init()
     836             : {
     837         113 :     SCTAB nDocMaxTab = mpDoc->GetTableCount() - 1;
     838             : 
     839         113 :     PutInOrder(maStartPos, maEndPos);
     840             : 
     841         113 :     if (!ValidCol(maStartPos.Col())) maStartPos.SetCol(MAXCOL);
     842         113 :     if (!ValidCol(maEndPos.Col())) maEndPos.SetCol(MAXCOL);
     843         113 :     if (!ValidRow(maStartPos.Row())) maStartPos.SetRow(MAXROW);
     844         113 :     if (!ValidRow(maEndPos.Row())) maEndPos.SetRow(MAXROW);
     845         113 :     if (!ValidTab(maStartPos.Tab(), nDocMaxTab)) maStartPos.SetTab(nDocMaxTab);
     846         113 :     if (!ValidTab(maEndPos.Tab(), nDocMaxTab)) maEndPos.SetTab(nDocMaxTab);
     847             : 
     848         226 :     while (maEndPos.Tab() > 0 && !mpDoc->maTabs[maEndPos.Tab()])
     849           0 :         maEndPos.IncTab(-1); // Only the tables in use
     850             : 
     851         113 :     if (maStartPos.Tab() > maEndPos.Tab())
     852           0 :         maStartPos.SetTab(maEndPos.Tab());
     853             : 
     854         113 :     maCurPos = maStartPos;
     855             : 
     856         113 :     if (!mpDoc->maTabs[maCurPos.Tab()])
     857             :     {
     858             :         OSL_FAIL("Table not found");
     859           0 :         maStartPos = ScAddress(MAXCOL+1, MAXROW+1, MAXTAB+1); // -> Abort on GetFirst.
     860           0 :         maCurPos = maStartPos;
     861             :     }
     862         113 : }
     863             : 
     864        1470 : bool ScCellIterator::getCurrent()
     865             : {
     866        1470 :     const ScColumn* pCol = getColumn();
     867             : 
     868             :     while (true)
     869             :     {
     870        1748 :         bool bNextColumn = maCurColPos.first == pCol->maCells.end();
     871        1748 :         if (!bNextColumn)
     872             :         {
     873        1613 :             if (maCurPos.Row() > maEndPos.Row())
     874         187 :                 bNextColumn = true;
     875             :         }
     876             : 
     877        1748 :         if (bNextColumn)
     878             :         {
     879             :             // Move to the next column.
     880         322 :             maCurPos.SetRow(maStartPos.Row());
     881       22640 :             do
     882             :             {
     883       22753 :                 maCurPos.IncCol();
     884       22753 :                 if (maCurPos.Col() > maEndPos.Col())
     885             :                 {
     886         113 :                     maCurPos.SetCol(maStartPos.Col());
     887         113 :                     maCurPos.IncTab();
     888         113 :                     if (maCurPos.Tab() > maEndPos.Tab())
     889             :                     {
     890         113 :                         maCurCell.clear();
     891        1583 :                         return false; // Over and out
     892             :                     }
     893             :                 }
     894       22640 :                 pCol = getColumn();
     895             :             }
     896             :             while (pCol->IsEmptyData());
     897             : 
     898         209 :             maCurColPos = pCol->maCells.position(maCurPos.Row());
     899             :         }
     900             : 
     901        1635 :         if (maCurColPos.first->type == sc::element_type_empty)
     902             :         {
     903         278 :             incBlock();
     904         556 :             continue;
     905             :         }
     906             : 
     907             :         SCROW nLastRow;
     908        1357 :         if (mbSubTotal && pCol->GetDoc().maTabs[maCurPos.Tab()]->RowFiltered(maCurPos.Row(), NULL, &nLastRow))
     909             :         {
     910             :             // Skip all filtered rows for subtotal mode.
     911           0 :             setPos(nLastRow+1);
     912           0 :             continue;
     913             :         }
     914             : 
     915        1357 :         if (maCurColPos.first->type == sc::element_type_formula)
     916             :         {
     917         688 :             const ScFormulaCell* pCell = sc::formula_block::at(*maCurColPos.first->data, maCurColPos.second);
     918         688 :             if (pCell->IsSubTotal())
     919             :             {
     920             :                 // Skip subtotal formula cells.
     921           0 :                 incPos();
     922           0 :                 continue;
     923             :             }
     924             :         }
     925             : 
     926        1357 :         maCurCell = sc::toRefCell(maCurColPos.first, maCurColPos.second);
     927        1357 :         return true;
     928             :     }
     929         278 :     return false;
     930             : }
     931             : 
     932         783 : CellType ScCellIterator::getType() const
     933             : {
     934         783 :     return maCurCell.meType;
     935             : }
     936             : 
     937           0 : OUString ScCellIterator::getString()
     938             : {
     939           0 :     return maCurCell.getString(mpDoc);
     940             : }
     941             : 
     942           0 : const EditTextObject* ScCellIterator::getEditText() const
     943             : {
     944           0 :     return maCurCell.mpEditText;
     945             : }
     946             : 
     947         346 : ScFormulaCell* ScCellIterator::getFormulaCell()
     948             : {
     949         346 :     return maCurCell.mpFormula;
     950             : }
     951             : 
     952           0 : const ScFormulaCell* ScCellIterator::getFormulaCell() const
     953             : {
     954           0 :     return maCurCell.mpFormula;
     955             : }
     956             : 
     957           0 : ScCellValue ScCellIterator::getCellValue() const
     958             : {
     959           0 :     ScCellValue aRet;
     960           0 :     aRet.meType = maCurCell.meType;
     961             : 
     962           0 :     switch (maCurCell.meType)
     963             :     {
     964             :         case CELLTYPE_STRING:
     965           0 :             aRet.mpString = new svl::SharedString(*maCurCell.mpString);
     966           0 :         break;
     967             :         case CELLTYPE_EDIT:
     968           0 :             aRet.mpEditText = maCurCell.mpEditText->Clone();
     969           0 :         break;
     970             :         case CELLTYPE_VALUE:
     971           0 :             aRet.mfValue = maCurCell.mfValue;
     972           0 :         break;
     973             :         case CELLTYPE_FORMULA:
     974           0 :             aRet.mpFormula = maCurCell.mpFormula->Clone();
     975           0 :         break;
     976             :         default:
     977             :             ;
     978             :     }
     979             : 
     980           0 :     return aRet;
     981             : }
     982             : 
     983           0 : const ScRefCellValue& ScCellIterator::getRefCellValue() const
     984             : {
     985           0 :     return maCurCell;
     986             : }
     987             : 
     988         398 : bool ScCellIterator::hasString() const
     989             : {
     990         398 :     return maCurCell.hasString();
     991             : }
     992             : 
     993          86 : bool ScCellIterator::hasEmptyData() const
     994             : {
     995          86 :     if (maCurCell.isEmpty())
     996           0 :         return true;
     997             : 
     998          86 :     if (maCurCell.meType == CELLTYPE_FORMULA)
     999          86 :         return maCurCell.mpFormula->IsEmpty();
    1000             : 
    1001           0 :     return false;
    1002             : }
    1003             : 
    1004         153 : bool ScCellIterator::isEmpty() const
    1005             : {
    1006         153 :     return maCurCell.isEmpty();
    1007             : }
    1008             : 
    1009          58 : bool ScCellIterator::equalsWithoutFormat( const ScAddress& rPos ) const
    1010             : {
    1011          58 :     ScRefCellValue aOther;
    1012          58 :     aOther.assign(*mpDoc, rPos);
    1013          58 :     return maCurCell.equalsWithoutFormat(aOther);
    1014             : }
    1015             : 
    1016         113 : bool ScCellIterator::first()
    1017             : {
    1018         113 :     if (!ValidTab(maCurPos.Tab()))
    1019           0 :         return false;
    1020             : 
    1021         113 :     maCurPos = maStartPos;
    1022         113 :     const ScColumn* pCol = getColumn();
    1023             : 
    1024         113 :     maCurColPos = pCol->maCells.position(maCurPos.Row());
    1025         113 :     return getCurrent();
    1026             : }
    1027             : 
    1028        1357 : bool ScCellIterator::next()
    1029             : {
    1030        1357 :     incPos();
    1031        1357 :     return getCurrent();
    1032             : }
    1033             : 
    1034         127 : ScQueryCellIterator::ScQueryCellIterator(ScDocument* pDocument, SCTAB nTable,
    1035             :              const ScQueryParam& rParam, bool bMod ) :
    1036         127 :     mpParam(new ScQueryParam(rParam)),
    1037             :     pDoc( pDocument ),
    1038             :     nTab( nTable),
    1039             :     nStopOnMismatch( nStopOnMismatchDisabled ),
    1040             :     nTestEqualCondition( nTestEqualConditionDisabled ),
    1041             :     bAdvanceQuery( false ),
    1042         254 :     bIgnoreMismatchOnLeadingStrings( false )
    1043             : {
    1044         127 :     nCol = mpParam->nCol1;
    1045         127 :     nRow = mpParam->nRow1;
    1046             :     SCSIZE i;
    1047         127 :     if (bMod) // Or else it's already inserted
    1048             :     {
    1049           5 :         SCSIZE nCount = mpParam->GetEntryCount();
    1050          15 :         for (i = 0; (i < nCount) && (mpParam->GetEntry(i).bDoQuery); ++i)
    1051             :         {
    1052          10 :             ScQueryEntry& rEntry = mpParam->GetEntry(i);
    1053          10 :             ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
    1054          10 :             sal_uInt32 nIndex = 0;
    1055             :             bool bNumber = pDoc->GetFormatTable()->IsNumberFormat(
    1056          10 :                 rItem.maString.getString(), nIndex, rItem.mfVal);
    1057          10 :             rItem.meType = bNumber ? ScQueryEntry::ByValue : ScQueryEntry::ByString;
    1058             :         }
    1059             :     }
    1060         127 :     nNumFormat = 0; // Initialized in GetNumberFormat
    1061         127 :     pAttrArray = 0;
    1062         127 :     nAttrEndRow = 0;
    1063         127 : }
    1064             : 
    1065         278 : void ScQueryCellIterator::InitPos()
    1066             : {
    1067         278 :     nRow = mpParam->nRow1;
    1068         278 :     if (mpParam->bHasHeader && mpParam->bByRow)
    1069           5 :         ++nRow;
    1070         278 :     ScColumn* pCol = &(pDoc->maTabs[nTab])->aCol[nCol];
    1071         278 :     maCurPos = pCol->maCells.position(nRow);
    1072         278 : }
    1073             : 
    1074         625 : void ScQueryCellIterator::IncPos()
    1075             : {
    1076         625 :     if (maCurPos.second + 1 < maCurPos.first->size)
    1077             :     {
    1078             :         // Move within the same block.
    1079         447 :         ++maCurPos.second;
    1080         447 :         ++nRow;
    1081             :     }
    1082             :     else
    1083             :         // Move to the next block.
    1084         178 :         IncBlock();
    1085         625 : }
    1086             : 
    1087         212 : void ScQueryCellIterator::IncBlock()
    1088             : {
    1089         212 :     ++maCurPos.first;
    1090         212 :     maCurPos.second = 0;
    1091             : 
    1092         212 :     nRow = maCurPos.first->position;
    1093         212 : }
    1094             : 
    1095         474 : bool ScQueryCellIterator::GetThis()
    1096             : {
    1097         474 :     if (nTab >= pDoc->GetTableCount())
    1098             :         OSL_FAIL("try to access index out of bounds, FIX IT");
    1099         474 :     const ScQueryEntry& rEntry = mpParam->GetEntry(0);
    1100         474 :     const ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
    1101             : 
    1102         474 :     SCCOLROW nFirstQueryField = rEntry.nField;
    1103         801 :     bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings &&
    1104         801 :         rItem.meType != ScQueryEntry::ByString;
    1105         327 :     bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
    1106         900 :         !mpParam->bHasHeader && rItem.meType == ScQueryEntry::ByString &&
    1107         196 :         ((mpParam->bByRow && nRow == mpParam->nRow1) ||
    1108         606 :          (!mpParam->bByRow && nCol == mpParam->nCol1));
    1109             : 
    1110         474 :     ScColumn* pCol = &(pDoc->maTabs[nTab])->aCol[nCol];
    1111             :     while (true)
    1112             :     {
    1113         813 :         bool bNextColumn = maCurPos.first == pCol->maCells.end();
    1114         813 :         if (!bNextColumn)
    1115             :         {
    1116         811 :             if (nRow > mpParam->nRow2)
    1117         265 :                 bNextColumn = true;
    1118             :         }
    1119             : 
    1120         813 :         if (bNextColumn)
    1121             :         {
    1122         210 :             do
    1123             :             {
    1124         267 :                 if ( ++nCol > mpParam->nCol2 )
    1125         531 :                     return false; // Over and out
    1126         210 :                 if ( bAdvanceQuery )
    1127             :                 {
    1128         210 :                     AdvanceQueryParamEntryField();
    1129         210 :                     nFirstQueryField = rEntry.nField;
    1130             :                 }
    1131         210 :                 pCol = &(pDoc->maTabs[nTab])->aCol[nCol];
    1132             :             }
    1133             :             while (pCol->IsEmptyData());
    1134             : 
    1135         210 :             InitPos();
    1136             : 
    1137         210 :             bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
    1138         459 :                 !mpParam->bHasHeader && rItem.meType == ScQueryEntry::ByString &&
    1139         249 :                 mpParam->bByRow;
    1140             :         }
    1141             : 
    1142         756 :         if (maCurPos.first->type == sc::element_type_empty)
    1143             :         {
    1144          34 :             IncBlock();
    1145          34 :             continue;
    1146             :         }
    1147             : 
    1148         722 :         ScRefCellValue aCell = sc::toRefCell(maCurPos.first, maCurPos.second);
    1149             : 
    1150         722 :         if (bAllStringIgnore && aCell.hasString())
    1151          72 :             IncPos();
    1152             :         else
    1153             :         {
    1154         650 :             bool bTestEqualCondition = false;
    1155        1950 :             if ( pDoc->maTabs[nTab]->ValidQuery( nRow, *mpParam,
    1156         650 :                     (nCol == static_cast<SCCOL>(nFirstQueryField) ? &aCell : NULL),
    1157        2600 :                     (nTestEqualCondition ? &bTestEqualCondition : NULL) ) )
    1158             :             {
    1159         350 :                 if ( nTestEqualCondition && bTestEqualCondition )
    1160           9 :                     nTestEqualCondition |= nTestEqualConditionMatched;
    1161         767 :                 return !aCell.isEmpty(); // Found it!
    1162             :             }
    1163         300 :             else if ( nStopOnMismatch )
    1164             :             {
    1165             :                 // Yes, even a mismatch may have a fulfilled equal
    1166             :                 // condition if regular expressions were involved and
    1167             :                 // SC_LESS_EQUAL or SC_GREATER_EQUAL were queried.
    1168          68 :                 if ( nTestEqualCondition && bTestEqualCondition )
    1169             :                 {
    1170           0 :                     nTestEqualCondition |= nTestEqualConditionMatched;
    1171           0 :                     nStopOnMismatch |= nStopOnMismatchOccurred;
    1172           0 :                     return false;
    1173             :                 }
    1174             :                 bool bStop;
    1175          68 :                 if (bFirstStringIgnore)
    1176             :                 {
    1177           1 :                     if (aCell.hasString())
    1178             :                     {
    1179           1 :                         IncPos();
    1180           1 :                         bStop = false;
    1181             :                     }
    1182             :                     else
    1183           0 :                         bStop = true;
    1184             :                 }
    1185             :                 else
    1186          67 :                     bStop = true;
    1187          68 :                 if (bStop)
    1188             :                 {
    1189          67 :                     nStopOnMismatch |= nStopOnMismatchOccurred;
    1190          67 :                     return false;
    1191             :                 }
    1192             :             }
    1193             :             else
    1194         232 :                 IncPos();
    1195             :         }
    1196         305 :         bFirstStringIgnore = false;
    1197         644 :     }
    1198             : }
    1199             : 
    1200          68 : bool ScQueryCellIterator::GetFirst()
    1201             : {
    1202          68 :     if (nTab >= pDoc->GetTableCount())
    1203             :         OSL_FAIL("try to access index out of bounds, FIX IT");
    1204          68 :     nCol = mpParam->nCol1;
    1205          68 :     InitPos();
    1206          68 :     return GetThis();
    1207             : }
    1208             : 
    1209         320 : bool ScQueryCellIterator::GetNext()
    1210             : {
    1211         320 :     IncPos();
    1212         320 :     if ( nStopOnMismatch )
    1213         219 :         nStopOnMismatch = nStopOnMismatchEnabled;
    1214         320 :     if ( nTestEqualCondition )
    1215         210 :         nTestEqualCondition = nTestEqualConditionEnabled;
    1216         320 :     return GetThis();
    1217             : }
    1218             : 
    1219         210 : void ScQueryCellIterator::AdvanceQueryParamEntryField()
    1220             : {
    1221         210 :     SCSIZE nEntries = mpParam->GetEntryCount();
    1222         420 :     for ( SCSIZE j = 0; j < nEntries; j++  )
    1223             :     {
    1224         420 :         ScQueryEntry& rEntry = mpParam->GetEntry( j );
    1225         420 :         if ( rEntry.bDoQuery )
    1226             :         {
    1227         210 :             if ( rEntry.nField < MAXCOL )
    1228         210 :                 rEntry.nField++;
    1229             :             else
    1230             :             {
    1231             :                 OSL_FAIL( "AdvanceQueryParamEntryField: ++rEntry.nField > MAXCOL" );
    1232             :             }
    1233             :         }
    1234             :         else
    1235         210 :             break;  // for
    1236             :     }
    1237         210 : }
    1238             : 
    1239             : 
    1240          90 : bool ScQueryCellIterator::FindEqualOrSortedLastInRange( SCCOL& nFoundCol,
    1241             :         SCROW& nFoundRow, bool bSearchForEqualAfterMismatch,
    1242             :         bool bIgnoreMismatchOnLeadingStringsP )
    1243             : {
    1244             :     // Set and automatically reset mpParam->mbRangeLookup when returning. We
    1245             :     // could use comphelper::FlagRestorationGuard, but really, that one is
    1246             :     // overengineered for this simple purpose here.
    1247             :     struct BoolResetter
    1248             :     {
    1249             :         bool& mr;
    1250             :         bool  mb;
    1251          90 :         BoolResetter( bool& r, bool b ) : mr(r), mb(r) { r = b; }
    1252          90 :         ~BoolResetter() { mr = mb; }
    1253          90 :     } aRangeLookupResetter( mpParam->mbRangeLookup, true);
    1254             : 
    1255          90 :     nFoundCol = MAXCOL+1;
    1256          90 :     nFoundRow = MAXROW+1;
    1257          90 :     SetStopOnMismatch( true ); // assume sorted keys
    1258          90 :     SetTestEqualCondition( true );
    1259          90 :     bIgnoreMismatchOnLeadingStrings = bIgnoreMismatchOnLeadingStringsP;
    1260          90 :     bool bRegExp = mpParam->bRegExp && mpParam->GetEntry(0).GetQueryItem().meType == ScQueryEntry::ByString;
    1261         149 :     bool bBinary = !bRegExp && mpParam->bByRow && (mpParam->GetEntry(0).eOp ==
    1262         107 :             SC_LESS_EQUAL || mpParam->GetEntry(0).eOp == SC_GREATER_EQUAL);
    1263          90 :     bool bFound = false;
    1264          90 :     if (bBinary)
    1265             :     {
    1266          59 :         if (BinarySearch())
    1267             :         {
    1268             :             // BinarySearch() already positions correctly and only needs real
    1269             :             // query comparisons afterwards, skip the verification check below.
    1270          58 :             mpParam->mbRangeLookup = false;
    1271          58 :             bFound = GetThis();
    1272             :         }
    1273             :     }
    1274             :     else
    1275             :     {
    1276          31 :         bFound = GetFirst();
    1277             :     }
    1278          90 :     if (bFound)
    1279             :     {
    1280             :         // First equal entry or last smaller than (greater than) entry.
    1281          82 :         PositionType aPosSave;
    1282          82 :         bool bNext = false;
    1283         219 :         do
    1284             :         {
    1285         219 :             nFoundCol = GetCol();
    1286         219 :             nFoundRow = GetRow();
    1287         219 :             aPosSave = maCurPos;
    1288             :         }
    1289         219 :         while ( !IsEqualConditionFulfilled() && (bNext = GetNext()));
    1290             : 
    1291             :         // There may be no pNext but equal condition fulfilled if regular
    1292             :         // expressions are involved. Keep the found entry and proceed.
    1293          82 :         if (!bNext && !IsEqualConditionFulfilled())
    1294             :         {
    1295             :             // Step back to last in range and adjust position markers for
    1296             :             // GetNumberFormat() or similar.
    1297          73 :             SCCOL nColDiff = nCol - nFoundCol;
    1298          73 :             nCol = nFoundCol;
    1299          73 :             nRow = nFoundRow;
    1300          73 :             maCurPos = aPosSave;
    1301          73 :             if (mpParam->mbRangeLookup)
    1302             :             {
    1303             :                 // Verify that the found entry does not only fulfill the range
    1304             :                 // lookup but also the real query, i.e. not numeric was found
    1305             :                 // if query is ByString and vice versa.
    1306          28 :                 mpParam->mbRangeLookup = false;
    1307             :                 // Step back the last field advance if GetNext() did one.
    1308          28 :                 if (bAdvanceQuery && nColDiff)
    1309             :                 {
    1310          28 :                     SCSIZE nEntries = mpParam->GetEntryCount();
    1311          56 :                     for (SCSIZE j=0; j < nEntries; ++j)
    1312             :                     {
    1313          56 :                         ScQueryEntry& rEntry = mpParam->GetEntry( j );
    1314          56 :                         if (rEntry.bDoQuery)
    1315             :                         {
    1316          28 :                             if (rEntry.nField - nColDiff >= 0)
    1317          28 :                                 rEntry.nField -= nColDiff;
    1318             :                             else
    1319             :                             {
    1320             :                                 assert(!"FindEqualOrSortedLastInRange: rEntry.nField -= nColDiff < 0");
    1321             :                             }
    1322             :                         }
    1323             :                         else
    1324          28 :                             break;  // for
    1325             :                     }
    1326             :                 }
    1327             :                 // Check it.
    1328          28 :                 if (!GetThis())
    1329             :                 {
    1330           1 :                     nFoundCol = MAXCOL+1;
    1331           1 :                     nFoundRow = MAXROW+1;
    1332             :                 }
    1333             :             }
    1334             :         }
    1335             :     }
    1336          90 :     if ( IsEqualConditionFulfilled() )
    1337             :     {
    1338             :         // Position on last equal entry.
    1339           9 :         SCSIZE nEntries = mpParam->GetEntryCount();
    1340          36 :         for ( SCSIZE j = 0; j < nEntries; j++  )
    1341             :         {
    1342          18 :             ScQueryEntry& rEntry = mpParam->GetEntry( j );
    1343          18 :             if ( rEntry.bDoQuery )
    1344             :             {
    1345           9 :                 switch ( rEntry.eOp )
    1346             :                 {
    1347             :                     case SC_LESS_EQUAL :
    1348             :                     case SC_GREATER_EQUAL :
    1349           9 :                         rEntry.eOp = SC_EQUAL;
    1350           9 :                     break;
    1351             :                     default:
    1352             :                     {
    1353             :                         // added to avoid warnings
    1354             :                     }
    1355             :                 }
    1356             :             }
    1357             :             else
    1358           9 :                 break;  // for
    1359             :         }
    1360           9 :         PositionType aPosSave;
    1361           9 :         bIgnoreMismatchOnLeadingStrings = false;
    1362           9 :         SetTestEqualCondition( false );
    1363           9 :         do
    1364             :         {
    1365           9 :             nFoundCol = GetCol();
    1366           9 :             nFoundRow = GetRow();
    1367           9 :             aPosSave = maCurPos;
    1368             :         } while (GetNext());
    1369             : 
    1370             :         // Step back conditions are the same as above
    1371           9 :         nCol = nFoundCol;
    1372           9 :         nRow = nFoundRow;
    1373           9 :         maCurPos = aPosSave;
    1374           9 :         return true;
    1375             :     }
    1376          81 :     if ( (bSearchForEqualAfterMismatch || mpParam->bRegExp) &&
    1377           0 :             StoppedOnMismatch() )
    1378             :     {
    1379             :         // Assume found entry to be the last value less than respectively
    1380             :         // greater than the query. But keep on searching for an equal match.
    1381           0 :         SCSIZE nEntries = mpParam->GetEntryCount();
    1382           0 :         for ( SCSIZE j = 0; j < nEntries; j++  )
    1383             :         {
    1384           0 :             ScQueryEntry& rEntry = mpParam->GetEntry( j );
    1385           0 :             if ( rEntry.bDoQuery )
    1386             :             {
    1387           0 :                 switch ( rEntry.eOp )
    1388             :                 {
    1389             :                     case SC_LESS_EQUAL :
    1390             :                     case SC_GREATER_EQUAL :
    1391           0 :                         rEntry.eOp = SC_EQUAL;
    1392           0 :                     break;
    1393             :                     default:
    1394             :                     {
    1395             :                         // added to avoid warnings
    1396             :                     }
    1397             :                 }
    1398             :             }
    1399             :             else
    1400           0 :                 break;  // for
    1401             :         }
    1402           0 :         SetStopOnMismatch( false );
    1403           0 :         SetTestEqualCondition( false );
    1404           0 :         if (GetNext())
    1405             :         {
    1406             :             // Last of a consecutive area, avoid searching the entire parameter
    1407             :             // range as it is a real performance bottleneck in case of regular
    1408             :             // expressions.
    1409           0 :             PositionType aPosSave;
    1410           0 :             do
    1411             :             {
    1412           0 :                 nFoundCol = GetCol();
    1413           0 :                 nFoundRow = GetRow();
    1414           0 :                 aPosSave = maCurPos;
    1415           0 :                 SetStopOnMismatch( true );
    1416             :             } while (GetNext());
    1417           0 :             nCol = nFoundCol;
    1418           0 :             nRow = nFoundRow;
    1419           0 :             maCurPos = aPosSave;
    1420             :         }
    1421             :     }
    1422          81 :     return (nFoundCol <= MAXCOL) && (nFoundRow <= MAXROW);
    1423             : }
    1424             : 
    1425             : namespace {
    1426             : 
    1427             : /**
    1428             :  * This class sequentially indexes non-empty cells in order, from the top of
    1429             :  * the block where the start row position is, to the bottom of the block
    1430             :  * where the end row position is.  It skips all empty blocks that may be
    1431             :  * present in between.
    1432             :  *
    1433             :  * The index value is an offset from the first element of the first block
    1434             :  * disregarding all empty cell blocks.
    1435             :  */
    1436          59 : class NonEmptyCellIndexer
    1437             : {
    1438             :     typedef std::map<size_t, sc::CellStoreType::const_iterator> BlockMapType;
    1439             : 
    1440             :     BlockMapType maBlockMap;
    1441             : 
    1442             :     const sc::CellStoreType& mrCells;
    1443             : 
    1444             :     size_t mnLowIndex;
    1445             :     size_t mnHighIndex;
    1446             : 
    1447             :     bool mbValid;
    1448             : 
    1449             : public:
    1450             : 
    1451             :     typedef std::pair<ScRefCellValue, SCROW> CellType;
    1452             : 
    1453             :     /**
    1454             :      * @param rCells cell storage container
    1455             :      * @param nStartRow logical start row position
    1456             :      * @param nEndRow logical end row position, inclusive.
    1457             :      * @param bSkipTopStrBlock when true, skip all leading string cells.
    1458             :      */
    1459          59 :     NonEmptyCellIndexer(
    1460             :         const sc::CellStoreType& rCells, SCROW nStartRow, SCROW nEndRow, bool bSkipTopStrBlock ) :
    1461          59 :         mrCells(rCells), mnLowIndex(0), mnHighIndex(0), mbValid(true)
    1462             :     {
    1463          59 :         if (nEndRow < nStartRow)
    1464             :         {
    1465           0 :             mbValid = false;
    1466           0 :             return;
    1467             :         }
    1468             : 
    1469             :         // Find the low position.
    1470             : 
    1471          59 :         sc::CellStoreType::const_position_type aLoPos = mrCells.position(nStartRow);
    1472          59 :         if (aLoPos.first->type == sc::element_type_empty)
    1473           6 :             incBlock(aLoPos);
    1474             : 
    1475          59 :         if (aLoPos.first == rCells.end())
    1476             :         {
    1477           0 :             mbValid = false;
    1478           0 :             return;
    1479             :         }
    1480             : 
    1481          59 :         if (bSkipTopStrBlock)
    1482             :         {
    1483             :             // Skip all leading string or empty blocks.
    1484         180 :             while (aLoPos.first->type == sc::element_type_string ||
    1485          90 :                    aLoPos.first->type == sc::element_type_edittext ||
    1486          39 :                    aLoPos.first->type == sc::element_type_empty)
    1487             :             {
    1488          12 :                 incBlock(aLoPos);
    1489          12 :                 if (aLoPos.first == rCells.end())
    1490             :                 {
    1491           0 :                     mbValid = false;
    1492           0 :                     return;
    1493             :                 }
    1494             :             }
    1495             :         }
    1496             : 
    1497          59 :         SCROW nFirstRow = aLoPos.first->position;
    1498          59 :         SCROW nLastRow = aLoPos.first->position + aLoPos.first->size - 1;
    1499             : 
    1500          59 :         if (nFirstRow > nEndRow)
    1501             :         {
    1502             :             // Both start and end row positions are within the leading skipped
    1503             :             // blocks.
    1504           0 :             mbValid = false;
    1505           0 :             return;
    1506             :         }
    1507             : 
    1508             :         // Calculate the index of the low position.
    1509          59 :         if (nFirstRow < nStartRow)
    1510           1 :             mnLowIndex = nStartRow - nFirstRow;
    1511             :         else
    1512             :         {
    1513             :             // Start row is within the skipped block(s). Set it to the first
    1514             :             // element of the low block.
    1515          58 :             mnLowIndex = 0;
    1516             :         }
    1517             : 
    1518          59 :         if (nEndRow < nLastRow)
    1519             :         {
    1520             :             assert(nEndRow > nFirstRow);
    1521           0 :             mnHighIndex = nEndRow - nFirstRow;
    1522             : 
    1523           0 :             maBlockMap.insert(BlockMapType::value_type(aLoPos.first->size, aLoPos.first));
    1524           0 :             return;
    1525             :         }
    1526             : 
    1527             :         // Find the high position.
    1528             : 
    1529          59 :         sc::CellStoreType::const_position_type aHiPos = mrCells.position(aLoPos.first, nEndRow);
    1530          59 :         if (aHiPos.first->type == sc::element_type_empty)
    1531             :         {
    1532             :             // Move to the last position of the previous block.
    1533           3 :             decBlock(aHiPos);
    1534             : 
    1535             :             // Check the row postion of the end of the previous block, and make sure it's valid.
    1536           3 :             SCROW nBlockEndRow = aHiPos.first->position + aHiPos.first->size - 1;
    1537           3 :             if (nBlockEndRow < nStartRow)
    1538             :             {
    1539           0 :                 mbValid = false;
    1540           0 :                 return;
    1541             :             }
    1542             :         }
    1543             : 
    1544             :         // Tag the start and end blocks, and all blocks in between in order
    1545             :         // but skip all empty blocks.
    1546             : 
    1547          59 :         size_t nPos = 0;
    1548          59 :         sc::CellStoreType::const_iterator itBlk = aLoPos.first;
    1549         165 :         while (itBlk != aHiPos.first)
    1550             :         {
    1551          47 :             if (itBlk->type == sc::element_type_empty)
    1552             :             {
    1553           0 :                 ++itBlk;
    1554           0 :                 continue;
    1555             :             }
    1556             : 
    1557          47 :             nPos += itBlk->size;
    1558          47 :             maBlockMap.insert(BlockMapType::value_type(nPos, itBlk));
    1559          47 :             ++itBlk;
    1560             : 
    1561          47 :             if (itBlk->type == sc::element_type_empty)
    1562          10 :                 ++itBlk;
    1563             : 
    1564             :             assert(itBlk != mrCells.end());
    1565             :         }
    1566             : 
    1567             :         assert(itBlk == aHiPos.first);
    1568          59 :         nPos += itBlk->size;
    1569          59 :         maBlockMap.insert(BlockMapType::value_type(nPos, itBlk));
    1570             : 
    1571             :         // Calculate the high index.
    1572          59 :         BlockMapType::const_reverse_iterator ri = maBlockMap.rbegin();
    1573          59 :         mnHighIndex = ri->first;
    1574          59 :         mnHighIndex -= ri->second->size;
    1575          59 :         mnHighIndex += aHiPos.second;
    1576             :     }
    1577             : 
    1578         372 :     sc::CellStoreType::const_position_type getPosition( size_t nIndex ) const
    1579             :     {
    1580             :         assert(mbValid);
    1581             :         assert(mnLowIndex <= nIndex);
    1582             :         assert(nIndex <= mnHighIndex);
    1583             : 
    1584         372 :         sc::CellStoreType::const_position_type aRet(mrCells.end(), 0);
    1585             : 
    1586         372 :         BlockMapType::const_iterator it = maBlockMap.upper_bound(nIndex);
    1587         372 :         if (it == maBlockMap.end())
    1588           0 :             return aRet;
    1589             : 
    1590         372 :         sc::CellStoreType::const_iterator itBlk = it->second;
    1591         372 :         size_t nBlkIndex = it->first - itBlk->size; // index of the first element of the block.
    1592             :         assert(nBlkIndex <= nIndex);
    1593             :         assert(nIndex < it->first);
    1594             : 
    1595         372 :         size_t nOffset = nIndex - nBlkIndex;
    1596         372 :         aRet.first = itBlk;
    1597         372 :         aRet.second = nOffset;
    1598         372 :         return aRet;
    1599             :     }
    1600             : 
    1601         314 :     CellType getCell( size_t nIndex ) const
    1602             :     {
    1603         314 :         std::pair<ScRefCellValue, SCROW> aRet;
    1604         314 :         aRet.second = -1;
    1605             : 
    1606         314 :         sc::CellStoreType::const_position_type aPos = getPosition(nIndex);
    1607         314 :         if (aPos.first == mrCells.end())
    1608           0 :             return aRet;
    1609             : 
    1610         314 :         aRet.first = sc::toRefCell(aPos.first, aPos.second);
    1611         314 :         aRet.second = aPos.first->position + aPos.second;
    1612         314 :         return aRet;
    1613             :     }
    1614             : 
    1615          59 :     size_t getLowIndex() const { return mnLowIndex; }
    1616             : 
    1617          59 :     size_t getHighIndex() const { return mnHighIndex; }
    1618             : 
    1619          59 :     bool isValid() const { return mbValid; }
    1620             : };
    1621             : 
    1622             : }
    1623             : 
    1624          59 : bool ScQueryCellIterator::BinarySearch()
    1625             : {
    1626             :     // TODO: This will be extremely slow with mdds::multi_type_vector.
    1627             : 
    1628          59 :     if (nTab >= pDoc->GetTableCount())
    1629             :         OSL_FAIL("try to access index out of bounds, FIX IT");
    1630          59 :     nCol = mpParam->nCol1;
    1631          59 :     ScColumn* pCol = &(pDoc->maTabs[nTab])->aCol[nCol];
    1632          59 :     if (pCol->IsEmptyData())
    1633           0 :         return false;
    1634             : 
    1635          59 :     CollatorWrapper* pCollator = (mpParam->bCaseSens ? ScGlobal::GetCaseCollator() :
    1636          59 :         ScGlobal::GetCollator());
    1637          59 :     SvNumberFormatter& rFormatter = *(pDoc->GetFormatTable());
    1638          59 :     const ScQueryEntry& rEntry = mpParam->GetEntry(0);
    1639          59 :     const ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
    1640          59 :     bool bLessEqual = rEntry.eOp == SC_LESS_EQUAL;
    1641          59 :     bool bByString = rItem.meType == ScQueryEntry::ByString;
    1642          59 :     bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings && !bByString;
    1643          59 :     bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
    1644         118 :         !mpParam->bHasHeader && bByString;
    1645             : 
    1646          59 :     nRow = mpParam->nRow1;
    1647          59 :     if (mpParam->bHasHeader)
    1648           0 :         ++nRow;
    1649             : 
    1650          59 :     ScRefCellValue aCell;
    1651          59 :     if (bFirstStringIgnore)
    1652             :     {
    1653          20 :         sc::CellStoreType::const_position_type aPos = pCol->maCells.position(nRow);
    1654          20 :         if (aPos.first->type == sc::element_type_string || aPos.first->type == sc::element_type_edittext)
    1655             :         {
    1656           5 :             aCell = sc::toRefCell(aPos.first, aPos.second);
    1657           5 :             sal_uLong nFormat = pCol->GetNumberFormat(nRow);
    1658           5 :             OUString aCellStr;
    1659           5 :             ScCellFormat::GetInputString(aCell, nFormat, aCellStr, rFormatter, pDoc);
    1660           5 :             sal_Int32 nTmp = pCollator->compareString(aCellStr, rEntry.GetQueryItem().maString.getString());
    1661          10 :             if ((rEntry.eOp == SC_LESS_EQUAL && nTmp > 0) ||
    1662          13 :                     (rEntry.eOp == SC_GREATER_EQUAL && nTmp < 0) ||
    1663           4 :                     (rEntry.eOp == SC_EQUAL && nTmp != 0))
    1664           1 :                 ++nRow;
    1665             :         }
    1666             :     }
    1667             : 
    1668         118 :     NonEmptyCellIndexer aIndexer(pCol->maCells, nRow, mpParam->nRow2, bAllStringIgnore);
    1669          59 :     if (!aIndexer.isValid())
    1670           0 :         return false;
    1671             : 
    1672          59 :     size_t nLo = aIndexer.getLowIndex();
    1673          59 :     size_t nHi = aIndexer.getHighIndex();
    1674         118 :     NonEmptyCellIndexer::CellType aCellData;
    1675             : 
    1676             :     // Bookkeeping values for breaking up the binary search in case the data
    1677             :     // range isn't strictly sorted.
    1678          59 :     size_t nLastInRange = nLo;
    1679          59 :     size_t nFirstLastInRange = nLastInRange;
    1680             :     double fLastInRangeValue = bLessEqual ?
    1681          42 :         -(::std::numeric_limits<double>::max()) :
    1682         101 :             ::std::numeric_limits<double>::max();
    1683         118 :     OUString aLastInRangeString;
    1684          59 :     if (!bLessEqual)
    1685          17 :         aLastInRangeString = OUString(sal_Unicode(0xFFFF));
    1686             : 
    1687          59 :     aCellData = aIndexer.getCell(nLastInRange);
    1688          59 :     aCell = aCellData.first;
    1689          59 :     if (aCell.hasString())
    1690             :     {
    1691           8 :         sal_uLong nFormat = pCol->GetNumberFormat(aCellData.second);
    1692           8 :         OUString aStr;
    1693           8 :         ScCellFormat::GetInputString(aCell, nFormat, aStr, rFormatter, pDoc);
    1694           8 :         aLastInRangeString = aStr;
    1695             :     }
    1696             :     else
    1697             :     {
    1698          51 :         switch (aCell.meType)
    1699             :         {
    1700             :             case CELLTYPE_VALUE :
    1701          51 :                 fLastInRangeValue = aCell.mfValue;
    1702          51 :             break;
    1703             :             case CELLTYPE_FORMULA :
    1704           0 :                 fLastInRangeValue = aCell.mpFormula->GetValue();
    1705           0 :             break;
    1706             :             default:
    1707             :             {
    1708             :                 // added to avoid warnings
    1709             :             }
    1710             :         }
    1711             :     }
    1712             : 
    1713          59 :     sal_Int32 nRes = 0;
    1714          59 :     bool bFound = false;
    1715          59 :     bool bDone = false;
    1716         314 :     while (nLo <= nHi && !bDone)
    1717             :     {
    1718         196 :         size_t nMid = (nLo+nHi)/2;
    1719         196 :         size_t i = nMid;
    1720         196 :         if (i > nHi)
    1721             :         {
    1722           0 :             if (nMid > 0)
    1723           0 :                 nHi = nMid - 1;
    1724             :             else
    1725           0 :                 bDone = true;
    1726           0 :             continue; // while
    1727             :         }
    1728             : 
    1729         196 :         aCellData = aIndexer.getCell(i);
    1730         196 :         aCell = aCellData.first;
    1731         196 :         bool bStr = aCell.hasString();
    1732         196 :         nRes = 0;
    1733             : 
    1734             :         // compares are content<query:-1, content>query:1
    1735             :         // Cell value comparison similar to ScTable::ValidQuery()
    1736         196 :         if (!bStr && !bByString)
    1737             :         {
    1738             :             double nCellVal;
    1739         118 :             switch (aCell.meType)
    1740             :             {
    1741             :                 case CELLTYPE_VALUE :
    1742             :                 case CELLTYPE_FORMULA :
    1743         118 :                     nCellVal = aCell.getValue();
    1744         118 :                 break;
    1745             :                 default:
    1746           0 :                     nCellVal = 0.0;
    1747             :             }
    1748         172 :             if ((nCellVal < rItem.mfVal) && !::rtl::math::approxEqual(
    1749          54 :                         nCellVal, rItem.mfVal))
    1750             :             {
    1751          54 :                 nRes = -1;
    1752          54 :                 if (bLessEqual)
    1753             :                 {
    1754          39 :                     if (fLastInRangeValue < nCellVal)
    1755             :                     {
    1756          35 :                         fLastInRangeValue = nCellVal;
    1757          35 :                         nLastInRange = i;
    1758             :                     }
    1759           4 :                     else if (fLastInRangeValue > nCellVal)
    1760             :                     {
    1761             :                         // not strictly sorted, continue with GetThis()
    1762           0 :                         nLastInRange = nFirstLastInRange;
    1763           0 :                         bDone = true;
    1764             :                     }
    1765             :                 }
    1766             :             }
    1767         124 :             else if ((nCellVal > rItem.mfVal) && !::rtl::math::approxEqual(
    1768          60 :                         nCellVal, rItem.mfVal))
    1769             :             {
    1770          60 :                 nRes = 1;
    1771          60 :                 if (!bLessEqual)
    1772             :                 {
    1773          27 :                     if (fLastInRangeValue > nCellVal)
    1774             :                     {
    1775          26 :                         fLastInRangeValue = nCellVal;
    1776          26 :                         nLastInRange = i;
    1777             :                     }
    1778           1 :                     else if (fLastInRangeValue < nCellVal)
    1779             :                     {
    1780             :                         // not strictly sorted, continue with GetThis()
    1781           0 :                         nLastInRange = nFirstLastInRange;
    1782           0 :                         bDone = true;
    1783             :                     }
    1784             :                 }
    1785         118 :             }
    1786             :         }
    1787          78 :         else if (bStr && bByString)
    1788             :         {
    1789          46 :             OUString aCellStr;
    1790          46 :             sal_uLong nFormat = pCol->GetNumberFormat(aCellData.second);
    1791          46 :             ScCellFormat::GetInputString(aCell, nFormat, aCellStr, rFormatter, pDoc);
    1792             : 
    1793          46 :             nRes = pCollator->compareString(aCellStr, rEntry.GetQueryItem().maString.getString());
    1794          46 :             if (nRes < 0 && bLessEqual)
    1795             :             {
    1796             :                 sal_Int32 nTmp = pCollator->compareString( aLastInRangeString,
    1797          21 :                         aCellStr);
    1798          21 :                 if (nTmp < 0)
    1799             :                 {
    1800          20 :                     aLastInRangeString = aCellStr;
    1801          20 :                     nLastInRange = i;
    1802             :                 }
    1803           1 :                 else if (nTmp > 0)
    1804             :                 {
    1805             :                     // not strictly sorted, continue with GetThis()
    1806           0 :                     nLastInRange = nFirstLastInRange;
    1807           0 :                     bDone = true;
    1808          21 :                 }
    1809             :             }
    1810          25 :             else if (nRes > 0 && !bLessEqual)
    1811             :             {
    1812             :                 sal_Int32 nTmp = pCollator->compareString( aLastInRangeString,
    1813           4 :                         aCellStr);
    1814           4 :                 if (nTmp > 0)
    1815             :                 {
    1816           2 :                     aLastInRangeString = aCellStr;
    1817           2 :                     nLastInRange = i;
    1818             :                 }
    1819           2 :                 else if (nTmp < 0)
    1820             :                 {
    1821             :                     // not strictly sorted, continue with GetThis()
    1822           0 :                     nLastInRange = nFirstLastInRange;
    1823           0 :                     bDone = true;
    1824             :                 }
    1825          46 :             }
    1826             :         }
    1827          32 :         else if (!bStr && bByString)
    1828             :         {
    1829          20 :             nRes = -1; // numeric < string
    1830          40 :             if (bLessEqual)
    1831          14 :                 nLastInRange = i;
    1832             :         }
    1833             :         else // if (bStr && !bByString)
    1834             :         {
    1835          12 :             nRes = 1; // string > numeric
    1836          12 :             if (!bLessEqual)
    1837           0 :                 nLastInRange = i;
    1838             :         }
    1839         196 :         if (nRes < 0)
    1840             :         {
    1841          99 :             if (bLessEqual)
    1842          74 :                 nLo = nMid + 1;
    1843             :             else // assumed to be SC_GREATER_EQUAL
    1844             :             {
    1845          25 :                 if (nMid > 0)
    1846          24 :                     nHi = nMid - 1;
    1847             :                 else
    1848           1 :                     bDone = true;
    1849             :             }
    1850             :         }
    1851          97 :         else if (nRes > 0)
    1852             :         {
    1853          88 :             if (bLessEqual)
    1854             :             {
    1855          57 :                 if (nMid > 0)
    1856          56 :                     nHi = nMid - 1;
    1857             :                 else
    1858           1 :                     bDone = true;
    1859             :             }
    1860             :             else // assumed to be SC_GREATER_EQUAL
    1861          31 :                 nLo = nMid + 1;
    1862             :         }
    1863             :         else
    1864             :         {
    1865           9 :             nLo = i;
    1866           9 :             bDone = bFound = true;
    1867             :         }
    1868             :     }
    1869             : 
    1870          59 :     if (!bFound)
    1871             :     {
    1872             :         // If all hits didn't result in a moving limit there's something
    1873             :         // strange, e.g. data range not properly sorted, or only identical
    1874             :         // values encountered, which doesn't mean there aren't any others in
    1875             :         // between.. leave it to GetThis(). The condition for this would be
    1876             :         // if (nLastInRange == nFirstLastInRange) nLo = nFirstLastInRange;
    1877             :         // Else, in case no exact match was found, we step back for a
    1878             :         // subsequent GetThis() to find the last in range. Effectively this is
    1879             :         // --nLo with nLastInRange == nLo-1. Both conditions combined yield:
    1880          50 :         nLo = nLastInRange;
    1881             :     }
    1882             : 
    1883          59 :     aCellData = aIndexer.getCell(nLo);
    1884          59 :     if (nLo <= nHi && aCellData.second <= mpParam->nRow2)
    1885             :     {
    1886          58 :         nRow = aCellData.second;
    1887          58 :         maCurPos = aIndexer.getPosition(nLo);
    1888          58 :         return true;
    1889             :     }
    1890             :     else
    1891             :     {
    1892           1 :         nRow = mpParam->nRow2 + 1;
    1893             :         // Set current position to the last possible row.
    1894           1 :         maCurPos.first = pCol->maCells.end();
    1895           1 :         --maCurPos.first;
    1896           1 :         maCurPos.second = maCurPos.first->size - 1;
    1897           1 :         return false;
    1898          59 :     }
    1899             : }
    1900             : 
    1901             : 
    1902         719 : ScHorizontalCellIterator::ScHorizontalCellIterator(ScDocument* pDocument, SCTAB nTable,
    1903             :                                     SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
    1904             :     pDoc( pDocument ),
    1905             :     mnTab( nTable ),
    1906             :     nStartCol( nCol1 ),
    1907             :     nEndCol( nCol2 ),
    1908             :     nStartRow( nRow1 ),
    1909             :     nEndRow( nRow2 ),
    1910             :     mnCol( nCol1 ),
    1911             :     mnRow( nRow1 ),
    1912         719 :     mbMore( false )
    1913             : {
    1914         719 :     if (mnTab >= pDoc->GetTableCount())
    1915             :         OSL_FAIL("try to access index out of bounds, FIX IT");
    1916             : 
    1917         719 :     pNextRows = new SCROW[ nCol2-nCol1+1 ];
    1918         719 :     pNextIndices = new SCSIZE[ nCol2-nCol1+1 ];
    1919         719 :     maColPositions.reserve( nCol2-nCol1+1 );
    1920             : 
    1921         719 :     SetTab( mnTab );
    1922         719 : }
    1923             : 
    1924        1438 : ScHorizontalCellIterator::~ScHorizontalCellIterator()
    1925             : {
    1926         719 :     delete [] pNextRows;
    1927         719 :     delete [] pNextIndices;
    1928         719 : }
    1929             : 
    1930         719 : void ScHorizontalCellIterator::SetTab( SCTAB nTabP )
    1931             : {
    1932         719 :     mbMore = false;
    1933         719 :     mnTab = nTabP;
    1934         719 :     mnRow = nStartRow;
    1935         719 :     mnCol = nStartCol;
    1936         719 :     maColPositions.resize(0);
    1937             : 
    1938             :     // Set the start position in each column.
    1939       39257 :     for (SCCOL i = nStartCol; i <= nEndCol; ++i)
    1940             :     {
    1941       38538 :         ScColumn* pCol = &pDoc->maTabs[mnTab]->aCol[i];
    1942       38538 :         ColParam aParam;
    1943       38538 :         aParam.maPos = pCol->maCells.position(nStartRow).first;
    1944       38538 :         aParam.maEnd = pCol->maCells.end();
    1945       38538 :         aParam.mnCol = i;
    1946             : 
    1947             :         // find first non-empty element.
    1948      114126 :         while (aParam.maPos != aParam.maEnd) {
    1949       39770 :             if (aParam.maPos->type == sc::element_type_empty)
    1950       37050 :                 ++aParam.maPos;
    1951             :             else
    1952             :             {
    1953        2720 :                 maColPositions.push_back( aParam );
    1954        2720 :                 break;
    1955             :             }
    1956             :         }
    1957             :     }
    1958             : 
    1959         719 :     if (maColPositions.size() == 0)
    1960         989 :         return;
    1961             : 
    1962         449 :     maColPos = maColPositions.begin();
    1963         449 :     mbMore = true;
    1964         449 :     SkipInvalid();
    1965             : }
    1966             : 
    1967        3574 : ScRefCellValue* ScHorizontalCellIterator::GetNext( SCCOL& rCol, SCROW& rRow )
    1968             : {
    1969        3574 :     if (!mbMore)
    1970             :     {
    1971             :         debugiter("no more !\n");
    1972         348 :         return NULL;
    1973             :     }
    1974             : 
    1975             :     // Return the current non-empty cell, and move the cursor to the next one.
    1976        3226 :     ColParam& r = *maColPos;
    1977             : 
    1978        3226 :     rCol = mnCol = r.mnCol;
    1979        3226 :     rRow = mnRow;
    1980             :     debugiter("return col %d row %d\n", (int)rCol, (int)rRow);
    1981             : 
    1982        3226 :     size_t nOffset = static_cast<size_t>(mnRow) - r.maPos->position;
    1983        3226 :     maCurCell = sc::toRefCell(r.maPos, nOffset);
    1984        3226 :     Advance();
    1985             :     debugiter("advance to: col %d row %d\n", (int)maColPos->mnCol, (int)mnRow);
    1986             : 
    1987        3226 :     return &maCurCell;
    1988             : }
    1989             : 
    1990         335 : bool ScHorizontalCellIterator::GetPos( SCCOL& rCol, SCROW& rRow )
    1991             : {
    1992         335 :     rCol = mnCol;
    1993         335 :     rRow = mnRow;
    1994         335 :     return mbMore;
    1995             : }
    1996             : 
    1997             : // Skip any invalid / empty cells across the current row,
    1998             : // we only advance the cursor if the current entry is invalid.
    1999             : // if we return true we have a valid cursor (or hit the end)
    2000        4255 : bool ScHorizontalCellIterator::SkipInvalidInRow()
    2001             : {
    2002             :     assert (mbMore);
    2003             :     assert (maColPos != maColPositions.end());
    2004             : 
    2005             :     // Find the next non-empty cell in the current row.
    2006       13617 :     while( maColPos != maColPositions.end() )
    2007             :     {
    2008        8681 :         ColParam& r = *maColPos;
    2009             :         assert (r.maPos != r.maEnd);
    2010             : 
    2011        8681 :         size_t nRow = static_cast<size_t>(mnRow);
    2012             : 
    2013        8681 :         if (nRow >= r.maPos->position)
    2014             :         {
    2015        4247 :             if (nRow < r.maPos->position + r.maPos->size)
    2016             :             {
    2017        3574 :                 mnCol = maColPos->mnCol;
    2018             :                 debugiter("found valid cell at column %d, row %d\n",
    2019             :                           (int)mnCol, (int)mnRow);
    2020             :                 assert(r.maPos->type != sc::element_type_empty);
    2021        3574 :                 return true;
    2022             :             }
    2023             :             else
    2024             :             {
    2025         673 :                 bool bMoreBlocksInColumn = false;
    2026             :                 // This block is behind the current row position. Advance the block.
    2027        1229 :                 for (++r.maPos; r.maPos != r.maEnd; ++r.maPos)
    2028             :                 {
    2029        2064 :                     if (nRow < r.maPos->position + r.maPos->size &&
    2030        1032 :                         r.maPos->type != sc::element_type_empty)
    2031             :                     {
    2032         476 :                         bMoreBlocksInColumn = true;
    2033         476 :                         break;
    2034             :                     }
    2035             :                 }
    2036         673 :                 if (!bMoreBlocksInColumn)
    2037             :                 {
    2038             :                     debugiter("remove column %d at row %d\n",
    2039             :                               (int)maColPos->mnCol, (int)nRow);
    2040         197 :                     maColPos = maColPositions.erase(maColPos);
    2041         197 :                     if (maColPositions.size() == 0)
    2042             :                     {
    2043             :                         debugiter("no more columns\n");
    2044          46 :                         mbMore = false;
    2045             :                     }
    2046             :                 }
    2047             :                 else
    2048             :                 {
    2049             :                     debugiter("advanced column %d to block starting row %d, retying\n",
    2050             :                               (int)maColPos->mnCol, r.maPos->position);
    2051             :                 }
    2052             :             }
    2053             :         }
    2054             :         else
    2055             :         {
    2056             :             debugiter("skip empty cells at column %d, row %d\n",
    2057             :                       (int)maColPos->mnCol, (int)nRow);
    2058        4434 :             maColPos++;
    2059             :         }
    2060             :     }
    2061             : 
    2062             :     // No more columns with anything interesting in them ?
    2063         681 :     if (maColPositions.size() == 0)
    2064             :     {
    2065             :         debugiter("no more live columns left - done\n");
    2066          46 :         mbMore = false;
    2067          46 :         return true;
    2068             :     }
    2069             : 
    2070         635 :     return false;
    2071             : }
    2072             : 
    2073             : /// Find the next row that has some real content in one of it's columns.
    2074         211 : SCROW ScHorizontalCellIterator::FindNextNonEmptyRow()
    2075             : {
    2076         211 :     size_t nNextRow = MAXROW+1;
    2077             : 
    2078        4260 :     for (std::vector<ColParam>::iterator it = maColPositions.begin();
    2079        2840 :          it != maColPositions.end(); ++it)
    2080             :     {
    2081        1209 :         ColParam& r = *it;
    2082             : 
    2083             :         assert(static_cast<size_t>(mnRow) <= r.maPos->position);
    2084        1209 :         nNextRow = std::min (nNextRow, static_cast<size_t>(r.maPos->position));
    2085             :     }
    2086             : 
    2087         211 :     SCROW nRow = std::max(static_cast<SCROW>(nNextRow), mnRow);
    2088             :     debugiter("Next non empty row is %d\n", (int) nRow);
    2089         211 :     return nRow;
    2090             : }
    2091             : 
    2092        3226 : void ScHorizontalCellIterator::Advance()
    2093             : {
    2094             :     assert (mbMore);
    2095             :     assert (maColPos != maColPositions.end());
    2096             : 
    2097        3226 :     maColPos++;
    2098             : 
    2099        3226 :     SkipInvalid();
    2100        3226 : }
    2101             : 
    2102        3675 : void ScHorizontalCellIterator::SkipInvalid()
    2103             : {
    2104        6781 :     if (maColPos == maColPositions.end() ||
    2105        3106 :         !SkipInvalidInRow())
    2106             :     {
    2107         993 :         mnRow++;
    2108             : 
    2109         993 :         if (mnRow > nEndRow)
    2110             :         {
    2111          55 :             mbMore = false;
    2112          55 :             return;
    2113             :         }
    2114             : 
    2115         938 :         maColPos = maColPositions.begin();
    2116             :         debugiter("moving to next row\n");
    2117         938 :         if (SkipInvalidInRow())
    2118             :         {
    2119             :             debugiter("moved to valid cell in next row (or end)\n");
    2120         727 :             return;
    2121             :         }
    2122             : 
    2123         211 :         mnRow = FindNextNonEmptyRow();
    2124         211 :         maColPos = maColPositions.begin();
    2125         211 :         bool bCorrect = SkipInvalidInRow();
    2126             :         assert (bCorrect); (void) bCorrect;
    2127             :     }
    2128             : 
    2129        2893 :     if (mnRow > nEndRow)
    2130          17 :         mbMore = false;
    2131             : }
    2132             : 
    2133           0 : ScHorizontalValueIterator::ScHorizontalValueIterator( ScDocument* pDocument,
    2134             :         const ScRange& rRange, bool bSTotal, bool bTextZero ) :
    2135             :     pDoc( pDocument ),
    2136             :     nNumFmtIndex(0),
    2137           0 :     nEndTab( rRange.aEnd.Tab() ),
    2138             :     nNumFmtType( NUMBERFORMAT_UNDEFINED ),
    2139             :     bNumValid( false ),
    2140             :     bSubTotal( bSTotal ),
    2141           0 :     bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ),
    2142           0 :     bTextAsZero( bTextZero )
    2143             : {
    2144           0 :     SCCOL nStartCol = rRange.aStart.Col();
    2145           0 :     SCROW nStartRow = rRange.aStart.Row();
    2146           0 :     SCTAB nStartTab = rRange.aStart.Tab();
    2147           0 :     SCCOL nEndCol = rRange.aEnd.Col();
    2148           0 :     SCROW nEndRow = rRange.aEnd.Row();
    2149           0 :     PutInOrder( nStartCol, nEndCol);
    2150           0 :     PutInOrder( nStartRow, nEndRow);
    2151           0 :     PutInOrder( nStartTab, nEndTab );
    2152             : 
    2153           0 :     if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
    2154           0 :     if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
    2155           0 :     if (!ValidRow(nStartRow)) nStartRow = MAXROW;
    2156           0 :     if (!ValidRow(nEndRow)) nEndRow = MAXROW;
    2157           0 :     if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
    2158           0 :     if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
    2159             : 
    2160           0 :     nCurCol = nStartCol;
    2161           0 :     nCurRow = nStartRow;
    2162           0 :     nCurTab = nStartTab;
    2163             : 
    2164           0 :     nNumFormat = 0; // Will be initialized in GetNumberFormat()
    2165           0 :     pAttrArray = 0;
    2166           0 :     nAttrEndRow = 0;
    2167             : 
    2168             :     pCellIter = new ScHorizontalCellIterator( pDoc, nStartTab, nStartCol,
    2169           0 :             nStartRow, nEndCol, nEndRow );
    2170           0 : }
    2171             : 
    2172           0 : ScHorizontalValueIterator::~ScHorizontalValueIterator()
    2173             : {
    2174           0 :     delete pCellIter;
    2175           0 : }
    2176             : 
    2177           0 : bool ScHorizontalValueIterator::GetNext( double& rValue, sal_uInt16& rErr )
    2178             : {
    2179           0 :     bool bFound = false;
    2180           0 :     while ( !bFound )
    2181             :     {
    2182           0 :         ScRefCellValue* pCell = pCellIter->GetNext( nCurCol, nCurRow );
    2183           0 :         while ( !pCell )
    2184             :         {
    2185           0 :             if ( nCurTab < nEndTab )
    2186             :             {
    2187           0 :                 pCellIter->SetTab( ++nCurTab);
    2188           0 :                 pCell = pCellIter->GetNext( nCurCol, nCurRow );
    2189             :             }
    2190             :             else
    2191           0 :                 return false;
    2192             :         }
    2193           0 :         if ( !bSubTotal || !pDoc->maTabs[nCurTab]->RowFiltered( nCurRow ) )
    2194             :         {
    2195           0 :             switch (pCell->meType)
    2196             :             {
    2197             :                 case CELLTYPE_VALUE:
    2198             :                     {
    2199           0 :                         bNumValid = false;
    2200           0 :                         rValue = pCell->mfValue;
    2201           0 :                         rErr = 0;
    2202           0 :                         if ( bCalcAsShown )
    2203             :                         {
    2204           0 :                             ScColumn* pCol = &pDoc->maTabs[nCurTab]->aCol[nCurCol];
    2205             :                             ScAttrArray_IterGetNumberFormat( nNumFormat, pAttrArray,
    2206           0 :                                     nAttrEndRow, pCol->pAttrArray, nCurRow, pDoc );
    2207           0 :                             rValue = pDoc->RoundValueAsShown( rValue, nNumFormat );
    2208             :                         }
    2209           0 :                         bFound = true;
    2210             :                     }
    2211           0 :                     break;
    2212             :                 case CELLTYPE_FORMULA:
    2213             :                     {
    2214           0 :                         if (!bSubTotal || !pCell->mpFormula->IsSubTotal())
    2215             :                         {
    2216           0 :                             rErr = pCell->mpFormula->GetErrCode();
    2217           0 :                             if (rErr || pCell->mpFormula->IsValue())
    2218             :                             {
    2219           0 :                                 rValue = pCell->mpFormula->GetValue();
    2220           0 :                                 bNumValid = false;
    2221           0 :                                 bFound = true;
    2222             :                             }
    2223           0 :                             else if ( bTextAsZero )
    2224             :                             {
    2225           0 :                                 rValue = 0.0;
    2226           0 :                                 bNumValid = false;
    2227           0 :                                 bFound = true;
    2228             :                             }
    2229             :                         }
    2230             :                     }
    2231           0 :                     break;
    2232             :                 case CELLTYPE_STRING :
    2233             :                 case CELLTYPE_EDIT :
    2234             :                     {
    2235           0 :                         if ( bTextAsZero )
    2236             :                         {
    2237           0 :                             rErr = 0;
    2238           0 :                             rValue = 0.0;
    2239           0 :                             nNumFmtType = NUMBERFORMAT_NUMBER;
    2240           0 :                             nNumFmtIndex = 0;
    2241           0 :                             bNumValid = true;
    2242           0 :                             bFound = true;
    2243             :                         }
    2244             :                     }
    2245           0 :                     break;
    2246             :                 default: ;   // nothing
    2247             :             }
    2248             :         }
    2249             :     }
    2250           0 :     return bFound;
    2251             : }
    2252             : 
    2253          44 : ScHorizontalAttrIterator::ScHorizontalAttrIterator( ScDocument* pDocument, SCTAB nTable,
    2254             :                             SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
    2255             :     pDoc( pDocument ),
    2256             :     nTab( nTable ),
    2257             :     nStartCol( nCol1 ),
    2258             :     nStartRow( nRow1 ),
    2259             :     nEndCol( nCol2 ),
    2260          44 :     nEndRow( nRow2 )
    2261             : {
    2262          44 :     if (nTab >= pDoc->GetTableCount())
    2263             :         OSL_FAIL("try to access index out of bounds, FIX IT");
    2264             :     OSL_ENSURE( pDoc->maTabs[nTab], "Table does not exist" );
    2265             : 
    2266             :     SCCOL i;
    2267             : 
    2268          44 :     nRow = nStartRow;
    2269          44 :     nCol = nStartCol;
    2270          44 :     bRowEmpty = false;
    2271             : 
    2272          44 :     pIndices    = new SCSIZE[nEndCol-nStartCol+1];
    2273          44 :     pNextEnd    = new SCROW[nEndCol-nStartCol+1];
    2274          44 :     ppPatterns  = new const ScPatternAttr*[nEndCol-nStartCol+1];
    2275             : 
    2276          44 :     SCROW nSkipTo = MAXROW;
    2277          44 :     bool bEmpty = true;
    2278       30508 :     for (i=nStartCol; i<=nEndCol; i++)
    2279             :     {
    2280       30464 :         SCCOL nPos = i - nStartCol;
    2281       30464 :         const ScAttrArray* pArray = pDoc->maTabs[nTab]->aCol[i].pAttrArray;
    2282             :         OSL_ENSURE( pArray, "pArray == 0" );
    2283             : 
    2284             :         SCSIZE nIndex;
    2285       30464 :         pArray->Search( nStartRow, nIndex );
    2286             : 
    2287       30464 :         const ScPatternAttr* pPattern = pArray->pData[nIndex].pPattern;
    2288       30464 :         SCROW nThisEnd = pArray->pData[nIndex].nRow;
    2289       30464 :         if ( IsDefaultItem( pPattern ) )
    2290             :         {
    2291       28124 :             pPattern = NULL;
    2292       28124 :             if ( nThisEnd < nSkipTo )
    2293          12 :                 nSkipTo = nThisEnd; // nSkipTo can be set here already
    2294             :         }
    2295             :         else
    2296        2340 :             bEmpty = false; // Found attributes
    2297             : 
    2298       30464 :         pIndices[nPos] = nIndex;
    2299       30464 :         pNextEnd[nPos] = nThisEnd;
    2300       30464 :         ppPatterns[nPos] = pPattern;
    2301             :     }
    2302             : 
    2303          44 :     if (bEmpty)
    2304          31 :         nRow = nSkipTo; // Skip until end of next section
    2305             : 
    2306          44 :     bRowEmpty = bEmpty;
    2307          44 : }
    2308             : 
    2309          44 : ScHorizontalAttrIterator::~ScHorizontalAttrIterator()
    2310             : {
    2311          44 :     delete[] ppPatterns;
    2312          44 :     delete[] pNextEnd;
    2313          44 :     delete[] pIndices;
    2314          44 : }
    2315             : 
    2316         515 : const ScPatternAttr* ScHorizontalAttrIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2, SCROW& rRow )
    2317             : {
    2318         515 :     if (nTab >= pDoc->GetTableCount())
    2319             :         OSL_FAIL("try to access index out of bounds, FIX IT");
    2320             :     for (;;)
    2321             :     {
    2322         647 :         if (!bRowEmpty)
    2323             :         {
    2324             :             // Search in this row
    2325       68712 :             while ( nCol <= nEndCol && !ppPatterns[nCol-nStartCol] )
    2326       67492 :                 ++nCol;
    2327             : 
    2328         610 :             if ( nCol <= nEndCol )
    2329             :             {
    2330         471 :                 const ScPatternAttr* pPat = ppPatterns[nCol-nStartCol];
    2331         471 :                 rRow = nRow;
    2332         471 :                 rCol1 = nCol;
    2333       17715 :                 while ( nCol < nEndCol && ppPatterns[nCol+1-nStartCol] == pPat )
    2334       16773 :                     ++nCol;
    2335         471 :                 rCol2 = nCol;
    2336         471 :                 ++nCol; // Count up for next call
    2337         471 :                 return pPat; // Found it!
    2338             :             }
    2339             :         }
    2340             : 
    2341             :         // Next row
    2342         176 :         ++nRow;
    2343         176 :         if ( nRow > nEndRow ) // Already at the end?
    2344          44 :             return NULL; // Found nothing
    2345             : 
    2346         132 :         bool bEmpty = true;
    2347             :         SCCOL i;
    2348             : 
    2349       80772 :         for ( i = nStartCol; i <= nEndCol; i++)
    2350             :         {
    2351       80640 :             SCCOL nPos = i-nStartCol;
    2352       80640 :             if ( pNextEnd[nPos] < nRow )
    2353             :             {
    2354        1433 :                 const ScAttrArray* pArray = pDoc->maTabs[nTab]->aCol[i].pAttrArray;
    2355             : 
    2356        1433 :                 SCSIZE nIndex = ++pIndices[nPos];
    2357        1433 :                 if ( nIndex < pArray->nCount )
    2358             :                 {
    2359        1433 :                     const ScPatternAttr* pPattern = pArray->pData[nIndex].pPattern;
    2360        1433 :                     SCROW nThisEnd = pArray->pData[nIndex].nRow;
    2361        1433 :                     if ( IsDefaultItem( pPattern ) )
    2362         281 :                         pPattern = NULL;
    2363             :                     else
    2364        1152 :                         bEmpty = false; // Found attributes
    2365             : 
    2366        1433 :                     pNextEnd[nPos] = nThisEnd;
    2367        1433 :                     ppPatterns[nPos] = pPattern;
    2368             : 
    2369             :                     OSL_ENSURE( pNextEnd[nPos] >= nRow, "Sequence out of order" );
    2370             :                 }
    2371             :                 else
    2372             :                 {
    2373             :                     OSL_FAIL("AttrArray does not range to MAXROW");
    2374           0 :                     pNextEnd[nPos] = MAXROW;
    2375           0 :                     ppPatterns[nPos] = NULL;
    2376             :                 }
    2377             :             }
    2378       79207 :             else if ( ppPatterns[nPos] )
    2379       13752 :                 bEmpty = false; // Area not at the end yet
    2380             :         }
    2381             : 
    2382         132 :         if (bEmpty)
    2383             :         {
    2384           6 :             SCCOL nCount = nEndCol-nStartCol+1;
    2385           6 :             SCROW nSkipTo = pNextEnd[0]; // Search next end of area
    2386        4608 :             for (i=1; i<nCount; i++)
    2387        4602 :                 if ( pNextEnd[i] < nSkipTo )
    2388           2 :                     nSkipTo = pNextEnd[i];
    2389           6 :             nRow = nSkipTo; // Skip empty rows
    2390             :         }
    2391         132 :         bRowEmpty = bEmpty;
    2392         132 :         nCol = nStartCol; // Start at the left again
    2393         132 :     }
    2394             : }
    2395             : 
    2396        2091 : inline bool IsGreater( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
    2397             : {
    2398        2091 :     return ( nRow1 > nRow2 ) || ( nRow1 == nRow2 && nCol1 > nCol2 );
    2399             : }
    2400             : 
    2401          44 : ScUsedAreaIterator::ScUsedAreaIterator( ScDocument* pDocument, SCTAB nTable,
    2402             :                             SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
    2403             :     : aCellIter( pDocument, nTable, nCol1, nRow1, nCol2, nRow2 )
    2404             :     , aAttrIter( pDocument, nTable, nCol1, nRow1, nCol2, nRow2 )
    2405             :     , nNextCol( nCol1 )
    2406             :     , nNextRow( nRow1 )
    2407             :     , nFoundStartCol( 0 )
    2408             :     , nFoundEndCol( 0 )
    2409             :     , nFoundRow( 0 )
    2410          44 :     , pFoundPattern( NULL )
    2411             : {
    2412          44 :     pCell    = aCellIter.GetNext( nCellCol, nCellRow );
    2413          44 :     pPattern = aAttrIter.GetNext( nAttrCol1, nAttrCol2, nAttrRow );
    2414          44 : }
    2415             : 
    2416          44 : ScUsedAreaIterator::~ScUsedAreaIterator()
    2417             : {
    2418          44 : }
    2419             : 
    2420         835 : bool ScUsedAreaIterator::GetNext()
    2421             : {
    2422             :     //  Forward iterators
    2423         835 :     if ( pCell && IsGreater( nNextCol, nNextRow, nCellCol, nCellRow ) )
    2424         544 :         pCell = aCellIter.GetNext( nCellCol, nCellRow );
    2425             : 
    2426        1670 :     while (pCell && pCell->isEmpty())
    2427           0 :         pCell = aCellIter.GetNext( nCellCol, nCellRow );
    2428             : 
    2429         835 :     if ( pPattern && IsGreater( nNextCol, nNextRow, nAttrCol2, nAttrRow ) )
    2430         471 :         pPattern = aAttrIter.GetNext( nAttrCol1, nAttrCol2, nAttrRow );
    2431             : 
    2432         835 :     if ( pPattern && nAttrRow == nNextRow && nAttrCol1 < nNextCol )
    2433         115 :         nAttrCol1 = nNextCol;
    2434             : 
    2435             :     // Find next area
    2436         835 :     bool bFound = true;
    2437         835 :     bool bUseCell = false;
    2438             : 
    2439         835 :     if ( pCell && pPattern )
    2440             :     {
    2441        1252 :         if ( IsGreater( nCellCol, nCellRow, nAttrCol1, nAttrRow ) ) // Only attributes at the beginning?
    2442             :         {
    2443         242 :             maFoundCell.clear();
    2444         242 :             pFoundPattern = pPattern;
    2445         242 :             nFoundRow = nAttrRow;
    2446         242 :             nFoundStartCol = nAttrCol1;
    2447         242 :             if ( nCellRow == nAttrRow && nCellCol <= nAttrCol2 ) // Area also contains cell?
    2448          43 :                 nFoundEndCol = nCellCol - 1; // Only until right before the cell
    2449             :             else
    2450         199 :                 nFoundEndCol = nAttrCol2; // Everything
    2451             :         }
    2452             :         else
    2453             :         {
    2454         384 :             bUseCell = true;
    2455         384 :             if ( nAttrRow == nCellRow && nAttrCol1 == nCellCol ) // Attributes on the cell?
    2456         339 :                 pFoundPattern = pPattern;
    2457             :             else
    2458          45 :                 pFoundPattern = NULL;
    2459             :         }
    2460             :     }
    2461         209 :     else if ( pCell ) // Just a cell -> take over right away
    2462             :     {
    2463         160 :         pFoundPattern = NULL;
    2464         160 :         bUseCell = true; // Cell position
    2465             :     }
    2466          49 :     else if ( pPattern ) // Just attributes -> take over right away
    2467             :     {
    2468           5 :         maFoundCell.clear();
    2469           5 :         pFoundPattern = pPattern;
    2470           5 :         nFoundRow = nAttrRow;
    2471           5 :         nFoundStartCol = nAttrCol1;
    2472           5 :         nFoundEndCol = nAttrCol2;
    2473             :     }
    2474             :     else // Nothing
    2475          44 :         bFound = false;
    2476             : 
    2477         835 :     if ( bUseCell ) // Cell position
    2478             :     {
    2479         544 :         if (pCell)
    2480         544 :             maFoundCell = *pCell;
    2481             :         else
    2482           0 :             maFoundCell.clear();
    2483             : 
    2484         544 :         nFoundRow = nCellRow;
    2485         544 :         nFoundStartCol = nFoundEndCol = nCellCol;
    2486             :     }
    2487             : 
    2488         835 :     if (bFound)
    2489             :     {
    2490         791 :         nNextRow = nFoundRow;
    2491         791 :         nNextCol = nFoundEndCol + 1;
    2492             :     }
    2493             : 
    2494         835 :     return bFound;
    2495             : }
    2496             : 
    2497         791 : const ScRefCellValue& ScUsedAreaIterator::GetCell() const
    2498             : {
    2499         791 :     return maFoundCell;
    2500             : }
    2501             : 
    2502      362578 : ScDocAttrIterator::ScDocAttrIterator(ScDocument* pDocument, SCTAB nTable,
    2503             :                                     SCCOL nCol1, SCROW nRow1,
    2504             :                                     SCCOL nCol2, SCROW nRow2) :
    2505             :     pDoc( pDocument ),
    2506             :     nTab( nTable ),
    2507             :     nEndCol( nCol2 ),
    2508             :     nStartRow( nRow1 ),
    2509             :     nEndRow( nRow2 ),
    2510      362578 :     nCol( nCol1 )
    2511             : {
    2512      362578 :     if ( ValidTab(nTab) && nTab < pDoc->GetTableCount() && pDoc->maTabs[nTab] )
    2513      362578 :         pColIter = pDoc->maTabs[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow );
    2514             :     else
    2515           0 :         pColIter = NULL;
    2516      362578 : }
    2517             : 
    2518      362578 : ScDocAttrIterator::~ScDocAttrIterator()
    2519             : {
    2520      362578 :     delete pColIter;
    2521      362578 : }
    2522             : 
    2523      725354 : const ScPatternAttr* ScDocAttrIterator::GetNext( SCCOL& rCol, SCROW& rRow1, SCROW& rRow2 )
    2524             : {
    2525     1812204 :     while ( pColIter )
    2526             :     {
    2527      726377 :         const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 );
    2528      726377 :         if ( pPattern )
    2529             :         {
    2530      364881 :             rCol = nCol;
    2531      364881 :             return pPattern;
    2532             :         }
    2533             : 
    2534      361496 :         delete pColIter;
    2535      361496 :         ++nCol;
    2536      361496 :         if ( nCol <= nEndCol )
    2537        1023 :             pColIter = pDoc->maTabs[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow );
    2538             :         else
    2539      360473 :             pColIter = NULL;
    2540             :     }
    2541      360473 :     return NULL;  // Nothing anymore
    2542             : }
    2543             : 
    2544           0 : ScDocRowHeightUpdater::TabRanges::TabRanges(SCTAB nTab) :
    2545           0 :     mnTab(nTab), mpRanges(new ScFlatBoolRowSegments)
    2546             : {
    2547           0 : }
    2548             : 
    2549           8 : ScDocRowHeightUpdater::ScDocRowHeightUpdater(ScDocument& rDoc, OutputDevice* pOutDev, double fPPTX, double fPPTY, const vector<TabRanges>* pTabRangesArray) :
    2550           8 :     mrDoc(rDoc), mpOutDev(pOutDev), mfPPTX(fPPTX), mfPPTY(fPPTY), mpTabRangesArray(pTabRangesArray)
    2551             : {
    2552           8 : }
    2553             : 
    2554           8 : void ScDocRowHeightUpdater::update()
    2555             : {
    2556           8 :     if (!mpTabRangesArray || mpTabRangesArray->empty())
    2557             :     {
    2558             :         // No ranges defined. Update all rows in all tables.
    2559           8 :         updateAll();
    2560          16 :         return;
    2561             :     }
    2562             : 
    2563           0 :     sal_uInt32 nCellCount = 0;
    2564           0 :     vector<TabRanges>::const_iterator itr = mpTabRangesArray->begin(), itrEnd = mpTabRangesArray->end();
    2565           0 :     for (; itr != itrEnd; ++itr)
    2566             :     {
    2567             :         ScFlatBoolRowSegments::RangeData aData;
    2568           0 :         ScFlatBoolRowSegments::RangeIterator aRangeItr(*itr->mpRanges);
    2569           0 :         for (bool bFound = aRangeItr.getFirst(aData); bFound; bFound = aRangeItr.getNext(aData))
    2570             :         {
    2571           0 :             if (!aData.mbValue)
    2572           0 :                 continue;
    2573             : 
    2574           0 :             nCellCount += aData.mnRow2 - aData.mnRow1 + 1;
    2575             :         }
    2576             :     }
    2577             : 
    2578           0 :     ScProgress aProgress(mrDoc.GetDocumentShell(), ScGlobal::GetRscString(STR_PROGRESS_HEIGHTING), nCellCount);
    2579             : 
    2580           0 :     Fraction aZoom(1, 1);
    2581           0 :     itr = mpTabRangesArray->begin();
    2582           0 :     sal_uInt32 nProgressStart = 0;
    2583           0 :     sc::RowHeightContext aCxt(mfPPTX, mfPPTY, aZoom, aZoom, mpOutDev);
    2584           0 :     for (; itr != itrEnd; ++itr)
    2585             :     {
    2586           0 :         SCTAB nTab = itr->mnTab;
    2587           0 :         if (!ValidTab(nTab) || nTab >= mrDoc.GetTableCount() || !mrDoc.maTabs[nTab])
    2588           0 :             continue;
    2589             : 
    2590             :         ScFlatBoolRowSegments::RangeData aData;
    2591           0 :         ScFlatBoolRowSegments::RangeIterator aRangeItr(*itr->mpRanges);
    2592           0 :         for (bool bFound = aRangeItr.getFirst(aData); bFound; bFound = aRangeItr.getNext(aData))
    2593             :         {
    2594           0 :             if (!aData.mbValue)
    2595           0 :                 continue;
    2596             : 
    2597           0 :             mrDoc.maTabs[nTab]->SetOptimalHeight(
    2598           0 :                 aCxt, aData.mnRow1, aData.mnRow2, &aProgress, nProgressStart);
    2599             : 
    2600           0 :             nProgressStart += aData.mnRow2 - aData.mnRow1 + 1;
    2601             :         }
    2602           0 :     }
    2603             : }
    2604             : 
    2605           8 : void ScDocRowHeightUpdater::updateAll()
    2606             : {
    2607           8 :     sal_uInt32 nCellCount = 0;
    2608          16 :     for (SCTAB nTab = 0; nTab < mrDoc.GetTableCount(); ++nTab)
    2609             :     {
    2610           8 :         if (!ValidTab(nTab) || !mrDoc.maTabs[nTab])
    2611           0 :             continue;
    2612             : 
    2613           8 :         nCellCount += mrDoc.maTabs[nTab]->GetWeightedCount();
    2614             :     }
    2615             : 
    2616           8 :     ScProgress aProgress(mrDoc.GetDocumentShell(), ScGlobal::GetRscString(STR_PROGRESS_HEIGHTING), nCellCount);
    2617             : 
    2618           8 :     Fraction aZoom(1, 1);
    2619          16 :     sc::RowHeightContext aCxt(mfPPTX, mfPPTY, aZoom, aZoom, mpOutDev);
    2620           8 :     sal_uLong nProgressStart = 0;
    2621          16 :     for (SCTAB nTab = 0; nTab < mrDoc.GetTableCount(); ++nTab)
    2622             :     {
    2623           8 :         if (!ValidTab(nTab) || !mrDoc.maTabs[nTab])
    2624           0 :             continue;
    2625             : 
    2626           8 :         mrDoc.maTabs[nTab]->SetOptimalHeight(aCxt, 0, MAXROW, &aProgress, nProgressStart);
    2627           8 :         nProgressStart += mrDoc.maTabs[nTab]->GetWeightedCount();
    2628           8 :     }
    2629           8 : }
    2630             : 
    2631          35 : ScAttrRectIterator::ScAttrRectIterator(ScDocument* pDocument, SCTAB nTable,
    2632             :                                     SCCOL nCol1, SCROW nRow1,
    2633             :                                     SCCOL nCol2, SCROW nRow2) :
    2634             :     pDoc( pDocument ),
    2635             :     nTab( nTable ),
    2636             :     nEndCol( nCol2 ),
    2637             :     nStartRow( nRow1 ),
    2638             :     nEndRow( nRow2 ),
    2639             :     nIterStartCol( nCol1 ),
    2640          35 :     nIterEndCol( nCol1 )
    2641             : {
    2642          35 :     if ( ValidTab(nTab) && nTab < pDoc->GetTableCount() && pDoc->maTabs[nTab] )
    2643             :     {
    2644          35 :         pColIter = pDoc->maTabs[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow );
    2645       47155 :         while ( nIterEndCol < nEndCol &&
    2646       23547 :                 pDoc->maTabs[nTab]->aCol[nIterEndCol].IsAllAttrEqual(
    2647       47094 :                     pDoc->maTabs[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) )
    2648       23538 :             ++nIterEndCol;
    2649             :     }
    2650             :     else
    2651           0 :         pColIter = NULL;
    2652          35 : }
    2653             : 
    2654          35 : ScAttrRectIterator::~ScAttrRectIterator()
    2655             : {
    2656          35 :     delete pColIter;
    2657          35 : }
    2658             : 
    2659           0 : void ScAttrRectIterator::DataChanged()
    2660             : {
    2661           0 :     if (pColIter)
    2662             :     {
    2663           0 :         SCROW nNextRow = pColIter->GetNextRow();
    2664           0 :         delete pColIter;
    2665           0 :         pColIter = pDoc->maTabs[nTab]->aCol[nIterStartCol].CreateAttrIterator( nNextRow, nEndRow );
    2666             :     }
    2667           0 : }
    2668             : 
    2669         188 : const ScPatternAttr* ScAttrRectIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2,
    2670             :                                                     SCROW& rRow1, SCROW& rRow2 )
    2671             : {
    2672         455 :     while ( pColIter )
    2673             :     {
    2674         233 :         const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 );
    2675         233 :         if ( pPattern )
    2676             :         {
    2677         154 :             rCol1 = nIterStartCol;
    2678         154 :             rCol2 = nIterEndCol;
    2679         154 :             return pPattern;
    2680             :         }
    2681             : 
    2682          79 :         delete pColIter;
    2683          79 :         nIterStartCol = nIterEndCol+1;
    2684          79 :         if ( nIterStartCol <= nEndCol )
    2685             :         {
    2686          45 :             nIterEndCol = nIterStartCol;
    2687          45 :             pColIter = pDoc->maTabs[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow );
    2688       18450 :             while ( nIterEndCol < nEndCol &&
    2689        9198 :                     pDoc->maTabs[nTab]->aCol[nIterEndCol].IsAllAttrEqual(
    2690       18396 :                         pDoc->maTabs[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) )
    2691        9162 :                 ++nIterEndCol;
    2692             :         }
    2693             :         else
    2694          34 :             pColIter = NULL;
    2695             :     }
    2696          34 :     return NULL; // Nothing anymore
    2697             : }
    2698             : 
    2699             : SCROW ScRowBreakIterator::NOT_FOUND = -1;
    2700             : 
    2701          76 : ScRowBreakIterator::ScRowBreakIterator(set<SCROW>& rBreaks) :
    2702             :     mrBreaks(rBreaks),
    2703          76 :     maItr(rBreaks.begin()), maEnd(rBreaks.end())
    2704             : {
    2705          76 : }
    2706             : 
    2707          76 : SCROW ScRowBreakIterator::first()
    2708             : {
    2709          76 :     maItr = mrBreaks.begin();
    2710          76 :     return maItr == maEnd ? NOT_FOUND : *maItr;
    2711             : }
    2712             : 
    2713           3 : SCROW ScRowBreakIterator::next()
    2714             : {
    2715           3 :     ++maItr;
    2716           3 :     return maItr == maEnd ? NOT_FOUND : *maItr;
    2717         102 : }
    2718             : 
    2719             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10