1*cdf0e10cSrcweir /************************************************************************* 2*cdf0e10cSrcweir * 3*cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4*cdf0e10cSrcweir * 5*cdf0e10cSrcweir * Copyright 2000, 2010 Oracle and/or its affiliates. 6*cdf0e10cSrcweir * 7*cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite 8*cdf0e10cSrcweir * 9*cdf0e10cSrcweir * This file is part of OpenOffice.org. 10*cdf0e10cSrcweir * 11*cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify 12*cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3 13*cdf0e10cSrcweir * only, as published by the Free Software Foundation. 14*cdf0e10cSrcweir * 15*cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful, 16*cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of 17*cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details 19*cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code). 20*cdf0e10cSrcweir * 21*cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License 22*cdf0e10cSrcweir * version 3 along with OpenOffice.org. If not, see 23*cdf0e10cSrcweir * <http://www.openoffice.org/license.html> 24*cdf0e10cSrcweir * for a copy of the LGPLv3 License. 25*cdf0e10cSrcweir * 26*cdf0e10cSrcweir ************************************************************************/ 27*cdf0e10cSrcweir 28*cdf0e10cSrcweir #include "oox/xls/sheetdatabuffer.hxx" 29*cdf0e10cSrcweir 30*cdf0e10cSrcweir #include <algorithm> 31*cdf0e10cSrcweir #include <com/sun/star/sheet/XArrayFormulaTokens.hpp> 32*cdf0e10cSrcweir #include <com/sun/star/sheet/XCellRangeData.hpp> 33*cdf0e10cSrcweir #include <com/sun/star/sheet/XFormulaTokens.hpp> 34*cdf0e10cSrcweir #include <com/sun/star/sheet/XMultipleOperation.hpp> 35*cdf0e10cSrcweir #include <com/sun/star/table/XCell.hpp> 36*cdf0e10cSrcweir #include <com/sun/star/text/XText.hpp> 37*cdf0e10cSrcweir #include <com/sun/star/util/DateTime.hpp> 38*cdf0e10cSrcweir #include <com/sun/star/util/NumberFormat.hpp> 39*cdf0e10cSrcweir #include <com/sun/star/util/XMergeable.hpp> 40*cdf0e10cSrcweir #include <com/sun/star/util/XNumberFormatTypes.hpp> 41*cdf0e10cSrcweir #include <com/sun/star/util/XNumberFormatsSupplier.hpp> 42*cdf0e10cSrcweir #include <rtl/ustrbuf.hxx> 43*cdf0e10cSrcweir #include "oox/helper/containerhelper.hxx" 44*cdf0e10cSrcweir #include "oox/helper/propertymap.hxx" 45*cdf0e10cSrcweir #include "oox/helper/propertyset.hxx" 46*cdf0e10cSrcweir #include "oox/token/tokens.hxx" 47*cdf0e10cSrcweir #include "oox/xls/addressconverter.hxx" 48*cdf0e10cSrcweir #include "oox/xls/biffinputstream.hxx" 49*cdf0e10cSrcweir #include "oox/xls/formulaparser.hxx" 50*cdf0e10cSrcweir #include "oox/xls/sharedstringsbuffer.hxx" 51*cdf0e10cSrcweir #include "oox/xls/unitconverter.hxx" 52*cdf0e10cSrcweir 53*cdf0e10cSrcweir namespace oox { 54*cdf0e10cSrcweir namespace xls { 55*cdf0e10cSrcweir 56*cdf0e10cSrcweir // ============================================================================ 57*cdf0e10cSrcweir 58*cdf0e10cSrcweir using namespace ::com::sun::star::lang; 59*cdf0e10cSrcweir using namespace ::com::sun::star::sheet; 60*cdf0e10cSrcweir using namespace ::com::sun::star::table; 61*cdf0e10cSrcweir using namespace ::com::sun::star::text; 62*cdf0e10cSrcweir using namespace ::com::sun::star::uno; 63*cdf0e10cSrcweir using namespace ::com::sun::star::util; 64*cdf0e10cSrcweir 65*cdf0e10cSrcweir using ::rtl::OUString; 66*cdf0e10cSrcweir using ::rtl::OUStringBuffer; 67*cdf0e10cSrcweir 68*cdf0e10cSrcweir // ============================================================================ 69*cdf0e10cSrcweir 70*cdf0e10cSrcweir CellModel::CellModel() : 71*cdf0e10cSrcweir mnCellType( XML_TOKEN_INVALID ), 72*cdf0e10cSrcweir mnXfId( -1 ), 73*cdf0e10cSrcweir mbShowPhonetic( false ) 74*cdf0e10cSrcweir { 75*cdf0e10cSrcweir } 76*cdf0e10cSrcweir 77*cdf0e10cSrcweir // ---------------------------------------------------------------------------- 78*cdf0e10cSrcweir 79*cdf0e10cSrcweir CellFormulaModel::CellFormulaModel() : 80*cdf0e10cSrcweir mnFormulaType( XML_TOKEN_INVALID ), 81*cdf0e10cSrcweir mnSharedId( -1 ) 82*cdf0e10cSrcweir { 83*cdf0e10cSrcweir } 84*cdf0e10cSrcweir 85*cdf0e10cSrcweir bool CellFormulaModel::isValidArrayRef( const CellAddress& rCellAddr ) 86*cdf0e10cSrcweir { 87*cdf0e10cSrcweir return 88*cdf0e10cSrcweir (maFormulaRef.Sheet == rCellAddr.Sheet) && 89*cdf0e10cSrcweir (maFormulaRef.StartColumn == rCellAddr.Column) && 90*cdf0e10cSrcweir (maFormulaRef.StartRow == rCellAddr.Row); 91*cdf0e10cSrcweir } 92*cdf0e10cSrcweir 93*cdf0e10cSrcweir bool CellFormulaModel::isValidSharedRef( const CellAddress& rCellAddr ) 94*cdf0e10cSrcweir { 95*cdf0e10cSrcweir return 96*cdf0e10cSrcweir (maFormulaRef.Sheet == rCellAddr.Sheet) && 97*cdf0e10cSrcweir (maFormulaRef.StartColumn <= rCellAddr.Column) && (rCellAddr.Column <= maFormulaRef.EndColumn) && 98*cdf0e10cSrcweir (maFormulaRef.StartRow <= rCellAddr.Row) && (rCellAddr.Row <= maFormulaRef.EndRow); 99*cdf0e10cSrcweir } 100*cdf0e10cSrcweir 101*cdf0e10cSrcweir // ---------------------------------------------------------------------------- 102*cdf0e10cSrcweir 103*cdf0e10cSrcweir DataTableModel::DataTableModel() : 104*cdf0e10cSrcweir mb2dTable( false ), 105*cdf0e10cSrcweir mbRowTable( false ), 106*cdf0e10cSrcweir mbRef1Deleted( false ), 107*cdf0e10cSrcweir mbRef2Deleted( false ) 108*cdf0e10cSrcweir { 109*cdf0e10cSrcweir } 110*cdf0e10cSrcweir 111*cdf0e10cSrcweir // ============================================================================ 112*cdf0e10cSrcweir 113*cdf0e10cSrcweir namespace { 114*cdf0e10cSrcweir 115*cdf0e10cSrcweir const sal_Int32 CELLBLOCK_MAXROWS = 16; /// Number of rows in a cell block. 116*cdf0e10cSrcweir 117*cdf0e10cSrcweir } // namespace 118*cdf0e10cSrcweir 119*cdf0e10cSrcweir CellBlock::CellBlock( const WorksheetHelper& rHelper, const ValueRange& rColSpan, sal_Int32 nRow ) : 120*cdf0e10cSrcweir WorksheetHelper( rHelper ), 121*cdf0e10cSrcweir maRange( rHelper.getSheetIndex(), rColSpan.mnFirst, nRow, rColSpan.mnLast, nRow ), 122*cdf0e10cSrcweir mnRowLength( rColSpan.mnLast - rColSpan.mnFirst + 1 ), 123*cdf0e10cSrcweir mnFirstFreeIndex( 0 ) 124*cdf0e10cSrcweir { 125*cdf0e10cSrcweir maCellArray.realloc( 1 ); 126*cdf0e10cSrcweir maCellArray[ 0 ].realloc( mnRowLength ); 127*cdf0e10cSrcweir mpCurrCellRow = maCellArray[ 0 ].getArray(); 128*cdf0e10cSrcweir } 129*cdf0e10cSrcweir 130*cdf0e10cSrcweir bool CellBlock::isExpandable( const ValueRange& rColSpan ) const 131*cdf0e10cSrcweir { 132*cdf0e10cSrcweir return (maRange.StartColumn == rColSpan.mnFirst) && (maRange.EndColumn == rColSpan.mnLast); 133*cdf0e10cSrcweir } 134*cdf0e10cSrcweir 135*cdf0e10cSrcweir bool CellBlock::isBefore( const ValueRange& rColSpan ) const 136*cdf0e10cSrcweir { 137*cdf0e10cSrcweir return (maRange.EndColumn < rColSpan.mnLast) || 138*cdf0e10cSrcweir ((maRange.EndColumn == rColSpan.mnLast) && (maRange.StartColumn != rColSpan.mnFirst)); 139*cdf0e10cSrcweir } 140*cdf0e10cSrcweir 141*cdf0e10cSrcweir bool CellBlock::contains( sal_Int32 nCol ) const 142*cdf0e10cSrcweir { 143*cdf0e10cSrcweir return (maRange.StartColumn <= nCol) && (nCol <= maRange.EndColumn); 144*cdf0e10cSrcweir } 145*cdf0e10cSrcweir 146*cdf0e10cSrcweir void CellBlock::insertRichString( const CellAddress& rAddress, const RichStringRef& rxString, const Font* pFirstPortionFont ) 147*cdf0e10cSrcweir { 148*cdf0e10cSrcweir maRichStrings.push_back( RichStringCell( rAddress, rxString, pFirstPortionFont ) ); 149*cdf0e10cSrcweir } 150*cdf0e10cSrcweir 151*cdf0e10cSrcweir void CellBlock::startNextRow() 152*cdf0e10cSrcweir { 153*cdf0e10cSrcweir // fill last cells in current row with empty strings (placeholder for empty cells) 154*cdf0e10cSrcweir fillUnusedCells( mnRowLength ); 155*cdf0e10cSrcweir // flush if the cell block reaches maximum size 156*cdf0e10cSrcweir if( maCellArray.getLength() == CELLBLOCK_MAXROWS ) 157*cdf0e10cSrcweir { 158*cdf0e10cSrcweir finalizeImport(); 159*cdf0e10cSrcweir maRange.StartRow = ++maRange.EndRow; 160*cdf0e10cSrcweir maCellArray.realloc( 1 ); 161*cdf0e10cSrcweir mpCurrCellRow = maCellArray[ 0 ].getArray(); 162*cdf0e10cSrcweir } 163*cdf0e10cSrcweir else 164*cdf0e10cSrcweir { 165*cdf0e10cSrcweir // prepare next row 166*cdf0e10cSrcweir ++maRange.EndRow; 167*cdf0e10cSrcweir sal_Int32 nRowCount = maCellArray.getLength(); 168*cdf0e10cSrcweir maCellArray.realloc( nRowCount + 1 ); 169*cdf0e10cSrcweir maCellArray[ nRowCount ].realloc( mnRowLength ); 170*cdf0e10cSrcweir mpCurrCellRow = maCellArray[ nRowCount ].getArray(); 171*cdf0e10cSrcweir } 172*cdf0e10cSrcweir mnFirstFreeIndex = 0; 173*cdf0e10cSrcweir } 174*cdf0e10cSrcweir 175*cdf0e10cSrcweir Any& CellBlock::getCellAny( sal_Int32 nCol ) 176*cdf0e10cSrcweir { 177*cdf0e10cSrcweir OSL_ENSURE( contains( nCol ), "CellBlock::getCellAny - invalid column" ); 178*cdf0e10cSrcweir // fill cells before passed column with empty strings (the placeholder for empty cells) 179*cdf0e10cSrcweir sal_Int32 nIndex = nCol - maRange.StartColumn; 180*cdf0e10cSrcweir fillUnusedCells( nIndex ); 181*cdf0e10cSrcweir mnFirstFreeIndex = nIndex + 1; 182*cdf0e10cSrcweir return mpCurrCellRow[ nIndex ]; 183*cdf0e10cSrcweir } 184*cdf0e10cSrcweir 185*cdf0e10cSrcweir void CellBlock::finalizeImport() 186*cdf0e10cSrcweir { 187*cdf0e10cSrcweir // fill last cells in last row with empty strings (placeholder for empty cells) 188*cdf0e10cSrcweir fillUnusedCells( mnRowLength ); 189*cdf0e10cSrcweir // insert all buffered cells into the Calc sheet 190*cdf0e10cSrcweir try 191*cdf0e10cSrcweir { 192*cdf0e10cSrcweir Reference< XCellRangeData > xRangeData( getCellRange( maRange ), UNO_QUERY_THROW ); 193*cdf0e10cSrcweir xRangeData->setDataArray( maCellArray ); 194*cdf0e10cSrcweir } 195*cdf0e10cSrcweir catch( Exception& ) 196*cdf0e10cSrcweir { 197*cdf0e10cSrcweir } 198*cdf0e10cSrcweir // insert uncacheable cells separately 199*cdf0e10cSrcweir for( RichStringCellList::const_iterator aIt = maRichStrings.begin(), aEnd = maRichStrings.end(); aIt != aEnd; ++aIt ) 200*cdf0e10cSrcweir putRichString( aIt->maCellAddr, *aIt->mxString, aIt->mpFirstPortionFont ); 201*cdf0e10cSrcweir } 202*cdf0e10cSrcweir 203*cdf0e10cSrcweir // private -------------------------------------------------------------------- 204*cdf0e10cSrcweir 205*cdf0e10cSrcweir CellBlock::RichStringCell::RichStringCell( const CellAddress& rCellAddr, const RichStringRef& rxString, const Font* pFirstPortionFont ) : 206*cdf0e10cSrcweir maCellAddr( rCellAddr ), 207*cdf0e10cSrcweir mxString( rxString ), 208*cdf0e10cSrcweir mpFirstPortionFont( pFirstPortionFont ) 209*cdf0e10cSrcweir { 210*cdf0e10cSrcweir } 211*cdf0e10cSrcweir 212*cdf0e10cSrcweir void CellBlock::fillUnusedCells( sal_Int32 nIndex ) 213*cdf0e10cSrcweir { 214*cdf0e10cSrcweir if( mnFirstFreeIndex < nIndex ) 215*cdf0e10cSrcweir { 216*cdf0e10cSrcweir Any* pCellEnd = mpCurrCellRow + nIndex; 217*cdf0e10cSrcweir for( Any* pCell = mpCurrCellRow + mnFirstFreeIndex; pCell < pCellEnd; ++pCell ) 218*cdf0e10cSrcweir *pCell <<= OUString(); 219*cdf0e10cSrcweir } 220*cdf0e10cSrcweir } 221*cdf0e10cSrcweir 222*cdf0e10cSrcweir // ============================================================================ 223*cdf0e10cSrcweir 224*cdf0e10cSrcweir CellBlockBuffer::CellBlockBuffer( const WorksheetHelper& rHelper ) : 225*cdf0e10cSrcweir WorksheetHelper( rHelper ), 226*cdf0e10cSrcweir mnCurrRow( -1 ) 227*cdf0e10cSrcweir { 228*cdf0e10cSrcweir maCellBlockIt = maCellBlocks.end(); 229*cdf0e10cSrcweir } 230*cdf0e10cSrcweir 231*cdf0e10cSrcweir void CellBlockBuffer::setColSpans( sal_Int32 nRow, const ValueRangeSet& rColSpans ) 232*cdf0e10cSrcweir { 233*cdf0e10cSrcweir OSL_ENSURE( maColSpans.count( nRow ) == 0, "CellBlockBuffer::setColSpans - multiple column spans for the same row" ); 234*cdf0e10cSrcweir OSL_ENSURE( (mnCurrRow < nRow) && (maColSpans.empty() || (maColSpans.rbegin()->first < nRow)), "CellBlockBuffer::setColSpans - rows are unsorted" ); 235*cdf0e10cSrcweir if( (mnCurrRow < nRow) && (maColSpans.count( nRow ) == 0) ) 236*cdf0e10cSrcweir maColSpans[ nRow ] = rColSpans.getRanges(); 237*cdf0e10cSrcweir } 238*cdf0e10cSrcweir 239*cdf0e10cSrcweir CellBlock* CellBlockBuffer::getCellBlock( const CellAddress& rCellAddr ) 240*cdf0e10cSrcweir { 241*cdf0e10cSrcweir OSL_ENSURE( rCellAddr.Row >= mnCurrRow, "CellBlockBuffer::getCellBlock - passed row out of order" ); 242*cdf0e10cSrcweir // prepare cell blocks, if row changes 243*cdf0e10cSrcweir if( rCellAddr.Row != mnCurrRow ) 244*cdf0e10cSrcweir { 245*cdf0e10cSrcweir // find colspans for the new row 246*cdf0e10cSrcweir ColSpanVectorMap::iterator aIt = maColSpans.find( rCellAddr.Row ); 247*cdf0e10cSrcweir 248*cdf0e10cSrcweir /* Gap between rows, or rows out of order, or no colspan 249*cdf0e10cSrcweir information for the new row found: flush all open cell blocks. */ 250*cdf0e10cSrcweir if( (aIt == maColSpans.end()) || (rCellAddr.Row != mnCurrRow + 1) ) 251*cdf0e10cSrcweir { 252*cdf0e10cSrcweir finalizeImport(); 253*cdf0e10cSrcweir maCellBlocks.clear(); 254*cdf0e10cSrcweir maCellBlockIt = maCellBlocks.end(); 255*cdf0e10cSrcweir } 256*cdf0e10cSrcweir 257*cdf0e10cSrcweir /* Prepare matching cell blocks, create new cell blocks, finalize 258*cdf0e10cSrcweir unmatching cell blocks, if colspan information is available. */ 259*cdf0e10cSrcweir if( aIt != maColSpans.end() ) 260*cdf0e10cSrcweir { 261*cdf0e10cSrcweir /* The colspan vector aIt points to is sorted by columns, as well 262*cdf0e10cSrcweir as the cell block map. In the folloing, this vector and the 263*cdf0e10cSrcweir list of cell blocks can be iterated simultanously. */ 264*cdf0e10cSrcweir CellBlockMap::iterator aMIt = maCellBlocks.begin(); 265*cdf0e10cSrcweir const ValueRangeVector& rColRanges = aIt->second; 266*cdf0e10cSrcweir for( ValueRangeVector::const_iterator aVIt = rColRanges.begin(), aVEnd = rColRanges.end(); aVIt != aVEnd; ++aVIt, ++aMIt ) 267*cdf0e10cSrcweir { 268*cdf0e10cSrcweir const ValueRange& rColSpan = *aVIt; 269*cdf0e10cSrcweir /* Finalize and remove all cell blocks up to end of the column 270*cdf0e10cSrcweir range (cell blocks are keyed by end column index). 271*cdf0e10cSrcweir CellBlock::isBefore() returns true, if the end index of the 272*cdf0e10cSrcweir passed colspan is greater than the column end index of the 273*cdf0e10cSrcweir cell block, or if the passed range has the same end index 274*cdf0e10cSrcweir but the start indexes do not match. */ 275*cdf0e10cSrcweir while( (aMIt != maCellBlocks.end()) && aMIt->second->isBefore( rColSpan ) ) 276*cdf0e10cSrcweir { 277*cdf0e10cSrcweir aMIt->second->finalizeImport(); 278*cdf0e10cSrcweir maCellBlocks.erase( aMIt++ ); 279*cdf0e10cSrcweir } 280*cdf0e10cSrcweir /* If the current cell block (aMIt) fits to the colspan, start 281*cdf0e10cSrcweir a new row there, otherwise create and insert a new cell block. */ 282*cdf0e10cSrcweir if( (aMIt != maCellBlocks.end()) && aMIt->second->isExpandable( rColSpan ) ) 283*cdf0e10cSrcweir aMIt->second->startNextRow(); 284*cdf0e10cSrcweir else 285*cdf0e10cSrcweir aMIt = maCellBlocks.insert( aMIt, CellBlockMap::value_type( rColSpan.mnLast, 286*cdf0e10cSrcweir CellBlockMap::mapped_type( new CellBlock( *this, rColSpan, rCellAddr.Row ) ) ) ); 287*cdf0e10cSrcweir } 288*cdf0e10cSrcweir // finalize and remove all remaining cell blocks 289*cdf0e10cSrcweir CellBlockMap::iterator aMEnd = maCellBlocks.end(); 290*cdf0e10cSrcweir for( CellBlockMap::iterator aMIt2 = aMIt; aMIt2 != aMEnd; ++aMIt2 ) 291*cdf0e10cSrcweir aMIt2->second->finalizeImport(); 292*cdf0e10cSrcweir maCellBlocks.erase( aMIt, aMEnd ); 293*cdf0e10cSrcweir 294*cdf0e10cSrcweir // remove cached colspan information (including current one aIt points to) 295*cdf0e10cSrcweir maColSpans.erase( maColSpans.begin(), ++aIt ); 296*cdf0e10cSrcweir } 297*cdf0e10cSrcweir maCellBlockIt = maCellBlocks.begin(); 298*cdf0e10cSrcweir mnCurrRow = rCellAddr.Row; 299*cdf0e10cSrcweir } 300*cdf0e10cSrcweir 301*cdf0e10cSrcweir // try to find a valid cell block (update maCellBlockIt) 302*cdf0e10cSrcweir if( ((maCellBlockIt != maCellBlocks.end()) && maCellBlockIt->second->contains( rCellAddr.Column )) || 303*cdf0e10cSrcweir (((maCellBlockIt = maCellBlocks.lower_bound( rCellAddr.Column )) != maCellBlocks.end()) && maCellBlockIt->second->contains( rCellAddr.Column )) ) 304*cdf0e10cSrcweir { 305*cdf0e10cSrcweir // maCellBlockIt points to valid cell block 306*cdf0e10cSrcweir return maCellBlockIt->second.get(); 307*cdf0e10cSrcweir } 308*cdf0e10cSrcweir 309*cdf0e10cSrcweir // no valid cell block found 310*cdf0e10cSrcweir return 0; 311*cdf0e10cSrcweir } 312*cdf0e10cSrcweir 313*cdf0e10cSrcweir void CellBlockBuffer::finalizeImport() 314*cdf0e10cSrcweir { 315*cdf0e10cSrcweir maCellBlocks.forEachMem( &CellBlock::finalizeImport ); 316*cdf0e10cSrcweir } 317*cdf0e10cSrcweir 318*cdf0e10cSrcweir // ============================================================================ 319*cdf0e10cSrcweir 320*cdf0e10cSrcweir SheetDataBuffer::SheetDataBuffer( const WorksheetHelper& rHelper ) : 321*cdf0e10cSrcweir WorksheetHelper( rHelper ), 322*cdf0e10cSrcweir maCellBlocks( rHelper ), 323*cdf0e10cSrcweir mbPendingSharedFmla( false ) 324*cdf0e10cSrcweir { 325*cdf0e10cSrcweir } 326*cdf0e10cSrcweir 327*cdf0e10cSrcweir void SheetDataBuffer::setColSpans( sal_Int32 nRow, const ValueRangeSet& rColSpans ) 328*cdf0e10cSrcweir { 329*cdf0e10cSrcweir maCellBlocks.setColSpans( nRow, rColSpans ); 330*cdf0e10cSrcweir } 331*cdf0e10cSrcweir 332*cdf0e10cSrcweir void SheetDataBuffer::setBlankCell( const CellModel& rModel ) 333*cdf0e10cSrcweir { 334*cdf0e10cSrcweir setCellFormat( rModel ); 335*cdf0e10cSrcweir } 336*cdf0e10cSrcweir 337*cdf0e10cSrcweir void SheetDataBuffer::setValueCell( const CellModel& rModel, double fValue ) 338*cdf0e10cSrcweir { 339*cdf0e10cSrcweir if( CellBlock* pCellBlock = maCellBlocks.getCellBlock( rModel.maCellAddr ) ) 340*cdf0e10cSrcweir pCellBlock->getCellAny( rModel.maCellAddr.Column ) <<= fValue; 341*cdf0e10cSrcweir else 342*cdf0e10cSrcweir putValue( rModel.maCellAddr, fValue ); 343*cdf0e10cSrcweir setCellFormat( rModel ); 344*cdf0e10cSrcweir } 345*cdf0e10cSrcweir 346*cdf0e10cSrcweir void SheetDataBuffer::setStringCell( const CellModel& rModel, const OUString& rText ) 347*cdf0e10cSrcweir { 348*cdf0e10cSrcweir if( CellBlock* pCellBlock = maCellBlocks.getCellBlock( rModel.maCellAddr ) ) 349*cdf0e10cSrcweir pCellBlock->getCellAny( rModel.maCellAddr.Column ) <<= rText; 350*cdf0e10cSrcweir else 351*cdf0e10cSrcweir putString( rModel.maCellAddr, rText ); 352*cdf0e10cSrcweir setCellFormat( rModel ); 353*cdf0e10cSrcweir } 354*cdf0e10cSrcweir 355*cdf0e10cSrcweir void SheetDataBuffer::setStringCell( const CellModel& rModel, const RichStringRef& rxString ) 356*cdf0e10cSrcweir { 357*cdf0e10cSrcweir OSL_ENSURE( rxString.get(), "SheetDataBuffer::setStringCell - missing rich string object" ); 358*cdf0e10cSrcweir const Font* pFirstPortionFont = getStyles().getFontFromCellXf( rModel.mnXfId ).get(); 359*cdf0e10cSrcweir OUString aText; 360*cdf0e10cSrcweir if( rxString->extractPlainString( aText, pFirstPortionFont ) ) 361*cdf0e10cSrcweir { 362*cdf0e10cSrcweir setStringCell( rModel, aText ); 363*cdf0e10cSrcweir } 364*cdf0e10cSrcweir else 365*cdf0e10cSrcweir { 366*cdf0e10cSrcweir if( CellBlock* pCellBlock = maCellBlocks.getCellBlock( rModel.maCellAddr ) ) 367*cdf0e10cSrcweir pCellBlock->insertRichString( rModel.maCellAddr, rxString, pFirstPortionFont ); 368*cdf0e10cSrcweir else 369*cdf0e10cSrcweir putRichString( rModel.maCellAddr, *rxString, pFirstPortionFont ); 370*cdf0e10cSrcweir setCellFormat( rModel ); 371*cdf0e10cSrcweir } 372*cdf0e10cSrcweir } 373*cdf0e10cSrcweir 374*cdf0e10cSrcweir void SheetDataBuffer::setStringCell( const CellModel& rModel, sal_Int32 nStringId ) 375*cdf0e10cSrcweir { 376*cdf0e10cSrcweir RichStringRef xString = getSharedStrings().getString( nStringId ); 377*cdf0e10cSrcweir if( xString.get() ) 378*cdf0e10cSrcweir setStringCell( rModel, xString ); 379*cdf0e10cSrcweir else 380*cdf0e10cSrcweir setBlankCell( rModel ); 381*cdf0e10cSrcweir } 382*cdf0e10cSrcweir 383*cdf0e10cSrcweir void SheetDataBuffer::setDateTimeCell( const CellModel& rModel, const DateTime& rDateTime ) 384*cdf0e10cSrcweir { 385*cdf0e10cSrcweir // write serial date/time value into the cell 386*cdf0e10cSrcweir double fSerial = getUnitConverter().calcSerialFromDateTime( rDateTime ); 387*cdf0e10cSrcweir setValueCell( rModel, fSerial ); 388*cdf0e10cSrcweir // set appropriate number format 389*cdf0e10cSrcweir using namespace ::com::sun::star::util::NumberFormat; 390*cdf0e10cSrcweir sal_Int16 nStdFmt = (fSerial < 1.0) ? TIME : (((rDateTime.Hours > 0) || (rDateTime.Minutes > 0) || (rDateTime.Seconds > 0)) ? DATETIME : DATE); 391*cdf0e10cSrcweir setStandardNumFmt( rModel.maCellAddr, nStdFmt ); 392*cdf0e10cSrcweir } 393*cdf0e10cSrcweir 394*cdf0e10cSrcweir void SheetDataBuffer::setBooleanCell( const CellModel& rModel, bool bValue ) 395*cdf0e10cSrcweir { 396*cdf0e10cSrcweir setCellFormula( rModel.maCellAddr, getFormulaParser().convertBoolToFormula( bValue ) ); 397*cdf0e10cSrcweir // #108770# set 'Standard' number format for all Boolean cells 398*cdf0e10cSrcweir setCellFormat( rModel, 0 ); 399*cdf0e10cSrcweir } 400*cdf0e10cSrcweir 401*cdf0e10cSrcweir void SheetDataBuffer::setErrorCell( const CellModel& rModel, const OUString& rErrorCode ) 402*cdf0e10cSrcweir { 403*cdf0e10cSrcweir setErrorCell( rModel, getUnitConverter().calcBiffErrorCode( rErrorCode ) ); 404*cdf0e10cSrcweir } 405*cdf0e10cSrcweir 406*cdf0e10cSrcweir void SheetDataBuffer::setErrorCell( const CellModel& rModel, sal_uInt8 nErrorCode ) 407*cdf0e10cSrcweir { 408*cdf0e10cSrcweir setCellFormula( rModel.maCellAddr, getFormulaParser().convertErrorToFormula( nErrorCode ) ); 409*cdf0e10cSrcweir setCellFormat( rModel ); 410*cdf0e10cSrcweir } 411*cdf0e10cSrcweir 412*cdf0e10cSrcweir void SheetDataBuffer::setFormulaCell( const CellModel& rModel, const ApiTokenSequence& rTokens ) 413*cdf0e10cSrcweir { 414*cdf0e10cSrcweir mbPendingSharedFmla = false; 415*cdf0e10cSrcweir ApiTokenSequence aTokens; 416*cdf0e10cSrcweir 417*cdf0e10cSrcweir /* Detect special token passed as placeholder for array formulas, shared 418*cdf0e10cSrcweir formulas, and table operations. In BIFF, these formulas are represented 419*cdf0e10cSrcweir by a single tExp resp. tTbl token. If the formula parser finds these 420*cdf0e10cSrcweir tokens, it puts a single OPCODE_BAD token with the base address and 421*cdf0e10cSrcweir formula type into the token sequence. This information will be 422*cdf0e10cSrcweir extracted here, and in case of a shared formula, the shared formula 423*cdf0e10cSrcweir buffer will generate the resulting formula token array. */ 424*cdf0e10cSrcweir ApiSpecialTokenInfo aTokenInfo; 425*cdf0e10cSrcweir if( rTokens.hasElements() && getFormulaParser().extractSpecialTokenInfo( aTokenInfo, rTokens ) ) 426*cdf0e10cSrcweir { 427*cdf0e10cSrcweir /* The second member of the token info is set to true, if the formula 428*cdf0e10cSrcweir represents a table operation, which will be skipped. In BIFF12 it 429*cdf0e10cSrcweir is not possible to distinguish array and shared formulas 430*cdf0e10cSrcweir (BIFF5/BIFF8 provide this information with a special flag in the 431*cdf0e10cSrcweir FORMULA record). */ 432*cdf0e10cSrcweir if( !aTokenInfo.Second ) 433*cdf0e10cSrcweir { 434*cdf0e10cSrcweir /* Construct the token array representing the shared formula. If 435*cdf0e10cSrcweir the returned sequence is empty, the definition of the shared 436*cdf0e10cSrcweir formula has not been loaded yet, or the cell is part of an 437*cdf0e10cSrcweir array formula. In this case, the cell will be remembered. After 438*cdf0e10cSrcweir reading the formula definition it will be retried to insert the 439*cdf0e10cSrcweir formula via retryPendingSharedFormulaCell(). */ 440*cdf0e10cSrcweir BinAddress aBaseAddr( aTokenInfo.First ); 441*cdf0e10cSrcweir aTokens = resolveSharedFormula( aBaseAddr ); 442*cdf0e10cSrcweir if( !aTokens.hasElements() ) 443*cdf0e10cSrcweir { 444*cdf0e10cSrcweir maSharedFmlaAddr = rModel.maCellAddr; 445*cdf0e10cSrcweir maSharedBaseAddr = aBaseAddr; 446*cdf0e10cSrcweir mbPendingSharedFmla = true; 447*cdf0e10cSrcweir } 448*cdf0e10cSrcweir } 449*cdf0e10cSrcweir } 450*cdf0e10cSrcweir else 451*cdf0e10cSrcweir { 452*cdf0e10cSrcweir // simple formula, use the passed token array 453*cdf0e10cSrcweir aTokens = rTokens; 454*cdf0e10cSrcweir } 455*cdf0e10cSrcweir 456*cdf0e10cSrcweir setCellFormula( rModel.maCellAddr, aTokens ); 457*cdf0e10cSrcweir setCellFormat( rModel ); 458*cdf0e10cSrcweir } 459*cdf0e10cSrcweir 460*cdf0e10cSrcweir void SheetDataBuffer::setFormulaCell( const CellModel& rModel, sal_Int32 nSharedId ) 461*cdf0e10cSrcweir { 462*cdf0e10cSrcweir setCellFormula( rModel.maCellAddr, resolveSharedFormula( BinAddress( nSharedId, 0 ) ) ); 463*cdf0e10cSrcweir setCellFormat( rModel ); 464*cdf0e10cSrcweir } 465*cdf0e10cSrcweir 466*cdf0e10cSrcweir void SheetDataBuffer::createArrayFormula( const CellRangeAddress& rRange, const ApiTokenSequence& rTokens ) 467*cdf0e10cSrcweir { 468*cdf0e10cSrcweir /* Array formulas will be inserted later in finalizeImport(). This is 469*cdf0e10cSrcweir needed to not disturb collecting all the cells, which will be put into 470*cdf0e10cSrcweir the sheet in large blocks to increase performance. */ 471*cdf0e10cSrcweir maArrayFormulas.push_back( ArrayFormula( rRange, rTokens ) ); 472*cdf0e10cSrcweir } 473*cdf0e10cSrcweir 474*cdf0e10cSrcweir void SheetDataBuffer::createTableOperation( const CellRangeAddress& rRange, const DataTableModel& rModel ) 475*cdf0e10cSrcweir { 476*cdf0e10cSrcweir /* Table operations will be inserted later in finalizeImport(). This is 477*cdf0e10cSrcweir needed to not disturb collecting all the cells, which will be put into 478*cdf0e10cSrcweir the sheet in large blocks to increase performance. */ 479*cdf0e10cSrcweir maTableOperations.push_back( TableOperation( rRange, rModel ) ); 480*cdf0e10cSrcweir } 481*cdf0e10cSrcweir 482*cdf0e10cSrcweir void SheetDataBuffer::createSharedFormula( sal_Int32 nSharedId, const ApiTokenSequence& rTokens ) 483*cdf0e10cSrcweir { 484*cdf0e10cSrcweir createSharedFormula( BinAddress( nSharedId, 0 ), rTokens ); 485*cdf0e10cSrcweir } 486*cdf0e10cSrcweir 487*cdf0e10cSrcweir void SheetDataBuffer::createSharedFormula( const CellAddress& rCellAddr, const ApiTokenSequence& rTokens ) 488*cdf0e10cSrcweir { 489*cdf0e10cSrcweir createSharedFormula( BinAddress( rCellAddr ), rTokens ); 490*cdf0e10cSrcweir } 491*cdf0e10cSrcweir 492*cdf0e10cSrcweir void SheetDataBuffer::setRowFormat( sal_Int32 nRow, sal_Int32 nXfId, bool bCustomFormat ) 493*cdf0e10cSrcweir { 494*cdf0e10cSrcweir // set row formatting 495*cdf0e10cSrcweir if( bCustomFormat ) 496*cdf0e10cSrcweir { 497*cdf0e10cSrcweir // try to expand cached row range, if formatting is equal 498*cdf0e10cSrcweir if( (maXfIdRowRange.maRowRange.mnLast < 0) || !maXfIdRowRange.tryExpand( nRow, nXfId ) ) 499*cdf0e10cSrcweir { 500*cdf0e10cSrcweir writeXfIdRowRangeProperties( maXfIdRowRange ); 501*cdf0e10cSrcweir maXfIdRowRange.set( nRow, nXfId ); 502*cdf0e10cSrcweir } 503*cdf0e10cSrcweir } 504*cdf0e10cSrcweir else if( maXfIdRowRange.maRowRange.mnLast >= 0 ) 505*cdf0e10cSrcweir { 506*cdf0e10cSrcweir // finish last cached row range 507*cdf0e10cSrcweir writeXfIdRowRangeProperties( maXfIdRowRange ); 508*cdf0e10cSrcweir maXfIdRowRange.set( -1, -1 ); 509*cdf0e10cSrcweir } 510*cdf0e10cSrcweir } 511*cdf0e10cSrcweir 512*cdf0e10cSrcweir void SheetDataBuffer::setMergedRange( const CellRangeAddress& rRange ) 513*cdf0e10cSrcweir { 514*cdf0e10cSrcweir maMergedRanges.push_back( MergedRange( rRange ) ); 515*cdf0e10cSrcweir } 516*cdf0e10cSrcweir 517*cdf0e10cSrcweir void SheetDataBuffer::setStandardNumFmt( const CellAddress& rCellAddr, sal_Int16 nStdNumFmt ) 518*cdf0e10cSrcweir { 519*cdf0e10cSrcweir try 520*cdf0e10cSrcweir { 521*cdf0e10cSrcweir Reference< XNumberFormatsSupplier > xNumFmtsSupp( getDocument(), UNO_QUERY_THROW ); 522*cdf0e10cSrcweir Reference< XNumberFormatTypes > xNumFmtTypes( xNumFmtsSupp->getNumberFormats(), UNO_QUERY_THROW ); 523*cdf0e10cSrcweir sal_Int32 nIndex = xNumFmtTypes->getStandardFormat( nStdNumFmt, Locale() ); 524*cdf0e10cSrcweir PropertySet aPropSet( getCell( rCellAddr ) ); 525*cdf0e10cSrcweir aPropSet.setProperty( PROP_NumberFormat, nIndex ); 526*cdf0e10cSrcweir } 527*cdf0e10cSrcweir catch( Exception& ) 528*cdf0e10cSrcweir { 529*cdf0e10cSrcweir } 530*cdf0e10cSrcweir } 531*cdf0e10cSrcweir 532*cdf0e10cSrcweir void SheetDataBuffer::finalizeImport() 533*cdf0e10cSrcweir { 534*cdf0e10cSrcweir // insert all cells of all open cell blocks 535*cdf0e10cSrcweir maCellBlocks.finalizeImport(); 536*cdf0e10cSrcweir 537*cdf0e10cSrcweir // create all array formulas 538*cdf0e10cSrcweir for( ArrayFormulaList::iterator aIt = maArrayFormulas.begin(), aEnd = maArrayFormulas.end(); aIt != aEnd; ++aIt ) 539*cdf0e10cSrcweir finalizeArrayFormula( aIt->first, aIt->second ); 540*cdf0e10cSrcweir 541*cdf0e10cSrcweir // create all table operations 542*cdf0e10cSrcweir for( TableOperationList::iterator aIt = maTableOperations.begin(), aEnd = maTableOperations.end(); aIt != aEnd; ++aIt ) 543*cdf0e10cSrcweir finalizeTableOperation( aIt->first, aIt->second ); 544*cdf0e10cSrcweir 545*cdf0e10cSrcweir // write default formatting of remaining row range 546*cdf0e10cSrcweir writeXfIdRowRangeProperties( maXfIdRowRange ); 547*cdf0e10cSrcweir 548*cdf0e10cSrcweir // try to merge remaining inserted ranges 549*cdf0e10cSrcweir mergeXfIdRanges(); 550*cdf0e10cSrcweir // write all formatting 551*cdf0e10cSrcweir for( XfIdRangeMap::const_iterator aIt = maXfIdRanges.begin(), aEnd = maXfIdRanges.end(); aIt != aEnd; ++aIt ) 552*cdf0e10cSrcweir writeXfIdRangeProperties( aIt->second ); 553*cdf0e10cSrcweir 554*cdf0e10cSrcweir // merge all cached merged ranges and update right/bottom cell borders 555*cdf0e10cSrcweir for( MergedRangeList::iterator aIt = maMergedRanges.begin(), aEnd = maMergedRanges.end(); aIt != aEnd; ++aIt ) 556*cdf0e10cSrcweir finalizeMergedRange( aIt->maRange ); 557*cdf0e10cSrcweir for( MergedRangeList::iterator aIt = maCenterFillRanges.begin(), aEnd = maCenterFillRanges.end(); aIt != aEnd; ++aIt ) 558*cdf0e10cSrcweir finalizeMergedRange( aIt->maRange ); 559*cdf0e10cSrcweir } 560*cdf0e10cSrcweir 561*cdf0e10cSrcweir // private -------------------------------------------------------------------- 562*cdf0e10cSrcweir 563*cdf0e10cSrcweir SheetDataBuffer::XfIdRowRange::XfIdRowRange() : 564*cdf0e10cSrcweir maRowRange( -1 ), 565*cdf0e10cSrcweir mnXfId( -1 ) 566*cdf0e10cSrcweir { 567*cdf0e10cSrcweir } 568*cdf0e10cSrcweir 569*cdf0e10cSrcweir bool SheetDataBuffer::XfIdRowRange::intersects( const CellRangeAddress& rRange ) const 570*cdf0e10cSrcweir { 571*cdf0e10cSrcweir return (rRange.StartRow <= maRowRange.mnLast) && (maRowRange.mnFirst <= rRange.EndRow); 572*cdf0e10cSrcweir } 573*cdf0e10cSrcweir 574*cdf0e10cSrcweir void SheetDataBuffer::XfIdRowRange::set( sal_Int32 nRow, sal_Int32 nXfId ) 575*cdf0e10cSrcweir { 576*cdf0e10cSrcweir maRowRange = ValueRange( nRow ); 577*cdf0e10cSrcweir mnXfId = nXfId; 578*cdf0e10cSrcweir } 579*cdf0e10cSrcweir 580*cdf0e10cSrcweir bool SheetDataBuffer::XfIdRowRange::tryExpand( sal_Int32 nRow, sal_Int32 nXfId ) 581*cdf0e10cSrcweir { 582*cdf0e10cSrcweir if( mnXfId == nXfId ) 583*cdf0e10cSrcweir { 584*cdf0e10cSrcweir if( maRowRange.mnLast + 1 == nRow ) 585*cdf0e10cSrcweir { 586*cdf0e10cSrcweir ++maRowRange.mnLast; 587*cdf0e10cSrcweir return true; 588*cdf0e10cSrcweir } 589*cdf0e10cSrcweir if( maRowRange.mnFirst == nRow + 1 ) 590*cdf0e10cSrcweir { 591*cdf0e10cSrcweir --maRowRange.mnFirst; 592*cdf0e10cSrcweir return true; 593*cdf0e10cSrcweir } 594*cdf0e10cSrcweir } 595*cdf0e10cSrcweir return false; 596*cdf0e10cSrcweir } 597*cdf0e10cSrcweir 598*cdf0e10cSrcweir void SheetDataBuffer::XfIdRange::set( const CellAddress& rCellAddr, sal_Int32 nXfId, sal_Int32 nNumFmtId ) 599*cdf0e10cSrcweir { 600*cdf0e10cSrcweir maRange.Sheet = rCellAddr.Sheet; 601*cdf0e10cSrcweir maRange.StartColumn = maRange.EndColumn = rCellAddr.Column; 602*cdf0e10cSrcweir maRange.StartRow = maRange.EndRow = rCellAddr.Row; 603*cdf0e10cSrcweir mnXfId = nXfId; 604*cdf0e10cSrcweir mnNumFmtId = nNumFmtId; 605*cdf0e10cSrcweir } 606*cdf0e10cSrcweir 607*cdf0e10cSrcweir bool SheetDataBuffer::XfIdRange::tryExpand( const CellAddress& rCellAddr, sal_Int32 nXfId, sal_Int32 nNumFmtId ) 608*cdf0e10cSrcweir { 609*cdf0e10cSrcweir if( (mnXfId == nXfId) && (mnNumFmtId == nNumFmtId) && 610*cdf0e10cSrcweir (maRange.StartRow == rCellAddr.Row) && 611*cdf0e10cSrcweir (maRange.EndRow == rCellAddr.Row) && 612*cdf0e10cSrcweir (maRange.EndColumn + 1 == rCellAddr.Column) ) 613*cdf0e10cSrcweir { 614*cdf0e10cSrcweir ++maRange.EndColumn; 615*cdf0e10cSrcweir return true; 616*cdf0e10cSrcweir } 617*cdf0e10cSrcweir return false; 618*cdf0e10cSrcweir } 619*cdf0e10cSrcweir 620*cdf0e10cSrcweir bool SheetDataBuffer::XfIdRange::tryMerge( const XfIdRange& rXfIdRange ) 621*cdf0e10cSrcweir { 622*cdf0e10cSrcweir if( (mnXfId == rXfIdRange.mnXfId) && 623*cdf0e10cSrcweir (mnNumFmtId == rXfIdRange.mnNumFmtId) && 624*cdf0e10cSrcweir (maRange.EndRow + 1 == rXfIdRange.maRange.StartRow) && 625*cdf0e10cSrcweir (maRange.StartColumn == rXfIdRange.maRange.StartColumn) && 626*cdf0e10cSrcweir (maRange.EndColumn == rXfIdRange.maRange.EndColumn) ) 627*cdf0e10cSrcweir { 628*cdf0e10cSrcweir maRange.EndRow = rXfIdRange.maRange.EndRow; 629*cdf0e10cSrcweir return true; 630*cdf0e10cSrcweir } 631*cdf0e10cSrcweir return false; 632*cdf0e10cSrcweir } 633*cdf0e10cSrcweir 634*cdf0e10cSrcweir 635*cdf0e10cSrcweir SheetDataBuffer::MergedRange::MergedRange( const CellRangeAddress& rRange ) : 636*cdf0e10cSrcweir maRange( rRange ), 637*cdf0e10cSrcweir mnHorAlign( XML_TOKEN_INVALID ) 638*cdf0e10cSrcweir { 639*cdf0e10cSrcweir } 640*cdf0e10cSrcweir 641*cdf0e10cSrcweir SheetDataBuffer::MergedRange::MergedRange( const CellAddress& rAddress, sal_Int32 nHorAlign ) : 642*cdf0e10cSrcweir maRange( rAddress.Sheet, rAddress.Column, rAddress.Row, rAddress.Column, rAddress.Row ), 643*cdf0e10cSrcweir mnHorAlign( nHorAlign ) 644*cdf0e10cSrcweir { 645*cdf0e10cSrcweir } 646*cdf0e10cSrcweir 647*cdf0e10cSrcweir bool SheetDataBuffer::MergedRange::tryExpand( const CellAddress& rAddress, sal_Int32 nHorAlign ) 648*cdf0e10cSrcweir { 649*cdf0e10cSrcweir if( (mnHorAlign == nHorAlign) && (maRange.StartRow == rAddress.Row) && 650*cdf0e10cSrcweir (maRange.EndRow == rAddress.Row) && (maRange.EndColumn + 1 == rAddress.Column) ) 651*cdf0e10cSrcweir { 652*cdf0e10cSrcweir ++maRange.EndColumn; 653*cdf0e10cSrcweir return true; 654*cdf0e10cSrcweir } 655*cdf0e10cSrcweir return false; 656*cdf0e10cSrcweir } 657*cdf0e10cSrcweir 658*cdf0e10cSrcweir // ---------------------------------------------------------------------------- 659*cdf0e10cSrcweir 660*cdf0e10cSrcweir void SheetDataBuffer::setCellFormula( const CellAddress& rCellAddr, const ApiTokenSequence& rTokens ) 661*cdf0e10cSrcweir { 662*cdf0e10cSrcweir if( rTokens.hasElements() ) 663*cdf0e10cSrcweir { 664*cdf0e10cSrcweir if( CellBlock* pCellBlock = maCellBlocks.getCellBlock( rCellAddr ) ) 665*cdf0e10cSrcweir pCellBlock->getCellAny( rCellAddr.Column ) <<= rTokens; 666*cdf0e10cSrcweir else 667*cdf0e10cSrcweir putFormulaTokens( rCellAddr, rTokens ); 668*cdf0e10cSrcweir } 669*cdf0e10cSrcweir } 670*cdf0e10cSrcweir 671*cdf0e10cSrcweir void SheetDataBuffer::createSharedFormula( const BinAddress& rMapKey, const ApiTokenSequence& rTokens ) 672*cdf0e10cSrcweir { 673*cdf0e10cSrcweir // create the defined name that will represent the shared formula 674*cdf0e10cSrcweir OUString aName = OUStringBuffer().appendAscii( RTL_CONSTASCII_STRINGPARAM( "__shared_" ) ). 675*cdf0e10cSrcweir append( static_cast< sal_Int32 >( getSheetIndex() + 1 ) ). 676*cdf0e10cSrcweir append( sal_Unicode( '_' ) ).append( rMapKey.mnRow ). 677*cdf0e10cSrcweir append( sal_Unicode( '_' ) ).append( rMapKey.mnCol ).makeStringAndClear(); 678*cdf0e10cSrcweir Reference< XNamedRange > xNamedRange = createNamedRangeObject( aName ); 679*cdf0e10cSrcweir OSL_ENSURE( xNamedRange.is(), "SheetDataBuffer::createSharedFormula - cannot create shared formula" ); 680*cdf0e10cSrcweir PropertySet aNameProps( xNamedRange ); 681*cdf0e10cSrcweir aNameProps.setProperty( PROP_IsSharedFormula, true ); 682*cdf0e10cSrcweir 683*cdf0e10cSrcweir // get and store the token index of the defined name 684*cdf0e10cSrcweir OSL_ENSURE( maSharedFormulas.count( rMapKey ) == 0, "SheetDataBuffer::createSharedFormula - shared formula exists already" ); 685*cdf0e10cSrcweir sal_Int32 nTokenIndex = 0; 686*cdf0e10cSrcweir if( aNameProps.getProperty( nTokenIndex, PROP_TokenIndex ) && (nTokenIndex >= 0) ) try 687*cdf0e10cSrcweir { 688*cdf0e10cSrcweir // store the token index in the map 689*cdf0e10cSrcweir maSharedFormulas[ rMapKey ] = nTokenIndex; 690*cdf0e10cSrcweir // set the formula definition 691*cdf0e10cSrcweir Reference< XFormulaTokens > xTokens( xNamedRange, UNO_QUERY_THROW ); 692*cdf0e10cSrcweir xTokens->setTokens( rTokens ); 693*cdf0e10cSrcweir // retry to insert a pending shared formula cell 694*cdf0e10cSrcweir if( mbPendingSharedFmla ) 695*cdf0e10cSrcweir setCellFormula( maSharedFmlaAddr, resolveSharedFormula( maSharedBaseAddr ) ); 696*cdf0e10cSrcweir } 697*cdf0e10cSrcweir catch( Exception& ) 698*cdf0e10cSrcweir { 699*cdf0e10cSrcweir } 700*cdf0e10cSrcweir mbPendingSharedFmla = false; 701*cdf0e10cSrcweir } 702*cdf0e10cSrcweir 703*cdf0e10cSrcweir ApiTokenSequence SheetDataBuffer::resolveSharedFormula( const BinAddress& rMapKey ) const 704*cdf0e10cSrcweir { 705*cdf0e10cSrcweir sal_Int32 nTokenIndex = ContainerHelper::getMapElement( maSharedFormulas, rMapKey, -1 ); 706*cdf0e10cSrcweir return (nTokenIndex >= 0) ? getFormulaParser().convertNameToFormula( nTokenIndex ) : ApiTokenSequence(); 707*cdf0e10cSrcweir } 708*cdf0e10cSrcweir 709*cdf0e10cSrcweir void SheetDataBuffer::finalizeArrayFormula( const CellRangeAddress& rRange, const ApiTokenSequence& rTokens ) const 710*cdf0e10cSrcweir { 711*cdf0e10cSrcweir Reference< XArrayFormulaTokens > xTokens( getCellRange( rRange ), UNO_QUERY ); 712*cdf0e10cSrcweir OSL_ENSURE( xTokens.is(), "SheetDataBuffer::finalizeArrayFormula - missing formula token interface" ); 713*cdf0e10cSrcweir if( xTokens.is() ) 714*cdf0e10cSrcweir xTokens->setArrayTokens( rTokens ); 715*cdf0e10cSrcweir } 716*cdf0e10cSrcweir 717*cdf0e10cSrcweir void SheetDataBuffer::finalizeTableOperation( const CellRangeAddress& rRange, const DataTableModel& rModel ) const 718*cdf0e10cSrcweir { 719*cdf0e10cSrcweir sal_Int16 nSheet = getSheetIndex(); 720*cdf0e10cSrcweir bool bOk = false; 721*cdf0e10cSrcweir if( !rModel.mbRef1Deleted && (rModel.maRef1.getLength() > 0) && (rRange.StartColumn > 0) && (rRange.StartRow > 0) ) 722*cdf0e10cSrcweir { 723*cdf0e10cSrcweir CellRangeAddress aOpRange = rRange; 724*cdf0e10cSrcweir CellAddress aRef1; 725*cdf0e10cSrcweir if( getAddressConverter().convertToCellAddress( aRef1, rModel.maRef1, nSheet, true ) ) try 726*cdf0e10cSrcweir { 727*cdf0e10cSrcweir if( rModel.mb2dTable ) 728*cdf0e10cSrcweir { 729*cdf0e10cSrcweir CellAddress aRef2; 730*cdf0e10cSrcweir if( !rModel.mbRef2Deleted && getAddressConverter().convertToCellAddress( aRef2, rModel.maRef2, nSheet, true ) ) 731*cdf0e10cSrcweir { 732*cdf0e10cSrcweir // API call expects input values inside operation range 733*cdf0e10cSrcweir --aOpRange.StartColumn; 734*cdf0e10cSrcweir --aOpRange.StartRow; 735*cdf0e10cSrcweir // formula range is top-left cell of operation range 736*cdf0e10cSrcweir CellRangeAddress aFormulaRange( nSheet, aOpRange.StartColumn, aOpRange.StartRow, aOpRange.StartColumn, aOpRange.StartRow ); 737*cdf0e10cSrcweir // set multiple operation 738*cdf0e10cSrcweir Reference< XMultipleOperation > xMultOp( getCellRange( aOpRange ), UNO_QUERY_THROW ); 739*cdf0e10cSrcweir xMultOp->setTableOperation( aFormulaRange, TableOperationMode_BOTH, aRef2, aRef1 ); 740*cdf0e10cSrcweir bOk = true; 741*cdf0e10cSrcweir } 742*cdf0e10cSrcweir } 743*cdf0e10cSrcweir else if( rModel.mbRowTable ) 744*cdf0e10cSrcweir { 745*cdf0e10cSrcweir // formula range is column to the left of operation range 746*cdf0e10cSrcweir CellRangeAddress aFormulaRange( nSheet, aOpRange.StartColumn - 1, aOpRange.StartRow, aOpRange.StartColumn - 1, aOpRange.EndRow ); 747*cdf0e10cSrcweir // API call expects input values (top row) inside operation range 748*cdf0e10cSrcweir --aOpRange.StartRow; 749*cdf0e10cSrcweir // set multiple operation 750*cdf0e10cSrcweir Reference< XMultipleOperation > xMultOp( getCellRange( aOpRange ), UNO_QUERY_THROW ); 751*cdf0e10cSrcweir xMultOp->setTableOperation( aFormulaRange, TableOperationMode_ROW, aRef1, aRef1 ); 752*cdf0e10cSrcweir bOk = true; 753*cdf0e10cSrcweir } 754*cdf0e10cSrcweir else 755*cdf0e10cSrcweir { 756*cdf0e10cSrcweir // formula range is row above operation range 757*cdf0e10cSrcweir CellRangeAddress aFormulaRange( nSheet, aOpRange.StartColumn, aOpRange.StartRow - 1, aOpRange.EndColumn, aOpRange.StartRow - 1 ); 758*cdf0e10cSrcweir // API call expects input values (left column) inside operation range 759*cdf0e10cSrcweir --aOpRange.StartColumn; 760*cdf0e10cSrcweir // set multiple operation 761*cdf0e10cSrcweir Reference< XMultipleOperation > xMultOp( getCellRange( aOpRange ), UNO_QUERY_THROW ); 762*cdf0e10cSrcweir xMultOp->setTableOperation( aFormulaRange, TableOperationMode_COLUMN, aRef1, aRef1 ); 763*cdf0e10cSrcweir bOk = true; 764*cdf0e10cSrcweir } 765*cdf0e10cSrcweir } 766*cdf0e10cSrcweir catch( Exception& ) 767*cdf0e10cSrcweir { 768*cdf0e10cSrcweir } 769*cdf0e10cSrcweir } 770*cdf0e10cSrcweir 771*cdf0e10cSrcweir // on error: fill cell range with #REF! error codes 772*cdf0e10cSrcweir if( !bOk ) try 773*cdf0e10cSrcweir { 774*cdf0e10cSrcweir Reference< XCellRangeData > xCellRangeData( getCellRange( rRange ), UNO_QUERY_THROW ); 775*cdf0e10cSrcweir size_t nWidth = static_cast< size_t >( rRange.EndColumn - rRange.StartColumn + 1 ); 776*cdf0e10cSrcweir size_t nHeight = static_cast< size_t >( rRange.EndRow - rRange.StartRow + 1 ); 777*cdf0e10cSrcweir Matrix< Any > aErrorCells( nWidth, nHeight, Any( getFormulaParser().convertErrorToFormula( BIFF_ERR_REF ) ) ); 778*cdf0e10cSrcweir xCellRangeData->setDataArray( ContainerHelper::matrixToSequenceSequence( aErrorCells ) ); 779*cdf0e10cSrcweir } 780*cdf0e10cSrcweir catch( Exception& ) 781*cdf0e10cSrcweir { 782*cdf0e10cSrcweir } 783*cdf0e10cSrcweir } 784*cdf0e10cSrcweir 785*cdf0e10cSrcweir void SheetDataBuffer::setCellFormat( const CellModel& rModel, sal_Int32 nNumFmtId ) 786*cdf0e10cSrcweir { 787*cdf0e10cSrcweir if( (rModel.mnXfId >= 0) || (nNumFmtId >= 0) ) 788*cdf0e10cSrcweir { 789*cdf0e10cSrcweir // try to merge existing ranges and to write some formatting properties 790*cdf0e10cSrcweir if( !maXfIdRanges.empty() ) 791*cdf0e10cSrcweir { 792*cdf0e10cSrcweir // get row index of last inserted cell 793*cdf0e10cSrcweir sal_Int32 nLastRow = maXfIdRanges.rbegin()->second.maRange.StartRow; 794*cdf0e10cSrcweir // row changed - try to merge ranges of last row with existing ranges 795*cdf0e10cSrcweir if( rModel.maCellAddr.Row != nLastRow ) 796*cdf0e10cSrcweir { 797*cdf0e10cSrcweir mergeXfIdRanges(); 798*cdf0e10cSrcweir // write format properties of all ranges above last row and remove them 799*cdf0e10cSrcweir XfIdRangeMap::iterator aIt = maXfIdRanges.begin(), aEnd = maXfIdRanges.end(); 800*cdf0e10cSrcweir while( aIt != aEnd ) 801*cdf0e10cSrcweir { 802*cdf0e10cSrcweir // check that range cannot be merged with current row, and that range is not in cached row range 803*cdf0e10cSrcweir if( (aIt->second.maRange.EndRow < nLastRow) && !maXfIdRowRange.intersects( aIt->second.maRange ) ) 804*cdf0e10cSrcweir { 805*cdf0e10cSrcweir writeXfIdRangeProperties( aIt->second ); 806*cdf0e10cSrcweir maXfIdRanges.erase( aIt++ ); 807*cdf0e10cSrcweir } 808*cdf0e10cSrcweir else 809*cdf0e10cSrcweir ++aIt; 810*cdf0e10cSrcweir } 811*cdf0e10cSrcweir } 812*cdf0e10cSrcweir } 813*cdf0e10cSrcweir 814*cdf0e10cSrcweir // try to expand last existing range, or create new range entry 815*cdf0e10cSrcweir if( maXfIdRanges.empty() || !maXfIdRanges.rbegin()->second.tryExpand( rModel.maCellAddr, rModel.mnXfId, nNumFmtId ) ) 816*cdf0e10cSrcweir maXfIdRanges[ BinAddress( rModel.maCellAddr ) ].set( rModel.maCellAddr, rModel.mnXfId, nNumFmtId ); 817*cdf0e10cSrcweir 818*cdf0e10cSrcweir // update merged ranges for 'center across selection' and 'fill' 819*cdf0e10cSrcweir if( const Xf* pXf = getStyles().getCellXf( rModel.mnXfId ).get() ) 820*cdf0e10cSrcweir { 821*cdf0e10cSrcweir sal_Int32 nHorAlign = pXf->getAlignment().getModel().mnHorAlign; 822*cdf0e10cSrcweir if( (nHorAlign == XML_centerContinuous) || (nHorAlign == XML_fill) ) 823*cdf0e10cSrcweir { 824*cdf0e10cSrcweir /* start new merged range, if cell is not empty (#108781#), 825*cdf0e10cSrcweir or try to expand last range with empty cell */ 826*cdf0e10cSrcweir if( rModel.mnCellType != XML_TOKEN_INVALID ) 827*cdf0e10cSrcweir maCenterFillRanges.push_back( MergedRange( rModel.maCellAddr, nHorAlign ) ); 828*cdf0e10cSrcweir else if( !maCenterFillRanges.empty() ) 829*cdf0e10cSrcweir maCenterFillRanges.rbegin()->tryExpand( rModel.maCellAddr, nHorAlign ); 830*cdf0e10cSrcweir } 831*cdf0e10cSrcweir } 832*cdf0e10cSrcweir } 833*cdf0e10cSrcweir } 834*cdf0e10cSrcweir 835*cdf0e10cSrcweir void SheetDataBuffer::writeXfIdRowRangeProperties( const XfIdRowRange& rXfIdRowRange ) const 836*cdf0e10cSrcweir { 837*cdf0e10cSrcweir if( (rXfIdRowRange.maRowRange.mnLast >= 0) && (rXfIdRowRange.mnXfId >= 0) ) 838*cdf0e10cSrcweir { 839*cdf0e10cSrcweir AddressConverter& rAddrConv = getAddressConverter(); 840*cdf0e10cSrcweir CellRangeAddress aRange( getSheetIndex(), 0, rXfIdRowRange.maRowRange.mnFirst, rAddrConv.getMaxApiAddress().Column, rXfIdRowRange.maRowRange.mnLast ); 841*cdf0e10cSrcweir if( rAddrConv.validateCellRange( aRange, true, false ) ) 842*cdf0e10cSrcweir { 843*cdf0e10cSrcweir PropertySet aPropSet( getCellRange( aRange ) ); 844*cdf0e10cSrcweir getStyles().writeCellXfToPropertySet( aPropSet, rXfIdRowRange.mnXfId ); 845*cdf0e10cSrcweir } 846*cdf0e10cSrcweir } 847*cdf0e10cSrcweir } 848*cdf0e10cSrcweir 849*cdf0e10cSrcweir void SheetDataBuffer::writeXfIdRangeProperties( const XfIdRange& rXfIdRange ) const 850*cdf0e10cSrcweir { 851*cdf0e10cSrcweir StylesBuffer& rStyles = getStyles(); 852*cdf0e10cSrcweir PropertyMap aPropMap; 853*cdf0e10cSrcweir if( rXfIdRange.mnXfId >= 0 ) 854*cdf0e10cSrcweir rStyles.writeCellXfToPropertyMap( aPropMap, rXfIdRange.mnXfId ); 855*cdf0e10cSrcweir if( rXfIdRange.mnNumFmtId >= 0 ) 856*cdf0e10cSrcweir rStyles.writeNumFmtToPropertyMap( aPropMap, rXfIdRange.mnNumFmtId ); 857*cdf0e10cSrcweir PropertySet aPropSet( getCellRange( rXfIdRange.maRange ) ); 858*cdf0e10cSrcweir aPropSet.setProperties( aPropMap ); 859*cdf0e10cSrcweir } 860*cdf0e10cSrcweir 861*cdf0e10cSrcweir void SheetDataBuffer::mergeXfIdRanges() 862*cdf0e10cSrcweir { 863*cdf0e10cSrcweir if( !maXfIdRanges.empty() ) 864*cdf0e10cSrcweir { 865*cdf0e10cSrcweir // get row index of last range 866*cdf0e10cSrcweir sal_Int32 nLastRow = maXfIdRanges.rbegin()->second.maRange.StartRow; 867*cdf0e10cSrcweir // process all ranges located in the same row of the last range 868*cdf0e10cSrcweir XfIdRangeMap::iterator aMergeIt = maXfIdRanges.end(); 869*cdf0e10cSrcweir while( (aMergeIt != maXfIdRanges.begin()) && ((--aMergeIt)->second.maRange.StartRow == nLastRow) ) 870*cdf0e10cSrcweir { 871*cdf0e10cSrcweir const XfIdRange& rMergeXfIdRange = aMergeIt->second; 872*cdf0e10cSrcweir // try to find a range that can be merged with rMergeRange 873*cdf0e10cSrcweir bool bFound = false; 874*cdf0e10cSrcweir for( XfIdRangeMap::iterator aIt = maXfIdRanges.begin(); !bFound && (aIt != aMergeIt); ++aIt ) 875*cdf0e10cSrcweir if( (bFound = aIt->second.tryMerge( rMergeXfIdRange )) == true ) 876*cdf0e10cSrcweir maXfIdRanges.erase( aMergeIt++ ); 877*cdf0e10cSrcweir } 878*cdf0e10cSrcweir } 879*cdf0e10cSrcweir } 880*cdf0e10cSrcweir 881*cdf0e10cSrcweir void SheetDataBuffer::finalizeMergedRange( const CellRangeAddress& rRange ) 882*cdf0e10cSrcweir { 883*cdf0e10cSrcweir bool bMultiCol = rRange.StartColumn < rRange.EndColumn; 884*cdf0e10cSrcweir bool bMultiRow = rRange.StartRow < rRange.EndRow; 885*cdf0e10cSrcweir 886*cdf0e10cSrcweir if( bMultiCol || bMultiRow ) try 887*cdf0e10cSrcweir { 888*cdf0e10cSrcweir // merge the cell range 889*cdf0e10cSrcweir Reference< XMergeable > xMerge( getCellRange( rRange ), UNO_QUERY_THROW ); 890*cdf0e10cSrcweir xMerge->merge( sal_True ); 891*cdf0e10cSrcweir 892*cdf0e10cSrcweir // if merging this range worked (no overlapping merged ranges), update cell borders 893*cdf0e10cSrcweir Reference< XCell > xTopLeft( getCell( CellAddress( getSheetIndex(), rRange.StartColumn, rRange.StartRow ) ), UNO_SET_THROW ); 894*cdf0e10cSrcweir PropertySet aTopLeftProp( xTopLeft ); 895*cdf0e10cSrcweir 896*cdf0e10cSrcweir // copy right border of top-right cell to right border of top-left cell 897*cdf0e10cSrcweir if( bMultiCol ) 898*cdf0e10cSrcweir { 899*cdf0e10cSrcweir PropertySet aTopRightProp( getCell( CellAddress( getSheetIndex(), rRange.EndColumn, rRange.StartRow ) ) ); 900*cdf0e10cSrcweir BorderLine aLine; 901*cdf0e10cSrcweir if( aTopRightProp.getProperty( aLine, PROP_RightBorder ) ) 902*cdf0e10cSrcweir aTopLeftProp.setProperty( PROP_RightBorder, aLine ); 903*cdf0e10cSrcweir } 904*cdf0e10cSrcweir 905*cdf0e10cSrcweir // copy bottom border of bottom-left cell to bottom border of top-left cell 906*cdf0e10cSrcweir if( bMultiRow ) 907*cdf0e10cSrcweir { 908*cdf0e10cSrcweir PropertySet aBottomLeftProp( getCell( CellAddress( getSheetIndex(), rRange.StartColumn, rRange.EndRow ) ) ); 909*cdf0e10cSrcweir BorderLine aLine; 910*cdf0e10cSrcweir if( aBottomLeftProp.getProperty( aLine, PROP_BottomBorder ) ) 911*cdf0e10cSrcweir aTopLeftProp.setProperty( PROP_BottomBorder, aLine ); 912*cdf0e10cSrcweir } 913*cdf0e10cSrcweir 914*cdf0e10cSrcweir // #i93609# merged range in a single row: test if manual row height is needed 915*cdf0e10cSrcweir if( !bMultiRow ) 916*cdf0e10cSrcweir { 917*cdf0e10cSrcweir bool bTextWrap = aTopLeftProp.getBoolProperty( PROP_IsTextWrapped ); 918*cdf0e10cSrcweir if( !bTextWrap && (xTopLeft->getType() == CellContentType_TEXT) ) 919*cdf0e10cSrcweir { 920*cdf0e10cSrcweir Reference< XText > xText( xTopLeft, UNO_QUERY ); 921*cdf0e10cSrcweir bTextWrap = xText.is() && (xText->getString().indexOf( '\x0A' ) >= 0); 922*cdf0e10cSrcweir } 923*cdf0e10cSrcweir if( bTextWrap ) 924*cdf0e10cSrcweir setManualRowHeight( rRange.StartRow ); 925*cdf0e10cSrcweir } 926*cdf0e10cSrcweir } 927*cdf0e10cSrcweir catch( Exception& ) 928*cdf0e10cSrcweir { 929*cdf0e10cSrcweir } 930*cdf0e10cSrcweir } 931*cdf0e10cSrcweir 932*cdf0e10cSrcweir // ============================================================================ 933*cdf0e10cSrcweir 934*cdf0e10cSrcweir } // namespace xls 935*cdf0e10cSrcweir } // namespace oox 936