LCOV - code coverage report
Current view: top level - sc/source/filter/excel - xetable.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 1040 1285 80.9 %
Date: 2015-06-13 12:38:46 Functions: 128 149 85.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 "xetable.hxx"
      21             : 
      22             : #include <map>
      23             : #include <com/sun/star/i18n/ScriptType.hpp>
      24             : #include "scitems.hxx"
      25             : #include <svl/intitem.hxx>
      26             : #include "document.hxx"
      27             : #include "dociter.hxx"
      28             : #include "olinetab.hxx"
      29             : #include "formulacell.hxx"
      30             : #include "patattr.hxx"
      31             : #include "attrib.hxx"
      32             : #include "xehelper.hxx"
      33             : #include "xecontent.hxx"
      34             : #include "xeescher.hxx"
      35             : #include "xeextlst.hxx"
      36             : #include "tokenarray.hxx"
      37             : #include <thread>
      38             : #include <comphelper/threadpool.hxx>
      39             : 
      40             : using namespace ::oox;
      41             : 
      42             : namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
      43             : 
      44             : // Helper records for cell records
      45             : 
      46           0 : XclExpStringRec::XclExpStringRec( const XclExpRoot& rRoot, const OUString& rResult ) :
      47             :     XclExpRecord( EXC_ID3_STRING ),
      48           0 :     mxResult( XclExpStringHelper::CreateString( rRoot, rResult ) )
      49             : {
      50             :     OSL_ENSURE( (rRoot.GetBiff() <= EXC_BIFF5) || (mxResult->Len() > 0),
      51             :         "XclExpStringRec::XclExpStringRec - empty result not allowed in BIFF8+" );
      52           0 :     SetRecSize( mxResult->GetSize() );
      53           0 : }
      54             : 
      55           0 : void XclExpStringRec::WriteBody( XclExpStream& rStrm )
      56             : {
      57           0 :     rStrm << *mxResult;
      58           0 : }
      59             : 
      60             : // Additional records for special formula ranges ==============================
      61             : 
      62         127 : XclExpRangeFmlaBase::XclExpRangeFmlaBase(
      63             :         sal_uInt16 nRecId, sal_uInt32 nRecSize, const ScAddress& rScPos ) :
      64             :     XclExpRecord( nRecId, nRecSize ),
      65             :     maXclRange( ScAddress::UNINITIALIZED ),
      66         127 :     maBaseXclPos( ScAddress::UNINITIALIZED )
      67             : {
      68         127 :     maBaseXclPos.Set( static_cast< sal_uInt16 >( rScPos.Col() ), static_cast< sal_uInt16 >( rScPos.Row() ) );
      69         127 :     maXclRange.maFirst = maXclRange.maLast = maBaseXclPos;
      70         127 : }
      71             : 
      72           3 : XclExpRangeFmlaBase::XclExpRangeFmlaBase(
      73             :         sal_uInt16 nRecId, sal_uInt32 nRecSize, const ScRange& rScRange ) :
      74             :     XclExpRecord( nRecId, nRecSize ),
      75             :     maXclRange( ScAddress::UNINITIALIZED ),
      76           3 :     maBaseXclPos( ScAddress::UNINITIALIZED )
      77             : {
      78             :     maXclRange.Set(
      79           3 :         static_cast< sal_uInt16 >( rScRange.aStart.Col() ),
      80           3 :         static_cast< sal_uInt16 >( rScRange.aStart.Row() ),
      81           3 :         static_cast< sal_uInt16 >( rScRange.aEnd.Col() ),
      82          12 :         static_cast< sal_uInt16 >( rScRange.aEnd.Row() ) );
      83           3 :     maBaseXclPos = maXclRange.maFirst;
      84           3 : }
      85             : 
      86         393 : bool XclExpRangeFmlaBase::IsBasePos( sal_uInt16 nXclCol, sal_uInt32 nXclRow ) const
      87             : {
      88         393 :     return (maBaseXclPos.mnCol == nXclCol) && (maBaseXclPos.mnRow == nXclRow);
      89             : }
      90             : 
      91         632 : void XclExpRangeFmlaBase::Extend( const ScAddress& rScPos )
      92             : {
      93         632 :     sal_uInt16 nXclCol = static_cast< sal_uInt16 >( rScPos.Col() );
      94         632 :     sal_uInt32 nXclRow = static_cast< sal_uInt32 >( rScPos.Row() );
      95         632 :     maXclRange.maFirst.mnCol = ::std::min( maXclRange.maFirst.mnCol, nXclCol );
      96         632 :     maXclRange.maFirst.mnRow = ::std::min( maXclRange.maFirst.mnRow, nXclRow );
      97         632 :     maXclRange.maLast.mnCol  = ::std::max( maXclRange.maLast.mnCol,  nXclCol );
      98         632 :     maXclRange.maLast.mnRow  = ::std::max( maXclRange.maLast.mnRow,  nXclRow );
      99         632 : }
     100             : 
     101          66 : void XclExpRangeFmlaBase::WriteRangeAddress( XclExpStream& rStrm ) const
     102             : {
     103          66 :     maXclRange.Write( rStrm, false );
     104          66 : }
     105             : 
     106             : // Array formulas =============================================================
     107             : 
     108           3 : XclExpArray::XclExpArray( XclTokenArrayRef xTokArr, const ScRange& rScRange ) :
     109           3 :     XclExpRangeFmlaBase( EXC_ID3_ARRAY, 14 + xTokArr->GetSize(), rScRange ),
     110           3 :     mxTokArr( xTokArr )
     111             : {
     112           3 : }
     113             : 
     114          16 : XclTokenArrayRef XclExpArray::CreateCellTokenArray( const XclExpRoot& rRoot ) const
     115             : {
     116          16 :     return rRoot.GetFormulaCompiler().CreateSpecialRefFormula( EXC_TOKID_EXP, maBaseXclPos );
     117             : }
     118             : 
     119          19 : bool XclExpArray::IsVolatile() const
     120             : {
     121          19 :     return mxTokArr->IsVolatile();
     122             : }
     123             : 
     124           3 : void XclExpArray::WriteBody( XclExpStream& rStrm )
     125             : {
     126           3 :     WriteRangeAddress( rStrm );
     127           3 :     sal_uInt16 nFlags = EXC_ARRAY_DEFAULTFLAGS;
     128           3 :     ::set_flag( nFlags, EXC_ARRAY_RECALC_ALWAYS, IsVolatile() );
     129           3 :     rStrm << nFlags << sal_uInt32( 0 ) << *mxTokArr;
     130           3 : }
     131             : 
     132         129 : XclExpArrayBuffer::XclExpArrayBuffer( const XclExpRoot& rRoot ) :
     133         129 :     XclExpRoot( rRoot )
     134             : {
     135         129 : }
     136             : 
     137           3 : XclExpArrayRef XclExpArrayBuffer::CreateArray( const ScTokenArray& rScTokArr, const ScRange& rScRange )
     138             : {
     139           3 :     const ScAddress& rScPos = rScRange.aStart;
     140           3 :     XclTokenArrayRef xTokArr = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_MATRIX, rScTokArr, &rScPos );
     141             : 
     142             :     OSL_ENSURE( maRecMap.find( rScPos ) == maRecMap.end(), "XclExpArrayBuffer::CreateArray - array exists already" );
     143           3 :     XclExpArrayRef& rxRec = maRecMap[ rScPos ];
     144           3 :     rxRec.reset( new XclExpArray( xTokArr, rScRange ) );
     145           3 :     return rxRec;
     146             : }
     147             : 
     148          13 : XclExpArrayRef XclExpArrayBuffer::FindArray( const ScTokenArray& rScTokArr, const ScAddress& rBasePos ) const
     149             : {
     150          13 :     XclExpArrayRef xRec;
     151             :     // try to extract a matrix reference token
     152          13 :     if (rScTokArr.GetLen() != 1)
     153             :         // Must consist of a single reference token.
     154           0 :         return xRec;
     155             : 
     156          13 :     const formula::FormulaToken* pToken = rScTokArr.GetArray()[0];
     157          13 :     if (!pToken || pToken->GetOpCode() != ocMatRef)
     158             :         // not a matrix reference token.
     159           0 :         return xRec;
     160             : 
     161          13 :     const ScSingleRefData& rRef = *pToken->GetSingleRef();
     162          13 :     ScAddress aAbsPos = rRef.toAbs(rBasePos);
     163          13 :     XclExpArrayMap::const_iterator it = maRecMap.find(aAbsPos);
     164             : 
     165          13 :     return (it == maRecMap.end()) ? xRec : xRec = it->second;
     166             : }
     167             : 
     168             : // Shared formulas ============================================================
     169             : 
     170         127 : XclExpShrfmla::XclExpShrfmla( XclTokenArrayRef xTokArr, const ScAddress& rScPos ) :
     171         127 :     XclExpRangeFmlaBase( EXC_ID_SHRFMLA, 10 + xTokArr->GetSize(), rScPos ),
     172             :     mxTokArr( xTokArr ),
     173         127 :     mnUsedCount( 1 )
     174             : {
     175         127 : }
     176             : 
     177         632 : void XclExpShrfmla::ExtendRange( const ScAddress& rScPos )
     178             : {
     179         632 :     Extend( rScPos );
     180         632 :     ++mnUsedCount;
     181         632 : }
     182             : 
     183         377 : XclTokenArrayRef XclExpShrfmla::CreateCellTokenArray( const XclExpRoot& rRoot ) const
     184             : {
     185         377 :     return rRoot.GetFormulaCompiler().CreateSpecialRefFormula( EXC_TOKID_EXP, maBaseXclPos );
     186             : }
     187             : 
     188         759 : bool XclExpShrfmla::IsVolatile() const
     189             : {
     190         759 :     return mxTokArr->IsVolatile();
     191             : }
     192             : 
     193          63 : void XclExpShrfmla::WriteBody( XclExpStream& rStrm )
     194             : {
     195          63 :     WriteRangeAddress( rStrm );
     196          63 :     rStrm << sal_uInt8( 0 ) << mnUsedCount << *mxTokArr;
     197          63 : }
     198             : 
     199         129 : XclExpShrfmlaBuffer::XclExpShrfmlaBuffer( const XclExpRoot& rRoot ) :
     200         129 :     XclExpRoot( rRoot )
     201             : {
     202         129 : }
     203             : 
     204         763 : bool XclExpShrfmlaBuffer::IsValidTokenArray( const ScTokenArray& rArray ) const
     205             : {
     206             :     using namespace formula;
     207             : 
     208         763 :     FormulaToken** pTokens = rArray.GetArray();
     209         763 :     sal_uInt16 nLen = rArray.GetLen();
     210        9611 :     for (sal_uInt16 i = 0; i < nLen; ++i)
     211             :     {
     212        8852 :         const FormulaToken* p = pTokens[i];
     213        8852 :         switch (p->GetType())
     214             :         {
     215             :             case svSingleRef:
     216             :             {
     217        1496 :                 const ScSingleRefData& rRefData = *p->GetSingleRef();
     218        1496 :                 if (!GetFormulaCompiler().IsRef2D(rRefData))
     219             :                     // Excel's shared formula cannot include 3D reference.
     220           4 :                     return false;
     221             :             }
     222        1492 :             break;
     223             :             case svDoubleRef:
     224             :             {
     225         238 :                 const ScComplexRefData& rRefData = *p->GetDoubleRef();
     226         238 :                 if (!GetFormulaCompiler().IsRef2D(rRefData))
     227             :                     // Excel's shared formula cannot include 3D reference.
     228           0 :                     return false;
     229             :             }
     230         238 :             break;
     231             :             case svExternalSingleRef:
     232             :             case svExternalDoubleRef:
     233             :             case svExternalName:
     234             :                 // External references aren't allowed.
     235           0 :                 return false;
     236             :             default:
     237             :                 ;
     238             :         }
     239             :     }
     240         759 :     return true;
     241             : }
     242             : 
     243        1095 : XclExpShrfmlaRef XclExpShrfmlaBuffer::CreateOrExtendShrfmla(
     244             :     const ScFormulaCell& rScCell, const ScAddress& rScPos )
     245             : {
     246        1095 :     XclExpShrfmlaRef xRec;
     247        1095 :     const ScTokenArray* pShrdScTokArr = rScCell.GetSharedCode();
     248        1095 :     if (!pShrdScTokArr)
     249             :         // This formula cell is not shared formula cell.
     250         308 :         return xRec;
     251             : 
     252             :     // Check to see if this shared formula contains any tokens that Excel's shared formula cannot handle.
     253         787 :     if (maBadTokens.count(pShrdScTokArr) > 0)
     254             :         // Already on the black list. Skip it.
     255          24 :         return xRec;
     256             : 
     257         763 :     if (!IsValidTokenArray(*pShrdScTokArr))
     258             :     {
     259             :         // We can't export this as shared formula.
     260           4 :         maBadTokens.insert(pShrdScTokArr);
     261           4 :         return xRec;
     262             :     }
     263             : 
     264         759 :     TokensType::iterator aIt = maRecMap.find(pShrdScTokArr);
     265         759 :     if( aIt == maRecMap.end() )
     266             :     {
     267             :         // create a new record
     268         127 :         XclTokenArrayRef xTokArr = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_SHARED, *pShrdScTokArr, &rScPos );
     269         127 :         xRec.reset( new XclExpShrfmla( xTokArr, rScPos ) );
     270         127 :         maRecMap[ pShrdScTokArr ] = xRec;
     271             :     }
     272             :     else
     273             :     {
     274             :         // extend existing record
     275             :         OSL_ENSURE( aIt->second, "XclExpShrfmlaBuffer::CreateOrExtendShrfmla - missing record" );
     276         632 :         xRec = aIt->second;
     277         632 :         xRec->ExtendRange( rScPos );
     278             :     }
     279             : 
     280         759 :     return xRec;
     281             : }
     282             : 
     283             : // Multiple operations ========================================================
     284             : 
     285           0 : XclExpTableop::XclExpTableop( const ScAddress& rScPos,
     286             :         const XclMultipleOpRefs& rRefs, sal_uInt8 nScMode ) :
     287             :     XclExpRangeFmlaBase( EXC_ID3_TABLEOP, 16, rScPos ),
     288           0 :     mnLastAppXclCol( static_cast< sal_uInt16 >( rScPos.Col() ) ),
     289           0 :     mnColInpXclCol( static_cast< sal_uInt16 >( rRefs.maColFirstScPos.Col() ) ),
     290           0 :     mnColInpXclRow( static_cast< sal_uInt16 >( rRefs.maColFirstScPos.Row() ) ),
     291           0 :     mnRowInpXclCol( static_cast< sal_uInt16 >( rRefs.maRowFirstScPos.Col() ) ),
     292           0 :     mnRowInpXclRow( static_cast< sal_uInt16 >( rRefs.maRowFirstScPos.Row() ) ),
     293             :     mnScMode( nScMode ),
     294           0 :     mbValid( false )
     295             : {
     296           0 : }
     297             : 
     298           0 : bool XclExpTableop::TryExtend( const ScAddress& rScPos, const XclMultipleOpRefs& rRefs )
     299             : {
     300           0 :     sal_uInt16 nXclCol = static_cast< sal_uInt16 >( rScPos.Col() );
     301           0 :     sal_uInt16 nXclRow = static_cast< sal_uInt16 >( rScPos.Row() );
     302             : 
     303           0 :     bool bOk = IsAppendable( nXclCol, nXclRow );
     304           0 :     if( bOk )
     305             :     {
     306           0 :         SCCOL nFirstScCol  = static_cast< SCCOL >( maXclRange.maFirst.mnCol );
     307           0 :         SCROW nFirstScRow  = static_cast< SCROW >( maXclRange.maFirst.mnRow );
     308           0 :         SCCOL nColInpScCol = static_cast< SCCOL >( mnColInpXclCol );
     309           0 :         SCROW nColInpScRow = static_cast< SCROW >( mnColInpXclRow );
     310           0 :         SCCOL nRowInpScCol = static_cast< SCCOL >( mnRowInpXclCol );
     311           0 :         SCROW nRowInpScRow = static_cast< SCROW >( mnRowInpXclRow );
     312             : 
     313           0 :         bOk =   ((mnScMode == 2) == rRefs.mbDblRefMode) &&
     314           0 :                 (rScPos.Tab() == rRefs.maFmlaScPos.Tab()) &&
     315           0 :                 (nColInpScCol == rRefs.maColFirstScPos.Col()) &&
     316           0 :                 (nColInpScRow == rRefs.maColFirstScPos.Row()) &&
     317           0 :                 (rScPos.Tab() == rRefs.maColFirstScPos.Tab()) &&
     318           0 :                 (rScPos.Tab() == rRefs.maColRelScPos.Tab());
     319             : 
     320           0 :         if( bOk ) switch( mnScMode )
     321             :         {
     322             :             case 0:
     323           0 :                 bOk =   (rScPos.Col() == rRefs.maFmlaScPos.Col()) &&
     324           0 :                         (nFirstScRow  == rRefs.maFmlaScPos.Row() + 1) &&
     325           0 :                         (nFirstScCol  == rRefs.maColRelScPos.Col() + 1) &&
     326           0 :                         (rScPos.Row() == rRefs.maColRelScPos.Row());
     327           0 :             break;
     328             :             case 1:
     329           0 :                 bOk =   (nFirstScCol  == rRefs.maFmlaScPos.Col() + 1) &&
     330           0 :                         (rScPos.Row() == rRefs.maFmlaScPos.Row()) &&
     331           0 :                         (rScPos.Col() == rRefs.maColRelScPos.Col()) &&
     332           0 :                         (nFirstScRow  == rRefs.maColRelScPos.Row() + 1);
     333           0 :             break;
     334             :             case 2:
     335           0 :                 bOk =   (nFirstScCol  == rRefs.maFmlaScPos.Col() + 1) &&
     336           0 :                         (nFirstScRow  == rRefs.maFmlaScPos.Row() + 1) &&
     337           0 :                         (nFirstScCol  == rRefs.maColRelScPos.Col() + 1) &&
     338           0 :                         (rScPos.Row() == rRefs.maColRelScPos.Row()) &&
     339           0 :                         (nRowInpScCol == rRefs.maRowFirstScPos.Col()) &&
     340           0 :                         (nRowInpScRow == rRefs.maRowFirstScPos.Row()) &&
     341           0 :                         (rScPos.Tab() == rRefs.maRowFirstScPos.Tab()) &&
     342           0 :                         (rScPos.Col() == rRefs.maRowRelScPos.Col()) &&
     343           0 :                         (nFirstScRow  == rRefs.maRowRelScPos.Row() + 1) &&
     344           0 :                         (rScPos.Tab() == rRefs.maRowRelScPos.Tab());
     345           0 :             break;
     346             :             default:
     347           0 :                 bOk = false;
     348             :         }
     349             : 
     350           0 :         if( bOk )
     351             :         {
     352             :             // extend the cell range
     353             :             OSL_ENSURE( IsAppendable( nXclCol, nXclRow ), "XclExpTableop::TryExtend - wrong cell address" );
     354           0 :             Extend( rScPos );
     355           0 :             mnLastAppXclCol = nXclCol;
     356             :         }
     357             :     }
     358             : 
     359           0 :     return bOk;
     360             : }
     361             : 
     362           0 : void XclExpTableop::Finalize()
     363             : {
     364             :     // is the range complete? (last appended cell is in last column)
     365           0 :     mbValid = maXclRange.maLast.mnCol == mnLastAppXclCol;
     366             :     // if last row is incomplete, try to shorten the used range
     367           0 :     if( !mbValid && (maXclRange.maFirst.mnRow < maXclRange.maLast.mnRow) )
     368             :     {
     369           0 :         --maXclRange.maLast.mnRow;
     370           0 :         mbValid = true;
     371             :     }
     372             : 
     373             :     // check if referred cells are outside of own range
     374           0 :     if( mbValid ) switch( mnScMode )
     375             :     {
     376             :         case 0:
     377           0 :             mbValid =   (mnColInpXclCol + 1 < maXclRange.maFirst.mnCol) || (mnColInpXclCol > maXclRange.maLast.mnCol) ||
     378           0 :                         (mnColInpXclRow     < maXclRange.maFirst.mnRow) || (mnColInpXclRow > maXclRange.maLast.mnRow);
     379           0 :         break;
     380             :         case 1:
     381           0 :             mbValid =   (mnColInpXclCol     < maXclRange.maFirst.mnCol) || (mnColInpXclCol > maXclRange.maLast.mnCol) ||
     382           0 :                         (mnColInpXclRow + 1 < maXclRange.maFirst.mnRow) || (mnColInpXclRow > maXclRange.maLast.mnRow);
     383           0 :         break;
     384             :         case 2:
     385           0 :             mbValid =   ((mnColInpXclCol + 1 < maXclRange.maFirst.mnCol) || (mnColInpXclCol > maXclRange.maLast.mnCol) ||
     386           0 :                          (mnColInpXclRow + 1 < maXclRange.maFirst.mnRow) || (mnColInpXclRow > maXclRange.maLast.mnRow)) &&
     387           0 :                         ((mnRowInpXclCol + 1 < maXclRange.maFirst.mnCol) || (mnRowInpXclCol > maXclRange.maLast.mnCol) ||
     388           0 :                          (mnRowInpXclRow + 1 < maXclRange.maFirst.mnRow) || (mnRowInpXclRow > maXclRange.maLast.mnRow));
     389           0 :         break;
     390             :     }
     391           0 : }
     392             : 
     393           0 : XclTokenArrayRef XclExpTableop::CreateCellTokenArray( const XclExpRoot& rRoot ) const
     394             : {
     395           0 :     XclExpFormulaCompiler& rFmlaComp = rRoot.GetFormulaCompiler();
     396             :     return mbValid ?
     397             :         rFmlaComp.CreateSpecialRefFormula( EXC_TOKID_TBL, maBaseXclPos ) :
     398           0 :         rFmlaComp.CreateErrorFormula( EXC_ERR_NA );
     399             : }
     400             : 
     401           0 : bool XclExpTableop::IsVolatile() const
     402             : {
     403           0 :     return true;
     404             : }
     405             : 
     406           0 : void XclExpTableop::Save( XclExpStream& rStrm )
     407             : {
     408           0 :     if( mbValid )
     409           0 :         XclExpRangeFmlaBase::Save( rStrm );
     410           0 : }
     411             : 
     412           0 : bool XclExpTableop::IsAppendable( sal_uInt16 nXclCol, sal_uInt16 nXclRow ) const
     413             : {
     414           0 :     return  ((nXclCol == mnLastAppXclCol + 1) && (nXclRow == maXclRange.maFirst.mnRow)) ||
     415           0 :             ((nXclCol == mnLastAppXclCol + 1) && (nXclCol <= maXclRange.maLast.mnCol) && (nXclRow == maXclRange.maLast.mnRow)) ||
     416           0 :             ((mnLastAppXclCol == maXclRange.maLast.mnCol) && (nXclCol == maXclRange.maFirst.mnCol) && (nXclRow == maXclRange.maLast.mnRow + 1));
     417             : }
     418             : 
     419           0 : void XclExpTableop::WriteBody( XclExpStream& rStrm )
     420             : {
     421           0 :     sal_uInt16 nFlags = EXC_TABLEOP_DEFAULTFLAGS;
     422           0 :     ::set_flag( nFlags, EXC_TABLEOP_RECALC_ALWAYS, IsVolatile() );
     423           0 :     switch( mnScMode )
     424             :     {
     425           0 :         case 1: ::set_flag( nFlags, EXC_TABLEOP_ROW );  break;
     426           0 :         case 2: ::set_flag( nFlags, EXC_TABLEOP_BOTH ); break;
     427             :     }
     428             : 
     429           0 :     WriteRangeAddress( rStrm );
     430           0 :     rStrm << nFlags;
     431           0 :     if( mnScMode == 2 )
     432           0 :         rStrm << mnRowInpXclRow << mnRowInpXclCol << mnColInpXclRow << mnColInpXclCol;
     433             :     else
     434           0 :         rStrm << mnColInpXclRow << mnColInpXclCol << sal_uInt32( 0 );
     435           0 : }
     436             : 
     437         129 : XclExpTableopBuffer::XclExpTableopBuffer( const XclExpRoot& rRoot ) :
     438         129 :     XclExpRoot( rRoot )
     439             : {
     440         129 : }
     441             : 
     442        1111 : XclExpTableopRef XclExpTableopBuffer::CreateOrExtendTableop(
     443             :         const ScTokenArray& rScTokArr, const ScAddress& rScPos )
     444             : {
     445        1111 :     XclExpTableopRef xRec;
     446             : 
     447             :     // try to extract cell references of a multiple operations formula
     448        1111 :     XclMultipleOpRefs aRefs;
     449        1111 :     if (XclTokenArrayHelper::GetMultipleOpRefs(aRefs, rScTokArr, rScPos))
     450             :     {
     451             :         // try to find an existing TABLEOP record for this cell position
     452           0 :         for( size_t nPos = 0, nSize = maTableopList.GetSize(); !xRec && (nPos < nSize); ++nPos )
     453             :         {
     454           0 :             XclExpTableopRef xTempRec = maTableopList.GetRecord( nPos );
     455           0 :             if( xTempRec->TryExtend( rScPos, aRefs ) )
     456           0 :                 xRec = xTempRec;
     457           0 :         }
     458             : 
     459             :         // no record found, or found record not extensible
     460           0 :         if( !xRec )
     461           0 :             xRec = TryCreate( rScPos, aRefs );
     462             :     }
     463             : 
     464        1111 :     return xRec;
     465             : }
     466             : 
     467         129 : void XclExpTableopBuffer::Finalize()
     468             : {
     469         129 :     for( size_t nPos = 0, nSize = maTableopList.GetSize(); nPos < nSize; ++nPos )
     470           0 :         maTableopList.GetRecord( nPos )->Finalize();
     471         129 : }
     472             : 
     473           0 : XclExpTableopRef XclExpTableopBuffer::TryCreate( const ScAddress& rScPos, const XclMultipleOpRefs& rRefs )
     474             : {
     475           0 :     sal_uInt8 nScMode = 0;
     476           0 :     bool bOk =  (rScPos.Tab() == rRefs.maFmlaScPos.Tab()) &&
     477           0 :                 (rScPos.Tab() == rRefs.maColFirstScPos.Tab()) &&
     478           0 :                 (rScPos.Tab() == rRefs.maColRelScPos.Tab());
     479             : 
     480           0 :     if( bOk )
     481             :     {
     482           0 :         if( rRefs.mbDblRefMode )
     483             :         {
     484           0 :             nScMode = 2;
     485           0 :             bOk =   (rScPos.Col() == rRefs.maFmlaScPos.Col() + 1) &&
     486           0 :                     (rScPos.Row() == rRefs.maFmlaScPos.Row() + 1) &&
     487           0 :                     (rScPos.Col() == rRefs.maColRelScPos.Col() + 1) &&
     488           0 :                     (rScPos.Row() == rRefs.maColRelScPos.Row()) &&
     489           0 :                     (rScPos.Tab() == rRefs.maRowFirstScPos.Tab()) &&
     490           0 :                     (rScPos.Col() == rRefs.maRowRelScPos.Col()) &&
     491           0 :                     (rScPos.Row() == rRefs.maRowRelScPos.Row() + 1) &&
     492           0 :                     (rScPos.Tab() == rRefs.maRowRelScPos.Tab());
     493             :         }
     494           0 :         else if( (rScPos.Col() == rRefs.maFmlaScPos.Col()) &&
     495           0 :                  (rScPos.Row() == rRefs.maFmlaScPos.Row() + 1) &&
     496           0 :                  (rScPos.Col() == rRefs.maColRelScPos.Col() + 1) &&
     497           0 :                  (rScPos.Row() == rRefs.maColRelScPos.Row()) )
     498             :         {
     499           0 :             nScMode = 0;
     500             :         }
     501           0 :         else if( (rScPos.Col() == rRefs.maFmlaScPos.Col() + 1) &&
     502           0 :                  (rScPos.Row() == rRefs.maFmlaScPos.Row()) &&
     503           0 :                  (rScPos.Col() == rRefs.maColRelScPos.Col()) &&
     504           0 :                  (rScPos.Row() == rRefs.maColRelScPos.Row() + 1) )
     505             :         {
     506           0 :             nScMode = 1;
     507             :         }
     508             :         else
     509             :         {
     510           0 :             bOk = false;
     511             :         }
     512             :     }
     513             : 
     514           0 :     XclExpTableopRef xRec;
     515           0 :     if( bOk )
     516             :     {
     517           0 :         xRec.reset( new XclExpTableop( rScPos, rRefs, nScMode ) );
     518           0 :         maTableopList.AppendRecord( xRec );
     519             :     }
     520             : 
     521           0 :     return xRec;
     522             : }
     523             : 
     524             : // Cell records
     525             : 
     526        4455 : XclExpCellBase::XclExpCellBase(
     527             :         sal_uInt16 nRecId, sal_Size nContSize, const XclAddress& rXclPos ) :
     528             :     XclExpRecord( nRecId, nContSize + 4 ),
     529        4455 :     maXclPos( rXclPos )
     530             : {
     531        4455 : }
     532             : 
     533           0 : bool XclExpCellBase::IsMultiLineText() const
     534             : {
     535           0 :     return false;
     536             : }
     537             : 
     538        1817 : bool XclExpCellBase::TryMerge( const XclExpCellBase& /*rCell*/ )
     539             : {
     540        1817 :     return false;
     541             : }
     542             : 
     543        2386 : void XclExpCellBase::GetBlankXFIndexes( ScfUInt16Vec& /*rXFIndexes*/ ) const
     544             : {
     545             :     // default: do nothing
     546        2386 : }
     547             : 
     548        2386 : void XclExpCellBase::RemoveUnusedBlankCells( const ScfUInt16Vec& /*rXFIndexes*/ )
     549             : {
     550             :     // default: do nothing
     551        2386 : }
     552             : 
     553             : // Single cell records ========================================================
     554             : 
     555        1560 : XclExpSingleCellBase::XclExpSingleCellBase(
     556             :         sal_uInt16 nRecId, sal_Size nContSize, const XclAddress& rXclPos, sal_uInt32 nXFId ) :
     557             :     XclExpCellBase( nRecId, 2, rXclPos ),
     558             :     maXFId( nXFId ),
     559        1560 :     mnContSize( nContSize )
     560             : {
     561        1560 : }
     562             : 
     563         233 : XclExpSingleCellBase::XclExpSingleCellBase( const XclExpRoot& rRoot,
     564             :         sal_uInt16 nRecId, sal_Size nContSize, const XclAddress& rXclPos,
     565             :         const ScPatternAttr* pPattern, sal_Int16 nScript, sal_uInt32 nForcedXFId ) :
     566             :     XclExpCellBase( nRecId, 2, rXclPos ),
     567             :     maXFId( nForcedXFId ),
     568         233 :     mnContSize( nContSize )
     569             : {
     570         233 :     if( GetXFId() == EXC_XFID_NOTFOUND )
     571         233 :         SetXFId( rRoot.GetXFBuffer().Insert( pPattern, nScript ) );
     572         233 : }
     573             : 
     574        2256 : sal_uInt16 XclExpSingleCellBase::GetLastXclCol() const
     575             : {
     576        2256 :     return GetXclCol();
     577             : }
     578             : 
     579         954 : sal_uInt32 XclExpSingleCellBase::GetFirstXFId() const
     580             : {
     581         954 :     return GetXFId();
     582             : }
     583             : 
     584        1793 : bool XclExpSingleCellBase::IsEmpty() const
     585             : {
     586        1793 :     return false;
     587             : }
     588             : 
     589        1793 : void XclExpSingleCellBase::ConvertXFIndexes( const XclExpRoot& rRoot )
     590             : {
     591        1793 :     maXFId.ConvertXFIndex( rRoot );
     592        1793 : }
     593             : 
     594         845 : void XclExpSingleCellBase::Save( XclExpStream& rStrm )
     595             : {
     596             :     OSL_ENSURE_BIFF( rStrm.GetRoot().GetBiff() >= EXC_BIFF3 );
     597         845 :     AddRecSize( mnContSize );
     598         845 :     XclExpCellBase::Save( rStrm );
     599         845 : }
     600             : 
     601         845 : void XclExpSingleCellBase::WriteBody( XclExpStream& rStrm )
     602             : {
     603         845 :     rStrm << static_cast<sal_uInt16> (GetXclRow()) << GetXclCol() << maXFId.mnXFIndex;
     604         845 :     WriteContents( rStrm );
     605         845 : }
     606             : 
     607          10 : IMPL_FIXEDMEMPOOL_NEWDEL( XclExpNumberCell )
     608             : 
     609         233 : XclExpNumberCell::XclExpNumberCell(
     610             :         const XclExpRoot& rRoot, const XclAddress& rXclPos,
     611             :         const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId, double fValue ) :
     612             :     // #i41210# always use latin script for number cells - may look wrong for special number formats...
     613             :     XclExpSingleCellBase( rRoot, EXC_ID3_NUMBER, 8, rXclPos, pPattern, ApiScriptType::LATIN, nForcedXFId ),
     614         233 :     mfValue( fValue )
     615             : {
     616         233 : }
     617             : 
     618        2030 : static OString lcl_GetStyleId( XclExpXmlStream& rStrm, sal_uInt32 nXFIndex )
     619             : {
     620        2030 :     return OString::number( rStrm.GetRoot().GetXFBuffer()
     621        2030 :             .GetXmlCellIndex( nXFIndex ) );
     622             : }
     623             : 
     624         948 : static OString lcl_GetStyleId( XclExpXmlStream& rStrm, const XclExpCellBase& rCell )
     625             : {
     626         948 :     sal_uInt32 nXFId    = rCell.GetFirstXFId();
     627         948 :     sal_uInt16 nXFIndex = rStrm.GetRoot().GetXFBuffer().GetXFIndex( nXFId );
     628         948 :     return lcl_GetStyleId( rStrm, nXFIndex );
     629             : }
     630             : 
     631         124 : void XclExpNumberCell::SaveXml( XclExpXmlStream& rStrm )
     632             : {
     633         124 :     sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
     634             :     rWorksheet->startElement( XML_c,
     635         124 :             XML_r,      XclXmlUtils::ToOString( rStrm.GetRoot().GetStringBuf(), GetXclPos() ).getStr(),
     636             :             XML_s,      lcl_GetStyleId( rStrm, *this ).getStr(),
     637             :             XML_t,      "n",
     638             :             // OOXTODO: XML_cm, XML_vm, XML_ph
     639         248 :             FSEND );
     640         124 :     rWorksheet->startElement( XML_v, FSEND );
     641         124 :     rWorksheet->write( mfValue );
     642         124 :     rWorksheet->endElement( XML_v );
     643         124 :     rWorksheet->endElement( XML_c );
     644         124 : }
     645             : 
     646         109 : void XclExpNumberCell::WriteContents( XclExpStream& rStrm )
     647             : {
     648         109 :     rStrm << mfValue;
     649         109 : }
     650             : 
     651          10 : IMPL_FIXEDMEMPOOL_NEWDEL( XclExpBooleanCell )
     652             : 
     653           0 : XclExpBooleanCell::XclExpBooleanCell(
     654             :         const XclExpRoot& rRoot, const XclAddress& rXclPos,
     655             :         const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId, bool bValue ) :
     656             :     // #i41210# always use latin script for boolean cells
     657             :     XclExpSingleCellBase( rRoot, EXC_ID3_BOOLERR, 2, rXclPos, pPattern, ApiScriptType::LATIN, nForcedXFId ),
     658           0 :     mbValue( bValue )
     659             : {
     660           0 : }
     661             : 
     662           0 : void XclExpBooleanCell::SaveXml( XclExpXmlStream& rStrm )
     663             : {
     664           0 :     sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
     665             :     rWorksheet->startElement( XML_c,
     666           0 :             XML_r,      XclXmlUtils::ToOString( rStrm.GetRoot().GetStringBuf(), GetXclPos() ).getStr(),
     667             :             XML_s,      lcl_GetStyleId( rStrm, *this ).getStr(),
     668             :             XML_t,      "b",
     669             :             // OOXTODO: XML_cm, XML_vm, XML_ph
     670           0 :             FSEND );
     671           0 :     rWorksheet->startElement( XML_v, FSEND );
     672           0 :     rWorksheet->write( mbValue ? "1" : "0" );
     673           0 :     rWorksheet->endElement( XML_v );
     674           0 :     rWorksheet->endElement( XML_c );
     675           0 : }
     676             : 
     677           0 : void XclExpBooleanCell::WriteContents( XclExpStream& rStrm )
     678             : {
     679           0 :     rStrm << sal_uInt16( mbValue ? 1 : 0 ) << EXC_BOOLERR_BOOL;
     680           0 : }
     681             : 
     682          10 : IMPL_FIXEDMEMPOOL_NEWDEL( XclExpLabelCell )
     683             : 
     684         447 : XclExpLabelCell::XclExpLabelCell(
     685             :         const XclExpRoot& rRoot, const XclAddress& rXclPos,
     686             :         const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId, const OUString& rStr ) :
     687         447 :     XclExpSingleCellBase( EXC_ID3_LABEL, 0, rXclPos, nForcedXFId )
     688             : {
     689         447 :     sal_uInt16 nMaxLen = (rRoot.GetBiff() == EXC_BIFF8) ? EXC_STR_MAXLEN : EXC_LABEL_MAXLEN;
     690             :     XclExpStringRef xText = XclExpStringHelper::CreateCellString(
     691         447 :         rRoot, rStr, pPattern, EXC_STR_DEFAULT, nMaxLen);
     692         447 :     Init( rRoot, pPattern, xText );
     693         447 : }
     694             : 
     695           2 : XclExpLabelCell::XclExpLabelCell(
     696             :         const XclExpRoot& rRoot, const XclAddress& rXclPos,
     697             :         const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId,
     698             :         const EditTextObject* pEditText, XclExpHyperlinkHelper& rLinkHelper ) :
     699           2 :     XclExpSingleCellBase( EXC_ID3_LABEL, 0, rXclPos, nForcedXFId )
     700             : {
     701           2 :     sal_uInt16 nMaxLen = (rRoot.GetBiff() == EXC_BIFF8) ? EXC_STR_MAXLEN : EXC_LABEL_MAXLEN;
     702             : 
     703           2 :     XclExpStringRef xText;
     704           2 :     if (pEditText)
     705           4 :         xText = XclExpStringHelper::CreateCellString(
     706           2 :             rRoot, *pEditText, pPattern, rLinkHelper, EXC_STR_DEFAULT, nMaxLen);
     707             :     else
     708           0 :         xText = XclExpStringHelper::CreateCellString(
     709           0 :             rRoot, EMPTY_OUSTRING, pPattern, EXC_STR_DEFAULT, nMaxLen);
     710             : 
     711           2 :     Init( rRoot, pPattern, xText );
     712           2 : }
     713             : 
     714           6 : bool XclExpLabelCell::IsMultiLineText() const
     715             : {
     716           6 :     return mbLineBreak || mxText->IsWrapped();
     717             : }
     718             : 
     719         449 : void XclExpLabelCell::Init( const XclExpRoot& rRoot,
     720             :         const ScPatternAttr* pPattern, XclExpStringRef xText )
     721             : {
     722             :     OSL_ENSURE( xText && xText->Len(), "XclExpLabelCell::XclExpLabelCell - empty string passed" );
     723         449 :     mxText = xText;
     724         449 :     mnSstIndex = 0;
     725             : 
     726             :     // create the cell format
     727         449 :     sal_uInt16 nXclFont = mxText->RemoveLeadingFont();
     728         449 :     if( GetXFId() == EXC_XFID_NOTFOUND )
     729             :     {
     730             :         OSL_ENSURE( nXclFont != EXC_FONT_NOTFOUND, "XclExpLabelCell::Init - leading font not found" );
     731         449 :         bool bForceLineBreak = mxText->IsWrapped();
     732         449 :         SetXFId( rRoot.GetXFBuffer().InsertWithFont( pPattern, ApiScriptType::WEAK, nXclFont, bForceLineBreak ) );
     733             :     }
     734             : 
     735             :     // get auto-wrap attribute from cell format
     736         449 :     const XclExpXF* pXF = rRoot.GetXFBuffer().GetXFById( GetXFId() );
     737         449 :     mbLineBreak = pXF && pXF->GetAlignmentData().mbLineBreak;
     738             : 
     739             :     // initialize the record contents
     740         449 :     switch( rRoot.GetBiff() )
     741             :     {
     742             :         case EXC_BIFF5:
     743             :             // BIFF5-BIFF7: create a LABEL or RSTRING record
     744             :             OSL_ENSURE( mxText->Len() <= EXC_LABEL_MAXLEN, "XclExpLabelCell::XclExpLabelCell - string too long" );
     745           0 :             SetContSize( mxText->GetSize() );
     746             :             // formatted string is exported in an RSTRING record
     747           0 :             if( mxText->IsRich() )
     748             :             {
     749             :                 OSL_ENSURE( mxText->GetFormatsCount() <= EXC_LABEL_MAXLEN, "XclExpLabelCell::WriteContents - too many formats" );
     750           0 :                 mxText->LimitFormatCount( EXC_LABEL_MAXLEN );
     751           0 :                 SetRecId( EXC_ID_RSTRING );
     752           0 :                 SetContSize( GetContSize() + 1 + 2 * mxText->GetFormatsCount() );
     753             :             }
     754           0 :         break;
     755             :         case EXC_BIFF8:
     756             :             // BIFF8+: create a LABELSST record
     757         449 :             mnSstIndex = rRoot.GetSst().Insert( xText );
     758         449 :             SetRecId( EXC_ID_LABELSST );
     759         449 :             SetContSize( 4 );
     760         449 :         break;
     761             :         default:    DBG_ERROR_BIFF();
     762             :     }
     763         449 : }
     764             : 
     765         275 : void XclExpLabelCell::SaveXml( XclExpXmlStream& rStrm )
     766             : {
     767         275 :     sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
     768             :     rWorksheet->startElement( XML_c,
     769         275 :             XML_r,      XclXmlUtils::ToOString( rStrm.GetRoot().GetStringBuf(), GetXclPos() ).getStr(),
     770             :             XML_s,      lcl_GetStyleId( rStrm, *this ).getStr(),
     771             :             XML_t,      "s",
     772             :             // OOXTODO: XML_cm, XML_vm, XML_ph
     773         550 :             FSEND );
     774         275 :     rWorksheet->startElement( XML_v, FSEND );
     775         275 :     rWorksheet->write( (sal_Int32) mnSstIndex );
     776         275 :     rWorksheet->endElement( XML_v );
     777         275 :     rWorksheet->endElement( XML_c );
     778         275 : }
     779             : 
     780         174 : void XclExpLabelCell::WriteContents( XclExpStream& rStrm )
     781             : {
     782         174 :     switch( rStrm.GetRoot().GetBiff() )
     783             :     {
     784             :         case EXC_BIFF5:
     785           0 :             rStrm << *mxText;
     786           0 :             if( mxText->IsRich() )
     787             :             {
     788           0 :                 rStrm << static_cast< sal_uInt8 >( mxText->GetFormatsCount() );
     789           0 :                 mxText->WriteFormats( rStrm );
     790             :             }
     791           0 :         break;
     792             :         case EXC_BIFF8:
     793         174 :             rStrm << mnSstIndex;
     794         174 :         break;
     795             :         default:    DBG_ERROR_BIFF();
     796             :     }
     797         174 : }
     798             : 
     799          10 : IMPL_FIXEDMEMPOOL_NEWDEL( XclExpFormulaCell )
     800             : 
     801        1111 : XclExpFormulaCell::XclExpFormulaCell(
     802             :         const XclExpRoot& rRoot, const XclAddress& rXclPos,
     803             :         const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId,
     804             :         const ScFormulaCell& rScFmlaCell,
     805             :         XclExpArrayBuffer& rArrayBfr,
     806             :         XclExpShrfmlaBuffer& rShrfmlaBfr,
     807             :         XclExpTableopBuffer& rTableopBfr ) :
     808             :     XclExpSingleCellBase( EXC_ID2_FORMULA, 0, rXclPos, nForcedXFId ),
     809        1111 :     mrScFmlaCell( const_cast< ScFormulaCell& >( rScFmlaCell ) )
     810             : {
     811             :     // *** Find result number format overwriting cell number format *** -------
     812             : 
     813        1111 :     if( GetXFId() == EXC_XFID_NOTFOUND )
     814             :     {
     815        1111 :         SvNumberFormatter& rFormatter = rRoot.GetFormatter();
     816        1111 :         XclExpNumFmtBuffer& rNumFmtBfr = rRoot.GetNumFmtBuffer();
     817             : 
     818             :         // current cell number format
     819             :         sal_uLong nScNumFmt = pPattern ?
     820         363 :             GETITEMVALUE( pPattern->GetItemSet(), SfxUInt32Item, ATTR_VALUE_FORMAT, sal_uLong ) :
     821        1474 :             rNumFmtBfr.GetStandardFormat();
     822             : 
     823             :         // alternative number format passed to XF buffer
     824        1111 :         sal_uLong nAltScNumFmt = NUMBERFORMAT_ENTRY_NOT_FOUND;
     825             :         /*  Xcl doesn't know Boolean number formats, we write
     826             :             "TRUE";"FALSE" (language dependent). Don't do it for automatic
     827             :             formula formats, because Excel gets them right. */
     828             :         /*  #i8640# Don't set text format, if we have string results. */
     829        1111 :         short nFormatType = mrScFmlaCell.GetFormatType();
     830        1111 :         if( ((nScNumFmt % SV_COUNTRY_LANGUAGE_OFFSET) == 0) &&
     831         952 :                 (nFormatType != css::util::NumberFormat::LOGICAL) &&
     832             :                 (nFormatType != css::util::NumberFormat::TEXT) )
     833         952 :             nAltScNumFmt = nScNumFmt;
     834             :         /*  If cell number format is Boolean and automatic formula
     835             :             format is Boolean don't write that ugly special format. */
     836         160 :         else if( (nFormatType == css::util::NumberFormat::LOGICAL) &&
     837           1 :                 (rFormatter.GetType( nScNumFmt ) == css::util::NumberFormat::LOGICAL) )
     838           0 :             nAltScNumFmt = rNumFmtBfr.GetStandardFormat();
     839             : 
     840             :         // #i41420# find script type according to result type (always latin for numeric results)
     841        1111 :         sal_Int16 nScript = ApiScriptType::LATIN;
     842        1111 :         bool bForceLineBreak = false;
     843        1111 :         if( nFormatType == css::util::NumberFormat::TEXT )
     844             :         {
     845           0 :             OUString aResult = mrScFmlaCell.GetString().getString();
     846           0 :             bForceLineBreak = mrScFmlaCell.IsMultilineResult();
     847           0 :             nScript = XclExpStringHelper::GetLeadingScriptType( rRoot, aResult );
     848             :         }
     849        1111 :         SetXFId( rRoot.GetXFBuffer().InsertWithNumFmt( pPattern, nScript, nAltScNumFmt, bForceLineBreak ) );
     850             :     }
     851             : 
     852             :     // *** Convert the formula token array *** --------------------------------
     853             : 
     854        1111 :     ScAddress aScPos( static_cast< SCCOL >( rXclPos.mnCol ), static_cast< SCROW >( rXclPos.mnRow ), rRoot.GetCurrScTab() );
     855        1111 :     const ScTokenArray& rScTokArr = *mrScFmlaCell.GetCode();
     856             : 
     857             :     // first try to create multiple operations
     858        1111 :     mxAddRec = rTableopBfr.CreateOrExtendTableop( rScTokArr, aScPos );
     859             : 
     860             :     // no multiple operation found - try to create matrix formula
     861        1111 :     if( !mxAddRec ) switch( static_cast< ScMatrixMode >( mrScFmlaCell.GetMatrixFlag() ) )
     862             :     {
     863             :         case MM_FORMULA:
     864             :         {
     865             :             // origin of the matrix - find the used matrix range
     866             :             SCCOL nMatWidth;
     867             :             SCROW nMatHeight;
     868           3 :             mrScFmlaCell.GetMatColsRows( nMatWidth, nMatHeight );
     869             :             OSL_ENSURE( nMatWidth && nMatHeight, "XclExpFormulaCell::XclExpFormulaCell - empty matrix" );
     870           3 :             ScRange aMatScRange( aScPos );
     871           3 :             ScAddress& rMatEnd = aMatScRange.aEnd;
     872           3 :             rMatEnd.IncCol( static_cast< SCsCOL >( nMatWidth - 1 ) );
     873           3 :             rMatEnd.IncRow( static_cast< SCsROW >( nMatHeight - 1 ) );
     874             :             // reduce to valid range (range keeps valid, because start position IS valid)
     875           3 :             rRoot.GetAddressConverter().ValidateRange( aMatScRange, true );
     876             :             // create the ARRAY record
     877           3 :             mxAddRec = rArrayBfr.CreateArray( rScTokArr, aMatScRange );
     878             :         }
     879           3 :         break;
     880             :         case MM_REFERENCE:
     881             :         {
     882             :             // other formula cell covered by a matrix - find the ARRAY record
     883          13 :             mxAddRec = rArrayBfr.FindArray(rScTokArr, aScPos);
     884             :             // should always be found, if Calc document is not broken
     885             :             OSL_ENSURE( mxAddRec, "XclExpFormulaCell::XclExpFormulaCell - no matrix found" );
     886             :         }
     887          13 :         break;
     888             :         default:;
     889             :     }
     890             : 
     891             :     // no matrix found - try to create shared formula
     892        1111 :     if( !mxAddRec )
     893        1095 :         mxAddRec = rShrfmlaBfr.CreateOrExtendShrfmla(mrScFmlaCell, aScPos);
     894             : 
     895             :     // no shared formula found - create a simple cell formula
     896        1111 :     if( !mxAddRec )
     897         336 :         mxTokArr = rRoot.GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CELL, rScTokArr, &aScPos );
     898        1111 : }
     899             : 
     900         562 : void XclExpFormulaCell::Save( XclExpStream& rStrm )
     901             : {
     902             :     // create token array for FORMULA cells with additional record
     903         562 :     if( mxAddRec )
     904         393 :         mxTokArr = mxAddRec->CreateCellTokenArray( rStrm.GetRoot() );
     905             : 
     906             :     // FORMULA record itself
     907             :     OSL_ENSURE( mxTokArr, "XclExpFormulaCell::Save - missing token array" );
     908         562 :     if( !mxTokArr )
     909           0 :         mxTokArr = rStrm.GetRoot().GetFormulaCompiler().CreateErrorFormula( EXC_ERR_NA );
     910         562 :     SetContSize( 16 + mxTokArr->GetSize() );
     911         562 :     XclExpSingleCellBase::Save( rStrm );
     912             : 
     913             :     // additional record (ARRAY, SHRFMLA, or TABLEOP), only for first FORMULA record
     914         562 :     if( mxAddRec && mxAddRec->IsBasePos( GetXclCol(), GetXclRow() ) )
     915          66 :         mxAddRec->Save( rStrm );
     916             : 
     917             :     // STRING record for string result
     918         562 :     if( mxStringRec )
     919           0 :         mxStringRec->Save( rStrm );
     920         562 : }
     921             : 
     922         549 : void XclExpFormulaCell::SaveXml( XclExpXmlStream& rStrm )
     923             : {
     924         549 :     const char* sType = NULL;
     925         549 :     OUString    sValue;
     926         549 :     XclXmlUtils::GetFormulaTypeAndValue( mrScFmlaCell, sType, sValue );
     927         549 :     sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
     928             :     rWorksheet->startElement( XML_c,
     929         549 :             XML_r,      XclXmlUtils::ToOString( rStrm.GetRoot().GetStringBuf(), GetXclPos() ).getStr(),
     930             :             XML_s,      lcl_GetStyleId( rStrm, *this ).getStr(),
     931             :             XML_t,      sType,
     932             :             // OOXTODO: XML_cm, XML_vm, XML_ph
     933        1098 :             FSEND );
     934             : 
     935             :     rWorksheet->startElement( XML_f,
     936             :             // OOXTODO: XML_t,      ST_CellFormulaType
     937         549 :             XML_aca,    XclXmlUtils::ToPsz( (mxTokArr && mxTokArr->IsVolatile()) || (mxAddRec && mxAddRec->IsVolatile()) ),
     938             :             // OOXTODO: XML_ref,    ST_Ref
     939             :             // OOXTODO: XML_dt2D,   bool
     940             :             // OOXTODO: XML_dtr,    bool
     941             :             // OOXTODO: XML_del1,   bool
     942             :             // OOXTODO: XML_del2,   bool
     943             :             // OOXTODO: XML_r1,     ST_CellRef
     944             :             // OOXTODO: XML_r2,     ST_CellRef
     945             :             // OOXTODO: XML_ca,     bool
     946             :             // OOXTODO: XML_si,     uint
     947             :             // OOXTODO: XML_bx      bool
     948         549 :             FSEND );
     949             :     rWorksheet->writeEscaped( XclXmlUtils::ToOUString(
     950         549 :         rStrm.GetRoot().GetCompileFormulaContext(), mrScFmlaCell.aPos, mrScFmlaCell.GetCode()));
     951         549 :     rWorksheet->endElement( XML_f );
     952         549 :     if( strcmp( sType, "inlineStr" ) == 0 )
     953             :     {
     954           0 :         rWorksheet->startElement( XML_is, FSEND );
     955           0 :         rWorksheet->startElement( XML_t, FSEND );
     956           0 :         rWorksheet->writeEscaped( sValue );
     957           0 :         rWorksheet->endElement( XML_t );
     958           0 :         rWorksheet->endElement( XML_is );
     959             :     }
     960             :     else
     961             :     {
     962         549 :         rWorksheet->startElement( XML_v, FSEND );
     963         549 :         rWorksheet->writeEscaped( sValue );
     964         549 :         rWorksheet->endElement( XML_v );
     965             :     }
     966         549 :     rWorksheet->endElement( XML_c );
     967         549 : }
     968             : 
     969         562 : void XclExpFormulaCell::WriteContents( XclExpStream& rStrm )
     970             : {
     971         562 :     sal_uInt16 nScErrCode = mrScFmlaCell.GetErrCode();
     972         562 :     if( nScErrCode )
     973             :     {
     974           1 :         rStrm << EXC_FORMULA_RES_ERROR << sal_uInt8( 0 )
     975           2 :             << XclTools::GetXclErrorCode( nScErrCode )
     976           1 :             << sal_uInt8( 0 ) << sal_uInt16( 0 )
     977           1 :             << sal_uInt16( 0xFFFF );
     978             :     }
     979             :     else
     980             :     {
     981             :         // result of the formula
     982         561 :         switch( mrScFmlaCell.GetFormatType() )
     983             :         {
     984             :             case css::util::NumberFormat::NUMBER:
     985             :                 {
     986             :                     // either value or error code
     987         560 :                     rStrm << mrScFmlaCell.GetValue();
     988             :                 }
     989         560 :                 break;
     990             : 
     991             :             case css::util::NumberFormat::TEXT:
     992             :                 {
     993           0 :                     OUString aResult = mrScFmlaCell.GetString().getString();
     994           0 :                     if( !aResult.isEmpty() || (rStrm.GetRoot().GetBiff() <= EXC_BIFF5) )
     995             :                     {
     996           0 :                         rStrm << EXC_FORMULA_RES_STRING;
     997           0 :                         mxStringRec.reset( new XclExpStringRec( rStrm.GetRoot(), aResult ) );
     998             :                     }
     999             :                     else
    1000           0 :                         rStrm << EXC_FORMULA_RES_EMPTY;     // BIFF8 only
    1001           0 :                     rStrm << sal_uInt8( 0 ) << sal_uInt32( 0 ) << sal_uInt16( 0xFFFF );
    1002             :                 }
    1003           0 :                 break;
    1004             : 
    1005             :             case css::util::NumberFormat::LOGICAL:
    1006             :                 {
    1007           1 :                     sal_uInt8 nXclValue = (mrScFmlaCell.GetValue() == 0.0) ? 0 : 1;
    1008           1 :                     rStrm << EXC_FORMULA_RES_BOOL << sal_uInt8( 0 )
    1009           2 :                         << nXclValue << sal_uInt8( 0 ) << sal_uInt16( 0 )
    1010           1 :                         << sal_uInt16( 0xFFFF );
    1011             :                 }
    1012           1 :                 break;
    1013             : 
    1014             :             default:
    1015           0 :                 rStrm << mrScFmlaCell.GetValue();
    1016             :         }
    1017             :     }
    1018             : 
    1019             :     // flags and formula token array
    1020         562 :     sal_uInt16 nFlags = EXC_FORMULA_DEFAULTFLAGS;
    1021         562 :     ::set_flag( nFlags, EXC_FORMULA_RECALC_ALWAYS, mxTokArr->IsVolatile() || (mxAddRec && mxAddRec->IsVolatile()) );
    1022         562 :     ::set_flag( nFlags, EXC_FORMULA_SHARED, mxAddRec && (mxAddRec->GetRecId() == EXC_ID_SHRFMLA) );
    1023         562 :     rStrm << nFlags << sal_uInt32( 0 ) << *mxTokArr;
    1024         562 : }
    1025             : 
    1026             : // Multiple cell records ======================================================
    1027             : 
    1028        2662 : XclExpMultiCellBase::XclExpMultiCellBase(
    1029             :         sal_uInt16 nRecId, sal_uInt16 nMulRecId, sal_Size nContSize, const XclAddress& rXclPos ) :
    1030             :     XclExpCellBase( nRecId, 0, rXclPos ),
    1031             :     mnMulRecId( nMulRecId ),
    1032        2662 :     mnContSize( nContSize )
    1033             : {
    1034        2662 : }
    1035             : 
    1036        5242 : sal_uInt16 XclExpMultiCellBase::GetLastXclCol() const
    1037             : {
    1038        5242 :     return GetXclCol() + GetCellCount() - 1;
    1039             : }
    1040             : 
    1041           0 : sal_uInt32 XclExpMultiCellBase::GetFirstXFId() const
    1042             : {
    1043           0 :     return maXFIds.empty() ? XclExpXFBuffer::GetDefCellXFId() : maXFIds.front().mnXFId;
    1044             : }
    1045             : 
    1046        1823 : bool XclExpMultiCellBase::IsEmpty() const
    1047             : {
    1048        1823 :     return maXFIds.empty();
    1049             : }
    1050             : 
    1051        1053 : void XclExpMultiCellBase::ConvertXFIndexes( const XclExpRoot& rRoot )
    1052             : {
    1053        2604 :     for( XclExpMultiXFIdDeq::iterator aIt = maXFIds.begin(), aEnd = maXFIds.end(); aIt != aEnd; ++aIt )
    1054        1551 :         aIt->ConvertXFIndex( rRoot );
    1055        1053 : }
    1056             : 
    1057         280 : void XclExpMultiCellBase::Save( XclExpStream& rStrm )
    1058             : {
    1059             :     OSL_ENSURE_BIFF( rStrm.GetRoot().GetBiff() >= EXC_BIFF3 );
    1060             : 
    1061         280 :     XclExpMultiXFIdDeq::const_iterator aEnd = maXFIds.end();
    1062         280 :     XclExpMultiXFIdDeq::const_iterator aRangeBeg = maXFIds.begin();
    1063         280 :     XclExpMultiXFIdDeq::const_iterator aRangeEnd = aRangeBeg;
    1064         280 :     sal_uInt16 nBegXclCol = GetXclCol();
    1065         280 :     sal_uInt16 nEndXclCol = nBegXclCol;
    1066             : 
    1067         853 :     while( aRangeEnd != aEnd )
    1068             :     {
    1069             :         // find begin of next used XF range
    1070         293 :         aRangeBeg = aRangeEnd;
    1071         293 :         nBegXclCol = nEndXclCol;
    1072         599 :         while( (aRangeBeg != aEnd) && (aRangeBeg->mnXFIndex == EXC_XF_NOTFOUND) )
    1073             :         {
    1074          13 :             nBegXclCol = nBegXclCol + aRangeBeg->mnCount;
    1075          13 :             ++aRangeBeg;
    1076             :         }
    1077             :         // find end of next used XF range
    1078         293 :         aRangeEnd = aRangeBeg;
    1079         293 :         nEndXclCol = nBegXclCol;
    1080        1047 :         while( (aRangeEnd != aEnd) && (aRangeEnd->mnXFIndex != EXC_XF_NOTFOUND) )
    1081             :         {
    1082         461 :             nEndXclCol = nEndXclCol + aRangeEnd->mnCount;
    1083         461 :             ++aRangeEnd;
    1084             :         }
    1085             : 
    1086             :         // export this range as a record
    1087         293 :         if( aRangeBeg != aRangeEnd )
    1088             :         {
    1089         293 :             sal_uInt16 nCount = nEndXclCol - nBegXclCol;
    1090         293 :             bool bIsMulti = nCount > 1;
    1091         293 :             sal_Size nTotalSize = GetRecSize() + (2 + mnContSize) * nCount;
    1092         293 :             if( bIsMulti ) nTotalSize += 2;
    1093             : 
    1094         293 :             rStrm.StartRecord( bIsMulti ? mnMulRecId : GetRecId(), nTotalSize );
    1095         293 :             rStrm << static_cast<sal_uInt16> (GetXclRow()) << nBegXclCol;
    1096             : 
    1097         293 :             sal_uInt16 nRelCol = nBegXclCol - GetXclCol();
    1098         754 :             for( XclExpMultiXFIdDeq::const_iterator aIt = aRangeBeg; aIt != aRangeEnd; ++aIt )
    1099             :             {
    1100        1057 :                 for( sal_uInt16 nIdx = 0; nIdx < aIt->mnCount; ++nIdx )
    1101             :                 {
    1102         596 :                     rStrm << aIt->mnXFIndex;
    1103         596 :                     WriteContents( rStrm, nRelCol );
    1104         596 :                     ++nRelCol;
    1105             :                 }
    1106             :             }
    1107         293 :             if( bIsMulti )
    1108         118 :                 rStrm << static_cast< sal_uInt16 >( nEndXclCol - 1 );
    1109         293 :             rStrm.EndRecord();
    1110             :         }
    1111             :     }
    1112         280 : }
    1113             : 
    1114         570 : void XclExpMultiCellBase::SaveXml( XclExpXmlStream& rStrm )
    1115             : {
    1116         570 :     XclExpMultiXFIdDeq::const_iterator aEnd = maXFIds.end();
    1117         570 :     XclExpMultiXFIdDeq::const_iterator aRangeBeg = maXFIds.begin();
    1118         570 :     XclExpMultiXFIdDeq::const_iterator aRangeEnd = aRangeBeg;
    1119         570 :     sal_uInt16 nBegXclCol = GetXclCol();
    1120         570 :     sal_uInt16 nEndXclCol = nBegXclCol;
    1121             : 
    1122        1711 :     while( aRangeEnd != aEnd )
    1123             :     {
    1124             :         // find begin of next used XF range
    1125         571 :         aRangeBeg = aRangeEnd;
    1126         571 :         nBegXclCol = nEndXclCol;
    1127        1143 :         while( (aRangeBeg != aEnd) && (aRangeBeg->mnXFIndex == EXC_XF_NOTFOUND) )
    1128             :         {
    1129           1 :             nBegXclCol = nBegXclCol + aRangeBeg->mnCount;
    1130           1 :             ++aRangeBeg;
    1131             :         }
    1132             :         // find end of next used XF range
    1133         571 :         aRangeEnd = aRangeBeg;
    1134         571 :         nEndXclCol = nBegXclCol;
    1135        1955 :         while( (aRangeEnd != aEnd) && (aRangeEnd->mnXFIndex != EXC_XF_NOTFOUND) )
    1136             :         {
    1137         813 :             nEndXclCol = nEndXclCol + aRangeEnd->mnCount;
    1138         813 :             ++aRangeEnd;
    1139             :         }
    1140             : 
    1141             :         // export this range as a record
    1142         571 :         if( aRangeBeg != aRangeEnd )
    1143             :         {
    1144         571 :             sal_uInt16 nRelColIdx = nBegXclCol - GetXclCol();
    1145         571 :             sal_Int32  nRelCol    = 0;
    1146        1384 :             for( XclExpMultiXFIdDeq::const_iterator aIt = aRangeBeg; aIt != aRangeEnd; ++aIt )
    1147             :             {
    1148        1760 :                 for( sal_uInt16 nIdx = 0; nIdx < aIt->mnCount; ++nIdx )
    1149             :                 {
    1150             :                     WriteXmlContents(
    1151             :                             rStrm,
    1152             :                             XclAddress( static_cast<sal_uInt16>(nBegXclCol + nRelCol), GetXclRow() ),
    1153         947 :                             aIt->mnXFIndex,
    1154        1894 :                             nRelColIdx );
    1155         947 :                     ++nRelCol;
    1156         947 :                     ++nRelColIdx;
    1157             :                 }
    1158             :             }
    1159             :         }
    1160             :     }
    1161         570 : }
    1162             : 
    1163        5242 : sal_uInt16 XclExpMultiCellBase::GetCellCount() const
    1164             : {
    1165        5242 :     sal_uInt16 nCount = 0;
    1166       14173 :     for( XclExpMultiXFIdDeq::const_iterator aIt = maXFIds.begin(), aEnd = maXFIds.end(); aIt != aEnd; ++aIt )
    1167        8931 :         nCount = nCount + aIt->mnCount;
    1168        5242 :     return nCount;
    1169             : }
    1170             : 
    1171      512383 : void XclExpMultiCellBase::AppendXFId( const XclExpMultiXFId& rXFId )
    1172             : {
    1173      512383 :     if( maXFIds.empty() || (maXFIds.back().mnXFId != rXFId.mnXFId) )
    1174        4214 :         maXFIds.push_back( rXFId );
    1175             :     else
    1176      508169 :         maXFIds.back().mnCount = maXFIds.back().mnCount + rXFId.mnCount;
    1177      512383 : }
    1178             : 
    1179        1551 : void XclExpMultiCellBase::AppendXFId( const XclExpRoot& rRoot,
    1180             :         const ScPatternAttr* pPattern, sal_uInt16 nScript, sal_uInt32 nForcedXFId, sal_uInt16 nCount )
    1181             : {
    1182             :     sal_uInt32 nXFId = (nForcedXFId == EXC_XFID_NOTFOUND) ?
    1183        1551 :         rRoot.GetXFBuffer().Insert( pPattern, nScript ) : nForcedXFId;
    1184        1551 :     AppendXFId( XclExpMultiXFId( nXFId, nCount ) );
    1185        1551 : }
    1186             : 
    1187        1010 : bool XclExpMultiCellBase::TryMergeXFIds( const XclExpMultiCellBase& rCell )
    1188             : {
    1189        1010 :     if( GetLastXclCol() + 1 == rCell.GetXclCol() )
    1190             :     {
    1191         839 :         maXFIds.insert( maXFIds.end(), rCell.maXFIds.begin(), rCell.maXFIds.end() );
    1192         839 :         return true;
    1193             :     }
    1194         171 :     return false;
    1195             : }
    1196             : 
    1197         460 : void XclExpMultiCellBase::GetXFIndexes( ScfUInt16Vec& rXFIndexes ) const
    1198             : {
    1199             :     OSL_ENSURE( GetLastXclCol() < rXFIndexes.size(), "XclExpMultiCellBase::GetXFIndexes - vector too small" );
    1200         460 :     ScfUInt16Vec::iterator aDestIt = rXFIndexes.begin() + GetXclCol();
    1201        1013 :     for( XclExpMultiXFIdDeq::const_iterator aIt = maXFIds.begin(), aEnd = maXFIds.end(); aIt != aEnd; ++aIt )
    1202             :     {
    1203         553 :         ::std::fill( aDestIt, aDestIt + aIt->mnCount, aIt->mnXFIndex );
    1204         553 :         aDestIt += aIt->mnCount;
    1205             :     }
    1206         460 : }
    1207             : 
    1208        1230 : void XclExpMultiCellBase::RemoveUnusedXFIndexes( const ScfUInt16Vec& rXFIndexes )
    1209             : {
    1210             :     // save last column before calling maXFIds.clear()
    1211        1230 :     sal_uInt16 nLastXclCol = GetLastXclCol();
    1212             :     OSL_ENSURE( nLastXclCol < rXFIndexes.size(), "XclExpMultiCellBase::RemoveUnusedXFIndexes - XF index vector too small" );
    1213             : 
    1214             :     // build new XF index vector, containing passed XF indexes
    1215        1230 :     maXFIds.clear();
    1216        1230 :     XclExpMultiXFId aXFId( 0 );
    1217      510951 :     for( ScfUInt16Vec::const_iterator aIt = rXFIndexes.begin() + GetXclCol(), aEnd = rXFIndexes.begin() + nLastXclCol + 1; aIt != aEnd; ++aIt )
    1218             :     {
    1219             :         // AppendXFId() tests XclExpXFIndex::mnXFId, set it too
    1220      509721 :         aXFId.mnXFId = aXFId.mnXFIndex = *aIt;
    1221      509721 :         AppendXFId( aXFId );
    1222             :     }
    1223             : 
    1224             :     // remove leading and trailing unused XF indexes
    1225        1230 :     if( !maXFIds.empty() && (maXFIds.front().mnXFIndex == EXC_XF_NOTFOUND) )
    1226             :     {
    1227        1064 :         SetXclCol( GetXclCol() + maXFIds.front().mnCount );
    1228        1064 :         maXFIds.erase(maXFIds.begin(), maXFIds.begin() + 1);
    1229             :     }
    1230        1230 :     if( !maXFIds.empty() && (maXFIds.back().mnXFIndex == EXC_XF_NOTFOUND) )
    1231         198 :         maXFIds.pop_back();
    1232             : 
    1233             :     // The Save() function will skip all XF indexes equal to EXC_XF_NOTFOUND.
    1234        1230 : }
    1235             : 
    1236          10 : IMPL_FIXEDMEMPOOL_NEWDEL( XclExpBlankCell )
    1237             : 
    1238        1111 : XclExpBlankCell::XclExpBlankCell( const XclAddress& rXclPos, const XclExpMultiXFId& rXFId ) :
    1239        1111 :     XclExpMultiCellBase( EXC_ID3_BLANK, EXC_ID_MULBLANK, 0, rXclPos )
    1240             : {
    1241             :     OSL_ENSURE( rXFId.mnCount > 0, "XclExpBlankCell::XclExpBlankCell - invalid count" );
    1242        1111 :     AppendXFId( rXFId );
    1243        1111 : }
    1244             : 
    1245         553 : XclExpBlankCell::XclExpBlankCell(
    1246             :         const XclExpRoot& rRoot, const XclAddress& rXclPos, sal_uInt16 nLastXclCol,
    1247             :         const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId ) :
    1248         553 :     XclExpMultiCellBase( EXC_ID3_BLANK, EXC_ID_MULBLANK, 0, rXclPos )
    1249             : {
    1250             :     OSL_ENSURE( rXclPos.mnCol <= nLastXclCol, "XclExpBlankCell::XclExpBlankCell - invalid column range" );
    1251             :     // #i46627# use default script type instead of ApiScriptType::WEAK
    1252         553 :     AppendXFId( rRoot, pPattern, rRoot.GetDefApiScript(), nForcedXFId, nLastXclCol - rXclPos.mnCol + 1 );
    1253         553 : }
    1254             : 
    1255        1013 : bool XclExpBlankCell::TryMerge( const XclExpCellBase& rCell )
    1256             : {
    1257        1013 :     const XclExpBlankCell* pBlankCell = dynamic_cast< const XclExpBlankCell* >( &rCell );
    1258        1013 :     return pBlankCell && TryMergeXFIds( *pBlankCell );
    1259             : }
    1260             : 
    1261         460 : void XclExpBlankCell::GetBlankXFIndexes( ScfUInt16Vec& rXFIndexes ) const
    1262             : {
    1263         460 :     GetXFIndexes( rXFIndexes );
    1264         460 : }
    1265             : 
    1266        1230 : void XclExpBlankCell::RemoveUnusedBlankCells( const ScfUInt16Vec& rXFIndexes )
    1267             : {
    1268        1230 :     RemoveUnusedXFIndexes( rXFIndexes );
    1269        1230 : }
    1270             : 
    1271         279 : void XclExpBlankCell::WriteContents( XclExpStream& /*rStrm*/, sal_uInt16 /*nRelCol*/ )
    1272             : {
    1273         279 : }
    1274             : 
    1275         266 : void XclExpBlankCell::WriteXmlContents( XclExpXmlStream& rStrm, const XclAddress& rAddress, sal_uInt32 nXFId, sal_uInt16 /* nRelCol */ )
    1276             : {
    1277         266 :     sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
    1278             :     rWorksheet->singleElement( XML_c,
    1279         266 :             XML_r,      XclXmlUtils::ToOString( rStrm.GetRoot().GetStringBuf(), rAddress ).getStr(),
    1280             :             XML_s,      lcl_GetStyleId( rStrm, nXFId ).getStr(),
    1281         532 :             FSEND );
    1282         266 : }
    1283             : 
    1284          10 : IMPL_FIXEDMEMPOOL_NEWDEL( XclExpRkCell )
    1285             : 
    1286         998 : XclExpRkCell::XclExpRkCell(
    1287             :         const XclExpRoot& rRoot, const XclAddress& rXclPos,
    1288             :         const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId, sal_Int32 nRkValue ) :
    1289         998 :     XclExpMultiCellBase( EXC_ID_RK, EXC_ID_MULRK, 4, rXclPos )
    1290             : {
    1291             :     // #i41210# always use latin script for number cells - may look wrong for special number formats...
    1292         998 :     AppendXFId( rRoot, pPattern, ApiScriptType::LATIN, nForcedXFId );
    1293         998 :     maRkValues.push_back( nRkValue );
    1294         998 : }
    1295             : 
    1296        1161 : bool XclExpRkCell::TryMerge( const XclExpCellBase& rCell )
    1297             : {
    1298        1161 :     const XclExpRkCell* pRkCell = dynamic_cast< const XclExpRkCell* >( &rCell );
    1299        1161 :     if( pRkCell && TryMergeXFIds( *pRkCell ) )
    1300             :     {
    1301         405 :         maRkValues.insert( maRkValues.end(), pRkCell->maRkValues.begin(), pRkCell->maRkValues.end() );
    1302         405 :         return true;
    1303             :     }
    1304         756 :     return false;
    1305             : }
    1306             : 
    1307         681 : void XclExpRkCell::WriteXmlContents( XclExpXmlStream& rStrm, const XclAddress& rAddress, sal_uInt32 nXFId, sal_uInt16 nRelCol )
    1308             : {
    1309         681 :     sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
    1310             :     rWorksheet->startElement( XML_c,
    1311         681 :             XML_r,      XclXmlUtils::ToOString( rStrm.GetRoot().GetStringBuf(), rAddress ).getStr(),
    1312             :             XML_s,      lcl_GetStyleId( rStrm, nXFId ).getStr(),
    1313             :             XML_t,      "n",
    1314             :             // OOXTODO: XML_cm, XML_vm, XML_ph
    1315        1362 :             FSEND );
    1316         681 :     rWorksheet->startElement( XML_v, FSEND );
    1317         681 :     rWorksheet->write( XclTools::GetDoubleFromRK( maRkValues[ nRelCol ] ) );
    1318         681 :     rWorksheet->endElement( XML_v );
    1319         681 :     rWorksheet->endElement( XML_c );
    1320         681 : }
    1321             : 
    1322         317 : void XclExpRkCell::WriteContents( XclExpStream& rStrm, sal_uInt16 nRelCol )
    1323             : {
    1324             :     OSL_ENSURE( nRelCol < maRkValues.size(), "XclExpRkCell::WriteContents - overflow error" );
    1325         317 :     rStrm << maRkValues[ nRelCol ];
    1326         317 : }
    1327             : 
    1328             : // Rows and Columns
    1329             : 
    1330         258 : XclExpOutlineBuffer::XclExpOutlineBuffer( const XclExpRoot& rRoot, bool bRows ) :
    1331             :         mpScOLArray( 0 ),
    1332             :         maLevelInfos( SC_OL_MAXDEPTH ),
    1333             :         mnCurrLevel( 0 ),
    1334         258 :         mbCurrCollapse( false )
    1335             : {
    1336         258 :     if( const ScOutlineTable* pOutlineTable = rRoot.GetDoc().GetOutlineTable( rRoot.GetCurrScTab() ) )
    1337          28 :         mpScOLArray = &(bRows ? pOutlineTable->GetRowArray() : pOutlineTable->GetColArray());
    1338             : 
    1339         258 :     if( mpScOLArray )
    1340         224 :         for( size_t nLevel = 0; nLevel < SC_OL_MAXDEPTH; ++nLevel )
    1341         196 :             if( const ScOutlineEntry* pEntry = mpScOLArray->GetEntryByPos( nLevel, 0 ) )
    1342           0 :                 maLevelInfos[ nLevel ].mnScEndPos = pEntry->GetEnd();
    1343         258 : }
    1344             : 
    1345      110743 : void XclExpOutlineBuffer::UpdateColRow( SCCOLROW nScPos )
    1346             : {
    1347      110743 :     if( mpScOLArray )
    1348             :     {
    1349             :         // find open level index for passed position
    1350        3697 :         size_t nNewOpenScLevel = 0; // new open level (0-based Calc index)
    1351        3697 :         sal_uInt8 nNewLevel = 0;    // new open level (1-based Excel index)
    1352             : 
    1353        3697 :         if( mpScOLArray->FindTouchedLevel( nScPos, nScPos, nNewOpenScLevel ) )
    1354           0 :             nNewLevel = static_cast< sal_uInt8 >( nNewOpenScLevel + 1 );
    1355             :         // else nNewLevel keeps 0 to show that there are no groups
    1356             : 
    1357        3697 :         mbCurrCollapse = false;
    1358        3697 :         if( nNewLevel >= mnCurrLevel )
    1359             :         {
    1360             :             // new level(s) opened, or no level closed - update all level infos
    1361        7394 :             for( size_t nScLevel = 0; nScLevel <= nNewOpenScLevel; ++nScLevel )
    1362             :             {
    1363             :                 /*  In each level: check if a new group is started (there may be
    1364             :                     neighbored groups without gap - therefore check ALL levels). */
    1365        3697 :                 if( maLevelInfos[ nScLevel ].mnScEndPos < nScPos )
    1366             :                 {
    1367        3669 :                     if( const ScOutlineEntry* pEntry = mpScOLArray->GetEntryByPos( nScLevel, nScPos ) )
    1368             :                     {
    1369           0 :                         maLevelInfos[ nScLevel ].mnScEndPos = pEntry->GetEnd();
    1370           0 :                         maLevelInfos[ nScLevel ].mbHidden = pEntry->IsHidden();
    1371             :                     }
    1372             :                 }
    1373             :             }
    1374             :         }
    1375             :         else
    1376             :         {
    1377             :             // level(s) closed - check if any of the closed levels are collapsed
    1378             :             // Calc uses 0-based level indexes
    1379           0 :             sal_uInt16 nOldOpenScLevel = mnCurrLevel - 1;
    1380           0 :             for( sal_uInt16 nScLevel = nNewOpenScLevel + 1; !mbCurrCollapse && (nScLevel <= nOldOpenScLevel); ++nScLevel )
    1381           0 :                 mbCurrCollapse = maLevelInfos[ nScLevel ].mbHidden;
    1382             :         }
    1383             : 
    1384             :         // cache new opened level
    1385        3697 :         mnCurrLevel = nNewLevel;
    1386             :     }
    1387      110743 : }
    1388             : 
    1389         129 : XclExpGuts::XclExpGuts( const XclExpRoot& rRoot ) :
    1390             :     XclExpRecord( EXC_ID_GUTS, 8 ),
    1391             :     mnColLevels( 0 ),
    1392             :     mnColWidth( 0 ),
    1393             :     mnRowLevels( 0 ),
    1394         129 :     mnRowWidth( 0 )
    1395             : {
    1396         129 :     if( const ScOutlineTable* pOutlineTable = rRoot.GetDoc().GetOutlineTable( rRoot.GetCurrScTab() ) )
    1397             :     {
    1398             :         // column outline groups
    1399          14 :         const ScOutlineArray& rColArray = pOutlineTable->GetColArray();
    1400          14 :         mnColLevels = ulimit_cast< sal_uInt16 >( rColArray.GetDepth(), EXC_OUTLINE_MAX );
    1401          14 :         if( mnColLevels )
    1402             :         {
    1403           0 :             ++mnColLevels;
    1404           0 :             mnColWidth = 12 * mnColLevels + 5;
    1405             :         }
    1406             : 
    1407             :         // row outline groups
    1408          14 :         const ScOutlineArray& rRowArray = pOutlineTable->GetRowArray();
    1409          14 :         mnRowLevels = ulimit_cast< sal_uInt16 >( rRowArray.GetDepth(), EXC_OUTLINE_MAX );
    1410          14 :         if( mnRowLevels )
    1411             :         {
    1412           0 :             ++mnRowLevels;
    1413           0 :             mnRowWidth = 12 * mnRowLevels + 5;
    1414             :         }
    1415             :     }
    1416         129 : }
    1417             : 
    1418          29 : void XclExpGuts::WriteBody( XclExpStream& rStrm )
    1419             : {
    1420          29 :     rStrm << mnRowWidth << mnColWidth << mnRowLevels << mnColLevels;
    1421          29 : }
    1422             : 
    1423         129 : XclExpDimensions::XclExpDimensions( const XclExpRoot& rRoot ) :
    1424             :     mnFirstUsedXclRow( 0 ),
    1425             :     mnFirstFreeXclRow( 0 ),
    1426             :     mnFirstUsedXclCol( 0 ),
    1427         129 :     mnFirstFreeXclCol( 0 )
    1428             : {
    1429         129 :     switch( rRoot.GetBiff() )
    1430             :     {
    1431           0 :         case EXC_BIFF2: SetRecHeader( EXC_ID2_DIMENSIONS, 8 );  break;
    1432             :         case EXC_BIFF3:
    1433             :         case EXC_BIFF4:
    1434           0 :         case EXC_BIFF5: SetRecHeader( EXC_ID3_DIMENSIONS, 10 ); break;
    1435         129 :         case EXC_BIFF8: SetRecHeader( EXC_ID3_DIMENSIONS, 14 ); break;
    1436             :         default:        DBG_ERROR_BIFF();
    1437             :     }
    1438         129 : }
    1439             : 
    1440         129 : void XclExpDimensions::SetDimensions(
    1441             :         sal_uInt16 nFirstUsedXclCol, sal_uInt32 nFirstUsedXclRow,
    1442             :         sal_uInt16 nFirstFreeXclCol, sal_uInt32 nFirstFreeXclRow )
    1443             : {
    1444         129 :     mnFirstUsedXclRow = nFirstUsedXclRow;
    1445         129 :     mnFirstFreeXclRow = nFirstFreeXclRow;
    1446         129 :     mnFirstUsedXclCol = nFirstUsedXclCol;
    1447         129 :     mnFirstFreeXclCol = nFirstFreeXclCol;
    1448         129 : }
    1449             : 
    1450         100 : void XclExpDimensions::SaveXml( XclExpXmlStream& rStrm )
    1451             : {
    1452         100 :     ScRange aRange;
    1453         100 :     aRange.aStart.SetRow( (SCROW) mnFirstUsedXclRow );
    1454         100 :     aRange.aStart.SetCol( (SCCOL) mnFirstUsedXclCol );
    1455             : 
    1456         100 :     if( mnFirstFreeXclRow != mnFirstUsedXclRow && mnFirstFreeXclCol != mnFirstUsedXclCol )
    1457             :     {
    1458          46 :         aRange.aEnd.SetRow( (SCROW) (mnFirstFreeXclRow-1) );
    1459          46 :         aRange.aEnd.SetCol( (SCCOL) (mnFirstFreeXclCol-1) );
    1460             :     }
    1461             : 
    1462         100 :     rStrm.GetCurrentStream()->singleElement( XML_dimension,
    1463             :             XML_ref, XclXmlUtils::ToOString( aRange ).getStr(),
    1464         200 :             FSEND );
    1465         100 : }
    1466             : 
    1467          29 : void XclExpDimensions::WriteBody( XclExpStream& rStrm )
    1468             : {
    1469          29 :     XclBiff eBiff = rStrm.GetRoot().GetBiff();
    1470          29 :     if( eBiff == EXC_BIFF8 )
    1471          29 :         rStrm << mnFirstUsedXclRow << mnFirstFreeXclRow;
    1472             :     else
    1473           0 :         rStrm << static_cast< sal_uInt16 >( mnFirstUsedXclRow ) << static_cast< sal_uInt16 >( mnFirstFreeXclRow );
    1474          29 :     rStrm << mnFirstUsedXclCol << mnFirstFreeXclCol;
    1475          29 :     if( eBiff >= EXC_BIFF3 )
    1476          29 :         rStrm << sal_uInt16( 0 );
    1477          29 : }
    1478             : 
    1479             : namespace {
    1480             : 
    1481         316 : double lclGetCorrectedColWidth( const XclExpRoot& rRoot, sal_uInt16 nXclColWidth )
    1482             : {
    1483         316 :     long nFontHt = rRoot.GetFontBuffer().GetAppFontData().mnHeight;
    1484         316 :     return nXclColWidth - XclTools::GetXclDefColWidthCorrection( nFontHt );
    1485             : }
    1486             : 
    1487             : } // namespace
    1488             : 
    1489         129 : XclExpDefcolwidth::XclExpDefcolwidth( const XclExpRoot& rRoot ) :
    1490             :     XclExpUInt16Record( EXC_ID_DEFCOLWIDTH, EXC_DEFCOLWIDTH_DEF ),
    1491         129 :     XclExpRoot( rRoot )
    1492             : {
    1493         129 : }
    1494             : 
    1495         187 : bool XclExpDefcolwidth::IsDefWidth( sal_uInt16 nXclColWidth ) const
    1496             : {
    1497         187 :     double fNewColWidth = lclGetCorrectedColWidth( GetRoot(), nXclColWidth );
    1498             :     // exactly matched, if difference is less than 1/16 of a character to the left or to the right
    1499         187 :     return std::abs( static_cast< long >( GetValue() * 256.0 - fNewColWidth + 0.5 ) ) < 16;
    1500             : }
    1501             : 
    1502         129 : void XclExpDefcolwidth::SetDefWidth( sal_uInt16 nXclColWidth )
    1503             : {
    1504         129 :     double fNewColWidth = lclGetCorrectedColWidth( GetRoot(), nXclColWidth );
    1505         129 :     SetValue( limit_cast< sal_uInt16 >( fNewColWidth / 256.0 + 0.5 ) );
    1506         129 : }
    1507             : 
    1508      109824 : XclExpColinfo::XclExpColinfo( const XclExpRoot& rRoot,
    1509             :         SCCOL nScCol, SCROW nLastScRow, XclExpColOutlineBuffer& rOutlineBfr ) :
    1510             :     XclExpRecord( EXC_ID_COLINFO, 12 ),
    1511             :     XclExpRoot( rRoot ),
    1512             :     mnWidth( 0 ),
    1513             :     mnScWidth( 0 ),
    1514             :     mnFlags( 0 ),
    1515             :     mnFirstXclCol( static_cast< sal_uInt16 >( nScCol ) ),
    1516      109824 :     mnLastXclCol( static_cast< sal_uInt16 >( nScCol ) )
    1517             : {
    1518      109824 :     ScDocument& rDoc = GetDoc();
    1519      109824 :     SCTAB nScTab = GetCurrScTab();
    1520             : 
    1521             :     // column default format
    1522      109824 :     maXFId.mnXFId = GetXFBuffer().Insert(
    1523      219648 :         rDoc.GetMostUsedPattern( nScCol, 0, nLastScRow, nScTab ), GetDefApiScript() );
    1524             : 
    1525             :     // column width
    1526      109824 :     sal_uInt16 nScWidth = rDoc.GetColWidth( nScCol, nScTab );
    1527      109824 :     mnWidth = XclTools::GetXclColumnWidth( nScWidth, GetCharWidth() );
    1528      109824 :     mnScWidth =  sc::TwipsToHMM( nScWidth );
    1529             :     // column flags
    1530      109824 :     ::set_flag( mnFlags, EXC_COLINFO_HIDDEN, rDoc.ColHidden(nScCol, nScTab) );
    1531             : 
    1532             :     // outline data
    1533      109824 :     rOutlineBfr.Update( nScCol );
    1534      109824 :     ::set_flag( mnFlags, EXC_COLINFO_COLLAPSED, rOutlineBfr.IsCollapsed() );
    1535      109824 :     ::insert_value( mnFlags, rOutlineBfr.GetLevel(), 8, 3 );
    1536      109824 : }
    1537             : 
    1538      109824 : sal_uInt16 XclExpColinfo::ConvertXFIndexes()
    1539             : {
    1540      109824 :     maXFId.ConvertXFIndex( GetRoot() );
    1541      109824 :     return maXFId.mnXFIndex;
    1542             : }
    1543             : 
    1544         188 : bool XclExpColinfo::IsDefault( const XclExpDefcolwidth& rDefColWidth ) const
    1545             : {
    1546         188 :     return (maXFId.mnXFIndex == EXC_XF_DEFAULTCELL) && (mnFlags == 0) && rDefColWidth.IsDefWidth( mnWidth );
    1547             : }
    1548             : 
    1549      109695 : bool XclExpColinfo::TryMerge( const XclExpColinfo& rColInfo )
    1550             : {
    1551      219388 :     if( (maXFId.mnXFIndex == rColInfo.maXFId.mnXFIndex) &&
    1552      219329 :         (mnWidth == rColInfo.mnWidth) &&
    1553      219272 :         (mnFlags == rColInfo.mnFlags) &&
    1554      109636 :         (mnLastXclCol + 1 == rColInfo.mnFirstXclCol) )
    1555             :     {
    1556      109636 :         mnLastXclCol = rColInfo.mnLastXclCol;
    1557      109636 :         return true;
    1558             :     }
    1559          59 :     return false;
    1560             : }
    1561             : 
    1562          39 : void XclExpColinfo::WriteBody( XclExpStream& rStrm )
    1563             : {
    1564             :     // if last column is equal to last possible column, Excel adds one more
    1565          39 :     sal_uInt16 nLastXclCol = mnLastXclCol;
    1566          39 :     if( nLastXclCol == static_cast< sal_uInt16 >( rStrm.GetRoot().GetMaxPos().Col() ) )
    1567          17 :         ++nLastXclCol;
    1568             : 
    1569          39 :     rStrm   << mnFirstXclCol
    1570          78 :             << nLastXclCol
    1571          78 :             << mnWidth
    1572          78 :             << maXFId.mnXFIndex
    1573          78 :             << mnFlags
    1574          39 :             << sal_uInt16( 0 );
    1575          39 : }
    1576             : 
    1577         135 : void XclExpColinfo::SaveXml( XclExpXmlStream& rStrm )
    1578             : {
    1579             :     // if last column is equal to last possible column, Excel adds one more
    1580         135 :     sal_uInt16 nLastXclCol = mnLastXclCol;
    1581         135 :     if( nLastXclCol == static_cast< sal_uInt16 >( rStrm.GetRoot().GetMaxPos().Col() ) )
    1582         100 :         ++nLastXclCol;
    1583             : 
    1584         135 :     rStrm.GetCurrentStream()->singleElement( XML_col,
    1585             :             // OOXTODO: XML_bestFit,
    1586         135 :             XML_collapsed,      XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_COLINFO_COLLAPSED ) ),
    1587             :             // OOXTODO: XML_customWidth,
    1588         135 :             XML_hidden,         XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_COLINFO_HIDDEN ) ),
    1589             :             XML_max,            OString::number(  (nLastXclCol+1) ).getStr(),
    1590             :             XML_min,            OString::number(  (mnFirstXclCol+1) ).getStr(),
    1591             :             // OOXTODO: XML_outlineLevel,
    1592             :             // OOXTODO: XML_phonetic,
    1593             :             XML_style,          lcl_GetStyleId( rStrm, maXFId.mnXFIndex ).getStr(),
    1594         135 :             XML_width,          OString::number( (double) (mnScWidth / (double)sc::TwipsToHMM( GetCharWidth() )) ).getStr(),
    1595         675 :             FSEND );
    1596         135 : }
    1597             : 
    1598         129 : XclExpColinfoBuffer::XclExpColinfoBuffer( const XclExpRoot& rRoot ) :
    1599             :     XclExpRoot( rRoot ),
    1600             :     maDefcolwidth( rRoot ),
    1601         129 :     maOutlineBfr( rRoot )
    1602             : {
    1603         129 : }
    1604             : 
    1605         129 : void XclExpColinfoBuffer::Initialize( SCROW nLastScRow )
    1606             : {
    1607             : 
    1608      109953 :     for( sal_uInt16 nScCol = 0, nLastScCol = GetMaxPos().Col(); nScCol <= nLastScCol; ++nScCol )
    1609      109824 :         maColInfos.AppendNewRecord( new XclExpColinfo( GetRoot(), nScCol, nLastScRow, maOutlineBfr ) );
    1610         129 : }
    1611             : 
    1612         129 : void XclExpColinfoBuffer::Finalize( ScfUInt16Vec& rXFIndexes )
    1613             : {
    1614         129 :     rXFIndexes.clear();
    1615         129 :     rXFIndexes.reserve( maColInfos.GetSize() );
    1616             : 
    1617             :     size_t nPos, nSize;
    1618             : 
    1619             :     // do not cache the record list size, it may change in the loop
    1620      109953 :     for( nPos = 0; nPos < maColInfos.GetSize(); ++nPos )
    1621             :     {
    1622      109824 :         XclExpColinfoRef xRec = maColInfos.GetRecord( nPos );
    1623      109824 :         xRec->ConvertXFIndexes();
    1624             : 
    1625             :         // try to merge with previous record
    1626      109824 :         if( nPos > 0 )
    1627             :         {
    1628      109695 :             XclExpColinfoRef xPrevRec = maColInfos.GetRecord( nPos - 1 );
    1629      109695 :             if( xPrevRec->TryMerge( *xRec ) )
    1630             :                 // adjust nPos to get the next COLINFO record at the same position
    1631      109636 :                 maColInfos.RemoveRecord( nPos-- );
    1632             :         }
    1633      109824 :     }
    1634             : 
    1635             :     // put XF indexes into passed vector, collect use count of all different widths
    1636             :     typedef ::std::map< sal_uInt16, sal_uInt16 > XclExpWidthMap;
    1637         129 :     XclExpWidthMap aWidthMap;
    1638         129 :     sal_uInt16 nMaxColCount = 0;
    1639         129 :     sal_uInt16 nMaxUsedWidth = 0;
    1640         317 :     for( nPos = 0, nSize = maColInfos.GetSize(); nPos < nSize; ++nPos )
    1641             :     {
    1642         188 :         XclExpColinfoRef xRec = maColInfos.GetRecord( nPos );
    1643         188 :         sal_uInt16 nColCount = xRec->GetColCount();
    1644             : 
    1645             :         // add XF index to passed vector
    1646         188 :         rXFIndexes.resize( rXFIndexes.size() + nColCount, xRec->GetXFIndex() );
    1647             : 
    1648             :         // collect use count of column width
    1649         188 :         sal_uInt16 nWidth = xRec->GetColWidth();
    1650         188 :         sal_uInt16& rnMapCount = aWidthMap[ nWidth ];
    1651         188 :         rnMapCount = rnMapCount + nColCount;
    1652         188 :         if( rnMapCount > nMaxColCount )
    1653             :         {
    1654         150 :             nMaxColCount = rnMapCount;
    1655         150 :             nMaxUsedWidth = nWidth;
    1656             :         }
    1657         188 :     }
    1658         129 :     maDefcolwidth.SetDefWidth( nMaxUsedWidth );
    1659             : 
    1660             :     // remove all default COLINFO records
    1661         129 :     nPos = 0;
    1662         446 :     while( nPos < maColInfos.GetSize() )
    1663             :     {
    1664         188 :         XclExpColinfoRef xRec = maColInfos.GetRecord( nPos );
    1665         188 :         if( xRec->IsDefault( maDefcolwidth ) )
    1666          14 :             maColInfos.RemoveRecord( nPos );
    1667             :         else
    1668         174 :             ++nPos;
    1669         317 :     }
    1670         129 : }
    1671             : 
    1672          29 : void XclExpColinfoBuffer::Save( XclExpStream& rStrm )
    1673             : {
    1674             :     // DEFCOLWIDTH
    1675          29 :     maDefcolwidth.Save( rStrm );
    1676             :     // COLINFO records
    1677          29 :     maColInfos.Save( rStrm );
    1678          29 : }
    1679             : 
    1680         100 : void XclExpColinfoBuffer::SaveXml( XclExpXmlStream& rStrm )
    1681             : {
    1682         100 :     if( maColInfos.IsEmpty() )
    1683         100 :         return;
    1684             : 
    1685         100 :     sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
    1686             :     rWorksheet->startElement( XML_cols,
    1687         100 :             FSEND );
    1688         100 :     maColInfos.SaveXml( rStrm );
    1689         100 :     rWorksheet->endElement( XML_cols );
    1690             : }
    1691             : 
    1692         387 : XclExpDefaultRowData::XclExpDefaultRowData() :
    1693             :     mnFlags( EXC_DEFROW_DEFAULTFLAGS ),
    1694         387 :     mnHeight( EXC_DEFROW_DEFAULTHEIGHT )
    1695             : {
    1696         387 : }
    1697             : 
    1698         489 : XclExpDefaultRowData::XclExpDefaultRowData( const XclExpRow& rRow ) :
    1699             :     mnFlags( EXC_DEFROW_DEFAULTFLAGS ),
    1700         489 :     mnHeight( rRow.GetHeight() )
    1701             : {
    1702         489 :     ::set_flag( mnFlags, EXC_DEFROW_HIDDEN, rRow.IsHidden() );
    1703         489 :     ::set_flag( mnFlags, EXC_DEFROW_UNSYNCED, rRow.IsUnsynced() );
    1704         489 : }
    1705             : 
    1706         782 : bool operator<( const XclExpDefaultRowData& rLeft, const XclExpDefaultRowData& rRight )
    1707             : {
    1708        1564 :     return (rLeft.mnHeight < rRight.mnHeight) ||
    1709        2200 :         ((rLeft.mnHeight == rRight.mnHeight) && (rLeft.mnFlags < rRight.mnFlags));
    1710             : }
    1711             : 
    1712         129 : XclExpDefrowheight::XclExpDefrowheight() :
    1713         129 :     XclExpRecord( EXC_ID3_DEFROWHEIGHT, 4 )
    1714             : {
    1715         129 : }
    1716             : 
    1717         129 : void XclExpDefrowheight::SetDefaultData( const XclExpDefaultRowData& rDefData )
    1718             : {
    1719         129 :     maDefData = rDefData;
    1720         129 : }
    1721             : 
    1722          29 : void XclExpDefrowheight::WriteBody( XclExpStream& rStrm )
    1723             : {
    1724             :     OSL_ENSURE_BIFF( rStrm.GetRoot().GetBiff() >= EXC_BIFF3 );
    1725          29 :     rStrm << maDefData.mnFlags << maDefData.mnHeight;
    1726          29 : }
    1727             : 
    1728         919 : XclExpRow::XclExpRow( const XclExpRoot& rRoot, sal_uInt32 nXclRow,
    1729             :         XclExpRowOutlineBuffer& rOutlineBfr, bool bAlwaysEmpty ) :
    1730             :     XclExpRecord( EXC_ID3_ROW, 16 ),
    1731             :     XclExpRoot( rRoot ),
    1732             :     mnXclRow( nXclRow ),
    1733             :     mnHeight( 0 ),
    1734             :     mnFlags( EXC_ROW_DEFAULTFLAGS ),
    1735             :     mnXFIndex( EXC_XF_DEFAULTCELL ),
    1736             :     mnOutlineLevel( 0 ),
    1737             :     mnXclRowRpt( 1 ),
    1738             :     mnCurrentRow( nXclRow ),
    1739             :     mbAlwaysEmpty( bAlwaysEmpty ),
    1740         919 :     mbEnabled( true )
    1741             : {
    1742         919 :     SCTAB nScTab = GetCurrScTab();
    1743         919 :     SCROW nScRow = static_cast< SCROW >( mnXclRow );
    1744             : 
    1745             :     // *** Row flags *** ------------------------------------------------------
    1746             : 
    1747         919 :     sal_uInt8 nRowFlags = GetDoc().GetRowFlags( nScRow, nScTab );
    1748         919 :     bool bUserHeight = ::get_flag< sal_uInt8 >( nRowFlags, CR_MANUALSIZE );
    1749         919 :     bool bHidden = GetDoc().RowHidden(nScRow, nScTab);
    1750         919 :     ::set_flag( mnFlags, EXC_ROW_UNSYNCED, bUserHeight );
    1751         919 :     ::set_flag( mnFlags, EXC_ROW_HIDDEN, bHidden );
    1752             : 
    1753             :     // *** Row height *** -----------------------------------------------------
    1754             : 
    1755             :     // Always get the actual row height even if the manual size flag is not set,
    1756             :     // to correctly export the heights of rows with wrapped texts.
    1757             : 
    1758         919 :     mnHeight = GetDoc().GetRowHeight(nScRow, nScTab, false);
    1759             : 
    1760             :     // *** Outline data *** ---------------------------------------------------
    1761             : 
    1762         919 :     rOutlineBfr.Update( nScRow );
    1763         919 :     ::set_flag( mnFlags, EXC_ROW_COLLAPSED, rOutlineBfr.IsCollapsed() );
    1764         919 :     ::insert_value( mnFlags, rOutlineBfr.GetLevel(), 0, 3 );
    1765         919 :     mnOutlineLevel = rOutlineBfr.GetLevel();
    1766             : 
    1767             :     // *** Progress bar *** ---------------------------------------------------
    1768             : 
    1769         919 :     XclExpProgressBar& rProgress = GetProgressBar();
    1770         919 :     rProgress.IncRowRecordCount();
    1771         919 :     rProgress.Progress();
    1772         919 : }
    1773             : 
    1774        3344 : void XclExpRow::AppendCell( XclExpCellRef xCell, bool bIsMergedBase )
    1775             : {
    1776             :     OSL_ENSURE( !mbAlwaysEmpty, "XclExpRow::AppendCell - row is marked to be always empty" );
    1777             :     // try to merge with last existing cell
    1778        3344 :     InsertCell( xCell, maCellList.GetSize(), bIsMergedBase );
    1779        3344 : }
    1780             : 
    1781         919 : void XclExpRow::Finalize( const ScfUInt16Vec& rColXFIndexes, bool bProgress )
    1782             : {
    1783             :     size_t nPos, nSize;
    1784             : 
    1785             :     // *** Convert XF identifiers *** -----------------------------------------
    1786             : 
    1787             :     // additionally collect the blank XF indexes
    1788         919 :     size_t nColCount = GetMaxPos().Col() + 1;
    1789             :     OSL_ENSURE( rColXFIndexes.size() == nColCount, "XclExpRow::Finalize - wrong column XF index count" );
    1790             : 
    1791         919 :     ScfUInt16Vec aXFIndexes( nColCount, EXC_XF_NOTFOUND );
    1792        3765 :     for( nPos = 0, nSize = maCellList.GetSize(); nPos < nSize; ++nPos )
    1793             :     {
    1794        2846 :         XclExpCellRef xCell = maCellList.GetRecord( nPos );
    1795        2846 :         xCell->ConvertXFIndexes( GetRoot() );
    1796        2846 :         xCell->GetBlankXFIndexes( aXFIndexes );
    1797        2846 :     }
    1798             : 
    1799             :     // *** Fill gaps with BLANK/MULBLANK cell records *** ---------------------
    1800             : 
    1801             :     /*  This is needed because nonexistant cells in Calc are not formatted at all,
    1802             :         but in Excel they would have the column default format. Blank cells that
    1803             :         are equal to the respective column default are removed later in this function. */
    1804         919 :     if( !mbAlwaysEmpty )
    1805             :     {
    1806             :         // XF identifier representing default cell XF
    1807         688 :         XclExpMultiXFId aXFId( XclExpXFBuffer::GetDefCellXFId() );
    1808         688 :         aXFId.ConvertXFIndex( GetRoot() );
    1809             : 
    1810         688 :         nPos = 0;
    1811        6791 :         while( nPos <= maCellList.GetSize() )  // don't cache list size, may change in the loop
    1812             :         {
    1813             :             // get column index that follows previous cell
    1814        5415 :             sal_uInt16 nFirstFreeXclCol = (nPos > 0) ? (maCellList.GetRecord( nPos - 1 )->GetLastXclCol() + 1) : 0;
    1815             :             // get own column index
    1816        5415 :             sal_uInt16 nNextUsedXclCol = (nPos < maCellList.GetSize()) ? maCellList.GetRecord( nPos )->GetXclCol() : (GetMaxPos().Col() + 1);
    1817             : 
    1818             :             // is there a gap?
    1819        5415 :             if( nFirstFreeXclCol < nNextUsedXclCol )
    1820             :             {
    1821        1111 :                 aXFId.mnCount = nNextUsedXclCol - nFirstFreeXclCol;
    1822        1111 :                 XclExpCellRef xNewCell( new XclExpBlankCell( XclAddress( nFirstFreeXclCol, mnXclRow ), aXFId ) );
    1823             :                 // insert the cell, InsertCell() may merge it with existing BLANK records
    1824        1111 :                 InsertCell( xNewCell, nPos, false );
    1825             :                 // insert default XF indexes into aXFIndexes
    1826             :                 ::std::fill( aXFIndexes.begin() + nFirstFreeXclCol,
    1827        1111 :                     aXFIndexes.begin() + nNextUsedXclCol, aXFId.mnXFIndex );
    1828             :                 // don't step forward with nPos, InsertCell() may remove records
    1829             :             }
    1830             :             else
    1831        4304 :                 ++nPos;
    1832             :         }
    1833             :     }
    1834             : 
    1835             :     // *** Find default row format *** ----------------------------------------
    1836             : 
    1837         919 :     ScfUInt16Vec::iterator aCellBeg = aXFIndexes.begin(), aCellEnd = aXFIndexes.end(), aCellIt;
    1838         919 :     ScfUInt16Vec::const_iterator aColBeg = rColXFIndexes.begin(), aColIt;
    1839             : 
    1840             :     // find most used XF index in the row
    1841             :     typedef ::std::map< sal_uInt16, size_t > XclExpXFIndexMap;
    1842        1838 :     XclExpXFIndexMap aIndexMap;
    1843         919 :     sal_uInt16 nRowXFIndex = EXC_XF_DEFAULTCELL;
    1844         919 :     size_t nMaxXFCount = 0;
    1845      703127 :     for( aCellIt = aCellBeg; aCellIt != aCellEnd; ++aCellIt )
    1846             :     {
    1847      702208 :         if( *aCellIt != EXC_XF_NOTFOUND )
    1848             :         {
    1849      509721 :             size_t& rnCount = aIndexMap[ *aCellIt ];
    1850      509721 :             ++rnCount;
    1851      509721 :             if( rnCount > nMaxXFCount )
    1852             :             {
    1853      508886 :                 nRowXFIndex = *aCellIt;
    1854      508886 :                 nMaxXFCount = rnCount;
    1855             :             }
    1856             :         }
    1857             :     }
    1858             : 
    1859             :     // decide whether to use the row default XF index or column default XF indexes
    1860         919 :     bool bUseColDefXFs = nRowXFIndex == EXC_XF_DEFAULTCELL;
    1861         919 :     if( !bUseColDefXFs )
    1862             :     {
    1863             :         // count needed XF indexes for blank cells with and without row default XF index
    1864          14 :         size_t nXFCountWithRowDefXF = 0;
    1865          14 :         size_t nXFCountWithoutRowDefXF = 0;
    1866        3598 :         for( aCellIt = aCellBeg, aColIt = aColBeg; aCellIt != aCellEnd; ++aCellIt, ++aColIt )
    1867             :         {
    1868        3584 :             sal_uInt16 nXFIndex = *aCellIt;
    1869        3584 :             if( nXFIndex != EXC_XF_NOTFOUND )
    1870             :             {
    1871        3549 :                 if( nXFIndex != nRowXFIndex )
    1872         305 :                     ++nXFCountWithRowDefXF;     // with row default XF index
    1873        3549 :                 if( nXFIndex != *aColIt )
    1874        1007 :                     ++nXFCountWithoutRowDefXF;  // without row default XF index
    1875             :             }
    1876             :         }
    1877             : 
    1878             :         // use column XF indexes if this would cause less or equal number of BLANK records
    1879          14 :         bUseColDefXFs = nXFCountWithoutRowDefXF <= nXFCountWithRowDefXF;
    1880             :     }
    1881             : 
    1882             :     // *** Remove unused BLANK cell records *** -------------------------------
    1883             : 
    1884         919 :     if( bUseColDefXFs )
    1885             :     {
    1886             :         // use column default XF indexes
    1887             :         // #i194#: remove cell XF indexes equal to column default XF indexes
    1888      702099 :         for( aCellIt = aCellBeg, aColIt = aColBeg; aCellIt != aCellEnd; ++aCellIt, ++aColIt )
    1889      701184 :             if( *aCellIt == *aColIt )
    1890      508182 :                 *aCellIt = EXC_XF_NOTFOUND;
    1891             :     }
    1892             :     else
    1893             :     {
    1894             :         // use row default XF index
    1895           4 :         mnXFIndex = nRowXFIndex;
    1896           4 :         ::set_flag( mnFlags, EXC_ROW_USEDEFXF );
    1897             :         // #98133#, #i194#, #i27407#: remove cell XF indexes equal to row default XF index
    1898        1028 :         for( aCellIt = aCellBeg; aCellIt != aCellEnd; ++aCellIt )
    1899        1024 :             if( *aCellIt == nRowXFIndex )
    1900         994 :                 *aCellIt = EXC_XF_NOTFOUND;
    1901             :     }
    1902             : 
    1903             :     // remove unused parts of BLANK/MULBLANK cell records
    1904         919 :     nPos = 0;
    1905        5454 :     while( nPos < maCellList.GetSize() )   // do not cache list size, may change in the loop
    1906             :     {
    1907        3616 :         XclExpCellRef xCell = maCellList.GetRecord( nPos );
    1908        3616 :         xCell->RemoveUnusedBlankCells( aXFIndexes );
    1909        3616 :         if( xCell->IsEmpty() )
    1910         973 :             maCellList.RemoveRecord( nPos );
    1911             :         else
    1912        2643 :             ++nPos;
    1913        3616 :     }
    1914             : 
    1915             :     // progress bar includes disabled rows; only update it in the lead thread.
    1916         919 :     if (bProgress)
    1917        1838 :         GetProgressBar().Progress();
    1918         919 : }
    1919         872 : sal_uInt16 XclExpRow::GetFirstUsedXclCol() const
    1920             : {
    1921         872 :     return maCellList.IsEmpty() ? 0 : maCellList.GetFirstRecord()->GetXclCol();
    1922             : }
    1923             : 
    1924         872 : sal_uInt16 XclExpRow::GetFirstFreeXclCol() const
    1925             : {
    1926         872 :     return maCellList.IsEmpty() ? 0 : (maCellList.GetLastRecord()->GetLastXclCol() + 1);
    1927             : }
    1928             : 
    1929        2628 : bool XclExpRow::IsDefaultable() const
    1930             : {
    1931        2628 :     const sal_uInt16 nAllowedFlags = EXC_ROW_DEFAULTFLAGS | EXC_ROW_HIDDEN | EXC_ROW_UNSYNCED;
    1932        2628 :     return !::get_flag( mnFlags, static_cast< sal_uInt16 >( ~nAllowedFlags ) ) && IsEmpty();
    1933             : }
    1934             : 
    1935         919 : void XclExpRow::DisableIfDefault( const XclExpDefaultRowData& rDefRowData )
    1936             : {
    1937        1228 :     mbEnabled = !IsDefaultable() ||
    1938         592 :         (mnHeight != rDefRowData.mnHeight) ||
    1939        1485 :         (IsHidden() != rDefRowData.IsHidden()) ||
    1940        1202 :         (IsUnsynced() != rDefRowData.IsUnsynced());
    1941         919 : }
    1942             : 
    1943         311 : void XclExpRow::WriteCellList( XclExpStream& rStrm )
    1944             : {
    1945             :     OSL_ENSURE( mbEnabled || maCellList.IsEmpty(), "XclExpRow::WriteCellList - cells in disabled row" );
    1946         311 :     maCellList.Save( rStrm );
    1947         311 : }
    1948             : 
    1949         311 : void XclExpRow::Save( XclExpStream& rStrm )
    1950             : {
    1951         311 :     if( mbEnabled )
    1952             :     {
    1953         241 :         mnCurrentRow = mnXclRow;
    1954         503 :         for ( sal_uInt32 i = 0; i < mnXclRowRpt; ++i, ++mnCurrentRow )
    1955         262 :             XclExpRecord::Save( rStrm );
    1956             :     }
    1957         311 : }
    1958             : 
    1959        4455 : void XclExpRow::InsertCell( XclExpCellRef xCell, size_t nPos, bool bIsMergedBase )
    1960             : {
    1961             :     OSL_ENSURE( xCell, "XclExpRow::InsertCell - missing cell" );
    1962             : 
    1963             :     /*  If we have a multi-line text in a merged cell, and the resulting
    1964             :         row height has not been confirmed, we need to force the EXC_ROW_UNSYNCED
    1965             :         flag to be true to ensure Excel works correctly. */
    1966        4455 :     if( bIsMergedBase && xCell->IsMultiLineText() )
    1967           0 :         ::set_flag( mnFlags, EXC_ROW_UNSYNCED );
    1968             : 
    1969             :     // try to merge with previous cell, insert the new cell if not successful
    1970        4455 :     XclExpCellRef xPrevCell = maCellList.GetRecord( nPos - 1 );
    1971        4455 :     if( xPrevCell && xPrevCell->TryMerge( *xCell ) )
    1972         727 :         xCell = xPrevCell;
    1973             :     else
    1974        3728 :         maCellList.InsertRecord( xCell, nPos++ );
    1975             :     // nPos points now to following cell
    1976             : 
    1977             :     // try to merge with following cell, remove it if successful
    1978        8910 :     XclExpCellRef xNextCell = maCellList.GetRecord( nPos );
    1979        4455 :     if( xNextCell && xCell->TryMerge( *xNextCell ) )
    1980        4567 :         maCellList.RemoveRecord( nPos );
    1981        4455 : }
    1982             : 
    1983         262 : void XclExpRow::WriteBody( XclExpStream& rStrm )
    1984             : {
    1985         262 :     rStrm   << static_cast< sal_uInt16 >(mnCurrentRow)
    1986         524 :             << GetFirstUsedXclCol()
    1987         524 :             << GetFirstFreeXclCol()
    1988         524 :             << mnHeight
    1989         262 :             << sal_uInt32( 0 )
    1990         524 :             << mnFlags
    1991         524 :             << mnXFIndex;
    1992         262 : }
    1993             : 
    1994         502 : void XclExpRow::SaveXml( XclExpXmlStream& rStrm )
    1995             : {
    1996         502 :     if( !mbEnabled )
    1997         609 :         return;
    1998         395 :     sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
    1999         395 :     bool haveFormat = ::get_flag( mnFlags, EXC_ROW_USEDEFXF );
    2000         395 :     mnCurrentRow = mnXclRow + 1;
    2001         811 :     for ( sal_uInt32 i=0; i<mnXclRowRpt; ++i )
    2002             :     {
    2003             :         rWorksheet->startElement( XML_row,
    2004             :                 XML_r,              OString::number(  (mnCurrentRow++) ).getStr(),
    2005             :                 // OOXTODO: XML_spans,          optional
    2006         416 :                 XML_s,              haveFormat ? lcl_GetStyleId( rStrm, mnXFIndex ).getStr() : NULL,
    2007             :                 XML_customFormat,   XclXmlUtils::ToPsz( haveFormat ),
    2008             :                 XML_ht,             OString::number( (double) mnHeight / 20.0 ).getStr(),
    2009         416 :                 XML_hidden,         XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_ROW_HIDDEN ) ),
    2010         416 :                 XML_customHeight,   XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_ROW_UNSYNCED ) ),
    2011             :                 XML_outlineLevel,   OString::number(  mnOutlineLevel ).getStr(),
    2012         416 :                 XML_collapsed,      XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_ROW_COLLAPSED ) ),
    2013             :                 // OOXTODO: XML_thickTop,       bool
    2014             :                 // OOXTODO: XML_thickBot,       bool
    2015             :                 // OOXTODO: XML_ph,             bool
    2016        1664 :                 FSEND );
    2017             :         // OOXTODO: XML_extLst
    2018         416 :         maCellList.SaveXml( rStrm );
    2019         416 :         rWorksheet->endElement( XML_row );
    2020             :     }
    2021             : }
    2022             : 
    2023         129 : XclExpRowBuffer::XclExpRowBuffer( const XclExpRoot& rRoot ) :
    2024             :     XclExpRoot( rRoot ),
    2025             :     maOutlineBfr( rRoot ),
    2026         129 :     maDimensions( rRoot )
    2027             : {
    2028         129 : }
    2029             : 
    2030        3344 : void XclExpRowBuffer::AppendCell( XclExpCellRef xCell, bool bIsMergedBase )
    2031             : {
    2032             :     OSL_ENSURE( xCell, "XclExpRowBuffer::AppendCell - missing cell" );
    2033        3344 :     GetOrCreateRow( xCell->GetXclRow(), false ).AppendCell( xCell, bIsMergedBase );
    2034        3344 : }
    2035             : 
    2036         129 : void XclExpRowBuffer::CreateRows( SCROW nFirstFreeScRow )
    2037             : {
    2038         129 :     if( nFirstFreeScRow > 0 )
    2039         129 :         GetOrCreateRow(  ::std::max ( nFirstFreeScRow - 1, GetMaxPos().Row() ), true );
    2040         129 : }
    2041             : 
    2042             : class RowFinalizeTask : public comphelper::ThreadTask
    2043             : {
    2044             :     bool mbProgress;
    2045             :     const ScfUInt16Vec& mrColXFIndexes;
    2046             :     std::vector< XclExpRow * > maRows;
    2047             : public:
    2048           0 :              RowFinalizeTask( const ScfUInt16Vec& rColXFIndexes,
    2049             :                               bool bProgress ) :
    2050             :                  mbProgress( bProgress ),
    2051           0 :                  mrColXFIndexes( rColXFIndexes ) {}
    2052           0 :     virtual ~RowFinalizeTask() {}
    2053           0 :     void     push_back( XclExpRow *pRow ) { maRows.push_back( pRow ); }
    2054           0 :     virtual void doWork() SAL_OVERRIDE
    2055             :     {
    2056           0 :         for (size_t i = 0; i < maRows.size(); i++ )
    2057           0 :             maRows[ i ]->Finalize( mrColXFIndexes, mbProgress );
    2058           0 :     }
    2059             : };
    2060             : 
    2061         129 : void XclExpRowBuffer::Finalize( XclExpDefaultRowData& rDefRowData, const ScfUInt16Vec& rColXFIndexes )
    2062             : {
    2063             :     // *** Finalize all rows *** ----------------------------------------------
    2064             : 
    2065         129 :     GetProgressBar().ActivateFinalRowsSegment();
    2066             : 
    2067             : #if 1
    2068             :     // This is staggeringly slow, and each element operates only
    2069             :     // on its own data.
    2070         129 :     const size_t nRows = maRowMap.size();
    2071         129 :     const size_t nThreads = nRows < 128 ? 1 : std::max(std::thread::hardware_concurrency(), 1U);
    2072             : #else
    2073             :     const size_t nThreads = 1; // globally disable multi-threading for now.
    2074             : #endif
    2075         129 :     if (nThreads == 1)
    2076             :     {
    2077         129 :         RowMap::iterator itr, itrBeg = maRowMap.begin(), itrEnd = maRowMap.end();
    2078        1048 :         for (itr = itrBeg; itr != itrEnd; ++itr)
    2079         919 :             itr->second->Finalize( rColXFIndexes, true );
    2080             :     }
    2081             :     else
    2082             :     {
    2083           0 :         comphelper::ThreadPool &rPool = comphelper::ThreadPool::getSharedOptimalPool();
    2084           0 :         std::vector<RowFinalizeTask*> pTasks(nThreads, NULL);
    2085           0 :         for ( size_t i = 0; i < nThreads; i++ )
    2086           0 :             pTasks[ i ] = new RowFinalizeTask( rColXFIndexes, i == 0 );
    2087             : 
    2088           0 :         RowMap::iterator itr, itrBeg = maRowMap.begin(), itrEnd = maRowMap.end();
    2089           0 :         size_t nIdx = 0;
    2090           0 :         for ( itr = itrBeg; itr != itrEnd; ++itr, ++nIdx )
    2091           0 :             pTasks[ nIdx % nThreads ]->push_back( itr->second.get() );
    2092             : 
    2093           0 :         for ( size_t i = 1; i < nThreads; i++ )
    2094           0 :             rPool.pushTask( pTasks[ i ] );
    2095             : 
    2096             :         // Progress bar updates must be synchronous to avoid deadlock
    2097           0 :         pTasks[0]->doWork();
    2098             : 
    2099           0 :         rPool.waitUntilEmpty();
    2100             :     }
    2101             : 
    2102             :     // *** Default row format *** ---------------------------------------------
    2103             : 
    2104             :     typedef ::std::map< XclExpDefaultRowData, size_t > XclExpDefRowDataMap;
    2105         129 :     XclExpDefRowDataMap aDefRowMap;
    2106             : 
    2107         129 :     XclExpDefaultRowData aMaxDefData;
    2108         129 :     size_t nMaxDefCount = 0;
    2109             :     // only look for default format in existing rows, if there are more than unused
    2110         129 :     XclExpRow* pPrev = NULL;
    2111             :     typedef std::vector< XclExpRow* > XclRepeatedRows;
    2112         258 :     XclRepeatedRows aRepeated;
    2113         129 :     RowMap::iterator itr, itrBeg = maRowMap.begin(), itrEnd = maRowMap.end();
    2114        1048 :     for (itr = itrBeg; itr != itrEnd; ++itr)
    2115             :     {
    2116         919 :         const RowRef& rRow = itr->second;
    2117         919 :         if (rRow->IsDefaultable())
    2118             :         {
    2119         309 :             XclExpDefaultRowData aDefData( *rRow );
    2120         309 :             size_t& rnDefCount = aDefRowMap[ aDefData ];
    2121         309 :             ++rnDefCount;
    2122         309 :             if( rnDefCount > nMaxDefCount )
    2123             :             {
    2124         285 :                 nMaxDefCount = rnDefCount;
    2125         285 :                 aMaxDefData = aDefData;
    2126             :             }
    2127             :         }
    2128         919 :         if ( pPrev )
    2129             :         {
    2130         790 :             if ( pPrev->IsDefaultable())
    2131             :             {
    2132             :                 // if the previous row we processed is not
    2133             :                 // defaultable then afaict the rows inbetween are
    2134             :                 // not used ( and not repeatable )
    2135         180 :                 sal_uInt32 nRpt =  rRow->GetXclRow() - pPrev->GetXclRow();
    2136         180 :                 if ( nRpt > 1 )
    2137         128 :                     aRepeated.push_back( pPrev );
    2138         180 :                 pPrev->SetXclRowRpt( nRpt );
    2139         180 :                 XclExpDefaultRowData aDefData( *pPrev );
    2140         180 :                 size_t& rnDefCount = aDefRowMap[ aDefData ];
    2141         180 :                 rnDefCount += ( pPrev->GetXclRowRpt() - 1 );
    2142         180 :                 if( rnDefCount > nMaxDefCount )
    2143             :                 {
    2144         122 :                     nMaxDefCount = rnDefCount;
    2145         122 :                     aMaxDefData = aDefData;
    2146             :                 }
    2147             :             }
    2148             :         }
    2149         919 :         pPrev = rRow.get();
    2150             :     }
    2151             :     // return the default row format to caller
    2152         129 :     rDefRowData = aMaxDefData;
    2153             : 
    2154             :     // now disable repeating extra (empty) rows that are equal to
    2155             :     // default row height
    2156         257 :     for ( XclRepeatedRows::iterator it = aRepeated.begin(), it_end = aRepeated.end(); it != it_end; ++it)
    2157             :     {
    2158         128 :         if ( (*it)->GetXclRowRpt() > 1 && (*it)->GetHeight() == rDefRowData.mnHeight )
    2159         116 :             (*it)->SetXclRowRpt( 1 );
    2160             :     }
    2161             : 
    2162             :     // *** Disable unused ROW records, find used area *** ---------------------
    2163             : 
    2164         129 :     sal_uInt16 nFirstUsedXclCol = SAL_MAX_UINT16;
    2165         129 :     sal_uInt16 nFirstFreeXclCol = 0;
    2166         129 :     sal_uInt32 nFirstUsedXclRow = SAL_MAX_UINT32;
    2167         129 :     sal_uInt32 nFirstFreeXclRow = 0;
    2168             : 
    2169        1048 :     for (itr = itrBeg; itr != itrEnd; ++itr)
    2170             :     {
    2171         919 :         const RowRef& rRow = itr->second;
    2172             :         // disable unused rows
    2173         919 :         rRow->DisableIfDefault( aMaxDefData );
    2174             : 
    2175             :         // find used column range
    2176         919 :         if( !rRow->IsEmpty() )      // empty rows return (0...0) as used range
    2177             :         {
    2178         610 :             nFirstUsedXclCol = ::std::min( nFirstUsedXclCol, rRow->GetFirstUsedXclCol() );
    2179         610 :             nFirstFreeXclCol = ::std::max( nFirstFreeXclCol, rRow->GetFirstFreeXclCol() );
    2180             :         }
    2181             : 
    2182             :         // find used row range
    2183         919 :         if( rRow->IsEnabled() )
    2184             :         {
    2185         636 :             sal_uInt16 nXclRow = rRow->GetXclRow();
    2186         636 :             nFirstUsedXclRow = ::std::min< sal_uInt32 >( nFirstUsedXclRow, nXclRow );
    2187         636 :             nFirstFreeXclRow = ::std::max< sal_uInt32 >( nFirstFreeXclRow, nXclRow + 1 );
    2188             :         }
    2189             :     }
    2190             : 
    2191             :     // adjust start position, if there are no or only empty/disabled ROW records
    2192         129 :     nFirstUsedXclCol = ::std::min( nFirstUsedXclCol, nFirstFreeXclCol );
    2193         129 :     nFirstUsedXclRow = ::std::min( nFirstUsedXclRow, nFirstFreeXclRow );
    2194             : 
    2195             :     // initialize the DIMENSIONS record
    2196             :     maDimensions.SetDimensions(
    2197         258 :         nFirstUsedXclCol, nFirstUsedXclRow, nFirstFreeXclCol, nFirstFreeXclRow );
    2198         129 : }
    2199             : 
    2200          29 : void XclExpRowBuffer::Save( XclExpStream& rStrm )
    2201             : {
    2202             :     // DIMENSIONS record
    2203          29 :     maDimensions.Save( rStrm );
    2204             : 
    2205             :     // save in blocks of 32 rows, each block contains first all ROWs, then all cells
    2206          29 :     size_t nSize = maRowMap.size();
    2207          29 :     RowMap::iterator itr, itrBeg = maRowMap.begin(), itrEnd = maRowMap.end();
    2208          29 :     RowMap::iterator itrBlkStart = maRowMap.begin(), itrBlkEnd = maRowMap.begin();
    2209          29 :     sal_uInt16 nStartXclRow = (nSize == 0) ? 0 : itrBeg->second->GetXclRow();
    2210             : 
    2211         340 :     for (itr = itrBeg; itr != itrEnd; ++itr)
    2212             :     {
    2213             :         // find end of row block
    2214         899 :         while( (itrBlkEnd != itrEnd) && (itrBlkEnd->second->GetXclRow() - nStartXclRow < EXC_ROW_ROWBLOCKSIZE) )
    2215         277 :             ++itrBlkEnd;
    2216             : 
    2217             :         // write the ROW records
    2218         311 :         RowMap::iterator itRow;
    2219         622 :         for( itRow = itrBlkStart; itRow != itrBlkEnd; ++itRow )
    2220         311 :             itRow->second->Save( rStrm );
    2221             : 
    2222             :         // write the cell records
    2223         622 :         for( itRow = itrBlkStart; itRow != itrBlkEnd; ++itRow )
    2224         311 :              itRow->second->WriteCellList( rStrm );
    2225             : 
    2226         311 :         itrBlkStart = (itrBlkEnd == itrEnd) ? itrBlkEnd : itrBlkEnd++;
    2227         311 :         nStartXclRow += EXC_ROW_ROWBLOCKSIZE;
    2228             :     }
    2229          29 : }
    2230             : 
    2231         100 : void XclExpRowBuffer::SaveXml( XclExpXmlStream& rStrm )
    2232             : {
    2233         100 :     sal_Int32 nNonEmpty = 0;
    2234         100 :     RowMap::iterator itr = maRowMap.begin(), itrEnd = maRowMap.end();
    2235         708 :     for (; itr != itrEnd; ++itr)
    2236         608 :         if (itr->second->IsEnabled())
    2237         395 :             ++nNonEmpty;
    2238             : 
    2239         100 :     if (nNonEmpty == 0)
    2240             :     {
    2241          53 :         rStrm.GetCurrentStream()->singleElement( XML_sheetData, FSEND );
    2242         153 :         return;
    2243             :     }
    2244             : 
    2245          47 :     sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
    2246          47 :     rWorksheet->startElement( XML_sheetData, FSEND );
    2247         549 :     for (itr = maRowMap.begin(); itr != itrEnd; ++itr)
    2248         502 :         itr->second->SaveXml(rStrm);
    2249          47 :     rWorksheet->endElement( XML_sheetData );
    2250             : }
    2251             : 
    2252        3473 : XclExpRow& XclExpRowBuffer::GetOrCreateRow( sal_uInt32 nXclRow, bool bRowAlwaysEmpty )
    2253             : {
    2254        3473 :     RowMap::iterator itr = maRowMap.begin();
    2255        3473 :     ScDocument& rDoc = GetRoot().GetDoc();
    2256        3473 :     SCTAB nScTab = GetRoot().GetCurrScTab();
    2257   107748841 :     for ( size_t nFrom = maRowMap.size(); nFrom <= nXclRow; ++nFrom )
    2258             :     {
    2259   107745368 :         itr = maRowMap.find(nFrom);
    2260   107745368 :         if ( itr == maRowMap.end() )
    2261             :         {
    2262             :             // only create RowMap entries for rows that differ from previous,
    2263             :             // or if it is the desired row
    2264   107741892 :             if ( !nFrom || ( nFrom == nXclRow ) || ( nFrom && ( rDoc.GetRowHeight(nFrom, nScTab, false) != rDoc.GetRowHeight(nFrom-1, nScTab, false) ) ) )
    2265             :             {
    2266         919 :                 RowRef p(new XclExpRow(GetRoot(), nFrom, maOutlineBfr, bRowAlwaysEmpty));
    2267         919 :                 maRowMap.insert(RowMap::value_type(nFrom, p));
    2268             :             }
    2269             :         }
    2270             :     }
    2271        3473 :     itr = maRowMap.find(nXclRow);
    2272        3473 :     return *itr->second;
    2273             : 
    2274             : }
    2275             : 
    2276             : // Cell Table
    2277             : 
    2278         129 : XclExpCellTable::XclExpCellTable( const XclExpRoot& rRoot ) :
    2279             :     XclExpRoot( rRoot ),
    2280             :     maColInfoBfr( rRoot ),
    2281             :     maRowBfr( rRoot ),
    2282             :     maArrayBfr( rRoot ),
    2283             :     maShrfmlaBfr( rRoot ),
    2284             :     maTableopBfr( rRoot ),
    2285         129 :     mxDefrowheight( new XclExpDefrowheight ),
    2286         129 :     mxGuts( new XclExpGuts( rRoot ) ),
    2287         129 :     mxNoteList( new XclExpNoteList ),
    2288         129 :     mxMergedcells( new XclExpMergedcells( rRoot ) ),
    2289         129 :     mxHyperlinkList( new XclExpHyperlinkList ),
    2290         129 :     mxDval( new XclExpDval( rRoot ) ),
    2291         903 :     mxExtLst( new XclExtLst( rRoot ) )
    2292             : {
    2293         129 :     ScDocument& rDoc = GetDoc();
    2294         129 :     SCTAB nScTab = GetCurrScTab();
    2295         129 :     SvNumberFormatter& rFormatter = GetFormatter();
    2296             : 
    2297             :     // maximum sheet limits
    2298         129 :     SCCOL nMaxScCol = GetMaxPos().Col();
    2299         129 :     SCROW nMaxScRow = GetMaxPos().Row();
    2300             : 
    2301             :     // find used area (non-empty cells)
    2302             :     SCCOL nLastUsedScCol;
    2303             :     SCROW nLastUsedScRow;
    2304         129 :     rDoc.GetTableArea( nScTab, nLastUsedScCol, nLastUsedScRow );
    2305             : 
    2306         129 :     if(nLastUsedScCol > nMaxScCol)
    2307           0 :         nLastUsedScCol = nMaxScCol;
    2308             : 
    2309         129 :     if(nLastUsedScRow > nMaxScRow)
    2310           0 :         nLastUsedScRow = nMaxScRow;
    2311             : 
    2312         129 :     ScRange aUsedRange( 0, 0, nScTab, nLastUsedScCol, nLastUsedScRow, nScTab );
    2313         129 :     GetAddressConverter().ValidateRange( aUsedRange, true );
    2314         129 :     nLastUsedScCol = aUsedRange.aEnd.Col();
    2315         129 :     nLastUsedScRow = aUsedRange.aEnd.Row();
    2316             : 
    2317             :     // first row without any set attributes (height/hidden/...)
    2318         129 :     SCROW nFirstUnflaggedScRow = rDoc.GetLastFlaggedRow( nScTab ) + 1;
    2319             : 
    2320             :     // find range of outlines
    2321         129 :     SCROW nFirstUngroupedScRow = 0;
    2322         129 :     if( const ScOutlineTable* pOutlineTable = rDoc.GetOutlineTable( nScTab ) )
    2323             :     {
    2324             :         SCCOLROW nScStartPos, nScEndPos;
    2325          14 :         const ScOutlineArray& rRowArray = pOutlineTable->GetRowArray();
    2326          14 :         rRowArray.GetRange( nScStartPos, nScEndPos );
    2327             :         // +1 because open/close button is in next row in Excel, +1 for "end->first unused"
    2328          14 :         nFirstUngroupedScRow = static_cast< SCROW >( nScEndPos + 2 );
    2329             :     }
    2330             : 
    2331             :     // column settings
    2332             :     /*  #i30411# Files saved with SO7/OOo1.x with nonstandard default column
    2333             :         formatting cause big Excel files, because all rows from row 1 to row
    2334             :         32000 are exported. Now, if the used area goes exactly to row 32000,
    2335             :         use this row as default and ignore all rows >32000.
    2336             :         #i59220# Tolerance of +-128 rows for inserted/removed rows. */
    2337         129 :     if( (31871 <= nLastUsedScRow) && (nLastUsedScRow <= 32127) && (nFirstUnflaggedScRow < nLastUsedScRow) && (nFirstUngroupedScRow <= nLastUsedScRow) )
    2338           0 :         nMaxScRow = nLastUsedScRow;
    2339         129 :     maColInfoBfr.Initialize( nMaxScRow );
    2340             : 
    2341             :     // range for cell iterator
    2342         129 :     SCCOL nLastIterScCol = nMaxScCol;
    2343         129 :     SCROW nLastIterScRow = ulimit_cast< SCROW >( nLastUsedScRow, nMaxScRow );
    2344         129 :     ScUsedAreaIterator aIt( &rDoc, nScTab, 0, 0, nLastIterScCol, nLastIterScRow );
    2345             : 
    2346             :     // activate the correct segment and sub segment at the progress bar
    2347         129 :     GetProgressBar().ActivateCreateRowsSegment();
    2348             : 
    2349        3473 :     for( bool bIt = aIt.GetNext(); bIt; bIt = aIt.GetNext() )
    2350             :     {
    2351        3344 :         SCCOL nScCol = aIt.GetStartCol();
    2352        3344 :         SCROW nScRow = aIt.GetRow();
    2353        3344 :         SCCOL nLastScCol = aIt.GetEndCol();
    2354        3344 :         ScAddress aScPos( nScCol, nScRow, nScTab );
    2355             : 
    2356        3344 :         XclAddress aXclPos( static_cast< sal_uInt16 >( nScCol ), static_cast< sal_uInt32 >( nScRow ) );
    2357        3344 :         sal_uInt16 nLastXclCol = static_cast< sal_uInt16 >( nLastScCol );
    2358             : 
    2359        3344 :         const ScRefCellValue& rScCell = aIt.GetCell();
    2360        3344 :         XclExpCellRef xCell;
    2361             : 
    2362        3344 :         const ScPatternAttr* pPattern = aIt.GetPattern();
    2363             : 
    2364             :         // handle overlapped merged cells before creating the cell record
    2365        3344 :         sal_uInt32 nMergeBaseXFId = EXC_XFID_NOTFOUND;
    2366        3344 :         bool bIsMergedBase = false;
    2367        3344 :         if( pPattern )
    2368             :         {
    2369        1694 :             const SfxItemSet& rItemSet = pPattern->GetItemSet();
    2370             :             // base cell in a merged range
    2371        1694 :             const ScMergeAttr& rMergeItem = GETITEM( rItemSet, ScMergeAttr, ATTR_MERGE );
    2372        1694 :             bIsMergedBase = rMergeItem.IsMerged();
    2373             :             /*  overlapped cell in a merged range; in Excel all merged cells
    2374             :                 must contain same XF index, for correct border */
    2375        1694 :             const ScMergeFlagAttr& rMergeFlagItem = GETITEM( rItemSet, ScMergeFlagAttr, ATTR_MERGE_FLAG );
    2376        1694 :             if( rMergeFlagItem.IsOverlapped() )
    2377          34 :                 nMergeBaseXFId = mxMergedcells->GetBaseXFId( aScPos );
    2378             :         }
    2379             : 
    2380        6688 :         OUString aAddNoteText;    // additional text to be appended to a note
    2381             : 
    2382        3344 :         switch (rScCell.meType)
    2383             :         {
    2384             :             case CELLTYPE_VALUE:
    2385             :             {
    2386        1231 :                 double fValue = rScCell.mfValue;
    2387             : 
    2388             :                 // try to create a Boolean cell
    2389        1231 :                 if( pPattern && ((fValue == 0.0) || (fValue == 1.0)) )
    2390             :                 {
    2391          54 :                     sal_uLong nScNumFmt = GETITEMVALUE( pPattern->GetItemSet(), SfxUInt32Item, ATTR_VALUE_FORMAT, sal_uLong );
    2392          54 :                     if( rFormatter.GetType( nScNumFmt ) == css::util::NumberFormat::LOGICAL )
    2393             :                         xCell.reset( new XclExpBooleanCell(
    2394           0 :                             GetRoot(), aXclPos, pPattern, nMergeBaseXFId, fValue != 0.0 ) );
    2395             :                 }
    2396             : 
    2397             :                 // try to create an RK value (compressed floating-point number)
    2398             :                 sal_Int32 nRkValue;
    2399        1231 :                 if( !xCell && XclTools::GetRKFromDouble( nRkValue, fValue ) )
    2400             :                     xCell.reset( new XclExpRkCell(
    2401         998 :                         GetRoot(), aXclPos, pPattern, nMergeBaseXFId, nRkValue ) );
    2402             : 
    2403             :                 // else: simple floating-point number cell
    2404        1231 :                 if( !xCell )
    2405             :                     xCell.reset( new XclExpNumberCell(
    2406         233 :                         GetRoot(), aXclPos, pPattern, nMergeBaseXFId, fValue ) );
    2407             :             }
    2408        1231 :             break;
    2409             : 
    2410             :             case CELLTYPE_STRING:
    2411             :             {
    2412             :                 xCell.reset(new XclExpLabelCell(
    2413         447 :                     GetRoot(), aXclPos, pPattern, nMergeBaseXFId, rScCell.mpString->getString()));
    2414             :             }
    2415         447 :             break;
    2416             : 
    2417             :             case CELLTYPE_EDIT:
    2418             :             {
    2419           2 :                 XclExpHyperlinkHelper aLinkHelper( GetRoot(), aScPos );
    2420             :                 xCell.reset(new XclExpLabelCell(
    2421           2 :                     GetRoot(), aXclPos, pPattern, nMergeBaseXFId, rScCell.mpEditText, aLinkHelper));
    2422             : 
    2423             :                 // add a single created HLINK record to the record list
    2424           2 :                 if( aLinkHelper.HasLinkRecord() )
    2425           0 :                     mxHyperlinkList->AppendRecord( aLinkHelper.GetLinkRecord() );
    2426             :                 // add list of multiple URLs to the additional cell note text
    2427           2 :                 if( aLinkHelper.HasMultipleUrls() )
    2428           0 :                     aAddNoteText = ScGlobal::addToken( aAddNoteText, aLinkHelper.GetUrlList(), '\n', 2 );
    2429             :             }
    2430           2 :             break;
    2431             : 
    2432             :             case CELLTYPE_FORMULA:
    2433             :             {
    2434             :                 xCell.reset(new XclExpFormulaCell(
    2435        1111 :                     GetRoot(), aXclPos, pPattern, nMergeBaseXFId,
    2436        1111 :                     *rScCell.mpFormula, maArrayBfr, maShrfmlaBfr, maTableopBfr));
    2437             :             }
    2438        1111 :             break;
    2439             : 
    2440             :             default:
    2441             :                 OSL_FAIL( "XclExpCellTable::XclExpCellTable - unknown cell type" );
    2442             :                 // run-through!
    2443             :             case CELLTYPE_NONE:
    2444             :             {
    2445             :                 xCell.reset( new XclExpBlankCell(
    2446         553 :                     GetRoot(), aXclPos, nLastXclCol, pPattern, nMergeBaseXFId ) );
    2447             :             }
    2448         553 :             break;
    2449             :         }
    2450             : 
    2451             :         // insert the cell into the current row
    2452        3344 :         if( xCell )
    2453        3344 :             maRowBfr.AppendCell( xCell, bIsMergedBase );
    2454             : 
    2455        3344 :         if ( !aAddNoteText.isEmpty()  )
    2456           0 :             mxNoteList->AppendNewRecord( new XclExpNote( GetRoot(), aScPos, NULL, aAddNoteText ) );
    2457             : 
    2458             :         // other sheet contents
    2459        3344 :         if( pPattern )
    2460             :         {
    2461        1694 :             const SfxItemSet& rItemSet = pPattern->GetItemSet();
    2462             : 
    2463             :             // base cell in a merged range
    2464        1694 :             if( bIsMergedBase )
    2465             :             {
    2466           6 :                 const ScMergeAttr& rMergeItem = GETITEM( rItemSet, ScMergeAttr, ATTR_MERGE );
    2467           6 :                 ScRange aScRange( aScPos );
    2468           6 :                 aScRange.aEnd.IncCol( rMergeItem.GetColMerge() - 1 );
    2469           6 :                 aScRange.aEnd.IncRow( rMergeItem.GetRowMerge() - 1 );
    2470           6 :                 sal_uInt32 nXFId = xCell ? xCell->GetFirstXFId() : EXC_XFID_NOTFOUND;
    2471             :                 // blank cells merged vertically may occur repeatedly
    2472             :                 OSL_ENSURE( (aScRange.aStart.Col() == aScRange.aEnd.Col()) || (nScCol == nLastScCol),
    2473             :                     "XclExpCellTable::XclExpCellTable - invalid repeated blank merged cell" );
    2474          12 :                 for( SCCOL nIndex = nScCol; nIndex <= nLastScCol; ++nIndex )
    2475             :                 {
    2476           6 :                     mxMergedcells->AppendRange( aScRange, nXFId );
    2477           6 :                     aScRange.aStart.IncCol();
    2478           6 :                     aScRange.aEnd.IncCol();
    2479             :                 }
    2480             :             }
    2481             : 
    2482             :             // data validation
    2483        1694 :             if( ScfTools::CheckItem( rItemSet, ATTR_VALIDDATA, false ) )
    2484             :             {
    2485           0 :                 sal_uLong nScHandle = GETITEMVALUE( rItemSet, SfxUInt32Item, ATTR_VALIDDATA, sal_uLong );
    2486           0 :                 ScRange aScRange( aScPos );
    2487           0 :                 aScRange.aEnd.SetCol( nLastScCol );
    2488           0 :                 mxDval->InsertCellRange( aScRange, nScHandle );
    2489             :             }
    2490             :         }
    2491        3344 :     }
    2492             : 
    2493             :     // create missing row settings for rows anyhow flagged or with outlines
    2494         129 :     maRowBfr.CreateRows( ::std::max( nFirstUnflaggedScRow, nFirstUngroupedScRow ) );
    2495         129 : }
    2496             : 
    2497         129 : void XclExpCellTable::Finalize()
    2498             : {
    2499             :     // Finalize multiple operations.
    2500         129 :     maTableopBfr.Finalize();
    2501             : 
    2502             :     /*  Finalize column buffer. This calculates column default XF indexes from
    2503             :         the XF identifiers and fills a vector with these XF indexes. */
    2504         129 :     ScfUInt16Vec aColXFIndexes;
    2505         129 :     maColInfoBfr.Finalize( aColXFIndexes );
    2506             : 
    2507             :     /*  Finalize row buffer. This calculates all cell XF indexes from the XF
    2508             :         identifiers. Then the XF index vector aColXFIndexes (filled above) is
    2509             :         used to calculate the row default formats. With this, all unneeded blank
    2510             :         cell records (equal to row default or column default) will be removed.
    2511             :         The function returns the (most used) default row format in aDefRowData. */
    2512         129 :     XclExpDefaultRowData aDefRowData;
    2513         129 :     maRowBfr.Finalize( aDefRowData, aColXFIndexes );
    2514             : 
    2515             :     // Initialize the DEFROWHEIGHT record.
    2516         129 :     mxDefrowheight->SetDefaultData( aDefRowData );
    2517         129 : }
    2518             : 
    2519         745 : XclExpRecordRef XclExpCellTable::CreateRecord( sal_uInt16 nRecId ) const
    2520             : {
    2521         745 :     XclExpRecordRef xRec;
    2522         745 :     switch( nRecId )
    2523             :     {
    2524         100 :         case EXC_ID3_DIMENSIONS:    xRec.reset( new XclExpDelegatingRecord( &const_cast<XclExpRowBuffer*>(&maRowBfr)->GetDimensions() ) );   break;
    2525         129 :         case EXC_ID2_DEFROWHEIGHT:  xRec = mxDefrowheight;  break;
    2526         129 :         case EXC_ID_GUTS:           xRec = mxGuts;          break;
    2527           0 :         case EXC_ID_NOTE:           xRec = mxNoteList;      break;
    2528         129 :         case EXC_ID_MERGEDCELLS:    xRec = mxMergedcells;   break;
    2529         129 :         case EXC_ID_HLINK:          xRec = mxHyperlinkList; break;
    2530         129 :         case EXC_ID_DVAL:           xRec = mxDval;          break;
    2531           0 :         case EXC_ID_EXTLST:         xRec = mxExtLst;        break;
    2532             :         default:    OSL_FAIL( "XclExpCellTable::CreateRecord - unknown record id" );
    2533             :     }
    2534         745 :     return xRec;
    2535             : }
    2536             : 
    2537          29 : void XclExpCellTable::Save( XclExpStream& rStrm )
    2538             : {
    2539             :     // DEFCOLWIDTH and COLINFOs
    2540          29 :     maColInfoBfr.Save( rStrm );
    2541             :     // ROWs and cell records
    2542          29 :     maRowBfr.Save( rStrm );
    2543          29 : }
    2544             : 
    2545         100 : void XclExpCellTable::SaveXml( XclExpXmlStream& rStrm )
    2546             : {
    2547             :     // DEFAULT row height
    2548         100 :     XclExpDefaultRowData& rDefData = mxDefrowheight->GetDefaultData();
    2549         100 :     sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
    2550             :     rWorksheet->startElement( XML_sheetFormatPr,
    2551         100 :         XML_defaultRowHeight, OString::number( (double) rDefData.mnHeight / 20.0 ).getStr(), FSEND );
    2552         100 :     rWorksheet->endElement( XML_sheetFormatPr );
    2553             : 
    2554         100 :     maColInfoBfr.SaveXml( rStrm );
    2555         100 :     maRowBfr.SaveXml( rStrm );
    2556         100 :     mxExtLst->SaveXml( rStrm );
    2557         130 : }
    2558             : 
    2559             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11