LCOV - code coverage report
Current view: top level - sc/source/core/data - dociter.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 1028 1358 75.7 %
Date: 2015-06-13 12:38:46 Functions: 97 113 85.8 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11