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