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