diff options
Diffstat (limited to 'oox/source/xls/pagesettings.cxx')
-rw-r--r-- | oox/source/xls/pagesettings.cxx | 1255 |
1 files changed, 1255 insertions, 0 deletions
diff --git a/oox/source/xls/pagesettings.cxx b/oox/source/xls/pagesettings.cxx new file mode 100644 index 000000000000..0a5ce05a37df --- /dev/null +++ b/oox/source/xls/pagesettings.cxx @@ -0,0 +1,1255 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/xls/pagesettings.hxx" +#include <set> +#include <algorithm> +#include <rtl/strbuf.hxx> +#include <rtl/ustrbuf.hxx> +#include <com/sun/star/awt/Size.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/sheet/XHeaderFooterContent.hpp> +#include <com/sun/star/style/GraphicLocation.hpp> +#include <com/sun/star/text/FilenameDisplayFormat.hpp> +#include <com/sun/star/text/XText.hpp> +#include <com/sun/star/text/XTextContent.hpp> +#include <com/sun/star/text/XTextCursor.hpp> +#include "properties.hxx" +#include "oox/helper/attributelist.hxx" +#include "oox/helper/graphichelper.hxx" +#include "oox/helper/propertymap.hxx" +#include "oox/helper/propertyset.hxx" +#include "oox/helper/recordinputstream.hxx" +#include "oox/core/xmlfilterbase.hxx" +#include "oox/xls/biffinputstream.hxx" +#include "oox/xls/excelhandlers.hxx" +#include "oox/xls/stylesbuffer.hxx" +#include "oox/xls/unitconverter.hxx" + +using ::rtl::OString; +using ::rtl::OStringBuffer; +using ::rtl::OUString; +using ::rtl::OUStringBuffer; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::container::XNamed; +using ::com::sun::star::lang::XMultiServiceFactory; +using ::com::sun::star::awt::Size; +using ::com::sun::star::sheet::XHeaderFooterContent; +using ::com::sun::star::style::XStyle; +using ::com::sun::star::text::XText; +using ::com::sun::star::text::XTextCursor; +using ::com::sun::star::text::XTextContent; +using ::com::sun::star::text::XTextRange; +using ::oox::core::Relations; + +namespace oox { +namespace xls { + +// ============================================================================ + +namespace { + +const double OOX_MARGIN_DEFAULT_LR = 0.748; /// Left/right default margin in inches. +const double OOX_MARGIN_DEFAULT_TB = 0.984; /// Top/bottom default margin in inches. +const double OOX_MARGIN_DEFAULT_HF = 0.512; /// Header/footer default margin in inches. + +const sal_uInt16 OOBIN_PRINTOPT_HORCENTER = 0x0001; +const sal_uInt16 OOBIN_PRINTOPT_VERCENTER = 0x0002; +const sal_uInt16 OOBIN_PRINTOPT_PRINTHEADING = 0x0004; +const sal_uInt16 OOBIN_PRINTOPT_PRINTGRID = 0x0008; + +const sal_uInt16 OOBIN_HEADERFOOTER_DIFFEVEN = 0x0001; +const sal_uInt16 OOBIN_HEADERFOOTER_DIFFFIRST = 0x0002; +const sal_uInt16 OOBIN_HEADERFOOTER_SCALEDOC = 0x0004; +const sal_uInt16 OOBIN_HEADERFOOTER_ALIGNMARGIN = 0x0008; + +const sal_uInt16 OOBIN_PAGESETUP_INROWS = 0x0001; +const sal_uInt16 OOBIN_PAGESETUP_LANDSCAPE = 0x0002; +const sal_uInt16 OOBIN_PAGESETUP_INVALID = 0x0004; +const sal_uInt16 OOBIN_PAGESETUP_BLACKWHITE = 0x0008; +const sal_uInt16 OOBIN_PAGESETUP_DRAFTQUALITY = 0x0010; +const sal_uInt16 OOBIN_PAGESETUP_PRINTNOTES = 0x0020; +const sal_uInt16 OOBIN_PAGESETUP_DEFAULTORIENT = 0x0040; +const sal_uInt16 OOBIN_PAGESETUP_USEFIRSTPAGE = 0x0080; +const sal_uInt16 OOBIN_PAGESETUP_NOTES_END = 0x0100; // different to BIFF flag + +const sal_uInt16 OOBIN_CHARTPAGESETUP_LANDSCAPE = 0x0001; +const sal_uInt16 OOBIN_CHARTPAGESETUP_INVALID = 0x0002; +const sal_uInt16 OOBIN_CHARTPAGESETUP_BLACKWHITE = 0x0004; +const sal_uInt16 OOBIN_CHARTPAGESETUP_DEFAULTORIENT = 0x0008; +const sal_uInt16 OOBIN_CHARTPAGESETUP_USEFIRSTPAGE = 0x0010; +const sal_uInt16 OOBIN_CHARTPAGESETUP_DRAFTQUALITY = 0x0020; + +const sal_uInt16 BIFF_PAGESETUP_INROWS = 0x0001; +const sal_uInt16 BIFF_PAGESETUP_PORTRAIT = 0x0002; +const sal_uInt16 BIFF_PAGESETUP_INVALID = 0x0004; +const sal_uInt16 BIFF_PAGESETUP_BLACKWHITE = 0x0008; +const sal_uInt16 BIFF_PAGESETUP_DRAFTQUALITY = 0x0010; +const sal_uInt16 BIFF_PAGESETUP_PRINTNOTES = 0x0020; +const sal_uInt16 BIFF_PAGESETUP_DEFAULTORIENT = 0x0040; +const sal_uInt16 BIFF_PAGESETUP_USEFIRSTPAGE = 0x0080; +const sal_uInt16 BIFF_PAGESETUP_NOTES_END = 0x0200; + +} // namespace + +// ============================================================================ + +PageSettingsModel::PageSettingsModel() : + mfLeftMargin( OOX_MARGIN_DEFAULT_LR ), + mfRightMargin( OOX_MARGIN_DEFAULT_LR ), + mfTopMargin( OOX_MARGIN_DEFAULT_TB ), + mfBottomMargin( OOX_MARGIN_DEFAULT_TB ), + mfHeaderMargin( OOX_MARGIN_DEFAULT_HF ), + mfFooterMargin( OOX_MARGIN_DEFAULT_HF ), + mnPaperSize( 1 ), + mnCopies( 1 ), + mnScale( 100 ), + mnFirstPage( 1 ), + mnFitToWidth( 1 ), + mnFitToHeight( 1 ), + mnHorPrintRes( 600 ), + mnVerPrintRes( 600 ), + mnOrientation( XML_default ), + mnPageOrder( XML_downThenOver ), + mnCellComments( XML_none ), + mnPrintErrors( XML_displayed ), + mbUseEvenHF( false ), + mbUseFirstHF( false ), + mbValidSettings( true ), + mbUseFirstPage( false ), + mbBlackWhite( false ), + mbDraftQuality( false ), + mbFitToPages( false ), + mbHorCenter( false ), + mbVerCenter( false ), + mbPrintGrid( false ), + mbPrintHeadings( false ) +{ +} + +void PageSettingsModel::setBinPrintErrors( sal_uInt8 nPrintErrors ) +{ + static const sal_Int32 spnErrorIds[] = { XML_displayed, XML_none, XML_dash, XML_NA }; + mnPrintErrors = STATIC_ARRAY_SELECT( spnErrorIds, nPrintErrors, XML_none ); +} + +// ============================================================================ + +PageSettings::PageSettings( const WorksheetHelper& rHelper ) : + WorksheetHelper( rHelper ) +{ +} + +void PageSettings::importPrintOptions( const AttributeList& rAttribs ) +{ + maModel.mbHorCenter = rAttribs.getBool( XML_horizontalCentered, false ); + maModel.mbVerCenter = rAttribs.getBool( XML_verticalCentered, false ); + maModel.mbPrintGrid = rAttribs.getBool( XML_gridLines, false ); + maModel.mbPrintHeadings = rAttribs.getBool( XML_headings, false ); +} + +void PageSettings::importPageMargins( const AttributeList& rAttribs ) +{ + maModel.mfLeftMargin = rAttribs.getDouble( XML_left, OOX_MARGIN_DEFAULT_LR ); + maModel.mfRightMargin = rAttribs.getDouble( XML_right, OOX_MARGIN_DEFAULT_LR ); + maModel.mfTopMargin = rAttribs.getDouble( XML_top, OOX_MARGIN_DEFAULT_TB ); + maModel.mfBottomMargin = rAttribs.getDouble( XML_bottom, OOX_MARGIN_DEFAULT_TB ); + maModel.mfHeaderMargin = rAttribs.getDouble( XML_header, OOX_MARGIN_DEFAULT_HF ); + maModel.mfFooterMargin = rAttribs.getDouble( XML_footer, OOX_MARGIN_DEFAULT_HF ); +} + +void PageSettings::importPageSetup( const Relations& rRelations, const AttributeList& rAttribs ) +{ + maModel.maBinSettPath = rRelations.getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) ); + maModel.mnPaperSize = rAttribs.getInteger( XML_paperSize, 1 ); + maModel.mnCopies = rAttribs.getInteger( XML_copies, 1 ); + maModel.mnScale = rAttribs.getInteger( XML_scale, 100 ); + maModel.mnFirstPage = rAttribs.getInteger( XML_firstPageNumber, 1 ); + maModel.mnFitToWidth = rAttribs.getInteger( XML_fitToWidth, 1 ); + maModel.mnFitToHeight = rAttribs.getInteger( XML_fitToHeight, 1 ); + maModel.mnHorPrintRes = rAttribs.getInteger( XML_horizontalDpi, 600 ); + maModel.mnVerPrintRes = rAttribs.getInteger( XML_verticalDpi, 600 ); + maModel.mnOrientation = rAttribs.getToken( XML_orientation, XML_default ); + maModel.mnPageOrder = rAttribs.getToken( XML_pageOrder, XML_downThenOver ); + maModel.mnCellComments = rAttribs.getToken( XML_cellComments, XML_none ); + maModel.mnPrintErrors = rAttribs.getToken( XML_errors, XML_displayed ); + maModel.mbValidSettings = rAttribs.getBool( XML_usePrinterDefaults, true ); + maModel.mbUseFirstPage = rAttribs.getBool( XML_useFirstPageNumber, false ); + maModel.mbBlackWhite = rAttribs.getBool( XML_blackAndWhite, false ); + maModel.mbDraftQuality = rAttribs.getBool( XML_draft, false ); +} + +void PageSettings::importChartPageSetup( const Relations& rRelations, const AttributeList& rAttribs ) +{ + maModel.maBinSettPath = rRelations.getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) ); + maModel.mnPaperSize = rAttribs.getInteger( XML_paperSize, 1 ); + maModel.mnCopies = rAttribs.getInteger( XML_copies, 1 ); + maModel.mnFirstPage = rAttribs.getInteger( XML_firstPageNumber, 1 ); + maModel.mnHorPrintRes = rAttribs.getInteger( XML_horizontalDpi, 600 ); + maModel.mnVerPrintRes = rAttribs.getInteger( XML_verticalDpi, 600 ); + maModel.mnOrientation = rAttribs.getToken( XML_orientation, XML_default ); + maModel.mbValidSettings = rAttribs.getBool( XML_usePrinterDefaults, true ); + maModel.mbUseFirstPage = rAttribs.getBool( XML_useFirstPageNumber, false ); + maModel.mbBlackWhite = rAttribs.getBool( XML_blackAndWhite, false ); + maModel.mbDraftQuality = rAttribs.getBool( XML_draft, false ); +} + +void PageSettings::importHeaderFooter( const AttributeList& rAttribs ) +{ + maModel.mbUseEvenHF = rAttribs.getBool( XML_differentOddEven, false ); + maModel.mbUseFirstHF = rAttribs.getBool( XML_differentFirst, false ); +} + +void PageSettings::importHeaderFooterCharacters( const OUString& rChars, sal_Int32 nElement ) +{ + switch( nElement ) + { + case XLS_TOKEN( oddHeader ): maModel.maOddHeader += rChars; break; + case XLS_TOKEN( oddFooter ): maModel.maOddFooter += rChars; break; + case XLS_TOKEN( evenHeader ): maModel.maEvenHeader += rChars; break; + case XLS_TOKEN( evenFooter ): maModel.maEvenFooter += rChars; break; + case XLS_TOKEN( firstHeader ): maModel.maFirstHeader += rChars; break; + case XLS_TOKEN( firstFooter ): maModel.maFirstFooter += rChars; break; + } +} + +void PageSettings::importPicture( const Relations& rRelations, const AttributeList& rAttribs ) +{ + importPictureData( rRelations, rAttribs.getString( R_TOKEN( id ), OUString() ) ); +} + +void PageSettings::importPageMargins( RecordInputStream& rStrm ) +{ + rStrm >> maModel.mfLeftMargin >> maModel.mfRightMargin + >> maModel.mfTopMargin >> maModel.mfBottomMargin + >> maModel.mfHeaderMargin >> maModel.mfFooterMargin; +} + +void PageSettings::importPrintOptions( RecordInputStream& rStrm ) +{ + sal_uInt16 nFlags; + rStrm >> nFlags; + maModel.mbHorCenter = getFlag( nFlags, OOBIN_PRINTOPT_HORCENTER ); + maModel.mbVerCenter = getFlag( nFlags, OOBIN_PRINTOPT_VERCENTER ); + maModel.mbPrintGrid = getFlag( nFlags, OOBIN_PRINTOPT_PRINTGRID ); + maModel.mbPrintHeadings = getFlag( nFlags, OOBIN_PRINTOPT_PRINTHEADING ); +} + +void PageSettings::importPageSetup( const Relations& rRelations, RecordInputStream& rStrm ) +{ + OUString aRelId; + sal_uInt16 nFlags; + rStrm >> maModel.mnPaperSize >> maModel.mnScale + >> maModel.mnHorPrintRes >> maModel.mnVerPrintRes + >> maModel.mnCopies >> maModel.mnFirstPage + >> maModel.mnFitToWidth >> maModel.mnFitToHeight + >> nFlags >> aRelId; + maModel.setBinPrintErrors( extractValue< sal_uInt8 >( nFlags, 9, 2 ) ); + maModel.maBinSettPath = rRelations.getFragmentPathFromRelId( aRelId ); + maModel.mnOrientation = getFlagValue( nFlags, OOBIN_PAGESETUP_DEFAULTORIENT, XML_default, getFlagValue( nFlags, OOBIN_PAGESETUP_LANDSCAPE, XML_landscape, XML_portrait ) ); + maModel.mnPageOrder = getFlagValue( nFlags, OOBIN_PAGESETUP_INROWS, XML_overThenDown, XML_downThenOver ); + maModel.mnCellComments = getFlagValue( nFlags, OOBIN_PAGESETUP_PRINTNOTES, getFlagValue( nFlags, OOBIN_PAGESETUP_NOTES_END, XML_atEnd, XML_asDisplayed ), XML_none ); + maModel.mbValidSettings = !getFlag( nFlags, OOBIN_PAGESETUP_INVALID ); + maModel.mbUseFirstPage = getFlag( nFlags, OOBIN_PAGESETUP_USEFIRSTPAGE ); + maModel.mbBlackWhite = getFlag( nFlags, OOBIN_PAGESETUP_BLACKWHITE ); + maModel.mbDraftQuality = getFlag( nFlags, OOBIN_PAGESETUP_DRAFTQUALITY ); +} + +void PageSettings::importChartPageSetup( const Relations& rRelations, RecordInputStream& rStrm ) +{ + OUString aRelId; + sal_uInt16 nFirstPage, nFlags; + rStrm >> maModel.mnPaperSize >> maModel.mnHorPrintRes >> maModel.mnVerPrintRes + >> maModel.mnCopies >> nFirstPage >> nFlags >> aRelId; + maModel.maBinSettPath = rRelations.getFragmentPathFromRelId( aRelId ); + maModel.mnFirstPage = nFirstPage; // 16-bit in CHARTPAGESETUP + maModel.mnOrientation = getFlagValue( nFlags, OOBIN_CHARTPAGESETUP_DEFAULTORIENT, XML_default, getFlagValue( nFlags, OOBIN_CHARTPAGESETUP_LANDSCAPE, XML_landscape, XML_portrait ) ); + maModel.mbValidSettings = !getFlag( nFlags, OOBIN_CHARTPAGESETUP_INVALID ); + maModel.mbUseFirstPage = getFlag( nFlags, OOBIN_CHARTPAGESETUP_USEFIRSTPAGE ); + maModel.mbBlackWhite = getFlag( nFlags, OOBIN_CHARTPAGESETUP_BLACKWHITE ); + maModel.mbDraftQuality = getFlag( nFlags, OOBIN_CHARTPAGESETUP_DRAFTQUALITY ); +} + +void PageSettings::importHeaderFooter( RecordInputStream& rStrm ) +{ + sal_uInt16 nFlags; + rStrm >> nFlags + >> maModel.maOddHeader >> maModel.maOddFooter + >> maModel.maEvenHeader >> maModel.maEvenFooter + >> maModel.maFirstHeader >> maModel.maFirstFooter; + maModel.mbUseEvenHF = getFlag( nFlags, OOBIN_HEADERFOOTER_DIFFEVEN ); + maModel.mbUseFirstHF = getFlag( nFlags, OOBIN_HEADERFOOTER_DIFFFIRST ); +} + +void PageSettings::importPicture( const Relations& rRelations, RecordInputStream& rStrm ) +{ + importPictureData( rRelations, rStrm.readString() ); +} + +void PageSettings::importLeftMargin( BiffInputStream& rStrm ) +{ + rStrm >> maModel.mfLeftMargin; +} + +void PageSettings::importRightMargin( BiffInputStream& rStrm ) +{ + rStrm >> maModel.mfRightMargin; +} + +void PageSettings::importTopMargin( BiffInputStream& rStrm ) +{ + rStrm >> maModel.mfTopMargin; +} + +void PageSettings::importBottomMargin( BiffInputStream& rStrm ) +{ + rStrm >> maModel.mfBottomMargin; +} + +void PageSettings::importPageSetup( BiffInputStream& rStrm ) +{ + sal_uInt16 nPaperSize, nScale, nFirstPage, nFitToWidth, nFitToHeight, nFlags; + rStrm >> nPaperSize >> nScale >> nFirstPage >> nFitToWidth >> nFitToHeight >> nFlags; + + maModel.mnPaperSize = nPaperSize; // equal in BIFF and OOX + maModel.mnScale = nScale; + maModel.mnFirstPage = nFirstPage; + maModel.mnFitToWidth = nFitToWidth; + maModel.mnFitToHeight = nFitToHeight; + maModel.mnOrientation = getFlagValue( nFlags, BIFF_PAGESETUP_PORTRAIT, XML_portrait, XML_landscape ); + maModel.mnPageOrder = getFlagValue( nFlags, BIFF_PAGESETUP_INROWS, XML_overThenDown, XML_downThenOver ); + maModel.mbValidSettings = !getFlag( nFlags, BIFF_PAGESETUP_INVALID ); + maModel.mbUseFirstPage = true; + maModel.mbBlackWhite = getFlag( nFlags, BIFF_PAGESETUP_BLACKWHITE ); + + if( getBiff() >= BIFF5 ) + { + sal_uInt16 nHorPrintRes, nVerPrintRes, nCopies; + rStrm >> nHorPrintRes >> nVerPrintRes >> maModel.mfHeaderMargin >> maModel.mfFooterMargin >> nCopies; + + maModel.mnCopies = nCopies; + maModel.mnOrientation = getFlagValue( nFlags, BIFF_PAGESETUP_DEFAULTORIENT, XML_default, maModel.mnOrientation ); + maModel.mnHorPrintRes = nHorPrintRes; + maModel.mnVerPrintRes = nVerPrintRes; + maModel.mnCellComments = getFlagValue( nFlags, BIFF_PAGESETUP_PRINTNOTES, XML_asDisplayed, XML_none ); + maModel.mbUseFirstPage = getFlag( nFlags, BIFF_PAGESETUP_USEFIRSTPAGE ); + maModel.mbDraftQuality = getFlag( nFlags, BIFF_PAGESETUP_DRAFTQUALITY ); + + if( getBiff() == BIFF8 ) + { + maModel.setBinPrintErrors( extractValue< sal_uInt8 >( nFlags, 10, 2 ) ); + maModel.mnCellComments = getFlagValue( nFlags, BIFF_PAGESETUP_PRINTNOTES, getFlagValue( nFlags, BIFF_PAGESETUP_NOTES_END, XML_atEnd, XML_asDisplayed ), XML_none ); + } + } +} + +void PageSettings::importHorCenter( BiffInputStream& rStrm ) +{ + maModel.mbHorCenter = rStrm.readuInt16() != 0; +} + +void PageSettings::importVerCenter( BiffInputStream& rStrm ) +{ + maModel.mbVerCenter = rStrm.readuInt16() != 0; +} + +void PageSettings::importPrintHeaders( BiffInputStream& rStrm ) +{ + maModel.mbPrintHeadings = rStrm.readuInt16() != 0; +} + +void PageSettings::importPrintGridLines( BiffInputStream& rStrm ) +{ + maModel.mbPrintGrid = rStrm.readuInt16() != 0; +} + +void PageSettings::importHeader( BiffInputStream& rStrm ) +{ + if( rStrm.getRemaining() > 0 ) + maModel.maOddHeader = (getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( false, getTextEncoding() ); + else + maModel.maOddHeader = OUString(); +} + +void PageSettings::importFooter( BiffInputStream& rStrm ) +{ + if( rStrm.getRemaining() > 0 ) + maModel.maOddFooter = (getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( false, getTextEncoding() ); + else + maModel.maOddFooter = OUString(); +} + +void PageSettings::importPicture( BiffInputStream& rStrm ) +{ + StreamDataSequence aPictureData; + BiffHelper::importImgData( aPictureData, rStrm, getBiff() ); + maModel.maGraphicUrl = getBaseFilter().getGraphicHelper().importGraphicObject( aPictureData ); +} + +void PageSettings::setFitToPagesMode( bool bFitToPages ) +{ + maModel.mbFitToPages = bFitToPages; +} + +void PageSettings::finalizeImport() +{ + OUStringBuffer aStyleNameBuffer( CREATE_OUSTRING( "PageStyle_" ) ); + Reference< XNamed > xSheetName( getSheet(), UNO_QUERY ); + if( xSheetName.is() ) + aStyleNameBuffer.append( xSheetName->getName() ); + else + aStyleNameBuffer.append( static_cast< sal_Int32 >( getSheetIndex() + 1 ) ); + OUString aStyleName = aStyleNameBuffer.makeStringAndClear(); + + Reference< XStyle > xStyle = createStyleObject( aStyleName, true ); + PropertySet aStyleProps( xStyle ); + getPageSettingsConverter().writePageSettingsProperties( aStyleProps, maModel, getSheetType() ); + + PropertySet aSheetProps( getSheet() ); + aSheetProps.setProperty( PROP_PageStyle, aStyleName ); +} + +void PageSettings::importPictureData( const Relations& rRelations, const OUString& rRelId ) +{ + OUString aPicturePath = rRelations.getFragmentPathFromRelId( rRelId ); + if( aPicturePath.getLength() > 0 ) + maModel.maGraphicUrl = getBaseFilter().getGraphicHelper().importEmbeddedGraphicObject( aPicturePath ); +} + +// ============================================================================ +// ============================================================================ + +enum HFPortionId +{ + HF_LEFT, + HF_CENTER, + HF_RIGHT, + HF_COUNT +}; + +// ---------------------------------------------------------------------------- + +struct HFPortionInfo +{ + Reference< XText > mxText; /// XText interface of this portion. + Reference< XTextCursor > mxStart; /// Start position of current text range for formatting. + Reference< XTextCursor > mxEnd; /// End position of current text range for formatting. + double mfTotalHeight; /// Sum of heights of previous lines in points. + double mfCurrHeight; /// Height of the current text line in points. + + bool initialize( const Reference< XText >& rxText ); +}; + +bool HFPortionInfo::initialize( const Reference< XText >& rxText ) +{ + mfTotalHeight = mfCurrHeight = 0.0; + mxText = rxText; + if( mxText.is() ) + { + mxStart = mxText->createTextCursor(); + mxEnd = mxText->createTextCursor(); + } + bool bRet = mxText.is() && mxStart.is() && mxEnd.is(); + OSL_ENSURE( bRet, "HFPortionInfo::initialize - missing interfaces" ); + return bRet; +} + +// ============================================================================ + +class HeaderFooterParser : public WorkbookHelper +{ +public: + explicit HeaderFooterParser( const WorkbookHelper& rHelper ); + + /** Parses the passed string and creates the header/footer contents. + @returns The total height of the converted header or footer in points. */ + double parse( + const Reference< XHeaderFooterContent >& rxContext, + const OUString& rData ); + +private: + /** Returns the current edit engine text object. */ + inline HFPortionInfo& getPortion() { return maPortions[ meCurrPortion ]; } + /** Returns the start cursor of the current text range. */ + inline const Reference< XTextCursor >& getStartPos() { return getPortion().mxStart; } + /** Returns the end cursor of the current text range. */ + inline const Reference< XTextCursor >& getEndPos() { return getPortion().mxEnd; } + + /** Returns the current line height of the specified portion. */ + double getCurrHeight( HFPortionId ePortion ) const; + /** Returns the current line height. */ + double getCurrHeight() const; + + /** Updates the current line height of the specified portion, using the current font size. */ + void updateCurrHeight( HFPortionId ePortion ); + /** Updates the current line height, using the current font size. */ + void updateCurrHeight(); + + /** Sets the font attributes at the current selection. */ + void setAttributes(); + /** Appends and clears internal string buffer. */ + void appendText(); + /** Appends a line break and adjusts internal text height data. */ + void appendLineBreak(); + + /** Creates a text field from the passed service name. */ + Reference< XTextContent > createField( const OUString& rServiceName ) const; + /** Appends the passed text field. */ + void appendField( const Reference< XTextContent >& rxContent ); + + /** Sets the passed font name if it is valid. */ + void convertFontName( const OUString& rStyle ); + /** Converts a font style given as string. */ + void convertFontStyle( const OUString& rStyle ); + /** Converts a font color given as string. */ + void convertFontColor( const OUString& rColor ); + + /** Finalizes current portion: sets font attributes and updates text height data. */ + void finalizePortion(); + /** Changes current header/footer portion. */ + void setNewPortion( HFPortionId ePortion ); + +private: + typedef ::std::vector< HFPortionInfo > HFPortionInfoVec; + typedef ::std::set< OString > OStringSet; + + const OUString maPageNumberService; + const OUString maPageCountService; + const OUString maSheetNameService; + const OUString maFileNameService; + const OUString maDateTimeService; + const OStringSet maBoldNames; /// All names for bold font style in lowercase UTF-8. + const OStringSet maItalicNames; /// All names for italic font style in lowercase UTF-8. + HFPortionInfoVec maPortions; + HFPortionId meCurrPortion; /// Identifier of current H/F portion. + OUStringBuffer maBuffer; /// Text data to append to current text range. + FontModel maFontModel; /// Font attributes of current text range. +}; + +// ---------------------------------------------------------------------------- + +namespace { + +// different names for bold font style (lowercase) +static const sal_Char* const sppcBoldNames[] = +{ + "bold", + "fett", // German 'bold' + "demibold", + "halbfett", // German 'demibold' + "black", + "heavy" +}; + +// different names for italic font style (lowercase) +static const sal_Char* const sppcItalicNames[] = +{ + "italic", + "kursiv", // German 'italic' + "oblique", + "schr\303\204g", // German 'oblique' with uppercase A umlaut + "schr\303\244g" // German 'oblique' with lowercase A umlaut +}; + +} // namespace + +// ---------------------------------------------------------------------------- + +HeaderFooterParser::HeaderFooterParser( const WorkbookHelper& rHelper ) : + WorkbookHelper( rHelper ), + maPageNumberService( CREATE_OUSTRING( "com.sun.star.text.TextField.PageNumber" ) ), + maPageCountService( CREATE_OUSTRING( "com.sun.star.text.TextField.PageCount" ) ), + maSheetNameService( CREATE_OUSTRING( "com.sun.star.text.TextField.SheetName" ) ), + maFileNameService( CREATE_OUSTRING( "com.sun.star.text.TextField.FileName" ) ), + maDateTimeService( CREATE_OUSTRING( "com.sun.star.text.TextField.DateTime" ) ), + maBoldNames( sppcBoldNames, STATIC_ARRAY_END( sppcBoldNames ) ), + maItalicNames( sppcItalicNames, STATIC_ARRAY_END( sppcItalicNames ) ), + maPortions( static_cast< size_t >( HF_COUNT ) ), + meCurrPortion( HF_CENTER ) +{ +} + +double HeaderFooterParser::parse( const Reference< XHeaderFooterContent >& rxContext, const OUString& rData ) +{ + if( !rxContext.is() || (rData.getLength() == 0) || + !maPortions[ HF_LEFT ].initialize( rxContext->getLeftText() ) || + !maPortions[ HF_CENTER ].initialize( rxContext->getCenterText() ) || + !maPortions[ HF_RIGHT ].initialize( rxContext->getRightText() ) ) + return 0.0; + + meCurrPortion = HF_CENTER; + maBuffer.setLength( 0 ); + maFontModel = getStyles().getDefaultFontModel(); + OUStringBuffer aFontName; // current font name + OUStringBuffer aFontStyle; // current font style + sal_Int32 nFontHeight = 0; // current font height + + /** State of the parser. */ + enum + { + STATE_TEXT, /// Literal text data. + STATE_TOKEN, /// Control token following a '&' character. + STATE_FONTNAME, /// Font name ('&' is followed by '"', reads until next '"' or ','). + STATE_FONTSTYLE, /// Font style name (font part after ',', reads until next '"'). + STATE_FONTHEIGHT /// Font height ('&' is followed by num. digits, reads until non-digit). + } + eState = STATE_TEXT; + + const sal_Unicode* pcChar = rData.getStr(); + const sal_Unicode* pcEnd = pcChar + rData.getLength(); + for( ; (pcChar != pcEnd) && (*pcChar != 0); ++pcChar ) + { + sal_Unicode cChar = *pcChar; + switch( eState ) + { + case STATE_TEXT: + { + switch( cChar ) + { + case '&': // new token + appendText(); + eState = STATE_TOKEN; + break; + case '\n': // line break + appendText(); + appendLineBreak(); + break; + default: + maBuffer.append( cChar ); + } + } + break; + + case STATE_TOKEN: + { + // default: back to text mode, may be changed in specific cases + eState = STATE_TEXT; + // ignore case of token codes + if( ('a' <= cChar) && (cChar <= 'z') ) + (cChar -= 'a') += 'A'; + switch( cChar ) + { + case '&': maBuffer.append( cChar ); break; // the '&' character + + case 'L': setNewPortion( HF_LEFT ); break; // left portion + case 'C': setNewPortion( HF_CENTER ); break; // center portion + case 'R': setNewPortion( HF_RIGHT ); break; // right portion + + case 'P': // page number + appendField( createField( maPageNumberService ) ); + break; + case 'N': // total page count + appendField( createField( maPageCountService ) ); + break; + case 'A': // current sheet name + appendField( createField( maSheetNameService ) ); + break; + + case 'F': // file name + { + Reference< XTextContent > xContent = createField( maFileNameService ); + PropertySet aPropSet( xContent ); + aPropSet.setProperty( PROP_FileFormat, ::com::sun::star::text::FilenameDisplayFormat::NAME_AND_EXT ); + appendField( xContent ); + } + break; + case 'Z': // file path (without file name), BIFF8 and OOX only + if( (getFilterType() == FILTER_OOX) || ((getFilterType() == FILTER_BIFF) && (getBiff() == BIFF8)) ) + { + Reference< XTextContent > xContent = createField( maFileNameService ); + PropertySet aPropSet( xContent ); + // FilenameDisplayFormat::PATH not supported by Calc + aPropSet.setProperty( PROP_FileFormat, ::com::sun::star::text::FilenameDisplayFormat::FULL ); + appendField( xContent ); + /* path only is not supported -- if we find a '&Z&F' + combination for path/name, skip the '&F' part */ + if( (pcChar + 2 < pcEnd) && (pcChar[ 1 ] == '&') && ((pcChar[ 2 ] == 'f') || (pcChar[ 2 ] == 'F')) ) + pcChar += 2; + } + break; + case 'D': // date + { + Reference< XTextContent > xContent = createField( maDateTimeService ); + PropertySet aPropSet( xContent ); + aPropSet.setProperty( PROP_IsDate, true ); + appendField( xContent ); + } + break; + case 'T': // time + { + Reference< XTextContent > xContent = createField( maDateTimeService ); + PropertySet aPropSet( xContent ); + aPropSet.setProperty( PROP_IsDate, false ); + appendField( xContent ); + } + break; + + case 'B': // bold + setAttributes(); + maFontModel.mbBold = !maFontModel.mbBold; + break; + case 'I': // italic + setAttributes(); + maFontModel.mbItalic = !maFontModel.mbItalic; + break; + case 'U': // underline + setAttributes(); + maFontModel.mnUnderline = (maFontModel.mnUnderline == XML_single) ? XML_none : XML_single; + break; + case 'E': // double underline + setAttributes(); + maFontModel.mnUnderline = (maFontModel.mnUnderline == XML_double) ? XML_none : XML_double; + break; + case 'S': // strikeout + setAttributes(); + maFontModel.mbStrikeout = !maFontModel.mbStrikeout; + break; + case 'X': // superscript + setAttributes(); + maFontModel.mnEscapement = (maFontModel.mnEscapement == XML_superscript) ? XML_baseline : XML_superscript; + break; + case 'Y': // subsrcipt + setAttributes(); + maFontModel.mnEscapement = (maFontModel.mnEscapement == XML_subscript) ? XML_baseline : XML_subscript; + break; + case 'O': // outlined + setAttributes(); + maFontModel.mbOutline = !maFontModel.mbOutline; + break; + case 'H': // shadow + setAttributes(); + maFontModel.mbShadow = !maFontModel.mbShadow; + break; + + case 'K': // text color (not in BIFF) + if( (getFilterType() == FILTER_OOX) && (pcChar + 6 < pcEnd) ) + { + setAttributes(); + // eat the following 6 characters + convertFontColor( OUString( pcChar + 1, 6 ) ); + pcChar += 6; + } + break; + + case '\"': // font name + aFontName.setLength( 0 ); + aFontStyle.setLength( 0 ); + eState = STATE_FONTNAME; + break; + default: + if( ('0' <= cChar) && (cChar <= '9') ) // font size + { + nFontHeight = cChar - '0'; + eState = STATE_FONTHEIGHT; + } + } + } + break; + + case STATE_FONTNAME: + { + switch( cChar ) + { + case '\"': + setAttributes(); + convertFontName( aFontName.makeStringAndClear() ); + eState = STATE_TEXT; + break; + case ',': + eState = STATE_FONTSTYLE; + break; + default: + aFontName.append( cChar ); + } + } + break; + + case STATE_FONTSTYLE: + { + switch( cChar ) + { + case '\"': + setAttributes(); + convertFontName( aFontName.makeStringAndClear() ); + convertFontStyle( aFontStyle.makeStringAndClear() ); + eState = STATE_TEXT; + break; + default: + aFontStyle.append( cChar ); + } + } + break; + + case STATE_FONTHEIGHT: + { + if( ('0' <= cChar) && (cChar <= '9') ) + { + if( nFontHeight >= 0 ) + { + nFontHeight *= 10; + nFontHeight += (cChar - '0'); + if( nFontHeight > 1000 ) + nFontHeight = -1; + } + } + else + { + if( nFontHeight > 0 ) + { + setAttributes(); + maFontModel.mfHeight = nFontHeight; + } + --pcChar; + eState = STATE_TEXT; + } + } + break; + } + } + + // finalize + finalizePortion(); + maPortions[ HF_LEFT ].mfTotalHeight += getCurrHeight( HF_LEFT ); + maPortions[ HF_CENTER ].mfTotalHeight += getCurrHeight( HF_CENTER ); + maPortions[ HF_RIGHT ].mfTotalHeight += getCurrHeight( HF_RIGHT ); + + return ::std::max( maPortions[ HF_LEFT ].mfTotalHeight, + ::std::max( maPortions[ HF_CENTER ].mfTotalHeight, maPortions[ HF_RIGHT ].mfTotalHeight ) ); +} + +// private -------------------------------------------------------------------- + +double HeaderFooterParser::getCurrHeight( HFPortionId ePortion ) const +{ + double fMaxHt = maPortions[ ePortion ].mfCurrHeight; + return (fMaxHt == 0.0) ? maFontModel.mfHeight : fMaxHt; +} + +double HeaderFooterParser::getCurrHeight() const +{ + return getCurrHeight( meCurrPortion ); +} + +void HeaderFooterParser::updateCurrHeight( HFPortionId ePortion ) +{ + double& rfMaxHt = maPortions[ ePortion ].mfCurrHeight; + rfMaxHt = ::std::max( rfMaxHt, maFontModel.mfHeight ); +} + +void HeaderFooterParser::updateCurrHeight() +{ + updateCurrHeight( meCurrPortion ); +} + +void HeaderFooterParser::setAttributes() +{ + Reference< XTextRange > xRange( getStartPos(), UNO_QUERY ); + getEndPos()->gotoRange( xRange, sal_False ); + getEndPos()->gotoEnd( sal_True ); + if( !getEndPos()->isCollapsed() ) + { + Font aFont( *this, maFontModel ); + aFont.finalizeImport(); + PropertySet aPropSet( getEndPos() ); + aFont.writeToPropertySet( aPropSet, FONT_PROPTYPE_TEXT ); + getStartPos()->gotoEnd( sal_False ); + getEndPos()->gotoEnd( sal_False ); + } +} + +void HeaderFooterParser::appendText() +{ + if( maBuffer.getLength() > 0 ) + { + getEndPos()->gotoEnd( sal_False ); + getEndPos()->setString( maBuffer.makeStringAndClear() ); + updateCurrHeight(); + } +} + +void HeaderFooterParser::appendLineBreak() +{ + getEndPos()->gotoEnd( sal_False ); + getEndPos()->setString( OUString( sal_Unicode( '\n' ) ) ); + getPortion().mfTotalHeight += getCurrHeight(); + getPortion().mfCurrHeight = 0; +} + +Reference< XTextContent > HeaderFooterParser::createField( const OUString& rServiceName ) const +{ + Reference< XTextContent > xContent; + try + { + Reference< XMultiServiceFactory > xFactory( getDocument(), UNO_QUERY_THROW ); + xContent.set( xFactory->createInstance( rServiceName ), UNO_QUERY_THROW ); + } + catch( Exception& ) + { + OSL_ENSURE( false, + OStringBuffer( "HeaderFooterParser::createField - error while creating text field \"" ). + append( OUStringToOString( rServiceName, RTL_TEXTENCODING_ASCII_US ) ). + append( '"' ).getStr() ); + } + return xContent; +} + +void HeaderFooterParser::appendField( const Reference< XTextContent >& rxContent ) +{ + getEndPos()->gotoEnd( sal_False ); + try + { + Reference< XTextRange > xRange( getEndPos(), UNO_QUERY_THROW ); + getPortion().mxText->insertTextContent( xRange, rxContent, sal_False ); + updateCurrHeight(); + } + catch( Exception& ) + { + } +} + +void HeaderFooterParser::convertFontName( const OUString& rName ) +{ + if( rName.getLength() > 0 ) + { + // single dash is document default font + if( (rName.getLength() == 1) && (rName[ 0 ] == '-') ) + maFontModel.maName = getStyles().getDefaultFontModel().maName; + else + maFontModel.maName = rName; + } +} + +void HeaderFooterParser::convertFontStyle( const OUString& rStyle ) +{ + maFontModel.mbBold = maFontModel.mbItalic = false; + sal_Int32 nPos = 0; + sal_Int32 nLen = rStyle.getLength(); + while( (0 <= nPos) && (nPos < nLen) ) + { + OString aToken = OUStringToOString( rStyle.getToken( 0, ' ', nPos ), RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase(); + if( aToken.getLength() > 0 ) + { + if( maBoldNames.count( aToken ) > 0 ) + maFontModel.mbBold = true; + else if( maItalicNames.count( aToken ) > 0 ) + maFontModel.mbItalic = true; + } + } +} + +void HeaderFooterParser::convertFontColor( const OUString& rColor ) +{ + OSL_ENSURE( rColor.getLength() == 6, "HeaderFooterParser::convertFontColor - invalid font color code" ); + if( (rColor[ 2 ] == '+') || (rColor[ 2 ] == '-') ) + // theme color: TTSNNN (TT = decimal theme index, S = +/-, NNN = decimal tint/shade in percent) + maFontModel.maColor.setTheme( + rColor.copy( 0, 2 ).toInt32(), + static_cast< double >( rColor.copy( 2 ).toInt32() ) / 100.0 ); + else + // RGB color: RRGGBB + maFontModel.maColor.setRgb( rColor.toInt32( 16 ) ); +} + +void HeaderFooterParser::finalizePortion() +{ + appendText(); + setAttributes(); +} + +void HeaderFooterParser::setNewPortion( HFPortionId ePortion ) +{ + if( ePortion != meCurrPortion ) + { + finalizePortion(); + meCurrPortion = ePortion; + maFontModel = getStyles().getDefaultFontModel(); + } +} + +// ============================================================================ + +namespace { + +/** Paper size in 1/100 millimeters. */ +struct ApiPaperSize +{ + sal_Int32 mnWidth; + sal_Int32 mnHeight; +}; + +#define IN2MM100( v ) static_cast< sal_Int32 >( (v) * 2540.0 + 0.5 ) +#define MM2MM100( v ) static_cast< sal_Int32 >( (v) * 100.0 + 0.5 ) + +static const ApiPaperSize spPaperSizeTable[] = +{ + { 0, 0 }, // 0 - (undefined) + { IN2MM100( 8.5 ), IN2MM100( 11 ) }, // 1 - Letter paper + { IN2MM100( 8.5 ), IN2MM100( 11 ) }, // 2 - Letter small paper + { IN2MM100( 11 ), IN2MM100( 17 ) }, // 3 - Tabloid paper + { IN2MM100( 17 ), IN2MM100( 11 ) }, // 4 - Ledger paper + { IN2MM100( 8.5 ), IN2MM100( 14 ) }, // 5 - Legal paper + { IN2MM100( 5.5 ), IN2MM100( 8.5 ) }, // 6 - Statement paper + { IN2MM100( 7.25 ), IN2MM100( 10.5 ) }, // 7 - Executive paper + { MM2MM100( 297 ), MM2MM100( 420 ) }, // 8 - A3 paper + { MM2MM100( 210 ), MM2MM100( 297 ) }, // 9 - A4 paper + { MM2MM100( 210 ), MM2MM100( 297 ) }, // 10 - A4 small paper + { MM2MM100( 148 ), MM2MM100( 210 ) }, // 11 - A5 paper + { MM2MM100( 250 ), MM2MM100( 353 ) }, // 12 - B4 paper + { MM2MM100( 176 ), MM2MM100( 250 ) }, // 13 - B5 paper + { IN2MM100( 8.5 ), IN2MM100( 13 ) }, // 14 - Folio paper + { MM2MM100( 215 ), MM2MM100( 275 ) }, // 15 - Quarto paper + { IN2MM100( 10 ), IN2MM100( 14 ) }, // 16 - Standard paper + { IN2MM100( 11 ), IN2MM100( 17 ) }, // 17 - Standard paper + { IN2MM100( 8.5 ), IN2MM100( 11 ) }, // 18 - Note paper + { IN2MM100( 3.875 ), IN2MM100( 8.875 ) }, // 19 - #9 envelope + { IN2MM100( 4.125 ), IN2MM100( 9.5 ) }, // 20 - #10 envelope + { IN2MM100( 4.5 ), IN2MM100( 10.375 ) }, // 21 - #11 envelope + { IN2MM100( 4.75 ), IN2MM100( 11 ) }, // 22 - #12 envelope + { IN2MM100( 5 ), IN2MM100( 11.5 ) }, // 23 - #14 envelope + { IN2MM100( 17 ), IN2MM100( 22 ) }, // 24 - C paper + { IN2MM100( 22 ), IN2MM100( 34 ) }, // 25 - D paper + { IN2MM100( 34 ), IN2MM100( 44 ) }, // 26 - E paper + { MM2MM100( 110 ), MM2MM100( 220 ) }, // 27 - DL envelope + { MM2MM100( 162 ), MM2MM100( 229 ) }, // 28 - C5 envelope + { MM2MM100( 324 ), MM2MM100( 458 ) }, // 29 - C3 envelope + { MM2MM100( 229 ), MM2MM100( 324 ) }, // 30 - C4 envelope + { MM2MM100( 114 ), MM2MM100( 162 ) }, // 31 - C6 envelope + { MM2MM100( 114 ), MM2MM100( 229 ) }, // 32 - C65 envelope + { MM2MM100( 250 ), MM2MM100( 353 ) }, // 33 - B4 envelope + { MM2MM100( 176 ), MM2MM100( 250 ) }, // 34 - B5 envelope + { MM2MM100( 176 ), MM2MM100( 125 ) }, // 35 - B6 envelope + { MM2MM100( 110 ), MM2MM100( 230 ) }, // 36 - Italy envelope + { IN2MM100( 3.875 ), IN2MM100( 7.5 ) }, // 37 - Monarch envelope + { IN2MM100( 3.625 ), IN2MM100( 6.5 ) }, // 38 - 6 3/4 envelope + { IN2MM100( 14.875 ), IN2MM100( 11 ) }, // 39 - US standard fanfold + { IN2MM100( 8.5 ), IN2MM100( 12 ) }, // 40 - German standard fanfold + { IN2MM100( 8.5 ), IN2MM100( 13 ) }, // 41 - German legal fanfold + { MM2MM100( 250 ), MM2MM100( 353 ) }, // 42 - ISO B4 + { MM2MM100( 200 ), MM2MM100( 148 ) }, // 43 - Japanese double postcard + { IN2MM100( 9 ), IN2MM100( 11 ) }, // 44 - Standard paper + { IN2MM100( 10 ), IN2MM100( 11 ) }, // 45 - Standard paper + { IN2MM100( 15 ), IN2MM100( 11 ) }, // 46 - Standard paper + { MM2MM100( 220 ), MM2MM100( 220 ) }, // 47 - Invite envelope + { 0, 0 }, // 48 - (undefined) + { 0, 0 }, // 49 - (undefined) + { IN2MM100( 9.275 ), IN2MM100( 12 ) }, // 50 - Letter extra paper + { IN2MM100( 9.275 ), IN2MM100( 15 ) }, // 51 - Legal extra paper + { IN2MM100( 11.69 ), IN2MM100( 18 ) }, // 52 - Tabloid extra paper + { MM2MM100( 236 ), MM2MM100( 322 ) }, // 53 - A4 extra paper + { IN2MM100( 8.275 ), IN2MM100( 11 ) }, // 54 - Letter transverse paper + { MM2MM100( 210 ), MM2MM100( 297 ) }, // 55 - A4 transverse paper + { IN2MM100( 9.275 ), IN2MM100( 12 ) }, // 56 - Letter extra transverse paper + { MM2MM100( 227 ), MM2MM100( 356 ) }, // 57 - SuperA/SuperA/A4 paper + { MM2MM100( 305 ), MM2MM100( 487 ) }, // 58 - SuperB/SuperB/A3 paper + { IN2MM100( 8.5 ), IN2MM100( 12.69 ) }, // 59 - Letter plus paper + { MM2MM100( 210 ), MM2MM100( 330 ) }, // 60 - A4 plus paper + { MM2MM100( 148 ), MM2MM100( 210 ) }, // 61 - A5 transverse paper + { MM2MM100( 182 ), MM2MM100( 257 ) }, // 62 - JIS B5 transverse paper + { MM2MM100( 322 ), MM2MM100( 445 ) }, // 63 - A3 extra paper + { MM2MM100( 174 ), MM2MM100( 235 ) }, // 64 - A5 extra paper + { MM2MM100( 201 ), MM2MM100( 276 ) }, // 65 - ISO B5 extra paper + { MM2MM100( 420 ), MM2MM100( 594 ) }, // 66 - A2 paper + { MM2MM100( 297 ), MM2MM100( 420 ) }, // 67 - A3 transverse paper + { MM2MM100( 322 ), MM2MM100( 445 ) } // 68 - A3 extra transverse paper +}; + +} // namespace + +// ---------------------------------------------------------------------------- + +PageSettingsConverter::HFHelperData::HFHelperData( sal_Int32 nLeftPropId, sal_Int32 nRightPropId ) : + mnLeftPropId( nLeftPropId ), + mnRightPropId( nRightPropId ), + mnHeight( 0 ), + mnBodyDist( 0 ), + mbHasContent( false ), + mbShareOddEven( false ), + mbDynamicHeight( false ) +{ +} + +// ---------------------------------------------------------------------------- + +PageSettingsConverter::PageSettingsConverter( const WorkbookHelper& rHelper ) : + WorkbookHelper( rHelper ), + mxHFParser( new HeaderFooterParser( rHelper ) ), + maHeaderData( PROP_LeftPageHeaderContent, PROP_RightPageHeaderContent ), + maFooterData( PROP_LeftPageFooterContent, PROP_RightPageFooterContent ) +{ +} + +PageSettingsConverter::~PageSettingsConverter() +{ +} + +void PageSettingsConverter::writePageSettingsProperties( + PropertySet& rPropSet, const PageSettingsModel& rModel, WorksheetType eSheetType ) +{ + // special handling for chart sheets + bool bChartSheet = eSheetType == SHEETTYPE_CHARTSHEET; + + // printout scaling + if( bChartSheet ) + { + // always fit chart sheet to 1 page + rPropSet.setProperty< sal_Int16 >( PROP_ScaleToPages, 1 ); + } + else if( rModel.mbFitToPages ) + { + // fit to number of pages + rPropSet.setProperty( PROP_ScaleToPagesX, getLimitedValue< sal_Int16, sal_Int32 >( rModel.mnFitToWidth, 0, 1000 ) ); + rPropSet.setProperty( PROP_ScaleToPagesY, getLimitedValue< sal_Int16, sal_Int32 >( rModel.mnFitToHeight, 0, 1000 ) ); + } + else + { + // scale may be 0 which indicates uninitialized + sal_Int16 nScale = (rModel.mbValidSettings && (rModel.mnScale > 0)) ? getLimitedValue< sal_Int16, sal_Int32 >( rModel.mnScale, 10, 400 ) : 100; + rPropSet.setProperty( PROP_PageScale, nScale ); + } + + // paper orientation + bool bLandscape = rModel.mnOrientation == XML_landscape; + // default orientation for current sheet type (chart sheets default to landscape) + if( !rModel.mbValidSettings || (rModel.mnOrientation == XML_default) ) + bLandscape = bChartSheet; + + // paper size + if( rModel.mbValidSettings && (0 < rModel.mnPaperSize) && (rModel.mnPaperSize < static_cast< sal_Int32 >( STATIC_ARRAY_SIZE( spPaperSizeTable ) )) ) + { + const ApiPaperSize& rPaperSize = spPaperSizeTable[ rModel.mnPaperSize ]; + Size aSize( rPaperSize.mnWidth, rPaperSize.mnHeight ); + if( bLandscape ) + ::std::swap( aSize.Width, aSize.Height ); + rPropSet.setProperty( PROP_Size, aSize ); + } + + // header/footer + convertHeaderFooterData( rPropSet, maHeaderData, rModel.maOddHeader, rModel.maEvenHeader, rModel.mbUseEvenHF, rModel.mfTopMargin, rModel.mfHeaderMargin ); + convertHeaderFooterData( rPropSet, maFooterData, rModel.maOddFooter, rModel.maEvenFooter, rModel.mbUseEvenHF, rModel.mfBottomMargin, rModel.mfFooterMargin ); + + // write all properties to property set + const UnitConverter& rUnitConv = getUnitConverter(); + PropertyMap aPropMap; + aPropMap[ PROP_IsLandscape ] <<= bLandscape; + aPropMap[ PROP_FirstPageNumber ] <<= getLimitedValue< sal_Int16, sal_Int32 >( rModel.mbUseFirstPage ? rModel.mnFirstPage : 0, 0, 9999 ); + aPropMap[ PROP_PrintDownFirst ] <<= (rModel.mnPageOrder == XML_downThenOver); + aPropMap[ PROP_PrintAnnotations ] <<= (rModel.mnCellComments == XML_asDisplayed); + aPropMap[ PROP_CenterHorizontally ] <<= rModel.mbHorCenter; + aPropMap[ PROP_CenterVertically ] <<= rModel.mbVerCenter; + aPropMap[ PROP_PrintGrid ] <<= (!bChartSheet && rModel.mbPrintGrid); // no gridlines in chart sheets + aPropMap[ PROP_PrintHeaders ] <<= (!bChartSheet && rModel.mbPrintHeadings); // no column/row headings in chart sheets + aPropMap[ PROP_LeftMargin ] <<= rUnitConv.scaleToMm100( rModel.mfLeftMargin, UNIT_INCH ); + aPropMap[ PROP_RightMargin ] <<= rUnitConv.scaleToMm100( rModel.mfRightMargin, UNIT_INCH ); + // #i23296# In Calc, "TopMargin" property is distance to top of header if enabled + aPropMap[ PROP_TopMargin ] <<= rUnitConv.scaleToMm100( maHeaderData.mbHasContent ? rModel.mfHeaderMargin : rModel.mfTopMargin, UNIT_INCH ); + // #i23296# In Calc, "BottomMargin" property is distance to bottom of footer if enabled + aPropMap[ PROP_BottomMargin ] <<= rUnitConv.scaleToMm100( maFooterData.mbHasContent ? rModel.mfFooterMargin : rModel.mfBottomMargin, UNIT_INCH ); + aPropMap[ PROP_HeaderIsOn ] <<= maHeaderData.mbHasContent; + aPropMap[ PROP_HeaderIsShared ] <<= maHeaderData.mbShareOddEven; + aPropMap[ PROP_HeaderIsDynamicHeight ] <<= maHeaderData.mbDynamicHeight; + aPropMap[ PROP_HeaderHeight ] <<= maHeaderData.mnHeight; + aPropMap[ PROP_HeaderBodyDistance ] <<= maHeaderData.mnBodyDist; + aPropMap[ PROP_FooterIsOn ] <<= maFooterData.mbHasContent; + aPropMap[ PROP_FooterIsShared ] <<= maFooterData.mbShareOddEven; + aPropMap[ PROP_FooterIsDynamicHeight ] <<= maFooterData.mbDynamicHeight; + aPropMap[ PROP_FooterHeight ] <<= maFooterData.mnHeight; + aPropMap[ PROP_FooterBodyDistance ] <<= maFooterData.mnBodyDist; + // background image + if( rModel.maGraphicUrl.getLength() > 0 ) + { + aPropMap[ PROP_BackGraphicURL ] <<= rModel.maGraphicUrl; + aPropMap[ PROP_BackGraphicLocation ] <<= ::com::sun::star::style::GraphicLocation_TILED; + } + + rPropSet.setProperties( aPropMap ); +} + +void PageSettingsConverter::convertHeaderFooterData( + PropertySet& rPropSet, HFHelperData& orHFData, + const OUString rOddContent, const OUString rEvenContent, bool bUseEvenContent, + double fPageMargin, double fContentMargin ) +{ + bool bHasOddContent = rOddContent.getLength() > 0; + bool bHasEvenContent = bUseEvenContent && (rEvenContent.getLength() > 0); + + sal_Int32 nOddHeight = bHasOddContent ? writeHeaderFooter( rPropSet, orHFData.mnRightPropId, rOddContent ) : 0; + sal_Int32 nEvenHeight = bHasEvenContent ? writeHeaderFooter( rPropSet, orHFData.mnLeftPropId, rEvenContent ) : 0; + + orHFData.mnHeight = 750; + orHFData.mnBodyDist = 250; + orHFData.mbHasContent = bHasOddContent || bHasEvenContent; + orHFData.mbShareOddEven = !bUseEvenContent; + orHFData.mbDynamicHeight = true; + + if( orHFData.mbHasContent ) + { + // use maximum height of odd/even header/footer + orHFData.mnHeight = ::std::max( nOddHeight, nEvenHeight ); + /* Calc contains distance between bottom of header and top of page + body in "HeaderBodyDistance" property, and distance between bottom + of page body and top of footer in "FooterBodyDistance" property */ + orHFData.mnBodyDist = getUnitConverter().scaleToMm100( fPageMargin - fContentMargin, UNIT_INCH ) - orHFData.mnHeight; + /* #i23296# Distance less than 0 means, header or footer overlays page + body. As this is not possible in Calc, set fixed header or footer + height (crop header/footer) to get correct top position of page body. */ + orHFData.mbDynamicHeight = orHFData.mnBodyDist >= 0; + /* "HeaderHeight" property is in fact distance from top of header to + top of page body (including "HeaderBodyDistance"). + "FooterHeight" property is in fact distance from bottom of page + body to bottom of footer (including "FooterBodyDistance"). */ + orHFData.mnHeight += orHFData.mnBodyDist; + // negative body distance not allowed + orHFData.mnBodyDist = ::std::max< sal_Int32 >( orHFData.mnBodyDist, 0 ); + } +} + +sal_Int32 PageSettingsConverter::writeHeaderFooter( + PropertySet& rPropSet, sal_Int32 nPropId, const OUString& rContent ) +{ + OSL_ENSURE( rContent.getLength() > 0, "PageSettingsConverter::writeHeaderFooter - empty h/f string found" ); + sal_Int32 nHeight = 0; + if( rContent.getLength() > 0 ) + { + Reference< XHeaderFooterContent > xHFContent; + if( rPropSet.getProperty( xHFContent, nPropId ) && xHFContent.is() ) + { + double fTotalHeight = mxHFParser->parse( xHFContent, rContent ); + rPropSet.setProperty( nPropId, xHFContent ); + nHeight = getUnitConverter().scaleToMm100( fTotalHeight, UNIT_POINT ); + } + } + return nHeight; +} + +// ============================================================================ + +} // namespace xls +} // namespace oox + |