fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / filter / oox / sheetdatabuffer.cxx
blob812eee140a27bb18024caf3161db10c1345b1590
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/tokens.hxx>
42 #include "addressconverter.hxx"
43 #include "biffinputstream.hxx"
44 #include "formulaparser.hxx"
45 #include "sharedstringsbuffer.hxx"
46 #include "unitconverter.hxx"
47 #include "convuno.hxx"
48 #include "markdata.hxx"
49 #include "rangelst.hxx"
50 #include "document.hxx"
51 #include "scitems.hxx"
52 #include "formulacell.hxx"
53 #include "docpool.hxx"
54 #include "paramisc.hxx"
55 #include "documentimport.hxx"
56 #include "formulabuffer.hxx"
57 #include <numformat.hxx>
59 namespace oox {
60 namespace xls {
62 using namespace ::com::sun::star::lang;
63 using namespace ::com::sun::star::sheet;
64 using namespace ::com::sun::star::table;
65 using namespace ::com::sun::star::text;
66 using namespace ::com::sun::star::uno;
67 using namespace ::com::sun::star::util;
69 CellModel::CellModel() :
70 mnCellType( XML_TOKEN_INVALID ),
71 mnXfId( -1 ),
72 mbShowPhonetic( false )
76 CellFormulaModel::CellFormulaModel() :
77 mnFormulaType( XML_TOKEN_INVALID ),
78 mnSharedId( -1 )
82 bool CellFormulaModel::isValidArrayRef( const CellAddress& rCellAddr )
84 return
85 (maFormulaRef.Sheet == rCellAddr.Sheet) &&
86 (maFormulaRef.StartColumn == rCellAddr.Column) &&
87 (maFormulaRef.StartRow == rCellAddr.Row);
90 bool CellFormulaModel::isValidSharedRef( const CellAddress& rCellAddr )
92 return
93 (maFormulaRef.Sheet == rCellAddr.Sheet) &&
94 (maFormulaRef.StartColumn <= rCellAddr.Column) && (rCellAddr.Column <= maFormulaRef.EndColumn) &&
95 (maFormulaRef.StartRow <= rCellAddr.Row) && (rCellAddr.Row <= maFormulaRef.EndRow);
98 DataTableModel::DataTableModel() :
99 mb2dTable( false ),
100 mbRowTable( false ),
101 mbRef1Deleted( false ),
102 mbRef2Deleted( false )
106 CellBlockBuffer::CellBlockBuffer( const WorksheetHelper& rHelper ) :
107 WorksheetHelper( rHelper ),
108 mnCurrRow( -1 )
112 void CellBlockBuffer::setColSpans( sal_Int32 nRow, const ValueRangeSet& rColSpans )
114 OSL_ENSURE( maColSpans.count( nRow ) == 0, "CellBlockBuffer::setColSpans - multiple column spans for the same row" );
115 OSL_ENSURE( (mnCurrRow < nRow) && (maColSpans.empty() || (maColSpans.rbegin()->first < nRow)), "CellBlockBuffer::setColSpans - rows are unsorted" );
116 if( (mnCurrRow < nRow) && (maColSpans.count( nRow ) == 0) )
117 maColSpans[ nRow ] = rColSpans.getRanges();
120 SheetDataBuffer::SheetDataBuffer( const WorksheetHelper& rHelper ) :
121 WorksheetHelper( rHelper ),
122 maCellBlocks( rHelper ),
123 mbPendingSharedFmla( false )
127 void SheetDataBuffer::setColSpans( sal_Int32 nRow, const ValueRangeSet& rColSpans )
129 maCellBlocks.setColSpans( nRow, rColSpans );
132 void SheetDataBuffer::setBlankCell( const CellModel& rModel )
134 setCellFormat( rModel );
137 void SheetDataBuffer::setValueCell( const CellModel& rModel, double fValue )
139 putValue( rModel.maCellAddr, fValue );
140 setCellFormat( rModel );
143 void SheetDataBuffer::setStringCell( const CellModel& rModel, const OUString& rText )
145 putString( rModel.maCellAddr, rText );
146 setCellFormat( rModel );
149 void SheetDataBuffer::setStringCell( const CellModel& rModel, const RichStringRef& rxString )
151 OSL_ENSURE( rxString.get(), "SheetDataBuffer::setStringCell - missing rich string object" );
152 const oox::xls::Font* pFirstPortionFont = getStyles().getFontFromCellXf( rModel.mnXfId ).get();
153 OUString aText;
154 if( rxString->extractPlainString( aText, pFirstPortionFont ) )
156 setStringCell( rModel, aText );
158 else
160 putRichString( rModel.maCellAddr, *rxString, pFirstPortionFont );
161 setCellFormat( rModel );
165 void SheetDataBuffer::setStringCell( const CellModel& rModel, sal_Int32 nStringId )
167 RichStringRef xString = getSharedStrings().getString( nStringId );
168 if( xString.get() )
169 setStringCell( rModel, xString );
170 else
171 setBlankCell( rModel );
174 void SheetDataBuffer::setDateTimeCell( const CellModel& rModel, const ::com::sun::star::util::DateTime& rDateTime )
176 // write serial date/time value into the cell
177 double fSerial = getUnitConverter().calcSerialFromDateTime( rDateTime );
178 setValueCell( rModel, fSerial );
179 // set appropriate number format
180 using namespace ::com::sun::star::util::NumberFormat;
181 sal_Int16 nStdFmt = (fSerial < 1.0) ? TIME : (((rDateTime.Hours > 0) || (rDateTime.Minutes > 0) || (rDateTime.Seconds > 0)) ? DATETIME : DATE);
182 setStandardNumFmt( rModel.maCellAddr, nStdFmt );
185 void SheetDataBuffer::setBooleanCell( const CellModel& rModel, bool bValue )
187 getFormulaBuffer().setCellFormula(
188 rModel.maCellAddr, bValue ? OUString("TRUE()") : OUString("FALSE()"));
190 // #108770# set 'Standard' number format for all Boolean cells
191 setCellFormat( rModel );
194 void SheetDataBuffer::setErrorCell( const CellModel& rModel, const OUString& rErrorCode )
196 // Using the formula compiler now we can simply pass on the error string.
197 getFormulaBuffer().setCellFormula( rModel.maCellAddr, rErrorCode);
198 setCellFormat( rModel );
201 void SheetDataBuffer::setErrorCell( const CellModel& rModel, sal_uInt8 nErrorCode )
203 setErrorCell( rModel, getUnitConverter().calcErrorString( nErrorCode));
206 void SheetDataBuffer::setDateCell( const CellModel& rModel, const OUString& rDateString )
208 ScDocument& rDoc = getScDocument();
209 SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
211 double fValue = 0.0;
212 sal_uInt32 nFormatIndex = 0;
213 bool bValid = pFormatter->IsNumberFormat( rDateString, nFormatIndex, fValue );
215 if(bValid)
216 setValueCell( rModel, fValue );
219 void SheetDataBuffer::createSharedFormula(const CellAddress& rAddr, const ApiTokenSequence& rTokens)
221 BinAddress aAddr(rAddr);
222 maSharedFormulas[aAddr] = rTokens;
223 if( mbPendingSharedFmla )
224 setCellFormula( maSharedFmlaAddr, resolveSharedFormula( maSharedBaseAddr ) );
227 void SheetDataBuffer::setFormulaCell( const CellModel& rModel, const ApiTokenSequence& rTokens )
229 mbPendingSharedFmla = false;
230 ApiTokenSequence aTokens;
232 /* Detect special token passed as placeholder for array formulas, shared
233 formulas, and table operations. In BIFF, these formulas are represented
234 by a single tExp resp. tTbl token. If the formula parser finds these
235 tokens, it puts a single OPCODE_BAD token with the base address and
236 formula type into the token sequence. This information will be
237 extracted here, and in case of a shared formula, the shared formula
238 buffer will generate the resulting formula token array. */
239 ApiSpecialTokenInfo aTokenInfo;
240 if( rTokens.hasElements() && getFormulaParser().extractSpecialTokenInfo( aTokenInfo, rTokens ) )
242 /* The second member of the token info is set to true, if the formula
243 represents a table operation, which will be skipped. In BIFF12 it
244 is not possible to distinguish array and shared formulas
245 (BIFF5/BIFF8 provide this information with a special flag in the
246 FORMULA record). */
247 if( !aTokenInfo.Second )
249 /* Construct the token array representing the shared formula. If
250 the returned sequence is empty, the definition of the shared
251 formula has not been loaded yet, or the cell is part of an
252 array formula. In this case, the cell will be remembered. After
253 reading the formula definition it will be retried to insert the
254 formula via retryPendingSharedFormulaCell(). */
255 BinAddress aBaseAddr( aTokenInfo.First );
256 aTokens = resolveSharedFormula( aTokenInfo.First );
257 if( !aTokens.hasElements() )
259 maSharedFmlaAddr = rModel.maCellAddr;
260 maSharedBaseAddr = aTokenInfo.First;
261 mbPendingSharedFmla = true;
265 else
267 // simple formula, use the passed token array
268 aTokens = rTokens;
271 setCellFormula( rModel.maCellAddr, aTokens );
272 setCellFormat( rModel );
275 void SheetDataBuffer::createArrayFormula( const CellRangeAddress& rRange, const ApiTokenSequence& rTokens )
277 /* Array formulas will be inserted later in finalizeImport(). This is
278 needed to not disturb collecting all the cells, which will be put into
279 the sheet in large blocks to increase performance. */
280 maArrayFormulas.push_back( ArrayFormula( rRange, rTokens ) );
283 void SheetDataBuffer::createTableOperation( const CellRangeAddress& rRange, const DataTableModel& rModel )
285 /* Table operations will be inserted later in finalizeImport(). This is
286 needed to not disturb collecting all the cells, which will be put into
287 the sheet in large blocks to increase performance. */
288 maTableOperations.push_back( TableOperation( rRange, rModel ) );
291 void SheetDataBuffer::setRowFormat( sal_Int32 nRow, sal_Int32 nXfId, bool bCustomFormat )
293 // set row formatting
294 if( bCustomFormat )
296 // try to expand cached row range, if formatting is equal
297 if( (maXfIdRowRange.maRowRange.mnLast < 0) || !maXfIdRowRange.tryExpand( nRow, nXfId ) )
300 maXfIdRowRangeList[ maXfIdRowRange.mnXfId ].push_back( maXfIdRowRange.maRowRange );
301 maXfIdRowRange.set( nRow, nXfId );
304 else if( maXfIdRowRange.maRowRange.mnLast >= 0 )
306 // finish last cached row range
307 maXfIdRowRangeList[ maXfIdRowRange.mnXfId ].push_back( maXfIdRowRange.maRowRange );
308 maXfIdRowRange.set( -1, -1 );
312 void SheetDataBuffer::setMergedRange( const CellRangeAddress& rRange )
314 maMergedRanges.push_back( MergedRange( rRange ) );
317 void SheetDataBuffer::setStandardNumFmt( const CellAddress& rCellAddr, sal_Int16 nStdNumFmt )
321 Reference< XNumberFormatsSupplier > xNumFmtsSupp( getDocument(), UNO_QUERY_THROW );
322 Reference< XNumberFormatTypes > xNumFmtTypes( xNumFmtsSupp->getNumberFormats(), UNO_QUERY_THROW );
323 sal_Int32 nIndex = xNumFmtTypes->getStandardFormat( nStdNumFmt, Locale() );
324 PropertySet aPropSet( getCell( rCellAddr ) );
325 aPropSet.setProperty( PROP_NumberFormat, nIndex );
327 catch( Exception& )
332 typedef std::pair<sal_Int32, sal_Int32> FormatKeyPair;
334 void addIfNotInMyMap( StylesBuffer& rStyles, std::map< FormatKeyPair, ApiCellRangeList >& rMap, sal_Int32 nXfId, sal_Int32 nFormatId, const ApiCellRangeList& rRangeList )
336 Xf* pXf1 = rStyles.getCellXf( nXfId ).get();
337 if ( pXf1 )
339 for ( std::map< FormatKeyPair, ApiCellRangeList >::iterator it = rMap.begin(), it_end = rMap.end(); it != it_end; ++it )
341 if ( it->first.second == nFormatId )
343 Xf* pXf2 = rStyles.getCellXf( it->first.first ).get();
344 if ( *pXf1 == *pXf2 ) // already exists
346 // add ranges from the rangelist to the existing rangelist for the
347 // matching style ( should we check if they overlap ? )
348 for ( ::std::vector< CellRangeAddress >::const_iterator iter = rRangeList.begin(), iter_end = rRangeList.end(); iter != iter_end; ++iter )
349 it->second.push_back( *iter );
350 return;
354 rMap[ FormatKeyPair( nXfId, nFormatId ) ] = rRangeList;
358 void SheetDataBuffer::addColXfStyle( sal_Int32 nXfId, sal_Int32 nFormatId, const ::com::sun::star::table::CellRangeAddress& rAddress, bool bProcessRowRange )
360 RowRangeStyle aStyleRows;
361 aStyleRows.mnNumFmt.first = nXfId;
362 aStyleRows.mnNumFmt.second = nFormatId;
363 aStyleRows.mnStartRow = rAddress.StartRow;
364 aStyleRows.mnEndRow = rAddress.EndRow;
365 for ( sal_Int32 nCol = rAddress.StartColumn; nCol <= rAddress.EndColumn; ++nCol )
367 if ( !bProcessRowRange )
368 maStylesPerColumn[ nCol ].insert( aStyleRows );
369 else
371 RowStyles& rRowStyles = maStylesPerColumn[ nCol ];
372 // If the rowrange style includes rows already
373 // allocated to a style then we need to split
374 // the range style Rows into sections ( to
375 // occupy only rows that have no style definition )
377 // We dont want to set any rowstyle 'rows'
378 // for rows where there is an existing 'style' )
379 std::vector< RowRangeStyle > aRangeRowsSplits;
381 RowStyles::iterator rows_it = rRowStyles.begin();
382 RowStyles::iterator rows_end = rRowStyles.end();
383 bool bAddRange = true;
384 for ( ; rows_it != rows_end; ++rows_it )
386 const RowRangeStyle& r = *rows_it;
387 // if row is completely within existing style, discard it
388 if ( aStyleRows.mnStartRow >= r.mnStartRow && aStyleRows.mnEndRow <= r.mnEndRow )
389 bAddRange = false;
390 else if ( aStyleRows.mnStartRow <= r.mnStartRow )
392 // not intersecting at all?, if so finish as none left
393 // to check ( row ranges are in ascending order
394 if ( aStyleRows.mnEndRow < r.mnStartRow )
395 break;
396 else if ( aStyleRows.mnEndRow <= r.mnEndRow )
398 aStyleRows.mnEndRow = r.mnStartRow - 1;
399 break;
401 if ( aStyleRows.mnStartRow < r.mnStartRow )
403 RowRangeStyle aSplit = aStyleRows;
404 aSplit.mnEndRow = r.mnStartRow - 1;
405 aRangeRowsSplits.push_back( aSplit );
409 std::vector< RowRangeStyle >::iterator splits_it = aRangeRowsSplits.begin();
410 std::vector< RowRangeStyle >::iterator splits_end = aRangeRowsSplits.end();
411 for ( ; splits_it != splits_end; ++splits_it )
412 rRowStyles.insert( *splits_it );
413 if ( bAddRange )
414 rRowStyles.insert( aStyleRows );
418 void SheetDataBuffer::finalizeImport()
420 // create all array formulas
421 for( ArrayFormulaList::iterator aIt = maArrayFormulas.begin(), aEnd = maArrayFormulas.end(); aIt != aEnd; ++aIt )
422 finalizeArrayFormula( aIt->first, aIt->second );
424 // create all table operations
425 for( TableOperationList::iterator aIt = maTableOperations.begin(), aEnd = maTableOperations.end(); aIt != aEnd; ++aIt )
426 finalizeTableOperation( aIt->first, aIt->second );
428 // write default formatting of remaining row range
429 maXfIdRowRangeList[ maXfIdRowRange.mnXfId ].push_back( maXfIdRowRange.maRowRange );
431 std::map< FormatKeyPair, ApiCellRangeList > rangeStyleListMap;
432 for( XfIdRangeListMap::const_iterator aIt = maXfIdRangeLists.begin(), aEnd = maXfIdRangeLists.end(); aIt != aEnd; ++aIt )
434 addIfNotInMyMap( getStyles(), rangeStyleListMap, aIt->first.first, aIt->first.second, aIt->second );
436 // gather all ranges that have the same style and apply them in bulk
437 for ( std::map< FormatKeyPair, ApiCellRangeList >::iterator it = rangeStyleListMap.begin(), it_end = rangeStyleListMap.end(); it != it_end; ++it )
439 const ApiCellRangeList& rRanges( it->second );
440 for ( ::std::vector< CellRangeAddress >::const_iterator it_range = rRanges.begin(), it_rangeend = rRanges.end(); it_range!=it_rangeend; ++it_range )
441 addColXfStyle( it->first.first, it->first.second, *it_range );
444 for ( std::map< sal_Int32, std::vector< ValueRange > >::iterator it = maXfIdRowRangeList.begin(), it_end = maXfIdRowRangeList.end(); it != it_end; ++it )
446 ApiCellRangeList rangeList;
447 AddressConverter& rAddrConv = getAddressConverter();
448 // get all row ranges for id
449 for ( std::vector< ValueRange >::iterator rangeIter = it->second.begin(), rangeIter_end = it->second.end(); rangeIter != rangeIter_end; ++rangeIter )
451 if ( it->first == -1 ) // it's a dud skip it
452 continue;
453 CellRangeAddress aRange( getSheetIndex(), 0, rangeIter->mnFirst, rAddrConv.getMaxApiAddress().Column, rangeIter->mnLast );
455 addColXfStyle( it->first, -1, aRange, true );
459 ScDocumentImport& rDoc = getDocImport();
460 StylesBuffer& rStyles = getStyles();
461 for ( ColStyles::iterator col = maStylesPerColumn.begin(), col_end = maStylesPerColumn.end(); col != col_end; ++col )
463 RowStyles& rRowStyles = col->second;
464 Xf::AttrList aAttrs;
465 SCCOL nScCol = static_cast< SCCOL >( col->first );
466 for ( RowStyles::iterator rRows = rRowStyles.begin(), rRows_end = rRowStyles.end(); rRows != rRows_end; ++rRows )
468 Xf* pXf = rStyles.getCellXf( rRows->mnNumFmt.first ).get();
470 if ( pXf )
471 pXf->applyPatternToAttrList( aAttrs, rRows->mnStartRow, rRows->mnEndRow, rRows->mnNumFmt.second );
473 if (aAttrs.maAttrs.empty() || aAttrs.maAttrs.back().nRow != MAXROW)
475 ScAttrEntry aEntry;
476 aEntry.nRow = MAXROW;
477 aEntry.pPattern = rDoc.getDoc().GetPattern(nScCol, 0, getSheetIndex());
478 rDoc.getDoc().GetPool()->Put(*aEntry.pPattern);
479 aAttrs.maAttrs.push_back(aEntry);
481 if (!sc::NumFmtUtil::isLatinScript(*aEntry.pPattern, rDoc.getDoc()))
482 aAttrs.mbLatinNumFmtOnly = false;
485 ScDocumentImport::Attrs aAttrParam;
486 aAttrParam.mnSize = aAttrs.maAttrs.size();
487 aAttrParam.mpData = new ScAttrEntry[aAttrParam.mnSize];
488 aAttrParam.mbLatinNumFmtOnly = aAttrs.mbLatinNumFmtOnly;
489 std::list<ScAttrEntry>::const_iterator itr = aAttrs.maAttrs.begin(), itrEnd = aAttrs.maAttrs.end();
490 for (size_t i = 0; itr != itrEnd; ++itr, ++i)
491 aAttrParam.mpData[i] = *itr;
493 rDoc.setAttrEntries(getSheetIndex(), nScCol, aAttrParam);
496 // merge all cached merged ranges and update right/bottom cell borders
497 for( MergedRangeList::iterator aIt = maMergedRanges.begin(), aEnd = maMergedRanges.end(); aIt != aEnd; ++aIt )
498 applyCellMerging( aIt->maRange );
499 for( MergedRangeList::iterator aIt = maCenterFillRanges.begin(), aEnd = maCenterFillRanges.end(); aIt != aEnd; ++aIt )
500 applyCellMerging( aIt->maRange );
503 // private --------------------------------------------------------------------
505 SheetDataBuffer::XfIdRowRange::XfIdRowRange() :
506 maRowRange( -1 ),
507 mnXfId( -1 )
511 void SheetDataBuffer::XfIdRowRange::set( sal_Int32 nRow, sal_Int32 nXfId )
513 maRowRange = ValueRange( nRow );
514 mnXfId = nXfId;
517 bool SheetDataBuffer::XfIdRowRange::tryExpand( sal_Int32 nRow, sal_Int32 nXfId )
519 if( mnXfId == nXfId )
521 if( maRowRange.mnLast + 1 == nRow )
523 ++maRowRange.mnLast;
524 return true;
526 if( maRowRange.mnFirst == nRow + 1 )
528 --maRowRange.mnFirst;
529 return true;
532 return false;
535 SheetDataBuffer::MergedRange::MergedRange( const CellRangeAddress& rRange ) :
536 maRange( rRange ),
537 mnHorAlign( XML_TOKEN_INVALID )
541 SheetDataBuffer::MergedRange::MergedRange( const CellAddress& rAddress, sal_Int32 nHorAlign ) :
542 maRange( rAddress.Sheet, rAddress.Column, rAddress.Row, rAddress.Column, rAddress.Row ),
543 mnHorAlign( nHorAlign )
547 bool SheetDataBuffer::MergedRange::tryExpand( const CellAddress& rAddress, sal_Int32 nHorAlign )
549 if( (mnHorAlign == nHorAlign) && (maRange.StartRow == rAddress.Row) &&
550 (maRange.EndRow == rAddress.Row) && (maRange.EndColumn + 1 == rAddress.Column) )
552 ++maRange.EndColumn;
553 return true;
555 return false;
558 void SheetDataBuffer::setCellFormula( const CellAddress& rCellAddr, const ApiTokenSequence& rTokens )
560 if( rTokens.hasElements() )
562 putFormulaTokens( rCellAddr, rTokens );
566 ApiTokenSequence SheetDataBuffer::resolveSharedFormula( const CellAddress& rAddr ) const
568 BinAddress aAddr(rAddr);
569 ApiTokenSequence aTokens = ContainerHelper::getMapElement( maSharedFormulas, aAddr, ApiTokenSequence() );
570 return aTokens;
573 void SheetDataBuffer::finalizeArrayFormula( const CellRangeAddress& rRange, const ApiTokenSequence& rTokens ) const
575 Reference< XArrayFormulaTokens > xTokens( getCellRange( rRange ), UNO_QUERY );
576 OSL_ENSURE( xTokens.is(), "SheetDataBuffer::finalizeArrayFormula - missing formula token interface" );
577 if( xTokens.is() )
578 xTokens->setArrayTokens( rTokens );
581 void SheetDataBuffer::finalizeTableOperation( const CellRangeAddress& rRange, const DataTableModel& rModel )
583 if (rModel.mbRef1Deleted)
584 return;
586 if (rModel.maRef1.isEmpty())
587 return;
589 if (rRange.StartColumn <= 0 || rRange.StartRow <= 0)
590 return;
592 sal_Int16 nSheet = getSheetIndex();
594 CellAddress aRef1;
595 if (!getAddressConverter().convertToCellAddress(aRef1, rModel.maRef1, nSheet, true))
596 return;
598 ScDocumentImport& rDoc = getDocImport();
599 ScTabOpParam aParam;
601 ScRange aScRange;
602 ScUnoConversion::FillScRange(aScRange, rRange);
604 if (rModel.mb2dTable)
606 // Two-variable data table.
607 if (rModel.mbRef2Deleted)
608 return;
610 if (rModel.maRef2.isEmpty())
611 return;
613 CellAddress aRef2;
614 if (!getAddressConverter().convertToCellAddress(aRef2, rModel.maRef2, nSheet, true))
615 return;
617 aParam.meMode = ScTabOpParam::Both;
619 aParam.aRefFormulaCell.Set(rRange.StartColumn-1, rRange.StartRow-1, nSheet, false, false, false);
620 aParam.aRefFormulaEnd = aParam.aRefFormulaCell;
622 aScRange.aStart.IncRow(-1);
623 aScRange.aStart.IncCol(-1);
625 // Ref1 is row input cell and Ref2 is column input cell.
626 aParam.aRefRowCell.Set(aRef1.Column, aRef1.Row, aRef1.Sheet, false, false, false);
627 aParam.aRefColCell.Set(aRef2.Column, aRef2.Row, aRef2.Sheet, false, false, false);
628 rDoc.setTableOpCells(aScRange, aParam);
630 return;
633 // One-variable data table.
635 if (rModel.mbRowTable)
637 // One-variable row input cell (horizontal).
638 aParam.meMode = ScTabOpParam::Row;
639 aParam.aRefRowCell.Set(aRef1.Column, aRef1.Row, aRef1.Sheet, false, false, false);
640 aParam.aRefFormulaCell.Set(rRange.StartColumn-1, rRange.StartRow, nSheet, false, true, false);
641 aParam.aRefFormulaEnd = aParam.aRefFormulaCell;
642 aScRange.aStart.IncRow(-1);
643 rDoc.setTableOpCells(aScRange, aParam);
645 else
647 // One-variable column input cell (vertical).
648 aParam.meMode = ScTabOpParam::Column;
649 aParam.aRefColCell.Set(aRef1.Column, aRef1.Row, aRef1.Sheet, false, false, false);
650 aParam.aRefFormulaCell.Set(rRange.StartColumn, rRange.StartRow-1, nSheet, true, false, false);
651 aParam.aRefFormulaEnd = aParam.aRefFormulaCell;
652 aScRange.aStart.IncCol(-1);
653 rDoc.setTableOpCells(aScRange, aParam);
657 void SheetDataBuffer::setCellFormat( const CellModel& rModel, sal_Int32 nNumFmtId )
659 if( (rModel.mnXfId >= 0) || (nNumFmtId >= 0) )
661 ::std::vector< CellRangeAddress >::reverse_iterator aIt = maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, nNumFmtId ) ].rbegin();
662 ::std::vector< CellRangeAddress >::reverse_iterator aItEnd = maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, nNumFmtId ) ].rend();
663 /* The xlsx sheet data contains row wise information.
664 * It is sufficient to check if the row range size is one
666 if( aIt != aItEnd &&
667 aIt->Sheet == rModel.maCellAddr.Sheet &&
668 aIt->StartRow == aIt->EndRow &&
669 aIt->StartRow == rModel.maCellAddr.Row &&
670 (aIt->EndColumn+1) == rModel.maCellAddr.Column )
672 aIt->EndColumn++; // Expand Column
674 else
676 maXfIdRangeLists[ XfIdNumFmtKey (rModel.mnXfId, nNumFmtId ) ].push_back(
677 CellRangeAddress( rModel.maCellAddr.Sheet, rModel.maCellAddr.Column, rModel.maCellAddr.Row,
678 rModel.maCellAddr.Column, rModel.maCellAddr.Row ) );
681 aIt = maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, nNumFmtId ) ].rbegin();
682 aItEnd = maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, nNumFmtId ) ].rend();
683 ::std::vector< CellRangeAddress >::reverse_iterator aItM = aIt+1;
684 while( aItM != aItEnd )
686 if( aIt->Sheet == aItM->Sheet )
688 /* Try to merge this with the previous range */
689 if( aIt->StartRow == (aItM->EndRow + 1) &&
690 aIt->StartColumn == aItM->StartColumn &&
691 aIt->EndColumn == aItM->EndColumn)
693 aItM->EndRow = aIt->EndRow;
694 maXfIdRangeLists[ XfIdNumFmtKey( rModel.mnXfId, nNumFmtId ) ].pop_back();
695 break;
697 else if( aIt->StartRow > aItM->EndRow + 1 )
698 break; // Un-necessary to check with any other rows
700 else
701 break;
702 ++aItM;
705 // update merged ranges for 'center across selection' and 'fill'
706 if( const Xf* pXf = getStyles().getCellXf( rModel.mnXfId ).get() )
708 sal_Int32 nHorAlign = pXf->getAlignment().getModel().mnHorAlign;
709 if( (nHorAlign == XML_centerContinuous) || (nHorAlign == XML_fill) )
711 /* start new merged range, if cell is not empty (#108781#),
712 or try to expand last range with empty cell */
713 if( rModel.mnCellType != XML_TOKEN_INVALID )
714 maCenterFillRanges.push_back( MergedRange( rModel.maCellAddr, nHorAlign ) );
715 else if( !maCenterFillRanges.empty() )
716 maCenterFillRanges.rbegin()->tryExpand( rModel.maCellAddr, nHorAlign );
722 void lcl_SetBorderLine( ScDocument& rDoc, ScRange& rRange, SCTAB nScTab, SvxBoxItemLine nLine )
724 SCCOL nFromScCol = (nLine == SvxBoxItemLine::RIGHT) ? rRange.aEnd.Col() : rRange.aStart.Col();
725 SCROW nFromScRow = (nLine == SvxBoxItemLine::BOTTOM) ? rRange.aEnd.Row() : rRange.aStart.Row();
727 const SvxBoxItem* pFromItem = static_cast< const SvxBoxItem* >(
728 rDoc.GetAttr( nFromScCol, nFromScRow, nScTab, ATTR_BORDER ) );
729 const SvxBoxItem* pToItem = static_cast< const SvxBoxItem* >(
730 rDoc.GetAttr( rRange.aStart.Col(), rRange.aStart.Row(), nScTab, ATTR_BORDER ) );
732 SvxBoxItem aNewItem( *pToItem );
733 aNewItem.SetLine( pFromItem->GetLine( nLine ), nLine );
734 rDoc.ApplyAttr( rRange.aStart.Col(), rRange.aStart.Row(), nScTab, aNewItem );
737 void SheetDataBuffer::applyCellMerging( const CellRangeAddress& rRange )
739 bool bMultiCol = rRange.StartColumn < rRange.EndColumn;
740 bool bMultiRow = rRange.StartRow < rRange.EndRow;
742 ScRange aRange;
743 ScUnoConversion::FillScRange( aRange, rRange );
744 const ScAddress& rStart = aRange.aStart;
745 const ScAddress& rEnd = aRange.aEnd;
746 ScDocument& rDoc = getScDocument();
747 // set correct right border
748 if( bMultiCol )
749 lcl_SetBorderLine( rDoc, aRange, getSheetIndex(), SvxBoxItemLine::RIGHT );
750 // set correct lower border
751 if( bMultiRow )
752 lcl_SetBorderLine( rDoc, aRange, getSheetIndex(), SvxBoxItemLine::BOTTOM );
753 // do merge
754 if( bMultiCol || bMultiRow )
755 rDoc.DoMerge( getSheetIndex(), rStart.Col(), rStart.Row(), rEnd.Col(), rEnd.Row() );
756 // #i93609# merged range in a single row: test if manual row height is needed
757 if( !bMultiRow )
759 bool bTextWrap = static_cast< const SfxBoolItem* >( rDoc.GetAttr( rStart.Col(), rStart.Row(), rStart.Tab(), ATTR_LINEBREAK ) )->GetValue();
760 if( !bTextWrap && (rDoc.GetCellType( rStart ) == CELLTYPE_EDIT) )
762 if (const EditTextObject* pEditObj = rDoc.GetEditText(rStart))
763 bTextWrap = pEditObj->GetParagraphCount() > 1;
768 } // namespace xls
769 } // namespace oox
771 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */