1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "sheetdatacontext.hxx"
22 #include <com/sun/star/table/CellContentType.hpp>
23 #include <com/sun/star/table/XCell.hpp>
24 #include <com/sun/star/table/XCellRange.hpp>
25 #include <com/sun/star/text/XText.hpp>
26 #include <oox/helper/attributelist.hxx>
27 #include <oox/helper/propertyset.hxx>
28 #include "addressconverter.hxx"
29 #include "biffinputstream.hxx"
30 #include "formulaparser.hxx"
31 #include "richstringcontext.hxx"
32 #include "unitconverter.hxx"
37 using namespace ::com::sun::star::sheet
;
38 using namespace ::com::sun::star::table
;
39 using namespace ::com::sun::star::text
;
40 using namespace ::com::sun::star::uno
;
42 using ::oox::core::ContextHandlerRef
;
46 // record constants -----------------------------------------------------------
48 const sal_uInt32 BIFF12_CELL_SHOWPHONETIC
= 0x01000000;
50 const sal_uInt8 BIFF12_DATATABLE_ROW
= 0x01;
51 const sal_uInt8 BIFF12_DATATABLE_2D
= 0x02;
52 const sal_uInt8 BIFF12_DATATABLE_REF1DEL
= 0x04;
53 const sal_uInt8 BIFF12_DATATABLE_REF2DEL
= 0x08;
55 const sal_uInt16 BIFF12_ROW_THICKTOP
= 0x0001;
56 const sal_uInt16 BIFF12_ROW_THICKBOTTOM
= 0x0002;
57 const sal_uInt16 BIFF12_ROW_COLLAPSED
= 0x0800;
58 const sal_uInt16 BIFF12_ROW_HIDDEN
= 0x1000;
59 const sal_uInt16 BIFF12_ROW_CUSTOMHEIGHT
= 0x2000;
60 const sal_uInt16 BIFF12_ROW_CUSTOMFORMAT
= 0x4000;
61 const sal_uInt8 BIFF12_ROW_SHOWPHONETIC
= 0x01;
65 SheetDataContextBase::SheetDataContextBase( const WorksheetHelper
& rHelper
) :
66 mrAddressConv( rHelper
.getAddressConverter() ),
67 mrSheetData( rHelper
.getSheetData() ),
68 mnSheet( rHelper
.getSheetIndex() )
70 mxFormulaParser
.reset(rHelper
.createFormulaParser());
73 SheetDataContextBase::~SheetDataContextBase()
77 SheetDataContext::SheetDataContext( WorksheetFragmentBase
& rFragment
) :
78 WorksheetContextBase( rFragment
),
79 SheetDataContextBase( rFragment
),
80 mbHasFormula( false ),
81 mbValidRange( false ),
85 SAL_INFO( "sc.filter", "start safe sheet data context - unlock\n" );
88 SheetDataContext::~SheetDataContext()
90 SAL_INFO( "sc.filter", "end safe sheet data context - relock\n" );
93 ContextHandlerRef
SheetDataContext::onCreateContext( sal_Int32 nElement
, const AttributeList
& rAttribs
)
95 switch( getCurrentElement() )
97 case XLS_TOKEN( sheetData
):
98 if( nElement
== XLS_TOKEN( row
) ) { importRow( rAttribs
); return this; }
101 case XLS_TOKEN( row
):
102 // do not process cell elements with invalid (out-of-range) address
103 if( nElement
== XLS_TOKEN( c
) && importCell( rAttribs
) )
110 case XLS_TOKEN( is
):
111 mxInlineStr
.reset( new RichString( *this ) );
112 return new RichStringContext( *this, mxInlineStr
);
114 return this; // characters contain cell value
116 importFormula( rAttribs
);
117 return this; // characters contain formula string
124 void SheetDataContext::onCharacters( const OUString
& rChars
)
126 switch( getCurrentElement() )
129 maCellValue
= rChars
;
132 if( maFmlaData
.mnFormulaType
!= XML_TOKEN_INVALID
)
134 maFormulaStr
= rChars
;
140 void SheetDataContext::onEndElement()
142 if( getCurrentElement() == XLS_TOKEN( c
) )
144 // try to create a formula cell
145 if( mbHasFormula
) switch( maFmlaData
.mnFormulaType
)
147 // will buffer formulas but need to
148 // a) need to set format first
151 setCellFormula( maCellData
.maCellAddr
, maFormulaStr
);
152 mrSheetData
.setCellFormat( maCellData
);
154 // If a number cell has some preloaded value, stick it into the buffer
155 // but do this only for real cell formulas (not array, shared etc.)
156 if (!maCellValue
.isEmpty())
157 setCellFormulaValue(maCellData
.maCellAddr
, maCellValue
, maCellData
.mnCellType
);
161 if( maFmlaData
.mnSharedId
>= 0 )
163 if( mbValidRange
&& maFmlaData
.isValidSharedRef( maCellData
.maCellAddr
) )
164 createSharedFormulaMapEntry(maCellData
.maCellAddr
, maFmlaData
.maFormulaRef
, maFmlaData
.mnSharedId
, maFormulaStr
);
166 setCellFormula(maCellData
.maCellAddr
, maFmlaData
.mnSharedId
, maCellValue
, maCellData
.mnCellType
);
167 mrSheetData
.setCellFormat( maCellData
);
170 // no success, set plain cell value and formatting below
171 mbHasFormula
= false;
174 if( mbValidRange
&& maFmlaData
.isValidArrayRef( maCellData
.maCellAddr
) )
175 setCellArrayFormula( maFmlaData
.maFormulaRef
, maCellData
.maCellAddr
, maFormulaStr
);
176 // set cell formatting, but do not set result as cell value
177 mrSheetData
.setBlankCell( maCellData
);
181 mrSheetData
.createTableOperation( maFmlaData
.maFormulaRef
, maTableData
);
182 // set cell formatting, but do not set result as cell value
183 mrSheetData
.setBlankCell( maCellData
);
186 OSL_ENSURE( maFmlaData
.mnFormulaType
== XML_TOKEN_INVALID
, "SheetDataContext::onEndElement - unknown formula type" );
187 mbHasFormula
= false;
192 // no formula created: try to set the cell value
193 if( !maCellValue
.isEmpty() ) switch( maCellData
.mnCellType
)
196 mrSheetData
.setValueCell( maCellData
, maCellValue
.toDouble() );
199 mrSheetData
.setBooleanCell( maCellData
, maCellValue
.toDouble() != 0.0 );
202 mrSheetData
.setErrorCell( maCellData
, maCellValue
);
205 mrSheetData
.setStringCell( maCellData
, maCellValue
);
208 mrSheetData
.setStringCell( maCellData
, maCellValue
.toInt32() );
211 mrSheetData
.setDateCell( maCellData
, maCellValue
);
214 else if( (maCellData
.mnCellType
== XML_inlineStr
) && mxInlineStr
.get() )
216 mxInlineStr
->finalizeImport();
217 mrSheetData
.setStringCell( maCellData
, mxInlineStr
);
221 // empty cell, update cell type
222 maCellData
.mnCellType
= XML_TOKEN_INVALID
;
223 mrSheetData
.setBlankCell( maCellData
);
229 ContextHandlerRef
SheetDataContext::onCreateRecordContext( sal_Int32 nRecId
, SequenceInputStream
& rStrm
)
231 switch( getCurrentElement() )
233 case BIFF12_ID_SHEETDATA
:
234 if( nRecId
== BIFF12_ID_ROW
) { importRow( rStrm
); return this; }
240 case BIFF12_ID_ARRAY
: importArray( rStrm
); break;
241 case BIFF12_ID_CELL_BOOL
: importCellBool( rStrm
, CELLTYPE_VALUE
); break;
242 case BIFF12_ID_CELL_BLANK
: importCellBlank( rStrm
, CELLTYPE_VALUE
); break;
243 case BIFF12_ID_CELL_DOUBLE
: importCellDouble( rStrm
, CELLTYPE_VALUE
); break;
244 case BIFF12_ID_CELL_ERROR
: importCellError( rStrm
, CELLTYPE_VALUE
); break;
245 case BIFF12_ID_CELL_RK
: importCellRk( rStrm
, CELLTYPE_VALUE
); break;
246 case BIFF12_ID_CELL_RSTRING
: importCellRString( rStrm
, CELLTYPE_VALUE
); break;
247 case BIFF12_ID_CELL_SI
: importCellSi( rStrm
, CELLTYPE_VALUE
); break;
248 case BIFF12_ID_CELL_STRING
: importCellString( rStrm
, CELLTYPE_VALUE
); break;
249 case BIFF12_ID_DATATABLE
: importDataTable( rStrm
); break;
250 case BIFF12_ID_FORMULA_BOOL
: importCellBool( rStrm
, CELLTYPE_FORMULA
); break;
251 case BIFF12_ID_FORMULA_DOUBLE
: importCellDouble( rStrm
, CELLTYPE_FORMULA
); break;
252 case BIFF12_ID_FORMULA_ERROR
: importCellError( rStrm
, CELLTYPE_FORMULA
); break;
253 case BIFF12_ID_FORMULA_STRING
: importCellString( rStrm
, CELLTYPE_FORMULA
); break;
254 case BIFF12_ID_MULTCELL_BOOL
: importCellBool( rStrm
, CELLTYPE_MULTI
); break;
255 case BIFF12_ID_MULTCELL_BLANK
: importCellBlank( rStrm
, CELLTYPE_MULTI
); break;
256 case BIFF12_ID_MULTCELL_DOUBLE
: importCellDouble( rStrm
, CELLTYPE_MULTI
); break;
257 case BIFF12_ID_MULTCELL_ERROR
: importCellError( rStrm
, CELLTYPE_MULTI
); break;
258 case BIFF12_ID_MULTCELL_RK
: importCellRk( rStrm
, CELLTYPE_MULTI
); break;
259 case BIFF12_ID_MULTCELL_RSTRING
:importCellRString( rStrm
, CELLTYPE_MULTI
); break;
260 case BIFF12_ID_MULTCELL_SI
: importCellSi( rStrm
, CELLTYPE_MULTI
); break;
261 case BIFF12_ID_MULTCELL_STRING
: importCellString( rStrm
, CELLTYPE_MULTI
); break;
262 case BIFF12_ID_SHAREDFMLA
: importSharedFmla( rStrm
); break;
269 // private --------------------------------------------------------------------
271 void SheetDataContext::importRow( const AttributeList
& rAttribs
)
274 sal_Int32 nRow
= rAttribs
.getInteger( XML_r
, -1 ); // 1-based row index
278 mnRow
= nRow
-1; // to 0-based row index.
281 aModel
.mnRow
= ++mnRow
;
284 aModel
.mfHeight
= rAttribs
.getDouble( XML_ht
, -1.0 );
285 aModel
.mnXfId
= rAttribs
.getInteger( XML_s
, -1 );
286 aModel
.mnLevel
= rAttribs
.getInteger( XML_outlineLevel
, 0 );
287 aModel
.mbCustomHeight
= rAttribs
.getBool( XML_customHeight
, false );
288 aModel
.mbCustomFormat
= rAttribs
.getBool( XML_customFormat
, false );
289 aModel
.mbShowPhonetic
= rAttribs
.getBool( XML_ph
, false );
290 aModel
.mbHidden
= rAttribs
.getBool( XML_hidden
, false );
291 aModel
.mbCollapsed
= rAttribs
.getBool( XML_collapsed
, false );
292 aModel
.mbThickTop
= rAttribs
.getBool( XML_thickTop
, false );
293 aModel
.mbThickBottom
= rAttribs
.getBool( XML_thickBot
, false );
295 // decode the column spans (space-separated list of colon-separated integer pairs)
296 OUString aColSpansText
= rAttribs
.getString( XML_spans
, OUString() );
297 sal_Int32 nMaxCol
= mrAddressConv
.getMaxApiAddress().Column
;
298 sal_Int32 nIndex
= 0;
301 OUString aColSpanToken
= aColSpansText
.getToken( 0, ' ', nIndex
);
302 sal_Int32 nSepPos
= aColSpanToken
.indexOf( ':' );
303 if( (0 < nSepPos
) && (nSepPos
+ 1 < aColSpanToken
.getLength()) )
305 // OOXML uses 1-based integer column indexes, row model expects 0-based colspans
306 sal_Int32 nLastCol
= ::std::min( aColSpanToken
.copy( nSepPos
+ 1 ).toInt32() - 1, nMaxCol
);
307 aModel
.insertColSpan( ValueRange( aColSpanToken
.copy( 0, nSepPos
).toInt32() - 1, nLastCol
) );
311 // set row properties in the current sheet
312 setRowModel( aModel
);
315 bool SheetDataContext::importCell( const AttributeList
& rAttribs
)
318 const char* p
= rAttribs
.getChar(XML_r
);
323 maCellData
.maCellAddr
= CellAddress( mnSheet
, mnCol
, mnRow
);
327 bValid
= mrAddressConv
.convertToCellAddress(maCellData
.maCellAddr
, p
, mnSheet
, true);
328 mnCol
= maCellData
.maCellAddr
.Column
;
333 maCellData
.mnCellType
= rAttribs
.getToken( XML_t
, XML_n
);
334 maCellData
.mnXfId
= rAttribs
.getInteger( XML_s
, -1 );
335 maCellData
.mbShowPhonetic
= rAttribs
.getBool( XML_ph
, false );
337 // reset cell value, formula settings, and inline string
340 mbHasFormula
= false;
342 // update used area of the sheet
343 extendUsedArea( maCellData
.maCellAddr
);
348 void SheetDataContext::importFormula( const AttributeList
& rAttribs
)
351 mbValidRange
= mrAddressConv
.convertToCellRange( maFmlaData
.maFormulaRef
, rAttribs
.getString( XML_ref
, OUString() ), mnSheet
, true, true );
353 maFmlaData
.mnFormulaType
= rAttribs
.getToken( XML_t
, XML_normal
);
354 maFmlaData
.mnSharedId
= rAttribs
.getInteger( XML_si
, -1 );
356 if( maFmlaData
.mnFormulaType
== XML_dataTable
)
358 maTableData
.maRef1
= rAttribs
.getString( XML_r1
, OUString() );
359 maTableData
.maRef2
= rAttribs
.getString( XML_r2
, OUString() );
360 maTableData
.mb2dTable
= rAttribs
.getBool( XML_dt2D
, false );
361 maTableData
.mbRowTable
= rAttribs
.getBool( XML_dtr
, false );
362 maTableData
.mbRef1Deleted
= rAttribs
.getBool( XML_del1
, false );
363 maTableData
.mbRef2Deleted
= rAttribs
.getBool( XML_del2
, false );
366 maFormulaStr
.clear();
369 void SheetDataContext::importRow( SequenceInputStream
& rStrm
)
372 sal_Int32 nSpanCount
;
373 sal_uInt16 nHeight
, nFlags1
;
375 maCurrPos
.mnRow
= rStrm
.readInt32();
376 aModel
.mnXfId
= rStrm
.readInt32();
377 nHeight
= rStrm
.readuInt16();
378 nFlags1
= rStrm
.readuInt16();
379 nFlags2
= rStrm
.readuChar();
380 nSpanCount
= rStrm
.readInt32();
383 // row index is 0-based in BIFF12, but RowModel expects 1-based
384 aModel
.mnRow
= maCurrPos
.mnRow
+ 1;
385 // row height is in twips in BIFF12, convert to points
386 aModel
.mfHeight
= nHeight
/ 20.0;
387 aModel
.mnLevel
= extractValue
< sal_Int32
>( nFlags1
, 8, 3 );
388 aModel
.mbCustomHeight
= getFlag( nFlags1
, BIFF12_ROW_CUSTOMHEIGHT
);
389 aModel
.mbCustomFormat
= getFlag( nFlags1
, BIFF12_ROW_CUSTOMFORMAT
);
390 aModel
.mbShowPhonetic
= getFlag( nFlags2
, BIFF12_ROW_SHOWPHONETIC
);
391 aModel
.mbHidden
= getFlag( nFlags1
, BIFF12_ROW_HIDDEN
);
392 aModel
.mbCollapsed
= getFlag( nFlags1
, BIFF12_ROW_COLLAPSED
);
393 aModel
.mbThickTop
= getFlag( nFlags1
, BIFF12_ROW_THICKTOP
);
394 aModel
.mbThickBottom
= getFlag( nFlags1
, BIFF12_ROW_THICKBOTTOM
);
396 // read the column spans
397 sal_Int32 nMaxCol
= mrAddressConv
.getMaxApiAddress().Column
;
398 for( sal_Int32 nSpanIdx
= 0; (nSpanIdx
< nSpanCount
) && !rStrm
.isEof(); ++nSpanIdx
)
400 sal_Int32 nFirstCol
, nLastCol
;
401 nFirstCol
= rStrm
.readInt32();
402 nLastCol
= rStrm
.readInt32();
403 aModel
.insertColSpan( ValueRange( nFirstCol
, ::std::min( nLastCol
, nMaxCol
) ) );
406 // set row properties in the current sheet
407 setRowModel( aModel
);
410 bool SheetDataContext::readCellHeader( SequenceInputStream
& rStrm
, CellType eCellType
)
415 case CELLTYPE_FORMULA
: maCurrPos
.mnCol
= rStrm
.readInt32(); break;
416 case CELLTYPE_MULTI
: ++maCurrPos
.mnCol
; break;
419 sal_uInt32 nXfId
= rStrm
.readuInt32();
421 bool bValidAddr
= mrAddressConv
.convertToCellAddress( maCellData
.maCellAddr
, maCurrPos
, mnSheet
, true );
422 maCellData
.mnXfId
= extractValue
< sal_Int32
>( nXfId
, 0, 24 );
423 maCellData
.mbShowPhonetic
= getFlag( nXfId
, BIFF12_CELL_SHOWPHONETIC
);
425 // update used area of the sheet
427 extendUsedArea( maCellData
.maCellAddr
);
431 ApiTokenSequence
SheetDataContext::readCellFormula( SequenceInputStream
& rStrm
)
434 return mxFormulaParser
->importFormula( maCellData
.maCellAddr
, FORMULATYPE_CELL
, rStrm
);
437 bool SheetDataContext::readFormulaRef( SequenceInputStream
& rStrm
)
441 return mrAddressConv
.convertToCellRange( maFmlaData
.maFormulaRef
, aRange
, mnSheet
, true, true );
444 void SheetDataContext::importCellBool( SequenceInputStream
& rStrm
, CellType eCellType
)
446 if( readCellHeader( rStrm
, eCellType
) )
448 maCellData
.mnCellType
= XML_b
;
449 bool bValue
= rStrm
.readuInt8() != 0;
450 if( eCellType
== CELLTYPE_FORMULA
)
451 mrSheetData
.setFormulaCell( maCellData
, readCellFormula( rStrm
) );
453 mrSheetData
.setBooleanCell( maCellData
, bValue
);
457 void SheetDataContext::importCellBlank( SequenceInputStream
& rStrm
, CellType eCellType
)
459 OSL_ENSURE( eCellType
!= CELLTYPE_FORMULA
, "SheetDataContext::importCellBlank - no formula cells supported" );
460 if( readCellHeader( rStrm
, eCellType
) )
461 mrSheetData
.setBlankCell( maCellData
);
464 void SheetDataContext::importCellDouble( SequenceInputStream
& rStrm
, CellType eCellType
)
466 if( readCellHeader( rStrm
, eCellType
) )
468 maCellData
.mnCellType
= XML_n
;
469 double fValue
= rStrm
.readDouble();
470 if( eCellType
== CELLTYPE_FORMULA
)
471 mrSheetData
.setFormulaCell( maCellData
, readCellFormula( rStrm
) );
473 mrSheetData
.setValueCell( maCellData
, fValue
);
477 void SheetDataContext::importCellError( SequenceInputStream
& rStrm
, CellType eCellType
)
479 if( readCellHeader( rStrm
, eCellType
) )
481 maCellData
.mnCellType
= XML_e
;
482 sal_uInt8 nErrorCode
= rStrm
.readuInt8();
483 if( eCellType
== CELLTYPE_FORMULA
)
484 mrSheetData
.setFormulaCell( maCellData
, readCellFormula( rStrm
) );
486 mrSheetData
.setErrorCell( maCellData
, nErrorCode
);
490 void SheetDataContext::importCellRk( SequenceInputStream
& rStrm
, CellType eCellType
)
492 OSL_ENSURE( eCellType
!= CELLTYPE_FORMULA
, "SheetDataContext::importCellRk - no formula cells supported" );
493 if( readCellHeader( rStrm
, eCellType
) )
495 maCellData
.mnCellType
= XML_n
;
496 mrSheetData
.setValueCell( maCellData
, BiffHelper::calcDoubleFromRk( rStrm
.readInt32() ) );
500 void SheetDataContext::importCellRString( SequenceInputStream
& rStrm
, CellType eCellType
)
502 OSL_ENSURE( eCellType
!= CELLTYPE_FORMULA
, "SheetDataContext::importCellRString - no formula cells supported" );
503 if( readCellHeader( rStrm
, eCellType
) )
505 maCellData
.mnCellType
= XML_inlineStr
;
506 RichStringRef
xString( new RichString( *this ) );
507 xString
->importString( rStrm
, true );
508 xString
->finalizeImport();
509 mrSheetData
.setStringCell( maCellData
, xString
);
513 void SheetDataContext::importCellSi( SequenceInputStream
& rStrm
, CellType eCellType
)
515 OSL_ENSURE( eCellType
!= CELLTYPE_FORMULA
, "SheetDataContext::importCellSi - no formula cells supported" );
516 if( readCellHeader( rStrm
, eCellType
) )
518 maCellData
.mnCellType
= XML_s
;
519 mrSheetData
.setStringCell( maCellData
, rStrm
.readInt32() );
523 void SheetDataContext::importCellString( SequenceInputStream
& rStrm
, CellType eCellType
)
525 if( readCellHeader( rStrm
, eCellType
) )
527 maCellData
.mnCellType
= XML_inlineStr
;
528 // always import the string, stream will point to formula afterwards, if existing
529 RichStringRef
xString( new RichString( *this ) );
530 xString
->importString( rStrm
, false );
531 xString
->finalizeImport();
532 if( eCellType
== CELLTYPE_FORMULA
)
533 mrSheetData
.setFormulaCell( maCellData
, readCellFormula( rStrm
) );
535 mrSheetData
.setStringCell( maCellData
, xString
);
539 void SheetDataContext::importArray( SequenceInputStream
& rStrm
)
541 if( readFormulaRef( rStrm
) && maFmlaData
.isValidArrayRef( maCellData
.maCellAddr
) )
544 ApiTokenSequence aTokens
= mxFormulaParser
->importFormula( maCellData
.maCellAddr
, FORMULATYPE_ARRAY
, rStrm
);
545 mrSheetData
.createArrayFormula( maFmlaData
.maFormulaRef
, aTokens
);
549 void SheetDataContext::importDataTable( SequenceInputStream
& rStrm
)
551 if( readFormulaRef( rStrm
) )
553 BinAddress aRef1
, aRef2
;
555 rStrm
>> aRef1
>> aRef2
;
556 nFlags
= rStrm
.readuChar();
557 maTableData
.maRef1
= FormulaProcessorBase::generateAddress2dString( aRef1
, false );
558 maTableData
.maRef2
= FormulaProcessorBase::generateAddress2dString( aRef2
, false );
559 maTableData
.mbRowTable
= getFlag( nFlags
, BIFF12_DATATABLE_ROW
);
560 maTableData
.mb2dTable
= getFlag( nFlags
, BIFF12_DATATABLE_2D
);
561 maTableData
.mbRef1Deleted
= getFlag( nFlags
, BIFF12_DATATABLE_REF1DEL
);
562 maTableData
.mbRef2Deleted
= getFlag( nFlags
, BIFF12_DATATABLE_REF2DEL
);
563 mrSheetData
.createTableOperation( maFmlaData
.maFormulaRef
, maTableData
);
567 void SheetDataContext::importSharedFmla( SequenceInputStream
& rStrm
)
569 if( readFormulaRef( rStrm
) && maFmlaData
.isValidSharedRef( maCellData
.maCellAddr
) )
571 ApiTokenSequence aTokens
= mxFormulaParser
->importFormula( maCellData
.maCellAddr
, FORMULATYPE_SHAREDFORMULA
, rStrm
);
572 mrSheetData
.createSharedFormula( maCellData
.maCellAddr
, aTokens
);
579 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */