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

Generated by: LCOV version 1.10