diff options
author | Daniel Rentz [dr] <daniel.rentz@oracle.com> | 2011-02-11 16:11:43 +0100 |
---|---|---|
committer | Daniel Rentz [dr] <daniel.rentz@oracle.com> | 2011-02-11 16:11:43 +0100 |
commit | f042519085109581abcdff4403e7e6d9999d4980 (patch) | |
tree | d3f22e98804fa22c88b62d7ea42553a32df09230 | |
parent | aec1b58b2f959770f072778ec187ae89f6053b76 (diff) |
dr78: #164376# oox import performance: step 2 - move every access to XCell interface into SheetDataBuffer class, delay creation of array formulas and table operations, let XCellRangeData::setDataArray() accept formula token sequences in addition to plain values
-rw-r--r-- | oox/inc/oox/xls/defnamesbuffer.hxx | 6 | ||||
-rwxr-xr-x | oox/inc/oox/xls/sheetdatabuffer.hxx | 133 | ||||
-rw-r--r-- | oox/inc/oox/xls/sheetdatacontext.hxx | 84 | ||||
-rw-r--r-- | oox/inc/oox/xls/worksheethelper.hxx | 47 | ||||
-rw-r--r-- | oox/source/xls/defnamesbuffer.cxx | 22 | ||||
-rw-r--r-- | oox/source/xls/externallinkbuffer.cxx | 5 | ||||
-rw-r--r-- | oox/source/xls/pivotcachebuffer.cxx | 18 | ||||
-rwxr-xr-x | oox/source/xls/sheetdatabuffer.cxx | 410 | ||||
-rw-r--r-- | oox/source/xls/sheetdatacontext.cxx | 789 | ||||
-rw-r--r-- | oox/source/xls/worksheethelper.cxx | 43 |
10 files changed, 771 insertions, 786 deletions
diff --git a/oox/inc/oox/xls/defnamesbuffer.hxx b/oox/inc/oox/xls/defnamesbuffer.hxx index 27f9f13f6e87..f26a51a1f04c 100644 --- a/oox/inc/oox/xls/defnamesbuffer.hxx +++ b/oox/inc/oox/xls/defnamesbuffer.hxx @@ -94,11 +94,11 @@ public: protected: /** Converts the OOXML formula string stored in the own model. */ - ApiTokenSequence importOoxFormula( const ::com::sun::star::table::CellAddress& rBaseAddr ); + ApiTokenSequence importOoxFormula( sal_Int16 nBaseSheet ); /** Imports the BIFF12 formula from the passed stream. */ - ApiTokenSequence importBiff12Formula( const ::com::sun::star::table::CellAddress& rBaseAddr, SequenceInputStream& rStrm ); + ApiTokenSequence importBiff12Formula( sal_Int16 nBaseSheet, SequenceInputStream& rStrm ); /** Imports the BIFF formula from the passed stream. */ - ApiTokenSequence importBiffFormula( const ::com::sun::star::table::CellAddress& rBaseAddr, BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize = 0 ); + ApiTokenSequence importBiffFormula( sal_Int16 nBaseSheet, BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize = 0 ); /** Tries to convert the passed token sequence to a SingleReference or ComplexReference. */ void extractReference( const ApiTokenSequence& rTokens ); diff --git a/oox/inc/oox/xls/sheetdatabuffer.hxx b/oox/inc/oox/xls/sheetdatabuffer.hxx index 52b71b4f0ef9..878d225ff81f 100755 --- a/oox/inc/oox/xls/sheetdatabuffer.hxx +++ b/oox/inc/oox/xls/sheetdatabuffer.hxx @@ -42,6 +42,53 @@ namespace xls { // ============================================================================ +/** Stores basic data about cell values and formatting. */ +struct CellModel +{ + ::com::sun::star::table::CellAddress + maCellAddr; /// The address of the current cell. + sal_Int32 mnCellType; /// Data type of the cell value. + sal_Int32 mnXfId; /// XF (cell formatting) identifier. + bool mbShowPhonetic; /// True = show phonetic text. + + explicit CellModel(); +}; + +// ---------------------------------------------------------------------------- + +/** Stores data about cell formulas. */ +struct CellFormulaModel +{ + ::com::sun::star::table::CellRangeAddress + maFormulaRef; /// Formula range for array/shared formulas and data tables. + sal_Int32 mnFormulaType; /// Type of the formula (regular, array, shared, table). + sal_Int32 mnSharedId; /// Identifier of a shared formula (OOXML only). + + explicit CellFormulaModel(); + + /** Returns true, if the passed cell address is valid for an array formula. */ + bool isValidArrayRef( const ::com::sun::star::table::CellAddress& rCellAddr ); + /** Returns true, if the passed cell address is valid for a shared formula. */ + bool isValidSharedRef( const ::com::sun::star::table::CellAddress& rCellAddr ); +}; + +// ---------------------------------------------------------------------------- + +/** Stores data about table operations. */ +struct DataTableModel +{ + ::rtl::OUString maRef1; /// First reference cell for table operations. + ::rtl::OUString maRef2; /// Second reference cell for table operations. + bool mb2dTable; /// True = 2-dimensional data table. + bool mbRowTable; /// True = row oriented data table. + bool mbRef1Deleted; /// True = first reference cell deleted. + bool mbRef2Deleted; /// True = second reference cell deleted. + + explicit DataTableModel(); +}; + +// ============================================================================ + /** Manages the cell contents and cell formatting of a sheet. */ class SheetDataBuffer : public WorksheetHelper @@ -49,81 +96,71 @@ class SheetDataBuffer : public WorksheetHelper public: explicit SheetDataBuffer( const WorksheetHelper& rHelper ); - /** Imports a shared formula from a OOXML formula string. */ - void importSharedFmla( const ::rtl::OUString& rFormula, - const ::rtl::OUString& rSharedRange, sal_Int32 nSharedId, - const ::com::sun::star::table::CellAddress& rBaseAddr ); - /** Imports a shared formula from a SHAREDFORMULA record in the passed stream */ - void importSharedFmla( SequenceInputStream& rStrm, - const ::com::sun::star::table::CellAddress& rBaseAddr ); - /** Imports a shared formula from a SHAREDFMLA record in the passed stream. */ - void importSharedFmla( BiffInputStream& rStrm, - const ::com::sun::star::table::CellAddress& rBaseAddr ); - /** Sets the passed value to the cell. */ void setValueCell( - const ::com::sun::star::uno::Reference< ::com::sun::star::table::XCell >& rxCell, const ::com::sun::star::table::CellAddress& rCellAddr, double fValue ); /** Sets the passed string to the cell. */ void setStringCell( - const ::com::sun::star::uno::Reference< ::com::sun::star::table::XCell >& rxCell, const ::com::sun::star::table::CellAddress& rCellAddr, const ::rtl::OUString& rText ); /** Sets the passed rich-string to the cell. */ void setStringCell( - const ::com::sun::star::uno::Reference< ::com::sun::star::table::XCell >& rxCell, const ::com::sun::star::table::CellAddress& rCellAddr, const RichString& rString, sal_Int32 nXfId ); /** Sets the shared string with the passed identifier to the cell. */ void setStringCell( - const ::com::sun::star::uno::Reference< ::com::sun::star::table::XCell >& rxCell, const ::com::sun::star::table::CellAddress& rCellAddr, sal_Int32 nStringId, sal_Int32 nXfId ); /** Sets the passed date/time value to the cell and adjusts number format. */ void setDateTimeCell( - const ::com::sun::star::uno::Reference< ::com::sun::star::table::XCell >& rxCell, const ::com::sun::star::table::CellAddress& rCellAddr, const ::com::sun::star::util::DateTime& rDateTime ); /** Sets the passed boolean value to the cell and adjusts number format. */ void setBooleanCell( - const ::com::sun::star::uno::Reference< ::com::sun::star::table::XCell >& rxCell, const ::com::sun::star::table::CellAddress& rCellAddr, bool bValue ); /** Sets the passed BIFF error code to the cell (by converting it to a formula). */ void setErrorCell( - const ::com::sun::star::uno::Reference< ::com::sun::star::table::XCell >& rxCell, const ::com::sun::star::table::CellAddress& rCellAddr, const ::rtl::OUString& rErrorCode ); /** Sets the passed BIFF error code to the cell (by converting it to a formula). */ void setErrorCell( - const ::com::sun::star::uno::Reference< ::com::sun::star::table::XCell >& rxCell, const ::com::sun::star::table::CellAddress& rCellAddr, sal_uInt8 nErrorCode ); /** Sets the passed formula token sequence to the cell. */ void setFormulaCell( - const ::com::sun::star::uno::Reference< ::com::sun::star::table::XCell >& rxCell, const ::com::sun::star::table::CellAddress& rCellAddr, const ApiTokenSequence& rTokens ); /** Sets the shared formula with the passed identifier to the cell (OOXML only). */ void setFormulaCell( - const ::com::sun::star::uno::Reference< ::com::sun::star::table::XCell >& rxCell, const ::com::sun::star::table::CellAddress& rCellAddr, sal_Int32 nSharedId ); /** Inserts the passed token array as array formula. */ - void setArrayFormula( + void createArrayFormula( const ::com::sun::star::table::CellRangeAddress& rRange, const ApiTokenSequence& rTokens ); /** Sets a multiple table operation to the passed range. */ - void setTableOperation( + void createTableOperation( const ::com::sun::star::table::CellRangeAddress& rRange, const DataTableModel& rModel ); + /** Creates a named range with a special name for a shared formula with the + specified identifier and formula definition (OOXML only). */ + void createSharedFormula( + sal_Int32 nSharedId, + const ApiTokenSequence& rTokens ); + /** Creates a named range with a special name for a shared formula with the + specified base address and formula definition (BIFF only). */ + void createSharedFormula( + const ::com::sun::star::table::CellAddress& rCellAddr, + const ApiTokenSequence& rTokens ); /** Sets default cell formatting for the specified range of rows. */ void setRowFormat( sal_Int32 nFirstRow, sal_Int32 nLastRow, sal_Int32 nXfId, bool bCustomFormat ); - /** Processes the cell formatting data of the passed cell. */ - void setCellFormat( const CellModel& rModel ); + /** Processes the cell formatting data of the passed cell. + @param nNumFmtId If set, overrides number format of the cell XF. */ + void setCellFormat( const CellModel& rModel, sal_Int32 nNumFmtId = -1 ); /** Merges the cells in the passed cell range. */ void setMergedRange( const ::com::sun::star::table::CellRangeAddress& rRange ); /** Sets a standard number format (constant from com.sun.star.util.NumberFormat) to the specified cell. */ @@ -138,21 +175,21 @@ private: struct XfIdRowRange; struct XfIdRange; - /** Creates and returns an empty named range with a special name for a - shared formula with the specified base position. */ - ::com::sun::star::uno::Reference< ::com::sun::star::sheet::XNamedRange > - createSharedFormulaName( const BinAddress& rMapKey ); + /** Inserts the passed array formula into the sheet. */ + void finalizeArrayFormula( + const ::com::sun::star::table::CellRangeAddress& rRange, + const ApiTokenSequence& rTokens ); + /** Inserts the passed table operation into the sheet. */ + void finalizeTableOperation( + const ::com::sun::star::table::CellRangeAddress& rRange, + const DataTableModel& rModel ); + /** Creates a named range with a special name for a shared formula with the + specified base address and formula definition. */ + void createSharedFormula( const BinAddress& rMapKey, const ApiTokenSequence& rTokens ); /** Creates a formula token array representing the shared formula with the - passed identifier (OOXML only). */ - ApiTokenSequence resolveSharedFormula( sal_Int32 nSharedId ) const; - /** Creates a formula token array representing the shared formula at the - passed base address. */ - ApiTokenSequence resolveSharedFormula( const ::com::sun::star::table::CellAddress& rBaseAddr ) const; - - /** Retries to insert a shared formula that has not been set in the last - call to setFormulaCell() due to the missing formula definition. */ - void retryPendingSharedFormulaCell(); + passed identifier. */ + ApiTokenSequence resolveSharedFormula( const BinAddress& rMapKey ) const; /** Writes all cell formatting attributes to the passed row range. */ void writeXfIdRowRangeProperties( const XfIdRowRange& rXfIdRowRange ) const; @@ -165,6 +202,9 @@ private: void finalizeMergedRange( const ::com::sun::star::table::CellRangeAddress& rRange ); private: + typedef ::std::pair< ::com::sun::star::table::CellRangeAddress, ApiTokenSequence > ArrayFormula; + typedef ::std::pair< ::com::sun::star::table::CellRangeAddress, DataTableModel > TableOperation; + struct XfIdRowRange { sal_Int32 mnFirstRow; /// Index of first row. @@ -182,10 +222,10 @@ private: ::com::sun::star::table::CellRangeAddress maRange; /// The formatted cell range. sal_Int32 mnXfId; /// XF identifier for the range. - sal_Int32 mnNumFmtId; /// Number format id overriding the XF. + sal_Int32 mnNumFmtId; /// Number format overriding the XF. - void set( const CellModel& rModel ); - bool tryExpand( const CellModel& rModel ); + void set( const CellModel& rModel, sal_Int32 nNumFmtId ); + bool tryExpand( const CellModel& rModel, sal_Int32 nNumFmtId ); bool tryMerge( const XfIdRange& rXfIdRange ); }; @@ -200,15 +240,18 @@ private: bool tryExpand( const ::com::sun::star::table::CellAddress& rAddress, sal_Int32 nHorAlign ); }; - typedef ::std::map< BinAddress, sal_Int32 > TokenIndexMap; + typedef ::std::list< ArrayFormula > ArrayFormulaList; + typedef ::std::list< TableOperation > TableOperationList; + typedef ::std::map< BinAddress, sal_Int32 > SharedFormulaMap; typedef ::std::map< BinAddress, XfIdRange > XfIdRangeMap; typedef ::std::list< MergedRange > MergedRangeList; - TokenIndexMap maTokenIndexes; /// Maps shared formula base address to defined name token index. + ArrayFormulaList maArrayFormulas; /// All array formulas in the sheet. + TableOperationList maTableOperations; /// All table operations in the sheet. + SharedFormulaMap maSharedFormulas; /// Maps shared formula base address to defined name token index. ::com::sun::star::table::CellAddress maSharedFmlaAddr; /// Address of a cell containing a pending shared formula. - ::com::sun::star::table::CellAddress - maSharedBaseAddr; /// Base address of the pending shared formula. + BinAddress maSharedBaseAddr; /// Base address of the pending shared formula. XfIdRowRange maXfIdRowRange; /// Cached XF identifier for a range of rows. XfIdRangeMap maXfIdRanges; /// Collected XF identifiers for cell ranges. MergedRangeList maMergedRanges; /// Merged cell ranges. diff --git a/oox/inc/oox/xls/sheetdatacontext.hxx b/oox/inc/oox/xls/sheetdatacontext.hxx index c01106228c72..60948ab9f70d 100644 --- a/oox/inc/oox/xls/sheetdatacontext.hxx +++ b/oox/inc/oox/xls/sheetdatacontext.hxx @@ -30,22 +30,37 @@ #include "oox/xls/excelhandlers.hxx" #include "oox/xls/richstring.hxx" - -namespace com { namespace sun { namespace star { - namespace table { class XCell; } -} } } +#include "oox/xls/sheetdatabuffer.hxx" namespace oox { namespace xls { // ============================================================================ +/** Used as base for sheet data context classes. Provides fast access to often + used converter objects and sheet index, to improve performance. + */ +struct SheetDataContextBase +{ + AddressConverter& mrAddressConv; /// The address converter. + FormulaParser& mrFormulaParser; /// The formula parser. + SheetDataBuffer& mrSheetData; /// The sheet data buffer for cell content and formatting. + CellModel maCellData; /// Position, contents, formatting of current imported cell. + CellFormulaModel maFmlaData; /// Settings for a cell formula. + sal_Int16 mnSheet; /// Index of the current sheet. + + explicit SheetDataContextBase( const WorksheetHelper& rHelper ); + virtual ~SheetDataContextBase(); +}; + +// ============================================================================ + /** This class implements importing the sheetData element. The sheetData element contains all row settings and all cells in a single sheet of a spreadsheet document. */ -class SheetDataContext : public WorksheetContextBase +class SheetDataContext : public WorksheetContextBase, private SheetDataContextBase { public: explicit SheetDataContext( WorksheetFragmentBase& rFragment ); @@ -64,12 +79,20 @@ private: /** Imports row settings from a row element. */ void importRow( const AttributeList& rAttribs ); /** Imports cell settings from a c element. */ - void importCell( const AttributeList& rAttribs ); + bool importCell( const AttributeList& rAttribs ); /** Imports cell settings from an f element. */ void importFormula( const AttributeList& rAttribs ); - /** Imports a cell address and the following XF identifier. */ - void importCellHeader( SequenceInputStream& rStrm, CellType eCellType ); + /** Imports row settings from a ROW record. */ + void importRow( SequenceInputStream& rStrm ); + + /** Reads a cell address and the following XF identifier. */ + bool readCellHeader( SequenceInputStream& rStrm, CellType eCellType ); + /** Reads a cell formula for the current cell. */ + ApiTokenSequence readCellFormula( SequenceInputStream& rStrm ); + /** Reads the formula range used by shared formulas, arrays, and data tables. */ + bool readFormulaRef( SequenceInputStream& rStrm ); + /** Imports an empty cell from a CELL_BLANK or MULTCELL_BLANK record. */ void importCellBlank( SequenceInputStream& rStrm, CellType eCellType ); /** Imports a boolean cell from a CELL_BOOL, MULTCELL_BOOL, or FORMULA_BOOL record. */ @@ -87,31 +110,28 @@ private: /** Imports a string cell from a CELL_STRING, MULTCELL_STRING, or FORMULA_STRING record. */ void importCellString( SequenceInputStream& rStrm, CellType eCellType ); - /** Imports a cell formula for the current cell. */ - void importCellFormula( SequenceInputStream& rStrm ); - - /** Imports row settings from a ROW record. */ - void importRow( SequenceInputStream& rStrm ); /** Imports an array formula from an ARRAY record. */ void importArray( SequenceInputStream& rStrm ); - /** Imports a shared formula from a SHAREDFORMULA record. */ - void importSharedFmla( SequenceInputStream& rStrm ); /** Imports table operation from a DATATABLE record. */ void importDataTable( SequenceInputStream& rStrm ); + /** Imports a shared formula from a SHAREDFORMULA record. */ + void importSharedFmla( SequenceInputStream& rStrm ); private: - SheetDataBuffer& mrSheetData; /// The sheet data buffer for cell content and formatting. - CellModel maCurrCell; /// Position and formatting of current imported cell. - DataTableModel maTableData; /// Additional data for table operation ranges. - BinAddress maCurrPos; /// Current position for binary import. - RichStringRef mxInlineStr; /// Inline rich string from 'is' element. + ::rtl::OUString maCellValue; /// Cell value string (OOXML only). + RichStringRef mxInlineStr; /// Inline rich string (OOXML only). + ApiTokenSequence maTokens; /// Formula token array (OOXML only). + DataTableModel maTableData; /// Settings for table operations. + BinAddress maCurrPos; /// Current cell position (BIFF12 only). + bool mbHasFormula; /// True = current cell has formula data (OOXML only). + bool mbValidRange; /// True = maFmlaData.maFormulaRef is valid (OOXML only). }; // ============================================================================ /** This class implements importing row settings and all cells of a sheet. */ -class BiffSheetDataContext : public BiffWorksheetContextBase +class BiffSheetDataContext : public BiffWorksheetContextBase, private SheetDataContextBase { public: explicit BiffSheetDataContext( const WorksheetHelper& rHelper ); @@ -120,13 +140,15 @@ public: virtual void importRecord( BiffInputStream& rStrm ); private: - /** Sets current cell according to the passed address. */ - void setCurrCell( const BinAddress& rAddr ); + /** Imports row settings from a ROW record. */ + void importRow( BiffInputStream& rStrm ); - /** Imports an XF identifier and sets the mnXfId member. */ - void importXfId( BiffInputStream& rStrm, bool bBiff2 ); - /** Imports a BIFF cell address and the following XF identifier. */ - void importCellHeader( BiffInputStream& rStrm, bool bBiff2 ); + /** Reads an XF identifier and initializes a new cell. */ + bool readCellXfId( const BinAddress& rAddr, BiffInputStream& rStrm, bool bBiff2 ); + /** Reads a BIFF cell address and the following XF identifier. */ + bool readCellHeader( BiffInputStream& rStrm, bool bBiff2 ); + /** Reads the formula range used by shared formulas, arrays, and data tables. */ + bool readFormulaRef( BiffInputStream& rStrm ); /** Imports a BLANK record describing a blank but formatted cell. */ void importBlank( BiffInputStream& rStrm ); @@ -149,18 +171,14 @@ private: /** Imports an RK record describing a numeric cell. */ void importRk( BiffInputStream& rStrm ); - /** Imports row settings from a ROW record. */ - void importRow( BiffInputStream& rStrm ); /** Imports an ARRAY record describing an array formula of a cell range. */ void importArray( BiffInputStream& rStrm ); - /** Imports a SHAREDFMLA record describing a shared formula in a cell range. */ - void importSharedFmla( BiffInputStream& rStrm ); /** Imports table operation from a DATATABLE or DATATABLE2 record. */ void importDataTable( BiffInputStream& rStrm ); + /** Imports a SHAREDFMLA record describing a shared formula in a cell range. */ + void importSharedFmla( BiffInputStream& rStrm ); private: - SheetDataBuffer& mrSheetData; /// The sheet data buffer for cell content and formatting. - CellModel maCurrCell; /// Position and formatting of current imported cell. sal_uInt32 mnFormulaSkipSize; /// Number of bytes to be ignored in FORMULA record. sal_uInt32 mnArraySkipSize; /// Number of bytes to be ignored in ARRAY record. sal_uInt16 mnBiff2XfId; /// Current XF identifier from IXFE record. diff --git a/oox/inc/oox/xls/worksheethelper.hxx b/oox/inc/oox/xls/worksheethelper.hxx index fe788be852cb..27754c898608 100644 --- a/oox/inc/oox/xls/worksheethelper.hxx +++ b/oox/inc/oox/xls/worksheethelper.hxx @@ -80,42 +80,6 @@ enum WorksheetType // ============================================================================ -/** Stores some data about a cell. */ -struct CellModel -{ - ::com::sun::star::uno::Reference< ::com::sun::star::table::XCell > mxCell; - ::com::sun::star::table::CellAddress maAddress; - ::rtl::OUString maValue; /// String containing cell value data. - ::rtl::OUString maFormula; /// String containing the formula definition. - ::rtl::OUString maFormulaRef; /// String containing formula range for array/shared formulas. - sal_Int32 mnCellType; /// Data type of the cell value. - sal_Int32 mnFormulaType; /// Type of the formula (regular, array, shared, table). - sal_Int32 mnSharedId; /// Shared formula identifier. - sal_Int32 mnXfId; /// XF (cell formatting) identifier. - sal_Int32 mnNumFmtId; /// Forced number format (overrides XF if set). - bool mbShowPhonetic; /// True = show phonetic text. - - inline explicit CellModel() { reset(); } - void reset(); -}; - -// ---------------------------------------------------------------------------- - -/** Stores data about a data table a.k.a. multiple operation range. */ -struct DataTableModel -{ - ::rtl::OUString maRef1; /// String containing first reference cell for data table formulas. - ::rtl::OUString maRef2; /// String containing second reference cell for data table formulas. - bool mb2dTable; /// True = 2-dimensional data table. - bool mbRowTable; /// True = row oriented data table. - bool mbRef1Deleted; /// True = first reference cell deleted. - bool mbRef2Deleted; /// True = second reference cell deleted. - - explicit DataTableModel(); -}; - -// ---------------------------------------------------------------------------- - /** Stores formatting data about a range of columns. */ struct ColumnModel { @@ -243,17 +207,6 @@ public: /** Returns the XCell interface for the passed cell address. */ ::com::sun::star::uno::Reference< ::com::sun::star::table::XCell > getCell( const ::com::sun::star::table::CellAddress& rAddress ) const; - /** Returns the XCell interface for the passed cell address string. */ - ::com::sun::star::uno::Reference< ::com::sun::star::table::XCell > - getCell( - const ::rtl::OUString& rAddressStr, - ::com::sun::star::table::CellAddress* opAddress = 0 ) const; - /** Returns the XCell interface for the passed cell address. */ - ::com::sun::star::uno::Reference< ::com::sun::star::table::XCell > - getCell( - const BinAddress& rBinAddress, - ::com::sun::star::table::CellAddress* opAddress = 0 ) const; - /** Returns the XCellRange interface for the passed cell range address. */ ::com::sun::star::uno::Reference< ::com::sun::star::table::XCellRange > getCellRange( const ::com::sun::star::table::CellRangeAddress& rRange ) const; diff --git a/oox/source/xls/defnamesbuffer.cxx b/oox/source/xls/defnamesbuffer.cxx index 335aae5273af..e69cc44c8a1d 100644 --- a/oox/source/xls/defnamesbuffer.cxx +++ b/oox/source/xls/defnamesbuffer.cxx @@ -276,22 +276,22 @@ Any DefinedNameBase::getReference( const CellAddress& rBaseAddr ) const return Any(); } -ApiTokenSequence DefinedNameBase::importOoxFormula( const CellAddress& rBaseAddr ) +ApiTokenSequence DefinedNameBase::importOoxFormula( sal_Int16 nBaseSheet ) { return (maModel.maFormula.getLength() > 0) ? - getFormulaParser().importFormula( rBaseAddr, maModel.maFormula ) : + getFormulaParser().importFormula( CellAddress( nBaseSheet, 0, 0 ), maModel.maFormula ) : getFormulaParser().convertErrorToFormula( BIFF_ERR_NAME ); } -ApiTokenSequence DefinedNameBase::importBiff12Formula( const CellAddress& rBaseAddr, SequenceInputStream& rStrm ) +ApiTokenSequence DefinedNameBase::importBiff12Formula( sal_Int16 nBaseSheet, SequenceInputStream& rStrm ) { - return getFormulaParser().importFormula( rBaseAddr, FORMULATYPE_DEFINEDNAME, rStrm ); + return getFormulaParser().importFormula( CellAddress( nBaseSheet, 0, 0 ), FORMULATYPE_DEFINEDNAME, rStrm ); } -ApiTokenSequence DefinedNameBase::importBiffFormula( const CellAddress& rBaseAddr, BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize ) +ApiTokenSequence DefinedNameBase::importBiffFormula( sal_Int16 nBaseSheet, BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize ) { return (!pnFmlaSize || (*pnFmlaSize > 0)) ? - getFormulaParser().importFormula( rBaseAddr, FORMULATYPE_DEFINEDNAME, rStrm, pnFmlaSize ) : + getFormulaParser().importFormula( CellAddress( nBaseSheet, 0, 0 ), FORMULATYPE_DEFINEDNAME, rStrm, pnFmlaSize ) : getFormulaParser().convertErrorToFormula( BIFF_ERR_NAME ); } @@ -460,8 +460,7 @@ void DefinedName::importDefinedName( BiffInputStream& rStrm, sal_Int16 nCalcShee these names contain a simple cell reference or range reference. Other regular defined names and external names rely on existence of this reference. */ - CellAddress aBaseAddr( mnCalcSheet, 0, 0 ); - ApiTokenSequence aTokens = importBiffFormula( aBaseAddr, rStrm, &mnFmlaSize ); + ApiTokenSequence aTokens = importBiffFormula( mnCalcSheet, rStrm, &mnFmlaSize ); extractReference( aTokens ); } else @@ -521,7 +520,6 @@ void DefinedName::convertFormula() // convert and set formula of the defined name ApiTokenSequence aTokens; - CellAddress aBaseAddr( mnCalcSheet, 0, 0 ); switch( getFilterType() ) { case FILTER_OOXML: @@ -529,10 +527,10 @@ void DefinedName::convertFormula() if( mxFormula.get() ) { SequenceInputStream aStrm( *mxFormula ); - aTokens = importBiff12Formula( aBaseAddr, aStrm ); + aTokens = importBiff12Formula( mnCalcSheet, aStrm ); } else - aTokens = importOoxFormula( aBaseAddr ); + aTokens = importOoxFormula( mnCalcSheet ); } break; case FILTER_BIFF: @@ -543,7 +541,7 @@ void DefinedName::convertFormula() BiffInputStream& rStrm = mxBiffStrm->getStream(); BiffInputStreamPosGuard aStrmGuard( rStrm ); if( mxBiffStrm->restorePosition() ) - aTokens = importBiffFormula( aBaseAddr, rStrm, &mnFmlaSize ); + aTokens = importBiffFormula( mnCalcSheet, rStrm, &mnFmlaSize ); } } break; diff --git a/oox/source/xls/externallinkbuffer.cxx b/oox/source/xls/externallinkbuffer.cxx index fe527f35f634..aa4d7a068530 100644 --- a/oox/source/xls/externallinkbuffer.cxx +++ b/oox/source/xls/externallinkbuffer.cxx @@ -242,8 +242,7 @@ void ExternalName::importExternalName( BiffInputStream& rStrm ) // cell references to other internal sheets are stored in hidden external names if( bHiddenRef && (getBiff() == BIFF4) && isWorkbookFile() ) { - CellAddress aBaseAddr( mrParentLink.getCalcSheetIndex(), 0, 0 ); - ApiTokenSequence aTokens = importBiffFormula( aBaseAddr, rStrm ); + ApiTokenSequence aTokens = importBiffFormula( mrParentLink.getCalcSheetIndex(), rStrm ); extractReference( aTokens ); } break; @@ -252,7 +251,7 @@ void ExternalName::importExternalName( BiffInputStream& rStrm ) // cell references to other documents are stored in hidden external names if( bHiddenRef ) { - ApiTokenSequence aTokens = importBiffFormula( CellAddress(), rStrm ); + ApiTokenSequence aTokens = importBiffFormula( 0, rStrm ); extractExternalReference( aTokens ); } break; diff --git a/oox/source/xls/pivotcachebuffer.cxx b/oox/source/xls/pivotcachebuffer.cxx index 88935a679c83..2c4d55b089f1 100644 --- a/oox/source/xls/pivotcachebuffer.cxx +++ b/oox/source/xls/pivotcachebuffer.cxx @@ -34,7 +34,6 @@ #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp> #include <com/sun/star/sheet/DataPilotFieldGroupInfo.hpp> #include <com/sun/star/sheet/XDataPilotFieldGrouping.hpp> -#include <com/sun/star/table/XCell.hpp> #include <rtl/ustrbuf.hxx> #include "oox/core/filterbase.hxx" #include "oox/helper/attributelist.hxx" @@ -938,7 +937,7 @@ OUString PivotCacheField::createParentGroupField( const Reference< XDataPilotFie void PivotCacheField::writeSourceHeaderCell( WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow ) const { CellAddress aCellAddr( rSheetHelper.getSheetIndex(), nCol, nRow ); - rSheetHelper.getSheetData().setStringCell( rSheetHelper.getCell( aCellAddr ), aCellAddr, maFieldModel.maName ); + rSheetHelper.getSheetData().setStringCell( aCellAddr, maFieldModel.maName ); } void PivotCacheField::writeSourceDataCell( WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow, const PivotCacheItem& rItem ) const @@ -986,15 +985,14 @@ void PivotCacheField::writeItemToSourceDataCell( WorksheetHelper& rSheetHelper, { CellAddress aCellAddr( rSheetHelper.getSheetIndex(), nCol, nRow ); SheetDataBuffer& rSheetData = rSheetHelper.getSheetData(); - Reference< XCell > xCell = rSheetHelper.getCell( aCellAddr ); - if( xCell.is() ) switch( rItem.getType() ) + switch( rItem.getType() ) { - case XML_s: rSheetData.setStringCell( xCell, aCellAddr, rItem.getValue().get< OUString >() ); break; - case XML_n: rSheetData.setValueCell( xCell, aCellAddr, rItem.getValue().get< double >() ); break; - case XML_i: rSheetData.setValueCell( xCell, aCellAddr, rItem.getValue().get< sal_Int16 >() ); break; - case XML_d: rSheetData.setDateTimeCell( xCell, aCellAddr, rItem.getValue().get< DateTime >() ); break; - case XML_b: rSheetData.setBooleanCell( xCell, aCellAddr, rItem.getValue().get< bool >() ); break; - case XML_e: rSheetData.setErrorCell( xCell, aCellAddr, static_cast< sal_uInt8 >( rItem.getValue().get< sal_Int32 >() ) ); break; + case XML_s: rSheetData.setStringCell( aCellAddr, rItem.getValue().get< OUString >() ); break; + case XML_n: rSheetData.setValueCell( aCellAddr, rItem.getValue().get< double >() ); break; + case XML_i: rSheetData.setValueCell( aCellAddr, rItem.getValue().get< sal_Int16 >() ); break; + case XML_d: rSheetData.setDateTimeCell( aCellAddr, rItem.getValue().get< DateTime >() ); break; + case XML_b: rSheetData.setBooleanCell( aCellAddr, rItem.getValue().get< bool >() ); break; + case XML_e: rSheetData.setErrorCell( aCellAddr, static_cast< sal_uInt8 >( rItem.getValue().get< sal_Int32 >() ) ); break; default: OSL_ENSURE( false, "PivotCacheField::writeItemToSourceDataCell - unexpected item data type" ); } } diff --git a/oox/source/xls/sheetdatabuffer.cxx b/oox/source/xls/sheetdatabuffer.cxx index e63e9fbb61b5..0cfe741cb135 100755 --- a/oox/source/xls/sheetdatabuffer.cxx +++ b/oox/source/xls/sheetdatabuffer.cxx @@ -29,6 +29,7 @@ #include <algorithm> #include <com/sun/star/sheet/XArrayFormulaTokens.hpp> +#include <com/sun/star/sheet/XCellRangeData.hpp> #include <com/sun/star/sheet/XFormulaTokens.hpp> #include <com/sun/star/sheet/XMultipleOperation.hpp> #include <com/sun/star/table/XCell.hpp> @@ -66,147 +67,116 @@ using ::rtl::OUStringBuffer; // ============================================================================ -namespace { - -bool lclContains( const CellRangeAddress& rRange, const CellAddress& rAddr ) +CellModel::CellModel() : + mnCellType( XML_TOKEN_INVALID ), + mnXfId( -1 ), + mbShowPhonetic( false ) { - return - (rRange.Sheet == rAddr.Sheet) && - (rRange.StartColumn <= rAddr.Column) && (rAddr.Column <= rRange.EndColumn) && - (rRange.StartRow <= rAddr.Row) && (rAddr.Row <= rRange.EndRow); } -} // namespace +// ---------------------------------------------------------------------------- -// ============================================================================ +CellFormulaModel::CellFormulaModel() : + mnFormulaType( XML_TOKEN_INVALID ), + mnSharedId( -1 ) +{ +} -SheetDataBuffer::SheetDataBuffer( const WorksheetHelper& rHelper ) : - WorksheetHelper( rHelper ), - mbPendingSharedFmla( false ) +bool CellFormulaModel::isValidArrayRef( const CellAddress& rCellAddr ) { + return + (maFormulaRef.Sheet == rCellAddr.Sheet) && + (maFormulaRef.StartColumn == rCellAddr.Column) && + (maFormulaRef.StartRow == rCellAddr.Row); } -void SheetDataBuffer::importSharedFmla( const OUString& rFormula, const OUString& rSharedRange, sal_Int32 nSharedId, const CellAddress& rBaseAddr ) +bool CellFormulaModel::isValidSharedRef( const CellAddress& rCellAddr ) { - CellRangeAddress aFmlaRange; - if( getAddressConverter().convertToCellRange( aFmlaRange, rSharedRange, getSheetIndex(), true, true ) ) try - { - // get or create the defined name representing the shared formula - OSL_ENSURE( lclContains( aFmlaRange, rBaseAddr ), "SheetDataBuffer::importSharedFmla - invalid range for shared formula" ); - Reference< XNamedRange > xNamedRange = createSharedFormulaName( BinAddress( nSharedId, 0 ) ); - Reference< XFormulaTokens > xTokens( xNamedRange, UNO_QUERY_THROW ); - // convert the formula definition - ApiTokenSequence aTokens = getFormulaParser().importFormula( rBaseAddr, rFormula ); - xTokens->setTokens( aTokens ); - // retry to insert a pending shared formula cell - retryPendingSharedFormulaCell(); - } - catch( Exception& ) - { - } + return + (maFormulaRef.Sheet == rCellAddr.Sheet) && + (maFormulaRef.StartColumn <= rCellAddr.Column) && (rCellAddr.Column <= maFormulaRef.EndColumn) && + (maFormulaRef.StartRow <= rCellAddr.Row) && (rCellAddr.Row <= maFormulaRef.EndRow); } -void SheetDataBuffer::importSharedFmla( SequenceInputStream& rStrm, const CellAddress& rBaseAddr ) +// ---------------------------------------------------------------------------- + +DataTableModel::DataTableModel() : + mb2dTable( false ), + mbRowTable( false ), + mbRef1Deleted( false ), + mbRef2Deleted( false ) { - BinRange aRange; - rStrm >> aRange; - CellRangeAddress aFmlaRange; - if( getAddressConverter().convertToCellRange( aFmlaRange, aRange, getSheetIndex(), true, true ) ) try - { - // get or create the defined name representing the shared formula - OSL_ENSURE( lclContains( aFmlaRange, rBaseAddr ), "SheetDataBuffer::importSharedFmla - invalid range for shared formula" ); - Reference< XNamedRange > xNamedRange = createSharedFormulaName( BinAddress( rBaseAddr ) ); - Reference< XFormulaTokens > xTokens( xNamedRange, UNO_QUERY_THROW ); - // load the formula definition - ApiTokenSequence aTokens = getFormulaParser().importFormula( rBaseAddr, FORMULATYPE_SHAREDFORMULA, rStrm ); - xTokens->setTokens( aTokens ); - // retry to insert a pending shared formula cell - retryPendingSharedFormulaCell(); - } - catch( Exception& ) - { - } } -void SheetDataBuffer::importSharedFmla( BiffInputStream& rStrm, const CellAddress& rBaseAddr ) +// ============================================================================ + +SheetDataBuffer::SheetDataBuffer( const WorksheetHelper& rHelper ) : + WorksheetHelper( rHelper ), + mbPendingSharedFmla( false ) { - BinRange aRange; - aRange.read( rStrm, false ); // always 8bit column indexes - CellRangeAddress aFmlaRange; - if( getAddressConverter().convertToCellRange( aFmlaRange, aRange, getSheetIndex(), true, true ) ) try - { - // get or create the defined name representing the shared formula - OSL_ENSURE( lclContains( aFmlaRange, rBaseAddr ), "SheetDataBuffer::importSharedFmla - invalid range for shared formula" ); - Reference< XNamedRange > xNamedRange = createSharedFormulaName( BinAddress( rBaseAddr ) ); - Reference< XFormulaTokens > xTokens( xNamedRange, UNO_QUERY_THROW ); - // load the formula definition - rStrm.skip( 2 ); // flags - ApiTokenSequence aTokens = getFormulaParser().importFormula( rBaseAddr, FORMULATYPE_SHAREDFORMULA, rStrm ); - xTokens->setTokens( aTokens ); - // retry to insert a pending shared formula cell - retryPendingSharedFormulaCell(); - } - catch( Exception& ) - { - } } -void SheetDataBuffer::setValueCell( const Reference< XCell >& rxCell, const CellAddress& /*rCellAddr*/, double fValue ) +void SheetDataBuffer::setValueCell( const CellAddress& rCellAddr, double fValue ) { - OSL_ENSURE( rxCell.is(), "SheetDataBuffer::setDateTimeCell - missing cell interface" ); - if( rxCell.is() ) - rxCell->setValue( fValue ); + Reference< XCell > xCell = getCell( rCellAddr ); + OSL_ENSURE( xCell.is(), "SheetDataBuffer::setValueCell - missing cell interface" ); + if( xCell.is() ) + xCell->setValue( fValue ); } -void SheetDataBuffer::setStringCell( const Reference< XCell >& rxCell, const CellAddress& /*rCellAddr*/, const OUString& rText ) +void SheetDataBuffer::setStringCell( const CellAddress& rCellAddr, const OUString& rText ) { - Reference< XText > xText( rxCell, UNO_QUERY ); + Reference< XText > xText( getCell( rCellAddr ), UNO_QUERY ); OSL_ENSURE( xText.is(), "SheetDataBuffer::setStringCell - missing text interface" ); if( xText.is() ) xText->setString( rText ); } -void SheetDataBuffer::setStringCell( const Reference< XCell >& rxCell, const CellAddress& /*rCellAddr*/, const RichString& rString, sal_Int32 nXfId ) +void SheetDataBuffer::setStringCell( const CellAddress& rCellAddr, const RichString& rString, sal_Int32 nXfId ) { - Reference< XText > xText( rxCell, UNO_QUERY ); + Reference< XText > xText( getCell( rCellAddr ), UNO_QUERY ); OSL_ENSURE( xText.is(), "SheetDataBuffer::setStringCell - missing text interface" ); rString.convert( xText, nXfId ); + (void)rString; + (void)nXfId; } -void SheetDataBuffer::setStringCell( const Reference< XCell >& rxCell, const CellAddress& /*rCellAddr*/, sal_Int32 nStringId, sal_Int32 nXfId ) +void SheetDataBuffer::setStringCell( const CellAddress& rCellAddr, sal_Int32 nStringId, sal_Int32 nXfId ) { - Reference< XText > xText( rxCell, UNO_QUERY ); + Reference< XText > xText( getCell( rCellAddr ), UNO_QUERY ); OSL_ENSURE( xText.is(), "SheetDataBuffer::setStringCell - missing text interface" ); getSharedStrings().convertString( xText, nStringId, nXfId ); + (void)nStringId; + (void)nXfId; } -void SheetDataBuffer::setDateTimeCell( const Reference< XCell >& rxCell, const CellAddress& rCellAddr, const DateTime& rDateTime ) +void SheetDataBuffer::setDateTimeCell( const CellAddress& rCellAddr, const DateTime& rDateTime ) { // write serial date/time value into the cell double fSerial = getUnitConverter().calcSerialFromDateTime( rDateTime ); - setValueCell( rxCell, rCellAddr, fSerial ); + setValueCell( rCellAddr, fSerial ); // set appropriate number format using namespace ::com::sun::star::util::NumberFormat; sal_Int16 nStdFmt = (fSerial < 1.0) ? TIME : (((rDateTime.Hours > 0) || (rDateTime.Minutes > 0) || (rDateTime.Seconds > 0)) ? DATETIME : DATE); setStandardNumFmt( rCellAddr, nStdFmt ); } -void SheetDataBuffer::setBooleanCell( const Reference< XCell >& rxCell, const CellAddress& rCellAddr, bool bValue ) +void SheetDataBuffer::setBooleanCell( const CellAddress& rCellAddr, bool bValue ) { - setFormulaCell( rxCell, rCellAddr, getFormulaParser().convertBoolToFormula( bValue ) ); + setFormulaCell( rCellAddr, getFormulaParser().convertBoolToFormula( bValue ) ); } -void SheetDataBuffer::setErrorCell( const Reference< XCell >& rxCell, const CellAddress& rCellAddr, const OUString& rErrorCode ) +void SheetDataBuffer::setErrorCell( const CellAddress& rCellAddr, const OUString& rErrorCode ) { - setErrorCell( rxCell, rCellAddr, getUnitConverter().calcBiffErrorCode( rErrorCode ) ); + setErrorCell( rCellAddr, getUnitConverter().calcBiffErrorCode( rErrorCode ) ); } -void SheetDataBuffer::setErrorCell( const Reference< XCell >& rxCell, const CellAddress& rCellAddr, sal_uInt8 nErrorCode ) +void SheetDataBuffer::setErrorCell( const CellAddress& rCellAddr, sal_uInt8 nErrorCode ) { - setFormulaCell( rxCell, rCellAddr, getFormulaParser().convertErrorToFormula( nErrorCode ) ); + setFormulaCell( rCellAddr, getFormulaParser().convertErrorToFormula( nErrorCode ) ); } -void SheetDataBuffer::setFormulaCell( const Reference< XCell >& rxCell, const CellAddress& rCellAddr, const ApiTokenSequence& rTokens ) +void SheetDataBuffer::setFormulaCell( const CellAddress& rCellAddr, const ApiTokenSequence& rTokens ) { mbPendingSharedFmla = false; ApiTokenSequence aTokens; @@ -234,11 +204,12 @@ void SheetDataBuffer::setFormulaCell( const Reference< XCell >& rxCell, const Ce array formula. In this case, the cell will be remembered. After reading the formula definition it will be retried to insert the formula via retryPendingSharedFormulaCell(). */ - aTokens = resolveSharedFormula( aTokenInfo.First ); + BinAddress aBaseAddr( aTokenInfo.First ); + aTokens = resolveSharedFormula( aBaseAddr ); if( !aTokens.hasElements() ) { maSharedFmlaAddr = rCellAddr; - maSharedBaseAddr = aTokenInfo.First; + maSharedBaseAddr = aBaseAddr; mbPendingSharedFmla = true; } } @@ -251,89 +222,42 @@ void SheetDataBuffer::setFormulaCell( const Reference< XCell >& rxCell, const Ce if( aTokens.hasElements() ) { - Reference< XFormulaTokens > xTokens( rxCell, UNO_QUERY ); + Reference< XFormulaTokens > xTokens( getCell( rCellAddr ), UNO_QUERY ); OSL_ENSURE( xTokens.is(), "SheetDataBuffer::setFormulaCell - missing formula interface" ); if( xTokens.is() ) xTokens->setTokens( aTokens ); } } -void SheetDataBuffer::setFormulaCell( const Reference< XCell >& rxCell, const CellAddress& rCellAddr, sal_Int32 nSharedId ) +void SheetDataBuffer::setFormulaCell( const CellAddress& rCellAddr, sal_Int32 nSharedId ) { - setFormulaCell( rxCell, rCellAddr, resolveSharedFormula( nSharedId ) ); + setFormulaCell( rCellAddr, resolveSharedFormula( BinAddress( nSharedId, 0 ) ) ); } -void SheetDataBuffer::setArrayFormula( const CellRangeAddress& rRange, const ApiTokenSequence& rTokens ) +void SheetDataBuffer::createArrayFormula( const CellRangeAddress& rRange, const ApiTokenSequence& rTokens ) { - try - { - Reference< XArrayFormulaTokens > xTokens( getCellRange( rRange ), UNO_QUERY_THROW ); - xTokens->setArrayTokens( rTokens ); - } - catch( Exception& ) - { - } + /* Array formulas will be inserted later in finalizeImport(). This is + needed to not disturb collecting all the cells, which will be put into + the sheet in large blocks to increase performance. */ + maArrayFormulas.push_back( ArrayFormula( rRange, rTokens ) ); } -void SheetDataBuffer::setTableOperation( const CellRangeAddress& rRange, const DataTableModel& rModel ) +void SheetDataBuffer::createTableOperation( const CellRangeAddress& rRange, const DataTableModel& rModel ) { - OSL_ENSURE( getAddressConverter().checkCellRange( rRange, true, false ), "SheetDataBuffer::setTableOperation - invalid range" ); - sal_Int16 nSheet = getSheetIndex(); - bool bOk = false; - if( !rModel.mbRef1Deleted && (rModel.maRef1.getLength() > 0) && (rRange.StartColumn > 0) && (rRange.StartRow > 0) ) - { - CellRangeAddress aOpRange = rRange; - CellAddress aRef1, aRef2; - if( getAddressConverter().convertToCellAddress( aRef1, rModel.maRef1, nSheet, true ) ) try - { - if( rModel.mb2dTable ) - { - if( !rModel.mbRef2Deleted && getAddressConverter().convertToCellAddress( aRef2, rModel.maRef2, nSheet, true ) ) - { - // API call expects input values inside operation range - --aOpRange.StartColumn; - --aOpRange.StartRow; - // formula range is top-left cell of operation range - CellRangeAddress aFormulaRange( nSheet, aOpRange.StartColumn, aOpRange.StartRow, aOpRange.StartColumn, aOpRange.StartRow ); - // set multiple operation - Reference< XMultipleOperation > xMultOp( getCellRange( aOpRange ), UNO_QUERY_THROW ); - xMultOp->setTableOperation( aFormulaRange, TableOperationMode_BOTH, aRef2, aRef1 ); - bOk = true; - } - } - else if( rModel.mbRowTable ) - { - // formula range is column to the left of operation range - CellRangeAddress aFormulaRange( nSheet, aOpRange.StartColumn - 1, aOpRange.StartRow, aOpRange.StartColumn - 1, aOpRange.EndRow ); - // API call expects input values (top row) inside operation range - --aOpRange.StartRow; - // set multiple operation - Reference< XMultipleOperation > xMultOp( getCellRange( aOpRange ), UNO_QUERY_THROW ); - xMultOp->setTableOperation( aFormulaRange, TableOperationMode_ROW, aRef1, aRef1 ); - bOk = true; - } - else - { - // formula range is row above operation range - CellRangeAddress aFormulaRange( nSheet, aOpRange.StartColumn, aOpRange.StartRow - 1, aOpRange.EndColumn, aOpRange.StartRow - 1 ); - // API call expects input values (left column) inside operation range - --aOpRange.StartColumn; - // set multiple operation - Reference< XMultipleOperation > xMultOp( getCellRange( aOpRange ), UNO_QUERY_THROW ); - xMultOp->setTableOperation( aFormulaRange, TableOperationMode_COLUMN, aRef1, aRef1 ); - bOk = true; - } - } - catch( Exception& ) - { - } - } + /* Table operations will be inserted later in finalizeImport(). This is + needed to not disturb collecting all the cells, which will be put into + the sheet in large blocks to increase performance. */ + maTableOperations.push_back( TableOperation( rRange, rModel ) ); +} + +void SheetDataBuffer::createSharedFormula( sal_Int32 nSharedId, const ApiTokenSequence& rTokens ) +{ + createSharedFormula( BinAddress( nSharedId, 0 ), rTokens ); +} - // on error: fill cell range with error codes - if( !bOk ) - for( CellAddress aPos( nSheet, rRange.StartColumn, rRange.StartRow ); aPos.Row <= rRange.EndRow; ++aPos.Row ) - for( aPos.Column = rRange.StartColumn; aPos.Column <= rRange.EndColumn; ++aPos.Column ) - setErrorCell( getCell( aPos ), aPos, BIFF_ERR_REF ); +void SheetDataBuffer::createSharedFormula( const CellAddress& rCellAddr, const ApiTokenSequence& rTokens ) +{ + createSharedFormula( BinAddress( rCellAddr ), rTokens ); } void SheetDataBuffer::setRowFormat( sal_Int32 nFirstRow, sal_Int32 nLastRow, sal_Int32 nXfId, bool bCustomFormat ) @@ -356,9 +280,9 @@ void SheetDataBuffer::setRowFormat( sal_Int32 nFirstRow, sal_Int32 nLastRow, sal } } -void SheetDataBuffer::setCellFormat( const CellModel& rModel ) +void SheetDataBuffer::setCellFormat( const CellModel& rModel, sal_Int32 nNumFmtId ) { - if( rModel.mxCell.is() && ((rModel.mnXfId >= 0) || (rModel.mnNumFmtId >= 0)) ) + if( (rModel.mnXfId >= 0) || (nNumFmtId >= 0) ) { // try to merge existing ranges and to write some formatting properties if( !maXfIdRanges.empty() ) @@ -366,7 +290,7 @@ void SheetDataBuffer::setCellFormat( const CellModel& rModel ) // get row index of last inserted cell sal_Int32 nLastRow = maXfIdRanges.rbegin()->second.maRange.StartRow; // row changed - try to merge ranges of last row with existing ranges - if( rModel.maAddress.Row != nLastRow ) + if( rModel.maCellAddr.Row != nLastRow ) { mergeXfIdRanges(); // write format properties of all ranges above last row and remove them @@ -386,8 +310,8 @@ void SheetDataBuffer::setCellFormat( const CellModel& rModel ) } // try to expand last existing range, or create new range entry - if( maXfIdRanges.empty() || !maXfIdRanges.rbegin()->second.tryExpand( rModel ) ) - maXfIdRanges[ BinAddress( rModel.maAddress ) ].set( rModel ); + if( maXfIdRanges.empty() || !maXfIdRanges.rbegin()->second.tryExpand( rModel, nNumFmtId ) ) + maXfIdRanges[ BinAddress( rModel.maCellAddr ) ].set( rModel, nNumFmtId ); // update merged ranges for 'center across selection' and 'fill' if( const Xf* pXf = getStyles().getCellXf( rModel.mnXfId ).get() ) @@ -398,9 +322,9 @@ void SheetDataBuffer::setCellFormat( const CellModel& rModel ) /* start new merged range, if cell is not empty (#108781#), or try to expand last range with empty cell */ if( rModel.mnCellType != XML_TOKEN_INVALID ) - maCenterFillRanges.push_back( MergedRange( rModel.maAddress, nHorAlign ) ); + maCenterFillRanges.push_back( MergedRange( rModel.maCellAddr, nHorAlign ) ); else if( !maCenterFillRanges.empty() ) - maCenterFillRanges.rbegin()->tryExpand( rModel.maAddress, nHorAlign ); + maCenterFillRanges.rbegin()->tryExpand( rModel.maCellAddr, nHorAlign ); } } } @@ -428,6 +352,14 @@ void SheetDataBuffer::setStandardNumFmt( const CellAddress& rCellAddr, sal_Int16 void SheetDataBuffer::finalizeImport() { + // create all array formulas + for( ArrayFormulaList::iterator aIt = maArrayFormulas.begin(), aEnd = maArrayFormulas.end(); aIt != aEnd; ++aIt ) + finalizeArrayFormula( aIt->first, aIt->second ); + + // create all table operations + for( TableOperationList::iterator aIt = maTableOperations.begin(), aEnd = maTableOperations.end(); aIt != aEnd; ++aIt ) + finalizeTableOperation( aIt->first, aIt->second ); + // write default formatting of remaining row range writeXfIdRowRangeProperties( maXfIdRowRange ); @@ -438,10 +370,9 @@ void SheetDataBuffer::finalizeImport() writeXfIdRangeProperties( aIt->second ); // merge all cached merged ranges and update right/bottom cell borders - MergedRangeList::const_iterator aIt, aEnd; - for( aIt = maMergedRanges.begin(), aEnd = maMergedRanges.end(); aIt != aEnd; ++aIt ) + for( MergedRangeList::iterator aIt = maMergedRanges.begin(), aEnd = maMergedRanges.end(); aIt != aEnd; ++aIt ) finalizeMergedRange( aIt->maRange ); - for( aIt = maCenterFillRanges.begin(), aEnd = maCenterFillRanges.end(); aIt != aEnd; ++aIt ) + for( MergedRangeList::iterator aIt = maCenterFillRanges.begin(), aEnd = maCenterFillRanges.end(); aIt != aEnd; ++aIt ) finalizeMergedRange( aIt->maRange ); } @@ -484,21 +415,21 @@ bool SheetDataBuffer::XfIdRowRange::tryExpand( sal_Int32 nFirstRow, sal_Int32 nL return false; } -void SheetDataBuffer::XfIdRange::set( const CellModel& rModel ) +void SheetDataBuffer::XfIdRange::set( const CellModel& rModel, sal_Int32 nNumFmtId ) { - maRange.Sheet = rModel.maAddress.Sheet; - maRange.StartColumn = maRange.EndColumn = rModel.maAddress.Column; - maRange.StartRow = maRange.EndRow = rModel.maAddress.Row; + maRange.Sheet = rModel.maCellAddr.Sheet; + maRange.StartColumn = maRange.EndColumn = rModel.maCellAddr.Column; + maRange.StartRow = maRange.EndRow = rModel.maCellAddr.Row; mnXfId = rModel.mnXfId; - mnNumFmtId = rModel.mnNumFmtId; + mnNumFmtId = nNumFmtId; } -bool SheetDataBuffer::XfIdRange::tryExpand( const CellModel& rModel ) +bool SheetDataBuffer::XfIdRange::tryExpand( const CellModel& rModel, sal_Int32 nNumFmtId ) { - if( (mnXfId == rModel.mnXfId) && (mnNumFmtId == rModel.mnNumFmtId) && - (maRange.StartRow == rModel.maAddress.Row) && - (maRange.EndRow == rModel.maAddress.Row) && - (maRange.EndColumn + 1 == rModel.maAddress.Column) ) + if( (mnXfId == rModel.mnXfId) && (mnNumFmtId == nNumFmtId) && + (maRange.StartRow == rModel.maCellAddr.Row) && + (maRange.EndRow == rModel.maCellAddr.Row) && + (maRange.EndColumn + 1 == rModel.maCellAddr.Column) ) { ++maRange.EndColumn; return true; @@ -544,7 +475,83 @@ bool SheetDataBuffer::MergedRange::tryExpand( const CellAddress& rAddress, sal_I return false; } -Reference< XNamedRange > SheetDataBuffer::createSharedFormulaName( const BinAddress& rMapKey ) +void SheetDataBuffer::finalizeArrayFormula( const CellRangeAddress& rRange, const ApiTokenSequence& rTokens ) +{ + Reference< XArrayFormulaTokens > xTokens( getCellRange( rRange ), UNO_QUERY ); + OSL_ENSURE( xTokens.is(), "SheetDataBuffer::finalizeArrayFormula - missing formula token interface" ); + if( xTokens.is() ) + xTokens->setArrayTokens( rTokens ); +} + +void SheetDataBuffer::finalizeTableOperation( const CellRangeAddress& rRange, const DataTableModel& rModel ) +{ + sal_Int16 nSheet = getSheetIndex(); + bool bOk = false; + if( !rModel.mbRef1Deleted && (rModel.maRef1.getLength() > 0) && (rRange.StartColumn > 0) && (rRange.StartRow > 0) ) + { + CellRangeAddress aOpRange = rRange; + CellAddress aRef1; + if( getAddressConverter().convertToCellAddress( aRef1, rModel.maRef1, nSheet, true ) ) try + { + if( rModel.mb2dTable ) + { + CellAddress aRef2; + if( !rModel.mbRef2Deleted && getAddressConverter().convertToCellAddress( aRef2, rModel.maRef2, nSheet, true ) ) + { + // API call expects input values inside operation range + --aOpRange.StartColumn; + --aOpRange.StartRow; + // formula range is top-left cell of operation range + CellRangeAddress aFormulaRange( nSheet, aOpRange.StartColumn, aOpRange.StartRow, aOpRange.StartColumn, aOpRange.StartRow ); + // set multiple operation + Reference< XMultipleOperation > xMultOp( getCellRange( aOpRange ), UNO_QUERY_THROW ); + xMultOp->setTableOperation( aFormulaRange, TableOperationMode_BOTH, aRef2, aRef1 ); + bOk = true; + } + } + else if( rModel.mbRowTable ) + { + // formula range is column to the left of operation range + CellRangeAddress aFormulaRange( nSheet, aOpRange.StartColumn - 1, aOpRange.StartRow, aOpRange.StartColumn - 1, aOpRange.EndRow ); + // API call expects input values (top row) inside operation range + --aOpRange.StartRow; + // set multiple operation + Reference< XMultipleOperation > xMultOp( getCellRange( aOpRange ), UNO_QUERY_THROW ); + xMultOp->setTableOperation( aFormulaRange, TableOperationMode_ROW, aRef1, aRef1 ); + bOk = true; + } + else + { + // formula range is row above operation range + CellRangeAddress aFormulaRange( nSheet, aOpRange.StartColumn, aOpRange.StartRow - 1, aOpRange.EndColumn, aOpRange.StartRow - 1 ); + // API call expects input values (left column) inside operation range + --aOpRange.StartColumn; + // set multiple operation + Reference< XMultipleOperation > xMultOp( getCellRange( aOpRange ), UNO_QUERY_THROW ); + xMultOp->setTableOperation( aFormulaRange, TableOperationMode_COLUMN, aRef1, aRef1 ); + bOk = true; + } + } + catch( Exception& ) + { + } + } + + // on error: fill cell range with #REF! error codes + if( !bOk ) try + { + Reference< XCellRangeData > xCellRangeData( getCellRange( rRange ), UNO_QUERY_THROW ); + size_t nWidth = static_cast< size_t >( rRange.EndColumn - rRange.StartColumn + 1 ); + size_t nHeight = static_cast< size_t >( rRange.EndRow - rRange.StartRow + 1 ); + Matrix< Any > aErrorCells( nWidth, nHeight, Any( getFormulaParser().convertErrorToFormula( BIFF_ERR_REF ) ) ); + xCellRangeData->setDataArray( ContainerHelper::matrixToSequenceSequence( aErrorCells ) ); + } + catch( Exception& ) + { + } +} + +void SheetDataBuffer::createSharedFormula( const BinAddress& rMapKey, const ApiTokenSequence& rTokens ) { // create the defined name that will represent the shared formula OUString aName = OUStringBuffer().appendAscii( RTL_CONSTASCII_STRINGPARAM( "__shared_" ) ). @@ -552,40 +559,39 @@ Reference< XNamedRange > SheetDataBuffer::createSharedFormulaName( const BinAddr append( sal_Unicode( '_' ) ).append( rMapKey.mnRow ). append( sal_Unicode( '_' ) ).append( rMapKey.mnCol ).makeStringAndClear(); Reference< XNamedRange > xNamedRange = createNamedRangeObject( aName ); + OSL_ENSURE( xNamedRange.is(), "SheetDataBuffer::createSharedFormula - cannot create shared formula" ); PropertySet aNameProps( xNamedRange ); aNameProps.setProperty( PROP_IsSharedFormula, true ); // get and store the token index of the defined name - OSL_ENSURE( maTokenIndexes.count( rMapKey ) == 0, "SheetDataBuffer::createSharedFormulaName - key exists already" ); + OSL_ENSURE( maSharedFormulas.count( rMapKey ) == 0, "SheetDataBuffer::createSharedFormula - shared formula exists already" ); sal_Int32 nTokenIndex = 0; - if( aNameProps.getProperty( nTokenIndex, PROP_TokenIndex ) ) - maTokenIndexes[ rMapKey ] = nTokenIndex; - - return xNamedRange; -} - -ApiTokenSequence SheetDataBuffer::resolveSharedFormula( sal_Int32 nSharedId ) const -{ - sal_Int32 nTokenIndex = ContainerHelper::getMapElement( maTokenIndexes, BinAddress( nSharedId, 0 ), -1 ); - return (nTokenIndex >= 0) ? getFormulaParser().convertNameToFormula( nTokenIndex ) : ApiTokenSequence(); + if( aNameProps.getProperty( nTokenIndex, PROP_TokenIndex ) && (nTokenIndex >= 0) ) try + { + // store the token index in the map + maSharedFormulas[ rMapKey ] = nTokenIndex; + // set the formula definition + Reference< XFormulaTokens > xTokens( xNamedRange, UNO_QUERY_THROW ); + xTokens->setTokens( rTokens ); + // retry to insert a pending shared formula cell + if( mbPendingSharedFmla ) + { + ApiTokenSequence aTokens = resolveSharedFormula( maSharedBaseAddr ); + setFormulaCell( maSharedFmlaAddr, aTokens ); + } + } + catch( Exception& ) + { + } + mbPendingSharedFmla = false; } -ApiTokenSequence SheetDataBuffer::resolveSharedFormula( const CellAddress& rBaseAddr ) const +ApiTokenSequence SheetDataBuffer::resolveSharedFormula( const BinAddress& rMapKey ) const { - sal_Int32 nTokenIndex = ContainerHelper::getMapElement( maTokenIndexes, BinAddress( rBaseAddr ), -1 ); + sal_Int32 nTokenIndex = ContainerHelper::getMapElement( maSharedFormulas, rMapKey, -1 ); return (nTokenIndex >= 0) ? getFormulaParser().convertNameToFormula( nTokenIndex ) : ApiTokenSequence(); } -void SheetDataBuffer::retryPendingSharedFormulaCell() -{ - if( mbPendingSharedFmla ) - { - ApiTokenSequence aTokens = resolveSharedFormula( maSharedBaseAddr ); - setFormulaCell( getCell( maSharedFmlaAddr ), maSharedFmlaAddr, aTokens ); - mbPendingSharedFmla = false; - } -} - void SheetDataBuffer::writeXfIdRowRangeProperties( const XfIdRowRange& rXfIdRowRange ) const { if( (rXfIdRowRange.mnLastRow >= 0) && (rXfIdRowRange.mnXfId >= 0) ) diff --git a/oox/source/xls/sheetdatacontext.cxx b/oox/source/xls/sheetdatacontext.cxx index f387257eaaf0..63db3286cff6 100644 --- a/oox/source/xls/sheetdatacontext.cxx +++ b/oox/source/xls/sheetdatacontext.cxx @@ -37,7 +37,6 @@ #include "oox/xls/biffinputstream.hxx" #include "oox/xls/formulaparser.hxx" #include "oox/xls/richstringcontext.hxx" -#include "oox/xls/sheetdatabuffer.hxx" #include "oox/xls/unitconverter.hxx" namespace oox { @@ -102,9 +101,25 @@ const sal_Int32 BIFF2_CELL_USEIXFE = 63; // ============================================================================ +SheetDataContextBase::SheetDataContextBase( const WorksheetHelper& rHelper ) : + mrAddressConv( rHelper.getAddressConverter() ), + mrFormulaParser( rHelper.getFormulaParser() ), + mrSheetData( rHelper.getSheetData() ), + mnSheet( rHelper.getSheetIndex() ) +{ +} + +SheetDataContextBase::~SheetDataContextBase() +{ +} + +// ============================================================================ + SheetDataContext::SheetDataContext( WorksheetFragmentBase& rFragment ) : WorksheetContextBase( rFragment ), - mrSheetData( getSheetData() ) + SheetDataContextBase( rFragment ), + mbHasFormula( false ), + mbValidRange( false ) { } @@ -117,11 +132,13 @@ ContextHandlerRef SheetDataContext::onCreateContext( sal_Int32 nElement, const A break; case XLS_TOKEN( row ): - if( nElement == XLS_TOKEN( c ) ) { importCell( rAttribs ); return this; } + // do not process cell elements with invalid (out-of-range) address + if( nElement == XLS_TOKEN( c ) && importCell( rAttribs ) ) + return this; break; case XLS_TOKEN( c ): - if( maCurrCell.mxCell.is() ) switch( nElement ) + switch( nElement ) { case XLS_TOKEN( is ): mxInlineStr.reset( new RichString( *this ) ); @@ -142,112 +159,84 @@ void SheetDataContext::onCharacters( const OUString& rChars ) switch( getCurrentElement() ) { case XLS_TOKEN( v ): - maCurrCell.maValue = rChars; + maCellValue = rChars; break; case XLS_TOKEN( f ): - maCurrCell.maFormula = rChars; + if( maFmlaData.mnFormulaType != XML_TOKEN_INVALID ) + maTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, rChars ); break; } } void SheetDataContext::onEndElement() { - switch( getCurrentElement() ) + if( getCurrentElement() == XLS_TOKEN( c ) ) { - case XLS_TOKEN( c ): - if( maCurrCell.mxCell.is() ) - { - // try to create a formula cell - if( maCurrCell.mxCell->getType() == CellContentType_EMPTY ) - { - switch( maCurrCell.mnFormulaType ) - { - case XML_normal: - if( maCurrCell.maFormula.getLength() > 0 ) - { - ApiTokenSequence aTokens = getFormulaParser().importFormula( maCurrCell.maAddress, maCurrCell.maFormula ); - mrSheetData.setFormulaCell( maCurrCell.mxCell, maCurrCell.maAddress, aTokens ); - } - break; - - case XML_array: - if( (maCurrCell.maFormula.getLength() > 0) && (maCurrCell.maFormulaRef.getLength() > 0) ) - { - CellRangeAddress aArrayRange; - if( getAddressConverter().convertToCellRange( aArrayRange, maCurrCell.maFormulaRef, getSheetIndex(), true, true ) ) - { - CellAddress aBaseAddr( aArrayRange.Sheet, aArrayRange.StartColumn, aArrayRange.StartRow ); - ApiTokenSequence aTokens = getFormulaParser().importFormula( aBaseAddr, maCurrCell.maFormula ); - mrSheetData.setArrayFormula( aArrayRange, aTokens ); - } - } - break; - - case XML_shared: - if( maCurrCell.mnSharedId >= 0 ) - { - if( maCurrCell.maFormula.getLength() > 0 ) - mrSheetData.importSharedFmla( maCurrCell.maFormula, maCurrCell.maFormulaRef, maCurrCell.mnSharedId, maCurrCell.maAddress ); - mrSheetData.setFormulaCell( maCurrCell.mxCell, maCurrCell.maAddress, maCurrCell.mnSharedId ); - } - break; - - case XML_dataTable: - if( maCurrCell.maFormulaRef.getLength() > 0 ) - { - CellRangeAddress aTableRange; - if( getAddressConverter().convertToCellRange( aTableRange, maCurrCell.maFormulaRef, getSheetIndex(), true, true ) ) - mrSheetData.setTableOperation( aTableRange, maTableData ); - } - break; - - default: - OSL_ENSURE( maCurrCell.mnFormulaType == XML_TOKEN_INVALID, "SheetDataContext::onCharacters - unknown formula type" ); - } - } - - // no formula created: try to set the cell value - if( maCurrCell.mxCell->getType() == CellContentType_EMPTY ) + // try to create a formula cell + if( mbHasFormula ) switch( maFmlaData.mnFormulaType ) + { + case XML_normal: + mrSheetData.setFormulaCell( maCellData.maCellAddr, maTokens ); + break; + case XML_shared: + if( maFmlaData.mnSharedId >= 0 ) { - if( maCurrCell.maValue.getLength() > 0 ) - { - switch( maCurrCell.mnCellType ) - { - case XML_n: - mrSheetData.setValueCell( maCurrCell.mxCell, maCurrCell.maAddress, maCurrCell.maValue.toDouble() ); - break; - case XML_b: - mrSheetData.setBooleanCell( maCurrCell.mxCell, maCurrCell.maAddress, maCurrCell.maValue.toDouble() != 0.0 ); - // #108770# set 'Standard' number format for all Boolean cells - maCurrCell.mnNumFmtId = 0; - break; - case XML_e: - mrSheetData.setErrorCell( maCurrCell.mxCell, maCurrCell.maAddress, maCurrCell.maValue ); - break; - case XML_str: - mrSheetData.setStringCell( maCurrCell.mxCell, maCurrCell.maAddress, maCurrCell.maValue ); - break; - case XML_s: - mrSheetData.setStringCell( maCurrCell.mxCell, maCurrCell.maAddress, maCurrCell.maValue.toInt32(), maCurrCell.mnXfId ); - break; - } - } - else if( (maCurrCell.mnCellType == XML_inlineStr) && mxInlineStr.get() ) - { - mxInlineStr->finalizeImport(); - mrSheetData.setStringCell( maCurrCell.mxCell, maCurrCell.maAddress, *mxInlineStr, maCurrCell.mnXfId ); - } - else - { - // empty cell, update cell type - maCurrCell.mnCellType = XML_TOKEN_INVALID; - } + if( mbValidRange && maFmlaData.isValidSharedRef( maCellData.maCellAddr ) ) + mrSheetData.createSharedFormula( maFmlaData.mnSharedId, maTokens ); + mrSheetData.setFormulaCell( maCellData.maCellAddr, maFmlaData.mnSharedId ); } + break; + case XML_array: + if( mbValidRange && maFmlaData.isValidArrayRef( maCellData.maCellAddr ) ) + mrSheetData.createArrayFormula( maFmlaData.maFormulaRef, maTokens ); + break; + case XML_dataTable: + if( mbValidRange ) + mrSheetData.createTableOperation( maFmlaData.maFormulaRef, maTableData ); + break; + default: + OSL_ENSURE( maFmlaData.mnFormulaType == XML_TOKEN_INVALID, "SheetDataContext::onEndElement - unknown formula type" ); + mbHasFormula = false; + } - // store the cell formatting data - mrSheetData.setCellFormat( maCurrCell ); + if( !mbHasFormula ) + { + // no formula created: try to set the cell value + if( maCellValue.getLength() > 0 ) switch( maCellData.mnCellType ) + { + case XML_n: + mrSheetData.setValueCell( maCellData.maCellAddr, maCellValue.toDouble() ); + break; + case XML_b: + mrSheetData.setBooleanCell( maCellData.maCellAddr, maCellValue.toDouble() != 0.0 ); + break; + case XML_e: + mrSheetData.setErrorCell( maCellData.maCellAddr, maCellValue ); + break; + case XML_str: + mrSheetData.setStringCell( maCellData.maCellAddr, maCellValue ); + break; + case XML_s: + mrSheetData.setStringCell( maCellData.maCellAddr, maCellValue.toInt32(), maCellData.mnXfId ); + break; } - break; + else if( (maCellData.mnCellType == XML_inlineStr) && mxInlineStr.get() ) + { + mxInlineStr->finalizeImport(); + mrSheetData.setStringCell( maCellData.maCellAddr, *mxInlineStr, maCellData.mnXfId ); + } + else + { + // empty cell, update cell type + maCellData.mnCellType = XML_TOKEN_INVALID; + } + } + + // #108770# set 'Standard' number format for all Boolean cells + bool bBoolCell = !mbHasFormula && (maCellData.mnCellType == XML_b); + sal_Int32 nNumFmtId = bBoolCell ? 0 : -1; + // store the cell formatting data + mrSheetData.setCellFormat( maCellData, nNumFmtId ); } } @@ -311,37 +300,73 @@ void SheetDataContext::importRow( const AttributeList& rAttribs ) setRowModel( aModel ); } -void SheetDataContext::importCell( const AttributeList& rAttribs ) +bool SheetDataContext::importCell( const AttributeList& rAttribs ) { - maCurrCell.reset(); - maCurrCell.mxCell = getCell( rAttribs.getString( XML_r, OUString() ), &maCurrCell.maAddress ); - maCurrCell.mnCellType = rAttribs.getToken( XML_t, XML_n ); - maCurrCell.mnXfId = rAttribs.getInteger( XML_s, -1 ); - maCurrCell.mbShowPhonetic = rAttribs.getBool( XML_ph, false ); - mxInlineStr.reset(); + bool bValidAddr = mrAddressConv.convertToCellAddress( maCellData.maCellAddr, rAttribs.getString( XML_r, OUString() ), mnSheet, true ); + if( bValidAddr ) + { + maCellData.mnCellType = rAttribs.getToken( XML_t, XML_n ); + maCellData.mnXfId = rAttribs.getInteger( XML_s, -1 ); + maCellData.mbShowPhonetic = rAttribs.getBool( XML_ph, false ); - // update used area of the sheet - if( maCurrCell.mxCell.is() ) - extendUsedArea( maCurrCell.maAddress ); + // reset cell value, formula settings, and inline string + maCellValue = OUString(); + mxInlineStr.reset(); + mbHasFormula = false; + + // update used area of the sheet + extendUsedArea( maCellData.maCellAddr ); + } + return bValidAddr; } void SheetDataContext::importFormula( const AttributeList& rAttribs ) { - maCurrCell.maFormulaRef = rAttribs.getString( XML_ref, OUString() ); - maCurrCell.mnFormulaType = rAttribs.getToken( XML_t, XML_normal ); - maCurrCell.mnSharedId = rAttribs.getInteger( XML_si, -1 ); - maTableData.maRef1 = rAttribs.getString( XML_r1, OUString() ); - maTableData.maRef2 = rAttribs.getString( XML_r2, OUString() ); - maTableData.mb2dTable = rAttribs.getBool( XML_dt2D, false ); - maTableData.mbRowTable = rAttribs.getBool( XML_dtr, false ); - maTableData.mbRef1Deleted = rAttribs.getBool( XML_del1, false ); - maTableData.mbRef2Deleted = rAttribs.getBool( XML_del2, false ); + mbHasFormula = true; + mbValidRange = mrAddressConv.convertToCellRange( maFmlaData.maFormulaRef, rAttribs.getString( XML_ref, OUString() ), mnSheet, true, true ); + + maFmlaData.mnFormulaType = rAttribs.getToken( XML_t, XML_normal ); + maFmlaData.mnSharedId = rAttribs.getInteger( XML_si, -1 ); + + if( maFmlaData.mnFormulaType == XML_dataTable ) + { + maTableData.maRef1 = rAttribs.getString( XML_r1, OUString() ); + maTableData.maRef2 = rAttribs.getString( XML_r2, OUString() ); + maTableData.mb2dTable = rAttribs.getBool( XML_dt2D, false ); + maTableData.mbRowTable = rAttribs.getBool( XML_dtr, false ); + maTableData.mbRef1Deleted = rAttribs.getBool( XML_del1, false ); + maTableData.mbRef2Deleted = rAttribs.getBool( XML_del2, false ); + } + + // clear token array, will be regenerated from element text + maTokens = ApiTokenSequence(); } -void SheetDataContext::importCellHeader( SequenceInputStream& rStrm, CellType eCellType ) +void SheetDataContext::importRow( SequenceInputStream& rStrm ) { - maCurrCell.reset(); + RowModel aModel; + sal_uInt16 nHeight, nFlags1; + sal_uInt8 nFlags2; + rStrm >> maCurrPos.mnRow >> aModel.mnXfId >> nHeight >> nFlags1 >> nFlags2; + // row index is 0-based in BIFF12, but RowModel expects 1-based + aModel.mnFirstRow = aModel.mnLastRow = maCurrPos.mnRow + 1; + // row height is in twips in BIFF12, convert to points + aModel.mfHeight = nHeight / 20.0; + aModel.mnLevel = extractValue< sal_Int32 >( nFlags1, 8, 3 ); + aModel.mbCustomHeight = getFlag( nFlags1, BIFF12_ROW_CUSTOMHEIGHT ); + aModel.mbCustomFormat = getFlag( nFlags1, BIFF12_ROW_CUSTOMFORMAT ); + aModel.mbShowPhonetic = getFlag( nFlags2, BIFF12_ROW_SHOWPHONETIC ); + aModel.mbHidden = getFlag( nFlags1, BIFF12_ROW_HIDDEN ); + aModel.mbCollapsed = getFlag( nFlags1, BIFF12_ROW_COLLAPSED ); + aModel.mbThickTop = getFlag( nFlags1, BIFF12_ROW_THICKTOP ); + aModel.mbThickBottom = getFlag( nFlags1, BIFF12_ROW_THICKBOTTOM ); + // set row properties in the current sheet + setRowModel( aModel ); +} + +bool SheetDataContext::readCellHeader( SequenceInputStream& rStrm, CellType eCellType ) +{ switch( eCellType ) { case CELLTYPE_VALUE: @@ -352,194 +377,166 @@ void SheetDataContext::importCellHeader( SequenceInputStream& rStrm, CellType eC sal_uInt32 nXfId; rStrm >> nXfId; - maCurrCell.mxCell = getCell( maCurrPos, &maCurrCell.maAddress ); - maCurrCell.mnXfId = extractValue< sal_Int32 >( nXfId, 0, 24 ); - maCurrCell.mbShowPhonetic = getFlag( nXfId, BIFF12_CELL_SHOWPHONETIC ); + bool bValidAddr = mrAddressConv.convertToCellAddress( maCellData.maCellAddr, maCurrPos, mnSheet, true ); + maCellData.mnXfId = extractValue< sal_Int32 >( nXfId, 0, 24 ); + maCellData.mbShowPhonetic = getFlag( nXfId, BIFF12_CELL_SHOWPHONETIC ); // update used area of the sheet - if( maCurrCell.mxCell.is() ) - extendUsedArea( maCurrCell.maAddress ); + if( bValidAddr ) + extendUsedArea( maCellData.maCellAddr ); + return bValidAddr; +} + +ApiTokenSequence SheetDataContext::readCellFormula( SequenceInputStream& rStrm ) +{ + rStrm.skip( 2 ); + return mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_CELL, rStrm ); +} + +bool SheetDataContext::readFormulaRef( SequenceInputStream& rStrm ) +{ + BinRange aRange; + rStrm >> aRange; + return mrAddressConv.convertToCellRange( maFmlaData.maFormulaRef, aRange, mnSheet, true, true ); } void SheetDataContext::importCellBool( SequenceInputStream& rStrm, CellType eCellType ) { - importCellHeader( rStrm, eCellType ); - maCurrCell.mnCellType = XML_b; - if( maCurrCell.mxCell.is() && (maCurrCell.mxCell->getType() == CellContentType_EMPTY) ) + if( readCellHeader( rStrm, eCellType ) ) { + maCellData.mnCellType = XML_b; bool bValue = rStrm.readuInt8() != 0; if( eCellType == CELLTYPE_FORMULA ) - { - importCellFormula( rStrm ); - } + mrSheetData.setFormulaCell( maCellData.maCellAddr, readCellFormula( rStrm ) ); else - { - mrSheetData.setBooleanCell( maCurrCell.mxCell, maCurrCell.maAddress, bValue ); - // #108770# set 'Standard' number format for all Boolean cells - maCurrCell.mnNumFmtId = 0; - } + mrSheetData.setBooleanCell( maCellData.maCellAddr, bValue ); + // #108770# set 'Standard' number format for all Boolean cells + sal_Int32 nNumFmtId = (eCellType != CELLTYPE_FORMULA) ? 0 : -1; + mrSheetData.setCellFormat( maCellData, nNumFmtId ); } - mrSheetData.setCellFormat( maCurrCell ); } void SheetDataContext::importCellBlank( SequenceInputStream& rStrm, CellType eCellType ) { OSL_ENSURE( eCellType != CELLTYPE_FORMULA, "SheetDataContext::importCellBlank - no formula cells supported" ); - importCellHeader( rStrm, eCellType ); - mrSheetData.setCellFormat( maCurrCell ); + if( readCellHeader( rStrm, eCellType ) ) + mrSheetData.setCellFormat( maCellData ); } void SheetDataContext::importCellDouble( SequenceInputStream& rStrm, CellType eCellType ) { - importCellHeader( rStrm, eCellType ); - maCurrCell.mnCellType = XML_n; - if( maCurrCell.mxCell.is() && (maCurrCell.mxCell->getType() == CellContentType_EMPTY) ) + if( readCellHeader( rStrm, eCellType ) ) { + maCellData.mnCellType = XML_n; double fValue = rStrm.readDouble(); if( eCellType == CELLTYPE_FORMULA ) - importCellFormula( rStrm ); + mrSheetData.setFormulaCell( maCellData.maCellAddr, readCellFormula( rStrm ) ); else - mrSheetData.setValueCell( maCurrCell.mxCell, maCurrCell.maAddress, fValue ); + mrSheetData.setValueCell( maCellData.maCellAddr, fValue ); + mrSheetData.setCellFormat( maCellData ); } - mrSheetData.setCellFormat( maCurrCell ); } void SheetDataContext::importCellError( SequenceInputStream& rStrm, CellType eCellType ) { - importCellHeader( rStrm, eCellType ); - maCurrCell.mnCellType = XML_e; - if( maCurrCell.mxCell.is() && (maCurrCell.mxCell->getType() == CellContentType_EMPTY) ) + if( readCellHeader( rStrm, eCellType ) ) { + maCellData.mnCellType = XML_e; sal_uInt8 nErrorCode = rStrm.readuInt8(); if( eCellType == CELLTYPE_FORMULA ) - importCellFormula( rStrm ); + mrSheetData.setFormulaCell( maCellData.maCellAddr, readCellFormula( rStrm ) ); else - mrSheetData.setErrorCell( maCurrCell.mxCell, maCurrCell.maAddress, nErrorCode ); + mrSheetData.setErrorCell( maCellData.maCellAddr, nErrorCode ); + mrSheetData.setCellFormat( maCellData ); } - mrSheetData.setCellFormat( maCurrCell ); } void SheetDataContext::importCellRk( SequenceInputStream& rStrm, CellType eCellType ) { OSL_ENSURE( eCellType != CELLTYPE_FORMULA, "SheetDataContext::importCellRk - no formula cells supported" ); - importCellHeader( rStrm, eCellType ); - maCurrCell.mnCellType = XML_n; - if( maCurrCell.mxCell.is() && (maCurrCell.mxCell->getType() == CellContentType_EMPTY) ) - mrSheetData.setValueCell( maCurrCell.mxCell, maCurrCell.maAddress, BiffHelper::calcDoubleFromRk( rStrm.readInt32() ) ); - mrSheetData.setCellFormat( maCurrCell ); + if( readCellHeader( rStrm, eCellType ) ) + { + maCellData.mnCellType = XML_n; + mrSheetData.setValueCell( maCellData.maCellAddr, BiffHelper::calcDoubleFromRk( rStrm.readInt32() ) ); + mrSheetData.setCellFormat( maCellData ); + } } void SheetDataContext::importCellRString( SequenceInputStream& rStrm, CellType eCellType ) { OSL_ENSURE( eCellType != CELLTYPE_FORMULA, "SheetDataContext::importCellRString - no formula cells supported" ); - importCellHeader( rStrm, eCellType ); - maCurrCell.mnCellType = XML_inlineStr; - if( maCurrCell.mxCell.is() && (maCurrCell.mxCell->getType() == CellContentType_EMPTY) ) + if( readCellHeader( rStrm, eCellType ) ) { + maCellData.mnCellType = XML_inlineStr; RichString aString( *this ); aString.importString( rStrm, true ); aString.finalizeImport(); - mrSheetData.setStringCell( maCurrCell.mxCell, maCurrCell.maAddress, aString, maCurrCell.mnXfId ); + mrSheetData.setStringCell( maCellData.maCellAddr, aString, maCellData.mnXfId ); + mrSheetData.setCellFormat( maCellData ); } - mrSheetData.setCellFormat( maCurrCell ); } void SheetDataContext::importCellSi( SequenceInputStream& rStrm, CellType eCellType ) { OSL_ENSURE( eCellType != CELLTYPE_FORMULA, "SheetDataContext::importCellSi - no formula cells supported" ); - importCellHeader( rStrm, eCellType ); - maCurrCell.mnCellType = XML_s; - if( maCurrCell.mxCell.is() && (maCurrCell.mxCell->getType() == CellContentType_EMPTY) ) - mrSheetData.setStringCell( maCurrCell.mxCell, maCurrCell.maAddress, rStrm.readInt32(), maCurrCell.mnXfId ); - mrSheetData.setCellFormat( maCurrCell ); + if( readCellHeader( rStrm, eCellType ) ) + { + maCellData.mnCellType = XML_s; + mrSheetData.setStringCell( maCellData.maCellAddr, rStrm.readInt32(), maCellData.mnXfId ); + mrSheetData.setCellFormat( maCellData ); + } } void SheetDataContext::importCellString( SequenceInputStream& rStrm, CellType eCellType ) { - importCellHeader( rStrm, eCellType ); - maCurrCell.mnCellType = XML_inlineStr; - Reference< XText > xText( maCurrCell.mxCell, UNO_QUERY ); - if( maCurrCell.mxCell.is() && (maCurrCell.mxCell->getType() == CellContentType_EMPTY) ) + if( readCellHeader( rStrm, eCellType ) ) { + maCellData.mnCellType = XML_inlineStr; + // always import the string, stream will point to formula afterwards, if existing RichString aString( *this ); aString.importString( rStrm, false ); aString.finalizeImport(); if( eCellType == CELLTYPE_FORMULA ) - importCellFormula( rStrm ); + mrSheetData.setFormulaCell( maCellData.maCellAddr, readCellFormula( rStrm ) ); else - mrSheetData.setStringCell( maCurrCell.mxCell, maCurrCell.maAddress, aString, maCurrCell.mnXfId ); + mrSheetData.setStringCell( maCellData.maCellAddr, aString, maCellData.mnXfId ); + mrSheetData.setCellFormat( maCellData ); } - mrSheetData.setCellFormat( maCurrCell ); -} - -void SheetDataContext::importCellFormula( SequenceInputStream& rStrm ) -{ - rStrm.skip( 2 ); - ApiTokenSequence aTokens = getFormulaParser().importFormula( maCurrCell.maAddress, FORMULATYPE_CELL, rStrm ); - mrSheetData.setFormulaCell( maCurrCell.mxCell, maCurrCell.maAddress, aTokens ); -} - -void SheetDataContext::importRow( SequenceInputStream& rStrm ) -{ - RowModel aModel; - - sal_uInt16 nHeight, nFlags1; - sal_uInt8 nFlags2; - rStrm >> maCurrPos.mnRow >> aModel.mnXfId >> nHeight >> nFlags1 >> nFlags2; - - // row index is 0-based in BIFF12, but RowModel expects 1-based - aModel.mnFirstRow = aModel.mnLastRow = maCurrPos.mnRow + 1; - // row height is in twips in BIFF12, convert to points - aModel.mfHeight = nHeight / 20.0; - aModel.mnLevel = extractValue< sal_Int32 >( nFlags1, 8, 3 ); - aModel.mbCustomHeight = getFlag( nFlags1, BIFF12_ROW_CUSTOMHEIGHT ); - aModel.mbCustomFormat = getFlag( nFlags1, BIFF12_ROW_CUSTOMFORMAT ); - aModel.mbShowPhonetic = getFlag( nFlags2, BIFF12_ROW_SHOWPHONETIC ); - aModel.mbHidden = getFlag( nFlags1, BIFF12_ROW_HIDDEN ); - aModel.mbCollapsed = getFlag( nFlags1, BIFF12_ROW_COLLAPSED ); - aModel.mbThickTop = getFlag( nFlags1, BIFF12_ROW_THICKTOP ); - aModel.mbThickBottom = getFlag( nFlags1, BIFF12_ROW_THICKBOTTOM ); - // set row properties in the current sheet - setRowModel( aModel ); } void SheetDataContext::importArray( SequenceInputStream& rStrm ) { - BinRange aRange; - rStrm >> aRange; - CellRangeAddress aArrayRange; - if( getAddressConverter().convertToCellRange( aArrayRange, aRange, getSheetIndex(), true, true ) ) + if( readFormulaRef( rStrm ) && maFmlaData.isValidArrayRef( maCellData.maCellAddr ) ) { rStrm.skip( 1 ); - CellAddress aBaseAddr( aArrayRange.Sheet, aArrayRange.StartColumn, aArrayRange.StartRow ); - ApiTokenSequence aTokens = getFormulaParser().importFormula( aBaseAddr, FORMULATYPE_ARRAY, rStrm ); - mrSheetData.setArrayFormula( aArrayRange, aTokens ); + ApiTokenSequence aTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_ARRAY, rStrm ); + mrSheetData.createArrayFormula( maFmlaData.maFormulaRef, aTokens ); } } -void SheetDataContext::importSharedFmla( SequenceInputStream& rStrm ) -{ - mrSheetData.importSharedFmla( rStrm, maCurrCell.maAddress ); -} - void SheetDataContext::importDataTable( SequenceInputStream& rStrm ) { - BinRange aRange; - rStrm >> aRange; - CellRangeAddress aTableRange; - if( getAddressConverter().convertToCellRange( aTableRange, aRange, getSheetIndex(), true, true ) ) + if( readFormulaRef( rStrm ) ) { - DataTableModel aModel; BinAddress aRef1, aRef2; sal_uInt8 nFlags; rStrm >> aRef1 >> aRef2 >> nFlags; - aModel.maRef1 = FormulaProcessorBase::generateAddress2dString( aRef1, false ); - aModel.maRef2 = FormulaProcessorBase::generateAddress2dString( aRef2, false ); - aModel.mbRowTable = getFlag( nFlags, BIFF12_DATATABLE_ROW ); - aModel.mb2dTable = getFlag( nFlags, BIFF12_DATATABLE_2D ); - aModel.mbRef1Deleted = getFlag( nFlags, BIFF12_DATATABLE_REF1DEL ); - aModel.mbRef2Deleted = getFlag( nFlags, BIFF12_DATATABLE_REF2DEL ); - mrSheetData.setTableOperation( aTableRange, aModel ); + maTableData.maRef1 = FormulaProcessorBase::generateAddress2dString( aRef1, false ); + maTableData.maRef2 = FormulaProcessorBase::generateAddress2dString( aRef2, false ); + maTableData.mbRowTable = getFlag( nFlags, BIFF12_DATATABLE_ROW ); + maTableData.mb2dTable = getFlag( nFlags, BIFF12_DATATABLE_2D ); + maTableData.mbRef1Deleted = getFlag( nFlags, BIFF12_DATATABLE_REF1DEL ); + maTableData.mbRef2Deleted = getFlag( nFlags, BIFF12_DATATABLE_REF2DEL ); + mrSheetData.createTableOperation( maFmlaData.maFormulaRef, maTableData ); + } +} + +void SheetDataContext::importSharedFmla( SequenceInputStream& rStrm ) +{ + if( readFormulaRef( rStrm ) && maFmlaData.isValidSharedRef( maCellData.maCellAddr ) ) + { + ApiTokenSequence aTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_SHAREDFORMULA, rStrm ); + mrSheetData.createSharedFormula( maCellData.maCellAddr, aTokens ); } } @@ -547,7 +544,7 @@ void SheetDataContext::importDataTable( SequenceInputStream& rStrm ) BiffSheetDataContext::BiffSheetDataContext( const WorksheetHelper& rHelper ) : BiffWorksheetContextBase( rHelper ), - mrSheetData( getSheetData() ), + SheetDataContextBase( rHelper ), mnBiff2XfId( 0 ) { switch( getBiff() ) @@ -656,109 +653,160 @@ void BiffSheetDataContext::importRecord( BiffInputStream& rStrm ) // private -------------------------------------------------------------------- -void BiffSheetDataContext::setCurrCell( const BinAddress& rAddr ) +void BiffSheetDataContext::importRow( BiffInputStream& rStrm ) { - maCurrCell.reset(); - maCurrCell.mxCell = getCell( rAddr, &maCurrCell.maAddress ); - // update used area of the sheet - if( maCurrCell.mxCell.is() ) - extendUsedArea( maCurrCell.maAddress ); -} - -void BiffSheetDataContext::importXfId( BiffInputStream& rStrm, bool bBiff2 ) -{ - if( bBiff2 ) - { - /* #i71453# On first call, check if the file contains XF records (by - trying to access the first XF with index 0). If there are no XFs, - the explicit formatting information contained in each cell record - will be used instead. */ - if( !mobBiff2HasXfs ) - mobBiff2HasXfs = getStyles().getCellXf( 0 ).get() != 0; - // read formatting information (includes the XF identifier) - sal_uInt8 nFlags1, nFlags2, nFlags3; - rStrm >> nFlags1 >> nFlags2 >> nFlags3; - /* If the file contains XFs, extract and set the XF identifier, - otherwise get the explicit formatting. */ - if( mobBiff2HasXfs.get() ) - { - maCurrCell.mnXfId = extractValue< sal_Int32 >( nFlags1, 0, 6 ); - /* If the identifier is equal to 63, then the real identifier is - contained in the preceding IXFE record (stored in mnBiff2XfId). */ - if( maCurrCell.mnXfId == BIFF2_CELL_USEIXFE ) - maCurrCell.mnXfId = mnBiff2XfId; - } - else + RowModel aModel; + sal_uInt16 nRow, nHeight; + rStrm >> nRow; + rStrm.skip( 4 ); + rStrm >> nHeight; + if( getBiff() == BIFF2 ) + { + rStrm.skip( 2 ); + aModel.mbCustomFormat = rStrm.readuInt8() == BIFF2_ROW_CUSTOMFORMAT; + if( aModel.mbCustomFormat ) { - /* Let the Xf class do the API conversion. Keeping the member - maCurrCell.mnXfId untouched will prevent to trigger the usual - XF formatting conversion later on. */ - PropertySet aPropSet( maCurrCell.mxCell ); - Xf::writeBiff2CellFormatToPropertySet( *this, aPropSet, nFlags1, nFlags2, nFlags3 ); + rStrm.skip( 5 ); + aModel.mnXfId = rStrm.readuInt16(); } } else { - maCurrCell.mnXfId = rStrm.readuInt16(); + rStrm.skip( 4 ); + sal_uInt32 nFlags = rStrm.readuInt32(); + aModel.mnXfId = extractValue< sal_Int32 >( nFlags, 16, 12 ); + aModel.mnLevel = extractValue< sal_Int32 >( nFlags, 0, 3 ); + aModel.mbCustomFormat = getFlag( nFlags, BIFF_ROW_CUSTOMFORMAT ); + aModel.mbCustomHeight = getFlag( nFlags, BIFF_ROW_CUSTOMHEIGHT ); + aModel.mbShowPhonetic = getFlag( nFlags, BIFF_ROW_SHOWPHONETIC ); + aModel.mbHidden = getFlag( nFlags, BIFF_ROW_HIDDEN ); + aModel.mbCollapsed = getFlag( nFlags, BIFF_ROW_COLLAPSED ); + aModel.mbThickTop = getFlag( nFlags, BIFF_ROW_THICKTOP ); + aModel.mbThickBottom = getFlag( nFlags, BIFF_ROW_THICKBOTTOM ); } + + // row index is 0-based in BIFF, but RowModel expects 1-based + aModel.mnFirstRow = aModel.mnLastRow = nRow + 1; + // row height is in twips in BIFF, convert to points + aModel.mfHeight = (nHeight & BIFF_ROW_HEIGHTMASK) / 20.0; + // set row properties in the current sheet + setRowModel( aModel ); } -void BiffSheetDataContext::importCellHeader( BiffInputStream& rStrm, bool bBiff2 ) +bool BiffSheetDataContext::readCellXfId( const BinAddress& rAddr, BiffInputStream& rStrm, bool bBiff2 ) +{ + bool bValidAddr = mrAddressConv.convertToCellAddress( maCellData.maCellAddr, rAddr, mnSheet, true ); + if( bValidAddr ) + { + // update used area of the sheet + extendUsedArea( maCellData.maCellAddr ); + + // load the XF identifier according to current BIFF version + if( bBiff2 ) + { + /* #i71453# On first call, check if the file contains XF records + (by trying to access the first XF with index 0). If there are + no XFs, the explicit formatting information contained in each + cell record will be used instead. */ + if( !mobBiff2HasXfs ) + mobBiff2HasXfs = getStyles().getCellXf( 0 ).get() != 0; + // read formatting information (includes the XF identifier) + sal_uInt8 nFlags1, nFlags2, nFlags3; + rStrm >> nFlags1 >> nFlags2 >> nFlags3; + /* If the file contains XFs, extract and set the XF identifier, + otherwise get the explicit formatting. */ + if( mobBiff2HasXfs.get() ) + { + maCellData.mnXfId = extractValue< sal_Int32 >( nFlags1, 0, 6 ); + /* If the identifier is equal to 63, then the real identifier + is contained in the preceding IXFE record (stored in the + class member mnBiff2XfId). */ + if( maCellData.mnXfId == BIFF2_CELL_USEIXFE ) + maCellData.mnXfId = mnBiff2XfId; + } + else + { + /* Let the Xf class do the API conversion. Keeping the member + maCellData.mnXfId untouched will prevent to trigger the + usual XF formatting conversion later on. */ + PropertySet aPropSet( getCell( maCellData.maCellAddr ) ); + Xf::writeBiff2CellFormatToPropertySet( *this, aPropSet, nFlags1, nFlags2, nFlags3 ); + } + } + else + { + // BIFF3-BIFF8: 16-bit XF identifier + maCellData.mnXfId = rStrm.readuInt16(); + } + } + return bValidAddr; +} + +bool BiffSheetDataContext::readCellHeader( BiffInputStream& rStrm, bool bBiff2 ) { BinAddress aAddr; rStrm >> aAddr; - setCurrCell( aAddr ); - importXfId( rStrm, bBiff2 ); + return readCellXfId( aAddr, rStrm, bBiff2 ); +} + +bool BiffSheetDataContext::readFormulaRef( BiffInputStream& rStrm ) +{ + BinRange aRange; + aRange.read( rStrm, false ); // columns always 8-bit + return mrAddressConv.convertToCellRange( maFmlaData.maFormulaRef, aRange, mnSheet, true, true ); } void BiffSheetDataContext::importBlank( BiffInputStream& rStrm ) { - importCellHeader( rStrm, rStrm.getRecId() == BIFF2_ID_BLANK ); - mrSheetData.setCellFormat( maCurrCell ); + if( readCellHeader( rStrm, rStrm.getRecId() == BIFF2_ID_BLANK ) ) + mrSheetData.setCellFormat( maCellData ); } void BiffSheetDataContext::importBoolErr( BiffInputStream& rStrm ) { - importCellHeader( rStrm, rStrm.getRecId() == BIFF2_ID_BOOLERR ); - if( maCurrCell.mxCell.is() ) + if( readCellHeader( rStrm, rStrm.getRecId() == BIFF2_ID_BOOLERR ) ) { sal_uInt8 nValue, nType; rStrm >> nValue >> nType; switch( nType ) { case BIFF_BOOLERR_BOOL: - maCurrCell.mnCellType = XML_b; - mrSheetData.setBooleanCell( maCurrCell.mxCell, maCurrCell.maAddress, nValue != 0 ); - // #108770# set 'Standard' number format for all Boolean cells - maCurrCell.mnNumFmtId = 0; + maCellData.mnCellType = XML_b; + mrSheetData.setBooleanCell( maCellData.maCellAddr, nValue != 0 ); break; case BIFF_BOOLERR_ERROR: - maCurrCell.mnCellType = XML_e; - mrSheetData.setErrorCell( maCurrCell.mxCell, maCurrCell.maAddress, nValue ); + maCellData.mnCellType = XML_e; + mrSheetData.setErrorCell( maCellData.maCellAddr, nValue ); break; default: OSL_ENSURE( false, "BiffSheetDataContext::importBoolErr - unknown cell type" ); } + // #108770# set 'Standard' number format for all Boolean cells + sal_Int32 nNumFmtId = (nType == BIFF_BOOLERR_BOOL) ? 0 : -1; + mrSheetData.setCellFormat( maCellData, nNumFmtId ); } - mrSheetData.setCellFormat( maCurrCell ); } void BiffSheetDataContext::importFormula( BiffInputStream& rStrm ) { - importCellHeader( rStrm, getBiff() == BIFF2 ); - maCurrCell.mnCellType = XML_n; - rStrm.skip( mnFormulaSkipSize ); - ApiTokenSequence aTokens = getFormulaParser().importFormula( maCurrCell.maAddress, FORMULATYPE_CELL, rStrm ); - mrSheetData.setFormulaCell( maCurrCell.mxCell, maCurrCell.maAddress, aTokens ); - mrSheetData.setCellFormat( maCurrCell ); + if( readCellHeader( rStrm, getBiff() == BIFF2 ) ) + { + maCellData.mnCellType = XML_n; + rStrm.skip( mnFormulaSkipSize ); + ApiTokenSequence aTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_CELL, rStrm ); + mrSheetData.setFormulaCell( maCellData.maCellAddr, aTokens ); + mrSheetData.setCellFormat( maCellData ); + } } void BiffSheetDataContext::importInteger( BiffInputStream& rStrm ) { - importCellHeader( rStrm, true ); - maCurrCell.mnCellType = XML_n; - mrSheetData.setValueCell( maCurrCell.mxCell, maCurrCell.maAddress, rStrm.readuInt16() ); - mrSheetData.setCellFormat( maCurrCell ); + if( readCellHeader( rStrm, true ) ) + { + maCellData.mnCellType = XML_n; + mrSheetData.setValueCell( maCellData.maCellAddr, rStrm.readuInt16() ); + mrSheetData.setCellFormat( maCellData ); + } } void BiffSheetDataContext::importLabel( BiffInputStream& rStrm ) @@ -771,143 +819,98 @@ void BiffSheetDataContext::importLabel( BiffInputStream& rStrm ) 0x0204 8 -> 2 byte 16-bit length, unicode string */ bool bBiff2Xf = rStrm.getRecId() == BIFF2_ID_LABEL; - importCellHeader( rStrm, bBiff2Xf ); - maCurrCell.mnCellType = XML_inlineStr; - RichString aString( *this ); - if( getBiff() == BIFF8 ) + if( readCellHeader( rStrm, bBiff2Xf ) ) { - aString.importUniString( rStrm ); - } - else - { - // #i63105# use text encoding from FONT record - rtl_TextEncoding eTextEnc = getTextEncoding(); - if( const Font* pFont = getStyles().getFontFromCellXf( maCurrCell.mnXfId ).get() ) - eTextEnc = pFont->getFontEncoding(); - BiffStringFlags nFlags = bBiff2Xf ? BIFF_STR_8BITLENGTH : BIFF_STR_DEFAULT; - setFlag( nFlags, BIFF_STR_EXTRAFONTS, rStrm.getRecId() == BIFF_ID_RSTRING ); - aString.importByteString( rStrm, eTextEnc, nFlags ); + maCellData.mnCellType = XML_inlineStr; + RichString aString( *this ); + if( getBiff() == BIFF8 ) + { + aString.importUniString( rStrm ); + } + else + { + // #i63105# use text encoding from FONT record + rtl_TextEncoding eTextEnc = getTextEncoding(); + if( const Font* pFont = getStyles().getFontFromCellXf( maCellData.mnXfId ).get() ) + eTextEnc = pFont->getFontEncoding(); + BiffStringFlags nFlags = bBiff2Xf ? BIFF_STR_8BITLENGTH : BIFF_STR_DEFAULT; + setFlag( nFlags, BIFF_STR_EXTRAFONTS, rStrm.getRecId() == BIFF_ID_RSTRING ); + aString.importByteString( rStrm, eTextEnc, nFlags ); + } + aString.finalizeImport(); + mrSheetData.setStringCell( maCellData.maCellAddr, aString, maCellData.mnXfId ); + mrSheetData.setCellFormat( maCellData ); } - aString.finalizeImport(); - mrSheetData.setStringCell( maCurrCell.mxCell, maCurrCell.maAddress, aString, maCurrCell.mnXfId ); - mrSheetData.setCellFormat( maCurrCell ); } void BiffSheetDataContext::importLabelSst( BiffInputStream& rStrm ) { - importCellHeader( rStrm, false ); - maCurrCell.mnCellType = XML_s; - mrSheetData.setStringCell( maCurrCell.mxCell, maCurrCell.maAddress, rStrm.readInt32(), maCurrCell.mnXfId ); - mrSheetData.setCellFormat( maCurrCell ); + if( readCellHeader( rStrm, false ) ) + { + maCellData.mnCellType = XML_s; + mrSheetData.setStringCell( maCellData.maCellAddr, rStrm.readInt32(), maCellData.mnXfId ); + mrSheetData.setCellFormat( maCellData ); + } } void BiffSheetDataContext::importMultBlank( BiffInputStream& rStrm ) { BinAddress aAddr; - for( rStrm >> aAddr; rStrm.getRemaining() > 2; ++aAddr.mnCol ) - { - setCurrCell( aAddr ); - importXfId( rStrm, false ); - mrSheetData.setCellFormat( maCurrCell ); - } + bool bValidAddr = true; + for( rStrm >> aAddr; bValidAddr && (rStrm.getRemaining() > 2); ++aAddr.mnCol ) + if( (bValidAddr = readCellXfId( aAddr, rStrm, false )) == true ) + mrSheetData.setCellFormat( maCellData ); } void BiffSheetDataContext::importMultRk( BiffInputStream& rStrm ) { BinAddress aAddr; - for( rStrm >> aAddr; rStrm.getRemaining() > 2; ++aAddr.mnCol ) + bool bValidAddr = true; + for( rStrm >> aAddr; bValidAddr && (rStrm.getRemaining() > 2); ++aAddr.mnCol ) { - setCurrCell( aAddr ); - maCurrCell.mnCellType = XML_n; - importXfId( rStrm, false ); - sal_Int32 nRkValue = rStrm.readInt32(); - mrSheetData.setValueCell( maCurrCell.mxCell, maCurrCell.maAddress, BiffHelper::calcDoubleFromRk( nRkValue ) ); - mrSheetData.setCellFormat( maCurrCell ); + if( (bValidAddr = readCellXfId( aAddr, rStrm, false )) == true ) + { + maCellData.mnCellType = XML_n; + sal_Int32 nRkValue = rStrm.readInt32(); + mrSheetData.setValueCell( maCellData.maCellAddr, BiffHelper::calcDoubleFromRk( nRkValue ) ); + mrSheetData.setCellFormat( maCellData ); + } } } void BiffSheetDataContext::importNumber( BiffInputStream& rStrm ) { - importCellHeader( rStrm, rStrm.getRecId() == BIFF2_ID_NUMBER ); - maCurrCell.mnCellType = XML_n; - mrSheetData.setValueCell( maCurrCell.mxCell, maCurrCell.maAddress, rStrm.readDouble() ); - mrSheetData.setCellFormat( maCurrCell ); + if( readCellHeader( rStrm, rStrm.getRecId() == BIFF2_ID_NUMBER ) ) + { + maCellData.mnCellType = XML_n; + mrSheetData.setValueCell( maCellData.maCellAddr, rStrm.readDouble() ); + mrSheetData.setCellFormat( maCellData ); + } } void BiffSheetDataContext::importRk( BiffInputStream& rStrm ) { - importCellHeader( rStrm, false ); - maCurrCell.mnCellType = XML_n; - mrSheetData.setValueCell( maCurrCell.mxCell, maCurrCell.maAddress, BiffHelper::calcDoubleFromRk( rStrm.readInt32() ) ); - mrSheetData.setCellFormat( maCurrCell ); -} - -void BiffSheetDataContext::importRow( BiffInputStream& rStrm ) -{ - RowModel aModel; - - sal_uInt16 nRow, nHeight; - rStrm >> nRow; - rStrm.skip( 4 ); - rStrm >> nHeight; - if( getBiff() == BIFF2 ) + if( readCellHeader( rStrm, false ) ) { - rStrm.skip( 2 ); - aModel.mbCustomFormat = rStrm.readuInt8() == BIFF2_ROW_CUSTOMFORMAT; - if( aModel.mbCustomFormat ) - { - rStrm.skip( 5 ); - aModel.mnXfId = rStrm.readuInt16(); - } - } - else - { - rStrm.skip( 4 ); - sal_uInt32 nFlags = rStrm.readuInt32(); - aModel.mnXfId = extractValue< sal_Int32 >( nFlags, 16, 12 ); - aModel.mnLevel = extractValue< sal_Int32 >( nFlags, 0, 3 ); - aModel.mbCustomFormat = getFlag( nFlags, BIFF_ROW_CUSTOMFORMAT ); - aModel.mbCustomHeight = getFlag( nFlags, BIFF_ROW_CUSTOMHEIGHT ); - aModel.mbShowPhonetic = getFlag( nFlags, BIFF_ROW_SHOWPHONETIC ); - aModel.mbHidden = getFlag( nFlags, BIFF_ROW_HIDDEN ); - aModel.mbCollapsed = getFlag( nFlags, BIFF_ROW_COLLAPSED ); - aModel.mbThickTop = getFlag( nFlags, BIFF_ROW_THICKTOP ); - aModel.mbThickBottom = getFlag( nFlags, BIFF_ROW_THICKBOTTOM ); + maCellData.mnCellType = XML_n; + mrSheetData.setValueCell( maCellData.maCellAddr, BiffHelper::calcDoubleFromRk( rStrm.readInt32() ) ); + mrSheetData.setCellFormat( maCellData ); } - - // row index is 0-based in BIFF, but RowModel expects 1-based - aModel.mnFirstRow = aModel.mnLastRow = nRow + 1; - // row height is in twips in BIFF, convert to points - aModel.mfHeight = (nHeight & BIFF_ROW_HEIGHTMASK) / 20.0; - // set row properties in the current sheet - setRowModel( aModel ); } void BiffSheetDataContext::importArray( BiffInputStream& rStrm ) { - BinRange aRange; - aRange.read( rStrm, false ); // columns always 8-bit - CellRangeAddress aArrayRange; - if( getAddressConverter().convertToCellRange( aArrayRange, aRange, getSheetIndex(), true, true ) ) + if( readFormulaRef( rStrm ) && maFmlaData.isValidArrayRef( maCellData.maCellAddr ) ) { rStrm.skip( mnArraySkipSize ); - CellAddress aBaseAddr( aArrayRange.Sheet, aArrayRange.StartColumn, aArrayRange.StartRow ); - ApiTokenSequence aTokens = getFormulaParser().importFormula( aBaseAddr, FORMULATYPE_ARRAY, rStrm ); - mrSheetData.setArrayFormula( aArrayRange, aTokens ); + ApiTokenSequence aTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_ARRAY, rStrm ); + mrSheetData.createArrayFormula( maFmlaData.maFormulaRef, aTokens ); } } -void BiffSheetDataContext::importSharedFmla( BiffInputStream& rStrm ) -{ - mrSheetData.importSharedFmla( rStrm, maCurrCell.maAddress ); -} - void BiffSheetDataContext::importDataTable( BiffInputStream& rStrm ) { - BinRange aRange; - aRange.read( rStrm, false ); // columns always 8-bit - CellRangeAddress aTableRange; - if( getAddressConverter().convertToCellRange( aTableRange, aRange, getSheetIndex(), true, true ) ) + if( readFormulaRef( rStrm ) ) { DataTableModel aModel; BinAddress aRef1, aRef2; @@ -939,7 +942,17 @@ void BiffSheetDataContext::importDataTable( BiffInputStream& rStrm ) } aModel.maRef1 = FormulaProcessorBase::generateAddress2dString( aRef1, false ); aModel.maRef2 = FormulaProcessorBase::generateAddress2dString( aRef2, false ); - mrSheetData.setTableOperation( aTableRange, aModel ); + mrSheetData.createTableOperation( maFmlaData.maFormulaRef, aModel ); + } +} + +void BiffSheetDataContext::importSharedFmla( BiffInputStream& rStrm ) +{ + if( readFormulaRef( rStrm ) && maFmlaData.isValidSharedRef( maCellData.maCellAddr ) ) + { + rStrm.skip( 2 ); // flags + ApiTokenSequence aTokens = mrFormulaParser.importFormula( maCellData.maCellAddr, FORMULATYPE_SHAREDFORMULA, rStrm ); + mrSheetData.createSharedFormula( maCellData.maCellAddr, aTokens ); } } diff --git a/oox/source/xls/worksheethelper.cxx b/oox/source/xls/worksheethelper.cxx index 778adcff24ab..bba52fb0d8f2 100644 --- a/oox/source/xls/worksheethelper.cxx +++ b/oox/source/xls/worksheethelper.cxx @@ -184,27 +184,6 @@ void ValueRangeSet::intersect( ValueRangeVector& orRanges, sal_Int32 nFirst, sal // ============================================================================ // ============================================================================ -void CellModel::reset() -{ - mxCell.clear(); - maValue = maFormula = maFormulaRef = OUString(); - mnCellType = mnFormulaType = XML_TOKEN_INVALID; - mnSharedId = mnXfId = mnNumFmtId = -1; - mbShowPhonetic = false; -} - -// ---------------------------------------------------------------------------- - -DataTableModel::DataTableModel() : - mb2dTable( false ), - mbRowTable( false ), - mbRef1Deleted( false ), - mbRef2Deleted( false ) -{ -} - -// ---------------------------------------------------------------------------- - ColumnModel::ColumnModel() : mnFirstCol( -1 ), mnLastCol( -1 ), @@ -1430,28 +1409,6 @@ Reference< XCell > WorksheetHelper::getCell( const CellAddress& rAddress ) const return mrSheetGlob.getCell( rAddress ); } -Reference< XCell > WorksheetHelper::getCell( const OUString& rAddressStr, CellAddress* opAddress ) const -{ - CellAddress aAddress; - if( getAddressConverter().convertToCellAddress( aAddress, rAddressStr, mrSheetGlob.getSheetIndex(), true ) ) - { - if( opAddress ) *opAddress = aAddress; - return mrSheetGlob.getCell( aAddress ); - } - return Reference< XCell >(); -} - -Reference< XCell > WorksheetHelper::getCell( const BinAddress& rBinAddress, CellAddress* opAddress ) const -{ - CellAddress aAddress; - if( getAddressConverter().convertToCellAddress( aAddress, rBinAddress, mrSheetGlob.getSheetIndex(), true ) ) - { - if( opAddress ) *opAddress = aAddress; - return mrSheetGlob.getCell( aAddress ); - } - return Reference< XCell >(); -} - Reference< XCellRange > WorksheetHelper::getCellRange( const CellRangeAddress& rRange ) const { return mrSheetGlob.getCellRange( rRange ); |