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

Generated by: LCOV version 1.10