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
10d0626817SAndrew Rist *
11d0626817SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0
12d0626817SAndrew Rist *
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.
19d0626817SAndrew Rist *
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
CellModel()67cdf0e10cSrcweir CellModel::CellModel() :
68cdf0e10cSrcweir mnCellType( XML_TOKEN_INVALID ),
69cdf0e10cSrcweir mnXfId( -1 ),
70cdf0e10cSrcweir mbShowPhonetic( false )
71cdf0e10cSrcweir {
72cdf0e10cSrcweir }
73cdf0e10cSrcweir
74cdf0e10cSrcweir // ----------------------------------------------------------------------------
75cdf0e10cSrcweir
CellFormulaModel()76cdf0e10cSrcweir CellFormulaModel::CellFormulaModel() :
77cdf0e10cSrcweir mnFormulaType( XML_TOKEN_INVALID ),
78cdf0e10cSrcweir mnSharedId( -1 )
79cdf0e10cSrcweir {
80cdf0e10cSrcweir }
81cdf0e10cSrcweir
isValidArrayRef(const CellAddress & rCellAddr)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
isValidSharedRef(const CellAddress & rCellAddr)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
DataTableModel()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
CellBlock(const WorksheetHelper & rHelper,const ValueRange & rColSpan,sal_Int32 nRow)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
isExpandable(const ValueRange & rColSpan) const127cdf0e10cSrcweir bool CellBlock::isExpandable( const ValueRange& rColSpan ) const
128cdf0e10cSrcweir {
129cdf0e10cSrcweir return (maRange.StartColumn == rColSpan.mnFirst) && (maRange.EndColumn == rColSpan.mnLast);
130cdf0e10cSrcweir }
131cdf0e10cSrcweir
isBefore(const ValueRange & rColSpan) const132cdf0e10cSrcweir 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
contains(sal_Int32 nCol) const138cdf0e10cSrcweir bool CellBlock::contains( sal_Int32 nCol ) const
139cdf0e10cSrcweir {
140cdf0e10cSrcweir return (maRange.StartColumn <= nCol) && (nCol <= maRange.EndColumn);
141cdf0e10cSrcweir }
142cdf0e10cSrcweir
insertRichString(const CellAddress & rAddress,const RichStringRef & rxString,const Font * pFirstPortionFont)143cdf0e10cSrcweir void CellBlock::insertRichString( const CellAddress& rAddress, const RichStringRef& rxString, const Font* pFirstPortionFont )
144cdf0e10cSrcweir {
145cdf0e10cSrcweir maRichStrings.push_back( RichStringCell( rAddress, rxString, pFirstPortionFont ) );
146cdf0e10cSrcweir }
147cdf0e10cSrcweir
startNextRow()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
getCellAny(sal_Int32 nCol)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
finalizeImport()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
RichStringCell(const CellAddress & rCellAddr,const RichStringRef & rxString,const Font * pFirstPortionFont)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
fillUnusedCells(sal_Int32 nIndex)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
CellBlockBuffer(const WorksheetHelper & rHelper)221cdf0e10cSrcweir CellBlockBuffer::CellBlockBuffer( const WorksheetHelper& rHelper ) :
222cdf0e10cSrcweir WorksheetHelper( rHelper ),
223cdf0e10cSrcweir mnCurrRow( -1 )
224cdf0e10cSrcweir {
225cdf0e10cSrcweir maCellBlockIt = maCellBlocks.end();
226cdf0e10cSrcweir }
227cdf0e10cSrcweir
setColSpans(sal_Int32 nRow,const ValueRangeSet & rColSpans)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
getCellBlock(const CellAddress & rCellAddr)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
finalizeImport()310cdf0e10cSrcweir void CellBlockBuffer::finalizeImport()
311cdf0e10cSrcweir {
312cdf0e10cSrcweir maCellBlocks.forEachMem( &CellBlock::finalizeImport );
313cdf0e10cSrcweir }
314cdf0e10cSrcweir
315cdf0e10cSrcweir // ============================================================================
316cdf0e10cSrcweir
SheetDataBuffer(const WorksheetHelper & rHelper)317cdf0e10cSrcweir SheetDataBuffer::SheetDataBuffer( const WorksheetHelper& rHelper ) :
318cdf0e10cSrcweir WorksheetHelper( rHelper ),
319cdf0e10cSrcweir maCellBlocks( rHelper ),
320cdf0e10cSrcweir mbPendingSharedFmla( false )
321cdf0e10cSrcweir {
322cdf0e10cSrcweir }
323cdf0e10cSrcweir
setColSpans(sal_Int32 nRow,const ValueRangeSet & rColSpans)324cdf0e10cSrcweir void SheetDataBuffer::setColSpans( sal_Int32 nRow, const ValueRangeSet& rColSpans )
325cdf0e10cSrcweir {
326cdf0e10cSrcweir maCellBlocks.setColSpans( nRow, rColSpans );
327cdf0e10cSrcweir }
328cdf0e10cSrcweir
setBlankCell(const CellModel & rModel)329cdf0e10cSrcweir void SheetDataBuffer::setBlankCell( const CellModel& rModel )
330cdf0e10cSrcweir {
331cdf0e10cSrcweir setCellFormat( rModel );
332cdf0e10cSrcweir }
333cdf0e10cSrcweir
setValueCell(const CellModel & rModel,double fValue)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
setStringCell(const CellModel & rModel,const OUString & rText)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
setStringCell(const CellModel & rModel,const RichStringRef & rxString)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
setStringCell(const CellModel & rModel,sal_Int32 nStringId)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
setDateTimeCell(const CellModel & rModel,const DateTime & rDateTime)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
setBooleanCell(const CellModel & rModel,bool bValue)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
setErrorCell(const CellModel & rModel,const OUString & rErrorCode)398cdf0e10cSrcweir void SheetDataBuffer::setErrorCell( const CellModel& rModel, const OUString& rErrorCode )
399cdf0e10cSrcweir {
400cdf0e10cSrcweir setErrorCell( rModel, getUnitConverter().calcBiffErrorCode( rErrorCode ) );
401cdf0e10cSrcweir }
402cdf0e10cSrcweir
setErrorCell(const CellModel & rModel,sal_uInt8 nErrorCode)403cdf0e10cSrcweir void SheetDataBuffer::setErrorCell( const CellModel& rModel, sal_uInt8 nErrorCode )
404cdf0e10cSrcweir {
405cdf0e10cSrcweir setCellFormula( rModel.maCellAddr, getFormulaParser().convertErrorToFormula( nErrorCode ) );
406cdf0e10cSrcweir setCellFormat( rModel );
407cdf0e10cSrcweir }
408cdf0e10cSrcweir
setFormulaCell(const CellModel & rModel,const ApiTokenSequence & rTokens)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
setFormulaCell(const CellModel & rModel,sal_Int32 nSharedId)457cdf0e10cSrcweir void SheetDataBuffer::setFormulaCell( const CellModel& rModel, sal_Int32 nSharedId )
458cdf0e10cSrcweir {
459cdf0e10cSrcweir setCellFormula( rModel.maCellAddr, resolveSharedFormula( BinAddress( nSharedId, 0 ) ) );
460cdf0e10cSrcweir setCellFormat( rModel );
461cdf0e10cSrcweir }
462cdf0e10cSrcweir
createArrayFormula(const CellRangeAddress & rRange,const ApiTokenSequence & rTokens)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
createTableOperation(const CellRangeAddress & rRange,const DataTableModel & rModel)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
createSharedFormula(sal_Int32 nSharedId,const ApiTokenSequence & rTokens)479cdf0e10cSrcweir void SheetDataBuffer::createSharedFormula( sal_Int32 nSharedId, const ApiTokenSequence& rTokens )
480cdf0e10cSrcweir {
481cdf0e10cSrcweir createSharedFormula( BinAddress( nSharedId, 0 ), rTokens );
482cdf0e10cSrcweir }
483cdf0e10cSrcweir
createSharedFormula(const CellAddress & rCellAddr,const ApiTokenSequence & rTokens)484cdf0e10cSrcweir void SheetDataBuffer::createSharedFormula( const CellAddress& rCellAddr, const ApiTokenSequence& rTokens )
485cdf0e10cSrcweir {
486cdf0e10cSrcweir createSharedFormula( BinAddress( rCellAddr ), rTokens );
487cdf0e10cSrcweir }
488cdf0e10cSrcweir
setRowFormat(sal_Int32 nRow,sal_Int32 nXfId,bool bCustomFormat)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
setMergedRange(const CellRangeAddress & rRange)509cdf0e10cSrcweir void SheetDataBuffer::setMergedRange( const CellRangeAddress& rRange )
510cdf0e10cSrcweir {
511cdf0e10cSrcweir maMergedRanges.push_back( MergedRange( rRange ) );
512cdf0e10cSrcweir }
513cdf0e10cSrcweir
setStandardNumFmt(const CellAddress & rCellAddr,sal_Int16 nStdNumFmt)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
finalizeImport()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
XfIdRowRange()560cdf0e10cSrcweir SheetDataBuffer::XfIdRowRange::XfIdRowRange() :
561cdf0e10cSrcweir maRowRange( -1 ),
562cdf0e10cSrcweir mnXfId( -1 )
563cdf0e10cSrcweir {
564cdf0e10cSrcweir }
565cdf0e10cSrcweir
intersects(const CellRangeAddress & rRange) const566cdf0e10cSrcweir bool SheetDataBuffer::XfIdRowRange::intersects( const CellRangeAddress& rRange ) const
567cdf0e10cSrcweir {
568cdf0e10cSrcweir return (rRange.StartRow <= maRowRange.mnLast) && (maRowRange.mnFirst <= rRange.EndRow);
569cdf0e10cSrcweir }
570cdf0e10cSrcweir
set(sal_Int32 nRow,sal_Int32 nXfId)571cdf0e10cSrcweir void SheetDataBuffer::XfIdRowRange::set( sal_Int32 nRow, sal_Int32 nXfId )
572cdf0e10cSrcweir {
573cdf0e10cSrcweir maRowRange = ValueRange( nRow );
574cdf0e10cSrcweir mnXfId = nXfId;
575cdf0e10cSrcweir }
576cdf0e10cSrcweir
tryExpand(sal_Int32 nRow,sal_Int32 nXfId)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
set(const CellAddress & rCellAddr,sal_Int32 nXfId,sal_Int32 nNumFmtId)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
tryExpand(const CellAddress & rCellAddr,sal_Int32 nXfId,sal_Int32 nNumFmtId)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
tryMerge(const XfIdRange & rXfIdRange)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
MergedRange(const CellRangeAddress & rRange)632cdf0e10cSrcweir SheetDataBuffer::MergedRange::MergedRange( const CellRangeAddress& rRange ) :
633cdf0e10cSrcweir maRange( rRange ),
634cdf0e10cSrcweir mnHorAlign( XML_TOKEN_INVALID )
635cdf0e10cSrcweir {
636cdf0e10cSrcweir }
637cdf0e10cSrcweir
MergedRange(const CellAddress & rAddress,sal_Int32 nHorAlign)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
tryExpand(const CellAddress & rAddress,sal_Int32 nHorAlign)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
setCellFormula(const CellAddress & rCellAddr,const ApiTokenSequence & rTokens)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
createSharedFormula(const BinAddress & rMapKey,const ApiTokenSequence & rTokens)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
resolveSharedFormula(const BinAddress & rMapKey) const700cdf0e10cSrcweir 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
finalizeArrayFormula(const CellRangeAddress & rRange,const ApiTokenSequence & rTokens) const706cdf0e10cSrcweir 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
finalizeTableOperation(const CellRangeAddress & rRange,const DataTableModel & rModel) const714cdf0e10cSrcweir 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
setCellFormat(const CellModel & rModel,sal_Int32 nNumFmtId)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
writeXfIdRowRangeProperties(const XfIdRowRange & rXfIdRowRange) const832cdf0e10cSrcweir 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
writeXfIdRangeProperties(const XfIdRange & rXfIdRange) const846cdf0e10cSrcweir 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
mergeXfIdRanges()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
finalizeMergedRange(const CellRangeAddress & rRange)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