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