Version 5.2.6.1, tag libreoffice-5.2.6.1
[LibreOffice.git] / sc / source / filter / oox / sheetdatabuffer.cxx
blob3182088fc7c2e20705e50ffa8c359a30f89fe6c5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "sheetdatabuffer.hxx"
22 #include <algorithm>
23 #include <com/sun/star/sheet/XArrayFormulaTokens.hpp>
24 #include <com/sun/star/sheet/XCellRangeData.hpp>
25 #include <com/sun/star/sheet/XFormulaTokens.hpp>
26 #include <com/sun/star/sheet/XMultipleOperation.hpp>
27 #include <com/sun/star/table/XCell.hpp>
28 #include <com/sun/star/text/XText.hpp>
29 #include <com/sun/star/util/DateTime.hpp>
30 #include <com/sun/star/util/NumberFormat.hpp>
31 #include <com/sun/star/util/XMergeable.hpp>
32 #include <com/sun/star/util/XNumberFormatTypes.hpp>
33 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
34 #include <rtl/ustrbuf.hxx>
35 #include <editeng/boxitem.hxx>
36 #include <editeng/editobj.hxx>
37 #include <svl/eitem.hxx>
38 #include <oox/helper/containerhelper.hxx>
39 #include <oox/helper/propertymap.hxx>
40 #include <oox/helper/propertyset.hxx>
41 #include <oox/token/properties.hxx>
42 #include <oox/token/tokens.hxx>
43 #include "addressconverter.hxx"
44 #include "biffinputstream.hxx"
45 #include "formulaparser.hxx"
46 #include "sharedstringsbuffer.hxx"
47 #include "unitconverter.hxx"
48 #include "convuno.hxx"
49 #include "markdata.hxx"
50 #include "rangelst.hxx"
51 #include "document.hxx"
52 #include "scitems.hxx"
53 #include "formulacell.hxx"
54 #include "docpool.hxx"
55 #include "paramisc.hxx"
56 #include "documentimport.hxx"
57 #include "formulabuffer.hxx"
58 #include <numformat.hxx>
60 namespace oox {
61 namespace xls {
63 using namespace ::com::sun::star::lang;
64 using namespace ::com::sun::star::sheet;
65 using namespace ::com::sun::star::table;
66 using namespace ::com::sun::star::text;
67 using namespace ::com::sun::star::uno;
68 using namespace ::com::sun::star::util;
70 CellModel::CellModel() :
71 mnCellType( XML_TOKEN_INVALID ),
72 mnXfId( -1 ),
73 mbShowPhonetic( false )
77 CellFormulaModel::CellFormulaModel() :
78 mnFormulaType( XML_TOKEN_INVALID ),
79 mnSharedId( -1 )
83 bool CellFormulaModel::isValidArrayRef( const ScAddress& rCellAddr )
85 return
86 (maFormulaRef.Sheet == rCellAddr.Tab() ) &&
87 (maFormulaRef.StartColumn == rCellAddr.Col() ) &&
88 (maFormulaRef.StartRow == rCellAddr.Row() );
91 bool CellFormulaModel::isValidSharedRef( const ScAddress& rCellAddr )
93 return
94 (maFormulaRef.Sheet == rCellAddr.Tab() ) &&
95 (maFormulaRef.StartColumn <= rCellAddr.Col() ) && (rCellAddr.Col() <= maFormulaRef.EndColumn) &&
96 (maFormulaRef.StartRow <= rCellAddr.Row() ) && (rCellAddr.Row() <= maFormulaRef.EndRow);
99 DataTableModel::DataTableModel() :
100 mb2dTable( false ),
101 mbRowTable( false ),
102 mbRef1Deleted( false ),
103 mbRef2Deleted( false )
107 CellBlockBuffer::CellBlockBuffer( const WorksheetHelper& rHelper ) :
108 WorksheetHelper( rHelper ),
109 mnCurrRow( -1 )
113 void CellBlockBuffer::setColSpans( sal_Int32 nRow, const ValueRangeSet& rColSpans )
115 OSL_ENSURE( maColSpans.count( nRow ) == 0, "CellBlockBuffer::setColSpans - multiple column spans for the same row" );
116 OSL_ENSURE( (mnCurrRow < nRow) && (maColSpans.empty() || (maColSpans.rbegin()->first < nRow)), "CellBlockBuffer::setColSpans - rows are unsorted" );
117 if( (mnCurrRow < nRow) && (maColSpans.count( nRow ) == 0) )
118 maColSpans[ nRow ] = rColSpans.getRanges();
121 SheetDataBuffer::SheetDataBuffer( const WorksheetHelper& rHelper ) :
122 WorksheetHelper( rHelper ),
123 maCellBlocks( rHelper ),
124 mbPendingSharedFmla( false )
128 void SheetDataBuffer::setColSpans( sal_Int32 nRow, const ValueRangeSet& rColSpans )
130 maCellBlocks.setColSpans( nRow, rColSpans );
133 void SheetDataBuffer::setBlankCell( const CellModel& rModel )
135 setCellFormat( rModel );
138 void SheetDataBuffer::setValueCell( const CellModel& rModel, double fValue )
140 putValue( rModel.maCellAddr, fValue );
141 setCellFormat( rModel );
144 void SheetDataBuffer::setStringCell( const CellModel& rModel, const OUString& rText )
146 putString( rModel.maCellAddr, rText );
147 setCellFormat( rModel );
150 void SheetDataBuffer::setStringCell( const CellModel& rModel, const RichStringRef& rxString )
152 OSL_ENSURE( rxString.get(), "SheetDataBuffer::setStringCell - missing rich string object" );
153 const oox::xls::Font* pFirstPortionFont = getStyles().getFontFromCellXf( rModel.mnXfId ).get();
154 OUString aText;
155 if( rxString->extractPlainString( aText, pFirstPortionFont ) )
157 setStringCell( rModel, aText );
159 else
161 putRichString( rModel.maCellAddr, *rxString, pFirstPortionFont );
162 setCellFormat( rModel );
166 void SheetDataBuffer::setStringCell( const CellModel& rModel, sal_Int32 nStringId )
168 RichStringRef xString = getSharedStrings().getString( nStringId );
169 if( xString.get() )
170 setStringCell( rModel, xString );
171 else
172 setBlankCell( rModel );
175 void SheetDataBuffer::setDateTimeCell( const CellModel& rModel, const css::util::DateTime& rDateTime )
177 // write serial date/time value into the cell
178 double fSerial = getUnitConverter().calcSerialFromDateTime( rDateTime );
179 setValueCell( rModel, fSerial );
180 // set appropriate number format
181 using namespace ::com::sun::star::util::NumberFormat;
182 sal_Int16 nStdFmt = (fSerial < 1.0) ? TIME : (((rDateTime.Hours > 0) || (rDateTime.Minutes > 0) || (rDateTime.Seconds > 0)) ? DATETIME : DATE);
183 setStandardNumFmt( rModel.maCellAddr, nStdFmt );
186 void SheetDataBuffer::setBooleanCell( const CellModel& rModel, bool bValue )
188 getFormulaBuffer().setCellFormula(
189 rModel.maCellAddr, bValue ? OUString("TRUE()") : OUString("FALSE()"));
191 // #108770# set 'Standard' number format for all Boolean cells
192 setCellFormat( rModel );
195 void SheetDataBuffer::setErrorCell( const CellModel& rModel, const OUString& rErrorCode )
197 // Using the formula compiler now we can simply pass on the error string.
198 getFormulaBuffer().setCellFormula( rModel.maCellAddr, rErrorCode);
199 setCellFormat( rModel );
202 void SheetDataBuffer::setErrorCell( const CellModel& rModel, sal_uInt8 nErrorCode )
204 setErrorCell( rModel, getUnitConverter().calcErrorString( nErrorCode));
207 void SheetDataBuffer::setDateCell( const CellModel& rModel, const OUString& rDateString )
209 ScDocument& rDoc = getScDocument();
210 SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
212 double fValue = 0.0;
213 sal_uInt32 nFormatIndex = 0;
214 bool bValid = pFormatter->IsNumberFormat( rDateString, nFormatIndex, fValue );
216 if(bValid)
217 setValueCell( rModel, fValue );
220 void SheetDataBuffer::createSharedFormula(const ScAddress& rAddr, const ApiTokenSequence& rTokens)
222 BinAddress aAddr(rAddr);
223 maSharedFormulas[aAddr] = rTokens;
224 if( mbPendingSharedFmla )
225 setCellFormula( maSharedFmlaAddr, resolveSharedFormula( maSharedBaseAddr ) );
228 void SheetDataBuffer::setFormulaCell( const CellModel& rModel, const ApiTokenSequence& rTokens )
230 mbPendingSharedFmla = false;
231 ApiTokenSequence aTokens;
233 /* Detect special token passed as placeholder for array formulas, shared
234 formulas, and table operations. In BIFF, these formulas are represented
235 by a single tExp resp. tTbl token. If the formula parser finds these
236 tokens, it puts a single OPCODE_BAD token with the base address and
237 formula type into the token sequence. This information will be
238 extracted here, and in case of a shared formula, the shared formula
239 buffer will generate the resulting formula token array. */
240 ApiSpecialTokenInfo aTokenInfo;
241 if( rTokens.hasElements() && getFormulaParser().extractSpecialTokenInfo( aTokenInfo, rTokens ) )
243 /* The second member of the token info is set to true, if the formula
244 represents a table operation, which will be skipped. In BIFF12 it
245 is not possible to distinguish array and shared formulas
246 (BIFF5/BIFF8 provide this information with a special flag in the
247 FORMULA record). */
248 if( !aTokenInfo.Second )
250 /* Construct the token array representing the shared formula. If
251 the returned sequence is empty, the definition of the shared
252 formula has not been loaded yet, or the cell is part of an
253 array formula. In this case, the cell will be remembered. After
254 reading the formula definition it will be retried to insert the
255 formula via retryPendingSharedFormulaCell(). */
256 ScAddress aTokenAddr = ScAddress ( aTokenInfo.First.Column, aTokenInfo.First.Row, aTokenInfo.First.Sheet );
257 BinAddress aBaseAddr( aTokenAddr );
258 aTokens = resolveSharedFormula( aTokenAddr );
259 if( !aTokens.hasElements() )
261 maSharedFmlaAddr = rModel.maCellAddr;
262 maSharedBaseAddr = aTokenAddr;
263 mbPendingSharedFmla = true;
267 else
269 // simple formula, use the passed token array
270 aTokens = rTokens;
273 setCellFormula( rModel.maCellAddr, aTokens );
274 setCellFormat( rModel );
277 void SheetDataBuffer::createArrayFormula( const CellRangeAddress& rRange, const ApiTokenSequence& rTokens )
279 /* Array formulas will be inserted later in finalizeImport(). This is
280 needed to not disturb collecting all the cells, which will be put into
281 the sheet in large blocks to increase performance. */
282 maArrayFormulas.push_back( ArrayFormula( rRange, rTokens ) );
285 void SheetDataBuffer::createTableOperation( const CellRangeAddress& rRange, const DataTableModel& rModel )
287 /* Table operations will be inserted later in finalizeImport(). This is
288 needed to not disturb collecting all the cells, which will be put into
289 the sheet in large blocks to increase performance. */
290 maTableOperations.push_back( TableOperation( rRange, rModel ) );
293 void SheetDataBuffer::setRowFormat( sal_Int32 nRow, sal_Int32 nXfId, bool bCustomFormat )
295 // set row formatting
296 if( bCustomFormat )
298 // try to expand cached row range, if formatting is equal
299 if( (maXfIdRowRange.maRowRange.mnLast < 0) || !maXfIdRowRange.tryExpand( nRow, nXfId ) )
302 maXfIdRowRangeList[ maXfIdRowRange.mnXfId ].push_back( maXfIdRowRange.maRowRange );
303 maXfIdRowRange.set( nRow, nXfId );
306 else if( maXfIdRowRange.maRowRange.mnLast >= 0 )
308 // finish last cached row range
309 maXfIdRowRangeList[ maXfIdRowRange.mnXfId ].push_back( maXfIdRowRange.maRowRange );
310 maXfIdRowRange.set( -1, -1 );
314 void SheetDataBuffer::setMergedRange( const CellRangeAddress& rRange )
316 maMergedRanges.push_back( MergedRange( rRange ) );
319 void SheetDataBuffer::setStandardNumFmt( const ScAddress& rCellAddr, sal_Int16 nStdNumFmt )
323 Reference< XNumberFormatsSupplier > xNumFmtsSupp( getDocument(), UNO_QUERY_THROW );
324 Reference< XNumberFormatTypes > xNumFmtTypes( xNumFmtsSupp->getNumberFormats(), UNO_QUERY_THROW );
325 sal_Int32 nIndex = xNumFmtTypes->getStandardFormat( nStdNumFmt, Locale() );
326 PropertySet aPropSet( getCell( rCellAddr ) );
327 aPropSet.setProperty( PROP_NumberFormat, nIndex );
329 catch( Exception& )
334 typedef std::pair<sal_Int32, sal_Int32> FormatKeyPair;
336 void addIfNotInMyMap( StylesBuffer& rStyles, std::map< FormatKeyPair, ApiCellRangeList >& rMap, sal_Int32 nXfId, sal_Int32 nFormatId, const ApiCellRangeList& rRangeList )
338 Xf* pXf1 = rStyles.getCellXf( nXfId ).get();
339 if ( pXf1 )
341 for ( std::map< FormatKeyPair, ApiCellRangeList >::iterator it = rMap.begin(), it_end = rMap.end(); it != it_end; ++it )
343 if ( it->first.second == nFormatId )
345 Xf* pXf2 = rStyles.getCellXf( it->first.first ).get();
346 if ( *pXf1 == *pXf2 ) // already exists
348 // add ranges from the rangelist to the existing rangelist for the
349 // matching style ( should we check if they overlap ? )
350 for ( ::std::vector< CellRangeAddress >::const_iterator iter = rRangeList.begin(), iter_end = rRangeList.end(); iter != iter_end; ++iter )
351 it->second.push_back( *iter );
352 return;
356 rMap[ FormatKeyPair( nXfId, nFormatId ) ] = rRangeList;
360 void SheetDataBuffer::addColXfStyle( sal_Int32 nXfId, sal_Int32 nFormatId, const css::table::CellRangeAddress& rAddress, bool bProcessRowRange )
362 RowRangeStyle aStyleRows;
363 aStyleRows.mnNumFmt.first = nXfId;
364 aStyleRows.mnNumFmt.second = nFormatId;
365 aStyleRows.mnStartRow = rAddress.StartRow;
366 aStyleRows.mnEndRow = rAddress.EndRow;
367 for ( sal_Int32 nCol = rAddress.StartColumn; nCol <= rAddress.EndColumn; ++nCol )
369 if ( !bProcessRowRange )
370 maStylesPerColumn[ nCol ].insert( aStyleRows );
371 else
373 RowStyles& rRowStyles = maStylesPerColumn[ nCol ];
374 // If the rowrange style includes rows already
375 // allocated to a style then we need to split
376 // the range style Rows into sections ( to
377 // occupy only rows that have no style definition )
379 // We don't want to set any rowstyle 'rows'
380 // for rows where there is an existing 'style' )
381 std::vector< RowRangeStyle > aRangeRowsSplits;
383 RowStyles::iterator rows_it = rRowStyles.begin();
384 RowStyles::iterator rows_end = rRowStyles.end();
385 bool bAddRange = true;
386 for ( ; rows_it != rows_end; ++rows_it )
388 const RowRangeStyle& r = *rows_it;
389 // if row is completely within existing style, discard it
390 if ( aStyleRows.mnStartRow >= r.mnStartRow && aStyleRows.mnEndRow <= r.mnEndRow )
391 bAddRange = false;
392 else if ( aStyleRows.mnStartRow <= r.mnStartRow )
394 // not intersecting at all?, if so finish as none left
395 // to check ( row ranges are in ascending order
396 if ( aStyleRows.mnEndRow < r.mnStartRow )
397 break;
398 else if ( aStyleRows.mnEndRow <= r.mnEndRow )
400 aStyleRows.mnEndRow = r.mnStartRow - 1;
401 break;
403 if ( aStyleRows.mnStartRow < r.mnStartRow )
405 RowRangeStyle aSplit = aStyleRows;
406 aSplit.mnEndRow = r.mnStartRow - 1;
407 aRangeRowsSplits.push_back( aSplit );
411 std::vector< RowRangeStyle >::iterator splits_it = aRangeRowsSplits.begin();
412 std::vector< RowRangeStyle >::iterator splits_end = aRangeRowsSplits.end();
413 for ( ; splits_it != splits_end; ++splits_it )
414 rRowStyles.insert( *splits_it );
415 if ( bAddRange )
416 rRowStyles.insert( aStyleRows );
420 void SheetDataBuffer::finalizeImport()
422 // create all array formulas
423 for( ArrayFormulaList::iterator aIt = maArrayFormulas.begin(), aEnd = maArrayFormulas.end(); aIt != aEnd; ++aIt )
424 finalizeArrayFormula( aIt->first, aIt->second );
426 // create all table operations
427 for( TableOperationList::iterator aIt = maTableOperations.begin(), aEnd = maTableOperations.end(); aIt != aEnd; ++aIt )
428 finalizeTableOperation( aIt->first, aIt->second );
430 // write default formatting of remaining row range
431 maXfIdRowRangeList[ maXfIdRowRange.mnXfId ].push_back( maXfIdRowRange.maRowRange );
433 std::map< FormatKeyPair, ApiCellRangeList > rangeStyleListMap;
434 for( XfIdRangeListMap::const_iterator aIt = maXfIdRangeLists.begin(), aEnd = maXfIdRangeLists.end(); aIt != aEnd; ++aIt )
436 addIfNotInMyMap( getStyles(), rangeStyleListMap, aIt->first.first, aIt->first.second, aIt->second );
438 // gather all ranges that have the same style and apply them in bulk
439 for ( std::map< FormatKeyPair, ApiCellRangeList >::iterator it = rangeStyleListMap.begin(), it_end = rangeStyleListMap.end(); it != it_end; ++it )
441 const ApiCellRangeList& rRanges( it->second );
442 for ( ::std::vector< CellRangeAddress >::const_iterator it_range = rRanges.begin(), it_rangeend = rRanges.end(); it_range!=it_rangeend; ++it_range )
443 addColXfStyle( it->first.first, it->first.second, *it_range );
446 for ( std::map< sal_Int32, std::vector< ValueRange > >::iterator it = maXfIdRowRangeList.begin(), it_end = maXfIdRowRangeList.end(); it != it_end; ++it )
448 ApiCellRangeList rangeList;
449 AddressConverter& rAddrConv = getAddressConverter();
450 // get all row ranges for id
451 for ( std::vector< ValueRange >::iterator rangeIter = it->second.begin(), rangeIter_end = it->second.end(); rangeIter != rangeIter_end; ++rangeIter )
453 if ( it->first == -1 ) // it's a dud skip it
454 continue;
455 CellRangeAddress aRange( getSheetIndex(), 0, rangeIter->mnFirst, rAddrConv.getMaxApiAddress().Col(), rangeIter->mnLast );
457 addColXfStyle( it->first, -1, aRange, true );
461 ScDocumentImport& rDoc = getDocImport();
462 StylesBuffer& rStyles = getStyles();
463 for ( ColStyles::iterator col = maStylesPerColumn.begin(), col_end = maStylesPerColumn.end(); col != col_end; ++col )
465 RowStyles& rRowStyles = col->second;
466 SCCOL nScCol = static_cast< SCCOL >( col->first );
467 const ScPatternAttr* pDefPattern = rDoc.getDoc().GetPattern(nScCol, 0, getSheetIndex());
468 Xf::AttrList aAttrs(pDefPattern);
469 for ( RowStyles::iterator rRows = rRowStyles.begin(), rRows_end = rRowStyles.end(); rRows != rRows_end; ++rRows )
471 Xf* pXf = rStyles.getCellXf( rRows->mnNumFmt.first ).get();
473 if ( pXf )
474 pXf->applyPatternToAttrList( aAttrs, rRows->mnStartRow, rRows->mnEndRow, rRows->mnNumFmt.second );
476 if (aAttrs.maAttrs.empty() || aAttrs.maAttrs.back().nRow != MAXROW)
478 ScAttrEntry aEntry;
479 aEntry.nRow = MAXROW;
480 aEntry.pPattern = pDefPattern;
481 rDoc.getDoc().GetPool()->Put(*aEntry.pPattern);
482 aAttrs.maAttrs.push_back(aEntry);
484 if (!sc::NumFmtUtil::isLatinScript(*aEntry.pPattern, rDoc.getDoc()))
485 aAttrs.mbLatinNumFmtOnly = false;
488 ScDocumentImport::Attrs aAttrParam;
489 aAttrParam.mnSize = aAttrs.maAttrs.size();
490 aAttrParam.mpData = new ScAttrEntry[aAttrParam.mnSize];
491 aAttrParam.mbLatinNumFmtOnly = aAttrs.mbLatinNumFmtOnly;
492 std::list<ScAttrEntry>::const_iterator itr = aAttrs.maAttrs.begin(), itrEnd = aAttrs.maAttrs.end();
493 for (size_t i = 0; itr != itrEnd; ++itr, ++i)
494 aAttrParam.mpData[i] = *itr;
496 rDoc.setAttrEntries(getSheetIndex(), nScCol, aAttrParam);
499 // merge all cached merged ranges and update right/bottom cell borders
500 for( MergedRangeList::iterator aIt = maMergedRanges.begin(), aEnd = maMergedRanges.end(); aIt != aEnd; ++aIt )
501 applyCellMerging( aIt->maRange );
502 for( MergedRangeList::iterator aIt = maCenterFillRanges.begin(), aEnd = maCenterFillRanges.end(); aIt != aEnd; ++aIt )
503 applyCellMerging( aIt->maRange );
506 // private --------------------------------------------------------------------
508 SheetDataBuffer::XfIdRowRange::XfIdRowRange() :
509 maRowRange( -1 ),
510 mnXfId( -1 )
514 void SheetDataBuffer::XfIdRowRange::set( sal_Int32 nRow, sal_Int32 nXfId )
516 maRowRange = ValueRange( nRow );
517 mnXfId = nXfId;
520 bool SheetDataBuffer::XfIdRowRange::tryExpand( sal_Int32 nRow, sal_Int32 nXfId )
522 if( mnXfId == nXfId )
524 if( maRowRange.mnLast + 1 == nRow )
526 ++maRowRange.mnLast;
527 return true;
529 if( maRowRange.mnFirst == nRow + 1 )
531 --maRowRange.mnFirst;
532 return true;
535 return false;
538 SheetDataBuffer::MergedRange::MergedRange( const CellRangeAddress& rRange ) :
539 maRange( rRange ),
540 mnHorAlign( XML_TOKEN_INVALID )
544 SheetDataBuffer::MergedRange::MergedRange( const ScAddress& rAddress, sal_Int32 nHorAlign ) :
545 maRange( rAddress.Tab(), rAddress.Col(), rAddress.Row(), rAddress.Col(), rAddress.Row() ),
546 mnHorAlign( nHorAlign )
550 bool SheetDataBuffer::MergedRange::tryExpand( const ScAddress& rAddress, sal_Int32 nHorAlign )
552 if( (mnHorAlign == nHorAlign) && (maRange.StartRow == rAddress.Row() ) &&
553 (maRange.EndRow == rAddress.Row() ) && (maRange.EndColumn + 1 == rAddress.Col() ) )
555 ++maRange.EndColumn;
556 return true;
558 return false;
561 void SheetDataBuffer::setCellFormula( const ScAddress& rCellAddr, const ApiTokenSequence& rTokens )
563 if( rTokens.hasElements() )
565 putFormulaTokens( rCellAddr, rTokens );
570 ApiTokenSequence SheetDataBuffer::resolveSharedFormula( const ScAddress& rAddr ) const
572 BinAddress aAddr(rAddr);
573 ApiTokenSequence aTokens = ContainerHelper::getMapElement( maSharedFormulas, aAddr, ApiTokenSequence() );
574 return aTokens;
577 void SheetDataBuffer::finalizeArrayFormula( const CellRangeAddress& rRange, const ApiTokenSequence& rTokens ) const
579 Reference< XArrayFormulaTokens > xTokens( getCellRange( rRange ), UNO_QUERY );
580 OSL_ENSURE( xTokens.is(), "SheetDataBuffer::finalizeArrayFormula - missing formula token interface" );
581 if( xTokens.is() )
582 xTokens->setArrayTokens( rTokens );
585 void SheetDataBuffer::finalizeTableOperation( const CellRangeAddress& rRange, const DataTableModel& rModel )
587 if (rModel.mbRef1Deleted)
588 return;
590 if (rModel.maRef1.isEmpty())
591 return;
593 if (rRange.StartColumn <= 0 || rRange.StartRow <= 0)
594 return;
596 sal_Int16 nSheet = getSheetIndex();
598 ScAddress aRef1( 0, 0, 0 );
599 if (!getAddressConverter().convertToCellAddress(aRef1, rModel.maRef1, nSheet, true))
600 return;
602 ScDocumentImport& rDoc = getDocImport();
603 ScTabOpParam aParam;
605 ScRange aScRange;
606 ScUnoConversion::FillScRange(aScRange, rRange);
608 if (rModel.mb2dTable)
610 // Two-variable data table.
611 if (rModel.mbRef2Deleted)
612 return;
614 if (rModel.maRef2.isEmpty())
615 return;
617 ScAddress aRef2( 0, 0, 0 );
618 if (!getAddressConverter().convertToCellAddress(aRef2, rModel.maRef2, nSheet, true))
619 return;
621 aParam.meMode = ScTabOpParam::Both;
623 aParam.aRefFormulaCell.Set(rRange.StartColumn-1, rRange.StartRow-1, nSheet, false, false, false);
624 aParam.aRefFormulaEnd = aParam.aRefFormulaCell;
626 aScRange.aStart.IncRow(-1);
627 aScRange.aStart.IncCol(-1);
629 // Ref1 is row input cell and Ref2 is column input cell.
630 aParam.aRefRowCell.Set(aRef1.Col(), aRef1.Row(), aRef1.Tab(), false, false, false);
631 aParam.aRefColCell.Set(aRef2.Col(), aRef2.Row(), aRef2.Tab(), false, false, false);
632 rDoc.setTableOpCells(aScRange, aParam);
634 return;
637 // One-variable data table.
639 if (rModel.mbRowTable)
641 // One-variable row input cell (horizontal).
642 aParam.meMode = ScTabOpParam::Row;
643 aParam.aRefRowCell.Set(aRef1.Col(), aRef1.Row(), aRef1.Tab(), false, false, false);
644 aParam.aRefFormulaCell.Set(rRange.StartColumn-1, rRange.StartRow, nSheet, false, true, false);
645 aParam.aRefFormulaEnd = aParam.aRefFormulaCell;
646 aScRange.aStart.IncRow(-1);
647 rDoc.setTableOpCells(aScRange, aParam);
649 else
651 // One-variable column input cell (vertical).
652 aParam.meMode = ScTabOpParam::Column;
653 aParam.aRefColCell.Set(aRef1.Col(), aRef1.Row(), aRef1.Tab(), false, false, false);
654 aParam.aRefFormulaCell.Set(rRange.StartColumn, rRange.StartRow-1, nSheet, true, false, false);
655 aParam.aRefFormulaEnd = aParam.aRefFormulaCell;
656 aScRange.aStart.IncCol(-1);
657 rDoc.setTableOpCells(aScRange, aParam);
661 void SheetDataBuffer::setCellFormat( const CellModel& rModel )
663 if( rModel.mnXfId >= 0 )
665 ::std::vector< CellRangeAddress >::reverse_iterator aIt = maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, -1 ) ].rbegin();
666 ::std::vector< CellRangeAddress >::reverse_iterator aItEnd = maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, -1 ) ].rend();
667 /* The xlsx sheet data contains row wise information.
668 * It is sufficient to check if the row range size is one
670 if( aIt != aItEnd &&
671 aIt->Sheet == rModel.maCellAddr.Tab() &&
672 aIt->StartRow == aIt->EndRow &&
673 aIt->StartRow == rModel.maCellAddr.Row() &&
674 (aIt->EndColumn+1) == rModel.maCellAddr.Col() )
676 aIt->EndColumn++; // Expand Column
678 else
680 maXfIdRangeLists[ XfIdNumFmtKey (rModel.mnXfId, -1 ) ].push_back(
681 CellRangeAddress( rModel.maCellAddr.Tab(), rModel.maCellAddr.Col(), rModel.maCellAddr.Row(),
682 rModel.maCellAddr.Col(), rModel.maCellAddr.Row() ) );
685 aIt = maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, -1 ) ].rbegin();
686 aItEnd = maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, -1 ) ].rend();
687 ::std::vector< CellRangeAddress >::reverse_iterator aItM = aIt+1;
688 while( aItM != aItEnd )
690 if( aIt->Sheet == aItM->Sheet )
692 /* Try to merge this with the previous range */
693 if( aIt->StartRow == (aItM->EndRow + 1) &&
694 aIt->StartColumn == aItM->StartColumn &&
695 aIt->EndColumn == aItM->EndColumn)
697 aItM->EndRow = aIt->EndRow;
698 maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, -1 ) ].pop_back();
699 break;
701 else if( aIt->StartRow > aItM->EndRow + 1 )
702 break; // Un-necessary to check with any other rows
704 else
705 break;
706 ++aItM;
709 // update merged ranges for 'center across selection' and 'fill'
710 if( const Xf* pXf = getStyles().getCellXf( rModel.mnXfId ).get() )
712 sal_Int32 nHorAlign = pXf->getAlignment().getModel().mnHorAlign;
713 if( (nHorAlign == XML_centerContinuous) || (nHorAlign == XML_fill) )
715 /* start new merged range, if cell is not empty (#108781#),
716 or try to expand last range with empty cell */
717 if( rModel.mnCellType != XML_TOKEN_INVALID )
718 maCenterFillRanges.push_back( MergedRange( rModel.maCellAddr, nHorAlign ) );
719 else if( !maCenterFillRanges.empty() )
720 maCenterFillRanges.rbegin()->tryExpand( rModel.maCellAddr, nHorAlign );
726 void lcl_SetBorderLine( ScDocument& rDoc, ScRange& rRange, SCTAB nScTab, SvxBoxItemLine nLine )
728 SCCOL nFromScCol = (nLine == SvxBoxItemLine::RIGHT) ? rRange.aEnd.Col() : rRange.aStart.Col();
729 SCROW nFromScRow = (nLine == SvxBoxItemLine::BOTTOM) ? rRange.aEnd.Row() : rRange.aStart.Row();
731 const SvxBoxItem* pFromItem = static_cast< const SvxBoxItem* >(
732 rDoc.GetAttr( nFromScCol, nFromScRow, nScTab, ATTR_BORDER ) );
733 const SvxBoxItem* pToItem = static_cast< const SvxBoxItem* >(
734 rDoc.GetAttr( rRange.aStart.Col(), rRange.aStart.Row(), nScTab, ATTR_BORDER ) );
736 SvxBoxItem aNewItem( *pToItem );
737 aNewItem.SetLine( pFromItem->GetLine( nLine ), nLine );
738 rDoc.ApplyAttr( rRange.aStart.Col(), rRange.aStart.Row(), nScTab, aNewItem );
741 void SheetDataBuffer::applyCellMerging( const CellRangeAddress& rRange )
743 bool bMultiCol = rRange.StartColumn < rRange.EndColumn;
744 bool bMultiRow = rRange.StartRow < rRange.EndRow;
746 ScRange aRange;
747 ScUnoConversion::FillScRange( aRange, rRange );
748 const ScAddress& rStart = aRange.aStart;
749 const ScAddress& rEnd = aRange.aEnd;
750 ScDocument& rDoc = getScDocument();
751 // set correct right border
752 if( bMultiCol )
753 lcl_SetBorderLine( rDoc, aRange, getSheetIndex(), SvxBoxItemLine::RIGHT );
754 // set correct lower border
755 if( bMultiRow )
756 lcl_SetBorderLine( rDoc, aRange, getSheetIndex(), SvxBoxItemLine::BOTTOM );
757 // do merge
758 if( bMultiCol || bMultiRow )
759 rDoc.DoMerge( getSheetIndex(), rStart.Col(), rStart.Row(), rEnd.Col(), rEnd.Row() );
762 } // namespace xls
763 } // namespace oox
765 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */