diff options
Diffstat (limited to 'sc/source/filter/inc/xetable.hxx')
-rw-r--r-- | sc/source/filter/inc/xetable.hxx | 1028 |
1 files changed, 1028 insertions, 0 deletions
diff --git a/sc/source/filter/inc/xetable.hxx b/sc/source/filter/inc/xetable.hxx new file mode 100644 index 000000000..ed16140f6 --- /dev/null +++ b/sc/source/filter/inc/xetable.hxx @@ -0,0 +1,1028 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "xltable.hxx" + +#include <vector> +#include "xladdress.hxx" +#include "xecontent.hxx" +#include "xerecord.hxx" +#include "xestyle.hxx" +#include "xlformula.hxx" + +#include <map> +#include <memory> +#include <unordered_map> +#include <o3tl/sorted_vector.hxx> + +class XclExtLst; + +/* ============================================================================ +Export of cell tables including row and column description. +- Managing all used and formatted cells in a sheet. +- Row and column properties, i.e. width/height, visibility. +- Find default row formatting and default column formatting. +- Merged cell ranges. +============================================================================ */ + +// Helper records for cell records + +/** Represents a STRING record that contains the result of a string formula. */ +class XclExpStringRec : public XclExpRecord +{ +public: + explicit XclExpStringRec( const XclExpRoot& rRoot, const OUString& rResult ); + +private: + virtual void WriteBody( XclExpStream& rStrm ) override; + +private: + XclExpStringRef mxResult; +}; + +// Additional records for special formula ranges + +/** Base record for additional range formula records (i.e. ARRAY, SHRFMLA). */ +class XclExpRangeFmlaBase : public XclExpRecord +{ +public: + /** Returns true, if the passed cell position is equal to own base position. */ + bool IsBasePos( sal_uInt16 nXclCol, sal_uInt32 nXclRow ) const; + + /** Derived classes create the token array for a corresponding FORMULA cell record. */ + virtual XclTokenArrayRef CreateCellTokenArray( const XclExpRoot& rRoot ) const = 0; + /** Derived classes return true, if the own formula contains volatile functions. */ + virtual bool IsVolatile() const = 0; + +protected: + /** Constructs the record with a single cell. */ + explicit XclExpRangeFmlaBase( + sal_uInt16 nRecId, sal_uInt32 nRecSize, const ScAddress& rScPos ); + /** Constructs the record with a cell range. */ + explicit XclExpRangeFmlaBase( + sal_uInt16 nRecId, sal_uInt32 nRecSize, const ScRange& rScRange ); + + /** Extends the cell range to include the passed cell address. */ + void Extend( const ScAddress& rScPos ); + + /** Writes the range address covered by this record. */ + void WriteRangeAddress( XclExpStream& rStrm ) const; + +protected: + XclRange maXclRange; /// Range described by this record. + XclAddress maBaseXclPos; /// Address of base cell (first FORMULA record). +}; + +typedef rtl::Reference< XclExpRangeFmlaBase > XclExpRangeFmlaRef; + +// Array formulas ============================================================= + +class ScTokenArray; + +/** Represents an ARRAY record that contains the token array of a matrix formula. + + An ARRAY record is stored following the first FORMULA record that is part + of a matrix formula. All FORMULA records of a matrix formula contain a + reference to the ARRAY record, while the ARRAY record contains the formula + token array used by all formulas. + */ +class XclExpArray : public XclExpRangeFmlaBase +{ +public: + explicit XclExpArray( const XclTokenArrayRef& xTokArr, const ScRange& rScRange ); + + /** Creates and returns the token array for a corresponding FORMULA cell record. */ + virtual XclTokenArrayRef CreateCellTokenArray( const XclExpRoot& rRoot ) const override; + /** Returns true, if the array formula contains volatile functions. */ + virtual bool IsVolatile() const override; + +private: + virtual void WriteBody( XclExpStream& rStrm ) override; + +private: + XclTokenArrayRef mxTokArr; /// The token array of a matrix formula. +}; + +typedef rtl::Reference< XclExpArray > XclExpArrayRef; + +/** Caches all ARRAY records. */ +class XclExpArrayBuffer : protected XclExpRoot +{ +public: + explicit XclExpArrayBuffer( const XclExpRoot& rRoot ); + + /** Inserts a new ARRAY record into the buffer and returns it. */ + XclExpArrayRef CreateArray( const ScTokenArray& rScTokArr, const ScRange& rScRange ); + /** Tries to find an ARRAY record that corresponds to an ocMatRef token. */ + XclExpArrayRef FindArray( const ScTokenArray& rScTokArr, const ScAddress& rBasePos ) const; + +private: + typedef ::std::map< ScAddress, XclExpArrayRef > XclExpArrayMap; + XclExpArrayMap maRecMap; /// Map containing the ARRAY records. +}; + +// Shared formulas ============================================================ + +/** Represents a SHRFMLA record that contains the token array of a shared formula. + + A SHRFMLA record is stored following the first FORMULA record that is part + of a shared formula. All FORMULA records of a shared formula contain a + reference to the SHRFMLA record, while the SHRFMLA record contains the + formula token array used by all formulas. + */ +class XclExpShrfmla : public XclExpRangeFmlaBase +{ +public: + /** Creates a SHRFMLA record that consists of the passed cell address only. */ + explicit XclExpShrfmla( const XclTokenArrayRef& xTokArr, const ScAddress& rScPos ); + + /** Extends the cell range to include the passed cell address. */ + void ExtendRange( const ScAddress& rScPos ); + + /** Creates and returns the token array for a corresponding FORMULA cell record. */ + virtual XclTokenArrayRef CreateCellTokenArray( const XclExpRoot& rRoot ) const override; + /** Returns true, if the shared formula contains volatile functions. */ + virtual bool IsVolatile() const override; + +private: + virtual void WriteBody( XclExpStream& rStrm ) override; + +private: + XclTokenArrayRef mxTokArr; /// The token array of a shared formula. + sal_uInt8 mnUsedCount; /// Number of FORMULA records referring to this record. +}; + +typedef rtl::Reference< XclExpShrfmla > XclExpShrfmlaRef; + +/** Caches all SHRFMLA records and provides functions to update their ranges. */ +class XclExpShrfmlaBuffer : protected XclExpRoot +{ +public: + explicit XclExpShrfmlaBuffer( const XclExpRoot& rRoot ); + + /** Tries to create a new or to update an existing SHRFMLA record. + @return An empty reference, if the passed token array does not contain + a shared formula. If the token array is a shared formula, this + function updates its cell range to include the passed cell position, + if there is a SHRFMLA record for the passed token array; otherwise + this function creates and returns a new SHRFMLA record. */ + XclExpShrfmlaRef CreateOrExtendShrfmla( const ScFormulaCell& rScCell, const ScAddress& rScPos ); + +private: + /** + * Check for presence of token that's not allowed in Excel's shared + * formula. Refer to the "SharedParsedFormula" section of [MS-XLS] spec + * for more info. + */ + bool IsValidTokenArray( const ScTokenArray& rArray ) const; + + typedef std::unordered_map<const ScTokenArray*, XclExpShrfmlaRef> TokensType; + typedef o3tl::sorted_vector<const ScTokenArray*> BadTokenArraysType; + + TokensType maRecMap; /// Map containing the SHRFMLA records. + BadTokenArraysType maBadTokens; /// shared tokens we should *not* export as SHRFMLA +}; + +// Multiple operations ======================================================== + +/** Represents a TABLEOP record for a multiple operations range. */ +class XclExpTableop : public XclExpRangeFmlaBase +{ +public: + explicit XclExpTableop( const ScAddress& rScPos, + const XclMultipleOpRefs& rRefs, sal_uInt8 nScMode ); + + /** Returns true, if the cell range has been extended to the passed position. + @descr All references passed in rRefs must fit the ranges passed in the constructor. */ + bool TryExtend( const ScAddress& rScPos, const XclMultipleOpRefs& rRefs ); + + /** Finalizes the record. Tests on valid cell range and reference addresses. */ + void Finalize(); + + /** Creates and returns the token array for a corresponding FORMULA cell record. */ + virtual XclTokenArrayRef CreateCellTokenArray( const XclExpRoot& rRoot ) const override; + /** Returns true, if the multiple operations range is volatile. */ + virtual bool IsVolatile() const override; + /** Writes the record if it is valid. */ + virtual void Save( XclExpStream& rStrm ) override; + +private: + /** Returns true, if the passed cell position can be appended to this record. */ + bool IsAppendable( sal_uInt16 nXclCol, sal_uInt16 nXclRow ) const; + + /** Writes the contents of the TABLEOP record. */ + virtual void WriteBody( XclExpStream& rStrm ) override; + +private: + sal_uInt16 mnLastAppXclCol;/// Column index of last appended cell. + sal_uInt16 mnColInpXclCol; /// Column index of column input cell. + sal_uInt32 mnColInpXclRow; /// Row index of column input cell. + sal_uInt16 mnRowInpXclCol; /// Column index of row input cell. + sal_uInt32 mnRowInpXclRow; /// Row index of row input cell. + sal_uInt8 mnScMode; /// Type of the multiple operation (Calc constant). + bool mbValid; /// true = Contains valid references. +}; + +typedef rtl::Reference< XclExpTableop > XclExpTableopRef; + +/** Contains all created TABLEOP records and supports creating or updating them. */ +class XclExpTableopBuffer : protected XclExpRoot +{ +public: + explicit XclExpTableopBuffer( const XclExpRoot& rRoot ); + + /** Tries to update an existing or to create a new TABLEOP record. + @return Reference to the TABLEOP record for this cell (existing or new), + or an empty reference, if rScTokArr does not contain a multiple + operations formula. */ + XclExpTableopRef CreateOrExtendTableop( + const ScTokenArray& rScTokArr, const ScAddress& rScPos ); + + /** Finalizes all contained TABLEOP records. */ + void Finalize(); + +private: + /** Tries to create a new TABLEOP record, if rRefs contains valid references. */ + XclExpTableopRef TryCreate( const ScAddress& rScPos, const XclMultipleOpRefs& rRefs ); + +private: + XclExpRecordList< XclExpTableop > maTableopList; /// List of all TABLEOP records. +}; + +// Cell records + +/** The base class of all cell records. */ +class XclExpCellBase : public XclExpRecord +{ +public: + /** Returns the (first) address of the cell(s). */ + const XclAddress& GetXclPos() const { return maXclPos; } + /** Returns the (first) Excel column index of the cell(s). */ + sal_uInt16 GetXclCol() const { return maXclPos.mnCol; } + /** Returns the Excel row index of the cell. */ + sal_uInt32 GetXclRow() const { return maXclPos.mnRow; } + + /** Derived classes return the column index of the last contained cell. */ + virtual sal_uInt16 GetLastXclCol() const = 0; + /** Derived classes return the XF identifier of the first contained cell. */ + virtual sal_uInt32 GetFirstXFId() const = 0; + /** Derived classes return true, if this record does not contain at least one valid cell. */ + virtual bool IsEmpty() const = 0; + /** Derived classes return whether the cell contains multi-line text. */ + virtual bool IsMultiLineText() const; + + /** Derived classes try to merge the contents of the passed cell to own data. */ + virtual bool TryMerge( const XclExpCellBase& rCell ); + /** Derived classes convert the XF identifier(s) into the Excel XF index(es). + @param rXFIndexes The converted XF index(es) are inserted here. */ + virtual void ConvertXFIndexes( const XclExpRoot& rRoot ) = 0; + /** Derived classes for blank cells insert the Excel XF index(es) into the passed vector. */ + virtual void GetBlankXFIndexes( ScfUInt16Vec& rXFIndexes ) const; + /** Derived classes for blank cells remove unused Excel XF index(es). */ + virtual void RemoveUnusedBlankCells( const ScfUInt16Vec& rXFIndexes, size_t nStartAllNotFound ); + +protected: + explicit XclExpCellBase( + sal_uInt16 nRecId, std::size_t nContSize, const XclAddress& rXclPos ); + + /** Sets this record to a new column position. */ + void SetXclCol( sal_uInt16 nXclCol ) { maXclPos.mnCol = nXclCol; } + +private: + XclAddress maXclPos; /// Address of the cell. +}; + +typedef rtl::Reference< XclExpCellBase > XclExpCellRef; + +// Single cell records ======================================================== + +/** Base class for all cell records not supporting multiple contents. */ +class XclExpSingleCellBase : public XclExpCellBase +{ +public: + /** Returns the last column, which is equal to the first column for single cells. */ + virtual sal_uInt16 GetLastXclCol() const override; + /** Return the XF identifier of the cell. */ + virtual sal_uInt32 GetFirstXFId() const override; + /** Returns true, if this record does not contain at least one valid cell. */ + virtual bool IsEmpty() const override; + /** Converts the XF identifier into the Excel XF index. */ + virtual void ConvertXFIndexes( const XclExpRoot& rRoot ) override; + /** Writes cell address, XF index, and calls WriteContents() for each cell. */ + virtual void Save( XclExpStream& rStrm ) override; + +protected: + explicit XclExpSingleCellBase( sal_uInt16 nRecId, std::size_t nContSize, + const XclAddress& rXclPos, sal_uInt32 nXFId ); + + explicit XclExpSingleCellBase( const XclExpRoot& rRoot, + sal_uInt16 nRecId, std::size_t nContSize, const XclAddress& rXclPos, + const ScPatternAttr* pPattern, sal_Int16 nScript, sal_uInt32 nForcedXFId ); + + void SetContSize( std::size_t nContSize ) { mnContSize = nContSize; } + std::size_t GetContSize() const { return mnContSize; } + + void SetXFId( sal_uInt32 nXFId ) { maXFId.mnXFId = nXFId; } + sal_uInt32 GetXFId() const { return maXFId.mnXFId; } + +private: + /** Writes cell address, XF index, and calls WriteContents() for each cell. */ + virtual void WriteBody( XclExpStream& rStrm ) override; + /** Derived classes write the contents of the specified cell (without XF index). */ + virtual void WriteContents( XclExpStream& rStrm ) = 0; + +private: + XclExpXFId maXFId; /// The XF identifier of the cell formatting. + std::size_t mnContSize; /// The size of the cell contents. +}; + +/** Represents a NUMBER record that describes a cell with a double value. */ +class XclExpNumberCell : public XclExpSingleCellBase +{ +public: + explicit XclExpNumberCell( const XclExpRoot& rRoot, const XclAddress& rXclPos, + const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId, + double fValue ); + + virtual void SaveXml( XclExpXmlStream& rStrm ) override; +private: + virtual void WriteContents( XclExpStream& rStrm ) override; + +private: + double mfValue; /// The cell value. +}; + +/** Represents a BOOLERR record that describes a cell with a Boolean value. */ +class XclExpBooleanCell : public XclExpSingleCellBase +{ +public: + explicit XclExpBooleanCell( const XclExpRoot& rRoot, const XclAddress& rXclPos, + const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId, + bool bValue ); + + virtual void SaveXml( XclExpXmlStream& rStrm ) override; +private: + virtual void WriteContents( XclExpStream& rStrm ) override; + +private: + bool mbValue; /// The cell value. +}; + +class XclExpHyperlinkHelper; +class EditTextObject; + +/** Represents a text cell record. + + May contain a BIFF2-BIFF7 LABEL record for a simple string, or a BIFF2-BIFF7 + RSTRING record for a formatted string, or a BIFF8 LABELSST string for any + string (simply stores a reference to the Shared String Table). + */ +class XclExpLabelCell : public XclExpSingleCellBase +{ +public: + /** Constructs the record from an unformatted Calc string cell. */ + explicit XclExpLabelCell( const XclExpRoot& rRoot, const XclAddress& rXclPos, + const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId, + const OUString& rStr ); + + /** Constructs the record from a formatted Calc edit cell. */ + explicit XclExpLabelCell( const XclExpRoot& rRoot, const XclAddress& rXclPos, + const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId, + const EditTextObject* pEditText, XclExpHyperlinkHelper& rHlinkHelper ); + + /** Returns true if the cell contains multi-line text. */ + virtual bool IsMultiLineText() const override; + + virtual void SaveXml( XclExpXmlStream& rStrm ) override; +private: + /** Initializes the record contents. Called from constructors. */ + void Init( const XclExpRoot& rRoot, + const ScPatternAttr* pPattern, XclExpStringRef const & xText ); + + virtual void WriteContents( XclExpStream& rStrm ) override; + +private: + XclExpStringRef mxText; /// The cell text. + sal_uInt32 mnSstIndex; /// Index into Shared String Table (only used for BIFF8). + bool mbLineBreak; /// True = cell has automatic linebreaks enabled. +}; + +class ScFormulaCell; + +/** Represents a FORMULA record that describes a cell with a formula. */ +class XclExpFormulaCell : public XclExpSingleCellBase +{ +public: + explicit XclExpFormulaCell( const XclExpRoot& rRoot, const XclAddress& rXclPos, + const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId, + const ScFormulaCell& rScFmlaCell, + XclExpArrayBuffer& rArrayBfr, + XclExpShrfmlaBuffer& rShrfmlaBfr, + XclExpTableopBuffer& rTableopBfr ); + + /** Writes the FORMULA record and additional records related to the formula. */ + virtual void Save( XclExpStream& rStrm ) override; + virtual void SaveXml( XclExpXmlStream& rStrm ) override; + +private: + virtual void WriteContents( XclExpStream& rStrm ) override; + +private: + ScFormulaCell& mrScFmlaCell; /// The Calc formula cell. + XclTokenArrayRef mxTokArr; /// The token array of the formula. + XclExpRangeFmlaRef mxAddRec; /// Additional record for matrix/shared formulas. + XclExpRecordRef mxStringRec; /// STRING record for string result. +}; + +// Multiple cell records ====================================================== + +struct XclExpMultiXFId : public XclExpXFId +{ + sal_uInt16 mnCount; /// Number of XF identifiers. + + explicit XclExpMultiXFId( sal_uInt32 nXFId, sal_uInt16 nCount = 1 ) : + XclExpXFId( nXFId ), mnCount( nCount ) {} +}; + +/** Base class for all cell records supporting multiple contents. */ +class XclExpMultiCellBase : public XclExpCellBase +{ +public: + /** Returns the column index of the last cell this record describes. */ + virtual sal_uInt16 GetLastXclCol() const override; + /** Return the XF identifier of the first contained cell. */ + virtual sal_uInt32 GetFirstXFId() const override; + /** Returns true, if this record does not contain at least one valid cell. */ + virtual bool IsEmpty() const override; + + /** Convert all XF identifiers into the Excel XF indexes. */ + virtual void ConvertXFIndexes( const XclExpRoot& rRoot ) override; + /** Writes the record, calls WriteContents() for each contained cell. + @descr May write several records, if unused XF indexes are contained. */ + virtual void Save( XclExpStream& rStrm ) override; + virtual void SaveXml( XclExpXmlStream& rStrm ) override; + +protected: + explicit XclExpMultiCellBase( sal_uInt16 nRecId, sal_uInt16 nMulRecId, + std::size_t nContSize, const XclAddress& rXclPos ); + + /** Returns the number of cells this record represents. */ + sal_uInt16 GetCellCount() const; + + /** Appends the passed XF identifier nCount times to the list of XF identifiers. */ + void AppendXFId( const XclExpMultiXFId& rXFId ); + /** Appends the passed cell format nCount times to the list of XF identifiers. */ + void AppendXFId( const XclExpRoot& rRoot, + const ScPatternAttr* pPattern, sal_uInt16 nScript, + sal_uInt32 nForcedXFId, sal_uInt16 nCount = 1 ); + + /** Tries to merge the XF ID list of the passed cell with the own list. */ + bool TryMergeXFIds( const XclExpMultiCellBase& rCell ); + /** Inserts the Excel XF index(es) into the passed vector. */ + void GetXFIndexes( ScfUInt16Vec& rXFIndexes ) const; + + /** Removes unused Excel XF index(es). + @param rXFIndexes Specifies which XF indexes are used. + @param nStartAllNotFound Index in rXFIndexes which starts EXC_XF_NOTFOUND until the end. + */ + void RemoveUnusedXFIndexes( const ScfUInt16Vec& rXFIndexes, size_t nStartAllNotFound ); + + /** Return starting column at which all indexes until the end are EXC_XF_DEFAULTCELL .*/ + sal_uInt16 GetStartColAllDefaultCell() const; + +private: + /** Derived classes write the remaining contents of the specified cell (without XF index). + @param nRelCol Relative column index (starts with 0 for first cell of this record). */ + virtual void WriteContents( XclExpStream& rStrm, sal_uInt16 nRelCol ) = 0; + virtual void WriteXmlContents( XclExpXmlStream& rStrm, const XclAddress& rAddress, sal_uInt32 nXFId, sal_uInt16 nRelCol ) = 0; + +private: + typedef ::std::vector< XclExpMultiXFId > XclExpMultiXFIdDeq; + + sal_uInt16 mnMulRecId; /// Record ID for multiple record variant. + std::size_t mnContSize; /// Data size of contents for one cell + XclExpMultiXFIdDeq maXFIds; /// The XF identifiers of the cell formatting. +}; + +/** Represents a BLANK or MULBLANK record that describes empty but formatted cells. */ +class XclExpBlankCell : public XclExpMultiCellBase +{ +public: + explicit XclExpBlankCell( const XclAddress& rXclPos, const XclExpMultiXFId& rXFId ); + + explicit XclExpBlankCell( const XclExpRoot& rRoot, + const XclAddress& rXclPos, sal_uInt16 nLastXclCol, + const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId ); + + /** Tries to merge the contents of the passed cell to own data. */ + virtual bool TryMerge( const XclExpCellBase& rCell ) override; + /** Inserts the Excel XF index(es) into the passed vector. */ + virtual void GetBlankXFIndexes( ScfUInt16Vec& rXFIndexes ) const override; + /** Tries to remove unused Excel XF index(es). */ + virtual void RemoveUnusedBlankCells( const ScfUInt16Vec& rXFIndexes, size_t nStartAllNotFound ) override; + + using XclExpMultiCellBase::GetStartColAllDefaultCell; + +private: + /** Writes the remaining contents of the specified cell (without XF index). */ + virtual void WriteContents( XclExpStream& rStrm, sal_uInt16 nRelCol ) override; + virtual void WriteXmlContents( XclExpXmlStream& rStrm, const XclAddress& rAddress, sal_uInt32 nXFId, sal_uInt16 nRelCol ) override; +}; + +/** Represents an RK or MULRK record that describes cells with a compressed double values. */ +class XclExpRkCell : public XclExpMultiCellBase +{ +public: + explicit XclExpRkCell( const XclExpRoot& rRoot, const XclAddress& rXclPos, + const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId, + sal_Int32 nRkValue ); + + /** Tries to merge the contents of the passed cell to own data. */ + virtual bool TryMerge( const XclExpCellBase& rCell ) override; + +private: + /** Writes the remaining contents of the specified cell (without XF index). */ + virtual void WriteContents( XclExpStream& rStrm, sal_uInt16 nRelCol ) override; + virtual void WriteXmlContents( XclExpXmlStream& rStrm, const XclAddress& rAddress, sal_uInt32 nXFId, sal_uInt16 nRelCol ) override; + +private: + ScfInt32Vec maRkValues; /// The cell values. +}; + +// Rows and Columns + +class ScOutlineArray; + +/** Base class for buffers containing row or column outline data. */ +class XclExpOutlineBuffer +{ +public: + /** Returns true, if a collapsed group ends at the last processed position. */ + bool IsCollapsed() const { return mbCurrCollapse; } + /** Returns the highest level of an open group at the last processed position. */ + sal_uInt8 GetLevel() const { return ::std::min( mnCurrLevel, EXC_OUTLINE_MAX ); } + +protected: + /** Constructs the outline buffer. + @param bRows true = Process row outline array; false = Process column outline array. */ + explicit XclExpOutlineBuffer( const XclExpRoot& rRoot, bool bRows ); + + /** Updates the current state by processing the settings at the passed Calc position. */ + void UpdateColRow( SCCOLROW nScPos ); + +private: + /** Data about an outline level. */ + struct XclExpLevelInfo + { + SCCOLROW mnScEndPos; /// The end position of a group in a level. + bool mbHidden; /// true = Group in this level is hidden. + explicit XclExpLevelInfo() : mnScEndPos( 0 ), mbHidden( false ) {} + }; + + const ScOutlineArray* mpScOLArray; /// Pointer to Calc outline array. + std::vector< XclExpLevelInfo > + maLevelInfos; /// Info for current row and all levels. + sal_uInt8 mnCurrLevel; /// Highest level of an open group for current position. + bool mbCurrCollapse; /// true = Collapsed group ends at current position. +}; + +/** The outline buffer for column outlines. */ +class XclExpColOutlineBuffer : public XclExpOutlineBuffer +{ +public: + explicit XclExpColOutlineBuffer( const XclExpRoot& rRoot ) : + XclExpOutlineBuffer( rRoot, false ) {} + + /** Updates the current state by processing the settings of the passed Calc column. */ + void Update( SCCOL nScCol ) + { UpdateColRow( static_cast< SCCOLROW >( nScCol ) ); } +}; + +/** The outline buffer for row outlines. */ +class XclExpRowOutlineBuffer : public XclExpOutlineBuffer +{ +public: + explicit XclExpRowOutlineBuffer( const XclExpRoot& rRoot ) : + XclExpOutlineBuffer( rRoot, true ) {} + + /** Updates the current state by processing the settings of the passed Calc row. */ + void Update( SCROW nScRow ) + { UpdateColRow( static_cast< SCCOLROW >( nScRow ) ); } +}; + +/** Represents a GUTS record containing the level count of row and column outlines. */ +class XclExpGuts : public XclExpRecord +{ +public: + explicit XclExpGuts( const XclExpRoot& rRoot ); + +private: + virtual void WriteBody( XclExpStream& rStrm ) override; + +private: + sal_uInt16 mnColLevels; /// Number of visible column outline levels. + sal_uInt16 mnColWidth; /// Width of column outline area (pixels). + sal_uInt16 mnRowLevels; /// Number of visible row outline levels. + sal_uInt16 mnRowWidth; /// Width of row outline area (pixels). +}; + +/** Represents a DIMENSIONS record containing the used area of a sheet. */ +class XclExpDimensions : public XclExpRecord +{ +public: + explicit XclExpDimensions( const XclExpRoot& rRoot ); + + /** Sets the used area to the record. */ + void SetDimensions( + sal_uInt16 nFirstUsedXclCol, sal_uInt32 nFirstUsedXclRow, + sal_uInt16 nFirstFreeXclCol, sal_uInt32 nFirstFreeXclRow ); + + virtual void SaveXml( XclExpXmlStream& rStrm ) override; +private: + /** Writes the contents of the DIMENSIONS record. */ + virtual void WriteBody( XclExpStream& rStrm ) override; + +private: + const XclExpRoot& mrRoot; + sal_uInt32 mnFirstUsedXclRow; /// First used row. + sal_uInt32 mnFirstFreeXclRow; /// First unused row after used area. + sal_uInt16 mnFirstUsedXclCol; /// First used column. + sal_uInt16 mnFirstFreeXclCol; /// First free column after used area. +}; + +/** Represents the DEFCOLWIDTH record containing the default column width of a sheet. + + Excel stores the default column width in entire character widths of the '0' + character using the application default font (i.e. the default width is 10, + if the '0' character fits 10 times into a cell in a column with default + width. + + Half of character width is reserved for non character display. + It is margin padding (two on each side) and padding for the gridlines. + + The IsDefWidth() function returns true, if the passed width (measured in + 1/256 of the width of the '0' character) could be converted exactly to the + default width. If the passed width is rounded up or down to get the default + width, the function returns false. + */ +class XclExpDefcolwidth : public XclExpDoubleRecord, protected XclExpRoot +{ +public: + explicit XclExpDefcolwidth( const XclExpRoot& rRoot ); + + /** Returns true, if the own default width exactly matches the passed width. */ + bool IsDefWidth( sal_uInt16 nXclColWidth ) const; + + /** Sets the passed column width (in 1/256 character width) as default width. */ + void SetDefWidth( sal_uInt16 nXclColWidth, bool bXLS ); + + virtual void Save(XclExpStream& rStrm) override; +}; + +/** Contains the column settings for a range of columns. + + After construction the record contains a temporary XF identifier returned + from the XF buffer. After creating the entire Excel document in memory, the + ConvertXFIndexes() function converts it into the real Excel XF index. + */ +class XclExpColinfo : public XclExpRecord, protected XclExpRoot +{ +public: + /** Constructs the record with the settings in the Calc document. */ + explicit XclExpColinfo( const XclExpRoot& rRoot, + SCCOL nScCol, SCROW nLastScRow, + XclExpColOutlineBuffer& rOutlineBfr ); + + /** Converts the XF identifier into the Excel XF index. */ + void ConvertXFIndexes(); + + /** Tries to merge this record with the passed record. + @descr Possible, if passed record directly follows this record and has equal contents. + @return true = This record is equal to passed record and has been updated. */ + bool TryMerge( const XclExpColinfo& rColInfo ); + + /** Returns the Excel width of the column(s). */ + sal_uInt16 GetColWidth() const { return mnWidth; } + /** Returns the final Excel XF index of the column(s). */ + sal_uInt16 GetXFIndex() const { return maXFId.mnXFIndex; } + /** Returns the number of columns represented by this record. */ + sal_uInt16 GetColCount() const { return mnLastXclCol - mnFirstXclCol + 1; } + + /** Returns true, if the column has default format and width. Also sets mbCustomWidth */ + bool IsDefault( const XclExpDefcolwidth& rDefColWidth ); + + virtual void SaveXml( XclExpXmlStream& rStrm ) override; + +private: + /** Writes the contents of this COLINFO record. */ + virtual void WriteBody( XclExpStream& rStrm ) override; + +private: + XclExpXFId maXFId; /// The XF identifier for column default format. + bool mbCustomWidth; /// True = Column width is different from default width + sal_uInt16 mnWidth; /// Excel width of the column. + sal_uInt16 mnScWidth; /// Calc width of the column. + sal_uInt16 mnFlags; /// Additional column flags. + sal_uInt8 mnOutlineLevel; /// Outline Level of column (for OOXML) + sal_uInt16 mnFirstXclCol; /// Index to first column. + sal_uInt16 mnLastXclCol; /// Index to last column. +}; + +/** Contains COLINFO records for all columns of a Calc sheet. + + On construction one COLINFO record per column is created. After creating + the entire Excel document in memory, the ConvertXFIndexes() function converts + all temporary XF identifiers into real Excel XF indexes and merges all equal + COLINFO records together. + */ +class XclExpColinfoBuffer : public XclExpRecordBase, protected XclExpRoot +{ +public: + explicit XclExpColinfoBuffer( const XclExpRoot& rRoot ); + + /** Initializes the buffer: finds settings and formatting of all columns. + @param nLastScRow Last row used to find default formatting. */ + void Initialize( SCROW nLastScRow ); + /** Converts the XF identifiers into the Excel XF indexes and merges equal columns. + @param rXFIndexes Returns the final XF indexes of all columns. */ + void Finalize( ScfUInt16Vec& rXFIndexes, bool bXLS ); + + /** Writes all COLINFO records of this buffer. */ + virtual void Save( XclExpStream& rStrm ) override; + virtual void SaveXml( XclExpXmlStream& rStrm ) override; + sal_uInt8 GetHighestOutlineLevel() const { return mnHighestOutlineLevel; } + double GetDefColWidth() const { return maDefcolwidth.GetValue(); } + +private: + typedef XclExpRecordList< XclExpColinfo > XclExpColinfoList; + typedef XclExpColinfoList::RecordRefType XclExpColinfoRef; + + XclExpColinfoList maColInfos; /// List of COLINFO records. + XclExpDefcolwidth maDefcolwidth; /// The DEFCOLWIDTH record. + XclExpColOutlineBuffer maOutlineBfr; /// Buffer for column outline groups. + sal_uInt8 mnHighestOutlineLevel; /// Highest number of outline levels for columns in sheet. +}; + +class XclExpRow; + +/** Contains all possible default row settings. */ +struct XclExpDefaultRowData +{ + sal_uInt16 mnFlags; /// Default flags for unspecified rows. + sal_uInt16 mnHeight; /// Default height for unspecified rows. + + explicit XclExpDefaultRowData(); + explicit XclExpDefaultRowData( const XclExpRow& rRow ); + + /** Returns true, if rows are hidden by default. */ + bool IsHidden() const { return ::get_flag( mnFlags, EXC_DEFROW_HIDDEN ); } + /** Returns true, if the rows have a manually set height by default. */ + bool IsUnsynced() const { return ::get_flag( mnFlags, EXC_DEFROW_UNSYNCED ); } +}; + +/** Represents a DEFROWHEIGHT record containing default format for unused rows. */ +class XclExpDefrowheight : public XclExpRecord +{ +public: + explicit XclExpDefrowheight(); + + /** Sets the passed default data as current record contents. */ + void SetDefaultData( const XclExpDefaultRowData& rDefData ); + XclExpDefaultRowData& GetDefaultData() { return maDefData; } +private: + /** Writes the contents of the record. */ + virtual void WriteBody( XclExpStream& rStrm ) override; + +private: + XclExpDefaultRowData maDefData; /// Record data. +}; + +/** Represents a ROW record and additionally contains all cells records of a row. + + This class contains all cell records of a row in a spreadsheet. There are 2 + cell records in Excel that support storing a range of cells in one record + (MULBLANK for multiple blank cells, and MULRK for multiple RK values). The + insertion functions try to merge a new inserted cell with existing + neighbors, if this is supported by the current type of cell record. + + The Finalize() function converts the XF identifiers of all cell records to + the final Excel XF indexes. Then a default + */ +class XclExpRow : public XclExpRecord, protected XclExpRoot +{ +public: + /** Constructs the ROW record and converts the Calc row settings. + @param bAlwaysEmpty true = This row will not be filled with blank cells + in the Finalize() function. */ + explicit XclExpRow( const XclExpRoot& rRoot, sal_uInt32 nXclRow, + XclExpRowOutlineBuffer& rOutlineBfr, bool bAlwaysEmpty, bool bHidden, sal_uInt16 nHeight ); + + /** Returns the excel row index of this ROW record. */ + sal_uInt32 GetXclRow() const { return mnXclRow; } + /** Returns the height of the row in twips. */ + sal_uInt16 GetHeight() const { return mnHeight; } + /** Returns true, if this row does not contain at least one valid cell. */ + bool IsEmpty() const { return maCellList.IsEmpty(); } + /** Returns true, if this row is hidden. */ + bool IsHidden() const { return ::get_flag( mnFlags, EXC_ROW_HIDDEN ); } + /** Returns true, if this row contains a manually set height. */ + bool IsUnsynced() const { return ::get_flag( mnFlags, EXC_ROW_UNSYNCED ); } + /** Returns true, if this row is enabled (will be exported). */ + bool IsEnabled() const { return mbEnabled; } + + /** Appends the passed cell object to this row. */ + void AppendCell( XclExpCellRef const & xCell, bool bIsMergedBase ); + + /** Converts all XF identifiers into the Excel XF indexes. */ + void Finalize( const ScfUInt16Vec& rColXFIndexes, + ScfUInt16Vec& aXFIndexes, + size_t nStartColAllDefault, + bool bUpdateProgress ); + + /** Returns the column index of the first used cell in this row. + @descr This function can only be called after Finalize(). */ + sal_uInt16 GetFirstUsedXclCol() const; + /** Returns the column index of the first unused cell following all used cells in this row. + @descr This function can only be called after Finalize(). */ + sal_uInt16 GetFirstFreeXclCol() const; + + /** Returns true, if this row may be omitted by using the DEFROWHEIGHT record. + @descr A row may be omitted, if it does not contain any cell or + explicit default cell formatting, and is not part of an outline. + This function can only be called after Finalize(). */ + bool IsDefaultable() const; + /** Disables this row, if it is defaultable and has the passed default format. + @descr Disabled rows will not be saved. + This function can only be called after Finalize(). */ + void DisableIfDefault( const XclExpDefaultRowData& rDefRowData ); + + /** Writes all cell records of this row. */ + void WriteCellList( XclExpStream& rStrm ); + + /** Writes the ROW record if the row is not disabled (see DisableIfDefault() function). */ + virtual void Save( XclExpStream& rStrm ) override; + virtual void SaveXml( XclExpXmlStream& rStrm ) override; + + sal_uInt32 GetXclRowRpt() const { return mnXclRowRpt; } + void SetXclRowRpt( sal_uInt32 nRpt ){ mnXclRowRpt = nRpt; } +private: + /** Inserts a cell at the specified list position, tries to merge with neighbors. */ + void InsertCell( XclExpCellRef xCell, size_t nPos, bool bIsMergedBase ); + + /** Writes the contents of the ROW record. */ + virtual void WriteBody( XclExpStream& rStrm ) override; + +private: + XclExpRecordList< XclExpCellBase > + maCellList; /// List of cell records for this row. + sal_uInt32 mnXclRow; /// Excel row index of this row. + sal_uInt16 mnHeight; /// Row height in twips. + sal_uInt16 mnFlags; /// Flags for the ROW record. + sal_uInt16 mnXFIndex; /// Default row formatting. + sal_uInt8 mnOutlineLevel; /// Outline Level of row (for OOXML) + sal_uInt32 mnXclRowRpt; + sal_uInt32 mnCurrentRow; + bool mbAlwaysEmpty; /// true = Do not add blank cells in Finalize(). + bool mbEnabled; /// true = Write this ROW record. +}; + +/** Collects all rows which contain all cells of a sheet. + + This row buffer automatically creates ROW records when cells are inserted + with the AppendCell() function. It is possible to force creation of more + ROW records with the CreateRows() function. In both cases, all preceding + missing ROW records are inserted too. + */ +class XclExpRowBuffer : public XclExpRecordBase, protected XclExpRoot +{ +public: + explicit XclExpRowBuffer( const XclExpRoot& rRoot ); + + /** Appends the passed cell object to the row that the cell specifies. */ + void AppendCell( XclExpCellRef const & xCell, bool bIsMergedBase ); + /** Forces insertion of all ROW records before the passed row. */ + void CreateRows( SCROW nFirstFreeScRow ); + + /** Converts all XF identifiers into the Excel XF indexes and calculates default formats. + @param rDefRowData (out-param) The default row format is returned here. + @param rColXFIndexes The column default XF indexes. + @param nStartColAllDefault Index in rColXFIndexes which starts EXC_XF_DEFAULTCELL until the end. + */ + void Finalize( XclExpDefaultRowData& rDefRowData, const ScfUInt16Vec& rColXFIndexes, + size_t nStartColAllDefault ); + + /** Writes the DIMENSIONS record, all ROW records and all cell records. */ + virtual void Save( XclExpStream& rStrm ) override; + virtual void SaveXml( XclExpXmlStream& rStrm ) override; + + XclExpDimensions& GetDimensions() { return maDimensions; } + sal_uInt8 GetHighestOutlineLevel() const { return mnHighestOutlineLevel; } + +private: + /** Returns access to the specified ROW record. Inserts preceding missing ROW records. + @param bRowAlwaysEmpty true = Created rows will not be filled with blank cells + in the XclExpRow::Finalize() function. */ + XclExpRow& GetOrCreateRow( sal_uInt32 nXclRow, bool bRowAlwaysEmpty ); + +private: + typedef std::shared_ptr<XclExpRow> RowRef; + typedef ::std::map<sal_uInt32, RowRef> RowMap; + + RowMap maRowMap; + XclExpRowOutlineBuffer maOutlineBfr; /// Buffer for row outline groups. + XclExpDimensions maDimensions; /// DIMENSIONS record for used area. + sal_uInt8 mnHighestOutlineLevel; /// Highest number of outline levels for rows in sheet. +}; + +// Cell Table + +class XclExpNote; +class XclExpMergedcells; +class XclExpHyperlink; +class XclExpDval; + +/** This class contains the cell contents and more of an entire sheet. + + The cell table includes the settings and default formatting of all columns, + the settings and default formatting of all used rows, and the contents of + all cells of one sheet in a spreadsheet document. + + The constructor does all the work creating the cell table. It reads the + Calc sheet and converts all columns, rows, and cells to Excel record data. + Additionally, hyperlink records, note records, additional records for + formula cells, data validation records, and outline records are created. + + The Finalize() function does even more work. It calculates default column + settings and removes column records that are equal to this default. The + same happens with rows: A default format is calculated for each row, and + all blank cells in this row that have the same format are removed. Then, + the most used row settings are calculated, and all empty rows that have the + same settings are removed too. + + Records that are not stored inside the cell table area in an Excel file + (i.e. DEFROWHEIGHT record, NOTE records, MERGEDCELLS record, HLINK records, + DVAL and DV records for data validation) can be accessed with the function + CreateRecord(). It returns the reference to the respective record (or + record list) which can be inserted into a record list. + */ +class XclExpCellTable : public XclExpRecordBase, protected XclExpRoot +{ +public: + explicit XclExpCellTable( const XclExpRoot& rRoot ); + + /** Converts all XF identifiers into the Excel XF indexes and calculates default formats. */ + void Finalize(bool bXLS); + + /** Returns the reference to an internal record specified by the passed record id. + @param nRecId The record identifier that specifies which record is + returned. Possible values are: EXC_ID_DEFROWHEIGHT, EXC_ID_NOTE, + EXC_ID_MERGEDCELLS, EXC_ID_HLINK, EXC_ID_DVAL. */ + XclExpRecordRef CreateRecord( sal_uInt16 nRecId ) const; + /** Saves the entire cell table. */ + virtual void Save( XclExpStream& rStrm ) override; + virtual void SaveXml( XclExpXmlStream& rStrm ) override; + +private: + typedef XclExpRecordList< XclExpNote > XclExpNoteList; + typedef XclExpRecordList< XclExpHyperlink > XclExpHyperlinkList; + + typedef rtl::Reference< XclExpDefrowheight > XclExpDefrowhRef; + typedef rtl::Reference< XclExpNoteList > XclExpNoteListRef; + typedef rtl::Reference< XclExpMergedcells > XclExpMergedcellsRef; + typedef rtl::Reference< XclExpHyperlinkList > XclExpHyperlinkRef; + typedef rtl::Reference< XclExpDval > XclExpDvalRef; + typedef rtl::Reference< XclExtLst > XclExtLstRef; + + XclExpColinfoBuffer maColInfoBfr; /// Buffer for column formatting. + XclExpRowBuffer maRowBfr; /// Rows and cell records. + XclExpArrayBuffer maArrayBfr; /// Buffer for ARRAY records. + XclExpShrfmlaBuffer maShrfmlaBfr; /// Buffer for SHRFMLA records. + XclExpTableopBuffer maTableopBfr; /// Buffer for TABLEOP records. + XclExpDefrowhRef mxDefrowheight; /// DEFROWHEIGHT record for default row format. + XclExpRecordRef mxGuts; /// GUTS record for outline areas. + XclExpNoteListRef mxNoteList; /// List of NOTE records. + XclExpMergedcellsRef mxMergedcells; /// MERGEDCELLS record for merged cell ranges. + XclExpHyperlinkRef mxHyperlinkList; /// List of HLINK records. + XclExpDvalRef mxDval; /// Data validation with DVAL and DV records. + XclExtLstRef mxExtLst; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |