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

Generated by: LCOV version 1.10