LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/sc/source/filter/oox - sheetdatabuffer.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 184 382 48.2 %
Date: 2013-07-09 Functions: 26 46 56.5 %
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 "sheetdatabuffer.hxx"
      21             : 
      22             : #include <algorithm>
      23             : #include <com/sun/star/sheet/XArrayFormulaTokens.hpp>
      24             : #include <com/sun/star/sheet/XCellRangeData.hpp>
      25             : #include <com/sun/star/sheet/XFormulaTokens.hpp>
      26             : #include <com/sun/star/sheet/XMultipleOperation.hpp>
      27             : #include <com/sun/star/table/XCell.hpp>
      28             : #include <com/sun/star/text/XText.hpp>
      29             : #include <com/sun/star/util/DateTime.hpp>
      30             : #include <com/sun/star/util/NumberFormat.hpp>
      31             : #include <com/sun/star/util/XMergeable.hpp>
      32             : #include <com/sun/star/util/XNumberFormatTypes.hpp>
      33             : #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
      34             : #include <rtl/ustrbuf.hxx>
      35             : #include <editeng/boxitem.hxx>
      36             : #include <editeng/editobj.hxx>
      37             : #include <svl/eitem.hxx>
      38             : #include "oox/helper/containerhelper.hxx"
      39             : #include "oox/helper/propertymap.hxx"
      40             : #include "oox/helper/propertyset.hxx"
      41             : #include "oox/token/tokens.hxx"
      42             : #include "addressconverter.hxx"
      43             : #include "biffinputstream.hxx"
      44             : #include "formulaparser.hxx"
      45             : #include "sharedstringsbuffer.hxx"
      46             : #include "unitconverter.hxx"
      47             : #include "convuno.hxx"
      48             : #include "markdata.hxx"
      49             : #include "rangelst.hxx"
      50             : #include "document.hxx"
      51             : #include "scitems.hxx"
      52             : #include "formulacell.hxx"
      53             : 
      54             : namespace oox {
      55             : namespace xls {
      56             : 
      57             : // ============================================================================
      58             : 
      59             : using namespace ::com::sun::star::lang;
      60             : using namespace ::com::sun::star::sheet;
      61             : using namespace ::com::sun::star::table;
      62             : using namespace ::com::sun::star::text;
      63             : using namespace ::com::sun::star::uno;
      64             : using namespace ::com::sun::star::util;
      65             : 
      66             : 
      67             : // ============================================================================
      68             : 
      69          43 : CellModel::CellModel() :
      70             :     mnCellType( XML_TOKEN_INVALID ),
      71             :     mnXfId( -1 ),
      72          43 :     mbShowPhonetic( false )
      73             : {
      74          43 : }
      75             : 
      76             : // ----------------------------------------------------------------------------
      77             : 
      78          43 : CellFormulaModel::CellFormulaModel() :
      79             :     mnFormulaType( XML_TOKEN_INVALID ),
      80          43 :     mnSharedId( -1 )
      81             : {
      82          43 : }
      83             : 
      84           0 : bool CellFormulaModel::isValidArrayRef( const CellAddress& rCellAddr )
      85             : {
      86             :     return
      87           0 :         (maFormulaRef.Sheet == rCellAddr.Sheet) &&
      88           0 :         (maFormulaRef.StartColumn == rCellAddr.Column) &&
      89           0 :         (maFormulaRef.StartRow == rCellAddr.Row);
      90             : }
      91             : 
      92           1 : bool CellFormulaModel::isValidSharedRef( const CellAddress& rCellAddr )
      93             : {
      94             :     return
      95           2 :         (maFormulaRef.Sheet == rCellAddr.Sheet) &&
      96           3 :         (maFormulaRef.StartColumn <= rCellAddr.Column) && (rCellAddr.Column <= maFormulaRef.EndColumn) &&
      97           3 :         (maFormulaRef.StartRow <= rCellAddr.Row) && (rCellAddr.Row <= maFormulaRef.EndRow);
      98             : }
      99             : 
     100             : // ----------------------------------------------------------------------------
     101             : 
     102          43 : DataTableModel::DataTableModel() :
     103             :     mb2dTable( false ),
     104             :     mbRowTable( false ),
     105             :     mbRef1Deleted( false ),
     106          43 :     mbRef2Deleted( false )
     107             : {
     108          43 : }
     109             : 
     110             : // ============================================================================
     111             : 
     112          43 : CellBlockBuffer::CellBlockBuffer( const WorksheetHelper& rHelper ) :
     113             :     WorksheetHelper( rHelper ),
     114          43 :     mnCurrRow( -1 )
     115             : {
     116          43 : }
     117             : 
     118         260 : void CellBlockBuffer::setColSpans( sal_Int32 nRow, const ValueRangeSet& rColSpans )
     119             : {
     120             :     OSL_ENSURE( maColSpans.count( nRow ) == 0, "CellBlockBuffer::setColSpans - multiple column spans for the same row" );
     121             :     OSL_ENSURE( (mnCurrRow < nRow) && (maColSpans.empty() || (maColSpans.rbegin()->first < nRow)), "CellBlockBuffer::setColSpans - rows are unsorted" );
     122         260 :     if( (mnCurrRow < nRow) && (maColSpans.count( nRow ) == 0) )
     123         260 :         maColSpans[ nRow ] = rColSpans.getRanges();
     124         260 : }
     125             : 
     126          43 : void CellBlockBuffer::finalizeImport()
     127             : {
     128          43 : }
     129             : 
     130             : // ============================================================================
     131             : 
     132          43 : SheetDataBuffer::SheetDataBuffer( const WorksheetHelper& rHelper ) :
     133             :     WorksheetHelper( rHelper ),
     134             :     maCellBlocks( rHelper ),
     135          43 :     mbPendingSharedFmla( false )
     136             : {
     137          43 : }
     138             : 
     139         260 : void SheetDataBuffer::setColSpans( sal_Int32 nRow, const ValueRangeSet& rColSpans )
     140             : {
     141         260 :     maCellBlocks.setColSpans( nRow, rColSpans );
     142         260 : }
     143             : 
     144           6 : void SheetDataBuffer::setBlankCell( const CellModel& rModel )
     145             : {
     146           6 :     setCellFormat( rModel );
     147           6 : }
     148             : 
     149         737 : void SheetDataBuffer::setValueCell( const CellModel& rModel, double fValue )
     150             : {
     151         737 :     putValue( rModel.maCellAddr, fValue );
     152         737 :     setCellFormat( rModel );
     153         737 : }
     154             : 
     155          66 : void SheetDataBuffer::setStringCell( const CellModel& rModel, const OUString& rText )
     156             : {
     157          66 :     putString( rModel.maCellAddr, rText );
     158          66 :     setCellFormat( rModel );
     159          66 : }
     160             : 
     161          66 : void SheetDataBuffer::setStringCell( const CellModel& rModel, const RichStringRef& rxString )
     162             : {
     163             :     OSL_ENSURE( rxString.get(), "SheetDataBuffer::setStringCell - missing rich string object" );
     164          66 :     const Font* pFirstPortionFont = getStyles().getFontFromCellXf( rModel.mnXfId ).get();
     165          66 :     OUString aText;
     166          66 :     if( rxString->extractPlainString( aText, pFirstPortionFont ) )
     167             :     {
     168          66 :         setStringCell( rModel, aText );
     169             :     }
     170             :     else
     171             :     {
     172           0 :         putRichString( rModel.maCellAddr, *rxString, pFirstPortionFont );
     173           0 :         setCellFormat( rModel );
     174          66 :     }
     175          66 : }
     176             : 
     177          66 : void SheetDataBuffer::setStringCell( const CellModel& rModel, sal_Int32 nStringId )
     178             : {
     179          66 :     RichStringRef xString = getSharedStrings().getString( nStringId );
     180          66 :     if( xString.get() )
     181          66 :         setStringCell( rModel, xString );
     182             :     else
     183           0 :         setBlankCell( rModel );
     184          66 : }
     185             : 
     186           0 : void SheetDataBuffer::setDateTimeCell( const CellModel& rModel, const ::com::sun::star::util::DateTime& rDateTime )
     187             : {
     188             :     // write serial date/time value into the cell
     189           0 :     double fSerial = getUnitConverter().calcSerialFromDateTime( rDateTime );
     190           0 :     setValueCell( rModel, fSerial );
     191             :     // set appropriate number format
     192             :     using namespace ::com::sun::star::util::NumberFormat;
     193           0 :     sal_Int16 nStdFmt = (fSerial < 1.0) ? TIME : (((rDateTime.Hours > 0) || (rDateTime.Minutes > 0) || (rDateTime.Seconds > 0)) ? DATETIME : DATE);
     194           0 :     setStandardNumFmt( rModel.maCellAddr, nStdFmt );
     195           0 : }
     196             : 
     197           0 : void SheetDataBuffer::setBooleanCell( const CellModel& rModel, bool bValue )
     198             : {
     199           0 :     setCellFormula( rModel.maCellAddr, getFormulaParser().convertBoolToFormula( bValue ) );
     200             :     // #108770# set 'Standard' number format for all Boolean cells
     201           0 :     setCellFormat( rModel, 0 );
     202           0 : }
     203             : 
     204           0 : void SheetDataBuffer::setErrorCell( const CellModel& rModel, const OUString& rErrorCode )
     205             : {
     206           0 :     setErrorCell( rModel, getUnitConverter().calcBiffErrorCode( rErrorCode ) );
     207           0 : }
     208             : 
     209           0 : void SheetDataBuffer::setErrorCell( const CellModel& rModel, sal_uInt8 nErrorCode )
     210             : {
     211           0 :     setCellFormula( rModel.maCellAddr, getFormulaParser().convertErrorToFormula( nErrorCode ) );
     212           0 :     setCellFormat( rModel );
     213           0 : }
     214             : 
     215           0 : void SheetDataBuffer::setFormulaCell( const CellModel& rModel, const ApiTokenSequence& rTokens )
     216             : {
     217           0 :     mbPendingSharedFmla = false;
     218           0 :     ApiTokenSequence aTokens;
     219             : 
     220             :     /*  Detect special token passed as placeholder for array formulas, shared
     221             :         formulas, and table operations. In BIFF, these formulas are represented
     222             :         by a single tExp resp. tTbl token. If the formula parser finds these
     223             :         tokens, it puts a single OPCODE_BAD token with the base address and
     224             :         formula type into the token sequence. This information will be
     225             :         extracted here, and in case of a shared formula, the shared formula
     226             :         buffer will generate the resulting formula token array. */
     227           0 :     ApiSpecialTokenInfo aTokenInfo;
     228           0 :     if( rTokens.hasElements() && getFormulaParser().extractSpecialTokenInfo( aTokenInfo, rTokens ) )
     229             :     {
     230             :         /*  The second member of the token info is set to true, if the formula
     231             :             represents a table operation, which will be skipped. In BIFF12 it
     232             :             is not possible to distinguish array and shared formulas
     233             :             (BIFF5/BIFF8 provide this information with a special flag in the
     234             :             FORMULA record). */
     235           0 :         if( !aTokenInfo.Second )
     236             :         {
     237             :             /*  Construct the token array representing the shared formula. If
     238             :                 the returned sequence is empty, the definition of the shared
     239             :                 formula has not been loaded yet, or the cell is part of an
     240             :                 array formula. In this case, the cell will be remembered. After
     241             :                 reading the formula definition it will be retried to insert the
     242             :                 formula via retryPendingSharedFormulaCell(). */
     243           0 :             BinAddress aBaseAddr( aTokenInfo.First );
     244           0 :             aTokens = resolveSharedFormula( aBaseAddr );
     245           0 :             if( !aTokens.hasElements() )
     246             :             {
     247           0 :                 maSharedFmlaAddr = rModel.maCellAddr;
     248           0 :                 maSharedBaseAddr = aBaseAddr;
     249           0 :                 mbPendingSharedFmla = true;
     250             :             }
     251             :         }
     252             :     }
     253             :     else
     254             :     {
     255             :         // simple formula, use the passed token array
     256           0 :         aTokens = rTokens;
     257             :     }
     258             : 
     259           0 :     setCellFormula( rModel.maCellAddr, aTokens );
     260           0 :     setCellFormat( rModel );
     261           0 : }
     262             : 
     263           0 : void SheetDataBuffer::createArrayFormula( const CellRangeAddress& rRange, const ApiTokenSequence& rTokens )
     264             : {
     265             :     /*  Array formulas will be inserted later in finalizeImport(). This is
     266             :         needed to not disturb collecting all the cells, which will be put into
     267             :         the sheet in large blocks to increase performance. */
     268           0 :     maArrayFormulas.push_back( ArrayFormula( rRange, rTokens ) );
     269           0 : }
     270             : 
     271           0 : void SheetDataBuffer::createTableOperation( const CellRangeAddress& rRange, const DataTableModel& rModel )
     272             : {
     273             :     /*  Table operations will be inserted later in finalizeImport(). This is
     274             :         needed to not disturb collecting all the cells, which will be put into
     275             :         the sheet in large blocks to increase performance. */
     276           0 :     maTableOperations.push_back( TableOperation( rRange, rModel ) );
     277           0 : }
     278             : 
     279           0 : void SheetDataBuffer::createSharedFormula( const CellAddress& rCellAddr, const ApiTokenSequence& rTokens )
     280             : {
     281           0 :     createSharedFormula( BinAddress( rCellAddr ), rTokens );
     282           0 : }
     283             : 
     284         260 : void SheetDataBuffer::setRowFormat( sal_Int32 nRow, sal_Int32 nXfId, bool bCustomFormat )
     285             : {
     286             :     // set row formatting
     287         260 :     if( bCustomFormat )
     288             :     {
     289             :         // try to expand cached row range, if formatting is equal
     290           0 :         if( (maXfIdRowRange.maRowRange.mnLast < 0) || !maXfIdRowRange.tryExpand( nRow, nXfId ) )
     291             :         {
     292             : 
     293           0 :             maXfIdRowRangeList[ maXfIdRowRange.mnXfId ].push_back( maXfIdRowRange.maRowRange );
     294           0 :             maXfIdRowRange.set( nRow, nXfId );
     295             :         }
     296             :     }
     297         260 :     else if( maXfIdRowRange.maRowRange.mnLast >= 0 )
     298             :     {
     299             :         // finish last cached row range
     300           0 :         maXfIdRowRangeList[ maXfIdRowRange.mnXfId ].push_back( maXfIdRowRange.maRowRange );
     301           0 :         maXfIdRowRange.set( -1, -1 );
     302             :     }
     303         260 : }
     304             : 
     305           1 : void SheetDataBuffer::setMergedRange( const CellRangeAddress& rRange )
     306             : {
     307           1 :     maMergedRanges.push_back( MergedRange( rRange ) );
     308           1 : }
     309             : 
     310           0 : void SheetDataBuffer::setStandardNumFmt( const CellAddress& rCellAddr, sal_Int16 nStdNumFmt )
     311             : {
     312             :     try
     313             :     {
     314           0 :         Reference< XNumberFormatsSupplier > xNumFmtsSupp( getDocument(), UNO_QUERY_THROW );
     315           0 :         Reference< XNumberFormatTypes > xNumFmtTypes( xNumFmtsSupp->getNumberFormats(), UNO_QUERY_THROW );
     316           0 :         sal_Int32 nIndex = xNumFmtTypes->getStandardFormat( nStdNumFmt, Locale() );
     317           0 :         PropertySet aPropSet( getCell( rCellAddr ) );
     318           0 :         aPropSet.setProperty( PROP_NumberFormat, nIndex );
     319             :     }
     320           0 :     catch( Exception& )
     321             :     {
     322             :     }
     323           0 : }
     324             : 
     325          27 : void addIfNotInMyMap( StylesBuffer& rStyles, std::map< std::pair< sal_Int32, sal_Int32 >, ApiCellRangeList >& rMap, sal_Int32 nXfId, sal_Int32 nFormatId, const ApiCellRangeList& rRangeList )
     326             : {
     327          27 :     Xf* pXf1 = rStyles.getCellXf( nXfId ).get();
     328          27 :     if ( pXf1 )
     329             :     {
     330          44 :         for ( std::map< std::pair< sal_Int32, sal_Int32 >, ApiCellRangeList >::iterator it = rMap.begin(), it_end = rMap.end(); it != it_end; ++it )
     331             :         {
     332          17 :             if ( it->first.second == nFormatId )
     333             :             {
     334          17 :                 Xf* pXf2 = rStyles.getCellXf( it->first.first ).get();
     335          17 :                 if ( *pXf1 == *pXf2 ) // already exists
     336             :                 {
     337             :                     // add ranges from the rangelist to the existing rangelist for the
     338             :                     // matching style ( should we check if they overlap ? )
     339           0 :                     for ( ApiCellRangeList::const_iterator iter = rRangeList.begin(), iter_end =  rRangeList.end(); iter != iter_end; ++iter )
     340           0 :                        it->second.push_back( *iter );
     341          27 :                     return;
     342             :                 }
     343             :             }
     344             :         }
     345          54 :         rMap[ std::pair<sal_Int32, sal_Int32>( nXfId, nFormatId ) ] = rRangeList;
     346             :     }
     347             : }
     348             : 
     349          76 : void SheetDataBuffer::addColXfStyle( sal_Int32 nXfId, sal_Int32 nFormatId, const ::com::sun::star::table::CellRangeAddress& rAddress, bool bProcessRowRange )
     350             : {
     351          76 :     RowRangeStyle aStyleRows;
     352          76 :     aStyleRows.mnNumFmt.first = nXfId;
     353          76 :     aStyleRows.mnNumFmt.second = nFormatId;
     354          76 :     aStyleRows.mnStartRow = rAddress.StartRow;
     355          76 :     aStyleRows.mnEndRow = rAddress.EndRow;
     356         183 :     for ( sal_Int32 nCol = rAddress.StartColumn; nCol <= rAddress.EndColumn; ++nCol )
     357             :     {
     358         107 :         if ( !bProcessRowRange )
     359         107 :             maStylesPerColumn[ nCol ].insert( aStyleRows );
     360             :         else
     361             :         {
     362           0 :             RowStyles& rRowStyles =  maStylesPerColumn[ nCol ];
     363             :             // If the rowrange style includes rows already
     364             :             // allocated to a style then we need to split
     365             :             // the range style Rows into sections ( to
     366             :             // occupy only rows that have no style definition )
     367             : 
     368             :             // We dont want to set any rowstyle 'rows'
     369             :             // for rows where there is an existing 'style' )
     370           0 :             std::vector< RowRangeStyle > aRangeRowsSplits;
     371             : 
     372           0 :             RowStyles::iterator rows_it = rRowStyles.begin();
     373           0 :             RowStyles::iterator rows_end = rRowStyles.end();
     374           0 :             bool bAddRange = true;
     375           0 :             for ( ; rows_it != rows_end; ++rows_it )
     376             :             {
     377           0 :                 const RowRangeStyle& r = *rows_it;
     378             :                 // if row is completely within existing style, discard it
     379           0 :                 if ( aStyleRows.mnStartRow >= r.mnStartRow && aStyleRows.mnEndRow <= r.mnEndRow )
     380           0 :                     bAddRange = false;
     381           0 :                 else if ( aStyleRows.mnStartRow <= r.mnStartRow )
     382             :                 {
     383             :                     // not intersecting at all?, if so finish as none left
     384             :                     // to check ( row ranges are in ascending order
     385           0 :                     if ( aStyleRows.mnEndRow < r.mnStartRow )
     386           0 :                         break;
     387           0 :                     else if ( aStyleRows.mnEndRow <= r.mnEndRow )
     388             :                     {
     389           0 :                         aStyleRows.mnEndRow = r.mnStartRow - 1;
     390           0 :                         break;
     391             :                     }
     392           0 :                     if ( aStyleRows.mnStartRow < r.mnStartRow )
     393             :                     {
     394           0 :                         RowRangeStyle aSplit = aStyleRows;
     395           0 :                         aSplit.mnEndRow = r.mnStartRow - 1;
     396           0 :                         aRangeRowsSplits.push_back( aSplit );
     397             :                     }
     398             :                 }
     399             :             }
     400           0 :             std::vector< RowRangeStyle >::iterator splits_it = aRangeRowsSplits.begin();
     401           0 :             std::vector< RowRangeStyle >::iterator splits_end = aRangeRowsSplits.end();
     402           0 :             for ( ; splits_it != splits_end; ++splits_it )
     403           0 :                 rRowStyles.insert( *splits_it );
     404           0 :             if ( bAddRange )
     405           0 :                 rRowStyles.insert( aStyleRows );
     406             :         }
     407             :     }
     408          76 : }
     409          43 : void SheetDataBuffer::finalizeImport()
     410             : {
     411             :     // insert all cells of all open cell blocks
     412          43 :     maCellBlocks.finalizeImport();
     413             : 
     414             :     // create all array formulas
     415          43 :     for( ArrayFormulaList::iterator aIt = maArrayFormulas.begin(), aEnd = maArrayFormulas.end(); aIt != aEnd; ++aIt )
     416           0 :         finalizeArrayFormula( aIt->first, aIt->second );
     417             : 
     418             :     // create all table operations
     419          43 :     for( TableOperationList::iterator aIt = maTableOperations.begin(), aEnd = maTableOperations.end(); aIt != aEnd; ++aIt )
     420           0 :         finalizeTableOperation( aIt->first, aIt->second );
     421             : 
     422             :     // write default formatting of remaining row range
     423          43 :     maXfIdRowRangeList[ maXfIdRowRange.mnXfId ].push_back( maXfIdRowRange.maRowRange );
     424             : 
     425          43 :     std::map< std::pair< sal_Int32, sal_Int32 >, ApiCellRangeList > rangeStyleListMap;
     426          70 :     for( XfIdRangeListMap::const_iterator aIt = maXfIdRangeLists.begin(), aEnd = maXfIdRangeLists.end(); aIt != aEnd; ++aIt )
     427             :     {
     428          27 :         addIfNotInMyMap( getStyles(), rangeStyleListMap, aIt->first.first, aIt->first.second, aIt->second );
     429             :     }
     430             :     // gather all ranges that have the same style and apply them in bulk
     431          70 :     for (  std::map< std::pair< sal_Int32, sal_Int32 >, ApiCellRangeList >::iterator it = rangeStyleListMap.begin(), it_end = rangeStyleListMap.end(); it != it_end; ++it )
     432             :     {
     433          27 :         const ApiCellRangeList& rRanges( it->second );
     434         103 :         for ( ApiCellRangeList::const_iterator it_range = rRanges.begin(), it_rangeend = rRanges.end(); it_range!=it_rangeend; ++it_range )
     435          76 :             addColXfStyle( it->first.first, it->first.second, *it_range );
     436             :     }
     437             : 
     438          86 :     for ( std::map< sal_Int32, std::vector< ValueRange > >::iterator it = maXfIdRowRangeList.begin(), it_end =  maXfIdRowRangeList.end(); it != it_end; ++it )
     439             :     {
     440          43 :         ApiCellRangeList rangeList;
     441          43 :         AddressConverter& rAddrConv = getAddressConverter();
     442             :         // get all row ranges for id
     443          86 :         for ( std::vector< ValueRange >::iterator rangeIter = it->second.begin(), rangeIter_end = it->second.end(); rangeIter != rangeIter_end; ++rangeIter )
     444             :         {
     445          43 :             if ( it->first == -1 ) // it's a dud skip it
     446          43 :                 continue;
     447           0 :             CellRangeAddress aRange( getSheetIndex(), 0, rangeIter->mnFirst, rAddrConv.getMaxApiAddress().Column, rangeIter->mnLast );
     448             : 
     449           0 :             addColXfStyle( it->first, -1, aRange, true );
     450             :         }
     451          43 :     }
     452             : 
     453          43 :     ScDocument& rDoc = getScDocument();
     454          43 :     StylesBuffer& rStyles = getStyles();
     455         117 :     for ( ColStyles::iterator col = maStylesPerColumn.begin(), col_end = maStylesPerColumn.end(); col != col_end; ++col )
     456             :     {
     457          74 :         RowStyles& rRowStyles = col->second;
     458          74 :         std::list<ScAttrEntry> aAttrs;
     459          74 :         SCCOL nScCol = static_cast< SCCOL >( col->first );
     460         181 :         for ( RowStyles::iterator rRows = rRowStyles.begin(), rRows_end = rRowStyles.end(); rRows != rRows_end; ++rRows )
     461             :         {
     462         107 :              Xf* pXf = rStyles.getCellXf( rRows->mnNumFmt.first ).get();
     463             : 
     464         107 :              if ( pXf )
     465         107 :                  pXf->applyPatternToAttrList( aAttrs,  rRows->mnStartRow,  rRows->mnEndRow,  rRows->mnNumFmt.second );
     466             :         }
     467          74 :         if (aAttrs.empty() || aAttrs.back().nRow != MAXROW)
     468             :         {
     469             :             ScAttrEntry aEntry;
     470          74 :             aEntry.nRow = MAXROW;
     471          74 :             aEntry.pPattern = rDoc.GetDefPattern();
     472          74 :             aAttrs.push_back(aEntry);
     473             :         }
     474             : 
     475          74 :         size_t nAttrSize = aAttrs.size();
     476          74 :         ScAttrEntry* pData = new ScAttrEntry[nAttrSize];
     477          74 :         std::list<ScAttrEntry>::const_iterator itr = aAttrs.begin(), itrEnd = aAttrs.end();
     478         302 :         for (size_t i = 0; itr != itrEnd; ++itr, ++i)
     479         228 :             pData[i] = *itr;
     480             : 
     481          74 :         rDoc.SetAttrEntries(nScCol, getSheetIndex(), pData, static_cast<SCSIZE>(nAttrSize));
     482          74 :     }
     483             : 
     484             :     // merge all cached merged ranges and update right/bottom cell borders
     485          44 :     for( MergedRangeList::iterator aIt = maMergedRanges.begin(), aEnd = maMergedRanges.end(); aIt != aEnd; ++aIt )
     486           1 :         applyCellMerging( aIt->maRange );
     487          43 :     for( MergedRangeList::iterator aIt = maCenterFillRanges.begin(), aEnd = maCenterFillRanges.end(); aIt != aEnd; ++aIt )
     488          43 :         applyCellMerging( aIt->maRange );
     489          43 : }
     490             : 
     491             : // private --------------------------------------------------------------------
     492             : 
     493          43 : SheetDataBuffer::XfIdRowRange::XfIdRowRange() :
     494             :     maRowRange( -1 ),
     495          43 :     mnXfId( -1 )
     496             : {
     497          43 : }
     498             : 
     499           0 : void SheetDataBuffer::XfIdRowRange::set( sal_Int32 nRow, sal_Int32 nXfId )
     500             : {
     501           0 :     maRowRange = ValueRange( nRow );
     502           0 :     mnXfId = nXfId;
     503           0 : }
     504             : 
     505           0 : bool SheetDataBuffer::XfIdRowRange::tryExpand( sal_Int32 nRow, sal_Int32 nXfId )
     506             : {
     507           0 :     if( mnXfId == nXfId )
     508             :     {
     509           0 :         if( maRowRange.mnLast + 1 == nRow )
     510             :         {
     511           0 :             ++maRowRange.mnLast;
     512           0 :             return true;
     513             :         }
     514           0 :         if( maRowRange.mnFirst == nRow + 1 )
     515             :         {
     516           0 :             --maRowRange.mnFirst;
     517           0 :             return true;
     518             :         }
     519             :     }
     520           0 :     return false;
     521             : }
     522             : 
     523             : 
     524           1 : SheetDataBuffer::MergedRange::MergedRange( const CellRangeAddress& rRange ) :
     525             :     maRange( rRange ),
     526           1 :     mnHorAlign( XML_TOKEN_INVALID )
     527             : {
     528           1 : }
     529             : 
     530           0 : SheetDataBuffer::MergedRange::MergedRange( const CellAddress& rAddress, sal_Int32 nHorAlign ) :
     531             :     maRange( rAddress.Sheet, rAddress.Column, rAddress.Row, rAddress.Column, rAddress.Row ),
     532           0 :     mnHorAlign( nHorAlign )
     533             : {
     534           0 : }
     535             : 
     536           0 : bool SheetDataBuffer::MergedRange::tryExpand( const CellAddress& rAddress, sal_Int32 nHorAlign )
     537             : {
     538           0 :     if( (mnHorAlign == nHorAlign) && (maRange.StartRow == rAddress.Row) &&
     539           0 :         (maRange.EndRow == rAddress.Row) && (maRange.EndColumn + 1 == rAddress.Column) )
     540             :     {
     541           0 :         ++maRange.EndColumn;
     542           0 :         return true;
     543             :     }
     544           0 :     return false;
     545             : }
     546             : 
     547             : // ----------------------------------------------------------------------------
     548             : 
     549           0 : void SheetDataBuffer::setCellFormula( const CellAddress& rCellAddr, const ApiTokenSequence& rTokens )
     550             : {
     551           0 :     if( rTokens.hasElements() )
     552             :     {
     553           0 :         putFormulaTokens( rCellAddr, rTokens );
     554             :     }
     555           0 : }
     556             : 
     557           0 : void SheetDataBuffer::createSharedFormula( const BinAddress& rMapKey, const ApiTokenSequence& rTokens )
     558             : {
     559             :     // create the defined name that will represent the shared formula
     560           0 :     OUString aName = OUStringBuffer().appendAscii( RTL_CONSTASCII_STRINGPARAM( "__shared_" ) ).
     561           0 :         append( static_cast< sal_Int32 >( getSheetIndex() + 1 ) ).
     562           0 :         append( sal_Unicode( '_' ) ).append( rMapKey.mnRow ).
     563           0 :         append( sal_Unicode( '_' ) ).append( rMapKey.mnCol ).makeStringAndClear();
     564           0 :     ScRangeData* pScRangeData = createNamedRangeObject( aName, rTokens, 0 );
     565           0 :     pScRangeData->SetType(RT_SHARED);
     566             : 
     567             :     // get and store the token index of the defined name
     568             :     OSL_ENSURE( maSharedFormulas.count( rMapKey ) == 0, "SheetDataBuffer::createSharedFormula - shared formula exists already" );
     569           0 :     sal_Int32 nTokenIndex = static_cast< sal_Int32 >( pScRangeData->GetIndex() );
     570           0 :     if( nTokenIndex >= 0 ) try
     571             :     {
     572             :         // store the token index in the map
     573           0 :         maSharedFormulas[ rMapKey ] = nTokenIndex;
     574             :         // retry to insert a pending shared formula cell
     575           0 :         if( mbPendingSharedFmla )
     576           0 :             setCellFormula( maSharedFmlaAddr, resolveSharedFormula( maSharedBaseAddr ) );
     577             :     }
     578           0 :     catch( Exception& )
     579             :     {
     580             :     }
     581           0 :     mbPendingSharedFmla = false;
     582           0 : }
     583             : 
     584           0 : ApiTokenSequence SheetDataBuffer::resolveSharedFormula( const BinAddress& rMapKey ) const
     585             : {
     586           0 :     sal_Int32 nTokenIndex = ContainerHelper::getMapElement( maSharedFormulas, rMapKey, -1 );
     587           0 :     return (nTokenIndex >= 0) ? getFormulaParser().convertNameToFormula( nTokenIndex ) : ApiTokenSequence();
     588             : }
     589             : 
     590           0 : void SheetDataBuffer::finalizeArrayFormula( const CellRangeAddress& rRange, const ApiTokenSequence& rTokens ) const
     591             : {
     592           0 :     Reference< XArrayFormulaTokens > xTokens( getCellRange( rRange ), UNO_QUERY );
     593             :     OSL_ENSURE( xTokens.is(), "SheetDataBuffer::finalizeArrayFormula - missing formula token interface" );
     594           0 :     if( xTokens.is() )
     595           0 :         xTokens->setArrayTokens( rTokens );
     596           0 : }
     597             : 
     598           0 : void SheetDataBuffer::finalizeTableOperation( const CellRangeAddress& rRange, const DataTableModel& rModel ) const
     599             : {
     600           0 :     sal_Int16 nSheet = getSheetIndex();
     601           0 :     bool bOk = false;
     602           0 :     if( !rModel.mbRef1Deleted && !rModel.maRef1.isEmpty() && (rRange.StartColumn > 0) && (rRange.StartRow > 0) )
     603             :     {
     604           0 :         CellRangeAddress aOpRange = rRange;
     605           0 :         CellAddress aRef1;
     606           0 :         if( getAddressConverter().convertToCellAddress( aRef1, rModel.maRef1, nSheet, true ) ) try
     607             :         {
     608           0 :             if( rModel.mb2dTable )
     609             :             {
     610           0 :                 CellAddress aRef2;
     611           0 :                 if( !rModel.mbRef2Deleted && getAddressConverter().convertToCellAddress( aRef2, rModel.maRef2, nSheet, true ) )
     612             :                 {
     613             :                     // API call expects input values inside operation range
     614           0 :                     --aOpRange.StartColumn;
     615           0 :                     --aOpRange.StartRow;
     616             :                     // formula range is top-left cell of operation range
     617           0 :                     CellRangeAddress aFormulaRange( nSheet, aOpRange.StartColumn, aOpRange.StartRow, aOpRange.StartColumn, aOpRange.StartRow );
     618             :                     // set multiple operation
     619           0 :                     Reference< XMultipleOperation > xMultOp( getCellRange( aOpRange ), UNO_QUERY_THROW );
     620           0 :                     xMultOp->setTableOperation( aFormulaRange, TableOperationMode_BOTH, aRef2, aRef1 );
     621           0 :                     bOk = true;
     622             :                 }
     623             :             }
     624           0 :             else if( rModel.mbRowTable )
     625             :             {
     626             :                 // formula range is column to the left of operation range
     627           0 :                 CellRangeAddress aFormulaRange( nSheet, aOpRange.StartColumn - 1, aOpRange.StartRow, aOpRange.StartColumn - 1, aOpRange.EndRow );
     628             :                 // API call expects input values (top row) inside operation range
     629           0 :                 --aOpRange.StartRow;
     630             :                 // set multiple operation
     631           0 :                 Reference< XMultipleOperation > xMultOp( getCellRange( aOpRange ), UNO_QUERY_THROW );
     632           0 :                 xMultOp->setTableOperation( aFormulaRange, TableOperationMode_ROW, aRef1, aRef1 );
     633           0 :                 bOk = true;
     634             :             }
     635             :             else
     636             :             {
     637             :                 // formula range is row above operation range
     638           0 :                 CellRangeAddress aFormulaRange( nSheet, aOpRange.StartColumn, aOpRange.StartRow - 1, aOpRange.EndColumn, aOpRange.StartRow - 1 );
     639             :                 // API call expects input values (left column) inside operation range
     640           0 :                 --aOpRange.StartColumn;
     641             :                 // set multiple operation
     642           0 :                 Reference< XMultipleOperation > xMultOp( getCellRange( aOpRange ), UNO_QUERY_THROW );
     643           0 :                 xMultOp->setTableOperation( aFormulaRange, TableOperationMode_COLUMN, aRef1, aRef1 );
     644           0 :                 bOk = true;
     645             :             }
     646             :         }
     647           0 :         catch( Exception& )
     648             :         {
     649             :         }
     650             :     }
     651             : 
     652             :     // on error: fill cell range with #REF! error codes
     653           0 :     if( !bOk ) try
     654             :     {
     655           0 :         Reference< XCellRangeData > xCellRangeData( getCellRange( rRange ), UNO_QUERY_THROW );
     656           0 :         size_t nWidth = static_cast< size_t >( rRange.EndColumn - rRange.StartColumn + 1 );
     657           0 :         size_t nHeight = static_cast< size_t >( rRange.EndRow - rRange.StartRow + 1 );
     658           0 :         Matrix< Any > aErrorCells( nWidth, nHeight, Any( getFormulaParser().convertErrorToFormula( BIFF_ERR_REF ) ) );
     659           0 :         xCellRangeData->setDataArray( ContainerHelper::matrixToSequenceSequence( aErrorCells ) );
     660             :     }
     661           0 :     catch( Exception& )
     662             :     {
     663             :     }
     664           0 : }
     665             : 
     666         851 : void SheetDataBuffer::setCellFormat( const CellModel& rModel, sal_Int32 nNumFmtId )
     667             : {
     668         851 :     if( (rModel.mnXfId >= 0) || (nNumFmtId >= 0) )
     669             :     {
     670         439 :         ApiCellRangeList::reverse_iterator aIt = maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, nNumFmtId ) ].rbegin();
     671         439 :         ApiCellRangeList::reverse_iterator aItEnd = maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, nNumFmtId ) ].rend();
     672             :         /* The xlsx sheet data contains row wise information.
     673             :          * It is sufficient to check if the row range size is one
     674             :          */
     675        1290 :         if(     aIt                 != aItEnd &&
     676         824 :                 aIt->Sheet          == rModel.maCellAddr.Sheet &&
     677         571 :                 aIt->StartRow       == aIt->EndRow &&
     678         696 :                 aIt->StartRow       == rModel.maCellAddr.Row &&
     679          98 :                 (aIt->EndColumn+1)  == rModel.maCellAddr.Column )
     680             :         {
     681          71 :             aIt->EndColumn++;       // Expand Column
     682             :         }
     683             :         else
     684             :         {
     685         736 :             maXfIdRangeLists[ XfIdNumFmtKey (rModel.mnXfId, nNumFmtId ) ].push_back(
     686             :                               CellRangeAddress( rModel.maCellAddr.Sheet, rModel.maCellAddr.Column, rModel.maCellAddr.Row,
     687        1104 :                               rModel.maCellAddr.Column, rModel.maCellAddr.Row ) );
     688             :         }
     689             : 
     690         439 :         aIt = maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, nNumFmtId ) ].rbegin();
     691         439 :         aItEnd = maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, nNumFmtId ) ].rend();
     692         439 :         ApiCellRangeList::reverse_iterator aItM = aIt+1;
     693        1685 :         while( aItM != aItEnd )
     694             :         {
     695        1139 :             if( aIt->Sheet == aItM->Sheet )
     696             :             {
     697             :                 /* Try to merge this with the previous range */
     698        3317 :                 if( aIt->StartRow == (aItM->EndRow + 1) &&
     699        1480 :                         aIt->StartColumn == aItM->StartColumn &&
     700         341 :                         aIt->EndColumn == aItM->EndColumn)
     701             :                 {
     702         292 :                     aItM->EndRow = aIt->EndRow;
     703         292 :                     maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, nNumFmtId ) ].pop_back();
     704         292 :                     break;
     705             :                 }
     706         847 :                 else if( aIt->StartRow > aItM->EndRow + 1 )
     707          40 :                     break; // Un-necessary to check with any other rows
     708             :             }
     709             :             else
     710           0 :                 break;
     711         807 :             ++aItM;
     712             :         }
     713             : 
     714             :         // update merged ranges for 'center across selection' and 'fill'
     715         439 :         if( const Xf* pXf = getStyles().getCellXf( rModel.mnXfId ).get() )
     716             :         {
     717         439 :             sal_Int32 nHorAlign = pXf->getAlignment().getModel().mnHorAlign;
     718         439 :             if( (nHorAlign == XML_centerContinuous) || (nHorAlign == XML_fill) )
     719             :             {
     720             :                 /*  start new merged range, if cell is not empty (#108781#),
     721             :                     or try to expand last range with empty cell */
     722           0 :                 if( rModel.mnCellType != XML_TOKEN_INVALID )
     723           0 :                     maCenterFillRanges.push_back( MergedRange( rModel.maCellAddr, nHorAlign ) );
     724           0 :                 else if( !maCenterFillRanges.empty() )
     725           0 :                     maCenterFillRanges.rbegin()->tryExpand( rModel.maCellAddr, nHorAlign );
     726             :             }
     727             :         }
     728             :     }
     729         851 : }
     730             : 
     731           0 : void SheetDataBuffer::writeXfIdRangeListProperties( sal_Int32 nXfId, sal_Int32 nNumFmtId, const ApiCellRangeList& rRanges ) const
     732             : {
     733           0 :     StylesBuffer& rStyles = getStyles();
     734           0 :     ScRangeList aList;
     735           0 :     for ( ApiCellRangeList::const_iterator it = rRanges.begin(), it_end = rRanges.end(); it!=it_end; ++it )
     736             :     {
     737           0 :         ScRange* pRange = new ScRange();
     738           0 :         ScUnoConversion::FillScRange( *pRange, *it );
     739           0 :         aList.push_back( pRange );
     740             :     }
     741           0 :     ScMarkData aMark;
     742           0 :     aMark.MarkFromRangeList( aList, false );
     743           0 :     rStyles.writeCellXfToMarkData( aMark, nXfId, nNumFmtId );
     744           0 : }
     745             : 
     746           2 : void lcl_SetBorderLine( ScDocument& rDoc, ScRange& rRange, SCTAB nScTab, sal_uInt16 nLine )
     747             : {
     748           2 :     SCCOL nFromScCol = (nLine == BOX_LINE_RIGHT) ? rRange.aEnd.Col() : rRange.aStart.Col();
     749           2 :     SCROW nFromScRow = (nLine == BOX_LINE_BOTTOM) ? rRange.aEnd.Row() : rRange.aStart.Row();
     750             : 
     751             :     const SvxBoxItem* pFromItem = static_cast< const SvxBoxItem* >(
     752           2 :         rDoc.GetAttr( nFromScCol, nFromScRow, nScTab, ATTR_BORDER ) );
     753             :     const SvxBoxItem* pToItem = static_cast< const SvxBoxItem* >(
     754           2 :         rDoc.GetAttr( rRange.aStart.Col(), rRange.aStart.Row(), nScTab, ATTR_BORDER ) );
     755             : 
     756           2 :     SvxBoxItem aNewItem( *pToItem );
     757           2 :     aNewItem.SetLine( pFromItem->GetLine( nLine ), nLine );
     758           2 :     rDoc.ApplyAttr( rRange.aStart.Col(), rRange.aStart.Row(), nScTab, aNewItem );
     759           2 : }
     760             : 
     761           1 : void SheetDataBuffer::applyCellMerging( const CellRangeAddress& rRange )
     762             : {
     763           1 :     bool bMultiCol = rRange.StartColumn < rRange.EndColumn;
     764           1 :     bool bMultiRow = rRange.StartRow < rRange.EndRow;
     765             : 
     766           1 :     ScRange aRange;
     767           1 :     ScUnoConversion::FillScRange( aRange, rRange );
     768           1 :     const ScAddress& rStart = aRange.aStart;
     769           1 :     const ScAddress& rEnd = aRange.aEnd;
     770           1 :     ScDocument& rDoc = getScDocument();
     771             :     // set correct right border
     772           1 :     if( bMultiCol )
     773           1 :         lcl_SetBorderLine( rDoc, aRange, getSheetIndex(), BOX_LINE_RIGHT );
     774             :         // set correct lower border
     775           1 :     if( bMultiRow )
     776           1 :         lcl_SetBorderLine( rDoc, aRange, getSheetIndex(), BOX_LINE_BOTTOM );
     777             :     // do merge
     778           1 :     if( bMultiCol || bMultiRow )
     779           1 :         rDoc.DoMerge( getSheetIndex(), rStart.Col(), rStart.Row(), rEnd.Col(), rEnd.Row() );
     780             :     // #i93609# merged range in a single row: test if manual row height is needed
     781           1 :     if( !bMultiRow )
     782             :     {
     783           0 :         bool bTextWrap = static_cast< const SfxBoolItem* >( rDoc.GetAttr( rStart.Col(), rStart.Row(), rStart.Tab(), ATTR_LINEBREAK ) )->GetValue();
     784           0 :         if( !bTextWrap && (rDoc.GetCellType( rStart ) == CELLTYPE_EDIT) )
     785             :         {
     786           0 :             if (const EditTextObject* pEditObj = rDoc.GetEditText(rStart))
     787           0 :                 bTextWrap = pEditObj->GetParagraphCount() > 1;
     788             :         }
     789             :     }
     790           1 : }
     791             : 
     792             : } // namespace xls
     793          15 : } // namespace oox
     794             : 
     795             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10