xref: /aoo41x/main/oox/source/xls/sheetdatabuffer.cxx (revision 102b8ff7)
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