LCOV - code coverage report
Current view: top level - sc/source/core/data - column2.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 1149 1578 72.8 %
Date: 2014-04-11 Functions: 117 146 80.1 %
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 "column.hxx"
      21             : #include "scitems.hxx"
      22             : #include "formulacell.hxx"
      23             : #include "document.hxx"
      24             : #include "docpool.hxx"
      25             : #include "attarray.hxx"
      26             : #include "patattr.hxx"
      27             : #include "cellform.hxx"
      28             : #include "stlsheet.hxx"
      29             : #include "rechead.hxx"
      30             : #include "brdcst.hxx"
      31             : #include "editutil.hxx"
      32             : #include "subtotal.hxx"
      33             : #include "markdata.hxx"
      34             : #include "compiler.hxx"
      35             : #include "dbdata.hxx"
      36             : #include "fillinfo.hxx"
      37             : #include "segmenttree.hxx"
      38             : #include "docparam.hxx"
      39             : #include "cellvalue.hxx"
      40             : #include "tokenarray.hxx"
      41             : #include "globalnames.hxx"
      42             : #include "formulagroup.hxx"
      43             : #include "listenercontext.hxx"
      44             : #include "mtvcellfunc.hxx"
      45             : #include "scmatrix.hxx"
      46             : #include <rowheightcontext.hxx>
      47             : 
      48             : #include <math.h>
      49             : 
      50             : #include <editeng/eeitem.hxx>
      51             : 
      52             : #include <svx/algitem.hxx>
      53             : #include <editeng/editobj.hxx>
      54             : #include <editeng/editstat.hxx>
      55             : #include <editeng/emphasismarkitem.hxx>
      56             : #include <editeng/fhgtitem.hxx>
      57             : #include <editeng/forbiddencharacterstable.hxx>
      58             : #include <svx/rotmodit.hxx>
      59             : #include <editeng/scripttypeitem.hxx>
      60             : #include <editeng/unolingu.hxx>
      61             : #include <editeng/justifyitem.hxx>
      62             : #include <svl/zforlist.hxx>
      63             : #include <svl/broadcast.hxx>
      64             : #include <vcl/outdev.hxx>
      65             : #include "formula/errorcodes.hxx"
      66             : #include "formula/vectortoken.hxx"
      67             : 
      68             : #include <boost/scoped_ptr.hpp>
      69             : 
      70             : // factor from font size to optimal cell height (text width)
      71             : #define SC_ROT_BREAK_FACTOR     6
      72             : 
      73       17447 : inline bool IsAmbiguousScript( sal_uInt8 nScript )
      74             : {
      75             :     //! move to a header file
      76           2 :     return ( nScript != SCRIPTTYPE_LATIN &&
      77       17447 :              nScript != SCRIPTTYPE_ASIAN &&
      78       17447 :              nScript != SCRIPTTYPE_COMPLEX );
      79             : }
      80             : 
      81             : 
      82             : //  Data operations
      83             : 
      84             : 
      85             : 
      86        1329 : long ScColumn::GetNeededSize(
      87             :     SCROW nRow, OutputDevice* pDev, double nPPTX, double nPPTY,
      88             :     const Fraction& rZoomX, const Fraction& rZoomY,
      89             :     bool bWidth, const ScNeededSizeOptions& rOptions ) const
      90             : {
      91        1329 :     std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
      92        1329 :     sc::CellStoreType::const_iterator it = aPos.first;
      93        1329 :     if (it == maCells.end() || it->type == sc::element_type_empty)
      94             :         // Empty cell, or invalid row.
      95           0 :         return 0;
      96             : 
      97        1329 :     long nValue = 0;
      98        1329 :     ScRefCellValue aCell = GetCellValue(it, aPos.second);
      99        1329 :     double nPPT = bWidth ? nPPTX : nPPTY;
     100             : 
     101        1329 :     const ScPatternAttr* pPattern = rOptions.pPattern;
     102        1329 :     if (!pPattern)
     103          20 :         pPattern = pAttrArray->GetPattern( nRow );
     104             : 
     105             :     //      merged?
     106             :     //      Do not merge in conditional formatting
     107             : 
     108        1329 :     const ScMergeAttr*      pMerge = (const ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE);
     109        1329 :     const ScMergeFlagAttr*  pFlag = (const ScMergeFlagAttr*)&pPattern->GetItem(ATTR_MERGE_FLAG);
     110             : 
     111        1329 :     if ( bWidth )
     112             :     {
     113          90 :         if ( pFlag->IsHorOverlapped() )
     114           0 :             return 0;
     115          90 :         if ( rOptions.bSkipMerged && pMerge->GetColMerge() > 1 )
     116           0 :             return 0;
     117             :     }
     118             :     else
     119             :     {
     120        1239 :         if ( pFlag->IsVerOverlapped() )
     121           0 :             return 0;
     122        1239 :         if ( rOptions.bSkipMerged && pMerge->GetRowMerge() > 1 )
     123           0 :             return 0;
     124             :     }
     125             : 
     126             :     //      conditional formatting
     127        1329 :     const SfxItemSet* pCondSet = pDocument->GetCondResult( nCol, nRow, nTab );
     128             : 
     129             :     //  line break?
     130             : 
     131             :     const SfxPoolItem* pCondItem;
     132             :     SvxCellHorJustify eHorJust;
     133        1329 :     if (pCondSet &&
     134           0 :             pCondSet->GetItemState(ATTR_HOR_JUSTIFY, true, &pCondItem) == SFX_ITEM_SET)
     135           0 :         eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem*)pCondItem)->GetValue();
     136             :     else
     137             :         eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&)
     138        1329 :                                         pPattern->GetItem( ATTR_HOR_JUSTIFY )).GetValue();
     139             :     bool bBreak;
     140        1329 :     if ( eHorJust == SVX_HOR_JUSTIFY_BLOCK )
     141          97 :         bBreak = true;
     142        1232 :     else if ( pCondSet &&
     143           0 :                 pCondSet->GetItemState(ATTR_LINEBREAK, true, &pCondItem) == SFX_ITEM_SET)
     144           0 :         bBreak = ((const SfxBoolItem*)pCondItem)->GetValue();
     145             :     else
     146        1232 :         bBreak = ((const SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK)).GetValue();
     147             : 
     148        1329 :     SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
     149        1329 :     sal_uLong nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet );
     150             :     // #i111387# disable automatic line breaks only for "General" number format
     151        1329 :     if (bBreak && aCell.hasNumeric() && ( nFormat % SV_COUNTRY_LANGUAGE_OFFSET ) == 0 )
     152             :     {
     153           5 :         bBreak = false;
     154             :     }
     155             : 
     156             :     //  get other attributes from pattern and conditional formatting
     157             : 
     158        1329 :     SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet );
     159        1331 :     bool bAsianVertical = ( eOrient == SVX_ORIENTATION_STACKED &&
     160        1331 :             ((const SfxBoolItem&)pPattern->GetItem( ATTR_VERTICAL_ASIAN, pCondSet )).GetValue() );
     161        1329 :     if ( bAsianVertical )
     162           0 :         bBreak = false;
     163             : 
     164        1329 :     if ( bWidth && bBreak )     // after determining bAsianVertical (bBreak may be reset)
     165           8 :         return 0;
     166             : 
     167        1321 :     long nRotate = 0;
     168        1321 :     SvxRotateMode eRotMode = SVX_ROTATE_MODE_STANDARD;
     169        1321 :     if ( eOrient == SVX_ORIENTATION_STANDARD )
     170             :     {
     171        1041 :         if (pCondSet &&
     172           0 :                 pCondSet->GetItemState(ATTR_ROTATE_VALUE, true, &pCondItem) == SFX_ITEM_SET)
     173           0 :             nRotate = ((const SfxInt32Item*)pCondItem)->GetValue();
     174             :         else
     175        1041 :             nRotate = ((const SfxInt32Item&)pPattern->GetItem(ATTR_ROTATE_VALUE)).GetValue();
     176        1041 :         if ( nRotate )
     177             :         {
     178         782 :             if (pCondSet &&
     179           0 :                     pCondSet->GetItemState(ATTR_ROTATE_MODE, true, &pCondItem) == SFX_ITEM_SET)
     180           0 :                 eRotMode = (SvxRotateMode)((const SvxRotateModeItem*)pCondItem)->GetValue();
     181             :             else
     182             :                 eRotMode = (SvxRotateMode)((const SvxRotateModeItem&)
     183         782 :                                             pPattern->GetItem(ATTR_ROTATE_MODE)).GetValue();
     184             : 
     185         782 :             if ( nRotate == 18000 )
     186           0 :                 eRotMode = SVX_ROTATE_MODE_STANDARD;    // no overflow
     187             :         }
     188             :     }
     189             : 
     190        1321 :     if ( eHorJust == SVX_HOR_JUSTIFY_REPEAT )
     191             :     {
     192             :         // ignore orientation/rotation if "repeat" is active
     193           0 :         eOrient = SVX_ORIENTATION_STANDARD;
     194           0 :         nRotate = 0;
     195           0 :         bAsianVertical = false;
     196             :     }
     197             : 
     198             :     const SvxMarginItem* pMargin;
     199        1321 :     if (pCondSet &&
     200           0 :             pCondSet->GetItemState(ATTR_MARGIN, true, &pCondItem) == SFX_ITEM_SET)
     201           0 :         pMargin = (const SvxMarginItem*) pCondItem;
     202             :     else
     203        1321 :         pMargin = (const SvxMarginItem*) &pPattern->GetItem(ATTR_MARGIN);
     204        1321 :     sal_uInt16 nIndent = 0;
     205        1321 :     if ( eHorJust == SVX_HOR_JUSTIFY_LEFT )
     206             :     {
     207         481 :         if (pCondSet &&
     208           0 :                 pCondSet->GetItemState(ATTR_INDENT, true, &pCondItem) == SFX_ITEM_SET)
     209           0 :             nIndent = ((const SfxUInt16Item*)pCondItem)->GetValue();
     210             :         else
     211         481 :             nIndent = ((const SfxUInt16Item&)pPattern->GetItem(ATTR_INDENT)).GetValue();
     212             :     }
     213             : 
     214        1321 :     sal_uInt8 nScript = pDocument->GetScriptType(nCol, nRow, nTab);
     215        1321 :     if (nScript == 0) nScript = ScGlobal::GetDefaultScriptType();
     216             : 
     217             :     //  also call SetFont for edit cells, because bGetFont may be set only once
     218             :     //  bGetFont is set also if script type changes
     219        1321 :     if (rOptions.bGetFont)
     220             :     {
     221        1321 :         Fraction aFontZoom = ( eOrient == SVX_ORIENTATION_STANDARD ) ? rZoomX : rZoomY;
     222        1321 :         Font aFont;
     223             :         // font color doesn't matter here
     224        1321 :         pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &aFontZoom, pCondSet, nScript );
     225        1321 :         pDev->SetFont(aFont);
     226             :     }
     227             : 
     228        1321 :     bool bAddMargin = true;
     229        1321 :     CellType eCellType = aCell.meType;
     230             : 
     231        1231 :     bool bEditEngine = (eCellType == CELLTYPE_EDIT ||
     232        1229 :                         eOrient == SVX_ORIENTATION_STACKED ||
     233        3871 :                         IsAmbiguousScript(nScript) ||
     234        1325 :                         ((eCellType == CELLTYPE_FORMULA) && aCell.mpFormula->IsMultilineResult()));
     235             : 
     236        1321 :     if (!bEditEngine)                                   // direct output
     237             :     {
     238             :         Color* pColor;
     239        1229 :         OUString aValStr;
     240             :         ScCellFormat::GetString(
     241        1229 :             aCell, nFormat, aValStr, &pColor, *pFormatter, pDocument, true, rOptions.bFormula, ftCheck);
     242             : 
     243        1229 :         if (!aValStr.isEmpty())
     244             :         {
     245             :             //  SetFont is moved up
     246             : 
     247        1229 :             Size aSize( pDev->GetTextWidth( aValStr ), pDev->GetTextHeight() );
     248        1229 :             if ( eOrient != SVX_ORIENTATION_STANDARD )
     249             :             {
     250         278 :                 long nTemp = aSize.Width();
     251         278 :                 aSize.Width() = aSize.Height();
     252         278 :                 aSize.Height() = nTemp;
     253             :             }
     254         951 :             else if ( nRotate )
     255             :             {
     256             :                 //! take different X/Y scaling into consideration
     257             : 
     258         781 :                 double nRealOrient = nRotate * F_PI18000;   // nRotate is in 1/100 Grad
     259         781 :                 double nCosAbs = fabs( cos( nRealOrient ) );
     260         781 :                 double nSinAbs = fabs( sin( nRealOrient ) );
     261         781 :                 long nHeight = (long)( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
     262             :                 long nWidth;
     263         781 :                 if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
     264         781 :                     nWidth  = (long)( aSize.Width() * nCosAbs + aSize.Height() * nSinAbs );
     265           0 :                 else if ( rOptions.bTotalSize )
     266             :                 {
     267           0 :                     nWidth = (long) ( pDocument->GetColWidth( nCol,nTab ) * nPPT );
     268           0 :                     bAddMargin = false;
     269             :                     //  only to the right:
     270             :                     //! differ on direction up/down (only Text/whole height)
     271           0 :                     if ( pPattern->GetRotateDir( pCondSet ) == SC_ROTDIR_RIGHT )
     272           0 :                         nWidth += (long)( pDocument->GetRowHeight( nRow,nTab ) *
     273           0 :                                             nPPT * nCosAbs / nSinAbs );
     274             :                 }
     275             :                 else
     276           0 :                     nWidth  = (long)( aSize.Height() / nSinAbs );   //! limit?
     277             : 
     278         781 :                 if ( bBreak && !rOptions.bTotalSize )
     279             :                 {
     280             :                     //  limit size for line break
     281         469 :                     long nCmp = pDev->GetFont().GetSize().Height() * SC_ROT_BREAK_FACTOR;
     282         469 :                     if ( nHeight > nCmp )
     283           0 :                         nHeight = nCmp;
     284             :                 }
     285             : 
     286         781 :                 aSize = Size( nWidth, nHeight );
     287             :             }
     288        1229 :             nValue = bWidth ? aSize.Width() : aSize.Height();
     289             : 
     290        1229 :             if ( bAddMargin )
     291             :             {
     292        1229 :                 if (bWidth)
     293             :                 {
     294         164 :                     nValue += (long) ( pMargin->GetLeftMargin() * nPPT ) +
     295         164 :                               (long) ( pMargin->GetRightMargin() * nPPT );
     296          82 :                     if ( nIndent )
     297           0 :                         nValue += (long) ( nIndent * nPPT );
     298             :                 }
     299             :                 else
     300        2294 :                     nValue += (long) ( pMargin->GetTopMargin() * nPPT ) +
     301        2294 :                               (long) ( pMargin->GetBottomMargin() * nPPT );
     302             :             }
     303             : 
     304             :             //  linebreak done ?
     305             : 
     306        1229 :             if ( bBreak && !bWidth )
     307             :             {
     308             :                 //  test with EditEngine the safety at 90%
     309             :                 //  (due to rounding errors and because EditEngine formats partially differently)
     310             : 
     311        1364 :                 long nDocPixel = (long) ( ( pDocument->GetColWidth( nCol,nTab ) -
     312        1364 :                                     pMargin->GetLeftMargin() - pMargin->GetRightMargin() -
     313             :                                     nIndent )
     314         682 :                                     * nPPT );
     315         682 :                 nDocPixel = (nDocPixel * 9) / 10;           // for safety
     316         682 :                 if ( aSize.Width() > nDocPixel )
     317         504 :                     bEditEngine = true;
     318             :             }
     319        1229 :         }
     320             :     }
     321             : 
     322        1321 :     if (bEditEngine)
     323             :     {
     324             :         //  the font is not reset each time with !bEditEngine
     325         596 :         Font aOldFont = pDev->GetFont();
     326             : 
     327        1192 :         MapMode aHMMMode( MAP_100TH_MM, Point(), rZoomX, rZoomY );
     328             : 
     329             :         // save in document ?
     330         596 :         ScFieldEditEngine* pEngine = pDocument->CreateFieldEditEngine();
     331             : 
     332         596 :         pEngine->SetUpdateMode( false );
     333         596 :         bool bTextWysiwyg = ( pDev->GetOutDevType() == OUTDEV_PRINTER );
     334         596 :         sal_uLong nCtrl = pEngine->GetControlWord();
     335         596 :         if ( bTextWysiwyg )
     336           0 :             nCtrl |= EE_CNTRL_FORMAT100;
     337             :         else
     338         596 :             nCtrl &= ~EE_CNTRL_FORMAT100;
     339         596 :         pEngine->SetControlWord( nCtrl );
     340        1192 :         MapMode aOld = pDev->GetMapMode();
     341         596 :         pDev->SetMapMode( aHMMMode );
     342         596 :         pEngine->SetRefDevice( pDev );
     343         596 :         pDocument->ApplyAsianEditSettings( *pEngine );
     344         596 :         SfxItemSet* pSet = new SfxItemSet( pEngine->GetEmptyItemSet() );
     345         596 :         if ( ScStyleSheet* pPreviewStyle = pDocument->GetPreviewCellStyle( nCol, nRow, nTab ) )
     346             :         {
     347           0 :             ScPatternAttr* pPreviewPattern = new ScPatternAttr( *pPattern );
     348           0 :             pPreviewPattern->SetStyleSheet(pPreviewStyle);
     349           0 :             pPreviewPattern->FillEditItemSet( pSet, pCondSet );
     350           0 :             delete pPreviewPattern;
     351             :         }
     352             :         else
     353             :         {
     354         596 :             SfxItemSet* pFontSet = pDocument->GetPreviewFont( nCol, nRow, nTab );
     355         596 :             pPattern->FillEditItemSet( pSet, pFontSet ? pFontSet : pCondSet );
     356             :         }
     357             : //          no longer needed, are setted with the text (is faster)
     358             : //          pEngine->SetDefaults( pSet );
     359             : 
     360         596 :         if ( ((const SfxBoolItem&)pSet->Get(EE_PARA_HYPHENATE)).GetValue() ) {
     361             : 
     362         409 :             com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
     363         409 :             pEngine->SetHyphenator( xXHyphenator );
     364             :         }
     365             : 
     366         596 :         Size aPaper = Size( 1000000, 1000000 );
     367         596 :         if ( eOrient==SVX_ORIENTATION_STACKED && !bAsianVertical )
     368           2 :             aPaper.Width() = 1;
     369         594 :         else if (bBreak)
     370             :         {
     371         505 :             double fWidthFactor = nPPTX;
     372         505 :             if ( bTextWysiwyg )
     373             :             {
     374             :                 //  if text is formatted for printer, don't use PixelToLogic,
     375             :                 //  to ensure the exact same paper width (and same line breaks) as in
     376             :                 //  ScEditUtil::GetEditArea, used for output.
     377             : 
     378           0 :                 fWidthFactor = HMM_PER_TWIPS;
     379             :             }
     380             : 
     381             :             // use original width for hidden columns:
     382         505 :             long nDocWidth = (long) ( pDocument->GetOriginalWidth(nCol,nTab) * fWidthFactor );
     383         505 :             SCCOL nColMerge = pMerge->GetColMerge();
     384         505 :             if (nColMerge > 1)
     385           0 :                 for (SCCOL nColAdd=1; nColAdd<nColMerge; nColAdd++)
     386           0 :                     nDocWidth += (long) ( pDocument->GetColWidth(nCol+nColAdd,nTab) * fWidthFactor );
     387         505 :             nDocWidth -= (long) ( pMargin->GetLeftMargin() * fWidthFactor )
     388         505 :                        + (long) ( pMargin->GetRightMargin() * fWidthFactor )
     389         505 :                        + 1;     // output size is width-1 pixel (due to gridline)
     390         505 :             if ( nIndent )
     391           0 :                 nDocWidth -= (long) ( nIndent * fWidthFactor );
     392             : 
     393             :             // space for AutoFilter button:  20 * nZoom/100
     394         505 :             if ( pFlag->HasAutoFilter() && !bTextWysiwyg )
     395           0 :                 nDocWidth -= (rZoomX.GetNumerator()*20)/rZoomX.GetDenominator();
     396             : 
     397         505 :             aPaper.Width() = nDocWidth;
     398             : 
     399         505 :             if ( !bTextWysiwyg )
     400         505 :                 aPaper = pDev->PixelToLogic( aPaper, aHMMMode );
     401             :         }
     402         596 :         pEngine->SetPaperSize(aPaper);
     403             : 
     404         596 :         if (aCell.meType == CELLTYPE_EDIT)
     405             :         {
     406          90 :             pEngine->SetTextNewDefaults(*aCell.mpEditText, pSet);
     407             :         }
     408             :         else
     409             :         {
     410             :             Color* pColor;
     411         506 :             OUString aString;
     412             :             ScCellFormat::GetString(
     413             :                 aCell, nFormat, aString, &pColor, *pFormatter, pDocument, true,
     414         506 :                 rOptions.bFormula, ftCheck);
     415             : 
     416         506 :             if (!aString.isEmpty())
     417         506 :                 pEngine->SetTextNewDefaults(aString, pSet);
     418             :             else
     419           0 :                 pEngine->SetDefaults(pSet);
     420             :         }
     421             : 
     422         596 :         bool bEngineVertical = pEngine->IsVertical();
     423         596 :         pEngine->SetVertical( bAsianVertical );
     424         596 :         pEngine->SetUpdateMode( true );
     425             : 
     426         596 :         bool bEdWidth = bWidth;
     427         596 :         if ( eOrient != SVX_ORIENTATION_STANDARD && eOrient != SVX_ORIENTATION_STACKED )
     428          24 :             bEdWidth = !bEdWidth;
     429         596 :         if ( nRotate )
     430             :         {
     431             :             //! take different X/Y scaling into consideration
     432             : 
     433         451 :             Size aSize( pEngine->CalcTextWidth(), pEngine->GetTextHeight() );
     434         451 :             double nRealOrient = nRotate * F_PI18000;   // nRotate is in 1/100 Grad
     435         451 :             double nCosAbs = fabs( cos( nRealOrient ) );
     436         451 :             double nSinAbs = fabs( sin( nRealOrient ) );
     437         451 :             long nHeight = (long)( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
     438             :             long nWidth;
     439         451 :             if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
     440         451 :                 nWidth  = (long)( aSize.Width() * nCosAbs + aSize.Height() * nSinAbs );
     441           0 :             else if ( rOptions.bTotalSize )
     442             :             {
     443           0 :                 nWidth = (long) ( pDocument->GetColWidth( nCol,nTab ) * nPPT );
     444           0 :                 bAddMargin = false;
     445           0 :                 if ( pPattern->GetRotateDir( pCondSet ) == SC_ROTDIR_RIGHT )
     446           0 :                     nWidth += (long)( pDocument->GetRowHeight( nRow,nTab ) *
     447           0 :                                         nPPT * nCosAbs / nSinAbs );
     448             :             }
     449             :             else
     450           0 :                 nWidth  = (long)( aSize.Height() / nSinAbs );   //! limit?
     451         451 :             aSize = Size( nWidth, nHeight );
     452             : 
     453         451 :             Size aPixSize = pDev->LogicToPixel( aSize, aHMMMode );
     454         451 :             if ( bEdWidth )
     455           0 :                 nValue = aPixSize.Width();
     456             :             else
     457             :             {
     458         451 :                 nValue = aPixSize.Height();
     459             : 
     460         451 :                 if ( bBreak && !rOptions.bTotalSize )
     461             :                 {
     462             :                     //  limit size for line break
     463         451 :                     long nCmp = aOldFont.GetSize().Height() * SC_ROT_BREAK_FACTOR;
     464         451 :                     if ( nValue > nCmp )
     465           1 :                         nValue = nCmp;
     466             :                 }
     467             :             }
     468             :         }
     469         145 :         else if ( bEdWidth )
     470             :         {
     471          24 :             if (bBreak)
     472          24 :                 nValue = 0;
     473             :             else
     474           0 :                 nValue = pDev->LogicToPixel(Size( pEngine->CalcTextWidth(), 0 ),
     475           0 :                                     aHMMMode).Width();
     476             :         }
     477             :         else            // height
     478             :         {
     479         121 :             nValue = pDev->LogicToPixel(Size( 0, pEngine->GetTextHeight() ),
     480         121 :                                 aHMMMode).Height();
     481             : 
     482             :             // With non-100% zoom and several lines or paragraphs, don't shrink below the result with FORMAT100 set
     483         121 :             if ( !bTextWysiwyg && ( rZoomY.GetNumerator() != 1 || rZoomY.GetDenominator() != 1 ) &&
     484           0 :                  ( pEngine->GetParagraphCount() > 1 || ( bBreak && pEngine->GetLineCount(0) > 1 ) ) )
     485             :             {
     486           0 :                 pEngine->SetControlWord( nCtrl | EE_CNTRL_FORMAT100 );
     487           0 :                 pEngine->QuickFormatDoc( true );
     488           0 :                 long nSecondValue = pDev->LogicToPixel(Size( 0, pEngine->GetTextHeight() ), aHMMMode).Height();
     489           0 :                 if ( nSecondValue > nValue )
     490           0 :                     nValue = nSecondValue;
     491             :             }
     492             :         }
     493             : 
     494         596 :         if ( nValue && bAddMargin )
     495             :         {
     496         572 :             if (bWidth)
     497             :             {
     498           0 :                 nValue += (long) ( pMargin->GetLeftMargin() * nPPT ) +
     499           0 :                           (long) ( pMargin->GetRightMargin() * nPPT );
     500           0 :                 if (nIndent)
     501           0 :                     nValue += (long) ( nIndent * nPPT );
     502             :             }
     503             :             else
     504             :             {
     505        1144 :                 nValue += (long) ( pMargin->GetTopMargin() * nPPT ) +
     506        1144 :                           (long) ( pMargin->GetBottomMargin() * nPPT );
     507             : 
     508         572 :                 if ( bAsianVertical && pDev->GetOutDevType() != OUTDEV_PRINTER )
     509             :                 {
     510             :                     //  add 1pt extra (default margin value) for line breaks with SetVertical
     511           0 :                     nValue += (long) ( 20 * nPPT );
     512             :                 }
     513             :             }
     514             :         }
     515             : 
     516             :         //  EditEngine is cached and re-used, so the old vertical flag must be restored
     517         596 :         pEngine->SetVertical( bEngineVertical );
     518             : 
     519         596 :         pDocument->DisposeFieldEditEngine(pEngine);
     520             : 
     521         596 :         pDev->SetMapMode( aOld );
     522        1192 :         pDev->SetFont( aOldFont );
     523             :     }
     524             : 
     525        1321 :     if (bWidth)
     526             :     {
     527             :         //      place for Autofilter Button
     528             :         //      20 * nZoom/100
     529             :         //      Conditional formatting is not interesting here
     530             : 
     531          82 :         sal_Int16 nFlags = ((const ScMergeFlagAttr&)pPattern->GetItem(ATTR_MERGE_FLAG)).GetValue();
     532          82 :         if (nFlags & SC_MF_AUTO)
     533           0 :             nValue += (rZoomX.GetNumerator()*20)/rZoomX.GetDenominator();
     534             :     }
     535        1321 :     return nValue;
     536             : }
     537             : 
     538             : namespace {
     539             : 
     540          67 : class MaxStrLenFinder
     541             : {
     542             :     ScDocument& mrDoc;
     543             :     sal_uInt32 mnFormat;
     544             :     OUString maMaxLenStr;
     545             :     sal_Int32 mnMaxLen;
     546             : 
     547        1489 :     void checkLength(ScRefCellValue& rCell)
     548             :     {
     549             :         Color* pColor;
     550        1489 :         OUString aValStr;
     551             :         ScCellFormat::GetString(
     552        1489 :             rCell, mnFormat, aValStr, &pColor, *mrDoc.GetFormatTable(), &mrDoc, true, false, ftCheck);
     553             : 
     554        1489 :         if (aValStr.getLength() > mnMaxLen)
     555             :         {
     556          59 :             mnMaxLen = aValStr.getLength();
     557          59 :             maMaxLenStr = aValStr;
     558        1489 :         }
     559        1489 :     }
     560             : 
     561             : public:
     562          67 :     MaxStrLenFinder(ScDocument& rDoc, sal_uInt32 nFormat) :
     563          67 :         mrDoc(rDoc), mnFormat(nFormat), mnMaxLen(0) {}
     564             : 
     565        1473 :     void operator() (size_t /*nRow*/, double f)
     566             :     {
     567        1473 :         ScRefCellValue aCell(f);
     568        1473 :         checkLength(aCell);
     569        1473 :     }
     570             : 
     571        1116 :     void operator() (size_t /*nRow*/, const svl::SharedString& rSS)
     572             :     {
     573        1116 :         if (rSS.getLength() > mnMaxLen)
     574             :         {
     575          64 :             mnMaxLen = rSS.getLength();
     576          64 :             maMaxLenStr = rSS.getString();
     577             :         }
     578        1116 :     }
     579             : 
     580          16 :     void operator() (size_t /*nRow*/, const EditTextObject* p)
     581             :     {
     582          16 :         ScRefCellValue aCell(p);
     583          16 :         checkLength(aCell);
     584          16 :     }
     585             : 
     586           0 :     void operator() (size_t /*nRow*/, const ScFormulaCell* p)
     587             :     {
     588           0 :         ScRefCellValue aCell(const_cast<ScFormulaCell*>(p));
     589           0 :         checkLength(aCell);
     590           0 :     }
     591             : 
     592          67 :     const OUString& getMaxLenStr() const { return maMaxLenStr; }
     593             : };
     594             : 
     595             : }
     596             : 
     597          89 : sal_uInt16 ScColumn::GetOptimalColWidth(
     598             :     OutputDevice* pDev, double nPPTX, double nPPTY, const Fraction& rZoomX, const Fraction& rZoomY,
     599             :     bool bFormula, sal_uInt16 nOldWidth, const ScMarkData* pMarkData, const ScColWidthParam* pParam) const
     600             : {
     601          89 :     if (maCells.block_size() == 1 && maCells.begin()->type == sc::element_type_empty)
     602             :         // All cells are empty.
     603          11 :         return nOldWidth;
     604             : 
     605          78 :     sc::SingleColumnSpanSet aSpanSet;
     606         156 :     sc::SingleColumnSpanSet::SpansType aMarkedSpans;
     607          78 :     if (pMarkData && (pMarkData->IsMarked() || pMarkData->IsMultiMarked()))
     608             :     {
     609          70 :         aSpanSet.scan(*pMarkData, nTab, nCol);
     610          70 :         aSpanSet.getSpans(aMarkedSpans);
     611             :     }
     612             :     else
     613             :         // "Select" the entire column if no selection exists.
     614           8 :         aMarkedSpans.push_back(sc::RowSpan(0, MAXROW));
     615             : 
     616          78 :     sal_uInt16 nWidth = static_cast<sal_uInt16>(nOldWidth*nPPTX);
     617          78 :     bool bFound = false;
     618             : 
     619          78 :     if ( pParam && pParam->mbSimpleText )
     620             :     {   // all the same except for number format
     621          67 :         const ScPatternAttr* pPattern = GetPattern( 0 );
     622          67 :         Font aFont;
     623             :         // font color doesn't matter here
     624          67 :         pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &rZoomX, NULL );
     625          67 :         pDev->SetFont( aFont );
     626          67 :         const SvxMarginItem* pMargin = (const SvxMarginItem*) &pPattern->GetItem(ATTR_MARGIN);
     627         134 :         long nMargin = (long) ( pMargin->GetLeftMargin() * nPPTX ) +
     628         134 :                         (long) ( pMargin->GetRightMargin() * nPPTX );
     629             : 
     630             :         // Try to find the row that has the longest string, and measure the width of that string.
     631          67 :         SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
     632          67 :         sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter );
     633         134 :         OUString aLongStr;
     634             :         Color* pColor;
     635          67 :         if (pParam->mnMaxTextRow >= 0)
     636             :         {
     637           0 :             ScRefCellValue aCell = GetCellValue(pParam->mnMaxTextRow);
     638             :             ScCellFormat::GetString(
     639           0 :                 aCell, nFormat, aLongStr, &pColor, *pFormatter, pDocument, true, false, ftCheck);
     640             :         }
     641             :         else
     642             :         {
     643             :             // Go though all non-empty cells within selection.
     644          67 :             MaxStrLenFinder aFunc(*pDocument, nFormat);
     645          67 :             sc::CellStoreType::const_iterator itPos = maCells.begin();
     646          67 :             sc::SingleColumnSpanSet::SpansType::const_iterator it = aMarkedSpans.begin(), itEnd = aMarkedSpans.end();
     647         134 :             for (; it != itEnd; ++it)
     648          67 :                 itPos = sc::ParseAllNonEmpty(itPos, maCells, it->mnRow1, it->mnRow2, aFunc);
     649             : 
     650          67 :             aLongStr = aFunc.getMaxLenStr();
     651             :         }
     652             : 
     653          67 :         if (!aLongStr.isEmpty())
     654             :         {
     655          67 :             nWidth = pDev->GetTextWidth(aLongStr) + static_cast<sal_uInt16>(nMargin);
     656          67 :             bFound = true;
     657          67 :         }
     658             :     }
     659             :     else
     660             :     {
     661          11 :         ScNeededSizeOptions aOptions;
     662          11 :         aOptions.bFormula = bFormula;
     663          11 :         const ScPatternAttr* pOldPattern = NULL;
     664          11 :         sal_uInt8 nOldScript = 0;
     665             : 
     666             :         // Go though all non-empty cells within selection.
     667          11 :         sc::CellStoreType::const_iterator itPos = maCells.begin();
     668          11 :         sc::SingleColumnSpanSet::SpansType::const_iterator it = aMarkedSpans.begin(), itEnd = aMarkedSpans.end();
     669          22 :         for (; it != itEnd; ++it)
     670             :         {
     671          11 :             SCROW nRow1 = it->mnRow1, nRow2 = it->mnRow2;
     672          11 :             SCROW nRow = nRow1;
     673          61 :             while (nRow <= nRow2)
     674             :             {
     675          39 :                 std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(itPos, nRow);
     676          39 :                 itPos = aPos.first;
     677          39 :                 if (itPos->type == sc::element_type_empty)
     678             :                 {
     679             :                     // Skip empty cells.
     680          22 :                     nRow += itPos->size - aPos.second;
     681          22 :                     continue;
     682             :                 }
     683             : 
     684          87 :                 for (size_t nOffset = aPos.second; nOffset < itPos->size; ++nOffset, ++nRow)
     685             :                 {
     686          70 :                     sal_uInt8 nScript = pDocument->GetScriptType(nCol, nRow, nTab);
     687          70 :                     if (nScript == 0)
     688           0 :                         nScript = ScGlobal::GetDefaultScriptType();
     689             : 
     690          70 :                     const ScPatternAttr* pPattern = GetPattern(nRow);
     691          70 :                     aOptions.pPattern = pPattern;
     692          70 :                     aOptions.bGetFont = (pPattern != pOldPattern || nScript != nOldScript);
     693             :                     sal_uInt16 nThis = (sal_uInt16) GetNeededSize(
     694          70 :                         nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, true, aOptions);
     695          70 :                     pOldPattern = pPattern;
     696          70 :                     if (nThis)
     697             :                     {
     698          62 :                         if (nThis > nWidth || !bFound)
     699             :                         {
     700          13 :                             nWidth = nThis;
     701          13 :                             bFound = true;
     702             :                         }
     703             :                     }
     704             :                 }
     705             :             }
     706             :         }
     707             :     }
     708             : 
     709          78 :     if (bFound)
     710             :     {
     711          78 :         nWidth += 2;
     712          78 :         sal_uInt16 nTwips = (sal_uInt16) (nWidth / nPPTX);
     713          78 :         return nTwips;
     714             :     }
     715             :     else
     716          78 :         return nOldWidth;
     717             : }
     718             : 
     719     1472169 : static sal_uInt16 lcl_GetAttribHeight( const ScPatternAttr& rPattern, sal_uInt16 nFontHeightId )
     720             : {
     721             :     const SvxFontHeightItem& rFontHeight =
     722     1472169 :         static_cast<const SvxFontHeightItem&>(rPattern.GetItem(nFontHeightId));
     723             : 
     724     1472169 :     sal_uInt16 nHeight = rFontHeight.GetHeight();
     725     1472169 :     nHeight *= 1.18;
     726             : 
     727     1472169 :     if ( ((const SvxEmphasisMarkItem&)rPattern.
     728     1472169 :             GetItem(ATTR_FONT_EMPHASISMARK)).GetEmphasisMark() != EMPHASISMARK_NONE )
     729             :     {
     730             :         //  add height for emphasis marks
     731             :         //! font metrics should be used instead
     732         566 :         nHeight += nHeight / 4;
     733             :     }
     734             : 
     735             :     const SvxMarginItem& rMargin =
     736     1472169 :         static_cast<const SvxMarginItem&>(rPattern.GetItem(ATTR_MARGIN));
     737             : 
     738     1472169 :     nHeight += rMargin.GetTopMargin() + rMargin.GetBottomMargin();
     739             : 
     740     1472169 :     if (nHeight > STD_ROWHEIGHT_DIFF)
     741     1472169 :         nHeight -= STD_ROWHEIGHT_DIFF;
     742             : 
     743     1472169 :     if (nHeight < ScGlobal::nStdRowHeight)
     744     1283989 :         nHeight = ScGlobal::nStdRowHeight;
     745             : 
     746     1472169 :     return nHeight;
     747             : }
     748             : 
     749             : //  pHeight in Twips
     750             : //  optimize nMinHeight, nMinStart : with nRow >= nMinStart is at least nMinHeight
     751             : //  (is only evaluated with bStdAllowed)
     752             : 
     753     1565696 : void ScColumn::GetOptimalHeight(
     754             :     sc::RowHeightContext& rCxt, SCROW nStartRow, SCROW nEndRow, sal_uInt16* pHeight,
     755             :     sal_uInt16 nMinHeight, SCROW nMinStart )
     756             : {
     757     1565696 :     ScAttrIterator aIter( pAttrArray, nStartRow, nEndRow );
     758             : 
     759     1565696 :     SCROW nStart = -1;
     760     1565696 :     SCROW nEnd = -1;
     761     1565696 :     SCROW nEditPos = 0;
     762     1565696 :     SCROW nNextEnd = 0;
     763             : 
     764             :     //  with conditional formatting, always consider the individual cells
     765             : 
     766     1565696 :     const ScPatternAttr* pPattern = aIter.Next(nStart,nEnd);
     767     1565696 :     ::boost::ptr_vector<ScPatternAttr> aAltPatterns;
     768     4700175 :     while ( pPattern )
     769             :     {
     770             :         // GetOptimalHeight called for preview style needs to
     771             :         // use really use the style
     772     1568783 :         if ( ScStyleSheet* pStyle = pDocument->GetPreviewCellStyle( nCol, nStartRow, nTab ) )
     773             :         {
     774           0 :             aAltPatterns.push_back( new ScPatternAttr( *pPattern ) );
     775           0 :             ScPatternAttr* pModifiedPatt = &aAltPatterns.back();
     776           0 :             pModifiedPatt->SetStyleSheet( pStyle );
     777           0 :             pPattern = pModifiedPatt;
     778             :         }
     779     1568783 :         const ScMergeAttr*      pMerge = (const ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE);
     780     1568783 :         const ScMergeFlagAttr*  pFlag = (const ScMergeFlagAttr*)&pPattern->GetItem(ATTR_MERGE_FLAG);
     781     1568783 :         if ( pMerge->GetRowMerge() > 1 || pFlag->IsOverlapped() )
     782             :         {
     783             :             //  do nothing - vertically with merged and overlapping,
     784             :             //        horizontally only with overlapped (invisible) -
     785             :             //        only one horizontal merged is always considered
     786             :         }
     787             :         else
     788             :         {
     789     1568754 :             bool bStdAllowed = (pPattern->GetCellOrientation() == SVX_ORIENTATION_STANDARD);
     790     1568754 :             bool bStdOnly = false;
     791     1568754 :             if (bStdAllowed)
     792             :             {
     793     2912047 :                 bool bBreak = ((SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK)).GetValue() ||
     794             :                                 ((SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern->
     795     1439789 :                                     GetItem( ATTR_HOR_JUSTIFY )).GetValue() ==
     796     1472258 :                                     SVX_HOR_JUSTIFY_BLOCK);
     797     1472258 :                 bStdOnly = !bBreak;
     798             : 
     799             :                 // conditional formatting: loop all cells
     800     2912034 :                 if (bStdOnly &&
     801             :                     !static_cast<const ScCondFormatItem&>(pPattern->GetItem(
     802     1439776 :                             ATTR_CONDITIONAL)).GetCondFormatData().empty())
     803             :                 {
     804        4321 :                     bStdOnly = false;
     805             :                 }
     806             : 
     807             :                 // rotated text: loop all cells
     808     2907713 :                 if ( bStdOnly && ((const SfxInt32Item&)pPattern->
     809     1435455 :                                     GetItem(ATTR_ROTATE_VALUE)).GetValue() )
     810           0 :                     bStdOnly = false;
     811             :             }
     812             : 
     813     1568754 :             if (bStdOnly)
     814     1435455 :                 if (HasEditCells(nStart,nEnd,nEditPos))     // includes mixed script types
     815             :                 {
     816          89 :                     if (nEditPos == nStart)
     817             :                     {
     818          89 :                         bStdOnly = false;
     819          89 :                         if (nEnd > nEditPos)
     820           0 :                             nNextEnd = nEnd;
     821          89 :                         nEnd = nEditPos;                // calculate single
     822          89 :                         bStdAllowed = false;            // will be computed in any case per cell
     823             :                     }
     824             :                     else
     825             :                     {
     826           0 :                         nNextEnd = nEnd;
     827           0 :                         nEnd = nEditPos - 1;            // standard - part
     828             :                     }
     829             :                 }
     830             : 
     831     1568754 :             sc::SingleColumnSpanSet aSpanSet;
     832     1568754 :             aSpanSet.scan(*this, nStart, nEnd);
     833     3137508 :             sc::SingleColumnSpanSet::SpansType aSpans;
     834     1568754 :             aSpanSet.getSpans(aSpans);
     835             : 
     836     1568754 :             if (bStdAllowed)
     837             :             {
     838     1472169 :                 sal_uInt16 nLatHeight = 0;
     839     1472169 :                 sal_uInt16 nCjkHeight = 0;
     840     1472169 :                 sal_uInt16 nCtlHeight = 0;
     841             :                 sal_uInt16 nDefHeight;
     842     1472169 :                 sal_uInt8 nDefScript = ScGlobal::GetDefaultScriptType();
     843     1472169 :                 if ( nDefScript == SCRIPTTYPE_ASIAN )
     844           0 :                     nDefHeight = nCjkHeight = lcl_GetAttribHeight( *pPattern, ATTR_CJK_FONT_HEIGHT );
     845     1472169 :                 else if ( nDefScript == SCRIPTTYPE_COMPLEX )
     846           0 :                     nDefHeight = nCtlHeight = lcl_GetAttribHeight( *pPattern, ATTR_CTL_FONT_HEIGHT );
     847             :                 else
     848     1472169 :                     nDefHeight = nLatHeight = lcl_GetAttribHeight( *pPattern, ATTR_FONT_HEIGHT );
     849             : 
     850             :                 //  if everything below is already larger, the loop doesn't have to
     851             :                 //  be run again
     852     1472169 :                 SCROW nStdEnd = nEnd;
     853     1472169 :                 if ( nDefHeight <= nMinHeight && nStdEnd >= nMinStart )
     854     1436543 :                     nStdEnd = (nMinStart>0) ? nMinStart-1 : 0;
     855             : 
     856   432683824 :                 for (SCROW nRow = nStart; nRow <= nStdEnd; ++nRow)
     857   431211655 :                     if (nDefHeight > pHeight[nRow-nStartRow])
     858   161485195 :                         pHeight[nRow-nStartRow] = nDefHeight;
     859             : 
     860     1472169 :                 if ( bStdOnly )
     861             :                 {
     862             :                     //  if cells are not handled individually below,
     863             :                     //  check for cells with different script type
     864     1435366 :                     sc::CellTextAttrStoreType::iterator itAttr = maCellTextAttrs.begin();
     865     1435366 :                     sc::SingleColumnSpanSet::SpansType::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
     866     1435366 :                     sc::CellStoreType::iterator itCells = maCells.begin();
     867     1438665 :                     for (; it != itEnd; ++it)
     868             :                     {
     869       33756 :                         for (SCROW nRow = it->mnRow1; nRow <= it->mnRow2; ++nRow)
     870             :                         {
     871       30457 :                             sal_uInt8 nScript = GetRangeScriptType(itAttr, nRow, nRow, itCells);
     872       30457 :                             if (nScript == nDefScript)
     873       30358 :                                 continue;
     874             : 
     875          99 :                             if ( nScript == SCRIPTTYPE_ASIAN )
     876             :                             {
     877           0 :                                 if ( nCjkHeight == 0 )
     878           0 :                                     nCjkHeight = lcl_GetAttribHeight( *pPattern, ATTR_CJK_FONT_HEIGHT );
     879           0 :                                 if (nCjkHeight > pHeight[nRow-nStartRow])
     880           0 :                                     pHeight[nRow-nStartRow] = nCjkHeight;
     881             :                             }
     882          99 :                             else if ( nScript == SCRIPTTYPE_COMPLEX )
     883             :                             {
     884           0 :                                 if ( nCtlHeight == 0 )
     885           0 :                                     nCtlHeight = lcl_GetAttribHeight( *pPattern, ATTR_CTL_FONT_HEIGHT );
     886           0 :                                 if (nCtlHeight > pHeight[nRow-nStartRow])
     887           0 :                                     pHeight[nRow-nStartRow] = nCtlHeight;
     888             :                             }
     889             :                             else
     890             :                             {
     891          99 :                                 if ( nLatHeight == 0 )
     892           0 :                                     nLatHeight = lcl_GetAttribHeight( *pPattern, ATTR_FONT_HEIGHT );
     893          99 :                                 if (nLatHeight > pHeight[nRow-nStartRow])
     894           0 :                                     pHeight[nRow-nStartRow] = nLatHeight;
     895             :                             }
     896             :                         }
     897             :                     }
     898             :                 }
     899             :             }
     900             : 
     901     1568754 :             if (!bStdOnly)                      // search covered cells
     902             :             {
     903      133388 :                 ScNeededSizeOptions aOptions;
     904             : 
     905      133388 :                 sc::SingleColumnSpanSet::SpansType::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
     906      134184 :                 for (; it != itEnd; ++it)
     907             :                 {
     908        2374 :                     for (SCROW nRow = it->mnRow1; nRow <= it->mnRow2; ++nRow)
     909             :                     {
     910             :                         //  only calculate the cell height when it's used later (#37928#)
     911             : 
     912        1578 :                         if (rCxt.isForceAutoSize() || !(pDocument->GetRowFlags(nRow, nTab) & CR_MANUALSIZE) )
     913             :                         {
     914        1239 :                             aOptions.pPattern = pPattern;
     915             :                             sal_uInt16 nHeight = (sal_uInt16)
     916             :                                     ( GetNeededSize( nRow, rCxt.getOutputDevice(), rCxt.getPPTX(), rCxt.getPPTY(),
     917        1239 :                                                         rCxt.getZoomX(), rCxt.getZoomY(), false, aOptions ) / rCxt.getPPTY() );
     918        1239 :                             if (nHeight > pHeight[nRow-nStartRow])
     919         826 :                                 pHeight[nRow-nStartRow] = nHeight;
     920             :                         }
     921             :                     }
     922             :                 }
     923     1568754 :             }
     924             :         }
     925             : 
     926     1568783 :         if (nNextEnd > 0)
     927             :         {
     928           0 :             nStart = nEnd + 1;
     929           0 :             nEnd = nNextEnd;
     930           0 :             nNextEnd = 0;
     931             :         }
     932             :         else
     933     1568783 :             pPattern = aIter.Next(nStart,nEnd);
     934     1565696 :     }
     935     1565696 : }
     936             : 
     937           0 : bool ScColumn::GetNextSpellingCell(SCROW& nRow, bool bInSel, const ScMarkData& rData) const
     938             : {
     939           0 :     bool bStop = false;
     940           0 :     sc::CellStoreType::const_iterator it = maCells.position(nRow).first;
     941           0 :     mdds::mtv::element_t eType = it->type;
     942           0 :     if (!bInSel && it != maCells.end() && eType != sc::element_type_empty)
     943             :     {
     944           0 :         if ( (eType == sc::element_type_string || eType == sc::element_type_edittext) &&
     945           0 :              !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
     946           0 :                pDocument->IsTabProtected(nTab)) )
     947           0 :             return true;
     948             :     }
     949           0 :     while (!bStop)
     950             :     {
     951           0 :         if (bInSel)
     952             :         {
     953           0 :             nRow = rData.GetNextMarked(nCol, nRow, false);
     954           0 :             if (!ValidRow(nRow))
     955             :             {
     956           0 :                 nRow = MAXROW+1;
     957           0 :                 bStop = true;
     958             :             }
     959             :             else
     960             :             {
     961           0 :                 it = maCells.position(it, nRow).first;
     962           0 :                 eType = it->type;
     963           0 :                 if ( (eType == sc::element_type_string || eType == sc::element_type_edittext) &&
     964           0 :                      !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
     965           0 :                        pDocument->IsTabProtected(nTab)) )
     966           0 :                     return true;
     967             :                 else
     968           0 :                     nRow++;
     969             :             }
     970             :         }
     971           0 :         else if (GetNextDataPos(nRow))
     972             :         {
     973           0 :             it = maCells.position(it, nRow).first;
     974           0 :             eType = it->type;
     975           0 :             if ( (eType == sc::element_type_string || eType == sc::element_type_edittext) &&
     976           0 :                  !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
     977           0 :                    pDocument->IsTabProtected(nTab)) )
     978           0 :                 return true;
     979             :             else
     980           0 :                 nRow++;
     981             :         }
     982             :         else
     983             :         {
     984           0 :             nRow = MAXROW+1;
     985           0 :             bStop = true;
     986             :         }
     987             :     }
     988           0 :     return false;
     989             : }
     990             : 
     991             : namespace {
     992             : 
     993           8 : class StrEntries
     994             : {
     995             :     sc::CellStoreType& mrCells;
     996             : 
     997             : protected:
     998           0 :     struct StrEntry
     999             :     {
    1000             :         SCROW mnRow;
    1001             :         OUString maStr;
    1002             : 
    1003           0 :         StrEntry(SCROW nRow, const OUString& rStr) : mnRow(nRow), maStr(rStr) {}
    1004             :     };
    1005             : 
    1006             :     std::vector<StrEntry> maStrEntries;
    1007             :     ScDocument* mpDoc;
    1008             : 
    1009           8 :     StrEntries(sc::CellStoreType& rCells, ScDocument* pDoc) : mrCells(rCells), mpDoc(pDoc) {}
    1010             : 
    1011             : public:
    1012           8 :     void commitStrings()
    1013             :     {
    1014           8 :         svl::SharedStringPool& rPool = mpDoc->GetSharedStringPool();
    1015           8 :         sc::CellStoreType::iterator it = mrCells.begin();
    1016           8 :         std::vector<StrEntry>::iterator itStr = maStrEntries.begin(), itStrEnd = maStrEntries.end();
    1017           8 :         for (; itStr != itStrEnd; ++itStr)
    1018           0 :             it = mrCells.set(it, itStr->mnRow, rPool.intern(itStr->maStr));
    1019           8 :     }
    1020             : };
    1021             : 
    1022           8 : class RemoveEditAttribsHandler : public StrEntries
    1023             : {
    1024             :     boost::scoped_ptr<ScFieldEditEngine> mpEngine;
    1025             : 
    1026             : public:
    1027           8 :     RemoveEditAttribsHandler(sc::CellStoreType& rCells, ScDocument* pDoc) : StrEntries(rCells, pDoc) {}
    1028             : 
    1029           0 :     void operator() (size_t nRow, EditTextObject*& pObj)
    1030             :     {
    1031             :         //  For the test on hard formatting (ScEditAttrTester), are the defaults in the
    1032             :         //  EditEngine of no importance. When the tester would later recognise the same
    1033             :         //  attributes in default and hard formatting and has to remove them, the correct
    1034             :         //  defaults must be set in the EditEngine for each cell.
    1035             : 
    1036             :         //  test for attributes
    1037           0 :         if (!mpEngine)
    1038             :         {
    1039           0 :             mpEngine.reset(new ScFieldEditEngine(mpDoc, mpDoc->GetEditPool()));
    1040             :             //  EE_CNTRL_ONLINESPELLING if there are errors already
    1041           0 :             mpEngine->SetControlWord(mpEngine->GetControlWord() | EE_CNTRL_ONLINESPELLING);
    1042           0 :             mpDoc->ApplyAsianEditSettings(*mpEngine);
    1043             :         }
    1044           0 :         mpEngine->SetText(*pObj);
    1045           0 :         sal_Int32 nParCount = mpEngine->GetParagraphCount();
    1046           0 :         for (sal_Int32 nPar=0; nPar<nParCount; nPar++)
    1047             :         {
    1048           0 :             mpEngine->QuickRemoveCharAttribs(nPar);
    1049           0 :             const SfxItemSet& rOld = mpEngine->GetParaAttribs(nPar);
    1050           0 :             if ( rOld.Count() )
    1051             :             {
    1052           0 :                 SfxItemSet aNew( *rOld.GetPool(), rOld.GetRanges() );   // empty
    1053           0 :                 mpEngine->SetParaAttribs( nPar, aNew );
    1054             :             }
    1055             :         }
    1056             :         //  change URL field to text (not possible otherwise, thus pType=0)
    1057           0 :         mpEngine->RemoveFields(true);
    1058             : 
    1059           0 :         bool bSpellErrors = mpEngine->HasOnlineSpellErrors();
    1060           0 :         bool bNeedObject = bSpellErrors || nParCount>1;         // keep errors/paragraphs
    1061             :         //  ScEditAttrTester is not needed anymore, arrays are gone
    1062             : 
    1063           0 :         if (bNeedObject)                                      // remains edit cell
    1064             :         {
    1065           0 :             sal_uInt32 nCtrl = mpEngine->GetControlWord();
    1066           0 :             sal_uInt32 nWantBig = bSpellErrors ? EE_CNTRL_ALLOWBIGOBJS : 0;
    1067           0 :             if ( ( nCtrl & EE_CNTRL_ALLOWBIGOBJS ) != nWantBig )
    1068           0 :                 mpEngine->SetControlWord( (nCtrl & ~EE_CNTRL_ALLOWBIGOBJS) | nWantBig );
    1069             : 
    1070             :             // Overwrite the existing object.
    1071           0 :             delete pObj;
    1072           0 :             pObj = mpEngine->CreateTextObject();
    1073             :         }
    1074             :         else                                            // create String
    1075             :         {
    1076             :             // Store the string replacement for later commits.
    1077           0 :             OUString aText = ScEditUtil::GetSpaceDelimitedString(*mpEngine);
    1078           0 :             maStrEntries.push_back(StrEntry(nRow, aText));
    1079             :         }
    1080           0 :     }
    1081             : };
    1082             : 
    1083             : class TestTabRefAbsHandler
    1084             : {
    1085             :     SCTAB mnTab;
    1086             :     bool mbTestResult;
    1087             : public:
    1088           4 :     TestTabRefAbsHandler(SCTAB nTab) : mnTab(nTab), mbTestResult(false) {}
    1089             : 
    1090           2 :     void operator() (size_t /*nRow*/, const ScFormulaCell* pCell)
    1091             :     {
    1092           2 :         if (const_cast<ScFormulaCell*>(pCell)->TestTabRefAbs(mnTab))
    1093           1 :             mbTestResult = true;
    1094           2 :     }
    1095             : 
    1096           4 :     bool getTestResult() const { return mbTestResult; }
    1097             : };
    1098             : 
    1099             : }
    1100             : 
    1101           8 : void ScColumn::RemoveEditAttribs( SCROW nStartRow, SCROW nEndRow )
    1102             : {
    1103           8 :     RemoveEditAttribsHandler aFunc(maCells, pDocument);
    1104           8 :     sc::ProcessEditText(maCells.begin(), maCells, nStartRow, nEndRow, aFunc);
    1105           8 :     aFunc.commitStrings();
    1106           8 : }
    1107             : 
    1108           4 : bool ScColumn::TestTabRefAbs(SCTAB nTable) const
    1109             : {
    1110           4 :     TestTabRefAbsHandler aFunc(nTable);
    1111           4 :     sc::ParseFormula(maCells, aFunc);
    1112           4 :     return aFunc.getTestResult();
    1113             : }
    1114             : 
    1115     6336684 : bool ScColumn::IsEmptyData() const
    1116             : {
    1117     6336684 :     return maCells.block_size() == 1 && maCells.begin()->type == sc::element_type_empty;
    1118             : }
    1119             : 
    1120             : namespace {
    1121             : 
    1122             : class CellCounter
    1123             : {
    1124             :     size_t mnCount;
    1125             : public:
    1126           4 :     CellCounter() : mnCount(0) {}
    1127             : 
    1128           4 :     void operator() (
    1129             :         const sc::CellStoreType::value_type& node, size_t /*nOffset*/, size_t nDataSize)
    1130             :     {
    1131           4 :         if (node.type == sc::element_type_empty)
    1132           8 :             return;
    1133             : 
    1134           0 :         mnCount += nDataSize;
    1135             :     }
    1136             : 
    1137           4 :     size_t getCount() const { return mnCount; }
    1138             : };
    1139             : 
    1140             : }
    1141             : 
    1142           4 : SCSIZE ScColumn::VisibleCount( SCROW nStartRow, SCROW nEndRow ) const
    1143             : {
    1144           4 :     CellCounter aFunc;
    1145           4 :     sc::ParseBlock(maCells.begin(), maCells, aFunc, nStartRow, nEndRow);
    1146           4 :     return aFunc.getCount();
    1147             : }
    1148             : 
    1149        2098 : bool ScColumn::HasVisibleDataAt(SCROW nRow) const
    1150             : {
    1151        2098 :     std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
    1152        2098 :     sc::CellStoreType::const_iterator it = aPos.first;
    1153        2098 :     if (it == maCells.end())
    1154             :         // Likely invalid row number.
    1155           0 :         return false;
    1156             : 
    1157        2098 :     return it->type != sc::element_type_empty;
    1158             : }
    1159             : 
    1160          40 : bool ScColumn::IsEmptyAttr() const
    1161             : {
    1162          40 :     if (pAttrArray)
    1163          40 :         return pAttrArray->IsEmpty();
    1164             :     else
    1165           0 :         return true;
    1166             : }
    1167             : 
    1168          40 : bool ScColumn::IsEmpty() const
    1169             : {
    1170          40 :     return (IsEmptyData() && IsEmptyAttr());
    1171             : }
    1172             : 
    1173     3273983 : bool ScColumn::IsEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
    1174             : {
    1175     3273983 :     std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
    1176     3273983 :     sc::CellStoreType::const_iterator it = aPos.first;
    1177     3273983 :     if (it == maCells.end())
    1178             :         // Invalid row number.
    1179           0 :         return false;
    1180             : 
    1181     3273983 :     if (it->type != sc::element_type_empty)
    1182             :         // Non-empty cell at the start position.
    1183         438 :         return false;
    1184             : 
    1185             :     // start position of next block which is not empty.
    1186     3273545 :     SCROW nNextRow = nStartRow + it->size - aPos.second;
    1187     3273545 :     return nEndRow < nNextRow;
    1188             : }
    1189             : 
    1190         415 : bool ScColumn::IsNotesEmptyBlock(SCROW nStartRow, SCROW nEndRow) const
    1191             : {
    1192         415 :     std::pair<sc::CellNoteStoreType::const_iterator,size_t> aPos = maCellNotes.position(nStartRow);
    1193         415 :     sc::CellNoteStoreType::const_iterator it = aPos.first;
    1194         415 :     if (it == maCellNotes.end())
    1195             :         // Invalid row number.
    1196           0 :         return false;
    1197             : 
    1198         415 :     if (it->type != sc::element_type_empty)
    1199             :         // Non-empty cell at the start position.
    1200           0 :         return false;
    1201             : 
    1202             :     // start position of next block which is not empty.
    1203         415 :     SCROW nNextRow = nStartRow + it->size - aPos.second;
    1204         415 :     return nEndRow < nNextRow;
    1205             : }
    1206             : 
    1207          29 : SCSIZE ScColumn::GetEmptyLinesInBlock( SCROW nStartRow, SCROW nEndRow, ScDirection eDir ) const
    1208             : {
    1209             :     // Given a range of rows, find a top or bottom empty segment.  Skip the start row.
    1210          29 :     switch (eDir)
    1211             :     {
    1212             :         case DIR_TOP:
    1213             :         {
    1214             :             // Determine the length of empty head segment.
    1215           8 :             size_t nLength = nEndRow - nStartRow;
    1216           8 :             std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
    1217           8 :             sc::CellStoreType::const_iterator it = aPos.first;
    1218           8 :             if (it->type != sc::element_type_empty)
    1219             :                 // First row is already not empty.
    1220           8 :                 return 0;
    1221             : 
    1222             :             // length of this empty block minus the offset.
    1223           0 :             size_t nThisLen = it->size - aPos.second;
    1224           0 :             return std::min(nThisLen, nLength);
    1225             :         }
    1226             :         break;
    1227             :         case DIR_BOTTOM:
    1228             :         {
    1229             :             // Determine the length of empty tail segment.
    1230          21 :             size_t nLength = nEndRow - nStartRow;
    1231          21 :             std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nEndRow);
    1232          21 :             sc::CellStoreType::const_iterator it = aPos.first;
    1233          21 :             if (it->type != sc::element_type_empty)
    1234             :                 // end row is already not empty.
    1235          11 :                 return 0;
    1236             : 
    1237             :             // length of this empty block from the tip to the end row position.
    1238          10 :             size_t nThisLen = aPos.second + 1;
    1239          10 :             return std::min(nThisLen, nLength);
    1240             :         }
    1241             :         break;
    1242             :         default:
    1243             :             ;
    1244             :     }
    1245             : 
    1246           0 :     return 0;
    1247             : }
    1248             : 
    1249        2882 : SCROW ScColumn::GetFirstDataPos() const
    1250             : {
    1251        2882 :     if (IsEmptyData())
    1252           0 :         return 0;
    1253             : 
    1254        2882 :     sc::CellStoreType::const_iterator it = maCells.begin();
    1255        2882 :     if (it->type != sc::element_type_empty)
    1256        1036 :         return 0;
    1257             : 
    1258        1846 :     return it->size;
    1259             : }
    1260             : 
    1261     1855583 : SCROW ScColumn::GetLastDataPos() const
    1262             : {
    1263     1855583 :     if (IsEmptyData())
    1264     1835616 :         return 0;
    1265             : 
    1266       19967 :     sc::CellStoreType::const_reverse_iterator it = maCells.rbegin();
    1267       19967 :     if (it->type != sc::element_type_empty)
    1268           0 :         return MAXROW;
    1269             : 
    1270       19967 :     return MAXROW - static_cast<SCROW>(it->size);
    1271             : }
    1272             : 
    1273          15 : SCROW ScColumn::GetLastDataPos( SCROW nLastRow ) const
    1274             : {
    1275          15 :     sc::CellStoreType::const_position_type aPos = maCells.position(nLastRow);
    1276          15 :     if (aPos.first->type != sc::element_type_empty)
    1277          15 :         return nLastRow;
    1278             : 
    1279           0 :     if (aPos.first == maCells.begin())
    1280             :         // This is the first block, and is empty.
    1281           0 :         return 0;
    1282             : 
    1283           0 :     return static_cast<SCROW>(aPos.first->position - 1);
    1284             : }
    1285             : 
    1286           0 : bool ScColumn::GetPrevDataPos(SCROW& rRow) const
    1287             : {
    1288           0 :     std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRow);
    1289           0 :     sc::CellStoreType::const_iterator it = aPos.first;
    1290           0 :     if (it == maCells.end())
    1291           0 :         return false;
    1292             : 
    1293           0 :     if (it->type == sc::element_type_empty)
    1294             :     {
    1295           0 :         if (it == maCells.begin())
    1296             :             // No more previous non-empty cell.
    1297           0 :             return false;
    1298             : 
    1299           0 :         rRow -= aPos.second + 1; // Last row position of the previous block.
    1300           0 :         return true;
    1301             :     }
    1302             : 
    1303             :     // This block is not empty.
    1304           0 :     if (aPos.second)
    1305             :     {
    1306             :         // There are preceding cells in this block. Simply move back one cell.
    1307           0 :         --rRow;
    1308           0 :         return true;
    1309             :     }
    1310             : 
    1311             :     // This is the first cell in an non-empty block. Move back to the previous block.
    1312           0 :     if (it == maCells.begin())
    1313             :         // No more preceding block.
    1314           0 :         return false;
    1315             : 
    1316           0 :     --rRow; // Move to the last cell of the previous block.
    1317           0 :     --it;
    1318           0 :     if (it->type == sc::element_type_empty)
    1319             :     {
    1320             :         // This block is empty.
    1321           0 :         if (it == maCells.begin())
    1322             :             // No more preceding blocks.
    1323           0 :             return false;
    1324             : 
    1325             :         // Skip the whole empty block segment.
    1326           0 :         rRow -= it->size;
    1327             :     }
    1328             : 
    1329           0 :     return true;
    1330             : }
    1331             : 
    1332        4070 : bool ScColumn::GetNextDataPos(SCROW& rRow) const        // greater than rRow
    1333             : {
    1334        4070 :     std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRow);
    1335        4070 :     sc::CellStoreType::const_iterator it = aPos.first;
    1336        4070 :     if (it == maCells.end())
    1337           0 :         return false;
    1338             : 
    1339        4070 :     if (it->type == sc::element_type_empty)
    1340             :     {
    1341             :         // This block is empty. Skip ahead to the next block (if exists).
    1342         527 :         rRow += it->size - aPos.second;
    1343         527 :         ++it;
    1344         527 :         if (it == maCells.end())
    1345             :             // No more next block.
    1346          65 :             return false;
    1347             : 
    1348             :         // Next block exists, and is non-empty.
    1349         462 :         return true;
    1350             :     }
    1351             : 
    1352        3543 :     if (aPos.second < it->size - 1)
    1353             :     {
    1354             :         // There are still cells following the current position.
    1355        2347 :         ++rRow;
    1356        2347 :         return true;
    1357             :     }
    1358             : 
    1359             :     // This is the last cell in the block. Move ahead to the next block.
    1360        1196 :     rRow += it->size - aPos.second; // First cell in the next block.
    1361        1196 :     ++it;
    1362        1196 :     if (it == maCells.end())
    1363             :         // No more next block.
    1364           0 :         return false;
    1365             : 
    1366        1196 :     if (it->type == sc::element_type_empty)
    1367             :     {
    1368             :         // Next block is empty. Move to the next block.
    1369        1051 :         rRow += it->size;
    1370        1051 :         ++it;
    1371        1051 :         if (it == maCells.end())
    1372         551 :             return false;
    1373             :     }
    1374             : 
    1375         645 :     return true;
    1376             : }
    1377             : 
    1378          28 : SCROW ScColumn::FindNextVisibleRow(SCROW nRow, bool bForward) const
    1379             : {
    1380          28 :     if(bForward)
    1381             :     {
    1382          19 :         nRow++;
    1383          19 :         SCROW nEndRow = 0;
    1384          19 :         bool bHidden = pDocument->RowHidden(nRow, nTab, NULL, &nEndRow);
    1385          19 :         if(bHidden)
    1386           2 :             return std::min<SCROW>(MAXROW, nEndRow + 1);
    1387             :         else
    1388          17 :             return nRow;
    1389             :     }
    1390             :     else
    1391             :     {
    1392           9 :         nRow--;
    1393           9 :         SCROW nStartRow = MAXROW;
    1394           9 :         bool bHidden = pDocument->RowHidden(nRow, nTab, &nStartRow, NULL);
    1395           9 :         if(bHidden)
    1396           2 :             return std::max<SCROW>(0, nStartRow - 1);
    1397             :         else
    1398           7 :             return nRow;
    1399             :     }
    1400             : }
    1401             : 
    1402           7 : SCROW ScColumn::FindNextVisibleRowWithContent(
    1403             :     sc::CellStoreType::const_iterator& itPos, SCROW nRow, bool bForward) const
    1404             : {
    1405           7 :     if (bForward)
    1406             :     {
    1407           2 :         do
    1408             :         {
    1409           6 :             nRow++;
    1410           6 :             SCROW nEndRow = 0;
    1411           6 :             bool bHidden = pDocument->RowHidden(nRow, nTab, NULL, &nEndRow);
    1412           6 :             if (bHidden)
    1413             :             {
    1414           1 :                 nRow = nEndRow + 1;
    1415           1 :                 if(nRow >= MAXROW)
    1416           4 :                     return MAXROW;
    1417             :             }
    1418             : 
    1419           6 :             std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(itPos, nRow);
    1420           6 :             itPos = aPos.first;
    1421           6 :             if (itPos == maCells.end())
    1422             :                 // Invalid row.
    1423           0 :                 return MAXROW;
    1424             : 
    1425           6 :             if (itPos->type != sc::element_type_empty)
    1426           4 :                 return nRow;
    1427             : 
    1428             :             // Move to the last cell of the current empty block.
    1429           2 :             nRow += itPos->size - aPos.second - 1;
    1430             :         }
    1431             :         while (nRow < MAXROW);
    1432             : 
    1433           1 :         return MAXROW;
    1434             :     }
    1435             : 
    1436           2 :     do
    1437             :     {
    1438           3 :         nRow--;
    1439           3 :         SCROW nStartRow = MAXROW;
    1440           3 :         bool bHidden = pDocument->RowHidden(nRow, nTab, &nStartRow, NULL);
    1441           3 :         if (bHidden)
    1442             :         {
    1443           0 :             nRow = nStartRow - 1;
    1444           0 :             if(nRow <= 0)
    1445           1 :                 return 0;
    1446             :         }
    1447             : 
    1448           3 :         std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(itPos, nRow);
    1449           3 :         itPos = aPos.first;
    1450           3 :         if (itPos == maCells.end())
    1451             :             // Invalid row.
    1452           0 :             return 0;
    1453             : 
    1454           3 :         if (itPos->type != sc::element_type_empty)
    1455           1 :             return nRow;
    1456             : 
    1457             :         // Move to the first cell of the current empty block.
    1458           2 :         nRow -= aPos.second;
    1459             :     }
    1460             :     while (nRow > 0);
    1461             : 
    1462           1 :     return 0;
    1463             : }
    1464             : 
    1465     2598459 : void ScColumn::CellStorageModified()
    1466             : {
    1467             :     // TODO: Update column's "last updated" timestamp here.
    1468             : 
    1469     2598459 :     mbDirtyGroups = true;
    1470             : 
    1471             : #if DEBUG_COLUMN_STORAGE
    1472             :     if (maCells.size() != MAXROWCOUNT)
    1473             :     {
    1474             :         cout << "ScColumn::CellStorageModified: Size of the cell array is incorrect." << endl;
    1475             :         cout.flush();
    1476             :         abort();
    1477             :     }
    1478             : 
    1479             :     if (maCellTextAttrs.size() != MAXROWCOUNT)
    1480             :     {
    1481             :         cout << "ScColumn::CellStorageModified: Size of the cell text attribute array is incorrect." << endl;
    1482             :         cout.flush();
    1483             :         abort();
    1484             :     }
    1485             : 
    1486             :     if (maBroadcasters.size() != MAXROWCOUNT)
    1487             :     {
    1488             :         cout << "ScColumn::CellStorageModified: Size of the broadcaster array is incorrect." << endl;
    1489             :         cout.flush();
    1490             :         abort();
    1491             :     }
    1492             : 
    1493             :     // Make sure that these two containers are synchronized wrt empty segments.
    1494             :     sc::CellStoreType::const_iterator itCell = maCells.begin();
    1495             :     sc::CellTextAttrStoreType::const_iterator itAttr = maCellTextAttrs.begin();
    1496             : 
    1497             :     // Move to the first empty blocks.
    1498             :     while (itCell != maCells.end() && itCell->type != sc::element_type_empty)
    1499             :         ++itCell;
    1500             : 
    1501             :     while (itAttr != maCellTextAttrs.end() && itAttr->type != sc::element_type_empty)
    1502             :         ++itAttr;
    1503             : 
    1504             :     while (itCell != maCells.end())
    1505             :     {
    1506             :         if (itCell->position != itAttr->position || itCell->size != itAttr->size)
    1507             :         {
    1508             :             cout << "ScColumn::CellStorageModified: Cell array and cell text attribute array are out of sync." << endl;
    1509             :             cout << "-- cell array" << endl;
    1510             :             maCells.dump_blocks(cout);
    1511             :             cout << "-- attribute array" << endl;
    1512             :             maCellTextAttrs.dump_blocks(cout);
    1513             :             cout.flush();
    1514             :             abort();
    1515             :         }
    1516             : 
    1517             :         // Move to the next empty blocks.
    1518             :         ++itCell;
    1519             :         while (itCell != maCells.end() && itCell->type != sc::element_type_empty)
    1520             :             ++itCell;
    1521             : 
    1522             :         ++itAttr;
    1523             :         while (itAttr != maCellTextAttrs.end() && itAttr->type != sc::element_type_empty)
    1524             :             ++itAttr;
    1525             :     }
    1526             : #endif
    1527     2598459 : }
    1528             : 
    1529             : #if DEBUG_COLUMN_STORAGE
    1530             : 
    1531             : namespace {
    1532             : 
    1533             : struct FormulaGroupDumper : std::unary_function<sc::CellStoreType::value_type, void>
    1534             : {
    1535             :     void operator() (const sc::CellStoreType::value_type& rNode) const
    1536             :     {
    1537             :         if (rNode.type != sc::element_type_formula)
    1538             :             return;
    1539             : 
    1540             :         cout << "  -- formula block" << endl;
    1541             :         sc::formula_block::const_iterator it = sc::formula_block::begin(*rNode.data);
    1542             :         sc::formula_block::const_iterator itEnd = sc::formula_block::end(*rNode.data);
    1543             : 
    1544             :         for (; it != itEnd; ++it)
    1545             :         {
    1546             :             const ScFormulaCell& rCell = **it;
    1547             :             if (!rCell.IsShared())
    1548             :             {
    1549             :                 cout << "  + row " << rCell.aPos.Row() << " not shared" << endl;
    1550             :                 continue;
    1551             :             }
    1552             : 
    1553             :             if (rCell.GetSharedTopRow() != rCell.aPos.Row())
    1554             :             {
    1555             :                 cout << "  + row " << rCell.aPos.Row() << " shared with top row " << rCell.GetSharedTopRow() << " with length " << rCell.GetSharedLength() << endl;
    1556             :                 continue;
    1557             :             }
    1558             : 
    1559             :             SCROW nLen = rCell.GetSharedLength();
    1560             :             cout << "  * group: start=" << rCell.aPos.Row() << ", length=" << nLen << endl;
    1561             :             std::advance(it, nLen-1);
    1562             :         }
    1563             :     }
    1564             : };
    1565             : 
    1566             : }
    1567             : 
    1568             : void ScColumn::DumpFormulaGroups() const
    1569             : {
    1570             :     cout << "-- formua groups" << endl;
    1571             :     std::for_each(maCells.begin(), maCells.end(), FormulaGroupDumper());
    1572             :     cout << "--" << endl;
    1573             : }
    1574             : #endif
    1575             : 
    1576           3 : void ScColumn::CopyCellTextAttrsToDocument(SCROW nRow1, SCROW nRow2, ScColumn& rDestCol) const
    1577             : {
    1578           3 :     rDestCol.maCellTextAttrs.set_empty(nRow1, nRow2); // Empty the destination range first.
    1579             : 
    1580           3 :     sc::CellTextAttrStoreType::const_iterator itBlk = maCellTextAttrs.begin(), itBlkEnd = maCellTextAttrs.end();
    1581             : 
    1582             :     // Locate the top row position.
    1583           3 :     size_t nOffsetInBlock = 0;
    1584           3 :     size_t nBlockStart = 0, nBlockEnd = 0, nRowPos = static_cast<size_t>(nRow1);
    1585           3 :     for (; itBlk != itBlkEnd; ++itBlk)
    1586             :     {
    1587           3 :         nBlockEnd = nBlockStart + itBlk->size;
    1588           3 :         if (nBlockStart <= nRowPos && nRowPos < nBlockEnd)
    1589             :         {
    1590             :             // Found.
    1591           3 :             nOffsetInBlock = nRowPos - nBlockStart;
    1592           3 :             break;
    1593             :         }
    1594             :     }
    1595             : 
    1596           3 :     if (itBlk == itBlkEnd)
    1597             :         // Specified range not found. Bail out.
    1598           3 :         return;
    1599             : 
    1600           3 :     nRowPos = static_cast<size_t>(nRow2); // End row position.
    1601             : 
    1602             :     // Keep copying until we hit the end row position.
    1603           3 :     sc::celltextattr_block::const_iterator itData, itDataEnd;
    1604           5 :     for (; itBlk != itBlkEnd; ++itBlk, nBlockStart = nBlockEnd, nOffsetInBlock = 0)
    1605             :     {
    1606           4 :         nBlockEnd = nBlockStart + itBlk->size;
    1607           4 :         if (!itBlk->data)
    1608             :         {
    1609             :             // Empty block.
    1610           1 :             if (nBlockStart <= nRowPos && nRowPos < nBlockEnd)
    1611             :                 // This block contains the end row.
    1612           1 :                 rDestCol.maCellTextAttrs.set_empty(nBlockStart + nOffsetInBlock, nRowPos);
    1613             :             else
    1614           0 :                 rDestCol.maCellTextAttrs.set_empty(nBlockStart + nOffsetInBlock, nBlockEnd-1);
    1615             : 
    1616           1 :             continue;
    1617             :         }
    1618             : 
    1619             :         // Non-empty block.
    1620           3 :         itData = sc::celltextattr_block::begin(*itBlk->data);
    1621           3 :         itDataEnd = sc::celltextattr_block::end(*itBlk->data);
    1622           3 :         std::advance(itData, nOffsetInBlock);
    1623             : 
    1624           3 :         if (nBlockStart <= nRowPos && nRowPos < nBlockEnd)
    1625             :         {
    1626             :             // This block contains the end row. Only copy partially.
    1627           2 :             size_t nOffset = nRowPos - nBlockStart + 1;
    1628           2 :             itDataEnd = sc::celltextattr_block::begin(*itBlk->data);
    1629           2 :             std::advance(itDataEnd, nOffset);
    1630             : 
    1631           2 :             rDestCol.maCellTextAttrs.set(nBlockStart + nOffsetInBlock, itData, itDataEnd);
    1632           2 :             break;
    1633             :         }
    1634             : 
    1635           1 :         rDestCol.maCellTextAttrs.set(nBlockStart + nOffsetInBlock, itData, itDataEnd);
    1636             :     }
    1637             : }
    1638             : 
    1639             : namespace {
    1640             : 
    1641             : class CopyCellNotesHandler
    1642             : {
    1643             :     ScColumn& mrDestCol;
    1644             :     sc::CellNoteStoreType& mrDestNotes;
    1645             :     sc::CellNoteStoreType::iterator miPos;
    1646             :     SCTAB mnSrcTab;
    1647             :     SCCOL mnSrcCol;
    1648             :     SCTAB mnDestTab;
    1649             :     SCCOL mnDestCol;
    1650             :     SCROW mnDestOffset; /// Add this to the source row position to get the destination row.
    1651             :     bool mbCloneCaption;
    1652             : 
    1653             : public:
    1654       51477 :     CopyCellNotesHandler( const ScColumn& rSrcCol, ScColumn& rDestCol, SCROW nDestOffset, bool bCloneCaption ) :
    1655             :         mrDestCol(rDestCol),
    1656       51477 :         mrDestNotes(rDestCol.GetCellNoteStore()),
    1657             :         miPos(mrDestNotes.begin()),
    1658       51477 :         mnSrcTab(rSrcCol.GetTab()),
    1659       51477 :         mnSrcCol(rSrcCol.GetCol()),
    1660       51477 :         mnDestTab(rDestCol.GetTab()),
    1661       51477 :         mnDestCol(rDestCol.GetCol()),
    1662             :         mnDestOffset(nDestOffset),
    1663      308862 :         mbCloneCaption(bCloneCaption) {}
    1664             : 
    1665          48 :     void operator() ( size_t nRow, const ScPostIt* p )
    1666             :     {
    1667          48 :         SCROW nDestRow = nRow + mnDestOffset;
    1668          48 :         ScAddress aSrcPos(mnSrcCol, nRow, mnSrcTab);
    1669          48 :         ScAddress aDestPos(mnDestCol, nDestRow, mnDestTab);
    1670          48 :         miPos = mrDestNotes.set(miPos, nDestRow, p->Clone(aSrcPos, mrDestCol.GetDoc(), aDestPos, mbCloneCaption));
    1671          48 :     }
    1672             : };
    1673             : 
    1674             : }
    1675             : 
    1676       51477 : void ScColumn::CopyCellNotesToDocument(
    1677             :     SCROW nRow1, SCROW nRow2, ScColumn& rDestCol, bool bCloneCaption, SCROW nRowOffsetDest ) const
    1678             : {
    1679       51477 :     CopyCellNotesHandler aFunc(*this, rDestCol, nRowOffsetDest, bCloneCaption);
    1680       51477 :     sc::ParseNote(maCellNotes.begin(), maCellNotes, nRow1, nRow2, aFunc);
    1681       51477 : }
    1682             : 
    1683       51474 : void ScColumn::DuplicateNotes(SCROW nStartRow, size_t nDataSize, ScColumn& rDestCol, sc::ColumnBlockPosition& maDestBlockPos,
    1684             :                               bool bCloneCaption, SCROW nRowOffsetDest ) const
    1685             : {
    1686       51474 :     CopyCellNotesToDocument(nStartRow, nStartRow + nDataSize -1, rDestCol, bCloneCaption, nRowOffsetDest);
    1687       51474 :     maDestBlockPos.miCellNotePos = rDestCol.maCellNotes.begin();
    1688       51474 : }
    1689             : 
    1690          29 : void ScColumn::SwapCellTextAttrs( SCROW nRow1, SCROW nRow2 )
    1691             : {
    1692          29 :     if (nRow1 == nRow2)
    1693          29 :         return;
    1694             : 
    1695          29 :     if (nRow1 > nRow2)
    1696           0 :         std::swap(nRow1, nRow2);
    1697             : 
    1698          29 :     sc::CellTextAttrStoreType::position_type aPos1 = maCellTextAttrs.position(nRow1);
    1699          29 :     if (aPos1.first == maCellTextAttrs.end())
    1700           0 :         return;
    1701             : 
    1702          29 :     sc::CellTextAttrStoreType::position_type aPos2 = maCellTextAttrs.position(aPos1.first, nRow2);
    1703          29 :     if (aPos2.first == maCellTextAttrs.end())
    1704           0 :         return;
    1705             : 
    1706          29 :     sc::CellTextAttrStoreType::iterator it1 = aPos1.first, it2 = aPos2.first;
    1707          29 :     if (it1->type == it2->type)
    1708             :     {
    1709          26 :         if (it1->type == sc::element_type_empty)
    1710             :             // Both are empty. Nothing to swap.
    1711           0 :             return;
    1712             : 
    1713             :         // Both are non-empty. Simply swap their values.
    1714             :         std::swap(
    1715          26 :             sc::celltextattr_block::at(*it1->data, aPos1.second),
    1716          52 :             sc::celltextattr_block::at(*it2->data, aPos2.second));
    1717             : 
    1718          26 :         return;
    1719             :     }
    1720             : 
    1721             :     // One is empty while the other isn't.
    1722           3 :     if (it1->type == sc::element_type_empty)
    1723             :     {
    1724             :         // row 1 is empty while row 2 is non-empty.
    1725           3 :         const sc::CellTextAttr& rVal2 = sc::celltextattr_block::at(*it2->data, aPos2.second);
    1726           3 :         it1 = maCellTextAttrs.set(it1, nRow1, rVal2);
    1727           3 :         maCellTextAttrs.set_empty(it1, nRow2, nRow2);
    1728           3 :         return;
    1729             :     }
    1730             : 
    1731             :     // row 1 is non-empty while row 2 is empty.
    1732           0 :     sc::CellTextAttr aVal1 = sc::celltextattr_block::at(*it1->data, aPos1.second); // make a copy.
    1733           0 :     it1 = maCellTextAttrs.set_empty(it1, nRow1, nRow1);
    1734           0 :     maCellTextAttrs.set(it1, nRow2, aVal1);
    1735             : 
    1736           0 :     CellStorageModified();
    1737             : }
    1738             : 
    1739          29 : void ScColumn::SwapCellNotes( SCROW nRow1, SCROW nRow2 )
    1740             : {
    1741          29 :     if (nRow1 == nRow2)
    1742          29 :         return;
    1743             : 
    1744          29 :     if (nRow1 > nRow2)
    1745           0 :         std::swap(nRow1, nRow2);
    1746             : 
    1747          29 :     sc::CellNoteStoreType::position_type aPos1 = maCellNotes.position(nRow1);
    1748          29 :     if (aPos1.first == maCellNotes.end())
    1749           0 :         return;
    1750             : 
    1751          29 :     sc::CellNoteStoreType::position_type aPos2 = maCellNotes.position(aPos1.first, nRow2);
    1752          29 :     if (aPos2.first == maCellNotes.end())
    1753           0 :         return;
    1754             : 
    1755          29 :     sc::CellNoteStoreType::iterator it1 = aPos1.first, it2 = aPos2.first;
    1756          29 :     if (it1->type == it2->type)
    1757             :     {
    1758          28 :         if (it1->type == sc::element_type_empty)
    1759             :             // Both are empty. Nothing to swap.
    1760          28 :             return;
    1761             : 
    1762             :         // Both are non-empty. Simply swap their values.
    1763             :         std::swap(
    1764           0 :             sc::cellnote_block::at(*it1->data, aPos1.second),
    1765           0 :             sc::cellnote_block::at(*it2->data, aPos2.second));
    1766             : 
    1767             :         //update Note caption with position
    1768           0 :         ScPostIt* pNote = sc::cellnote_block::at(*it1->data, aPos1.second);
    1769           0 :         pNote->UpdateCaptionPos(ScAddress(nCol,nRow2,nTab));
    1770           0 :         pNote = sc::cellnote_block::at(*it2->data, aPos2.second);
    1771           0 :         pNote->UpdateCaptionPos(ScAddress(nCol,nRow1,nTab));
    1772             : 
    1773           0 :         return;
    1774             :     }
    1775             : 
    1776             :     // One is empty while the other isn't.
    1777           1 :     if (it1->type == sc::element_type_empty)
    1778             :     {
    1779             :         // row 1 is empty while row 2 is non-empty.
    1780           1 :         ScPostIt* pVal2 = sc::cellnote_block::at(*it2->data, aPos2.second);
    1781           1 :         it1 = maCellNotes.set(it1, nRow1, pVal2);
    1782           1 :         maCellNotes.release(it1, nRow2, pVal2);
    1783           1 :         pVal2->UpdateCaptionPos(ScAddress(nCol,nRow1,nTab)); //update Note caption with position
    1784             : 
    1785           1 :         return;
    1786             :     }
    1787             : 
    1788             :     // row 1 is non-empty while row 2 is empty.
    1789           0 :     ScPostIt* pVal1 = NULL;
    1790           0 :     it1 = maCellNotes.release(it1, nRow1, pVal1);
    1791             :     assert(pVal1);
    1792           0 :     maCellNotes.set(it1, nRow2, pVal1);
    1793           0 :     pVal1->UpdateCaptionPos(ScAddress(nCol,nRow1,nTab));     //update Note caption with position
    1794             : }
    1795             : 
    1796       55462 : SvtBroadcaster* ScColumn::GetBroadcaster(SCROW nRow)
    1797             : {
    1798       55462 :     return maBroadcasters.get<SvtBroadcaster*>(nRow);
    1799             : }
    1800             : 
    1801          14 : const SvtBroadcaster* ScColumn::GetBroadcaster(SCROW nRow) const
    1802             : {
    1803          14 :     return maBroadcasters.get<SvtBroadcaster*>(nRow);
    1804             : }
    1805             : 
    1806          72 : void ScColumn::DeleteBroadcasters( sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2 )
    1807             : {
    1808         144 :     rBlockPos.miBroadcasterPos =
    1809          72 :         maBroadcasters.set_empty(rBlockPos.miBroadcasterPos, nRow1, nRow2);
    1810          72 : }
    1811             : 
    1812     1763328 : void ScColumn::PrepareBroadcastersForDestruction()
    1813             : {
    1814     1763328 :     sc::BroadcasterStoreType::iterator itPos = maBroadcasters.begin(), itPosEnd = maBroadcasters.end();
    1815     3529570 :     for (; itPos != itPosEnd; ++itPos)
    1816             :     {
    1817     1766242 :         if (itPos->type == sc::element_type_broadcaster)
    1818             :         {
    1819        1537 :             sc::broadcaster_block::iterator it = sc::broadcaster_block::begin(*itPos->data);
    1820        1537 :             sc::broadcaster_block::iterator itEnd = sc::broadcaster_block::end(*itPos->data);
    1821        5443 :             for (; it != itEnd; ++it)
    1822        3906 :                 (*it)->PrepareForDestruction();
    1823             :         }
    1824             :     }
    1825     1763328 : }
    1826             : 
    1827           0 : bool ScColumn::HasBroadcaster() const
    1828             : {
    1829           0 :     sc::BroadcasterStoreType::const_iterator it = maBroadcasters.begin(), itEnd = maBroadcasters.end();
    1830           0 :     for (; it != itEnd; ++it)
    1831             :     {
    1832           0 :         if (it->type == sc::element_type_broadcaster)
    1833             :             // Having a broadcaster block automatically means there is at least one broadcaster.
    1834           0 :             return true;
    1835             :     }
    1836           0 :     return false;
    1837             : }
    1838             : 
    1839      168597 : ScPostIt* ScColumn::GetCellNote(SCROW nRow)
    1840             : {
    1841      168597 :     return maCellNotes.get<ScPostIt*>(nRow);
    1842             : }
    1843             : 
    1844           0 : const ScPostIt* ScColumn::GetCellNote(SCROW nRow) const
    1845             : {
    1846           0 :     return maCellNotes.get<ScPostIt*>(nRow);
    1847             : }
    1848             : 
    1849          59 : void ScColumn::SetCellNote(SCROW nRow, ScPostIt* pNote)
    1850             : {
    1851             :     //pNote->UpdateCaptionPos(ScAddress(nCol, nRow, nTab)); // TODO notes usefull ? slow import with many notes
    1852          59 :     maCellNotes.set(nRow, pNote);
    1853          59 : }
    1854             : 
    1855       23741 : void ScColumn::DeleteCellNotes( sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2 )
    1856             : {
    1857       47482 :     rBlockPos.miCellNotePos =
    1858       23741 :         maCellNotes.set_empty(rBlockPos.miCellNotePos, nRow1, nRow2);
    1859       23741 : }
    1860             : 
    1861     2742283 : bool ScColumn::HasCellNotes() const
    1862             : {
    1863     2742283 :     sc::CellNoteStoreType::const_iterator it = maCellNotes.begin(), itEnd = maCellNotes.end();
    1864     5484561 :     for (; it != itEnd; ++it)
    1865             :     {
    1866     2742350 :         if (it->type == sc::element_type_cellnote)
    1867             :             // Having a cellnote block automatically means there is at least one cell note.
    1868          72 :             return true;
    1869             :     }
    1870     2742211 :     return false;
    1871             : }
    1872             : 
    1873          42 : SCROW ScColumn::GetCellNotesMaxRow() const
    1874             : {
    1875             :     // hypothesis : the column has cell notes (should be checked before)
    1876          42 :     SCROW maxRow = 0;
    1877          42 :     sc::CellNoteStoreType::const_iterator it = maCellNotes.begin(), itEnd = maCellNotes.end();
    1878         166 :     for (; it != itEnd; ++it)
    1879             :     {
    1880         124 :         if (it->type == sc::element_type_cellnote)
    1881          42 :             maxRow = it->position + it->size -1;
    1882             :     }
    1883          42 :     return maxRow;
    1884             : }
    1885          27 : SCROW ScColumn::GetCellNotesMinRow() const
    1886             : {
    1887             :     // hypothesis : the column has cell notes (should be checked before)
    1888          27 :     SCROW minRow = 0;
    1889          27 :     bool bFound = false;
    1890          27 :     sc::CellNoteStoreType::const_iterator it = maCellNotes.begin(), itEnd = maCellNotes.end();
    1891          81 :     for (; it != itEnd && !bFound; ++it)
    1892             :     {
    1893          54 :         if (it->type == sc::element_type_cellnote)
    1894             :         {
    1895          27 :             bFound = true;
    1896          27 :             minRow = it->position;
    1897             :         }
    1898             :     }
    1899          27 :     return minRow;
    1900             : }
    1901             : 
    1902          49 : sal_uInt16 ScColumn::GetTextWidth(SCROW nRow) const
    1903             : {
    1904          49 :     return maCellTextAttrs.get<sc::CellTextAttr>(nRow).mnTextWidth;
    1905             : }
    1906             : 
    1907          20 : void ScColumn::SetTextWidth(SCROW nRow, sal_uInt16 nWidth)
    1908             : {
    1909          20 :     sc::CellTextAttrStoreType::position_type aPos = maCellTextAttrs.position(nRow);
    1910          20 :     if (aPos.first->type != sc::element_type_celltextattr)
    1911          20 :         return;
    1912             : 
    1913             :     // Set new value only when the slot is not empty.
    1914          20 :     sc::celltextattr_block::at(*aPos.first->data, aPos.second).mnTextWidth = nWidth;
    1915          20 :     CellStorageModified();
    1916             : }
    1917             : 
    1918       19219 : sal_uInt8 ScColumn::GetScriptType( SCROW nRow ) const
    1919             : {
    1920       19219 :     if (!ValidRow(nRow) || maCellTextAttrs.is_empty(nRow))
    1921         960 :         return 0;
    1922             : 
    1923       18259 :     return maCellTextAttrs.get<sc::CellTextAttr>(nRow).mnScriptType;
    1924             : }
    1925             : 
    1926       60929 : sal_uInt8 ScColumn::GetRangeScriptType(
    1927             :     sc::CellTextAttrStoreType::iterator& itPos, SCROW nRow1, SCROW nRow2, sc::CellStoreType::iterator itrCells )
    1928             : {
    1929       60929 :     if (!ValidRow(nRow1) || !ValidRow(nRow2) || nRow1 > nRow2)
    1930           0 :         return 0;
    1931             : 
    1932       60929 :     SCROW nRow = nRow1;
    1933             :     std::pair<sc::CellTextAttrStoreType::iterator,size_t> aRet =
    1934       60929 :         maCellTextAttrs.position(itPos, nRow1);
    1935             : 
    1936       60929 :     itPos = aRet.first; // Track the position of cell text attribute array.
    1937             : 
    1938       60929 :     sal_uInt8 nScriptType = 0;
    1939       60929 :     bool bUpdated = false;
    1940       60929 :     if (itPos->type == sc::element_type_celltextattr)
    1941             :     {
    1942       60927 :         sc::celltextattr_block::iterator it = sc::celltextattr_block::begin(*itPos->data);
    1943       60927 :         sc::celltextattr_block::iterator itEnd = sc::celltextattr_block::end(*itPos->data);
    1944       60927 :         std::advance(it, aRet.second);
    1945      121864 :         for (; it != itEnd; ++it, ++nRow)
    1946             :         {
    1947      119616 :             if (nRow > nRow2)
    1948       58679 :                 return nScriptType;
    1949             : 
    1950       60937 :             sc::CellTextAttr& rVal = *it;
    1951       60937 :             if (UpdateScriptType(rVal, nRow, itrCells))
    1952       23113 :                 bUpdated = true;
    1953       60937 :             nScriptType |= rVal.mnScriptType;
    1954             :         }
    1955             :     }
    1956             :     else
    1957             :     {
    1958             :         // Skip this whole block.
    1959           2 :         nRow += itPos->size - aRet.second;
    1960             :     }
    1961             : 
    1962        4500 :     while (nRow <= nRow2)
    1963             :     {
    1964           0 :         ++itPos;
    1965           0 :         if (itPos == maCellTextAttrs.end())
    1966           0 :             return nScriptType;
    1967             : 
    1968           0 :         if (itPos->type != sc::element_type_celltextattr)
    1969             :         {
    1970             :             // Skip this whole block.
    1971           0 :             nRow += itPos->size;
    1972           0 :             continue;
    1973             :         }
    1974             : 
    1975           0 :         sc::celltextattr_block::iterator it = sc::celltextattr_block::begin(*itPos->data);
    1976           0 :         sc::celltextattr_block::iterator itEnd = sc::celltextattr_block::end(*itPos->data);
    1977           0 :         for (; it != itEnd; ++it, ++nRow)
    1978             :         {
    1979           0 :             if (nRow > nRow2)
    1980           0 :                 return nScriptType;
    1981             : 
    1982           0 :             sc::CellTextAttr& rVal = *it;
    1983           0 :             if (UpdateScriptType(rVal, nRow, itrCells))
    1984           0 :                 bUpdated = true;
    1985             : 
    1986           0 :             nScriptType |= rVal.mnScriptType;
    1987             :         }
    1988             :     }
    1989             : 
    1990        2250 :     if (bUpdated)
    1991         594 :         CellStorageModified();
    1992             : 
    1993        2250 :     return nScriptType;
    1994             : }
    1995             : 
    1996        3186 : void ScColumn::SetScriptType( SCROW nRow, sal_uInt8 nType )
    1997             : {
    1998        3186 :     if (!ValidRow(nRow))
    1999           0 :         return;
    2000             : 
    2001        3186 :     sc::CellTextAttrStoreType::position_type aPos = maCellTextAttrs.position(nRow);
    2002        3186 :     if (aPos.first->type != sc::element_type_celltextattr)
    2003             :         // Set new value only when the slot is already set.
    2004           0 :         return;
    2005             : 
    2006        3186 :     sc::celltextattr_block::at(*aPos.first->data, aPos.second).mnScriptType = nType;
    2007        3186 :     CellStorageModified();
    2008             : }
    2009             : 
    2010          38 : size_t ScColumn::GetFormulaHash( SCROW nRow ) const
    2011             : {
    2012          38 :     const ScFormulaCell* pCell = FetchFormulaCell(nRow);
    2013          38 :     return pCell ? pCell->GetHash() : 0;
    2014             : }
    2015             : 
    2016           6 : ScFormulaVectorState ScColumn::GetFormulaVectorState( SCROW nRow ) const
    2017             : {
    2018           6 :     const ScFormulaCell* pCell = FetchFormulaCell(nRow);
    2019           6 :     return pCell ? pCell->GetVectorState() : FormulaVectorUnknown;
    2020             : }
    2021             : 
    2022           0 : formula::FormulaTokenRef ScColumn::ResolveStaticReference( SCROW nRow )
    2023             : {
    2024           0 :     std::pair<sc::CellStoreType::iterator,size_t> aPos = maCells.position(nRow);
    2025           0 :     sc::CellStoreType::iterator it = aPos.first;
    2026           0 :     if (it == maCells.end())
    2027             :         // Invalid row. Return a null token.
    2028           0 :         return formula::FormulaTokenRef();
    2029             : 
    2030           0 :     switch (it->type)
    2031             :     {
    2032             :         case sc::element_type_numeric:
    2033             :         {
    2034           0 :             double fVal = sc::numeric_block::at(*it->data, aPos.second);
    2035           0 :             return formula::FormulaTokenRef(new formula::FormulaDoubleToken(fVal));
    2036             :         }
    2037             :         case sc::element_type_formula:
    2038             :         {
    2039           0 :             ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
    2040           0 :             if (p->IsValue())
    2041           0 :                 return formula::FormulaTokenRef(new formula::FormulaDoubleToken(p->GetValue()));
    2042             : 
    2043           0 :             return formula::FormulaTokenRef(new formula::FormulaStringToken(p->GetString()));
    2044             :         }
    2045             :         case sc::element_type_string:
    2046             :         {
    2047           0 :             const svl::SharedString& rSS = sc::string_block::at(*it->data, aPos.second);
    2048           0 :             return formula::FormulaTokenRef(new formula::FormulaStringToken(rSS.getString()));
    2049             :         }
    2050             :         case sc::element_type_edittext:
    2051             :         {
    2052           0 :             const EditTextObject* pText = sc::edittext_block::at(*it->data, aPos.second);
    2053           0 :             OUString aStr = ScEditUtil::GetString(*pText, pDocument);
    2054           0 :             return formula::FormulaTokenRef(new formula::FormulaStringToken(aStr));
    2055             :         }
    2056             :         case sc::element_type_empty:
    2057             :         default:
    2058             :             // Return a value of 0.0 in all the other cases.
    2059           0 :             return formula::FormulaTokenRef(new formula::FormulaDoubleToken(0.0));
    2060             :     }
    2061             : }
    2062             : 
    2063             : namespace {
    2064             : 
    2065             : class ToMatrixHandler
    2066             : {
    2067             :     ScMatrix& mrMat;
    2068             :     SCCOL mnMatCol;
    2069             :     SCROW mnTopRow;
    2070             :     ScDocument* mpDoc;
    2071             :     svl::SharedStringPool& mrStrPool;
    2072             : public:
    2073           0 :     ToMatrixHandler(ScMatrix& rMat, SCCOL nMatCol, SCROW nTopRow, ScDocument* pDoc) :
    2074             :         mrMat(rMat), mnMatCol(nMatCol), mnTopRow(nTopRow),
    2075           0 :         mpDoc(pDoc), mrStrPool(pDoc->GetSharedStringPool()) {}
    2076             : 
    2077           0 :     void operator() (size_t nRow, double fVal)
    2078             :     {
    2079           0 :         mrMat.PutDouble(fVal, mnMatCol, nRow - mnTopRow);
    2080           0 :     }
    2081             : 
    2082           0 :     void operator() (size_t nRow, const ScFormulaCell* p)
    2083             :     {
    2084             :         // Formula cell may need to re-calculate.
    2085           0 :         ScFormulaCell& rCell = const_cast<ScFormulaCell&>(*p);
    2086           0 :         if (rCell.IsValue())
    2087           0 :             mrMat.PutDouble(rCell.GetValue(), mnMatCol, nRow - mnTopRow);
    2088             :         else
    2089           0 :             mrMat.PutString(rCell.GetString(), mnMatCol, nRow - mnTopRow);
    2090           0 :     }
    2091             : 
    2092           0 :     void operator() (size_t nRow, const svl::SharedString& rSS)
    2093             :     {
    2094           0 :         mrMat.PutString(rSS, mnMatCol, nRow - mnTopRow);
    2095           0 :     }
    2096             : 
    2097           0 :     void operator() (size_t nRow, const EditTextObject* pStr)
    2098             :     {
    2099           0 :         mrMat.PutString(mrStrPool.intern(ScEditUtil::GetString(*pStr, mpDoc)), mnMatCol, nRow - mnTopRow);
    2100           0 :     }
    2101             : };
    2102             : 
    2103             : }
    2104             : 
    2105           0 : bool ScColumn::ResolveStaticReference( ScMatrix& rMat, SCCOL nMatCol, SCROW nRow1, SCROW nRow2 )
    2106             : {
    2107           0 :     if (nRow1 > nRow2)
    2108           0 :         return false;
    2109             : 
    2110           0 :     ToMatrixHandler aFunc(rMat, nMatCol, nRow1, pDocument);
    2111           0 :     sc::ParseAllNonEmpty(maCells.begin(), maCells, nRow1, nRow2, aFunc);
    2112           0 :     return true;
    2113             : }
    2114             : 
    2115             : namespace {
    2116             : 
    2117          16 : struct CellBucket
    2118             : {
    2119             :     SCSIZE mnNumValStart;
    2120             :     SCSIZE mnStrValStart;
    2121             :     std::vector<double> maNumVals;
    2122             :     std::vector<svl::SharedString> maStrVals;
    2123             : 
    2124          16 :     CellBucket() : mnNumValStart(0), mnStrValStart(0) {}
    2125             : 
    2126          32 :     void flush(ScMatrix& rMat, SCSIZE nCol)
    2127             :     {
    2128          32 :         if (!maNumVals.empty())
    2129             :         {
    2130          16 :             const double* p = &maNumVals[0];
    2131          16 :             rMat.PutDouble(p, maNumVals.size(), nCol, mnNumValStart);
    2132          16 :             reset();
    2133             :         }
    2134          16 :         else if (!maStrVals.empty())
    2135             :         {
    2136           0 :             const svl::SharedString* p = &maStrVals[0];
    2137           0 :             rMat.PutString(p, maStrVals.size(), nCol, mnStrValStart);
    2138           0 :             reset();
    2139             :         }
    2140          32 :     }
    2141             : 
    2142          16 :     void reset()
    2143             :     {
    2144          16 :         mnNumValStart = mnStrValStart = 0;
    2145          16 :         maNumVals.clear();
    2146          16 :         maStrVals.clear();
    2147          16 :     }
    2148             : };
    2149             : 
    2150             : class FillMatrixHandler
    2151             : {
    2152             :     ScMatrix& mrMat;
    2153             :     size_t mnMatCol;
    2154             :     size_t mnTopRow;
    2155             : 
    2156             :     SCCOL mnCol;
    2157             :     SCTAB mnTab;
    2158             :     ScDocument* mpDoc;
    2159             :     svl::SharedStringPool& mrPool;
    2160             : 
    2161             : public:
    2162          52 :     FillMatrixHandler(ScMatrix& rMat, size_t nMatCol, size_t nTopRow, SCCOL nCol, SCTAB nTab, ScDocument* pDoc) :
    2163          52 :         mrMat(rMat), mnMatCol(nMatCol), mnTopRow(nTopRow), mnCol(nCol), mnTab(nTab), mpDoc(pDoc), mrPool(pDoc->GetSharedStringPool()) {}
    2164             : 
    2165          91 :     void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
    2166             :     {
    2167          91 :         size_t nMatRow = node.position + nOffset - mnTopRow;
    2168             : 
    2169          91 :         switch (node.type)
    2170             :         {
    2171             :             case sc::element_type_numeric:
    2172             :             {
    2173          52 :                 const double* p = &sc::numeric_block::at(*node.data, nOffset);
    2174          52 :                 mrMat.PutDouble(p, nDataSize, mnMatCol, nMatRow);
    2175             :             }
    2176          52 :             break;
    2177             :             case sc::element_type_string:
    2178             :             {
    2179           8 :                 const svl::SharedString* p = &sc::string_block::at(*node.data, nOffset);
    2180           8 :                 mrMat.PutString(p, nDataSize, mnMatCol, nMatRow);
    2181             :             }
    2182           8 :             break;
    2183             :             case sc::element_type_edittext:
    2184             :             {
    2185           0 :                 std::vector<svl::SharedString> aSSs;
    2186           0 :                 aSSs.reserve(nDataSize);
    2187           0 :                 sc::edittext_block::const_iterator it = sc::edittext_block::begin(*node.data);
    2188           0 :                 std::advance(it, nOffset);
    2189           0 :                 sc::edittext_block::const_iterator itEnd = it;
    2190           0 :                 std::advance(itEnd, nDataSize);
    2191           0 :                 for (; it != itEnd; ++it)
    2192             :                 {
    2193           0 :                     OUString aStr = ScEditUtil::GetString(**it, mpDoc);
    2194           0 :                     aSSs.push_back(mrPool.intern(aStr));
    2195           0 :                 }
    2196             : 
    2197           0 :                 const svl::SharedString* p = &aSSs[0];
    2198           0 :                 mrMat.PutString(p, nDataSize, mnMatCol, nMatRow);
    2199             :             }
    2200           0 :             break;
    2201             :             case sc::element_type_formula:
    2202             :             {
    2203          16 :                 CellBucket aBucket;
    2204          16 :                 sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
    2205          16 :                 std::advance(it, nOffset);
    2206          16 :                 sc::formula_block::const_iterator itEnd = it;
    2207          16 :                 std::advance(itEnd, nDataSize);
    2208             : 
    2209          16 :                 size_t nPrevRow = 0, nThisRow = node.position + nOffset;
    2210          41 :                 for (; it != itEnd; ++it, nPrevRow = nThisRow, ++nThisRow)
    2211             :                 {
    2212          25 :                     ScFormulaCell& rCell = const_cast<ScFormulaCell&>(**it);
    2213             : 
    2214          25 :                     if (rCell.IsEmpty())
    2215             :                     {
    2216           0 :                         aBucket.flush(mrMat, mnMatCol);
    2217          25 :                         continue;
    2218             :                     }
    2219             : 
    2220             :                     sal_uInt16 nErr;
    2221             :                     double fVal;
    2222          25 :                     if (rCell.GetErrorOrValue(nErr, fVal))
    2223             :                     {
    2224          25 :                         ScAddress aAdr(mnCol, nThisRow, mnTab);
    2225             : 
    2226          25 :                         if (nErr)
    2227           3 :                             fVal = CreateDoubleError(nErr);
    2228             : 
    2229          25 :                         if (!aBucket.maNumVals.empty() && nThisRow == nPrevRow + 1)
    2230             :                         {
    2231             :                             // Secondary numbers.
    2232           9 :                             aBucket.maNumVals.push_back(fVal);
    2233             :                         }
    2234             :                         else
    2235             :                         {
    2236             :                             // First number.
    2237          16 :                             aBucket.flush(mrMat, mnMatCol);
    2238          16 :                             aBucket.mnNumValStart = nThisRow - mnTopRow;
    2239          16 :                             aBucket.maNumVals.push_back(fVal);
    2240             :                         }
    2241          25 :                         continue;
    2242             :                     }
    2243             : 
    2244           0 :                     svl::SharedString aStr = rCell.GetString();
    2245           0 :                     if (!aBucket.maStrVals.empty() && nThisRow == nPrevRow + 1)
    2246             :                     {
    2247             :                         // Secondary strings.
    2248           0 :                         aBucket.maStrVals.push_back(aStr);
    2249             :                     }
    2250             :                     else
    2251             :                     {
    2252             :                         // First string.
    2253           0 :                         aBucket.flush(mrMat, mnMatCol);
    2254           0 :                         aBucket.mnStrValStart = nThisRow - mnTopRow;
    2255           0 :                         aBucket.maStrVals.push_back(aStr);
    2256             :                     }
    2257           0 :                 }
    2258             : 
    2259          16 :                 aBucket.flush(mrMat, mnMatCol);
    2260             :             }
    2261          16 :             break;
    2262             :             default:
    2263             :                 ;
    2264             :         }
    2265          91 :     }
    2266             : };
    2267             : 
    2268             : }
    2269             : 
    2270          52 : void ScColumn::FillMatrix( ScMatrix& rMat, size_t nMatCol, SCROW nRow1, SCROW nRow2 ) const
    2271             : {
    2272          52 :     FillMatrixHandler aFunc(rMat, nMatCol, nRow1, nCol, nTab, pDocument);
    2273          52 :     sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
    2274          52 : }
    2275             : 
    2276             : namespace {
    2277             : 
    2278             : template<typename _Blk>
    2279          12 : void getBlockIterators(
    2280             :     sc::CellStoreType::iterator it, size_t& rLenRemain,
    2281             :     typename _Blk::iterator& rData, typename _Blk::iterator& rDataEnd )
    2282             : {
    2283          12 :     rData = _Blk::begin(*it->data);
    2284          12 :     if (rLenRemain >= it->size)
    2285             :     {
    2286             :         // Block is shorter than the remaining requested length.
    2287          12 :         rDataEnd = _Blk::end(*it->data);
    2288          12 :         rLenRemain -= it->size;
    2289             :     }
    2290             :     else
    2291             :     {
    2292           0 :         rDataEnd = rData;
    2293           0 :         std::advance(rDataEnd, rLenRemain);
    2294           0 :         rLenRemain = 0;
    2295             :     }
    2296          12 : }
    2297             : 
    2298           9 : bool appendToBlock(
    2299             :     ScDocument* pDoc, sc::FormulaGroupContext& rCxt, sc::FormulaGroupContext::ColArray& rColArray,
    2300             :     size_t nPos, size_t nArrayLen, sc::CellStoreType::iterator it, const sc::CellStoreType::iterator& itEnd )
    2301             : {
    2302           9 :     svl::SharedStringPool& rPool = pDoc->GetSharedStringPool();
    2303           9 :     size_t nLenRemain = nArrayLen - nPos;
    2304             :     double fNan;
    2305           9 :     rtl::math::setNan(&fNan);
    2306             : 
    2307          23 :     for (; it != itEnd; ++it)
    2308             :     {
    2309          23 :         switch (it->type)
    2310             :         {
    2311             :             case sc::element_type_string:
    2312             :             {
    2313           3 :                 sc::string_block::iterator itData, itDataEnd;
    2314           3 :                 getBlockIterators<sc::string_block>(it, nLenRemain, itData, itDataEnd);
    2315           3 :                 rCxt.ensureStrArray(rColArray, nArrayLen);
    2316             : 
    2317           6 :                 for (; itData != itDataEnd; ++itData, ++nPos)
    2318           3 :                     (*rColArray.mpStrArray)[nPos] = itData->getDataIgnoreCase();
    2319             :             }
    2320           3 :             break;
    2321             :             case sc::element_type_edittext:
    2322             :             {
    2323           0 :                 sc::edittext_block::iterator itData, itDataEnd;
    2324           0 :                 getBlockIterators<sc::edittext_block>(it, nLenRemain, itData, itDataEnd);
    2325           0 :                 rCxt.ensureStrArray(rColArray, nArrayLen);
    2326             : 
    2327           0 :                 for (; itData != itDataEnd; ++itData, ++nPos)
    2328             :                 {
    2329           0 :                     OUString aStr = ScEditUtil::GetString(**itData, pDoc);
    2330           0 :                     (*rColArray.mpStrArray)[nPos] = rPool.intern(aStr).getDataIgnoreCase();
    2331           0 :                 }
    2332             :             }
    2333           0 :             break;
    2334             :             case sc::element_type_formula:
    2335             :             {
    2336           4 :                 sc::formula_block::iterator itData, itDataEnd;
    2337           4 :                 getBlockIterators<sc::formula_block>(it, nLenRemain, itData, itDataEnd);
    2338             : 
    2339          10 :                 for (; itData != itDataEnd; ++itData, ++nPos)
    2340             :                 {
    2341           6 :                     ScFormulaCell& rFC = **itData;
    2342           6 :                     sc::FormulaResultValue aRes = rFC.GetResult();
    2343           6 :                     if (aRes.meType == sc::FormulaResultValue::Invalid || aRes.mnError)
    2344             :                     {
    2345           0 :                         if (aRes.mnError == ScErrorCodes::errCircularReference)
    2346             :                         {
    2347             :                             // This cell needs to be recalculated on next visit.
    2348           0 :                             rFC.SetErrCode(0);
    2349           0 :                             rFC.SetDirtyVar();
    2350             :                         }
    2351           0 :                         return false;
    2352             :                     }
    2353             : 
    2354           6 :                     if (aRes.meType == sc::FormulaResultValue::String)
    2355             :                     {
    2356           1 :                         rCxt.ensureStrArray(rColArray, nArrayLen);
    2357           1 :                         (*rColArray.mpStrArray)[nPos] = aRes.maString.getDataIgnoreCase();
    2358             :                     }
    2359             :                     else
    2360             :                     {
    2361           5 :                         rCxt.ensureNumArray(rColArray, nArrayLen);
    2362           5 :                         (*rColArray.mpNumArray)[nPos] = aRes.mfValue;
    2363             :                     }
    2364           6 :                 }
    2365             :             }
    2366           4 :             break;
    2367             :             case sc::element_type_empty:
    2368             :             {
    2369          11 :                 if (nLenRemain > it->size)
    2370             :                 {
    2371           3 :                     nPos += it->size;
    2372           3 :                     nLenRemain -= it->size;
    2373             :                 }
    2374             :                 else
    2375             :                 {
    2376           8 :                     nPos = nArrayLen;
    2377           8 :                     nLenRemain = 0;
    2378             :                 }
    2379             :             }
    2380          11 :             break;
    2381             :             case sc::element_type_numeric:
    2382             :             {
    2383           5 :                 sc::numeric_block::iterator itData, itDataEnd;
    2384           5 :                 getBlockIterators<sc::numeric_block>(it, nLenRemain, itData, itDataEnd);
    2385           5 :                 rCxt.ensureNumArray(rColArray, nArrayLen);
    2386             : 
    2387          14 :                 for (; itData != itDataEnd; ++itData, ++nPos)
    2388           9 :                     (*rColArray.mpNumArray)[nPos] = *itData;
    2389             :             }
    2390           5 :             break;
    2391             :             default:
    2392           0 :                 return false;
    2393             :         }
    2394             : 
    2395          23 :         if (!nLenRemain)
    2396           9 :             return true;
    2397             :     }
    2398             : 
    2399           0 :     return false;
    2400             : }
    2401             : 
    2402           4 : void copyFirstStringBlock(
    2403             :     ScDocument& rDoc, sc::FormulaGroupContext::StrArrayType& rArray, size_t nLen, const sc::CellStoreType::iterator& itBlk )
    2404             : {
    2405           4 :     sc::FormulaGroupContext::StrArrayType::iterator itArray = rArray.begin();
    2406             : 
    2407           4 :     switch (itBlk->type)
    2408             :     {
    2409             :         case sc::element_type_string:
    2410             :         {
    2411           4 :             sc::string_block::iterator it = sc::string_block::begin(*itBlk->data);
    2412           4 :             sc::string_block::iterator itEnd = it;
    2413           4 :             std::advance(itEnd, nLen);
    2414          20 :             for (; it != itEnd; ++it, ++itArray)
    2415          16 :                 *itArray = it->getDataIgnoreCase();
    2416             :         }
    2417           4 :         break;
    2418             :         case sc::element_type_edittext:
    2419             :         {
    2420           0 :             sc::edittext_block::iterator it = sc::edittext_block::begin(*itBlk->data);
    2421           0 :             sc::edittext_block::iterator itEnd = it;
    2422           0 :             std::advance(itEnd, nLen);
    2423             : 
    2424           0 :             svl::SharedStringPool& rPool = rDoc.GetSharedStringPool();
    2425           0 :             for (; it != itEnd; ++it, ++itArray)
    2426             :             {
    2427           0 :                 EditTextObject* pText = *it;
    2428           0 :                 OUString aStr = ScEditUtil::GetString(*pText, &rDoc);
    2429           0 :                 *itArray = rPool.intern(aStr).getDataIgnoreCase();
    2430           0 :             }
    2431             :         }
    2432           0 :         break;
    2433             :         default:
    2434             :             ;
    2435             :     }
    2436           4 : }
    2437             : 
    2438             : sc::FormulaGroupContext::ColArray*
    2439           4 : copyFirstFormulaBlock(
    2440             :     sc::FormulaGroupContext& rCxt, sc::CellStoreType::iterator itBlk, size_t nArrayLen,
    2441             :     SCTAB nTab, SCCOL nCol )
    2442             : {
    2443             :     double fNan;
    2444           4 :     rtl::math::setNan(&fNan);
    2445             : 
    2446           4 :     size_t nLen = std::min(itBlk->size, nArrayLen);
    2447             : 
    2448           4 :     sc::formula_block::iterator it = sc::formula_block::begin(*itBlk->data);
    2449           4 :     sc::formula_block::iterator itEnd;
    2450             : 
    2451           4 :     sc::FormulaGroupContext::NumArrayType* pNumArray = NULL;
    2452           4 :     sc::FormulaGroupContext::StrArrayType* pStrArray = NULL;
    2453             : 
    2454           4 :     itEnd = it;
    2455           4 :     std::advance(itEnd, nLen);
    2456           4 :     size_t nPos = 0;
    2457          32 :     for (; it != itEnd; ++it, ++nPos)
    2458             :     {
    2459          28 :         ScFormulaCell& rFC = **it;
    2460          28 :         sc::FormulaResultValue aRes = rFC.GetResult();
    2461          28 :         if (aRes.meType == sc::FormulaResultValue::Invalid || aRes.mnError)
    2462             :         {
    2463           0 :             if (aRes.mnError == ScErrorCodes::errCircularReference)
    2464             :             {
    2465             :                 // This cell needs to be recalculated on next visit.
    2466           0 :                 rFC.SetErrCode(0);
    2467           0 :                 rFC.SetDirtyVar();
    2468             :             }
    2469           0 :             return NULL;
    2470             :         }
    2471             : 
    2472          28 :         if (aRes.meType == sc::FormulaResultValue::Value)
    2473             :         {
    2474          28 :             if (!pNumArray)
    2475             :             {
    2476             :                 rCxt.maNumArrays.push_back(
    2477           4 :                     new sc::FormulaGroupContext::NumArrayType(nArrayLen, fNan));
    2478           4 :                 pNumArray = &rCxt.maNumArrays.back();
    2479             :             }
    2480             : 
    2481          28 :             (*pNumArray)[nPos] = aRes.mfValue;
    2482             :         }
    2483             :         else
    2484             :         {
    2485           0 :             if (!pStrArray)
    2486             :             {
    2487             :                 rCxt.maStrArrays.push_back(
    2488           0 :                     new sc::FormulaGroupContext::StrArrayType(nArrayLen, NULL));
    2489           0 :                 pStrArray = &rCxt.maStrArrays.back();
    2490             :             }
    2491             : 
    2492           0 :             (*pStrArray)[nPos] = aRes.maString.getDataIgnoreCase();
    2493             :         }
    2494          28 :     }
    2495             : 
    2496           4 :     if (!pNumArray && !pStrArray)
    2497             :         // At least one of these arrays should be allocated.
    2498           0 :         return NULL;
    2499             : 
    2500           4 :     return rCxt.setCachedColArray(nTab, nCol, pNumArray, pStrArray);
    2501             : }
    2502             : 
    2503             : struct FiniteValueFinder : std::unary_function<double, bool>
    2504             : {
    2505             :     bool operator() (double f) const { return !rtl::math::isNan(f); }
    2506             : };
    2507             : 
    2508             : struct NonNullStringFinder : std::unary_function<const rtl_uString*, bool>
    2509             : {
    2510           9 :     bool operator() (const rtl_uString* p) const { return p != NULL; }
    2511             : };
    2512             : 
    2513           3 : bool hasNonEmpty( const sc::FormulaGroupContext::StrArrayType& rArray, SCROW nRow1, SCROW nRow2 )
    2514             : {
    2515             :     // The caller has to make sure the array is at least nRow2+1 long.
    2516           3 :     sc::FormulaGroupContext::StrArrayType::const_iterator it = rArray.begin();
    2517           3 :     std::advance(it, nRow1);
    2518           3 :     sc::FormulaGroupContext::StrArrayType::const_iterator itEnd = it;
    2519           3 :     std::advance(itEnd, nRow2-nRow1+1);
    2520           3 :     return std::find_if(it, itEnd, NonNullStringFinder()) != itEnd;
    2521             : }
    2522             : 
    2523             : }
    2524             : 
    2525          20 : formula::VectorRefArray ScColumn::FetchVectorRefArray( SCROW nRow1, SCROW nRow2 )
    2526             : {
    2527          20 :     if (nRow1 > nRow2)
    2528           0 :         return formula::VectorRefArray();
    2529             : 
    2530             :     // See if the requested range is already cached.
    2531          20 :     sc::FormulaGroupContext& rCxt = pDocument->GetFormulaGroupContext();
    2532          20 :     sc::FormulaGroupContext::ColArray* pColArray = rCxt.getCachedColArray(nTab, nCol, nRow2+1);
    2533          20 :     if (pColArray)
    2534             :     {
    2535           4 :         const double* pNum = NULL;
    2536           4 :         if (pColArray->mpNumArray)
    2537           4 :             pNum = &(*pColArray->mpNumArray)[nRow1];
    2538             : 
    2539           4 :         rtl_uString** pStr = NULL;
    2540           4 :         if (pColArray->mpStrArray && hasNonEmpty(*pColArray->mpStrArray, nRow1, nRow2))
    2541           0 :             pStr = &(*pColArray->mpStrArray)[nRow1];
    2542             : 
    2543           4 :         return formula::VectorRefArray(pNum, pStr);
    2544             :     }
    2545             : 
    2546             :     double fNan;
    2547          16 :     rtl::math::setNan(&fNan);
    2548             : 
    2549             :     // We need to fetch all cell values from row 0 to nRow2 for caching purposes.
    2550          16 :     sc::CellStoreType::iterator itBlk = maCells.begin();
    2551          16 :     switch (itBlk->type)
    2552             :     {
    2553             :         case sc::element_type_numeric:
    2554             :         {
    2555           3 :             if (static_cast<size_t>(nRow2) < itBlk->size)
    2556             :             {
    2557             :                 // Requested range falls within the first block. No need to cache.
    2558           1 :                 const double* p = &sc::numeric_block::at(*itBlk->data, nRow1);
    2559           1 :                 return formula::VectorRefArray(p);
    2560             :             }
    2561             : 
    2562             :             // Allocate a new array and copy the values to it.
    2563           2 :             sc::numeric_block::const_iterator it = sc::numeric_block::begin(*itBlk->data);
    2564           2 :             sc::numeric_block::const_iterator itEnd = sc::numeric_block::end(*itBlk->data);
    2565           2 :             rCxt.maNumArrays.push_back(new sc::FormulaGroupContext::NumArrayType(it, itEnd));
    2566           2 :             sc::FormulaGroupContext::NumArrayType& rArray = rCxt.maNumArrays.back();
    2567           2 :             rArray.resize(nRow2+1, fNan); // allocate to the requested length.
    2568             : 
    2569           2 :             pColArray = rCxt.setCachedColArray(nTab, nCol, &rArray, NULL);
    2570           2 :             if (!pColArray)
    2571             :                 // Failed to insert a new cached column array.
    2572           0 :                 return formula::VectorRefArray();
    2573             : 
    2574             :             // Fill the remaining array with values from the following blocks.
    2575           2 :             size_t nPos = itBlk->size;
    2576           2 :             ++itBlk;
    2577           2 :             if (!appendToBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
    2578           0 :                 return formula::VectorRefArray();
    2579             : 
    2580           2 :             if (pColArray->mpStrArray)
    2581           1 :                 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1], &(*pColArray->mpStrArray)[nRow1]);
    2582             :             else
    2583           1 :                 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1]);
    2584             :         }
    2585             :         break;
    2586             :         case sc::element_type_string:
    2587             :         case sc::element_type_edittext:
    2588             :         {
    2589           4 :             rCxt.maStrArrays.push_back(new sc::FormulaGroupContext::StrArrayType(nRow2+1, NULL));
    2590           4 :             sc::FormulaGroupContext::StrArrayType& rArray = rCxt.maStrArrays.back();
    2591           4 :             pColArray = rCxt.setCachedColArray(nTab, nCol, NULL, &rArray);
    2592           4 :             if (!pColArray)
    2593             :                 // Failed to insert a new cached column array.
    2594           0 :                 return formula::VectorRefArray();
    2595             : 
    2596           4 :             if (static_cast<size_t>(nRow2) < itBlk->size)
    2597             :             {
    2598             :                 // Requested range falls within the first block.
    2599           2 :                 copyFirstStringBlock(*pDocument, rArray, nRow2+1, itBlk);
    2600           2 :                 return formula::VectorRefArray(&rArray[nRow1]);
    2601             :             }
    2602             : 
    2603           2 :             copyFirstStringBlock(*pDocument, rArray, itBlk->size, itBlk);
    2604             : 
    2605             :             // Fill the remaining array with values from the following blocks.
    2606           2 :             size_t nPos = itBlk->size;
    2607           2 :             ++itBlk;
    2608           2 :             if (!appendToBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
    2609           0 :                 return formula::VectorRefArray();
    2610             : 
    2611           2 :             if (pColArray->mpNumArray)
    2612           1 :                 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1], &(*pColArray->mpStrArray)[nRow1]);
    2613             :             else
    2614           1 :                 return formula::VectorRefArray(&(*pColArray->mpStrArray)[nRow1]);
    2615             :         }
    2616             :         break;
    2617             :         case sc::element_type_formula:
    2618             :         {
    2619           4 :             if (static_cast<size_t>(nRow2) < itBlk->size)
    2620             :             {
    2621             :                 // Requested length is within a single block, and the data is
    2622             :                 // not cached.
    2623           2 :                 pColArray = copyFirstFormulaBlock(rCxt, itBlk, nRow2+1, nTab, nCol);
    2624           2 :                 if (!pColArray)
    2625             :                     // Failed to insert a new cached column array.
    2626           0 :                     return formula::VectorRefArray();
    2627             : 
    2628           2 :                 const double* pNum = NULL;
    2629           2 :                 rtl_uString** pStr = NULL;
    2630           2 :                 if (pColArray->mpNumArray)
    2631           2 :                     pNum = &(*pColArray->mpNumArray)[nRow1];
    2632           2 :                 if (pColArray->mpStrArray)
    2633           0 :                     pStr = &(*pColArray->mpStrArray)[nRow1];
    2634             : 
    2635           2 :                 return formula::VectorRefArray(pNum, pStr);
    2636             :             }
    2637             : 
    2638           2 :             pColArray = copyFirstFormulaBlock(rCxt, itBlk, nRow2+1, nTab, nCol);
    2639           2 :             if (!pColArray)
    2640             :                 // Failed to insert a new cached column array.
    2641           0 :                 return formula::VectorRefArray();
    2642             : 
    2643           2 :             size_t nPos = itBlk->size;
    2644           2 :             ++itBlk;
    2645           2 :             if (!appendToBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
    2646           0 :                 return formula::VectorRefArray();
    2647             : 
    2648           2 :             const double* pNum = NULL;
    2649           2 :             rtl_uString** pStr = NULL;
    2650           2 :             if (pColArray->mpNumArray)
    2651           2 :                 pNum = &(*pColArray->mpNumArray)[nRow1];
    2652           2 :             if (pColArray->mpStrArray)
    2653           1 :                 pStr = &(*pColArray->mpStrArray)[nRow1];
    2654             : 
    2655           2 :             return formula::VectorRefArray(pNum, pStr);
    2656             :         }
    2657             :         break;
    2658             :         case sc::element_type_empty:
    2659             :         {
    2660             :             // Fill the whole length with NaN's.
    2661           5 :             rCxt.maNumArrays.push_back(new sc::FormulaGroupContext::NumArrayType(nRow2+1, fNan));
    2662           5 :             sc::FormulaGroupContext::NumArrayType& rArray = rCxt.maNumArrays.back();
    2663           5 :             pColArray = rCxt.setCachedColArray(nTab, nCol, &rArray, NULL);
    2664           5 :             if (!pColArray)
    2665             :                 // Failed to insert a new cached column array.
    2666           0 :                 return formula::VectorRefArray();
    2667             : 
    2668           5 :             if (static_cast<size_t>(nRow2) < itBlk->size)
    2669           2 :                 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1]);
    2670             : 
    2671             :             // Fill the remaining array with values from the following blocks.
    2672           3 :             size_t nPos = itBlk->size;
    2673           3 :             ++itBlk;
    2674           3 :             if (!appendToBlock(pDocument, rCxt, *pColArray, nPos, nRow2+1, itBlk, maCells.end()))
    2675           0 :                 return formula::VectorRefArray();
    2676             : 
    2677           3 :             if (pColArray->mpStrArray && hasNonEmpty(*pColArray->mpStrArray, nRow1, nRow2))
    2678           0 :                 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1], &(*pColArray->mpStrArray)[nRow1]);
    2679             :             else
    2680           3 :                 return formula::VectorRefArray(&(*pColArray->mpNumArray)[nRow1]);
    2681             :         }
    2682             :         break;
    2683             :         default:
    2684             :             ;
    2685             :     }
    2686             : 
    2687           0 :     return formula::VectorRefArray();
    2688             : }
    2689             : 
    2690           0 : void ScColumn::SetFormulaResults( SCROW nRow, const double* pResults, size_t nLen )
    2691             : {
    2692           0 :     sc::CellStoreType::position_type aPos = maCells.position(nRow);
    2693           0 :     sc::CellStoreType::iterator it = aPos.first;
    2694           0 :     if (it->type != sc::element_type_formula)
    2695             :         // This is not a formula block.
    2696           0 :         return;
    2697             : 
    2698           0 :     size_t nBlockLen = it->size - aPos.second;
    2699           0 :     if (nBlockLen < nLen)
    2700             :         // Result array is longer than the length of formula cells. Not good.
    2701           0 :         return;
    2702             : 
    2703           0 :     sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
    2704           0 :     std::advance(itCell, aPos.second);
    2705             : 
    2706           0 :     const double* pResEnd = pResults + nLen;
    2707           0 :     for (; pResults != pResEnd; ++pResults, ++itCell)
    2708             :     {
    2709           0 :         ScFormulaCell& rCell = **itCell;
    2710           0 :         rCell.SetResultDouble(*pResults);
    2711           0 :         rCell.ResetDirty();
    2712           0 :         rCell.SetChanged(true);
    2713             :     }
    2714             : }
    2715             : 
    2716           0 : void ScColumn::SetFormulaResults( SCROW nRow, const formula::FormulaTokenRef* pResults, size_t nLen )
    2717             : {
    2718           0 :     sc::CellStoreType::position_type aPos = maCells.position(nRow);
    2719           0 :     sc::CellStoreType::iterator it = aPos.first;
    2720           0 :     if (it->type != sc::element_type_formula)
    2721             :         // This is not a formula block.
    2722           0 :         return;
    2723             : 
    2724           0 :     size_t nBlockLen = it->size - aPos.second;
    2725           0 :     if (nBlockLen < nLen)
    2726             :         // Result array is longer than the length of formula cells. Not good.
    2727           0 :         return;
    2728             : 
    2729           0 :     sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
    2730           0 :     std::advance(itCell, aPos.second);
    2731             : 
    2732           0 :     const formula::FormulaTokenRef* pResEnd = pResults + nLen;
    2733           0 :     for (; pResults != pResEnd; ++pResults, ++itCell)
    2734             :     {
    2735           0 :         ScFormulaCell& rCell = **itCell;
    2736           0 :         rCell.SetResultToken(pResults->get());
    2737           0 :         rCell.ResetDirty();
    2738           0 :         rCell.SetChanged(true);
    2739             :     }
    2740             : }
    2741             : 
    2742         836 : void ScColumn::SetNumberFormat( SCROW nRow, sal_uInt32 nNumberFormat )
    2743             : {
    2744         836 :     ApplyAttr(nRow, SfxUInt32Item(ATTR_VALUE_FORMAT, nNumberFormat));
    2745         836 : }
    2746             : 
    2747        1645 : const ScFormulaCell* ScColumn::FetchFormulaCell( SCROW nRow ) const
    2748             : {
    2749        1645 :     if (!ValidRow(nRow))
    2750           0 :         return NULL;
    2751             : 
    2752        1645 :     std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
    2753        1645 :     sc::CellStoreType::const_iterator it = aPos.first;
    2754        1645 :     if (it == maCells.end())
    2755           0 :         return NULL;
    2756             : 
    2757        1645 :     if (it->type != sc::element_type_formula)
    2758             :         // Not a formula cell.
    2759         225 :         return NULL;
    2760             : 
    2761        1420 :     return sc::formula_block::at(*it->data, aPos.second);
    2762             : }
    2763             : 
    2764          13 : void ScColumn::FindDataAreaPos(SCROW& rRow, bool bDown) const
    2765             : {
    2766             :     // If the cell is empty, find the next non-empty cell position. If the
    2767             :     // cell is not empty, find the last non-empty cell position in the current
    2768             :     // contiguous cell block.
    2769             : 
    2770          13 :     std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rRow);
    2771          13 :     sc::CellStoreType::const_iterator it = aPos.first;
    2772          13 :     if (it == maCells.end())
    2773             :         // Invalid row.
    2774           7 :         return;
    2775             : 
    2776          13 :     if (it->type == sc::element_type_empty)
    2777             :     {
    2778             :         // Current cell is empty. Find the next non-empty cell.
    2779           4 :         rRow = FindNextVisibleRowWithContent(it, rRow, bDown);
    2780           4 :         return;
    2781             :     }
    2782             : 
    2783             :     // Current cell is not empty.
    2784           9 :     SCROW nNextRow = FindNextVisibleRow(rRow, bDown);
    2785           9 :     aPos = maCells.position(it, nNextRow);
    2786           9 :     it = aPos.first;
    2787           9 :     if (it->type == sc::element_type_empty)
    2788             :     {
    2789             :         // Next visible cell is empty. Find the next non-empty cell.
    2790           3 :         rRow = FindNextVisibleRowWithContent(it, nNextRow, bDown);
    2791           3 :         return;
    2792             :     }
    2793             : 
    2794             :     // Next visible cell is non-empty. Find the edge that's still visible.
    2795           6 :     SCROW nLastRow = nNextRow;
    2796          18 :     do
    2797             :     {
    2798          19 :         nNextRow = FindNextVisibleRow(nLastRow, bDown);
    2799          19 :         if (nNextRow == nLastRow)
    2800           1 :             break;
    2801             : 
    2802          18 :         aPos = maCells.position(it, nNextRow);
    2803          18 :         it = aPos.first;
    2804          18 :         if (it->type != sc::element_type_empty)
    2805          13 :             nLastRow = nNextRow;
    2806             :     }
    2807          18 :     while (it->type != sc::element_type_empty);
    2808             : 
    2809           6 :     rRow = nLastRow;
    2810             : }
    2811             : 
    2812        3832 : bool ScColumn::HasDataAt(SCROW nRow) const
    2813             : {
    2814        3832 :     return maCells.get_type(nRow) != sc::element_type_empty;
    2815             : }
    2816             : 
    2817       32745 : bool ScColumn::IsAllAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const
    2818             : {
    2819       32745 :     if (pAttrArray && rCol.pAttrArray)
    2820       32745 :         return pAttrArray->IsAllEqual( *rCol.pAttrArray, nStartRow, nEndRow );
    2821             :     else
    2822           0 :         return !pAttrArray && !rCol.pAttrArray;
    2823             : }
    2824             : 
    2825       11932 : bool ScColumn::IsVisibleAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const
    2826             : {
    2827       11932 :     if (pAttrArray && rCol.pAttrArray)
    2828       11932 :         return pAttrArray->IsVisibleEqual( *rCol.pAttrArray, nStartRow, nEndRow );
    2829             :     else
    2830           0 :         return !pAttrArray && !rCol.pAttrArray;
    2831             : }
    2832             : 
    2833     1137664 : bool ScColumn::GetFirstVisibleAttr( SCROW& rFirstRow ) const
    2834             : {
    2835     1137664 :     if (pAttrArray)
    2836     1137664 :         return pAttrArray->GetFirstVisibleAttr( rFirstRow );
    2837             :     else
    2838           0 :         return false;
    2839             : }
    2840             : 
    2841     1823921 : bool ScColumn::GetLastVisibleAttr( SCROW& rLastRow, bool bFullFormattedArea ) const
    2842             : {
    2843     1823921 :     if (pAttrArray)
    2844             :     {
    2845             :         // row of last cell is needed
    2846     1823921 :         SCROW nLastData = GetLastDataPos();    // always including notes, 0 if none
    2847             : 
    2848     1823921 :         return pAttrArray->GetLastVisibleAttr( rLastRow, nLastData, bFullFormattedArea );
    2849             :     }
    2850             :     else
    2851           0 :         return false;
    2852             : }
    2853             : 
    2854           0 : bool ScColumn::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
    2855             : {
    2856           0 :     if (pAttrArray)
    2857           0 :         return pAttrArray->HasVisibleAttrIn( nStartRow, nEndRow );
    2858             :     else
    2859           0 :         return false;
    2860             : }
    2861             : 
    2862             : namespace {
    2863             : 
    2864             : class FindUsedRowsHandler
    2865             : {
    2866             :     typedef mdds::flat_segment_tree<SCROW,bool> UsedRowsType;
    2867             :     UsedRowsType& mrUsed;
    2868             :     UsedRowsType::const_iterator miUsed;
    2869             : public:
    2870          10 :     FindUsedRowsHandler(UsedRowsType& rUsed) : mrUsed(rUsed), miUsed(rUsed.begin()) {}
    2871             : 
    2872          39 :     void operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
    2873             :     {
    2874          39 :         if (node.type == sc::element_type_empty)
    2875          51 :             return;
    2876             : 
    2877          27 :         SCROW nRow1 = node.position + nOffset;
    2878          27 :         SCROW nRow2 = nRow1 + nDataSize - 1;
    2879          27 :         miUsed = mrUsed.insert(miUsed, nRow1, nRow2+1, true).first;
    2880             :     }
    2881             : };
    2882             : 
    2883             : }
    2884             : 
    2885          10 : void ScColumn::FindUsed( SCROW nStartRow, SCROW nEndRow, mdds::flat_segment_tree<SCROW,bool>& rUsed ) const
    2886             : {
    2887          10 :     FindUsedRowsHandler aFunc(rUsed);
    2888          10 :     sc::ParseBlock(maCells.begin(), maCells, aFunc, nStartRow, nEndRow);
    2889          10 : }
    2890             : 
    2891             : namespace {
    2892             : 
    2893       12150 : void startListening(
    2894             :     sc::BroadcasterStoreType& rStore, sc::BroadcasterStoreType::iterator& itBlockPos, size_t nElemPos,
    2895             :     SCROW nRow, SvtListener& rLst)
    2896             : {
    2897       12150 :     switch (itBlockPos->type)
    2898             :     {
    2899             :         case sc::element_type_broadcaster:
    2900             :         {
    2901             :             // Broadcaster already exists here.
    2902        7602 :             SvtBroadcaster* pBC = sc::broadcaster_block::at(*itBlockPos->data, nElemPos);
    2903        7602 :             rLst.StartListening(*pBC);
    2904             :         }
    2905        7602 :         break;
    2906             :         case mdds::mtv::element_type_empty:
    2907             :         {
    2908             :             // No broadcaster exists at this position yet.
    2909        4548 :             SvtBroadcaster* pBC = new SvtBroadcaster;
    2910        4548 :             rLst.StartListening(*pBC);
    2911        4548 :             itBlockPos = rStore.set(itBlockPos, nRow, pBC); // Store the block position for next iteration.
    2912             :         }
    2913        4548 :         break;
    2914             :         default:
    2915             : #if DEBUG_COLUMN_STORAGE
    2916             :             cout << "ScColumn::StartListening: wrong block type encountered in the broadcaster storage." << endl;
    2917             :             cout.flush();
    2918             :             abort();
    2919             : #else
    2920             :             ;
    2921             : #endif
    2922             :     }
    2923       12150 : }
    2924             : 
    2925             : }
    2926             : 
    2927        6154 : void ScColumn::StartListening( SvtListener& rLst, SCROW nRow )
    2928             : {
    2929        6154 :     std::pair<sc::BroadcasterStoreType::iterator,size_t> aPos = maBroadcasters.position(nRow);
    2930        6154 :     startListening(maBroadcasters, aPos.first, aPos.second, nRow, rLst);
    2931        6154 : }
    2932             : 
    2933         406 : void ScColumn::EndListening( SvtListener& rLst, SCROW nRow )
    2934             : {
    2935         406 :     SvtBroadcaster* pBC = GetBroadcaster(nRow);
    2936         406 :     if (!pBC)
    2937         472 :         return;
    2938             : 
    2939         340 :     rLst.EndListening(*pBC);
    2940         340 :     if (!pBC->HasListeners())
    2941             :         // There is no more listeners for this cell. Remove the broadcaster.
    2942         221 :         maBroadcasters.set_empty(nRow, nRow);
    2943             : }
    2944             : 
    2945        5996 : void ScColumn::StartListening( sc::StartListeningContext& rCxt, SCROW nRow, SvtListener& rLst )
    2946             : {
    2947        5996 :     if (!ValidRow(nRow))
    2948           0 :         return;
    2949             : 
    2950        5996 :     sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
    2951        5996 :     if (!p)
    2952           0 :         return;
    2953             : 
    2954        5996 :     sc::BroadcasterStoreType::iterator& it = p->miBroadcasterPos;
    2955        5996 :     std::pair<sc::BroadcasterStoreType::iterator,size_t> aPos = maBroadcasters.position(it, nRow);
    2956        5996 :     it = aPos.first; // store the block position for next iteration.
    2957        5996 :     startListening(maBroadcasters, it, aPos.second, nRow, rLst);
    2958             : }
    2959             : 
    2960         218 : void ScColumn::EndListening( sc::EndListeningContext& rCxt, SCROW nRow, SvtListener& rListener )
    2961             : {
    2962         218 :     sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
    2963         218 :     if (!p)
    2964           6 :         return;
    2965             : 
    2966         218 :     sc::BroadcasterStoreType::iterator& it = p->miBroadcasterPos;
    2967         218 :     std::pair<sc::BroadcasterStoreType::iterator,size_t> aPos = maBroadcasters.position(it, nRow);
    2968         218 :     it = aPos.first; // store the block position for next iteration.
    2969         218 :     if (it->type != sc::element_type_broadcaster)
    2970           6 :         return;
    2971             : 
    2972         212 :     SvtBroadcaster* pBC = sc::broadcaster_block::at(*it->data, aPos.second);
    2973             :     OSL_ASSERT(pBC);
    2974             : 
    2975         212 :     rListener.EndListening(*pBC);
    2976         212 :     if (!pBC->HasListeners())
    2977             :         // There is no more listeners for this cell. Add it to the purge list for later purging.
    2978         194 :         rCxt.addEmptyBroadcasterPosition(nTab, nCol, nRow);
    2979             : }
    2980             : 
    2981             : namespace {
    2982             : 
    2983             : class CompileDBFormulaHandler
    2984             : {
    2985             :     sc::CompileFormulaContext& mrCxt;
    2986             : 
    2987             : public:
    2988        9216 :     CompileDBFormulaHandler( sc::CompileFormulaContext& rCxt ) :
    2989        9216 :         mrCxt(rCxt) {}
    2990             : 
    2991           2 :     void operator() (size_t, ScFormulaCell* p)
    2992             :     {
    2993           2 :         p->CompileDBFormula(mrCxt);
    2994           2 :     }
    2995             : };
    2996             : 
    2997             : class CompileDBFormula2Handler
    2998             : {
    2999             :     sc::CompileFormulaContext& mrCxt;
    3000             :     bool mbCreateFormulaString;
    3001             : 
    3002             : public:
    3003       16384 :     CompileDBFormula2Handler( sc::CompileFormulaContext& rCxt, bool bCreateFormulaString ) :
    3004       16384 :         mrCxt(rCxt), mbCreateFormulaString(bCreateFormulaString) {}
    3005             : 
    3006          14 :     void operator() (size_t, ScFormulaCell* p)
    3007             :     {
    3008          14 :         p->CompileDBFormula(mrCxt, mbCreateFormulaString);
    3009          14 :     }
    3010             : };
    3011             : 
    3012             : struct CompileColRowNameFormulaHandler
    3013             : {
    3014             :     sc::CompileFormulaContext& mrCxt;
    3015             : public:
    3016        7168 :     CompileColRowNameFormulaHandler( sc::CompileFormulaContext& rCxt ) : mrCxt(rCxt) {}
    3017             : 
    3018           0 :     void operator() (size_t, ScFormulaCell* p)
    3019             :     {
    3020           0 :         p->CompileColRowNameFormula(mrCxt);
    3021           0 :     }
    3022             : };
    3023             : 
    3024             : }
    3025             : 
    3026        9216 : void ScColumn::CompileDBFormula( sc::CompileFormulaContext& rCxt )
    3027             : {
    3028        9216 :     CompileDBFormulaHandler aFunc(rCxt);
    3029        9216 :     sc::ProcessFormula(maCells, aFunc);
    3030        9216 :     RegroupFormulaCells();
    3031        9216 : }
    3032             : 
    3033       16384 : void ScColumn::CompileDBFormula( sc::CompileFormulaContext& rCxt, bool bCreateFormulaString )
    3034             : {
    3035       16384 :     CompileDBFormula2Handler aFunc(rCxt, bCreateFormulaString);
    3036       16384 :     sc::ProcessFormula(maCells, aFunc);
    3037       16384 :     RegroupFormulaCells();
    3038       16384 : }
    3039             : 
    3040        7168 : void ScColumn::CompileColRowNameFormula( sc::CompileFormulaContext& rCxt )
    3041             : {
    3042        7168 :     CompileColRowNameFormulaHandler aFunc(rCxt);
    3043        7168 :     sc::ProcessFormula(maCells, aFunc);
    3044        7168 :     RegroupFormulaCells();
    3045        7168 : }
    3046             : 
    3047             : namespace {
    3048             : 
    3049             : class UpdateSubTotalHandler
    3050             : {
    3051             :     ScFunctionData& mrData;
    3052             : 
    3053         125 :     void update(double fVal, bool bVal)
    3054             :     {
    3055         125 :         if (mrData.bError)
    3056           0 :             return;
    3057             : 
    3058         125 :         switch (mrData.eFunc)
    3059             :         {
    3060             :             case SUBTOTAL_FUNC_SUM:
    3061             :             case SUBTOTAL_FUNC_AVE:
    3062             :             {
    3063          38 :                 if (!bVal)
    3064           4 :                     return;
    3065             : 
    3066          34 :                 ++mrData.nCount;
    3067          34 :                 if (!SubTotal::SafePlus(mrData.nVal, fVal))
    3068           0 :                     mrData.bError = true;
    3069             :             }
    3070          34 :             break;
    3071             :             case SUBTOTAL_FUNC_CNT:             // only the value
    3072             :             {
    3073          13 :                 if (!bVal)
    3074           2 :                     return;
    3075             : 
    3076          11 :                 ++mrData.nCount;
    3077             :             }
    3078          11 :             break;
    3079             :             case SUBTOTAL_FUNC_CNT2:            // everything
    3080          48 :                 ++mrData.nCount;
    3081          48 :             break;
    3082             :             case SUBTOTAL_FUNC_MAX:
    3083             :             {
    3084          13 :                 if (!bVal)
    3085           2 :                     return;
    3086             : 
    3087          11 :                 if (++mrData.nCount == 1 || fVal > mrData.nVal)
    3088          11 :                     mrData.nVal = fVal;
    3089             :             }
    3090          11 :             break;
    3091             :             case SUBTOTAL_FUNC_MIN:
    3092             :             {
    3093          13 :                 if (!bVal)
    3094           2 :                     return;
    3095             : 
    3096          11 :                 if (++mrData.nCount == 1 || fVal < mrData.nVal)
    3097           3 :                     mrData.nVal = fVal;
    3098             :             }
    3099          11 :             break;
    3100             :             default:
    3101             :             {
    3102             :                 // added to avoid warnings
    3103             :             }
    3104             :         }
    3105             :     }
    3106             : 
    3107             : public:
    3108      189440 :     UpdateSubTotalHandler(ScFunctionData& rData) : mrData(rData) {}
    3109             : 
    3110          71 :     void operator() (size_t /*nRow*/, double fVal)
    3111             :     {
    3112          71 :         update(fVal, true);
    3113          71 :     }
    3114             : 
    3115          27 :     void operator() (size_t /*nRow*/, const svl::SharedString&)
    3116             :     {
    3117          27 :         update(0.0, false);
    3118          27 :     }
    3119             : 
    3120           2 :     void operator() (size_t /*nRow*/, const EditTextObject*)
    3121             :     {
    3122           2 :         update(0.0, false);
    3123           2 :     }
    3124             : 
    3125          25 :     void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
    3126             :     {
    3127          25 :         double fVal = 0.0;
    3128          25 :         bool bVal = false;
    3129          25 :         if (mrData.eFunc != SUBTOTAL_FUNC_CNT2) // it doesn't interest us
    3130             :         {
    3131             : 
    3132          20 :             if (pCell->GetErrCode())
    3133             :             {
    3134           0 :                 if (mrData.eFunc != SUBTOTAL_FUNC_CNT) // simply remove from count
    3135           0 :                     mrData.bError = true;
    3136             :             }
    3137          20 :             else if (pCell->IsValue())
    3138             :             {
    3139          10 :                 fVal = pCell->GetValue();
    3140          10 :                 bVal = true;
    3141             :             }
    3142             :             // otherwise text
    3143             :         }
    3144             : 
    3145          25 :         update(fVal, bVal);
    3146          25 :     }
    3147             : };
    3148             : 
    3149             : }
    3150             : 
    3151             : //  multiple selections:
    3152      221184 : void ScColumn::UpdateSelectionFunction(
    3153             :     const ScMarkData& rMark, ScFunctionData& rData, ScFlatBoolRowSegments& rHiddenRows )
    3154             : {
    3155      221184 :     sc::SingleColumnSpanSet aSpanSet;
    3156      221184 :     aSpanSet.scan(rMark, nTab, nCol); // mark all selected rows.
    3157             : 
    3158             :     // Exclude all hidden rows.
    3159             :     ScFlatBoolRowSegments::RangeData aRange;
    3160      221184 :     SCROW nRow = 0;
    3161      735232 :     while (nRow <= MAXROW)
    3162             :     {
    3163      292864 :         if (!rHiddenRows.getRangeData(nRow, aRange))
    3164           0 :             break;
    3165             : 
    3166      292864 :         if (aRange.mbValue)
    3167             :             // Hidden range detected.
    3168       36864 :             aSpanSet.set(nRow, aRange.mnRow2, false);
    3169             : 
    3170      292864 :         nRow = aRange.mnRow2 + 1;
    3171             :     }
    3172             : 
    3173      442368 :     sc::SingleColumnSpanSet::SpansType aSpans;
    3174      221184 :     aSpanSet.getSpans(aSpans);
    3175             : 
    3176      221184 :     sc::SingleColumnSpanSet::SpansType::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
    3177             : 
    3178      221184 :     switch (rData.eFunc)
    3179             :     {
    3180             :         case SUBTOTAL_FUNC_SELECTION_COUNT:
    3181             :         {
    3182             :             // Simply count selected rows regardless of cell contents.
    3183       31781 :             for (; it != itEnd; ++it)
    3184          37 :                 rData.nCount += it->mnRow2 - it->mnRow1 + 1;
    3185             :         }
    3186       31744 :         break;
    3187             :         case SUBTOTAL_FUNC_CNT2:
    3188             :         {
    3189             :             // We need to parse all non-empty cells.
    3190        6144 :             sc::CellStoreType::const_iterator itCellPos = maCells.begin();
    3191        6144 :             UpdateSubTotalHandler aFunc(rData);
    3192        6166 :             for (; it != itEnd; ++it)
    3193             :             {
    3194          66 :                 itCellPos = sc::ParseAllNonEmpty(
    3195          66 :                     itCellPos, maCells, it->mnRow1, it->mnRow2, aFunc);
    3196             :             }
    3197             :         }
    3198        6144 :         break;
    3199             :         default:
    3200             :         {
    3201             :             // We need to parse only numeric values.
    3202      183296 :             sc::CellStoreType::const_iterator itCellPos = maCells.begin();
    3203      183296 :             UpdateSubTotalHandler aFunc(rData);
    3204      183519 :             for (; it != itEnd; ++it)
    3205             :             {
    3206         669 :                 itCellPos = sc::ParseFormulaNumeric(
    3207         669 :                     itCellPos, maCells, it->mnRow1, it->mnRow2, aFunc);
    3208             :             }
    3209             :         }
    3210      221184 :     }
    3211      221184 : }
    3212             : 
    3213             : namespace {
    3214             : 
    3215             : class WeightedCounter
    3216             : {
    3217             :     size_t mnCount;
    3218             : public:
    3219        5843 :     WeightedCounter() : mnCount(0) {}
    3220             : 
    3221       25287 :     void operator() (const sc::CellStoreType::value_type& node)
    3222             :     {
    3223       25287 :         switch (node.type)
    3224             :         {
    3225             :             case sc::element_type_numeric:
    3226             :             case sc::element_type_string:
    3227       11575 :                 mnCount += node.size;
    3228       11575 :             break;
    3229             :             case sc::element_type_formula:
    3230             :             {
    3231             :                 // Each formula cell is worth its code length plus 5.
    3232         761 :                 sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
    3233         761 :                 sc::formula_block::const_iterator itEnd = sc::formula_block::end(*node.data);
    3234        1702 :                 for (; it != itEnd; ++it)
    3235             :                 {
    3236         941 :                     const ScFormulaCell* p = *it;
    3237         941 :                     mnCount += 5 + p->GetCode()->GetCodeLen();
    3238             :                 }
    3239             :             }
    3240         761 :             break;
    3241             :             case sc::element_type_edittext:
    3242             :                 // each edit-text cell is worth 50.
    3243         100 :                 mnCount += node.size * 50;
    3244         100 :             break;
    3245             :             default:
    3246             :                 ;
    3247             :         }
    3248       25287 :     }
    3249             : 
    3250        5843 :     size_t getCount() const { return mnCount; }
    3251             : };
    3252             : 
    3253             : }
    3254             : 
    3255        5843 : sal_uInt32 ScColumn::GetWeightedCount() const
    3256             : {
    3257        5843 :     WeightedCounter aFunc;
    3258        5843 :     std::for_each(maCells.begin(), maCells.end(), aFunc);
    3259        5843 :     return aFunc.getCount();
    3260             : }
    3261             : 
    3262             : namespace {
    3263             : 
    3264             : class CodeCounter
    3265             : {
    3266             :     size_t mnCount;
    3267             : public:
    3268           0 :     CodeCounter() : mnCount(0) {}
    3269             : 
    3270           0 :     void operator() (size_t, const ScFormulaCell* p)
    3271             :     {
    3272           0 :         mnCount += p->GetCode()->GetCodeLen();
    3273           0 :     }
    3274             : 
    3275           0 :     size_t getCount() const { return mnCount; }
    3276             : };
    3277             : 
    3278             : }
    3279             : 
    3280           0 : sal_uInt32 ScColumn::GetCodeCount() const
    3281             : {
    3282           0 :     CodeCounter aFunc;
    3283           0 :     sc::ParseFormula(maCells, aFunc);
    3284           0 :     return aFunc.getCount();
    3285             : }
    3286             : 
    3287           0 : SCSIZE ScColumn::GetPatternCount() const
    3288             : {
    3289           0 :     return pAttrArray ? pAttrArray->Count() : 0;
    3290             : }
    3291             : 
    3292           0 : SCSIZE ScColumn::GetPatternCount( SCROW nRow1, SCROW nRow2 ) const
    3293             : {
    3294           0 :     return pAttrArray ? pAttrArray->Count( nRow1, nRow2 ) : 0;
    3295             : }
    3296             : 
    3297           0 : bool ScColumn::ReservePatternCount( SCSIZE nReserve )
    3298             : {
    3299           0 :     return pAttrArray ? pAttrArray->Reserve( nReserve ) : false;
    3300         102 : }
    3301             : 
    3302             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10