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

Generated by: LCOV version 1.10