LCOV - code coverage report
Current view: top level - sc/source/core/data - column.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 1180 1625 72.6 %
Date: 2014-11-03 Functions: 185 226 81.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 "attarray.hxx"
      26             : #include "patattr.hxx"
      27             : #include "compiler.hxx"
      28             : #include "brdcst.hxx"
      29             : #include "markdata.hxx"
      30             : #include "detfunc.hxx"
      31             : #include "postit.hxx"
      32             : #include "globalnames.hxx"
      33             : #include "cellvalue.hxx"
      34             : #include "tokenarray.hxx"
      35             : #include "cellform.hxx"
      36             : #include "clipcontext.hxx"
      37             : #include "types.hxx"
      38             : #include "editutil.hxx"
      39             : #include "mtvcellfunc.hxx"
      40             : #include "columnspanset.hxx"
      41             : #include "scopetools.hxx"
      42             : #include "sharedformula.hxx"
      43             : #include "refupdatecontext.hxx"
      44             : #include <listenercontext.hxx>
      45             : #include <refhint.hxx>
      46             : #include <stlalgorithm.hxx>
      47             : #include <formulagroup.hxx>
      48             : 
      49             : #include <svl/poolcach.hxx>
      50             : #include <svl/zforlist.hxx>
      51             : #include <svl/sharedstringpool.hxx>
      52             : #include <editeng/scripttypeitem.hxx>
      53             : #include <editeng/fieldupdater.hxx>
      54             : 
      55             : #include <cstring>
      56             : #include <map>
      57             : #include <cstdio>
      58             : #include <boost/checked_delete.hpp>
      59             : #include <boost/scoped_ptr.hpp>
      60             : 
      61             : using ::editeng::SvxBorderLine;
      62             : using namespace formula;
      63             : 
      64             : namespace {
      65             : 
      66       65731 : inline bool IsAmbiguousScriptNonZero( sal_uInt8 nScript )
      67             : {
      68             :     //! move to a header file
      69         346 :     return ( nScript != SCRIPTTYPE_LATIN &&
      70         346 :              nScript != SCRIPTTYPE_ASIAN &&
      71       66077 :              nScript != SCRIPTTYPE_COMPLEX &&
      72       65731 :              nScript != 0 );
      73             : }
      74             : 
      75             : }
      76             : 
      77      270992 : ScNeededSizeOptions::ScNeededSizeOptions() :
      78      270992 :     pPattern(NULL), bFormula(false), bSkipMerged(true), bGetFont(true), bTotalSize(false)
      79             : {
      80      270992 : }
      81             : 
      82     4425728 : ScColumn::ScColumn() :
      83             :     maCellTextAttrs(MAXROWCOUNT),
      84             :     maCellNotes(MAXROWCOUNT),
      85             :     maBroadcasters(MAXROWCOUNT),
      86             :     maCells(MAXROWCOUNT),
      87             :     nCol( 0 ),
      88             :     nTab( 0 ),
      89             :     pAttrArray( NULL ),
      90             :     pDocument( NULL ),
      91     4425728 :     mbDirtyGroups(true)
      92             : {
      93     4425728 : }
      94             : 
      95     8843264 : ScColumn::~ScColumn()
      96             : {
      97     4421632 :     FreeAll();
      98     4421632 :     delete pAttrArray;
      99     4421632 : }
     100             : 
     101     4425728 : void ScColumn::Init(SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc)
     102             : {
     103     4425728 :     nCol = nNewCol;
     104     4425728 :     nTab = nNewTab;
     105     4425728 :     pDocument = pDoc;
     106     4425728 :     pAttrArray = new ScAttrArray( nCol, nTab, pDocument );
     107     4425728 : }
     108             : 
     109           0 : SCsROW ScColumn::GetNextUnprotected( SCROW nRow, bool bUp ) const
     110             : {
     111           0 :     return pAttrArray->GetNextUnprotected(nRow, bUp);
     112             : }
     113             : 
     114      212466 : sal_uInt16 ScColumn::GetBlockMatrixEdges( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
     115             : {
     116             :     using namespace sc;
     117             : 
     118      212466 :     if (!ValidRow(nRow1) || !ValidRow(nRow2) || nRow1 > nRow2)
     119           0 :         return 0;
     120             : 
     121      212466 :     ScAddress aOrigin(ScAddress::INITIALIZE_INVALID);
     122             : 
     123      212466 :     if (nRow1 == nRow2)
     124             :     {
     125      210540 :         std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow1);
     126      210540 :         if (aPos.first->type != sc::element_type_formula)
     127      210310 :             return 0;
     128             : 
     129         230 :         const ScFormulaCell* pCell = sc::formula_block::at(*aPos.first->data, aPos.second);
     130         230 :         if (!pCell->GetMatrixFlag())
     131         220 :             return 0;
     132             : 
     133          10 :         return pCell->GetMatrixEdge(aOrigin);
     134             :     }
     135             : 
     136        1926 :     bool bOpen = false;
     137        1926 :     sal_uInt16 nEdges = 0;
     138             : 
     139        1926 :     std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow1);
     140        1926 :     sc::CellStoreType::const_iterator it = aPos.first;
     141        1926 :     size_t nOffset = aPos.second;
     142        1926 :     SCROW nRow = nRow1;
     143        5526 :     for (;it != maCells.end() && nRow <= nRow2; ++it, nOffset = 0)
     144             :     {
     145        3600 :         if (it->type != sc::element_type_formula)
     146             :         {
     147             :             // Skip this block.
     148        3490 :             nRow += it->size - nOffset;
     149        3490 :             continue;
     150             :         }
     151             : 
     152         110 :         size_t nRowsToRead = nRow2 - nRow + 1;
     153         110 :         size_t nEnd = std::min(it->size, nOffset+nRowsToRead); // last row + 1
     154         110 :         sc::formula_block::const_iterator itCell = sc::formula_block::begin(*it->data);
     155         110 :         std::advance(itCell, nOffset);
     156         390 :         for (size_t i = nOffset; i < nEnd; ++itCell, ++i)
     157             :         {
     158             :             // Loop inside the formula block.
     159         280 :             const ScFormulaCell* pCell = *itCell;
     160         280 :             if (!pCell->GetMatrixFlag())
     161         276 :                 continue;
     162             : 
     163           4 :             nEdges = pCell->GetMatrixEdge(aOrigin);
     164           4 :             if (!nEdges)
     165           0 :                 continue;
     166             : 
     167           4 :             if (nEdges & MatrixEdgeTop)
     168           2 :                 bOpen = true;       // top edge opens, keep on looking
     169           2 :             else if (!bOpen)
     170           0 :                 return nEdges | MatrixEdgeOpen; // there's something that wasn't opened
     171           2 :             else if (nEdges & MatrixEdgeInside)
     172           0 :                 return nEdges;      // inside
     173             :             // (nMask & 16 and  (4 and not 16)) or
     174             :             // (nMask & 4  and (16 and not 4))
     175           8 :             if (((nMask & MatrixEdgeRight) && (nEdges & MatrixEdgeLeft)  && !(nEdges & MatrixEdgeRight)) ||
     176           8 :                 ((nMask & MatrixEdgeLeft)  && (nEdges & MatrixEdgeRight) && !(nEdges & MatrixEdgeLeft)))
     177           0 :                 return nEdges;      // only left/right edge
     178             : 
     179           4 :             if (nEdges & MatrixEdgeBottom)
     180           2 :                 bOpen = false;      // bottom edge closes
     181             :         }
     182             : 
     183         110 :         nRow += nEnd;
     184             :     }
     185        1926 :     if (bOpen)
     186           0 :         nEdges |= MatrixEdgeOpen; // not closed, matrix continues
     187             : 
     188        1926 :     return nEdges;
     189             : }
     190             : 
     191         748 : bool ScColumn::HasSelectionMatrixFragment(const ScMarkData& rMark) const
     192             : {
     193             :     using namespace sc;
     194             : 
     195         748 :     if (!rMark.IsMultiMarked())
     196           0 :         return false;
     197             : 
     198         748 :     ScAddress aOrigin(ScAddress::INITIALIZE_INVALID);
     199         748 :     ScAddress aCurOrigin = aOrigin;
     200             : 
     201         748 :     bool bOpen = false;
     202         748 :     ScRangeList aRanges = rMark.GetMarkedRanges();
     203        3584 :     for (size_t i = 0, n = aRanges.size(); i < n; ++i)
     204             :     {
     205        2836 :         const ScRange& r = *aRanges[i];
     206        2836 :         if (nTab < r.aStart.Tab() || r.aEnd.Tab() < nTab)
     207        2088 :             continue;
     208             : 
     209        2836 :         if (nCol < r.aStart.Col() || r.aEnd.Col() < nCol)
     210        2088 :             continue;
     211             : 
     212         748 :         SCROW nTop = r.aStart.Row(), nBottom = r.aEnd.Row();
     213         748 :         SCROW nRow = nTop;
     214         748 :         std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
     215         748 :         sc::CellStoreType::const_iterator it = aPos.first;
     216         748 :         size_t nOffset = aPos.second;
     217             : 
     218        1496 :         for (;it != maCells.end() && nRow <= nBottom; ++it, nOffset = 0)
     219             :         {
     220         748 :             if (it->type != sc::element_type_formula)
     221             :             {
     222             :                 // Skip this block.
     223         748 :                 nRow += it->size - nOffset;
     224         748 :                 continue;
     225             :             }
     226             : 
     227             :             // This is a formula cell block.
     228           0 :             size_t nRowsToRead = nBottom - nRow + 1;
     229           0 :             size_t nEnd = std::min(it->size, nRowsToRead);
     230           0 :             sc::formula_block::const_iterator itCell = sc::formula_block::begin(*it->data);
     231           0 :             std::advance(itCell, nOffset);
     232           0 :             for (size_t j = nOffset; j < nEnd; ++itCell, ++j)
     233             :             {
     234             :                 // Loop inside the formula block.
     235           0 :                 const ScFormulaCell* pCell = *itCell;
     236           0 :                 if (!pCell->GetMatrixFlag())
     237             :                     // cell is not a part of a matrix.
     238           0 :                     continue;
     239             : 
     240           0 :                 sal_uInt16 nEdges = pCell->GetMatrixEdge(aOrigin);
     241           0 :                 if (!nEdges)
     242           0 :                     continue;
     243             : 
     244           0 :                 bool bFound = false;
     245             : 
     246           0 :                 if (nEdges & MatrixEdgeTop)
     247           0 :                     bOpen = true;   // top edge opens, keep on looking
     248           0 :                 else if (!bOpen)
     249           0 :                     return true;    // there's something that wasn't opened
     250           0 :                 else if (nEdges & MatrixEdgeInside)
     251           0 :                     bFound = true;  // inside, all selected?
     252             : 
     253           0 :                 if ((((nEdges & MatrixEdgeLeft) | MatrixEdgeRight) ^ ((nEdges & MatrixEdgeRight) | MatrixEdgeLeft)))
     254             :                     // either left or right, but not both.
     255           0 :                     bFound = true;  // only left/right edge, all selected?
     256             : 
     257           0 :                 if (nEdges & MatrixEdgeBottom)
     258           0 :                     bOpen = false;  // bottom edge closes
     259             : 
     260           0 :                 if (bFound)
     261             :                 {
     262             :                     // Check if the matrix is inside the selection in its entirety.
     263             :                     //
     264             :                     // TODO: It's more efficient to skip the matrix range if
     265             :                     // it's within selection, to avoid checking it again and
     266             :                     // again.
     267             : 
     268           0 :                     if (aCurOrigin != aOrigin)
     269             :                     {   // new matrix to check?
     270           0 :                         aCurOrigin = aOrigin;
     271             :                         const ScFormulaCell* pFCell;
     272           0 :                         if (pCell->GetMatrixFlag() == MM_REFERENCE)
     273           0 :                             pFCell = pDocument->GetFormulaCell(aOrigin);
     274             :                         else
     275           0 :                             pFCell = pCell;
     276             : 
     277             :                         SCCOL nC;
     278             :                         SCROW nR;
     279           0 :                         pFCell->GetMatColsRows(nC, nR);
     280           0 :                         ScRange aRange(aOrigin, ScAddress(aOrigin.Col()+nC-1, aOrigin.Row()+nR-1, aOrigin.Tab()));
     281           0 :                         if (rMark.IsAllMarked(aRange))
     282           0 :                             bFound = false;
     283             :                     }
     284             :                     else
     285           0 :                         bFound = false;     // done already
     286             :                 }
     287             : 
     288           0 :                 if (bFound)
     289           0 :                     return true;
     290             :             }
     291             : 
     292           0 :             nRow += nEnd;
     293             :         }
     294             :     }
     295             : 
     296         748 :     if (bOpen)
     297           0 :         return true;
     298             : 
     299         748 :     return false;
     300             : }
     301             : 
     302    28191952 : bool ScColumn::HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const
     303             : {
     304    28191952 :     return pAttrArray->HasAttrib( nRow1, nRow2, nMask );
     305             : }
     306             : 
     307           0 : bool ScColumn::HasAttribSelection( const ScMarkData& rMark, sal_uInt16 nMask ) const
     308             : {
     309           0 :     bool bFound = false;
     310             : 
     311             :     SCROW nTop;
     312             :     SCROW nBottom;
     313             : 
     314           0 :     if (rMark.IsMultiMarked())
     315             :     {
     316           0 :         ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
     317           0 :         while (aMarkIter.Next( nTop, nBottom ) && !bFound)
     318             :         {
     319           0 :             if (pAttrArray->HasAttrib( nTop, nBottom, nMask ))
     320           0 :                 bFound = true;
     321           0 :         }
     322             :     }
     323             : 
     324           0 :     return bFound;
     325             : }
     326             : 
     327       20536 : bool ScColumn::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
     328             :                             SCCOL& rPaintCol, SCROW& rPaintRow,
     329             :                             bool bRefresh )
     330             : {
     331       20536 :     return pAttrArray->ExtendMerge( nThisCol, nStartRow, nEndRow, rPaintCol, rPaintRow, bRefresh );
     332             : }
     333             : 
     334      512000 : void ScColumn::MergeSelectionPattern( ScMergePatternState& rState, const ScMarkData& rMark, bool bDeep ) const
     335             : {
     336             :     SCROW nTop;
     337             :     SCROW nBottom;
     338             : 
     339      512000 :     if ( rMark.IsMultiMarked() )
     340             :     {
     341      512000 :         const ScMarkArray* pArray = rMark.GetArray() + nCol;
     342      512000 :         if ( pArray->HasMarks() )
     343             :         {
     344       60160 :             ScMarkArrayIter aMarkIter( pArray );
     345      181936 :             while (aMarkIter.Next( nTop, nBottom ))
     346      121776 :                 pAttrArray->MergePatternArea( nTop, nBottom, rState, bDeep );
     347             :         }
     348             :     }
     349      512000 : }
     350             : 
     351      112654 : void ScColumn::MergePatternArea( ScMergePatternState& rState, SCROW nRow1, SCROW nRow2, bool bDeep ) const
     352             : {
     353      112654 :     pAttrArray->MergePatternArea( nRow1, nRow2, rState, bDeep );
     354      112654 : }
     355             : 
     356         256 : void ScColumn::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
     357             :                             ScLineFlags& rFlags,
     358             :                             SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight ) const
     359             : {
     360         256 :     pAttrArray->MergeBlockFrame( pLineOuter, pLineInner, rFlags, nStartRow, nEndRow, bLeft, nDistRight );
     361         256 : }
     362             : 
     363        3692 : void ScColumn::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner,
     364             :                             SCROW nStartRow, SCROW nEndRow, bool bLeft, SCCOL nDistRight )
     365             : {
     366        3692 :     pAttrArray->ApplyBlockFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight );
     367        3692 : }
     368             : 
     369    37831569 : const ScPatternAttr* ScColumn::GetPattern( SCROW nRow ) const
     370             : {
     371    37831569 :     return pAttrArray->GetPattern( nRow );
     372             : }
     373             : 
     374       22610 : const SfxPoolItem* ScColumn::GetAttr( SCROW nRow, sal_uInt16 nWhich ) const
     375             : {
     376       22610 :     return &pAttrArray->GetPattern( nRow )->GetItemSet().Get(nWhich);
     377             : }
     378             : 
     379       88576 : const ScPatternAttr* ScColumn::GetMostUsedPattern( SCROW nStartRow, SCROW nEndRow ) const
     380             : {
     381       88576 :     ::std::map< const ScPatternAttr*, size_t > aAttrMap;
     382       88576 :     const ScPatternAttr* pMaxPattern = 0;
     383       88576 :     size_t nMaxCount = 0;
     384             : 
     385       88576 :     ScAttrIterator aAttrIter( pAttrArray, nStartRow, nEndRow );
     386             :     const ScPatternAttr* pPattern;
     387       88576 :     SCROW nAttrRow1 = 0, nAttrRow2 = 0;
     388             : 
     389      269552 :     while( (pPattern = aAttrIter.Next( nAttrRow1, nAttrRow2 )) != 0 )
     390             :     {
     391       92400 :         size_t& rnCount = aAttrMap[ pPattern ];
     392       92400 :         rnCount += (nAttrRow2 - nAttrRow1 + 1);
     393       92400 :         if( rnCount > nMaxCount )
     394             :         {
     395       90576 :             pMaxPattern = pPattern;
     396       90576 :             nMaxCount = rnCount;
     397             :         }
     398             :     }
     399             : 
     400       88576 :     return pMaxPattern;
     401             : }
     402             : 
     403          48 : sal_uInt32 ScColumn::GetNumberFormat( SCROW nStartRow, SCROW nEndRow ) const
     404             : {
     405             :     SCROW nPatStartRow, nPatEndRow;
     406          48 :     const ScPatternAttr* pPattern = pAttrArray->GetPatternRange(nPatStartRow, nPatEndRow, nStartRow);
     407          48 :     sal_uInt32 nFormat = pPattern->GetNumberFormat(pDocument->GetFormatTable());
     408          96 :     while (nEndRow > nPatEndRow)
     409             :     {
     410           0 :         nStartRow = nPatEndRow + 1;
     411           0 :         pPattern = pAttrArray->GetPatternRange(nPatStartRow, nPatEndRow, nStartRow);
     412           0 :         sal_uInt32 nTmpFormat = pPattern->GetNumberFormat(pDocument->GetFormatTable());
     413           0 :         if (nFormat != nTmpFormat)
     414           0 :             return 0;
     415             :     }
     416          48 :     return nFormat;
     417             : }
     418             : 
     419      102775 : sal_uInt32 ScColumn::GetNumberFormat( SCROW nRow ) const
     420             : {
     421      102775 :     return pAttrArray->GetPattern( nRow )->GetNumberFormat( pDocument->GetFormatTable() );
     422             : }
     423             : 
     424      352256 : SCsROW ScColumn::ApplySelectionCache( SfxItemPoolCache* pCache, const ScMarkData& rMark, ScEditDataArray* pDataArray )
     425             : {
     426      352256 :     SCROW nTop = 0;
     427      352256 :     SCROW nBottom = 0;
     428      352256 :     bool bFound = false;
     429             : 
     430      352256 :     if ( rMark.IsMultiMarked() )
     431             :     {
     432      352256 :         ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
     433      720330 :         while (aMarkIter.Next( nTop, nBottom ))
     434             :         {
     435       15818 :             pAttrArray->ApplyCacheArea( nTop, nBottom, pCache, pDataArray );
     436       15818 :             bFound = true;
     437      352256 :         }
     438             :     }
     439             : 
     440      352256 :     if (!bFound)
     441      337666 :         return -1;
     442       14590 :     else if (nTop==0 && nBottom==MAXROW)
     443        8144 :         return 0;
     444             :     else
     445        6446 :         return nBottom;
     446             : }
     447             : 
     448       12288 : void ScColumn::ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark )
     449             : {
     450             :     SCROW nTop;
     451             :     SCROW nBottom;
     452             : 
     453       12288 :     if ( pAttrArray && rMark.IsMultiMarked() )
     454             :     {
     455       12288 :         ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
     456       24628 :         while (aMarkIter.Next( nTop, nBottom ))
     457       12340 :             pAttrArray->ChangeIndent(nTop, nBottom, bIncrement);
     458             :     }
     459       12288 : }
     460             : 
     461           0 : void ScColumn::ClearSelectionItems( const sal_uInt16* pWhich,const ScMarkData& rMark )
     462             : {
     463             :     SCROW nTop;
     464             :     SCROW nBottom;
     465             : 
     466           0 :     if ( pAttrArray && rMark.IsMultiMarked() )
     467             :     {
     468           0 :         ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
     469           0 :         while (aMarkIter.Next( nTop, nBottom ))
     470           0 :             pAttrArray->ClearItems(nTop, nBottom, pWhich);
     471             :     }
     472           0 : }
     473             : 
     474      190464 : void ScColumn::DeleteSelection( InsertDeleteFlags nDelFlag, const ScMarkData& rMark, bool bBroadcast )
     475             : {
     476             :     SCROW nTop;
     477             :     SCROW nBottom;
     478             : 
     479      190464 :     if ( rMark.IsMultiMarked() )
     480             :     {
     481      188416 :         ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
     482      377212 :         while (aMarkIter.Next( nTop, nBottom ))
     483      188796 :             DeleteArea(nTop, nBottom, nDelFlag, bBroadcast);
     484             :     }
     485      190464 : }
     486             : 
     487         274 : void ScColumn::ApplyPattern( SCROW nRow, const ScPatternAttr& rPatAttr )
     488             : {
     489         274 :     const SfxItemSet* pSet = &rPatAttr.GetItemSet();
     490         274 :     SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
     491             : 
     492         274 :     const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
     493             : 
     494             :     //  true = keep old content
     495             : 
     496         274 :     const ScPatternAttr* pNewPattern = static_cast<const ScPatternAttr*>( &aCache.ApplyTo( *pPattern, true ) );
     497         274 :     ScDocumentPool::CheckRef( *pPattern );
     498         274 :     ScDocumentPool::CheckRef( *pNewPattern );
     499             : 
     500         274 :     if (pNewPattern != pPattern)
     501         274 :       pAttrArray->SetPattern( nRow, pNewPattern );
     502         274 : }
     503             : 
     504      134398 : void ScColumn::ApplyPatternArea( SCROW nStartRow, SCROW nEndRow, const ScPatternAttr& rPatAttr,
     505             :                                  ScEditDataArray* pDataArray )
     506             : {
     507      134398 :     const SfxItemSet* pSet = &rPatAttr.GetItemSet();
     508      134398 :     SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
     509      134398 :     pAttrArray->ApplyCacheArea( nStartRow, nEndRow, &aCache, pDataArray );
     510      134398 : }
     511             : 
     512           0 : void ScColumn::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
     513             :         const ScPatternAttr& rPattern, short nNewType )
     514             : {
     515           0 :     const SfxItemSet* pSet = &rPattern.GetItemSet();
     516           0 :     SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
     517           0 :     SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
     518           0 :     SCROW nEndRow = rRange.aEnd.Row();
     519           0 :     for ( SCROW nRow = rRange.aStart.Row(); nRow <= nEndRow; nRow++ )
     520             :     {
     521             :         SCROW nRow1, nRow2;
     522             :         const ScPatternAttr* pPattern = pAttrArray->GetPatternRange(
     523           0 :             nRow1, nRow2, nRow );
     524           0 :         sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter );
     525           0 :         short nOldType = pFormatter->GetType( nFormat );
     526           0 :         if ( nOldType == nNewType || pFormatter->IsCompatible( nOldType, nNewType ) )
     527           0 :             nRow = nRow2;
     528             :         else
     529             :         {
     530           0 :             SCROW nNewRow1 = std::max( nRow1, nRow );
     531           0 :             SCROW nNewRow2 = std::min( nRow2, nEndRow );
     532           0 :             pAttrArray->ApplyCacheArea( nNewRow1, nNewRow2, &aCache );
     533           0 :             nRow = nNewRow2;
     534             :         }
     535           0 :     }
     536           0 : }
     537             : 
     538       13036 : void ScColumn::AddCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex )
     539             : {
     540       13036 :     pAttrArray->AddCondFormat( nStartRow, nEndRow, nIndex );
     541       13036 : }
     542             : 
     543           0 : void ScColumn::RemoveCondFormat( SCROW nStartRow, SCROW nEndRow, sal_uInt32 nIndex )
     544             : {
     545           0 :     pAttrArray->RemoveCondFormat( nStartRow, nEndRow, nIndex );
     546           0 : }
     547             : 
     548           4 : void ScColumn::ApplyStyle( SCROW nRow, const ScStyleSheet& rStyle )
     549             : {
     550           4 :     const ScPatternAttr* pPattern = pAttrArray->GetPattern(nRow);
     551           4 :     boost::scoped_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr(*pPattern));
     552           4 :     if (pNewPattern)
     553             :     {
     554           4 :         pNewPattern->SetStyleSheet((ScStyleSheet*)&rStyle);
     555           4 :         pAttrArray->SetPattern(nRow, pNewPattern.get(), true);
     556           4 :     }
     557           4 : }
     558             : 
     559      406092 : void ScColumn::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, const ScStyleSheet& rStyle )
     560             : {
     561      406092 :     pAttrArray->ApplyStyleArea(nStartRow, nEndRow, (ScStyleSheet*)&rStyle);
     562      406092 : }
     563             : 
     564      481280 : void ScColumn::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
     565             : {
     566             :     SCROW nTop;
     567             :     SCROW nBottom;
     568             : 
     569      481280 :     if ( rMark.IsMultiMarked() )
     570             :     {
     571      481280 :         ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
     572      983772 :         while (aMarkIter.Next( nTop, nBottom ))
     573      502492 :             pAttrArray->ApplyStyleArea(nTop, nBottom, (ScStyleSheet*)&rStyle);
     574             :     }
     575      481280 : }
     576             : 
     577           0 : void ScColumn::ApplySelectionLineStyle( const ScMarkData& rMark,
     578             :                                     const SvxBorderLine* pLine, bool bColorOnly )
     579             : {
     580           0 :     if ( bColorOnly && !pLine )
     581           0 :         return;
     582             : 
     583             :     SCROW nTop;
     584             :     SCROW nBottom;
     585             : 
     586           0 :     if (rMark.IsMultiMarked())
     587             :     {
     588           0 :         ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
     589           0 :         while (aMarkIter.Next( nTop, nBottom ))
     590           0 :             pAttrArray->ApplyLineStyleArea(nTop, nBottom, pLine, bColorOnly );
     591             :     }
     592             : }
     593             : 
     594          16 : const ScStyleSheet* ScColumn::GetStyle( SCROW nRow ) const
     595             : {
     596          16 :     return pAttrArray->GetPattern( nRow )->GetStyleSheet();
     597             : }
     598             : 
     599       45056 : const ScStyleSheet* ScColumn::GetSelectionStyle( const ScMarkData& rMark, bool& rFound ) const
     600             : {
     601       45056 :     rFound = false;
     602       45056 :     if (!rMark.IsMultiMarked())
     603             :     {
     604             :         OSL_FAIL("No selection in ScColumn::GetSelectionStyle");
     605           0 :         return NULL;
     606             :     }
     607             : 
     608       45056 :     bool bEqual = true;
     609             : 
     610       45056 :     const ScStyleSheet* pStyle = NULL;
     611             :     const ScStyleSheet* pNewStyle;
     612             : 
     613       45056 :     ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
     614             :     SCROW nTop;
     615             :     SCROW nBottom;
     616      135252 :     while (bEqual && aMarkIter.Next( nTop, nBottom ))
     617             :     {
     618       45140 :         ScAttrIterator aAttrIter( pAttrArray, nTop, nBottom );
     619             :         SCROW nRow;
     620             :         SCROW nDummy;
     621             :         const ScPatternAttr* pPattern;
     622      135420 :         while (bEqual && ( pPattern = aAttrIter.Next( nRow, nDummy ) ) != NULL)
     623             :         {
     624       45140 :             pNewStyle = pPattern->GetStyleSheet();
     625       45140 :             rFound = true;
     626       45140 :             if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
     627           0 :                 bEqual = false;                                             // difference
     628       45140 :             pStyle = pNewStyle;
     629             :         }
     630             :     }
     631             : 
     632       45056 :     return bEqual ? pStyle : NULL;
     633             : }
     634             : 
     635       70060 : const ScStyleSheet* ScColumn::GetAreaStyle( bool& rFound, SCROW nRow1, SCROW nRow2 ) const
     636             : {
     637       70060 :     rFound = false;
     638             : 
     639       70060 :     bool bEqual = true;
     640             : 
     641       70060 :     const ScStyleSheet* pStyle = NULL;
     642             :     const ScStyleSheet* pNewStyle;
     643             : 
     644       70060 :     ScAttrIterator aAttrIter( pAttrArray, nRow1, nRow2 );
     645             :     SCROW nRow;
     646             :     SCROW nDummy;
     647             :     const ScPatternAttr* pPattern;
     648      210200 :     while (bEqual && ( pPattern = aAttrIter.Next( nRow, nDummy ) ) != NULL)
     649             :     {
     650       70080 :         pNewStyle = pPattern->GetStyleSheet();
     651       70080 :         rFound = true;
     652       70080 :         if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
     653           0 :             bEqual = false;                                             // difference
     654       70080 :         pStyle = pNewStyle;
     655             :     }
     656             : 
     657       70060 :     return bEqual ? pStyle : NULL;
     658             : }
     659             : 
     660    10694656 : void ScColumn::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset )
     661             : {
     662    10694656 :     pAttrArray->FindStyleSheet( pStyleSheet, rUsedRows, bReset );
     663    10694656 : }
     664             : 
     665           0 : bool ScColumn::IsStyleSheetUsed( const ScStyleSheet& rStyle, bool bGatherAllStyles ) const
     666             : {
     667           0 :     return pAttrArray->IsStyleSheetUsed( rStyle, bGatherAllStyles );
     668             : }
     669             : 
     670       10872 : bool ScColumn::ApplyFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
     671             : {
     672       10872 :     return pAttrArray->ApplyFlags( nStartRow, nEndRow, nFlags );
     673             : }
     674             : 
     675       32328 : bool ScColumn::RemoveFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags )
     676             : {
     677       32328 :     return pAttrArray->RemoveFlags( nStartRow, nEndRow, nFlags );
     678             : }
     679             : 
     680         330 : void ScColumn::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich )
     681             : {
     682         330 :     pAttrArray->ClearItems( nStartRow, nEndRow, pWhich );
     683         330 : }
     684             : 
     685         326 : void ScColumn::SetPattern( SCROW nRow, const ScPatternAttr& rPatAttr, bool bPutToPool )
     686             : {
     687         326 :     pAttrArray->SetPattern( nRow, &rPatAttr, bPutToPool );
     688         326 : }
     689             : 
     690          68 : void ScColumn::SetPatternArea( SCROW nStartRow, SCROW nEndRow,
     691             :                                 const ScPatternAttr& rPatAttr, bool bPutToPool )
     692             : {
     693          68 :     pAttrArray->SetPatternArea( nStartRow, nEndRow, &rPatAttr, bPutToPool );
     694          68 : }
     695             : 
     696        6016 : void ScColumn::ApplyAttr( SCROW nRow, const SfxPoolItem& rAttr )
     697             : {
     698             :     //  in order to only create a new SetItem, we don't need SfxItemPoolCache.
     699             :     //! Warning: SfxItemPoolCache seems to create to many Refs for the new SetItem ??
     700             : 
     701        6016 :     ScDocumentPool* pDocPool = pDocument->GetPool();
     702             : 
     703        6016 :     const ScPatternAttr* pOldPattern = pAttrArray->GetPattern( nRow );
     704        6016 :     boost::scoped_ptr<ScPatternAttr> pTemp(new ScPatternAttr(*pOldPattern));
     705        6016 :     pTemp->GetItemSet().Put(rAttr);
     706        6016 :     const ScPatternAttr* pNewPattern = static_cast<const ScPatternAttr*>( &pDocPool->Put( *pTemp ) );
     707             : 
     708        6016 :     if ( pNewPattern != pOldPattern )
     709        5392 :         pAttrArray->SetPattern( nRow, pNewPattern );
     710             :     else
     711         624 :         pDocPool->Remove( *pNewPattern );       // free up resources
     712        6016 : }
     713             : 
     714      192220 : ScRefCellValue ScColumn::GetCellValue( SCROW nRow ) const
     715             : {
     716      192220 :     std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
     717      192220 :     if (aPos.first == maCells.end())
     718           0 :         return ScRefCellValue();
     719             : 
     720      192220 :     return GetCellValue(aPos.first, aPos.second);
     721             : }
     722             : 
     723       11370 : ScRefCellValue ScColumn::GetCellValue( sc::ColumnBlockConstPosition& rBlockPos, SCROW nRow ) const
     724             : {
     725       11370 :     std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(rBlockPos.miCellPos, nRow);
     726       11370 :     if (aPos.first == maCells.end())
     727           0 :         return ScRefCellValue();
     728             : 
     729       11370 :     rBlockPos.miCellPos = aPos.first; // Store this for next call.
     730       11370 :     return GetCellValue(aPos.first, aPos.second);
     731             : }
     732             : 
     733      256381 : ScRefCellValue ScColumn::GetCellValue( const sc::CellStoreType::const_iterator& itPos, size_t nOffset ) const
     734             : {
     735      256381 :     ScRefCellValue aVal; // Defaults to empty cell.
     736      256381 :     switch (itPos->type)
     737             :     {
     738             :         case sc::element_type_numeric:
     739             :             // Numeric cell
     740      100952 :             aVal.mfValue = sc::numeric_block::at(*itPos->data, nOffset);
     741      100952 :             aVal.meType = CELLTYPE_VALUE;
     742      100952 :         break;
     743             :         case sc::element_type_string:
     744             :             // String cell
     745       35549 :             aVal.mpString = &sc::string_block::at(*itPos->data, nOffset);
     746       35549 :             aVal.meType = CELLTYPE_STRING;
     747       35549 :         break;
     748             :         case sc::element_type_edittext:
     749             :             // Edit cell
     750        1576 :             aVal.mpEditText = sc::edittext_block::at(*itPos->data, nOffset);
     751        1576 :             aVal.meType = CELLTYPE_EDIT;
     752        1576 :         break;
     753             :         case sc::element_type_formula:
     754             :             // Formula cell
     755       55785 :             aVal.mpFormula = sc::formula_block::at(*itPos->data, nOffset);
     756       55785 :             aVal.meType = CELLTYPE_FORMULA;
     757       55785 :         break;
     758             :         default:
     759             :             ;
     760             :     }
     761             : 
     762      256381 :     return aVal;
     763             : }
     764             : 
     765       11120 : const sc::CellTextAttr* ScColumn::GetCellTextAttr( sc::ColumnBlockConstPosition& rBlockPos, SCROW nRow ) const
     766             : {
     767       11120 :     sc::CellTextAttrStoreType::const_position_type aPos = maCellTextAttrs.position(rBlockPos.miCellTextAttrPos, nRow);
     768       11120 :     if (aPos.first == maCellTextAttrs.end())
     769           0 :         return NULL;
     770             : 
     771       11120 :     rBlockPos.miCellTextAttrPos = aPos.first;
     772             : 
     773       11120 :     if (aPos.first->type != sc::element_type_celltextattr)
     774       10300 :         return NULL;
     775             : 
     776         820 :     return &sc::celltextattr_block::at(*aPos.first->data, aPos.second);
     777             : }
     778             : 
     779         118 : bool ScColumn::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
     780             : {
     781         118 :     if (IsEmpty())
     782         118 :         return true;
     783             : 
     784             :     // Return false if we have any non-empty cells between nStartRow and nEndRow inclusive.
     785           0 :     std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
     786           0 :     sc::CellStoreType::const_iterator it = aPos.first;
     787           0 :     if (it->type != sc::element_type_empty)
     788           0 :         return false;
     789             : 
     790             :     // Get the length of the remaining empty segment.
     791           0 :     size_t nLen = it->size - aPos.second;
     792           0 :     SCROW nNextNonEmptyRow = nStartRow + nLen;
     793           0 :     if (nNextNonEmptyRow <= nEndRow)
     794           0 :         return false;
     795             : 
     796             :     //  AttrArray only looks for merged cells
     797             : 
     798           0 :     return pAttrArray ? pAttrArray->TestInsertCol(nStartRow, nEndRow) : true;
     799             : }
     800             : 
     801       81938 : bool ScColumn::TestInsertRow( SCROW nStartRow, SCSIZE nSize ) const
     802             : {
     803             :     //  AttrArray only looks for merged cells
     804             :     {
     805       81938 :         std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nStartRow);
     806       81938 :         sc::CellStoreType::const_iterator it = aPos.first;
     807       81938 :         if (it->type == sc::element_type_empty && maCells.block_size() == 1)
     808             :             // The entire cell array is empty.
     809       81810 :             return pAttrArray->TestInsertRow(nSize);
     810             :     }
     811             : 
     812             :     // See if there would be any non-empty cell that gets pushed out.
     813             : 
     814             :     // Find the position of the last non-empty cell below nStartRow.
     815         128 :     size_t nLastNonEmptyRow = MAXROW;
     816         128 :     sc::CellStoreType::const_reverse_iterator it = maCells.rbegin();
     817         128 :     if (it->type == sc::element_type_empty)
     818         128 :         nLastNonEmptyRow -= it->size;
     819             : 
     820         128 :     if (nLastNonEmptyRow < static_cast<size_t>(nStartRow))
     821             :         // No cells would get pushed out.
     822          42 :         return pAttrArray->TestInsertRow(nSize);
     823             : 
     824          86 :     if (nLastNonEmptyRow + nSize > static_cast<size_t>(MAXROW))
     825             :         // At least one cell would get pushed out. Not good.
     826           0 :         return false;
     827             : 
     828          86 :     return pAttrArray->TestInsertRow(nSize);
     829             : }
     830             : 
     831       81938 : void ScColumn::InsertRow( SCROW nStartRow, SCSIZE nSize )
     832             : {
     833       81938 :     pAttrArray->InsertRow( nStartRow, nSize );
     834             : 
     835       81938 :     maCellNotes.insert_empty(nStartRow, nSize);
     836       81938 :     maCellNotes.resize(MAXROWCOUNT);
     837             : 
     838       81938 :     maBroadcasters.insert_empty(nStartRow, nSize);
     839       81938 :     maBroadcasters.resize(MAXROWCOUNT);
     840             : 
     841       81938 :     maCellTextAttrs.insert_empty(nStartRow, nSize);
     842       81938 :     maCellTextAttrs.resize(MAXROWCOUNT);
     843             : 
     844       81938 :     maCells.insert_empty(nStartRow, nSize);
     845       81938 :     maCells.resize(MAXROWCOUNT);
     846             : 
     847       81938 :     CellStorageModified();
     848             : 
     849             :     // We *probably* don't need to broadcast here since the parent call seems
     850             :     // to take care of it.
     851       81938 : }
     852             : 
     853             : namespace {
     854             : 
     855             : class CopyToClipHandler
     856             : {
     857             :     const ScColumn& mrSrcCol;
     858             :     ScColumn& mrDestCol;
     859             :     sc::ColumnBlockPosition maDestPos;
     860             :     sc::ColumnBlockPosition* mpDestPos;
     861             :     bool mbCopyNotes;
     862             : 
     863         154 :     void setDefaultAttrsToDest(size_t nRow, size_t nSize)
     864             :     {
     865         154 :         std::vector<sc::CellTextAttr> aAttrs(nSize); // default values
     866         308 :         maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
     867         308 :             maDestPos.miCellTextAttrPos, nRow, aAttrs.begin(), aAttrs.end());
     868         154 :     }
     869             : 
     870         200 :     void duplicateNotes(SCROW nStartRow, size_t nDataSize )
     871             :     {
     872         200 :         mrSrcCol.DuplicateNotes(nStartRow, nDataSize, mrDestCol, maDestPos, false);
     873         200 :     }
     874             : 
     875             : public:
     876         150 :     CopyToClipHandler(const ScColumn& rSrcCol, ScColumn& rDestCol, sc::ColumnBlockPosition* pDestPos, bool bCopyNotes) :
     877         150 :         mrSrcCol(rSrcCol), mrDestCol(rDestCol), mpDestPos(pDestPos), mbCopyNotes(bCopyNotes)
     878             :     {
     879         150 :         if (mpDestPos)
     880         150 :             maDestPos = *mpDestPos;
     881             :         else
     882           0 :             mrDestCol.InitBlockPosition(maDestPos);
     883         150 :     }
     884             : 
     885         150 :     ~CopyToClipHandler()
     886             :     {
     887         150 :         if (mpDestPos)
     888         150 :             *mpDestPos = maDestPos;
     889         150 :     }
     890             : 
     891         200 :     void operator() (const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
     892             :     {
     893         200 :         size_t nTopRow = aNode.position + nOffset;
     894             : 
     895         200 :         bool bSet = true;
     896             : 
     897         200 :         switch (aNode.type)
     898             :         {
     899             :             case sc::element_type_numeric:
     900             :             {
     901          70 :                 sc::numeric_block::const_iterator it = sc::numeric_block::begin(*aNode.data);
     902          70 :                 std::advance(it, nOffset);
     903          70 :                 sc::numeric_block::const_iterator itEnd = it;
     904          70 :                 std::advance(itEnd, nDataSize);
     905          70 :                 maDestPos.miCellPos = mrDestCol.GetCellStore().set(maDestPos.miCellPos, nTopRow, it, itEnd);
     906             :             }
     907          70 :             break;
     908             :             case sc::element_type_string:
     909             :             {
     910          42 :                 sc::string_block::const_iterator it = sc::string_block::begin(*aNode.data);
     911          42 :                 std::advance(it, nOffset);
     912          42 :                 sc::string_block::const_iterator itEnd = it;
     913          42 :                 std::advance(itEnd, nDataSize);
     914          42 :                 maDestPos.miCellPos = mrDestCol.GetCellStore().set(maDestPos.miCellPos, nTopRow, it, itEnd);
     915             : 
     916             :             }
     917          42 :             break;
     918             :             case sc::element_type_edittext:
     919             :             {
     920           0 :                 sc::edittext_block::const_iterator it = sc::edittext_block::begin(*aNode.data);
     921           0 :                 std::advance(it, nOffset);
     922           0 :                 sc::edittext_block::const_iterator itEnd = it;
     923           0 :                 std::advance(itEnd, nDataSize);
     924             : 
     925           0 :                 std::vector<EditTextObject*> aCloned;
     926           0 :                 aCloned.reserve(nDataSize);
     927           0 :                 for (; it != itEnd; ++it)
     928           0 :                     aCloned.push_back(ScEditUtil::Clone(**it, mrDestCol.GetDoc()));
     929             : 
     930           0 :                 maDestPos.miCellPos = mrDestCol.GetCellStore().set(
     931           0 :                     maDestPos.miCellPos, nTopRow, aCloned.begin(), aCloned.end());
     932             :             }
     933           0 :             break;
     934             :             case sc::element_type_formula:
     935             :             {
     936          42 :                 sc::formula_block::const_iterator it = sc::formula_block::begin(*aNode.data);
     937          42 :                 std::advance(it, nOffset);
     938          42 :                 sc::formula_block::const_iterator itEnd = it;
     939          42 :                 std::advance(itEnd, nDataSize);
     940             : 
     941          42 :                 std::vector<ScFormulaCell*> aCloned;
     942          42 :                 aCloned.reserve(nDataSize);
     943          42 :                 ScAddress aDestPos(mrDestCol.GetCol(), nTopRow, mrDestCol.GetTab());
     944         118 :                 for (; it != itEnd; ++it, aDestPos.IncRow())
     945             :                 {
     946          76 :                     const ScFormulaCell& rOld = **it;
     947          76 :                     if (rOld.GetDirty() && mrSrcCol.GetDoc().GetAutoCalc())
     948          32 :                         const_cast<ScFormulaCell&>(rOld).Interpret();
     949             : 
     950          76 :                     aCloned.push_back(new ScFormulaCell(rOld, mrDestCol.GetDoc(), aDestPos));
     951             :                 }
     952             : 
     953             :                 // Group the cloned formula cells.
     954          42 :                 if (!aCloned.empty())
     955          42 :                     sc::SharedFormulaUtil::groupFormulaCells(aCloned.begin(), aCloned.end());
     956             : 
     957          42 :                 sc::CellStoreType& rDestCells = mrDestCol.GetCellStore();
     958          84 :                 maDestPos.miCellPos = rDestCells.set(
     959          42 :                     maDestPos.miCellPos, nTopRow, aCloned.begin(), aCloned.end());
     960             : 
     961             :                 // Merge adjacent formula cell groups (if applicable).
     962             :                 sc::CellStoreType::position_type aPos =
     963          42 :                     rDestCells.position(maDestPos.miCellPos, nTopRow);
     964          42 :                 maDestPos.miCellPos = aPos.first;
     965          42 :                 sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
     966          42 :                 size_t nLastRow = nTopRow + nDataSize;
     967          42 :                 if (nLastRow < static_cast<size_t>(MAXROW))
     968             :                 {
     969          42 :                     aPos = rDestCells.position(maDestPos.miCellPos, nLastRow+1);
     970          42 :                     sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
     971          42 :                 }
     972             :             }
     973          42 :             break;
     974             :             default:
     975          46 :                 bSet = false;
     976             :         }
     977             : 
     978         200 :         if (bSet)
     979         154 :             setDefaultAttrsToDest(nTopRow, nDataSize);
     980             : 
     981         200 :         if (mbCopyNotes)
     982         200 :             duplicateNotes(nTopRow, nDataSize);
     983         200 :     }
     984             : };
     985             : 
     986             : class CopyTextAttrToClipHandler
     987             : {
     988             :     sc::CellTextAttrStoreType& mrDestAttrs;
     989             :     sc::CellTextAttrStoreType::iterator miPos;
     990             : 
     991             : public:
     992         150 :     CopyTextAttrToClipHandler( sc::CellTextAttrStoreType& rAttrs ) :
     993         150 :         mrDestAttrs(rAttrs), miPos(mrDestAttrs.begin()) {}
     994             : 
     995         178 :     void operator() ( const sc::CellTextAttrStoreType::value_type& aNode, size_t nOffset, size_t nDataSize )
     996             :     {
     997         178 :         if (aNode.type != sc::element_type_celltextattr)
     998         224 :             return;
     999             : 
    1000         132 :         sc::celltextattr_block::const_iterator it = sc::celltextattr_block::begin(*aNode.data);
    1001         132 :         std::advance(it, nOffset);
    1002         132 :         sc::celltextattr_block::const_iterator itEnd = it;
    1003         132 :         std::advance(itEnd, nDataSize);
    1004             : 
    1005         132 :         size_t nPos = aNode.position + nOffset;
    1006         132 :         miPos = mrDestAttrs.set(miPos, nPos, it, itEnd);
    1007             :     }
    1008             : };
    1009             : 
    1010             : 
    1011             : }
    1012             : 
    1013         150 : void ScColumn::CopyToClip(
    1014             :     sc::CopyToClipContext& rCxt, SCROW nRow1, SCROW nRow2, ScColumn& rColumn ) const
    1015             : {
    1016             :     pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray,
    1017         150 :                           rCxt.isKeepScenarioFlags() ? (SC_MF_ALL & ~SC_MF_SCENARIO) : SC_MF_ALL );
    1018             : 
    1019             :     {
    1020         150 :         CopyToClipHandler aFunc(*this, rColumn, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol), rCxt.isCloneNotes());
    1021         150 :         sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
    1022             :     }
    1023             : 
    1024             :     {
    1025         150 :         CopyTextAttrToClipHandler aFunc(rColumn.maCellTextAttrs);
    1026         150 :         sc::ParseBlock(maCellTextAttrs.begin(), maCellTextAttrs, aFunc, nRow1, nRow2);
    1027             :     }
    1028             : 
    1029         150 :     rColumn.CellStorageModified();
    1030         150 : }
    1031             : 
    1032          12 : void ScColumn::CopyStaticToDocument(
    1033             :     SCROW nRow1, SCROW nRow2, const SvNumberFormatterMergeMap& rMap, ScColumn& rDestCol )
    1034             : {
    1035          12 :     if (nRow1 > nRow2)
    1036          12 :         return;
    1037             : 
    1038          12 :     sc::ColumnBlockPosition aDestPos;
    1039          12 :     CopyCellTextAttrsToDocument(nRow1, nRow2, rDestCol);
    1040          12 :     CopyCellNotesToDocument(nRow1, nRow2, rDestCol);
    1041             : 
    1042             :     // First, clear the destination column for the specified row range.
    1043          12 :     rDestCol.maCells.set_empty(nRow1, nRow2);
    1044             : 
    1045          12 :     aDestPos.miCellPos = rDestCol.maCells.begin();
    1046             : 
    1047          12 :     std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow1);
    1048          12 :     sc::CellStoreType::const_iterator it = aPos.first;
    1049          12 :     size_t nOffset = aPos.second;
    1050          12 :     size_t nDataSize = 0;
    1051          12 :     size_t nCurRow = nRow1;
    1052             : 
    1053          18 :     for (; it != maCells.end() && nCurRow <= static_cast<size_t>(nRow2); ++it, nOffset = 0, nCurRow += nDataSize)
    1054             :     {
    1055          14 :         bool bLastBlock = false;
    1056          14 :         nDataSize = it->size - nOffset;
    1057          14 :         if (nCurRow + nDataSize - 1 > static_cast<size_t>(nRow2))
    1058             :         {
    1059             :             // Truncate the block to copy to clipboard.
    1060           8 :             nDataSize = nRow2 - nCurRow + 1;
    1061           8 :             bLastBlock = true;
    1062             :         }
    1063             : 
    1064          14 :         switch (it->type)
    1065             :         {
    1066             :             case sc::element_type_numeric:
    1067             :             {
    1068           8 :                 sc::numeric_block::const_iterator itData = sc::numeric_block::begin(*it->data);
    1069           8 :                 std::advance(itData, nOffset);
    1070           8 :                 sc::numeric_block::const_iterator itDataEnd = itData;
    1071           8 :                 std::advance(itDataEnd, nDataSize);
    1072           8 :                 aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nCurRow, itData, itDataEnd);
    1073             :             }
    1074           8 :             break;
    1075             :             case sc::element_type_string:
    1076             :             {
    1077           2 :                 sc::string_block::const_iterator itData = sc::string_block::begin(*it->data);
    1078           2 :                 std::advance(itData, nOffset);
    1079           2 :                 sc::string_block::const_iterator itDataEnd = itData;
    1080           2 :                 std::advance(itDataEnd, nDataSize);
    1081           2 :                 aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nCurRow, itData, itDataEnd);
    1082             :             }
    1083           2 :             break;
    1084             :             case sc::element_type_edittext:
    1085             :             {
    1086           0 :                 sc::edittext_block::const_iterator itData = sc::edittext_block::begin(*it->data);
    1087           0 :                 std::advance(itData, nOffset);
    1088           0 :                 sc::edittext_block::const_iterator itDataEnd = itData;
    1089           0 :                 std::advance(itDataEnd, nDataSize);
    1090             : 
    1091             :                 // Convert to simple strings.
    1092           0 :                 std::vector<svl::SharedString> aConverted;
    1093           0 :                 aConverted.reserve(nDataSize);
    1094           0 :                 for (; itData != itDataEnd; ++itData)
    1095             :                 {
    1096           0 :                     const EditTextObject& rObj = **itData;
    1097           0 :                     svl::SharedString aSS = pDocument->GetSharedStringPool().intern(ScEditUtil::GetString(rObj, pDocument));
    1098           0 :                     aConverted.push_back(aSS);
    1099           0 :                 }
    1100           0 :                 aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nCurRow, aConverted.begin(), aConverted.end());
    1101             :             }
    1102           0 :             break;
    1103             :             case sc::element_type_formula:
    1104             :             {
    1105           2 :                 sc::formula_block::const_iterator itData = sc::formula_block::begin(*it->data);
    1106           2 :                 std::advance(itData, nOffset);
    1107           2 :                 sc::formula_block::const_iterator itDataEnd = itData;
    1108           2 :                 std::advance(itDataEnd, nDataSize);
    1109             : 
    1110             :                 // Interpret and convert to raw values.
    1111           4 :                 for (SCROW i = 0; itData != itDataEnd; ++itData, ++i)
    1112             :                 {
    1113           2 :                     SCROW nRow = nCurRow + i;
    1114             : 
    1115           2 :                     ScFormulaCell& rFC = const_cast<ScFormulaCell&>(**itData);
    1116           2 :                     if (rFC.GetDirty() && pDocument->GetAutoCalc())
    1117           0 :                         rFC.Interpret();
    1118             : 
    1119           2 :                     if (rFC.GetErrCode())
    1120             :                         // Skip cells with error.
    1121           0 :                         break;
    1122             : 
    1123           2 :                     if (rFC.IsValue())
    1124           2 :                         aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nRow, rFC.GetValue());
    1125             :                     else
    1126             :                     {
    1127           0 :                         svl::SharedString aSS = rFC.GetString();
    1128           0 :                         if (aSS.isValid())
    1129           0 :                             aDestPos.miCellPos = rDestCol.maCells.set(aDestPos.miCellPos, nRow, aSS);
    1130             :                     }
    1131             :                 }
    1132             :             }
    1133           2 :             break;
    1134             :             default:
    1135             :                 ;
    1136             :         }
    1137             : 
    1138          14 :         if (bLastBlock)
    1139           8 :             break;
    1140             :     }
    1141             : 
    1142             :     // Dont' forget to copy the number formats over.  Charts may reference them.
    1143          34 :     for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
    1144             :     {
    1145          22 :         sal_uInt32 nNumFmt = GetNumberFormat(nRow);
    1146          22 :         SvNumberFormatterMergeMap::const_iterator itNum = rMap.find(nNumFmt);
    1147          22 :         if (itNum != rMap.end())
    1148           6 :             nNumFmt = itNum->second;
    1149             : 
    1150          22 :         rDestCol.SetNumberFormat(nRow, nNumFmt);
    1151             :     }
    1152             : 
    1153          12 :     rDestCol.CellStorageModified();
    1154             : }
    1155             : 
    1156           2 : void ScColumn::CopyCellToDocument( SCROW nSrcRow, SCROW nDestRow, ScColumn& rDestCol )
    1157             : {
    1158           2 :     std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nSrcRow);
    1159           2 :     sc::CellStoreType::const_iterator it = aPos.first;
    1160           2 :     bool bSet = true;
    1161           2 :     switch (it->type)
    1162             :     {
    1163             :         case sc::element_type_numeric:
    1164           0 :             rDestCol.maCells.set(nDestRow, sc::numeric_block::at(*it->data, aPos.second));
    1165           0 :         break;
    1166             :         case sc::element_type_string:
    1167           2 :             rDestCol.maCells.set(nDestRow, sc::string_block::at(*it->data, aPos.second));
    1168           2 :         break;
    1169             :         case sc::element_type_edittext:
    1170             :         {
    1171           0 :             EditTextObject* p = sc::edittext_block::at(*it->data, aPos.second);
    1172           0 :             if (pDocument == rDestCol.pDocument)
    1173           0 :                 rDestCol.maCells.set(nDestRow, p->Clone());
    1174             :             else
    1175           0 :                 rDestCol.maCells.set(nDestRow, ScEditUtil::Clone(*p, *rDestCol.pDocument));
    1176             :         }
    1177           0 :         break;
    1178             :         case sc::element_type_formula:
    1179             :         {
    1180           0 :             ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
    1181           0 :             if (p->GetDirty() && pDocument->GetAutoCalc())
    1182           0 :                 p->Interpret();
    1183             : 
    1184           0 :             ScAddress aDestPos = p->aPos;
    1185           0 :             aDestPos.SetRow(nDestRow);
    1186           0 :             ScFormulaCell* pNew = new ScFormulaCell(*p, *rDestCol.pDocument, aDestPos);
    1187           0 :             rDestCol.SetFormulaCell(nDestRow, pNew);
    1188             :         }
    1189           0 :         break;
    1190             :         case sc::element_type_empty:
    1191             :         default:
    1192             :             // empty
    1193           0 :             rDestCol.maCells.set_empty(nDestRow, nDestRow);
    1194           0 :             bSet = false;
    1195             :     }
    1196             : 
    1197           2 :     if (bSet)
    1198             :     {
    1199           2 :         rDestCol.maCellTextAttrs.set(nDestRow, maCellTextAttrs.get<sc::CellTextAttr>(nSrcRow));
    1200           2 :         ScPostIt* pNote = maCellNotes.get<ScPostIt*>(nSrcRow);
    1201           2 :         rDestCol.maCellNotes.set(nDestRow, pNote);
    1202           2 :         if (pNote)
    1203           0 :             pNote->UpdateCaptionPos(ScAddress(rDestCol.nCol, nDestRow, rDestCol.nTab));
    1204             :     }
    1205             :     else
    1206             :     {
    1207           0 :         rDestCol.maCellTextAttrs.set_empty(nDestRow, nDestRow);
    1208           0 :         rDestCol.maCellNotes.set_empty(nDestRow, nDestRow);
    1209             :     }
    1210             : 
    1211           2 :     rDestCol.CellStorageModified();
    1212           2 : }
    1213             : 
    1214             : namespace {
    1215             : 
    1216        2656 : bool canCopyValue(const ScDocument& rDoc, const ScAddress& rPos, InsertDeleteFlags nFlags)
    1217             : {
    1218        2656 :     sal_uInt32 nNumIndex = static_cast<const SfxUInt32Item*>(rDoc.GetAttr(rPos, ATTR_VALUE_FORMAT))->GetValue();
    1219        2656 :     short nType = rDoc.GetFormatTable()->GetType(nNumIndex);
    1220        2656 :     if ((nType == NUMBERFORMAT_DATE) || (nType == NUMBERFORMAT_TIME) || (nType == NUMBERFORMAT_DATETIME))
    1221           0 :         return ((nFlags & IDF_DATETIME) != IDF_NONE);
    1222             : 
    1223        2656 :     return (nFlags & IDF_VALUE) != IDF_NONE;
    1224             : }
    1225             : 
    1226             : class CopyAsLinkHandler
    1227             : {
    1228             :     const ScColumn& mrSrcCol;
    1229             :     ScColumn& mrDestCol;
    1230             :     sc::ColumnBlockPosition maDestPos;
    1231             :     sc::ColumnBlockPosition* mpDestPos;
    1232             :     InsertDeleteFlags mnCopyFlags;
    1233             : 
    1234           0 :     void setDefaultAttrToDest(size_t nRow)
    1235             :     {
    1236           0 :         maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
    1237           0 :             maDestPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
    1238           0 :     }
    1239             : 
    1240           0 :     void setDefaultAttrsToDest(size_t nRow, size_t nSize)
    1241             :     {
    1242           0 :         std::vector<sc::CellTextAttr> aAttrs(nSize); // default values
    1243           0 :         maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
    1244           0 :             maDestPos.miCellTextAttrPos, nRow, aAttrs.begin(), aAttrs.end());
    1245           0 :     }
    1246             : 
    1247           0 :     ScFormulaCell* createRefCell(size_t nRow)
    1248             :     {
    1249             :         ScSingleRefData aRef;
    1250           0 :         aRef.InitAddress(ScAddress(mrSrcCol.GetCol(), nRow, mrSrcCol.GetTab())); // Absolute reference.
    1251           0 :         aRef.SetFlag3D(true);
    1252             : 
    1253           0 :         ScTokenArray aArr;
    1254           0 :         aArr.AddSingleReference(aRef);
    1255           0 :         return new ScFormulaCell(&mrDestCol.GetDoc(), ScAddress(mrDestCol.GetCol(), nRow, mrDestCol.GetTab()), aArr);
    1256             :     }
    1257             : 
    1258           0 :     void createRefBlock(const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
    1259             :     {
    1260           0 :         size_t nTopRow = aNode.position + nOffset;
    1261             : 
    1262           0 :         for (size_t i = 0; i < nDataSize; ++i)
    1263             :         {
    1264           0 :             SCROW nRow = nTopRow + i;
    1265           0 :             mrDestCol.SetFormulaCell(maDestPos, nRow, createRefCell(nRow));
    1266             :         }
    1267             : 
    1268           0 :         setDefaultAttrsToDest(nTopRow, nDataSize);
    1269           0 :     }
    1270             : 
    1271           0 :     void duplicateNotes(SCROW nStartRow, size_t nDataSize, bool bCloneCaption )
    1272             :     {
    1273           0 :         mrSrcCol.DuplicateNotes(nStartRow, nDataSize, mrDestCol, maDestPos, bCloneCaption);
    1274           0 :     }
    1275             : 
    1276             : public:
    1277           0 :     CopyAsLinkHandler(const ScColumn& rSrcCol, ScColumn& rDestCol, sc::ColumnBlockPosition* pDestPos, InsertDeleteFlags nCopyFlags) :
    1278           0 :         mrSrcCol(rSrcCol), mrDestCol(rDestCol), mpDestPos(pDestPos), mnCopyFlags(nCopyFlags)
    1279             :     {
    1280           0 :         if (mpDestPos)
    1281           0 :             maDestPos = *mpDestPos;
    1282           0 :     }
    1283             : 
    1284           0 :     ~CopyAsLinkHandler()
    1285             :     {
    1286           0 :         if (mpDestPos)
    1287           0 :             *mpDestPos = maDestPos;
    1288           0 :     }
    1289             : 
    1290           0 :     void operator() (const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
    1291             :     {
    1292           0 :         size_t nRow = aNode.position + nOffset;
    1293             : 
    1294           0 :         if (mnCopyFlags & (IDF_NOTE|IDF_ADDNOTES))
    1295             :         {
    1296           0 :             bool bCloneCaption = (mnCopyFlags & IDF_NOCAPTIONS) == IDF_NONE;
    1297           0 :             duplicateNotes(nRow, nDataSize, bCloneCaption );
    1298             :         }
    1299             : 
    1300           0 :         switch (aNode.type)
    1301             :         {
    1302             :             case sc::element_type_numeric:
    1303             :             {
    1304           0 :                 if ((mnCopyFlags & (IDF_DATETIME|IDF_VALUE)) == IDF_NONE)
    1305           0 :                     return;
    1306             : 
    1307           0 :                 sc::numeric_block::const_iterator it = sc::numeric_block::begin(*aNode.data);
    1308           0 :                 std::advance(it, nOffset);
    1309           0 :                 sc::numeric_block::const_iterator itEnd = it;
    1310           0 :                 std::advance(itEnd, nDataSize);
    1311             : 
    1312           0 :                 ScAddress aSrcPos(mrSrcCol.GetCol(), nRow, mrSrcCol.GetTab());
    1313           0 :                 for (; it != itEnd; ++it, aSrcPos.IncRow(), ++nRow)
    1314             :                 {
    1315           0 :                     if (!canCopyValue(mrSrcCol.GetDoc(), aSrcPos, mnCopyFlags))
    1316           0 :                         continue;
    1317             : 
    1318           0 :                     maDestPos.miCellPos = mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, createRefCell(nRow));
    1319           0 :                     setDefaultAttrToDest(nRow);
    1320             :                 }
    1321             :             }
    1322           0 :             break;
    1323             :             case sc::element_type_string:
    1324             :             case sc::element_type_edittext:
    1325             :             {
    1326           0 :                 if (!(mnCopyFlags & IDF_STRING))
    1327           0 :                     return;
    1328             : 
    1329           0 :                 createRefBlock(aNode, nOffset, nDataSize);
    1330             :             }
    1331           0 :             break;
    1332             :             case sc::element_type_formula:
    1333             :             {
    1334           0 :                 if (!(mnCopyFlags & IDF_FORMULA))
    1335           0 :                     return;
    1336             : 
    1337           0 :                 createRefBlock(aNode, nOffset, nDataSize);
    1338             :             }
    1339           0 :             break;
    1340             :             default:
    1341             :                 ;
    1342             :         }
    1343             :     }
    1344             : };
    1345             : 
    1346             : class CopyByCloneHandler
    1347             : {
    1348             :     const ScColumn& mrSrcCol;
    1349             :     ScColumn& mrDestCol;
    1350             :     sc::ColumnBlockPosition maDestPos;
    1351             :     sc::ColumnBlockPosition* mpDestPos;
    1352             :     svl::SharedStringPool* mpSharedStringPool;
    1353             :     InsertDeleteFlags mnCopyFlags;
    1354             : 
    1355        5272 :     void setDefaultAttrToDest(size_t nRow)
    1356             :     {
    1357       10544 :         maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
    1358        5272 :             maDestPos.miCellTextAttrPos, nRow, sc::CellTextAttr());
    1359        5272 :     }
    1360             : 
    1361           8 :     void setDefaultAttrsToDest(size_t nRow, size_t nSize)
    1362             :     {
    1363           8 :         std::vector<sc::CellTextAttr> aAttrs(nSize); // default values
    1364          16 :         maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set(
    1365          16 :             maDestPos.miCellTextAttrPos, nRow, aAttrs.begin(), aAttrs.end());
    1366           8 :     }
    1367             : 
    1368         500 :     void cloneFormulaCell(size_t nRow, ScFormulaCell& rSrcCell)
    1369             :     {
    1370         500 :         ScAddress aDestPos(mrDestCol.GetCol(), nRow, mrDestCol.GetTab());
    1371             : 
    1372         500 :         bool bCloneValue          = (mnCopyFlags & IDF_VALUE) != IDF_NONE;
    1373         500 :         bool bCloneDateTime       = (mnCopyFlags & IDF_DATETIME) != IDF_NONE;
    1374         500 :         bool bCloneString         = (mnCopyFlags & IDF_STRING) != IDF_NONE;
    1375         500 :         bool bCloneSpecialBoolean = (mnCopyFlags & IDF_SPECIAL_BOOLEAN) != IDF_NONE;
    1376         500 :         bool bCloneFormula        = (mnCopyFlags & IDF_FORMULA) != IDF_NONE;
    1377             : 
    1378         500 :         bool bForceFormula = false;
    1379             : 
    1380         500 :         if (bCloneSpecialBoolean)
    1381             :         {
    1382             :             // See if the formula consists of =TRUE() or =FALSE().
    1383           0 :             ScTokenArray* pCode = rSrcCell.GetCode();
    1384           0 :             if (pCode && pCode->GetLen() == 1)
    1385             :             {
    1386           0 :                 const formula::FormulaToken* p = pCode->First();
    1387           0 :                 if (p->GetOpCode() == ocTrue || p->GetOpCode() == ocFalse)
    1388             :                     // This is a boolean formula.
    1389           0 :                     bForceFormula = true;
    1390             :             }
    1391             :         }
    1392             : 
    1393         500 :         if (bForceFormula || bCloneFormula)
    1394             :         {
    1395             :             // Clone as formula cell.
    1396         500 :             ScFormulaCell* pCell = new ScFormulaCell(rSrcCell, mrDestCol.GetDoc(), aDestPos);
    1397         500 :             pCell->SetDirtyVar();
    1398         500 :             mrDestCol.SetFormulaCell(maDestPos, nRow, pCell);
    1399         500 :             setDefaultAttrToDest(nRow);
    1400        1000 :             return;
    1401             :         }
    1402             : 
    1403           0 :         if (mrDestCol.GetDoc().IsUndo())
    1404           0 :             return;
    1405             : 
    1406           0 :         if (bCloneValue)
    1407             :         {
    1408           0 :             sal_uInt16 nErr = rSrcCell.GetErrCode();
    1409           0 :             if (nErr)
    1410             :             {
    1411             :                 // error codes are cloned with values
    1412           0 :                 ScFormulaCell* pErrCell = new ScFormulaCell(&mrDestCol.GetDoc(), aDestPos);
    1413           0 :                 pErrCell->SetErrCode(nErr);
    1414           0 :                 mrDestCol.SetFormulaCell(maDestPos, nRow, pErrCell);
    1415           0 :                 setDefaultAttrToDest(nRow);
    1416           0 :                 return;
    1417             :             }
    1418             :         }
    1419             : 
    1420           0 :         if (bCloneValue || bCloneDateTime)
    1421             :         {
    1422           0 :             if (rSrcCell.IsValue())
    1423             :             {
    1424           0 :                 if (canCopyValue(mrSrcCol.GetDoc(), ScAddress(mrSrcCol.GetCol(), nRow, mrSrcCol.GetTab()), mnCopyFlags))
    1425             :                 {
    1426           0 :                     maDestPos.miCellPos = mrDestCol.GetCellStore().set(
    1427           0 :                         maDestPos.miCellPos, nRow, rSrcCell.GetValue());
    1428           0 :                     setDefaultAttrToDest(nRow);
    1429             :                 }
    1430             : 
    1431           0 :                 return;
    1432             :             }
    1433             :         }
    1434             : 
    1435           0 :         if (bCloneString)
    1436             :         {
    1437           0 :             svl::SharedString aStr = rSrcCell.GetString();
    1438           0 :             if (aStr.isEmpty())
    1439             :                 // Don't create empty string cells.
    1440           0 :                 return;
    1441             : 
    1442           0 :             if (rSrcCell.IsMultilineResult())
    1443             :             {
    1444             :                 // Clone as an edit text object.
    1445           0 :                 EditEngine& rEngine = mrDestCol.GetDoc().GetEditEngine();
    1446           0 :                 rEngine.SetText(aStr.getString());
    1447           0 :                 maDestPos.miCellPos =
    1448           0 :                     mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, rEngine.CreateTextObject());
    1449             :             }
    1450             :             else
    1451             :             {
    1452           0 :                 maDestPos.miCellPos =
    1453           0 :                     mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, aStr);
    1454             :             }
    1455             : 
    1456           0 :             setDefaultAttrToDest(nRow);
    1457             :         }
    1458             :     }
    1459             : 
    1460      172544 :     void duplicateNotes(SCROW nStartRow, size_t nDataSize, bool bCloneCaption )
    1461             :     {
    1462      172544 :         mrSrcCol.DuplicateNotes(nStartRow, nDataSize, mrDestCol, maDestPos, bCloneCaption);
    1463      172544 :     }
    1464             : 
    1465             : public:
    1466      362890 :     CopyByCloneHandler(const ScColumn& rSrcCol, ScColumn& rDestCol, sc::ColumnBlockPosition* pDestPos,
    1467             :             InsertDeleteFlags nCopyFlags, svl::SharedStringPool* pSharedStringPool) :
    1468             :         mrSrcCol(rSrcCol), mrDestCol(rDestCol), mpDestPos(pDestPos), mpSharedStringPool(pSharedStringPool),
    1469      362890 :         mnCopyFlags(nCopyFlags)
    1470             :     {
    1471      362890 :         if (mpDestPos)
    1472      362890 :             maDestPos = *mpDestPos;
    1473      362890 :     }
    1474             : 
    1475      362890 :     ~CopyByCloneHandler()
    1476             :     {
    1477      362890 :         if (mpDestPos)
    1478      362890 :             *mpDestPos = maDestPos;
    1479      362890 :     }
    1480             : 
    1481      366696 :     void operator() (const sc::CellStoreType::value_type& aNode, size_t nOffset, size_t nDataSize)
    1482             :     {
    1483      366696 :         size_t nRow = aNode.position + nOffset;
    1484             : 
    1485      366696 :         if (mnCopyFlags & (IDF_NOTE|IDF_ADDNOTES))
    1486             :         {
    1487      172544 :             bool bCloneCaption = (mnCopyFlags & IDF_NOCAPTIONS) == IDF_NONE;
    1488      172544 :             duplicateNotes(nRow, nDataSize, bCloneCaption );
    1489             :         }
    1490             : 
    1491      366696 :         switch (aNode.type)
    1492             :         {
    1493             :             case sc::element_type_numeric:
    1494             :             {
    1495        1728 :                 if ((mnCopyFlags & (IDF_DATETIME|IDF_VALUE)) == IDF_NONE)
    1496         296 :                     return;
    1497             : 
    1498        1432 :                 sc::numeric_block::const_iterator it = sc::numeric_block::begin(*aNode.data);
    1499        1432 :                 std::advance(it, nOffset);
    1500        1432 :                 sc::numeric_block::const_iterator itEnd = it;
    1501        1432 :                 std::advance(itEnd, nDataSize);
    1502             : 
    1503        1432 :                 ScAddress aSrcPos(mrSrcCol.GetCol(), nRow, mrSrcCol.GetTab());
    1504        4088 :                 for (; it != itEnd; ++it, aSrcPos.IncRow(), ++nRow)
    1505             :                 {
    1506        2656 :                     if (!canCopyValue(mrSrcCol.GetDoc(), aSrcPos, mnCopyFlags))
    1507           0 :                         continue;
    1508             : 
    1509        2656 :                     maDestPos.miCellPos = mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, *it);
    1510        2656 :                     setDefaultAttrToDest(nRow);
    1511             :                 }
    1512             :             }
    1513        1432 :             break;
    1514             :             case sc::element_type_string:
    1515             :             {
    1516        1152 :                 if (!(mnCopyFlags & IDF_STRING))
    1517         204 :                     return;
    1518             : 
    1519         948 :                 sc::string_block::const_iterator it = sc::string_block::begin(*aNode.data);
    1520         948 :                 std::advance(it, nOffset);
    1521         948 :                 sc::string_block::const_iterator itEnd = it;
    1522         948 :                 std::advance(itEnd, nDataSize);
    1523             : 
    1524        3064 :                 for (; it != itEnd; ++it, ++nRow)
    1525             :                 {
    1526        2116 :                     const svl::SharedString& rStr = *it;
    1527        2116 :                     if (rStr.isEmpty())
    1528             :                     {
    1529             :                         // String cell with empty value is used to special-case cell value removal.
    1530           0 :                         maDestPos.miCellPos = mrDestCol.GetCellStore().set_empty(
    1531           0 :                             maDestPos.miCellPos, nRow, nRow);
    1532           0 :                         maDestPos.miCellTextAttrPos = mrDestCol.GetCellAttrStore().set_empty(
    1533           0 :                             maDestPos.miCellTextAttrPos, nRow, nRow);
    1534             :                     }
    1535             :                     else
    1536             :                     {
    1537        2116 :                         if (mpSharedStringPool)
    1538             :                         {
    1539             :                             // Re-intern the string if source is a different document.
    1540         104 :                             svl::SharedString aInterned = mpSharedStringPool->intern( rStr.getString());
    1541         312 :                             maDestPos.miCellPos =
    1542         312 :                                 mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, aInterned);
    1543             :                         }
    1544             :                         else
    1545             :                         {
    1546        6036 :                             maDestPos.miCellPos =
    1547        4024 :                                 mrDestCol.GetCellStore().set(maDestPos.miCellPos, nRow, rStr);
    1548             :                         }
    1549        2116 :                         setDefaultAttrToDest(nRow);
    1550             :                     }
    1551             :                 }
    1552             :             }
    1553         948 :             break;
    1554             :             case sc::element_type_edittext:
    1555             :             {
    1556           8 :                 if (!(mnCopyFlags & IDF_STRING))
    1557           0 :                     return;
    1558             : 
    1559           8 :                 sc::edittext_block::const_iterator it = sc::edittext_block::begin(*aNode.data);
    1560           8 :                 std::advance(it, nOffset);
    1561           8 :                 sc::edittext_block::const_iterator itEnd = it;
    1562           8 :                 std::advance(itEnd, nDataSize);
    1563             : 
    1564           8 :                 std::vector<EditTextObject*> aCloned;
    1565           8 :                 aCloned.reserve(nDataSize);
    1566          24 :                 for (; it != itEnd; ++it)
    1567          16 :                     aCloned.push_back(ScEditUtil::Clone(**it, mrDestCol.GetDoc()));
    1568             : 
    1569          16 :                 maDestPos.miCellPos = mrDestCol.GetCellStore().set(
    1570           8 :                     maDestPos.miCellPos, nRow, aCloned.begin(), aCloned.end());
    1571             : 
    1572           8 :                 setDefaultAttrsToDest(nRow, nDataSize);
    1573             :             }
    1574           8 :             break;
    1575             :             case sc::element_type_formula:
    1576             :             {
    1577         304 :                 sc::formula_block::const_iterator it = sc::formula_block::begin(*aNode.data);
    1578         304 :                 std::advance(it, nOffset);
    1579         304 :                 sc::formula_block::const_iterator itEnd = it;
    1580         304 :                 std::advance(itEnd, nDataSize);
    1581             : 
    1582         804 :                 for (; it != itEnd; ++it, ++nRow)
    1583         500 :                     cloneFormulaCell(nRow, const_cast<ScFormulaCell&>(**it));
    1584             :             }
    1585         304 :             break;
    1586             :             default:
    1587             :                 ;
    1588             :         }
    1589             :     }
    1590             : };
    1591             : 
    1592             : }
    1593             : 
    1594      368958 : void ScColumn::CopyToColumn(
    1595             :     sc::CopyToDocContext& rCxt,
    1596             :     SCROW nRow1, SCROW nRow2, InsertDeleteFlags nFlags, bool bMarked, ScColumn& rColumn,
    1597             :     const ScMarkData* pMarkData, bool bAsLink) const
    1598             : {
    1599      368958 :     if (bMarked)
    1600             :     {
    1601             :         SCROW nStart, nEnd;
    1602        2924 :         if (pMarkData && pMarkData->IsMultiMarked())
    1603             :         {
    1604        2924 :             ScMarkArrayIter aIter( pMarkData->GetArray()+nCol );
    1605             : 
    1606        6752 :             while ( aIter.Next( nStart, nEnd ) && nStart <= nRow2 )
    1607             :             {
    1608         904 :                 if ( nEnd >= nRow1 )
    1609        1808 :                     CopyToColumn(rCxt, std::max(nRow1,nStart), std::min(nRow2,nEnd),
    1610        2712 :                                     nFlags, false, rColumn, pMarkData, bAsLink );
    1611        2924 :             }
    1612             :         }
    1613             :         else
    1614             :         {
    1615             :             OSL_FAIL("CopyToColumn: bMarked, but no mark");
    1616             :         }
    1617      371882 :         return;
    1618             :     }
    1619             : 
    1620      366034 :     if ( (nFlags & IDF_ATTRIB) != IDF_NONE )
    1621             :     {
    1622      180930 :         if ( (nFlags & IDF_STYLES) != IDF_STYLES )
    1623             :         {   // keep the StyleSheets in the target document
    1624             :             // e.g. DIF and RTF Clipboard-Import
    1625           0 :             for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ )
    1626             :             {
    1627             :                 const ScStyleSheet* pStyle =
    1628           0 :                     rColumn.pAttrArray->GetPattern( nRow )->GetStyleSheet();
    1629           0 :                 const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
    1630           0 :                 boost::scoped_ptr<ScPatternAttr> pNewPattern(new ScPatternAttr( *pPattern ));
    1631           0 :                 pNewPattern->SetStyleSheet( (ScStyleSheet*)pStyle );
    1632           0 :                 rColumn.pAttrArray->SetPattern( nRow, pNewPattern.get(), true );
    1633           0 :             }
    1634             :         }
    1635             :         else
    1636      180930 :             pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray);
    1637             :     }
    1638             : 
    1639      366034 :     if ((nFlags & IDF_CONTENTS) != IDF_NONE)
    1640             :     {
    1641      362890 :         if (bAsLink)
    1642             :         {
    1643           0 :             CopyAsLinkHandler aFunc(*this, rColumn, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol), nFlags);
    1644           0 :             sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
    1645             :         }
    1646             :         else
    1647             :         {
    1648             :             // Compare the ScDocumentPool* to determine if we are copying
    1649             :             // within the same document. If not, re-intern shared strings.
    1650             :             svl::SharedStringPool* pSharedStringPool =
    1651      362890 :                 (pDocument->GetPool() != rColumn.pDocument->GetPool()) ?
    1652      362890 :                 &rColumn.pDocument->GetSharedStringPool() : NULL;
    1653             :             CopyByCloneHandler aFunc(*this, rColumn, rCxt.getBlockPosition(rColumn.nTab, rColumn.nCol), nFlags,
    1654      362890 :                     pSharedStringPool);
    1655      362890 :             sc::ParseBlock(maCells.begin(), maCells, aFunc, nRow1, nRow2);
    1656             :         }
    1657             : 
    1658      362890 :         rColumn.CellStorageModified();
    1659             :     }
    1660             : }
    1661             : 
    1662          32 : void ScColumn::UndoToColumn(
    1663             :     sc::CopyToDocContext& rCxt, SCROW nRow1, SCROW nRow2, InsertDeleteFlags nFlags, bool bMarked,
    1664             :     ScColumn& rColumn, const ScMarkData* pMarkData ) const
    1665             : {
    1666          32 :     if (nRow1 > 0)
    1667          14 :         CopyToColumn(rCxt, 0, nRow1-1, IDF_FORMULA, false, rColumn);
    1668             : 
    1669          32 :     CopyToColumn(rCxt, nRow1, nRow2, nFlags, bMarked, rColumn, pMarkData);      //! bMarked ????
    1670             : 
    1671          32 :     if (nRow2 < MAXROW)
    1672          32 :         CopyToColumn(rCxt, nRow2+1, MAXROW, IDF_FORMULA, false, rColumn);
    1673          32 : }
    1674             : 
    1675           0 : void ScColumn::CopyUpdated( const ScColumn& rPosCol, ScColumn& rDestCol ) const
    1676             : {
    1677             :     // Copy cells from this column to the destination column only for those
    1678             :     // rows that are present in the position column (rPosCol).
    1679             : 
    1680             :     // First, mark all the non-empty cell ranges from the position column.
    1681           0 :     sc::SingleColumnSpanSet aRangeSet;
    1682           0 :     aRangeSet.scan(rPosCol);
    1683             : 
    1684             :     // Now, copy cells from this column to the destination column for those
    1685             :     // marked row ranges.
    1686           0 :     sc::SingleColumnSpanSet::SpansType aRanges;
    1687           0 :     aRangeSet.getSpans(aRanges);
    1688             : 
    1689           0 :     bool bCopyNotes = true;
    1690           0 :     CopyToClipHandler aFunc(*this, rDestCol, NULL, bCopyNotes);
    1691           0 :     sc::CellStoreType::const_iterator itPos = maCells.begin();
    1692           0 :     sc::SingleColumnSpanSet::SpansType::const_iterator it = aRanges.begin(), itEnd = aRanges.end();
    1693           0 :     for (; it != itEnd; ++it)
    1694           0 :         itPos = sc::ParseBlock(itPos, maCells, aFunc, it->mnRow1, it->mnRow2);
    1695             : 
    1696           0 :     rDestCol.CellStorageModified();
    1697           0 : }
    1698             : 
    1699           0 : void ScColumn::CopyScenarioFrom( const ScColumn& rSrcCol )
    1700             : {
    1701             :     //  This is the scenario table, the data is copied into it
    1702           0 :     ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
    1703           0 :     SCROW nStart = -1, nEnd = -1;
    1704           0 :     const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
    1705           0 :     while (pPattern)
    1706             :     {
    1707           0 :         if ( static_cast<const ScMergeFlagAttr&>(pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
    1708             :         {
    1709           0 :             DeleteArea( nStart, nEnd, IDF_CONTENTS );
    1710           0 :             sc::CopyToDocContext aCxt(*pDocument);
    1711             :             ((ScColumn&)rSrcCol).
    1712           0 :                 CopyToColumn(aCxt, nStart, nEnd, IDF_CONTENTS, false, *this);
    1713             : 
    1714             :             //  UpdateUsed not needed, already done in TestCopyScenario (obsolete comment ?)
    1715             : 
    1716           0 :             sc::RefUpdateContext aRefCxt(*pDocument);
    1717           0 :             aRefCxt.meMode = URM_COPY;
    1718           0 :             aRefCxt.maRange = ScRange(nCol, nStart, nTab, nCol, nEnd, nTab);
    1719           0 :             aRefCxt.mnTabDelta = nTab - rSrcCol.nTab;
    1720           0 :             UpdateReferenceOnCopy(aRefCxt, NULL);
    1721           0 :             UpdateCompile();
    1722             :         }
    1723             : 
    1724             :         //! make CopyToColumn "const" !!! (obsolete comment ?)
    1725             : 
    1726           0 :         pPattern = aAttrIter.Next( nStart, nEnd );
    1727             :     }
    1728           0 : }
    1729             : 
    1730           0 : void ScColumn::CopyScenarioTo( ScColumn& rDestCol ) const
    1731             : {
    1732             :     //  This is the scenario table, the data is copied to the other
    1733           0 :     ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
    1734           0 :     SCROW nStart = -1, nEnd = -1;
    1735           0 :     const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
    1736           0 :     while (pPattern)
    1737             :     {
    1738           0 :         if ( static_cast<const ScMergeFlagAttr&>(pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
    1739             :         {
    1740           0 :             rDestCol.DeleteArea( nStart, nEnd, IDF_CONTENTS );
    1741           0 :             sc::CopyToDocContext aCxt(*rDestCol.pDocument);
    1742           0 :             CopyToColumn(aCxt, nStart, nEnd, IDF_CONTENTS, false, rDestCol);
    1743             : 
    1744             :             //  UpdateUsed not needed, is already done in TestCopyScenario (obsolete comment ?)
    1745             : 
    1746           0 :             sc::RefUpdateContext aRefCxt(*pDocument);
    1747           0 :             aRefCxt.meMode = URM_COPY;
    1748           0 :             aRefCxt.maRange = ScRange(rDestCol.nCol, nStart, rDestCol.nTab, rDestCol.nCol, nEnd, rDestCol.nTab);
    1749           0 :             aRefCxt.mnTabDelta = rDestCol.nTab - nTab;
    1750           0 :             rDestCol.UpdateReferenceOnCopy(aRefCxt, NULL);
    1751           0 :             rDestCol.UpdateCompile();
    1752             :         }
    1753             : 
    1754             :         //! make CopyToColumn "const" !!! (obsolete comment ?)
    1755             : 
    1756           0 :         pPattern = aAttrIter.Next( nStart, nEnd );
    1757             :     }
    1758           0 : }
    1759             : 
    1760           0 : bool ScColumn::TestCopyScenarioTo( const ScColumn& rDestCol ) const
    1761             : {
    1762           0 :     bool bOk = true;
    1763           0 :     ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
    1764           0 :     SCROW nStart = 0, nEnd = 0;
    1765           0 :     const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
    1766           0 :     while (pPattern && bOk)
    1767             :     {
    1768           0 :         if ( static_cast<const ScMergeFlagAttr&>(pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
    1769           0 :             if ( rDestCol.pAttrArray->HasAttrib( nStart, nEnd, HASATTR_PROTECTED ) )
    1770           0 :                 bOk = false;
    1771             : 
    1772           0 :         pPattern = aAttrIter.Next( nStart, nEnd );
    1773             :     }
    1774           0 :     return bOk;
    1775             : }
    1776             : 
    1777        2048 : void ScColumn::MarkScenarioIn( ScMarkData& rDestMark ) const
    1778             : {
    1779        2048 :     ScRange aRange( nCol, 0, nTab );
    1780             : 
    1781        2048 :     ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
    1782        2048 :     SCROW nStart = -1, nEnd = -1;
    1783        2048 :     const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
    1784        6172 :     while (pPattern)
    1785             :     {
    1786        2076 :         if ( static_cast<const ScMergeFlagAttr&>(pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
    1787             :         {
    1788          28 :             aRange.aStart.SetRow( nStart );
    1789          28 :             aRange.aEnd.SetRow( nEnd );
    1790          28 :             rDestMark.SetMultiMarkArea( aRange, true );
    1791             :         }
    1792             : 
    1793        2076 :         pPattern = aAttrIter.Next( nStart, nEnd );
    1794             :     }
    1795        2048 : }
    1796             : 
    1797             : namespace {
    1798             : 
    1799      318508 : void resetColumnPosition(sc::CellStoreType& rCells, SCCOL nCol)
    1800             : {
    1801      318508 :     sc::CellStoreType::iterator it = rCells.begin(), itEnd = rCells.end();
    1802      637348 :     for (; it != itEnd; ++it)
    1803             :     {
    1804      318840 :         if (it->type != sc::element_type_formula)
    1805      318742 :             continue;
    1806             : 
    1807          98 :         sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
    1808          98 :         sc::formula_block::iterator itCellEnd = sc::formula_block::end(*it->data);
    1809         230 :         for (; itCell != itCellEnd; ++itCell)
    1810             :         {
    1811         132 :             ScFormulaCell& rCell = **itCell;
    1812         132 :             rCell.aPos.SetCol(nCol);
    1813             :         }
    1814             :     }
    1815      318508 : }
    1816             : 
    1817             : class NoteCaptionUpdater
    1818             : {
    1819             :     SCCOL mnCol;
    1820             :     SCTAB mnTab;
    1821             : public:
    1822      347210 :     NoteCaptionUpdater( SCCOL nCol, SCTAB nTab ) : mnCol(nCol), mnTab(nTab) {}
    1823             : 
    1824           6 :     void operator() ( size_t nRow, ScPostIt* p )
    1825             :     {
    1826           6 :         p->UpdateCaptionPos(ScAddress(mnCol,nRow,mnTab));
    1827           6 :     }
    1828             : };
    1829             : 
    1830             : }
    1831             : 
    1832      347210 : void ScColumn::UpdateNoteCaptions( SCROW nRow1, SCROW nRow2 )
    1833             : {
    1834      347210 :     NoteCaptionUpdater aFunc(nCol, nTab);
    1835      347210 :     sc::ProcessNote(maCellNotes.begin(), maCellNotes, nRow1, nRow2, aFunc);
    1836      347210 : }
    1837             : 
    1838      159254 : void ScColumn::SwapCol(ScColumn& rCol)
    1839             : {
    1840      159254 :     maBroadcasters.swap(rCol.maBroadcasters);
    1841      159254 :     maCells.swap(rCol.maCells);
    1842      159254 :     maCellTextAttrs.swap(rCol.maCellTextAttrs);
    1843      159254 :     maCellNotes.swap(rCol.maCellNotes);
    1844             : 
    1845             :     // notes update caption
    1846      159254 :     UpdateNoteCaptions(0, MAXROW);
    1847      159254 :     rCol.UpdateNoteCaptions(0, MAXROW);
    1848             : 
    1849      159254 :     ScAttrArray* pTempAttr = rCol.pAttrArray;
    1850      159254 :     rCol.pAttrArray = pAttrArray;
    1851      159254 :     pAttrArray = pTempAttr;
    1852             : 
    1853             :     // AttrArray needs to have the right column number
    1854      159254 :     pAttrArray->SetCol(nCol);
    1855      159254 :     rCol.pAttrArray->SetCol(rCol.nCol);
    1856             : 
    1857      159254 :     std::swap(mbDirtyGroups, rCol.mbDirtyGroups);
    1858             : 
    1859             :     // Reset column positions in formula cells.
    1860      159254 :     resetColumnPosition(maCells, nCol);
    1861      159254 :     resetColumnPosition(rCol.maCells, rCol.nCol);
    1862             : 
    1863      159254 :     CellStorageModified();
    1864      159254 :     rCol.CellStorageModified();
    1865      159254 : }
    1866             : 
    1867       26488 : void ScColumn::MoveTo(SCROW nStartRow, SCROW nEndRow, ScColumn& rCol)
    1868             : {
    1869       26488 :     pAttrArray->MoveTo(nStartRow, nEndRow, *rCol.pAttrArray);
    1870             : 
    1871             :     // Mark the non-empty cells within the specified range, for later broadcasting.
    1872       26488 :     sc::SingleColumnSpanSet aNonEmpties;
    1873       26488 :     aNonEmpties.scan(*this, nStartRow, nEndRow);
    1874       52976 :     sc::SingleColumnSpanSet::SpansType aRanges;
    1875       26488 :     aNonEmpties.getSpans(aRanges);
    1876             : 
    1877             :     // Split the formula grouping at the top and bottom boundaries.
    1878       26488 :     sc::CellStoreType::position_type aPos = maCells.position(nStartRow);
    1879       26488 :     sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
    1880       26488 :     aPos = maCells.position(aPos.first, nEndRow+1);
    1881       26488 :     sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
    1882             : 
    1883             :     // Do the same with the destination column.
    1884       26488 :     aPos = rCol.maCells.position(nStartRow);
    1885       26488 :     sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
    1886       26488 :     aPos = rCol.maCells.position(aPos.first, nEndRow+1);
    1887       26488 :     sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
    1888             : 
    1889             :     // Move the broadcasters to the destination column.
    1890       26488 :     maBroadcasters.transfer(nStartRow, nEndRow, rCol.maBroadcasters, nStartRow);
    1891       26488 :     maCells.transfer(nStartRow, nEndRow, rCol.maCells, nStartRow);
    1892       26488 :     maCellTextAttrs.transfer(nStartRow, nEndRow, rCol.maCellTextAttrs, nStartRow);
    1893             : 
    1894             :     // move the notes to the destination column
    1895       26488 :     maCellNotes.transfer(nStartRow, nEndRow, rCol.maCellNotes, nStartRow);
    1896       26488 :     UpdateNoteCaptions(0, MAXROW);
    1897             : 
    1898             :     // Re-group transferred formula cells.
    1899       26488 :     aPos = rCol.maCells.position(nStartRow);
    1900       26488 :     sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
    1901       26488 :     aPos = rCol.maCells.position(aPos.first, nEndRow+1);
    1902       26488 :     sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
    1903             : 
    1904       26488 :     CellStorageModified();
    1905       26488 :     rCol.CellStorageModified();
    1906             : 
    1907             :     // Broadcast on moved ranges. Area-broadcast only.
    1908       52976 :     ScHint aHint(SC_HINT_DATACHANGED, ScAddress(nCol, 0, nTab));
    1909       26488 :     ScAddress& rPos = aHint.GetAddress();
    1910       26488 :     sc::SingleColumnSpanSet::SpansType::const_iterator itRange = aRanges.begin(), itRangeEnd = aRanges.end();
    1911       26510 :     for (; itRange != itRangeEnd; ++itRange)
    1912             :     {
    1913          48 :         for (SCROW nRow = itRange->mnRow1; nRow <= itRange->mnRow2; ++nRow)
    1914             :         {
    1915          26 :             rPos.SetRow(nRow);
    1916          26 :             pDocument->AreaBroadcast(aHint);
    1917             :         }
    1918       26488 :     }
    1919       26488 : }
    1920             : 
    1921             : namespace {
    1922             : 
    1923             : class SubTotalCellPicker
    1924             : {
    1925             :     sc::ColumnSpanSet& mrSet;
    1926             :     SCTAB mnTab;
    1927             :     SCCOL mnCol;
    1928             :     bool mbVal;
    1929             : public:
    1930           0 :     SubTotalCellPicker(sc::ColumnSpanSet& rSet, SCTAB nTab, SCCOL nCol, bool bVal) :
    1931           0 :         mrSet(rSet), mnTab(nTab), mnCol(nCol), mbVal(bVal) {}
    1932             : 
    1933           0 :     void operator() (size_t nRow, const ScFormulaCell* pCell)
    1934             :     {
    1935           0 :         if (pCell->IsSubTotal())
    1936           0 :             mrSet.set(mnTab, mnCol, nRow, mbVal);
    1937           0 :     }
    1938             : };
    1939             : 
    1940             : }
    1941             : 
    1942           0 : void ScColumn::MarkSubTotalCells( sc::ColumnSpanSet& rSet, SCROW nRow1, SCROW nRow2, bool bVal ) const
    1943             : {
    1944           0 :     SubTotalCellPicker aFunc(rSet, nTab, nCol, bVal);
    1945           0 :     sc::ParseFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
    1946           0 : }
    1947             : 
    1948             : namespace {
    1949             : 
    1950      667502 : class SharedTopFormulaCellPicker : std::unary_function<sc::CellStoreType::value_type, void>
    1951             : {
    1952             : public:
    1953      667502 :     virtual ~SharedTopFormulaCellPicker() {}
    1954             : 
    1955      337992 :     void operator() ( sc::CellStoreType::value_type& node )
    1956             :     {
    1957      337992 :         if (node.type != sc::element_type_formula)
    1958      675280 :             return;
    1959             : 
    1960         704 :         size_t nTopRow = node.position;
    1961             : 
    1962         704 :         sc::formula_block::iterator itBeg = sc::formula_block::begin(*node.data);
    1963         704 :         sc::formula_block::iterator itEnd = sc::formula_block::end(*node.data);
    1964             : 
    1965             :         // Only pick shared formula cells that are the top cells of their
    1966             :         // respective shared ranges.
    1967        1724 :         for (sc::formula_block::iterator it = itBeg; it != itEnd; ++it)
    1968             :         {
    1969        1020 :             ScFormulaCell* pCell = *it;
    1970        1020 :             size_t nRow = nTopRow + std::distance(itBeg, it);
    1971        1020 :             if (!pCell->IsShared())
    1972             :             {
    1973         816 :                 processNonShared(pCell, nRow);
    1974         816 :                 continue;
    1975             :             }
    1976             : 
    1977         204 :             if (pCell->IsSharedTop())
    1978             :             {
    1979         204 :                 ScFormulaCell** pp = &(*it);
    1980         204 :                 processSharedTop(pp, nRow, pCell->GetSharedLength());
    1981             : 
    1982             :                 // Move to the last cell in the group, to get incremented to
    1983             :                 // the next cell in the next iteration.
    1984         204 :                 size_t nOffsetToLast = pCell->GetSharedLength() - 1;
    1985         204 :                 std::advance(it, nOffsetToLast);
    1986             :             }
    1987             :         }
    1988             :     }
    1989             : 
    1990         374 :     virtual void processNonShared( ScFormulaCell* /*pCell*/, size_t /*nRow*/ ) {}
    1991           0 :     virtual void processSharedTop( ScFormulaCell** /*ppCells*/, size_t /*nRow*/, size_t /*nLength*/ ) {}
    1992             : };
    1993             : 
    1994             : class UpdateRefOnCopy
    1995             : {
    1996             :     const sc::RefUpdateContext& mrCxt;
    1997             :     ScDocument* mpUndoDoc;
    1998             :     bool mbUpdated;
    1999             : 
    2000             : public:
    2001       35038 :     UpdateRefOnCopy(const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc) :
    2002       35038 :         mrCxt(rCxt), mpUndoDoc(pUndoDoc), mbUpdated(false) {}
    2003             : 
    2004       35038 :     bool isUpdated() const { return mbUpdated; }
    2005             : 
    2006       35478 :     void operator() (sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
    2007             :     {
    2008       35478 :         if (node.type != sc::element_type_formula)
    2009       70836 :             return;
    2010             : 
    2011         120 :         sc::formula_block::iterator it = sc::formula_block::begin(*node.data);
    2012         120 :         std::advance(it, nOffset);
    2013         120 :         sc::formula_block::iterator itEnd = it;
    2014         120 :         std::advance(itEnd, nDataSize);
    2015             : 
    2016         276 :         for (; it != itEnd; ++it)
    2017             :         {
    2018         156 :             ScFormulaCell& rCell = **it;
    2019         156 :             mbUpdated |= rCell.UpdateReference(mrCxt, mpUndoDoc);
    2020             :         }
    2021             :     }
    2022             : };
    2023             : 
    2024             : class UpdateRefOnNonCopy : std::unary_function<sc::FormulaGroupEntry, void>
    2025             : {
    2026             :     SCCOL mnCol;
    2027             :     SCROW mnTab;
    2028             :     const sc::RefUpdateContext* mpCxt;
    2029             :     ScDocument* mpUndoDoc;
    2030             :     bool mbUpdated;
    2031             : 
    2032           4 :     void recompileTokenArray( ScFormulaCell& rTopCell )
    2033             :     {
    2034             :         // We need to re-compile the token array when a range name is
    2035             :         // modified, to correctly reflect the new references in the
    2036             :         // name.
    2037           4 :         ScCompiler aComp(&mpCxt->mrDoc, rTopCell.aPos, *rTopCell.GetCode());
    2038           4 :         aComp.SetGrammar(mpCxt->mrDoc.GetGrammar());
    2039           4 :         aComp.CompileTokenArray();
    2040           4 :     }
    2041             : 
    2042         432 :     void updateRefOnShift( sc::FormulaGroupEntry& rGroup )
    2043             :     {
    2044         432 :         if (!rGroup.mbShared)
    2045             :         {
    2046         348 :             ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab);
    2047         348 :             mbUpdated |= rGroup.mpCell->UpdateReferenceOnShift(*mpCxt, mpUndoDoc, &aUndoPos);
    2048         780 :             return;
    2049             :         }
    2050             : 
    2051             :         // Update references of a formula group.
    2052          84 :         ScFormulaCell** pp = rGroup.mpCells;
    2053          84 :         ScFormulaCell** ppEnd = pp + rGroup.mnLength;
    2054          84 :         ScFormulaCell* pTop = *pp;
    2055          84 :         ScTokenArray* pCode = pTop->GetCode();
    2056          84 :         boost::scoped_ptr<ScTokenArray> pOldCode(pCode->Clone());
    2057          84 :         ScAddress aOldPos = pTop->aPos;
    2058             : 
    2059             :         // Run this before the position gets updated.
    2060          84 :         sc::RefUpdateResult aRes = pCode->AdjustReferenceOnShift(*mpCxt, aOldPos);
    2061             : 
    2062          84 :         if (pTop->UpdatePosOnShift(*mpCxt))
    2063             :         {
    2064             :             // Update the positions of all formula cells.
    2065         132 :             for (++pp; pp != ppEnd; ++pp) // skip the top cell.
    2066             :             {
    2067          88 :                 ScFormulaCell* pFC = *pp;
    2068          88 :                 pFC->aPos.Move(mpCxt->mnColDelta, mpCxt->mnRowDelta, mpCxt->mnTabDelta);
    2069             :             }
    2070             : 
    2071          44 :             if (pCode->IsRecalcModeOnRefMove())
    2072           0 :                 aRes.mbValueChanged = true;
    2073             :         }
    2074          40 :         else if (aRes.mbReferenceModified && pCode->IsRecalcModeOnRefMove())
    2075             :         {
    2076             :             // The cell itself hasn't shifted. But it may have ROW or COLUMN
    2077             :             // referencing another cell that has.
    2078           2 :             aRes.mbValueChanged = true;
    2079             :         }
    2080             : 
    2081          84 :         if (aRes.mbNameModified)
    2082           2 :             recompileTokenArray(*pTop);
    2083             : 
    2084          84 :         if (aRes.mbReferenceModified || aRes.mbNameModified)
    2085             :         {
    2086          48 :             sc::StartListeningContext aStartCxt(mpCxt->mrDoc);
    2087          96 :             sc::EndListeningContext aEndCxt(mpCxt->mrDoc, pOldCode.get());
    2088             :             aEndCxt.setPositionDelta(
    2089          48 :                 ScAddress(-mpCxt->mnColDelta, -mpCxt->mnRowDelta, -mpCxt->mnTabDelta));
    2090             : 
    2091         188 :             for (pp = rGroup.mpCells; pp != ppEnd; ++pp)
    2092             :             {
    2093         140 :                 ScFormulaCell* p = *pp;
    2094         140 :                 p->EndListeningTo(aEndCxt);
    2095         140 :                 p->SetNeedsListening(true);
    2096             :             }
    2097             : 
    2098          48 :             mbUpdated = true;
    2099             : 
    2100          96 :             fillUndoDoc(aOldPos, rGroup.mnLength, *pOldCode);
    2101             :         }
    2102             : 
    2103          84 :         if (aRes.mbValueChanged)
    2104             :         {
    2105          60 :             for (pp = rGroup.mpCells; pp != ppEnd; ++pp)
    2106             :             {
    2107          40 :                 ScFormulaCell* p = *pp;
    2108          40 :                 p->SetNeedsDirty(true);
    2109             :             }
    2110          84 :         }
    2111             :     }
    2112             : 
    2113          68 :     void updateRefOnMove( sc::FormulaGroupEntry& rGroup )
    2114             :     {
    2115          68 :         if (!rGroup.mbShared)
    2116             :         {
    2117          58 :             ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab);
    2118          58 :             mbUpdated |= rGroup.mpCell->UpdateReferenceOnMove(*mpCxt, mpUndoDoc, &aUndoPos);
    2119         126 :             return;
    2120             :         }
    2121             : 
    2122             :         // Update references of a formula group.
    2123          10 :         ScFormulaCell** pp = rGroup.mpCells;
    2124          10 :         ScFormulaCell** ppEnd = pp + rGroup.mnLength;
    2125          10 :         ScFormulaCell* pTop = *pp;
    2126          10 :         ScTokenArray* pCode = pTop->GetCode();
    2127          10 :         boost::scoped_ptr<ScTokenArray> pOldCode(pCode->Clone());
    2128             : 
    2129          10 :         ScAddress aPos = pTop->aPos;
    2130          10 :         ScAddress aOldPos = aPos;
    2131             : 
    2132          10 :         if (mpCxt->maRange.In(aPos))
    2133             :         {
    2134             :             // The cell is being moved or copied to a new position. The
    2135             :             // position has already been updated prior to this call.
    2136             :             // Determine its original position before the move which will be
    2137             :             // used to adjust relative references later.
    2138             : 
    2139             :             aOldPos.Set(
    2140           0 :                 aPos.Col() - mpCxt->mnColDelta,
    2141           0 :                 aPos.Row() - mpCxt->mnRowDelta,
    2142           0 :                 aPos.Tab() - mpCxt->mnTabDelta);
    2143             :         }
    2144             : 
    2145          10 :         bool bRecalcOnMove = pCode->IsRecalcModeOnRefMove();
    2146          10 :         if (bRecalcOnMove)
    2147           0 :             bRecalcOnMove = aPos != aOldPos;
    2148             : 
    2149          10 :         sc::RefUpdateResult aRes = pCode->AdjustReferenceOnMove(*mpCxt, aOldPos, aPos);
    2150             : 
    2151          10 :         if (aRes.mbReferenceModified || aRes.mbNameModified || bRecalcOnMove)
    2152             :         {
    2153           8 :             sc::AutoCalcSwitch(mpCxt->mrDoc, false);
    2154             : 
    2155           8 :             if (aRes.mbNameModified)
    2156           2 :                 recompileTokenArray(*pTop);
    2157             : 
    2158             :             // Perform end-listening, start-listening, and dirtying on all
    2159             :             // formula cells in the group.
    2160             : 
    2161             :             // Make sure that the start and end listening contexts share the
    2162             :             // same block position set, else an invalid iterator may ensue.
    2163             :             boost::shared_ptr<sc::ColumnBlockPositionSet> pPosSet(
    2164           8 :                 new sc::ColumnBlockPositionSet(mpCxt->mrDoc));
    2165             : 
    2166          16 :             sc::StartListeningContext aStartCxt(mpCxt->mrDoc, pPosSet);
    2167          16 :             sc::EndListeningContext aEndCxt(mpCxt->mrDoc, pPosSet, pOldCode.get());
    2168             : 
    2169             :             aEndCxt.setPositionDelta(
    2170           8 :                 ScAddress(-mpCxt->mnColDelta, -mpCxt->mnRowDelta, -mpCxt->mnTabDelta));
    2171             : 
    2172          26 :             for (; pp != ppEnd; ++pp)
    2173             :             {
    2174          18 :                 ScFormulaCell* p = *pp;
    2175          18 :                 p->EndListeningTo(aEndCxt);
    2176          18 :                 p->StartListeningTo(aStartCxt);
    2177          18 :                 p->SetDirty();
    2178             :             }
    2179             : 
    2180          16 :             fillUndoDoc(aOldPos, rGroup.mnLength, *pOldCode);
    2181          10 :         }
    2182             :     }
    2183             : 
    2184          56 :     void fillUndoDoc( const ScAddress& rOldPos, SCROW nLength, const ScTokenArray& rOldCode )
    2185             :     {
    2186          56 :         if (!mpUndoDoc || nLength <= 0)
    2187         100 :             return;
    2188             : 
    2189             :         // Insert the old formula group into the undo document.
    2190           6 :         ScAddress aUndoPos = rOldPos;
    2191           6 :         ScFormulaCell* pFC = new ScFormulaCell(mpUndoDoc, aUndoPos, rOldCode.Clone());
    2192             : 
    2193           6 :         if (nLength == 1)
    2194             :         {
    2195           0 :             mpUndoDoc->SetFormulaCell(aUndoPos, pFC);
    2196           0 :             return;
    2197             :         }
    2198             : 
    2199           6 :         std::vector<ScFormulaCell*> aCells;
    2200           6 :         aCells.reserve(nLength);
    2201          12 :         ScFormulaCellGroupRef xGroup = pFC->CreateCellGroup(nLength, false);
    2202           6 :         aCells.push_back(pFC);
    2203           6 :         aUndoPos.IncRow();
    2204          12 :         for (SCROW i = 1; i < nLength; ++i, aUndoPos.IncRow())
    2205             :         {
    2206           6 :             pFC = new ScFormulaCell(mpUndoDoc, aUndoPos, xGroup);
    2207           6 :             aCells.push_back(pFC);
    2208             :         }
    2209             : 
    2210           6 :         if (!mpUndoDoc->SetFormulaCells(rOldPos, aCells))
    2211             :             // Insertion failed.  Delete all formula cells.
    2212           6 :             std::for_each(aCells.begin(), aCells.end(), boost::checked_deleter<ScFormulaCell>());
    2213             :     }
    2214             : 
    2215             : public:
    2216         790 :     UpdateRefOnNonCopy(
    2217             :         SCCOL nCol, SCTAB nTab, const sc::RefUpdateContext* pCxt,
    2218             :         ScDocument* pUndoDoc) :
    2219             :         mnCol(nCol), mnTab(nTab), mpCxt(pCxt),
    2220         790 :         mpUndoDoc(pUndoDoc), mbUpdated(false) {}
    2221             : 
    2222         500 :     void operator() ( sc::FormulaGroupEntry& rGroup )
    2223             :     {
    2224         500 :         switch (mpCxt->meMode)
    2225             :         {
    2226             :             case URM_INSDEL:
    2227         432 :                 updateRefOnShift(rGroup);
    2228         432 :                 return;
    2229             :             case URM_MOVE:
    2230          68 :                 updateRefOnMove(rGroup);
    2231          68 :                 return;
    2232             :             default:
    2233             :                 ;
    2234             :         }
    2235             : 
    2236           0 :         if (rGroup.mbShared)
    2237             :         {
    2238           0 :             ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab);
    2239           0 :             ScFormulaCell** pp = rGroup.mpCells;
    2240           0 :             ScFormulaCell** ppEnd = pp + rGroup.mnLength;
    2241           0 :             for (; pp != ppEnd; ++pp, aUndoPos.IncRow())
    2242             :             {
    2243           0 :                 ScFormulaCell* p = *pp;
    2244           0 :                 mbUpdated |= p->UpdateReference(*mpCxt, mpUndoDoc, &aUndoPos);
    2245             :             }
    2246             :         }
    2247             :         else
    2248             :         {
    2249           0 :             ScAddress aUndoPos(mnCol, rGroup.mnRow, mnTab);
    2250           0 :             mbUpdated |= rGroup.mpCell->UpdateReference(*mpCxt, mpUndoDoc, &aUndoPos);
    2251             :         }
    2252             :     }
    2253             : 
    2254        1580 :     bool isUpdated() const { return mbUpdated; }
    2255             : };
    2256             : 
    2257        1580 : class UpdateRefGroupBoundChecker : public SharedTopFormulaCellPicker
    2258             : {
    2259             :     const sc::RefUpdateContext& mrCxt;
    2260             :     std::vector<SCROW>& mrBounds;
    2261             : 
    2262             : public:
    2263         790 :     UpdateRefGroupBoundChecker(const sc::RefUpdateContext& rCxt, std::vector<SCROW>& rBounds) :
    2264         790 :         mrCxt(rCxt), mrBounds(rBounds) {}
    2265             : 
    2266        2370 :     virtual ~UpdateRefGroupBoundChecker() {}
    2267             : 
    2268          90 :     virtual void processSharedTop( ScFormulaCell** ppCells, size_t /*nRow*/, size_t /*nLength*/ ) SAL_OVERRIDE
    2269             :     {
    2270             :         // Check its tokens and record its reference boundaries.
    2271          90 :         ScFormulaCell& rCell = **ppCells;
    2272          90 :         const ScTokenArray& rCode = *rCell.GetCode();
    2273             :         rCode.CheckRelativeReferenceBounds(
    2274          90 :             mrCxt, rCell.aPos, rCell.GetSharedLength(), mrBounds);
    2275          90 :     }
    2276             : };
    2277             : 
    2278      332566 : class FormulaGroupPicker : public SharedTopFormulaCellPicker
    2279             : {
    2280             :     std::vector<sc::FormulaGroupEntry>& mrGroups;
    2281             : 
    2282             : public:
    2283      332566 :     FormulaGroupPicker( std::vector<sc::FormulaGroupEntry>& rGroups ) : mrGroups(rGroups) {}
    2284             : 
    2285      665132 :     virtual ~FormulaGroupPicker() {}
    2286             : 
    2287         442 :     virtual void processNonShared( ScFormulaCell* pCell, size_t nRow ) SAL_OVERRIDE
    2288             :     {
    2289         442 :         mrGroups.push_back(sc::FormulaGroupEntry(pCell, nRow));
    2290         442 :     }
    2291             : 
    2292         114 :     virtual void processSharedTop( ScFormulaCell** ppCells, size_t nRow, size_t nLength ) SAL_OVERRIDE
    2293             :     {
    2294         114 :         mrGroups.push_back(sc::FormulaGroupEntry(ppCells, nRow, nLength));
    2295         114 :     }
    2296             : };
    2297             : 
    2298             : }
    2299             : 
    2300       35038 : bool ScColumn::UpdateReferenceOnCopy( const sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc )
    2301             : {
    2302             :     // When copying, the range equals the destination range where cells
    2303             :     // are pasted, and the dx, dy, dz refer to the distance from the
    2304             :     // source range.
    2305             : 
    2306       35038 :     UpdateRefOnCopy aHandler(rCxt, pUndoDoc);
    2307       35038 :     sc::CellStoreType::position_type aPos = maCells.position(rCxt.maRange.aStart.Row());
    2308       35038 :     sc::ProcessBlock(aPos.first, maCells, aHandler, rCxt.maRange.aStart.Row(), rCxt.maRange.aEnd.Row());
    2309             : 
    2310             :     // The formula groups at the top and bottom boundaries are expected to
    2311             :     // have been split prior to this call. Here, we only do the joining.
    2312       35038 :     sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
    2313       35038 :     if (rCxt.maRange.aEnd.Row() < MAXROW)
    2314             :     {
    2315         222 :         aPos = maCells.position(aPos.first, rCxt.maRange.aEnd.Row()+1);
    2316         222 :         sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
    2317             :     }
    2318             : 
    2319       35038 :     return aHandler.isUpdated();
    2320             : }
    2321             : 
    2322      432350 : bool ScColumn::UpdateReference( sc::RefUpdateContext& rCxt, ScDocument* pUndoDoc )
    2323             : {
    2324      432350 :     if (rCxt.meMode == URM_COPY)
    2325       35038 :         return UpdateReferenceOnCopy(rCxt, pUndoDoc);
    2326             : 
    2327      397312 :     if (IsEmptyData() || pDocument->IsClipOrUndo())
    2328             :         // Cells in this column are all empty, or clip or undo doc. No update needed.
    2329      396522 :         return false;
    2330             : 
    2331         790 :     std::vector<SCROW> aBounds;
    2332             : 
    2333        2334 :     bool bThisColShifted = (rCxt.maRange.aStart.Tab() <= nTab && nTab <= rCxt.maRange.aEnd.Tab() &&
    2334        2078 :                             rCxt.maRange.aStart.Col() <= nCol && nCol <= rCxt.maRange.aEnd.Col());
    2335         790 :     if (bThisColShifted)
    2336             :     {
    2337             :         // Cells in this column is being shifted.  Split formula grouping at
    2338             :         // the top and bottom boundaries before they get shifted.
    2339             :         // Also, for deleted rows split at the top of the deleted area to adapt
    2340             :         // the affected group length.
    2341             :         SCROW nSplitPos;
    2342         480 :         if (rCxt.mnRowDelta < 0)
    2343             :         {
    2344         116 :             nSplitPos = rCxt.maRange.aStart.Row() + rCxt.mnRowDelta;
    2345         116 :             if (ValidRow(nSplitPos))
    2346         114 :                 aBounds.push_back(nSplitPos);
    2347             :         }
    2348         480 :         nSplitPos = rCxt.maRange.aStart.Row();
    2349         480 :         if (ValidRow(nSplitPos))
    2350             :         {
    2351         480 :             aBounds.push_back(nSplitPos);
    2352         480 :             nSplitPos = rCxt.maRange.aEnd.Row() + 1;
    2353         480 :             if (ValidRow(nSplitPos))
    2354          94 :                 aBounds.push_back(nSplitPos);
    2355             :         }
    2356             :     }
    2357             : 
    2358             :     // Check the row positions at which the group must be split per relative
    2359             :     // references.
    2360        1580 :     UpdateRefGroupBoundChecker aBoundChecker(rCxt, aBounds);
    2361         790 :     std::for_each(maCells.begin(), maCells.end(), aBoundChecker);
    2362             : 
    2363             :     // Do the actual splitting.
    2364         790 :     sc::SharedFormulaUtil::splitFormulaCellGroups(maCells, aBounds);
    2365             : 
    2366             :     // Collect all formula groups.
    2367        1580 :     std::vector<sc::FormulaGroupEntry> aGroups = GetFormulaGroupEntries();
    2368             : 
    2369             :     // Process all collected formula groups.
    2370         790 :     UpdateRefOnNonCopy aHandler(nCol, nTab, &rCxt, pUndoDoc);
    2371         790 :     aHandler = std::for_each(aGroups.begin(), aGroups.end(), aHandler);
    2372         790 :     if (aHandler.isUpdated())
    2373         232 :         rCxt.maRegroupCols.set(nTab, nCol);
    2374             : 
    2375        1580 :     return aHandler.isUpdated();
    2376             : }
    2377             : 
    2378      332566 : std::vector<sc::FormulaGroupEntry> ScColumn::GetFormulaGroupEntries()
    2379             : {
    2380      332566 :     std::vector<sc::FormulaGroupEntry> aGroups;
    2381      332566 :     std::for_each(maCells.begin(), maCells.end(), FormulaGroupPicker(aGroups));
    2382      332566 :     return aGroups;
    2383             : }
    2384             : 
    2385             : namespace {
    2386             : 
    2387             : class UpdateTransHandler
    2388             : {
    2389             :     ScColumn& mrColumn;
    2390             :     sc::CellStoreType::iterator miPos;
    2391             :     ScRange maSource;
    2392             :     ScAddress maDest;
    2393             :     ScDocument* mpUndoDoc;
    2394             : public:
    2395           0 :     UpdateTransHandler(ScColumn& rColumn, const ScRange& rSource, const ScAddress& rDest, ScDocument* pUndoDoc) :
    2396             :         mrColumn(rColumn),
    2397           0 :         miPos(rColumn.GetCellStore().begin()),
    2398           0 :         maSource(rSource), maDest(rDest), mpUndoDoc(pUndoDoc) {}
    2399             : 
    2400           0 :     void operator() (size_t nRow, ScFormulaCell* pCell)
    2401             :     {
    2402           0 :         sc::CellStoreType::position_type aPos = mrColumn.GetCellStore().position(miPos, nRow);
    2403           0 :         miPos = aPos.first;
    2404           0 :         sc::SharedFormulaUtil::unshareFormulaCell(aPos, *pCell);
    2405           0 :         pCell->UpdateTranspose(maSource, maDest, mpUndoDoc);
    2406           0 :         mrColumn.JoinNewFormulaCell(aPos, *pCell);
    2407           0 :     }
    2408             : };
    2409             : 
    2410             : class UpdateGrowHandler
    2411             : {
    2412             :     ScColumn& mrColumn;
    2413             :     sc::CellStoreType::iterator miPos;
    2414             :     ScRange maArea;
    2415             :     SCCOL mnGrowX;
    2416             :     SCROW mnGrowY;
    2417             : public:
    2418           0 :     UpdateGrowHandler(ScColumn& rColumn, const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY) :
    2419             :         mrColumn(rColumn),
    2420           0 :         miPos(rColumn.GetCellStore().begin()),
    2421           0 :         maArea(rArea), mnGrowX(nGrowX), mnGrowY(nGrowY) {}
    2422             : 
    2423           0 :     void operator() (size_t nRow, ScFormulaCell* pCell)
    2424             :     {
    2425           0 :         sc::CellStoreType::position_type aPos = mrColumn.GetCellStore().position(miPos, nRow);
    2426           0 :         miPos = aPos.first;
    2427           0 :         sc::SharedFormulaUtil::unshareFormulaCell(aPos, *pCell);
    2428           0 :         pCell->UpdateGrow(maArea, mnGrowX, mnGrowY);
    2429           0 :         mrColumn.JoinNewFormulaCell(aPos, *pCell);
    2430           0 :     }
    2431             : };
    2432             : 
    2433             : class InsertTabUpdater
    2434             : {
    2435             :     sc::RefUpdateInsertTabContext& mrCxt;
    2436             :     sc::CellTextAttrStoreType& mrTextAttrs;
    2437             :     sc::CellTextAttrStoreType::iterator miAttrPos;
    2438             :     SCTAB mnTab;
    2439             :     bool mbModified;
    2440             : 
    2441             : public:
    2442      274432 :     InsertTabUpdater(sc::RefUpdateInsertTabContext& rCxt, sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab) :
    2443             :         mrCxt(rCxt),
    2444             :         mrTextAttrs(rTextAttrs),
    2445             :         miAttrPos(rTextAttrs.begin()),
    2446             :         mnTab(nTab),
    2447      274432 :         mbModified(false) {}
    2448             : 
    2449         500 :     void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
    2450             :     {
    2451         500 :         pCell->UpdateInsertTab(mrCxt);
    2452         500 :         mbModified = true;
    2453         500 :     }
    2454             : 
    2455          12 :     void operator() (size_t nRow, EditTextObject* pCell)
    2456             :     {
    2457          12 :         editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
    2458          12 :         aUpdater.updateTableFields(mnTab);
    2459          12 :         miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
    2460          12 :         mbModified = true;
    2461          12 :     }
    2462             : 
    2463      274432 :     bool isModified() const { return mbModified; }
    2464             : };
    2465             : 
    2466             : class DeleteTabUpdater
    2467             : {
    2468             :     sc::RefUpdateDeleteTabContext& mrCxt;
    2469             :     sc::CellTextAttrStoreType& mrTextAttrs;
    2470             :     sc::CellTextAttrStoreType::iterator miAttrPos;
    2471             :     SCTAB mnTab;
    2472             :     bool mbModified;
    2473             : public:
    2474      438272 :     DeleteTabUpdater(sc::RefUpdateDeleteTabContext& rCxt, sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab) :
    2475             :         mrCxt(rCxt),
    2476             :         mrTextAttrs(rTextAttrs),
    2477             :         miAttrPos(rTextAttrs.begin()),
    2478             :         mnTab(nTab),
    2479      438272 :         mbModified(false) {}
    2480             : 
    2481         358 :     void operator() (size_t, ScFormulaCell* pCell)
    2482             :     {
    2483         358 :         pCell->UpdateDeleteTab(mrCxt);
    2484         358 :         mbModified = true;
    2485         358 :     }
    2486             : 
    2487          24 :     void operator() (size_t nRow, EditTextObject* pCell)
    2488             :     {
    2489          24 :         editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
    2490          24 :         aUpdater.updateTableFields(mnTab);
    2491          24 :         miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
    2492          24 :         mbModified = true;
    2493          24 :     }
    2494             : 
    2495      438272 :     bool isModified() const { return mbModified; }
    2496             : };
    2497             : 
    2498             : class InsertAbsTabUpdater
    2499             : {
    2500             :     sc::CellTextAttrStoreType& mrTextAttrs;
    2501             :     sc::CellTextAttrStoreType::iterator miAttrPos;
    2502             :     SCTAB mnTab;
    2503             :     SCTAB mnNewPos;
    2504             :     bool mbModified;
    2505             : public:
    2506       12288 :     InsertAbsTabUpdater(sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab, SCTAB nNewPos) :
    2507             :         mrTextAttrs(rTextAttrs),
    2508             :         miAttrPos(rTextAttrs.begin()),
    2509             :         mnTab(nTab),
    2510             :         mnNewPos(nNewPos),
    2511       12288 :         mbModified(false) {}
    2512             : 
    2513           4 :     void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
    2514             :     {
    2515           4 :         pCell->UpdateInsertTabAbs(mnNewPos);
    2516           4 :         mbModified = true;
    2517           4 :     }
    2518             : 
    2519          12 :     void operator() (size_t nRow, EditTextObject* pCell)
    2520             :     {
    2521          12 :         editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
    2522          12 :         aUpdater.updateTableFields(mnTab);
    2523          12 :         miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
    2524          12 :         mbModified = true;
    2525          12 :     }
    2526             : 
    2527       12288 :     bool isModified() const { return mbModified; }
    2528             : };
    2529             : 
    2530             : class MoveTabUpdater
    2531             : {
    2532             :     sc::RefUpdateMoveTabContext& mrCxt;
    2533             :     sc::CellTextAttrStoreType& mrTextAttrs;
    2534             :     sc::CellTextAttrStoreType::iterator miAttrPos;
    2535             :     SCTAB mnTab;
    2536             :     bool mbModified;
    2537             : public:
    2538       79872 :     MoveTabUpdater(sc::RefUpdateMoveTabContext& rCxt, sc::CellTextAttrStoreType& rTextAttrs, SCTAB nTab) :
    2539             :         mrCxt(rCxt),
    2540             :         mrTextAttrs(rTextAttrs),
    2541             :         miAttrPos(rTextAttrs.begin()),
    2542             :         mnTab(nTab),
    2543       79872 :         mbModified(false) {}
    2544             : 
    2545          48 :     void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
    2546             :     {
    2547          48 :         pCell->UpdateMoveTab(mrCxt, mnTab);
    2548          48 :         mbModified = true;
    2549          48 :     }
    2550             : 
    2551           0 :     void operator() (size_t nRow, EditTextObject* pCell)
    2552             :     {
    2553           0 :         editeng::FieldUpdater aUpdater = pCell->GetFieldUpdater();
    2554           0 :         aUpdater.updateTableFields(mnTab);
    2555           0 :         miAttrPos = mrTextAttrs.set(miAttrPos, nRow, sc::CellTextAttr());
    2556           0 :         mbModified = true;
    2557           0 :     }
    2558             : 
    2559       79872 :     bool isModified() const { return mbModified; }
    2560             : };
    2561             : 
    2562             : class UpdateCompileHandler
    2563             : {
    2564             :     bool mbForceIfNameInUse:1;
    2565             : public:
    2566      741376 :     UpdateCompileHandler(bool bForceIfNameInUse) :
    2567      741376 :         mbForceIfNameInUse(bForceIfNameInUse) {}
    2568             : 
    2569         828 :     void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
    2570             :     {
    2571         828 :         pCell->UpdateCompile(mbForceIfNameInUse);
    2572         828 :     }
    2573             : };
    2574             : 
    2575             : class TabNoSetter
    2576             : {
    2577             :     SCTAB mnTab;
    2578             : public:
    2579       26624 :     TabNoSetter(SCTAB nTab) : mnTab(nTab) {}
    2580             : 
    2581         100 :     void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
    2582             :     {
    2583         100 :         pCell->aPos.SetTab(mnTab);
    2584         100 :     }
    2585             : };
    2586             : 
    2587             : class UsedRangeNameFinder
    2588             : {
    2589             :     std::set<sal_uInt16>& mrIndexes;
    2590             : public:
    2591          22 :     UsedRangeNameFinder(std::set<sal_uInt16>& rIndexes) : mrIndexes(rIndexes) {}
    2592             : 
    2593           2 :     void operator() (size_t /*nRow*/, const ScFormulaCell* pCell)
    2594             :     {
    2595           2 :         pCell->FindRangeNamesInUse(mrIndexes);
    2596           2 :     }
    2597             : };
    2598             : 
    2599             : struct SetDirtyVarHandler
    2600             : {
    2601        7202 :     void operator() (size_t /*nRow*/, ScFormulaCell* p)
    2602             :     {
    2603        7202 :         p->SetDirtyVar();
    2604        7202 :     }
    2605             : };
    2606             : 
    2607             : class SetDirtyHandler
    2608             : {
    2609             :     ScDocument& mrDoc;
    2610             :     const sc::SetFormulaDirtyContext& mrCxt;
    2611             : public:
    2612     1861632 :     SetDirtyHandler( ScDocument& rDoc, const sc::SetFormulaDirtyContext& rCxt ) :
    2613     1861632 :         mrDoc(rDoc), mrCxt(rCxt) {}
    2614             : 
    2615         996 :     void operator() (size_t /*nRow*/, ScFormulaCell* p)
    2616             :     {
    2617         996 :         if (mrCxt.mbClearTabDeletedFlag)
    2618             :         {
    2619           6 :             if (!p->IsShared() || p->IsSharedTop())
    2620             :             {
    2621           2 :                 ScTokenArray* pCode = p->GetCode();
    2622             :                 pCode->ClearTabDeleted(
    2623           2 :                     p->aPos, mrCxt.mnTabDeletedStart, mrCxt.mnTabDeletedEnd);
    2624             :             }
    2625             :         }
    2626             : 
    2627         996 :         p->SetDirtyVar();
    2628         996 :         if (!mrDoc.IsInFormulaTree(p))
    2629         250 :             mrDoc.PutInFormulaTree(p);
    2630         996 :     }
    2631             : };
    2632             : 
    2633       29472 : class SetDirtyOnRangeHandler
    2634             : {
    2635             :     sc::SingleColumnSpanSet maValueRanges;
    2636             :     ScColumn& mrColumn;
    2637             : public:
    2638       29472 :     SetDirtyOnRangeHandler(ScColumn& rColumn) : mrColumn(rColumn) {}
    2639             : 
    2640         554 :     void operator() (size_t /*nRow*/, ScFormulaCell* p)
    2641             :     {
    2642         554 :         p->SetDirty();
    2643         554 :     }
    2644             : 
    2645       29812 :     void operator() (mdds::mtv::element_t type, size_t nTopRow, size_t nDataSize)
    2646             :     {
    2647       29812 :         if (type == sc::element_type_empty)
    2648             :             // Ignore empty blocks.
    2649       58664 :             return;
    2650             : 
    2651             :         // Non-formula cells.
    2652         960 :         SCROW nRow1 = nTopRow;
    2653         960 :         SCROW nRow2 = nTopRow + nDataSize - 1;
    2654         960 :         maValueRanges.set(nRow1, nRow2, true);
    2655             :     }
    2656             : 
    2657       29472 :     void broadcast()
    2658             :     {
    2659       29472 :         std::vector<SCROW> aRows;
    2660       29472 :         maValueRanges.getRows(aRows);
    2661       29472 :         mrColumn.BroadcastCells(aRows, SC_HINT_DATACHANGED);
    2662       29472 :     }
    2663             : };
    2664             : 
    2665          88 : class SetTableOpDirtyOnRangeHandler
    2666             : {
    2667             :     sc::SingleColumnSpanSet maValueRanges;
    2668             :     ScColumn& mrColumn;
    2669             : public:
    2670          88 :     SetTableOpDirtyOnRangeHandler(ScColumn& rColumn) : mrColumn(rColumn) {}
    2671             : 
    2672           0 :     void operator() (size_t /*nRow*/, ScFormulaCell* p)
    2673             :     {
    2674           0 :         p->SetTableOpDirty();
    2675           0 :     }
    2676             : 
    2677          88 :     void operator() (mdds::mtv::element_t type, size_t nTopRow, size_t nDataSize)
    2678             :     {
    2679          88 :         if (type == sc::element_type_empty)
    2680             :             // Ignore empty blocks.
    2681         152 :             return;
    2682             : 
    2683             :         // Non-formula cells.
    2684          24 :         SCROW nRow1 = nTopRow;
    2685          24 :         SCROW nRow2 = nTopRow + nDataSize - 1;
    2686          24 :         maValueRanges.set(nRow1, nRow2, true);
    2687             :     }
    2688             : 
    2689          88 :     void broadcast()
    2690             :     {
    2691          88 :         std::vector<SCROW> aRows;
    2692          88 :         maValueRanges.getRows(aRows);
    2693          88 :         mrColumn.BroadcastCells(aRows, SC_HINT_TABLEOPDIRTY);
    2694          88 :     }
    2695             : };
    2696             : 
    2697             : struct SetDirtyAfterLoadHandler
    2698             : {
    2699        7428 :     void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
    2700             :     {
    2701             : #if 1
    2702             :         // Simply set dirty and append to FormulaTree, without broadcasting,
    2703             :         // which is a magnitude faster. This is used to calculate the entire
    2704             :         // document, e.g. when loading alien file formats.
    2705        7428 :         pCell->SetDirtyAfterLoad();
    2706             : #else
    2707             : /* This was used with the binary file format that stored results, where only
    2708             :  * newly compiled and volatile functions and their dependents had to be
    2709             :  * recalculated, which was faster then. Since that was moved to 'binfilter' to
    2710             :  * convert to an XML file this isn't needed anymore, and not used for other
    2711             :  * file formats. Kept for reference in case mechanism needs to be reactivated
    2712             :  * for some file formats, we'd have to introduce a controlling parameter to
    2713             :  * this method here then.
    2714             : */
    2715             : 
    2716             :         // If the cell was alsready dirty because of CalcAfterLoad,
    2717             :         // FormulaTracking has to take place.
    2718             :         if (pCell->GetDirty())
    2719             :             pCell->SetDirty();
    2720             : #endif
    2721        7428 :     }
    2722             : };
    2723             : 
    2724             : struct SetDirtyIfPostponedHandler
    2725             : {
    2726         572 :     void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
    2727             :     {
    2728         572 :         if (pCell->IsPostponedDirty() || pCell->HasRelNameReference())
    2729         184 :             pCell->SetDirty();
    2730         572 :     }
    2731             : };
    2732             : 
    2733             : struct CalcAllHandler
    2734             : {
    2735        7202 :     void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
    2736             :     {
    2737             : #if OSL_DEBUG_LEVEL > 1
    2738             :         // after F9 ctrl-F9: check the calculation for each FormulaTree
    2739             :         double nOldVal, nNewVal;
    2740             :         nOldVal = pCell->GetValue();
    2741             : #endif
    2742        7202 :         pCell->Interpret();
    2743             : #if OSL_DEBUG_LEVEL > 1
    2744             :         if (pCell->GetCode()->IsRecalcModeNormal())
    2745             :             nNewVal = pCell->GetValue();
    2746             :         else
    2747             :             nNewVal = nOldVal;  // random(), jetzt() etc.
    2748             : 
    2749             :         OSL_ENSURE(nOldVal == nNewVal, "CalcAll: nOldVal != nNewVal");
    2750             : #endif
    2751        7202 :     }
    2752             : };
    2753             : 
    2754             : class CompileAllHandler
    2755             : {
    2756             :     sc::CompileFormulaContext& mrCxt;
    2757             : public:
    2758       63488 :     CompileAllHandler( sc::CompileFormulaContext& rCxt ) : mrCxt(rCxt) {}
    2759             : 
    2760         172 :     void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
    2761             :     {
    2762             :         // for unconditional compilation
    2763             :         // bCompile=true and pCode->nError=0
    2764         172 :         pCell->GetCode()->SetCodeError(0);
    2765         172 :         pCell->SetCompile(true);
    2766         172 :         pCell->CompileTokenArray(mrCxt);
    2767         172 :     }
    2768             : };
    2769             : 
    2770             : class CompileXMLHandler
    2771             : {
    2772             :     sc::CompileFormulaContext& mrCxt;
    2773             :     ScProgress& mrProgress;
    2774             :     const ScColumn& mrCol;
    2775             : public:
    2776      591872 :     CompileXMLHandler( sc::CompileFormulaContext& rCxt, ScProgress& rProgress, const ScColumn& rCol) :
    2777             :         mrCxt(rCxt),
    2778             :         mrProgress(rProgress),
    2779      591872 :         mrCol(rCol) {}
    2780             : 
    2781        1816 :     void operator() (size_t nRow, ScFormulaCell* pCell)
    2782             :     {
    2783        1816 :         sal_uInt32 nFormat = mrCol.GetNumberFormat(nRow);
    2784        1816 :         if( (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
    2785             :             // Non-default number format is set.
    2786         596 :             pCell->SetNeedNumberFormat(false);
    2787        1220 :         else if (pCell->NeedsNumberFormat())
    2788         484 :             pCell->SetDirtyVar();
    2789             : 
    2790        1816 :         if (pCell->GetMatrixFlag())
    2791         168 :             pCell->SetDirtyVar();
    2792             : 
    2793        1816 :         pCell->CompileXML(mrCxt, mrProgress);
    2794        1816 :     }
    2795             : };
    2796             : 
    2797             : class CompileErrorCellsHandler
    2798             : {
    2799             :     sc::CompileFormulaContext& mrCxt;
    2800             :     ScColumn& mrColumn;
    2801             :     sc::CellStoreType::iterator miPos;
    2802             :     sal_uInt16 mnErrCode;
    2803             :     bool mbCompiled;
    2804             : public:
    2805           0 :     CompileErrorCellsHandler( sc::CompileFormulaContext& rCxt, ScColumn& rColumn, sal_uInt16 nErrCode ) :
    2806             :         mrCxt(rCxt),
    2807             :         mrColumn(rColumn),
    2808           0 :         miPos(mrColumn.GetCellStore().begin()),
    2809             :         mnErrCode(nErrCode),
    2810           0 :         mbCompiled(false)
    2811             :     {
    2812           0 :     }
    2813             : 
    2814           0 :     void operator() (size_t nRow, ScFormulaCell* pCell)
    2815             :     {
    2816           0 :         sal_uInt16 nCurError = pCell->GetRawError();
    2817           0 :         if (!nCurError)
    2818             :             // It's not an error cell. Skip it.
    2819           0 :             return;
    2820             : 
    2821           0 :         if (mnErrCode && nCurError != mnErrCode)
    2822             :             // Error code is specified, and it doesn't match. Skip it.
    2823           0 :             return;
    2824             : 
    2825           0 :         sc::CellStoreType::position_type aPos = mrColumn.GetCellStore().position(miPos, nRow);
    2826           0 :         miPos = aPos.first;
    2827           0 :         sc::SharedFormulaUtil::unshareFormulaCell(aPos, *pCell);
    2828           0 :         pCell->GetCode()->SetCodeError(0);
    2829           0 :         OUString aFormula = pCell->GetFormula(mrCxt);
    2830           0 :         pCell->Compile(mrCxt, aFormula, false);
    2831           0 :         mrColumn.JoinNewFormulaCell(aPos, *pCell);
    2832             : 
    2833           0 :         mbCompiled = true;
    2834             :     }
    2835             : 
    2836           0 :     bool isCompiled() const { return mbCompiled; }
    2837             : };
    2838             : 
    2839             : class CalcAfterLoadHandler
    2840             : {
    2841             :     sc::CompileFormulaContext& mrCxt;
    2842             : public:
    2843      444416 :     CalcAfterLoadHandler( sc::CompileFormulaContext& rCxt ) : mrCxt(rCxt) {}
    2844             : 
    2845        7428 :     void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
    2846             :     {
    2847        7428 :         pCell->CalcAfterLoad(mrCxt);
    2848        7428 :     }
    2849             : };
    2850             : 
    2851             : struct ResetChangedHandler
    2852             : {
    2853         375 :     void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
    2854             :     {
    2855         375 :         pCell->SetChanged(false);
    2856         375 :     }
    2857             : };
    2858             : 
    2859             : /**
    2860             :  * Ambiguous script type counts as edit cell.
    2861             :  */
    2862             : class FindEditCellsHandler
    2863             : {
    2864             :     ScColumn& mrColumn;
    2865             :     sc::CellTextAttrStoreType::iterator miAttrPos;
    2866             :     sc::CellStoreType::iterator miCellPos;
    2867             : 
    2868             : public:
    2869     2510394 :     FindEditCellsHandler(ScColumn& rCol) :
    2870             :         mrColumn(rCol),
    2871     2510394 :         miAttrPos(rCol.GetCellAttrStore().begin()),
    2872     5020788 :         miCellPos(rCol.GetCellStore().begin()) {}
    2873             : 
    2874         214 :     bool operator() (size_t, const EditTextObject*)
    2875             :     {
    2876             :         // This is definitely an edit text cell.
    2877         214 :         return true;
    2878             :     }
    2879             : 
    2880        1616 :     bool operator() (size_t nRow, const ScFormulaCell* p)
    2881             :     {
    2882             :         // With a formula cell, it's considered an edit text cell when either
    2883             :         // the result is multi-line or it has more than one script types.
    2884        1616 :         sal_uInt8 nScriptType = mrColumn.GetRangeScriptType(miAttrPos, nRow, nRow, miCellPos);
    2885        1616 :         if (IsAmbiguousScriptNonZero(nScriptType))
    2886           0 :             return true;
    2887             : 
    2888        1616 :         return const_cast<ScFormulaCell*>(p)->IsMultilineResult();
    2889             :     }
    2890             : 
    2891             :     /**
    2892             :      * Callback for a block of other types.
    2893             :      */
    2894     2511358 :     std::pair<size_t,bool> operator() (const sc::CellStoreType::value_type& node, size_t nOffset, size_t nDataSize)
    2895             :     {
    2896             :         typedef std::pair<size_t,bool> RetType;
    2897             : 
    2898     2511358 :         if (node.type == sc::element_type_empty)
    2899             :             // Ignore empty blocks.
    2900     2503897 :             return RetType(0, false);
    2901             : 
    2902             :         // Check the script type of a non-empty element and see if it has
    2903             :         // multiple script types.
    2904       71572 :         for (size_t i = 0; i < nDataSize; ++i)
    2905             :         {
    2906       64115 :             SCROW nRow = node.position + i + nOffset;
    2907       64115 :             sal_uInt8 nScriptType = mrColumn.GetRangeScriptType(miAttrPos, nRow, nRow, miCellPos);
    2908       64115 :             if (IsAmbiguousScriptNonZero(nScriptType))
    2909             :                 // Return the offset from the first row.
    2910           4 :                 return RetType(i+nOffset, true);
    2911             :         }
    2912             : 
    2913             :         // No edit text cell found.
    2914        7457 :         return RetType(0, false);
    2915             :     }
    2916             : };
    2917             : 
    2918             : }
    2919             : 
    2920           0 : void ScColumn::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
    2921             :                                     ScDocument* pUndoDoc )
    2922             : {
    2923           0 :     UpdateTransHandler aFunc(*this, rSource, rDest, pUndoDoc);
    2924           0 :     sc::ProcessFormula(maCells, aFunc);
    2925           0 : }
    2926             : 
    2927           0 : void ScColumn::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
    2928             : {
    2929           0 :     UpdateGrowHandler aFunc(*this, rArea, nGrowX, nGrowY);
    2930           0 :     sc::ProcessFormula(maCells, aFunc);
    2931           0 : }
    2932             : 
    2933      274432 : void ScColumn::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
    2934             : {
    2935      274432 :     if (nTab >= rCxt.mnInsertPos)
    2936             :     {
    2937      253952 :         nTab += rCxt.mnSheets;
    2938      253952 :         pAttrArray->SetTab(nTab);
    2939             :     }
    2940             : 
    2941      274432 :     UpdateInsertTabOnlyCells(rCxt);
    2942      274432 : }
    2943             : 
    2944      274432 : void ScColumn::UpdateInsertTabOnlyCells( sc::RefUpdateInsertTabContext& rCxt )
    2945             : {
    2946      274432 :     InsertTabUpdater aFunc(rCxt, maCellTextAttrs, nTab);
    2947      274432 :     sc::ProcessFormulaEditText(maCells, aFunc);
    2948      274432 :     if (aFunc.isModified())
    2949         472 :         CellStorageModified();
    2950      274432 : }
    2951             : 
    2952      438272 : void ScColumn::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
    2953             : {
    2954      438272 :     if (nTab > rCxt.mnDeletePos)
    2955             :     {
    2956       86016 :         nTab -= rCxt.mnSheets;
    2957       86016 :         pAttrArray->SetTab(nTab);
    2958             :     }
    2959             : 
    2960      438272 :     DeleteTabUpdater aFunc(rCxt, maCellTextAttrs, nTab);
    2961      438272 :     sc::ProcessFormulaEditText(maCells, aFunc);
    2962      438272 :     if (aFunc.isModified())
    2963         130 :         CellStorageModified();
    2964      438272 : }
    2965             : 
    2966       12288 : void ScColumn::UpdateInsertTabAbs(SCTAB nNewPos)
    2967             : {
    2968       12288 :     InsertAbsTabUpdater aFunc(maCellTextAttrs, nTab, nNewPos);
    2969       12288 :     sc::ProcessFormulaEditText(maCells, aFunc);
    2970       12288 :     if (aFunc.isModified())
    2971           6 :         CellStorageModified();
    2972       12288 : }
    2973             : 
    2974       79872 : void ScColumn::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt, SCTAB nTabNo )
    2975             : {
    2976       79872 :     nTab = nTabNo;
    2977       79872 :     pAttrArray->SetTab( nTabNo );
    2978             : 
    2979       79872 :     MoveTabUpdater aFunc(rCxt, maCellTextAttrs, nTab);
    2980       79872 :     sc::ProcessFormulaEditText(maCells, aFunc);
    2981       79872 :     if (aFunc.isModified())
    2982          18 :         CellStorageModified();
    2983       79872 : }
    2984             : 
    2985      741376 : void ScColumn::UpdateCompile( bool bForceIfNameInUse )
    2986             : {
    2987      741376 :     UpdateCompileHandler aFunc(bForceIfNameInUse);
    2988      741376 :     sc::ProcessFormula(maCells, aFunc);
    2989      741376 : }
    2990             : 
    2991       26624 : void ScColumn::SetTabNo(SCTAB nNewTab)
    2992             : {
    2993       26624 :     nTab = nNewTab;
    2994       26624 :     pAttrArray->SetTab( nNewTab );
    2995             : 
    2996       26624 :     TabNoSetter aFunc(nTab);
    2997       26624 :     sc::ProcessFormula(maCells, aFunc);
    2998       26624 : }
    2999             : 
    3000          22 : void ScColumn::FindRangeNamesInUse(SCROW nRow1, SCROW nRow2, std::set<sal_uInt16>& rIndexes) const
    3001             : {
    3002          22 :     UsedRangeNameFinder aFunc(rIndexes);
    3003          22 :     sc::ParseFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc);
    3004          22 : }
    3005             : 
    3006      909312 : void ScColumn::SetDirtyVar()
    3007             : {
    3008             :     SetDirtyVarHandler aFunc;
    3009      909312 :     sc::ProcessFormula(maCells, aFunc);
    3010      909312 : }
    3011             : 
    3012           0 : bool ScColumn::IsFormulaDirty( SCROW nRow ) const
    3013             : {
    3014           0 :     if (!ValidRow(nRow))
    3015           0 :         return false;
    3016             : 
    3017           0 :     std::pair<sc::CellStoreType::const_iterator,size_t> aPos = maCells.position(nRow);
    3018           0 :     sc::CellStoreType::const_iterator it = aPos.first;
    3019           0 :     if (it->type != sc::element_type_formula)
    3020             :         // This is not a formula cell block.
    3021           0 :         return false;
    3022             : 
    3023           0 :     const ScFormulaCell* p = sc::formula_block::at(*it->data, aPos.second);
    3024           0 :     return p->GetDirty();
    3025             : }
    3026             : 
    3027     1861632 : void ScColumn::SetAllFormulasDirty( const sc::SetFormulaDirtyContext& rCxt )
    3028             : {
    3029             :     // is only done documentwide, no FormulaTracking
    3030     1861632 :     sc::AutoCalcSwitch aSwitch(*pDocument, false);
    3031     1861632 :     SetDirtyHandler aFunc(*pDocument, rCxt);
    3032     1861632 :     sc::ProcessFormula(maCells, aFunc);
    3033     1861632 : }
    3034             : 
    3035       29472 : void ScColumn::SetDirty( SCROW nRow1, SCROW nRow2 )
    3036             : {
    3037             :     // broadcasts everything within the range, with FormulaTracking
    3038       29472 :     sc::AutoCalcSwitch aSwitch(*pDocument, false);
    3039             : 
    3040       58944 :     SetDirtyOnRangeHandler aHdl(*this);
    3041       29472 :     sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl, aHdl);
    3042       58944 :     aHdl.broadcast();
    3043       29472 : }
    3044             : 
    3045          88 : void ScColumn::SetTableOpDirty( const ScRange& rRange )
    3046             : {
    3047          88 :     sc::AutoCalcSwitch aSwitch(*pDocument, false);
    3048             : 
    3049          88 :     SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
    3050         176 :     SetTableOpDirtyOnRangeHandler aHdl(*this);
    3051          88 :     sc::ProcessFormula(maCells.begin(), maCells, nRow1, nRow2, aHdl, aHdl);
    3052         176 :     aHdl.broadcast();
    3053          88 : }
    3054             : 
    3055      444416 : void ScColumn::SetDirtyAfterLoad()
    3056             : {
    3057      444416 :     sc::AutoCalcSwitch aSwitch(*pDocument, false);
    3058             :     SetDirtyAfterLoadHandler aFunc;
    3059      444416 :     sc::ProcessFormula(maCells, aFunc);
    3060      444416 : }
    3061             : 
    3062             : namespace {
    3063             : 
    3064      704512 : class RecalcOnRefMoveCollector
    3065             : {
    3066             :     std::vector<SCROW> maDirtyRows;
    3067             : public:
    3068         572 :     void operator() (size_t nRow, ScFormulaCell* pCell)
    3069             :     {
    3070         572 :         if (pCell->GetDirty() && pCell->GetCode()->IsRecalcModeOnRefMove())
    3071          20 :             maDirtyRows.push_back(nRow);
    3072         572 :     }
    3073             : 
    3074      352256 :     const std::vector<SCROW>& getDirtyRows() const
    3075             :     {
    3076      352256 :         return maDirtyRows;
    3077             :     }
    3078             : };
    3079             : 
    3080             : }
    3081             : 
    3082      352256 : void ScColumn::SetDirtyIfPostponed()
    3083             : {
    3084      352256 :     sc::AutoCalcSwitch aSwitch(*pDocument, false);
    3085             :     SetDirtyIfPostponedHandler aFunc;
    3086      352256 :     sc::ProcessFormula(maCells, aFunc);
    3087      352256 : }
    3088             : 
    3089      352256 : void ScColumn::BroadcastRecalcOnRefMove()
    3090             : {
    3091      352256 :     sc::AutoCalcSwitch aSwitch(*pDocument, false);
    3092      704512 :     RecalcOnRefMoveCollector aFunc;
    3093      352256 :     sc::ProcessFormula(maCells, aFunc);
    3094      704512 :     BroadcastCells(aFunc.getDirtyRows(), SC_HINT_DATACHANGED);
    3095      352256 : }
    3096             : 
    3097             : namespace {
    3098             : 
    3099          28 : class TransferListenersHandler
    3100             : {
    3101             : public:
    3102             :     typedef std::vector<SvtListener*> ListenersType;
    3103         112 :     struct Entry
    3104             :     {
    3105             :         size_t mnRow;
    3106             :         ListenersType maListeners;
    3107             :     };
    3108             :     typedef std::vector<Entry> ListenerListType;
    3109             : 
    3110          14 :     void swapListeners( std::vector<Entry>& rListenerList )
    3111             :     {
    3112          14 :         maListenerList.swap(rListenerList);
    3113          14 :     }
    3114             : 
    3115          20 :     void operator() ( size_t nRow, SvtBroadcaster* pBroadcaster )
    3116             :     {
    3117             :         assert(pBroadcaster);
    3118             : 
    3119             :         // It's important to make a copy here.
    3120          20 :         SvtBroadcaster::ListenersType aLis = pBroadcaster->GetAllListeners();
    3121          20 :         if (aLis.empty())
    3122             :             // No listeners to transfer.
    3123          20 :             return;
    3124             : 
    3125          40 :         Entry aEntry;
    3126          20 :         aEntry.mnRow = nRow;
    3127             : 
    3128          20 :         SvtBroadcaster::ListenersType::iterator it = aLis.begin(), itEnd = aLis.end();
    3129          50 :         for (; it != itEnd; ++it)
    3130             :         {
    3131          30 :             SvtListener* pLis = *it;
    3132          30 :             pLis->EndListening(*pBroadcaster);
    3133          30 :             aEntry.maListeners.push_back(pLis);
    3134             :         }
    3135             : 
    3136          20 :         maListenerList.push_back(aEntry);
    3137             : 
    3138             :         // At this point, the source broadcaster should have no more listeners.
    3139          20 :         assert(!pBroadcaster->HasListeners());
    3140             :     }
    3141             : 
    3142             : private:
    3143             :     ListenerListType maListenerList;
    3144             : };
    3145             : 
    3146          14 : class RemoveEmptyBroadcasterHandler
    3147             : {
    3148             :     sc::ColumnSpanSet maSet;
    3149             :     ScDocument& mrDoc;
    3150             :     SCCOL mnCol;
    3151             :     SCTAB mnTab;
    3152             : 
    3153             : public:
    3154          14 :     RemoveEmptyBroadcasterHandler( ScDocument& rDoc, SCCOL nCol, SCTAB nTab ) :
    3155          14 :         maSet(false), mrDoc(rDoc), mnCol(nCol), mnTab(nTab) {}
    3156             : 
    3157          20 :     void operator() ( size_t nRow, SvtBroadcaster* pBroadcaster )
    3158             :     {
    3159          20 :         if (!pBroadcaster->HasListeners())
    3160          16 :             maSet.set(mnTab, mnCol, nRow, true);
    3161          20 :     }
    3162             : 
    3163          14 :     void purge()
    3164             :     {
    3165          14 :         sc::PurgeListenerAction aAction(mrDoc);
    3166          14 :         maSet.executeAction(aAction);
    3167          14 :     }
    3168             : };
    3169             : 
    3170             : }
    3171             : 
    3172          14 : void ScColumn::TransferListeners(
    3173             :     ScColumn& rDestCol, SCROW nRow1, SCROW nRow2, SCROW nRowDelta )
    3174             : {
    3175          14 :     if (nRow2 < nRow1)
    3176           0 :         return;
    3177             : 
    3178          14 :     if (!ValidRow(nRow1) || !ValidRow(nRow2))
    3179           0 :         return;
    3180             : 
    3181          14 :     if (nRowDelta <= 0 && !ValidRow(nRow1+nRowDelta))
    3182           0 :         return;
    3183             : 
    3184          14 :     if (nRowDelta >= 0 && !ValidRow(nRow2+nRowDelta))
    3185           0 :         return;
    3186             : 
    3187             :     // Collect all listeners from the source broadcasters. The listeners will
    3188             :     // be removed from their broadcasters as they are collected.
    3189          14 :     TransferListenersHandler aFunc;
    3190          14 :     sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aFunc);
    3191             : 
    3192          28 :     TransferListenersHandler::ListenerListType aListenerList;
    3193          14 :     aFunc.swapListeners(aListenerList);
    3194             : 
    3195             :     // Re-register listeners with their destination broadcasters.
    3196          14 :     sc::BroadcasterStoreType::iterator itDestPos = rDestCol.maBroadcasters.begin();
    3197          14 :     TransferListenersHandler::ListenerListType::iterator it = aListenerList.begin(), itEnd = aListenerList.end();
    3198          34 :     for (; it != itEnd; ++it)
    3199             :     {
    3200          20 :         TransferListenersHandler::Entry& rEntry = *it;
    3201             : 
    3202          20 :         SCROW nDestRow = rEntry.mnRow + nRowDelta;
    3203             : 
    3204             :         sc::BroadcasterStoreType::position_type aPos =
    3205          20 :             rDestCol.maBroadcasters.position(itDestPos, nDestRow);
    3206             : 
    3207          20 :         itDestPos = aPos.first;
    3208          20 :         SvtBroadcaster* pDestBrd = NULL;
    3209          20 :         if (aPos.first->type == sc::element_type_broadcaster)
    3210             :         {
    3211             :             // Existing broadcaster.
    3212          20 :             pDestBrd = sc::broadcaster_block::at(*aPos.first->data, aPos.second);
    3213             :         }
    3214             :         else
    3215             :         {
    3216             :             // No existing broadcaster. Create a new one.
    3217             :             assert(aPos.first->type == sc::element_type_empty);
    3218           0 :             pDestBrd = new SvtBroadcaster;
    3219           0 :             itDestPos = rDestCol.maBroadcasters.set(itDestPos, nDestRow, pDestBrd);
    3220             :         }
    3221             : 
    3222             :         // Transfer all listeners from the source to the destination.
    3223          20 :         SvtBroadcaster::ListenersType::iterator it2 = rEntry.maListeners.begin(), it2End = rEntry.maListeners.end();
    3224          50 :         for (; it2 != it2End; ++it2)
    3225             :         {
    3226          30 :             SvtListener* pLis = *it2;
    3227          30 :             pLis->StartListening(*pDestBrd);
    3228             :         }
    3229             :     }
    3230             : 
    3231             :     // Remove any broadcasters that have no listeners.
    3232          28 :     RemoveEmptyBroadcasterHandler aFuncRemoveEmpty(*pDocument, nCol, nTab);
    3233          14 :     sc::ProcessBroadcaster(maBroadcasters.begin(), maBroadcasters, nRow1, nRow2, aFuncRemoveEmpty);
    3234          28 :     aFuncRemoveEmpty.purge();
    3235             : }
    3236             : 
    3237      909312 : void ScColumn::CalcAll()
    3238             : {
    3239             :     CalcAllHandler aFunc;
    3240      909312 :     sc::ProcessFormula(maCells, aFunc);
    3241      909312 : }
    3242             : 
    3243       63488 : void ScColumn::CompileAll( sc::CompileFormulaContext& rCxt )
    3244             : {
    3245       63488 :     CompileAllHandler aFunc(rCxt);
    3246       63488 :     sc::ProcessFormula(maCells, aFunc);
    3247       63488 : }
    3248             : 
    3249      591872 : void ScColumn::CompileXML( sc::CompileFormulaContext& rCxt, ScProgress& rProgress )
    3250             : {
    3251      591872 :     CompileXMLHandler aFunc(rCxt, rProgress, *this);
    3252      591872 :     sc::ProcessFormula(maCells, aFunc);
    3253      591872 :     RegroupFormulaCells();
    3254      591872 : }
    3255             : 
    3256           0 : bool ScColumn::CompileErrorCells( sc::CompileFormulaContext& rCxt, sal_uInt16 nErrCode )
    3257             : {
    3258           0 :     CompileErrorCellsHandler aHdl(rCxt, *this, nErrCode);
    3259           0 :     sc::ProcessFormula(maCells, aHdl);
    3260           0 :     return aHdl.isCompiled();
    3261             : }
    3262             : 
    3263      444416 : void ScColumn::CalcAfterLoad( sc::CompileFormulaContext& rCxt )
    3264             : {
    3265      444416 :     CalcAfterLoadHandler aFunc(rCxt);
    3266      444416 :     sc::ProcessFormula(maCells, aFunc);
    3267      444416 : }
    3268             : 
    3269       25204 : void ScColumn::ResetChanged( SCROW nStartRow, SCROW nEndRow )
    3270             : {
    3271             :     ResetChangedHandler aFunc;
    3272       25204 :     sc::ProcessFormula(maCells.begin(), maCells, nStartRow, nEndRow, aFunc);
    3273       25204 : }
    3274             : 
    3275     2510394 : bool ScColumn::HasEditCells(SCROW nStartRow, SCROW nEndRow, SCROW& rFirst)
    3276             : {
    3277             :     //  used in GetOptimalHeight - ambiguous script type counts as edit cell
    3278             : 
    3279     2510394 :     FindEditCellsHandler aFunc(*this);
    3280             :     std::pair<sc::CellStoreType::const_iterator,size_t> aPos =
    3281     2510394 :         sc::FindFormulaEditText(maCells, nStartRow, nEndRow, aFunc);
    3282             : 
    3283     2510394 :     if (aPos.first == maCells.end())
    3284     2510176 :         return false;
    3285             : 
    3286         218 :     rFirst = aPos.first->position + aPos.second;
    3287         218 :     return true;
    3288             : }
    3289             : 
    3290           0 : SCsROW ScColumn::SearchStyle(
    3291             :     SCsROW nRow, const ScStyleSheet* pSearchStyle, bool bUp, bool bInSelection,
    3292             :     const ScMarkData& rMark) const
    3293             : {
    3294           0 :     if (bInSelection)
    3295             :     {
    3296           0 :         if (rMark.IsMultiMarked())
    3297           0 :             return pAttrArray->SearchStyle(nRow, pSearchStyle, bUp, rMark.GetArray()+nCol);
    3298             :         else
    3299           0 :             return -1;
    3300             :     }
    3301             :     else
    3302           0 :         return pAttrArray->SearchStyle( nRow, pSearchStyle, bUp, NULL );
    3303             : }
    3304             : 
    3305           0 : bool ScColumn::SearchStyleRange(
    3306             :     SCsROW& rRow, SCsROW& rEndRow, const ScStyleSheet* pSearchStyle, bool bUp,
    3307             :     bool bInSelection, const ScMarkData& rMark) const
    3308             : {
    3309           0 :     if (bInSelection)
    3310             :     {
    3311           0 :         if (rMark.IsMultiMarked())
    3312             :             return pAttrArray->SearchStyleRange(
    3313           0 :                 rRow, rEndRow, pSearchStyle, bUp, rMark.GetArray() + nCol);
    3314             :         else
    3315           0 :             return false;
    3316             :     }
    3317             :     else
    3318           0 :         return pAttrArray->SearchStyleRange( rRow, rEndRow, pSearchStyle, bUp, NULL );
    3319         228 : }
    3320             : 
    3321             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10