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

Generated by: LCOV version 1.10