summaryrefslogtreecommitdiffstats
path: root/sc/source/filter/oox/pagesettings.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/filter/oox/pagesettings.cxx')
-rw-r--r--sc/source/filter/oox/pagesettings.cxx1065
1 files changed, 1065 insertions, 0 deletions
diff --git a/sc/source/filter/oox/pagesettings.cxx b/sc/source/filter/oox/pagesettings.cxx
new file mode 100644
index 000000000..28cf7c742
--- /dev/null
+++ b/sc/source/filter/oox/pagesettings.cxx
@@ -0,0 +1,1065 @@
+/* -*- 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 .
+ */
+
+#include <pagesettings.hxx>
+
+#include <algorithm>
+#include <set>
+#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/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/style/GraphicLocation.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/text/FilenameDisplayFormat.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/text/XTextCursor.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <osl/diagnose.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sax/tools/converter.hxx>
+#include <oox/helper/attributelist.hxx>
+#include <oox/helper/binaryinputstream.hxx>
+#include <oox/helper/graphichelper.hxx>
+#include <oox/helper/propertymap.hxx>
+#include <oox/helper/propertyset.hxx>
+#include <oox/token/namespaces.hxx>
+#include <oox/token/properties.hxx>
+#include <oox/token/tokens.hxx>
+#include <oox/core/filterbase.hxx>
+#include <oox/core/relations.hxx>
+#include <stylesbuffer.hxx>
+#include <document.hxx>
+#include <biffhelper.hxx>
+#include <filter/msfilter/util.hxx>
+#include <o3tl/string_view.hxx>
+
+namespace oox::xls {
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+
+using ::oox::core::Relations;
+
+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 BIFF12_PRINTOPT_HORCENTER = 0x0001;
+const sal_uInt16 BIFF12_PRINTOPT_VERCENTER = 0x0002;
+const sal_uInt16 BIFF12_PRINTOPT_PRINTHEADING = 0x0004;
+const sal_uInt16 BIFF12_PRINTOPT_PRINTGRID = 0x0008;
+
+const sal_uInt16 BIFF12_HEADERFOOTER_DIFFEVEN = 0x0001;
+const sal_uInt16 BIFF12_HEADERFOOTER_DIFFFIRST = 0x0002;
+
+const sal_uInt16 BIFF12_PAGESETUP_INROWS = 0x0001;
+const sal_uInt16 BIFF12_PAGESETUP_LANDSCAPE = 0x0002;
+const sal_uInt16 BIFF12_PAGESETUP_INVALID = 0x0004;
+const sal_uInt16 BIFF12_PAGESETUP_BLACKWHITE = 0x0008;
+const sal_uInt16 BIFF12_PAGESETUP_DRAFTQUALITY = 0x0010;
+const sal_uInt16 BIFF12_PAGESETUP_PRINTNOTES = 0x0020;
+const sal_uInt16 BIFF12_PAGESETUP_DEFAULTORIENT = 0x0040;
+const sal_uInt16 BIFF12_PAGESETUP_USEFIRSTPAGE = 0x0080;
+const sal_uInt16 BIFF12_PAGESETUP_NOTES_END = 0x0100; // different to BIFF flag
+
+const sal_uInt16 BIFF12_CHARTPAGESETUP_LANDSCAPE = 0x0001;
+const sal_uInt16 BIFF12_CHARTPAGESETUP_INVALID = 0x0002;
+const sal_uInt16 BIFF12_CHARTPAGESETUP_BLACKWHITE = 0x0004;
+const sal_uInt16 BIFF12_CHARTPAGESETUP_DEFAULTORIENT= 0x0008;
+const sal_uInt16 BIFF12_CHARTPAGESETUP_USEFIRSTPAGE = 0x0010;
+const sal_uInt16 BIFF12_CHARTPAGESETUP_DRAFTQUALITY = 0x0020;
+
+} // 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 ),
+ mnPaperWidth( 0 ),
+ mnPaperHeight( 0 ),
+ 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::setBiffPrintErrors( 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 )
+{
+ OUString aStr;
+ maModel.maBinSettPath = rRelations.getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) );
+ maModel.mnPaperSize = rAttribs.getInteger( XML_paperSize, 1 );
+ aStr = rAttribs.getString ( XML_paperWidth, OUString() );
+ ::sax::Converter::convertMeasure(
+ maModel.mnPaperWidth, aStr);
+ aStr = rAttribs.getString ( XML_paperHeight, OUString() );
+ ::sax::Converter::convertMeasure(
+ maModel.mnPaperHeight, aStr );
+ 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, false );
+ 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 )
+{
+ OUString aStr;
+ maModel.maBinSettPath = rRelations.getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) );
+ maModel.mnPaperSize = rAttribs.getInteger( XML_paperSize, 1 );
+ aStr = rAttribs.getString ( XML_paperWidth, OUString() );
+ ::sax::Converter::convertMeasure(
+ maModel.mnPaperWidth, aStr );
+ aStr = rAttribs.getString ( XML_paperHeight, OUString() );
+ ::sax::Converter::convertMeasure(
+ maModel.mnPaperHeight, aStr );
+ 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, false );
+ 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( std::u16string_view 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( SequenceInputStream& rStrm )
+{
+ maModel.mfLeftMargin = rStrm.readDouble();
+ maModel.mfRightMargin = rStrm.readDouble();
+ maModel.mfTopMargin = rStrm.readDouble();
+ maModel.mfBottomMargin = rStrm.readDouble();
+ maModel.mfHeaderMargin = rStrm.readDouble();
+ maModel.mfFooterMargin = rStrm.readDouble();
+}
+
+void PageSettings::importPrintOptions( SequenceInputStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ nFlags = rStrm.readuInt16();
+ maModel.mbHorCenter = getFlag( nFlags, BIFF12_PRINTOPT_HORCENTER );
+ maModel.mbVerCenter = getFlag( nFlags, BIFF12_PRINTOPT_VERCENTER );
+ maModel.mbPrintGrid = getFlag( nFlags, BIFF12_PRINTOPT_PRINTGRID );
+ maModel.mbPrintHeadings = getFlag( nFlags, BIFF12_PRINTOPT_PRINTHEADING );
+}
+
+void PageSettings::importPageSetup( const Relations& rRelations, SequenceInputStream& rStrm )
+{
+ OUString aRelId;
+ sal_uInt16 nFlags;
+ maModel.mnPaperSize = rStrm.readInt32();
+ maModel.mnScale = rStrm.readInt32();
+ maModel.mnHorPrintRes = rStrm.readInt32();
+ maModel.mnVerPrintRes = rStrm.readInt32();
+ maModel.mnCopies = rStrm.readInt32();
+ maModel.mnFirstPage = rStrm.readInt32();
+ maModel.mnFitToWidth = rStrm.readInt32();
+ maModel.mnFitToHeight = rStrm.readInt32();
+ nFlags = rStrm.readuInt16();
+ rStrm >> aRelId;
+ maModel.setBiffPrintErrors( extractValue< sal_uInt8 >( nFlags, 9, 2 ) );
+ maModel.maBinSettPath = rRelations.getFragmentPathFromRelId( aRelId );
+ maModel.mnOrientation = getFlagValue( nFlags, BIFF12_PAGESETUP_DEFAULTORIENT, XML_default, getFlagValue( nFlags, BIFF12_PAGESETUP_LANDSCAPE, XML_landscape, XML_portrait ) );
+ maModel.mnPageOrder = getFlagValue( nFlags, BIFF12_PAGESETUP_INROWS, XML_overThenDown, XML_downThenOver );
+ maModel.mnCellComments = getFlagValue( nFlags, BIFF12_PAGESETUP_PRINTNOTES, getFlagValue( nFlags, BIFF12_PAGESETUP_NOTES_END, XML_atEnd, XML_asDisplayed ), XML_none );
+ maModel.mbValidSettings = !getFlag( nFlags, BIFF12_PAGESETUP_INVALID );
+ maModel.mbUseFirstPage = getFlag( nFlags, BIFF12_PAGESETUP_USEFIRSTPAGE );
+ maModel.mbBlackWhite = getFlag( nFlags, BIFF12_PAGESETUP_BLACKWHITE );
+ maModel.mbDraftQuality = getFlag( nFlags, BIFF12_PAGESETUP_DRAFTQUALITY );
+}
+
+void PageSettings::importChartPageSetup( const Relations& rRelations, SequenceInputStream& rStrm )
+{
+ OUString aRelId;
+ sal_uInt16 nFirstPage, nFlags;
+ maModel.mnPaperSize = rStrm.readInt32();
+ maModel.mnHorPrintRes = rStrm.readInt32();
+ maModel.mnVerPrintRes = rStrm.readInt32();
+ maModel.mnCopies = rStrm.readInt32();
+ nFirstPage = rStrm.readuInt16();
+ nFlags = rStrm.readuInt16();
+ rStrm >> aRelId;
+ maModel.maBinSettPath = rRelations.getFragmentPathFromRelId( aRelId );
+ maModel.mnFirstPage = nFirstPage; // 16-bit in CHARTPAGESETUP
+ maModel.mnOrientation = getFlagValue( nFlags, BIFF12_CHARTPAGESETUP_DEFAULTORIENT, XML_default, getFlagValue( nFlags, BIFF12_CHARTPAGESETUP_LANDSCAPE, XML_landscape, XML_portrait ) );
+ maModel.mbValidSettings = !getFlag( nFlags, BIFF12_CHARTPAGESETUP_INVALID );
+ maModel.mbUseFirstPage = getFlag( nFlags, BIFF12_CHARTPAGESETUP_USEFIRSTPAGE );
+ maModel.mbBlackWhite = getFlag( nFlags, BIFF12_CHARTPAGESETUP_BLACKWHITE );
+ maModel.mbDraftQuality = getFlag( nFlags, BIFF12_CHARTPAGESETUP_DRAFTQUALITY );
+}
+
+void PageSettings::importHeaderFooter( SequenceInputStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ nFlags = rStrm.readuInt16();
+ rStrm >> maModel.maOddHeader >> maModel.maOddFooter
+ >> maModel.maEvenHeader >> maModel.maEvenFooter
+ >> maModel.maFirstHeader >> maModel.maFirstFooter;
+ maModel.mbUseEvenHF = getFlag( nFlags, BIFF12_HEADERFOOTER_DIFFEVEN );
+ maModel.mbUseFirstHF = getFlag( nFlags, BIFF12_HEADERFOOTER_DIFFFIRST );
+}
+
+void PageSettings::importPicture( const Relations& rRelations, SequenceInputStream& rStrm )
+{
+ importPictureData( rRelations, BiffHelper::readString( rStrm ) );
+}
+
+void PageSettings::setFitToPagesMode( bool bFitToPages )
+{
+ maModel.mbFitToPages = bFitToPages;
+}
+
+void PageSettings::finalizeImport()
+{
+ OUStringBuffer aStyleNameBuffer( "PageStyle_" );
+ Reference<container::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<style::XStyle> xStyle = createStyleObject(aStyleName, true);
+ PropertySet aStyleProps( xStyle );
+ getPageSettingsConverter().writePageSettingsProperties( aStyleProps, maModel, getSheetType() );
+
+ // Set page style name to the sheet.
+ SCTAB nTab = getSheetIndex();
+ getScDocument().SetPageStyle(nTab, aStyleName);
+}
+
+void PageSettings::importPictureData( const Relations& rRelations, const OUString& rRelId )
+{
+ OUString aPicturePath = rRelations.getFragmentPathFromRelId(rRelId);
+ if (!aPicturePath.isEmpty())
+ {
+ maModel.mxGraphic = getBaseFilter().getGraphicHelper().importEmbeddedGraphic(aPicturePath);
+ }
+}
+
+namespace {
+
+enum HFPortionId
+{
+ HF_LEFT,
+ HF_CENTER,
+ HF_RIGHT,
+ HF_COUNT
+};
+
+struct HFPortionInfo
+{
+ Reference<text::XText> mxText; /// XText interface of this portion.
+ Reference<text::XTextCursor> mxStart; /// Start position of current text range for formatting.
+ Reference<text::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<text::XText>& rxText );
+};
+
+}
+
+bool HFPortionInfo::initialize( const Reference<text::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<sheet::XHeaderFooterContent>& rxContext,
+ const OUString& rData );
+
+private:
+ /** Returns the current edit engine text object. */
+ HFPortionInfo& getPortion() { return maPortions[ meCurrPortion ]; }
+ /** Returns the start cursor of the current text range. */
+ const Reference<text::XTextCursor>& getStartPos() { return getPortion().mxStart; }
+ /** Returns the end cursor of the current text range. */
+ const Reference<text::XTextCursor>& getEndPos() { return getPortion().mxEnd; }
+
+ /** Returns the current line height of the specified portion. */
+ double getCurrHeight( HFPortionId ePortion ) 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<text::XTextContent> createField( const OUString& rServiceName ) const;
+ /** Appends the passed text field. */
+ void appendField( const Reference<text::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( std::u16string_view 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;
+
+ const std::set< OString > maBoldNames; /// All names for bold font style in lowercase UTF-8.
+ const std::set< OString > 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)
+const char* const sppcBoldNames[] =
+{
+ "bold",
+ "fett", // German 'bold'
+ "demibold",
+ "halbfett", // German 'demibold'
+ "black",
+ "heavy",
+ "f\303\251lk\303\266v\303\251r" // Hungarian 'bold'
+};
+
+// different names for italic font style (lowercase)
+const 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
+ "d\305\221lt" // Hungarian 'italic'
+};
+
+} // namespace
+
+constexpr OUStringLiteral gaPageNumberService( u"com.sun.star.text.TextField.PageNumber" );
+constexpr OUStringLiteral gaPageCountService( u"com.sun.star.text.TextField.PageCount" );
+constexpr OUStringLiteral gaSheetNameService( u"com.sun.star.text.TextField.SheetName" );
+constexpr OUStringLiteral gaFileNameService( u"com.sun.star.text.TextField.FileName" );
+constexpr OUStringLiteral gaDateTimeService( u"com.sun.star.text.TextField.DateTime" );
+
+HeaderFooterParser::HeaderFooterParser( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ maBoldNames( sppcBoldNames, sppcBoldNames + SAL_N_ELEMENTS(sppcBoldNames) ),
+ maItalicNames( sppcItalicNames, sppcItalicNames + SAL_N_ELEMENTS(sppcItalicNames) ),
+ maPortions( static_cast< size_t >( HF_COUNT ) ),
+ meCurrPortion( HF_CENTER )
+{
+}
+
+double HeaderFooterParser::parse( const Reference<sheet::XHeaderFooterContent>& rxContext, const OUString& rData )
+{
+ if( !rxContext.is() || rData.isEmpty() ||
+ !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 = (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( gaPageNumberService ) );
+ break;
+ case 'N': // total page count
+ appendField( createField( gaPageCountService ) );
+ break;
+ case 'A': // current sheet name
+ appendField( createField( gaSheetNameService ) );
+ break;
+
+ case 'F': // file name
+ {
+ Reference<text::XTextContent> xContent = createField( gaFileNameService );
+ PropertySet aPropSet( xContent );
+ aPropSet.setProperty( PROP_FileFormat, css::text::FilenameDisplayFormat::NAME_AND_EXT );
+ appendField( xContent );
+ }
+ break;
+ case 'Z': // file path (without file name), OOXML, BIFF12, and BIFF8 only
+ {
+ Reference<text::XTextContent> xContent = createField( gaFileNameService );
+ PropertySet aPropSet( xContent );
+ // FilenameDisplayFormat::PATH not supported by Calc
+ aPropSet.setProperty( PROP_FileFormat, css::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<text::XTextContent> xContent = createField( gaDateTimeService );
+ PropertySet aPropSet( xContent );
+ aPropSet.setProperty( PROP_IsDate, true );
+ appendField( xContent );
+ }
+ break;
+ case 'T': // time
+ {
+ Reference<text::XTextContent> xContent = createField( gaDateTimeService );
+ 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': // subscript
+ 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( 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 );
+ aFontStyle.setLength(0);
+ 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;
+}
+
+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<text::XTextRange> xRange = getStartPos();
+ getEndPos()->gotoRange( xRange, false );
+ getEndPos()->gotoEnd( true );
+ if( !getEndPos()->isCollapsed() )
+ {
+ Font aFont( *this, maFontModel );
+ aFont.finalizeImport();
+ PropertySet aPropSet( getEndPos() );
+ aFont.writeToPropertySet( aPropSet );
+ getStartPos()->gotoEnd( false );
+ getEndPos()->gotoEnd( false );
+ }
+}
+
+void HeaderFooterParser::appendText()
+{
+ if( !maBuffer.isEmpty() )
+ {
+ getEndPos()->gotoEnd( false );
+ getEndPos()->setString( maBuffer.makeStringAndClear() );
+ updateCurrHeight();
+ }
+}
+
+void HeaderFooterParser::appendLineBreak()
+{
+ getEndPos()->gotoEnd( false );
+ getEndPos()->setString( OUString( '\n' ) );
+ getPortion().mfTotalHeight += getCurrHeight( meCurrPortion ); // add the current line height.
+ getPortion().mfCurrHeight = 0;
+}
+
+Reference<text::XTextContent> HeaderFooterParser::createField( const OUString& rServiceName ) const
+{
+ Reference<text::XTextContent> xContent;
+ try
+ {
+ xContent.set( getBaseFilter().getModelFactory()->createInstance( rServiceName ), UNO_QUERY_THROW );
+ }
+ catch( Exception& )
+ {
+ OSL_FAIL( OStringBuffer( "HeaderFooterParser::createField - error while creating text field \"" ).
+ append( OUStringToOString( rServiceName, RTL_TEXTENCODING_ASCII_US ) ).
+ append( '"' ).getStr() );
+ }
+ return xContent;
+}
+
+void HeaderFooterParser::appendField( const Reference<text::XTextContent>& rxContent )
+{
+ getEndPos()->gotoEnd( false );
+ try
+ {
+ Reference<text::XTextRange> xRange( getEndPos(), UNO_QUERY_THROW );
+ getPortion().mxText->insertTextContent( xRange, rxContent, false );
+ updateCurrHeight();
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+void HeaderFooterParser::convertFontName( const OUString& rName )
+{
+ if( !rName.isEmpty() )
+ {
+ // single dash is document default font
+ if( (rName.getLength() == 1) && (rName[ 0 ] == '-') )
+ maFontModel.maName = getStyles().getDefaultFontModel().maName;
+ else
+ maFontModel.maName = rName;
+ }
+}
+
+void HeaderFooterParser::convertFontStyle( std::u16string_view rStyle )
+{
+ maFontModel.mbBold = maFontModel.mbItalic = false;
+ if (rStyle.empty())
+ return;
+ for( sal_Int32 nPos{ 0 }; nPos>=0; )
+ {
+ OString aToken = OUStringToOString( o3tl::getToken(rStyle, 0, ' ', nPos ), RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase();
+ if( !aToken.isEmpty() )
+ {
+ 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(
+ o3tl::toInt32(rColor.subView( 0, 2 )),
+ static_cast< double >( o3tl::toInt32(rColor.subView( 2 )) ) / 100.0 );
+ else
+ // RGB color: RRGGBB
+ maFontModel.maColor.setRgb( ::Color(ColorTransparency, rColor.toUInt32( 16 )) );
+}
+
+void HeaderFooterParser::finalizePortion()
+{
+ appendText();
+ setAttributes();
+}
+
+void HeaderFooterParser::setNewPortion( HFPortionId ePortion )
+{
+ if( ePortion != meCurrPortion )
+ {
+ finalizePortion();
+ meCurrPortion = ePortion;
+ maFontModel = getStyles().getDefaultFontModel();
+ }
+}
+
+PageSettingsConverter::HFHelperData::HFHelperData( sal_Int32 nLeftPropId, sal_Int32 nRightPropId, sal_Int32 nFirstPropId ) :
+ mnLeftPropId( nLeftPropId ),
+ mnRightPropId( nRightPropId ),
+ mnFirstPropId( nFirstPropId ),
+ mnHeight( 0 ),
+ mnBodyDist( 0 ),
+ mbHasContent( false ),
+ mbShareOddEven( false ),
+ mbShareFirst( false ),
+ mbDynamicHeight( false )
+{
+}
+
+PageSettingsConverter::PageSettingsConverter( const WorkbookHelper& rHelper ) :
+ WorkbookHelper( rHelper ),
+ mxHFParser( new HeaderFooterParser( rHelper ) ),
+ maHeaderData( PROP_LeftPageHeaderContent, PROP_RightPageHeaderContent, PROP_FirstPageHeaderContent ),
+ maFooterData( PROP_LeftPageFooterContent, PROP_RightPageFooterContent, PROP_FirstPageFooterContent )
+{
+}
+
+PageSettingsConverter::~PageSettingsConverter()
+{
+}
+
+void PageSettingsConverter::writePageSettingsProperties(
+ PropertySet& rPropSet, const PageSettingsModel& rModel, WorksheetType eSheetType )
+{
+ // special handling for chart sheets
+ bool bChartSheet = eSheetType == WorksheetType::Chart;
+
+ // 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.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( bChartSheet && ( !rModel.mbValidSettings || (rModel.mnOrientation == XML_default) ) )
+ bLandscape = true;
+
+ // paper size
+ if( !rModel.mbValidSettings )
+ {
+ awt::Size aSize;
+ bool bValid = false;
+
+ if( 0 < rModel.mnPaperSize )
+ {
+ const msfilter::util::ApiPaperSize& rPaperSize = msfilter::util::PaperSizeConv::getApiSizeForMSPaperSizeIndex( rModel.mnPaperSize );
+ aSize = awt::Size( rPaperSize.mnWidth, rPaperSize.mnHeight );
+ bValid = ( rPaperSize.mnWidth != 0 && rPaperSize.mnHeight != 0 );
+ }
+ if( rModel.mnPaperWidth > 0 && rModel.mnPaperHeight > 0 )
+ {
+ aSize = awt::Size( rModel.mnPaperWidth, rModel.mnPaperHeight );
+ bValid = true;
+ }
+
+ if( bValid )
+ {
+ if( bLandscape )
+ ::std::swap( aSize.Width, aSize.Height );
+ rPropSet.setProperty( PROP_Size, aSize );
+ }
+ }
+
+ // header/footer
+ convertHeaderFooterData( rPropSet, maHeaderData, rModel.maOddHeader, rModel.maEvenHeader, rModel.maFirstHeader, rModel.mbUseEvenHF, rModel.mbUseFirstHF, rModel.mfTopMargin, rModel.mfHeaderMargin );
+ convertHeaderFooterData( rPropSet, maFooterData, rModel.maOddFooter, rModel.maEvenFooter, rModel.maFirstFooter, rModel.mbUseEvenHF, rModel.mbUseFirstHF, rModel.mfBottomMargin, rModel.mfFooterMargin );
+
+ // write all properties to property set
+ PropertyMap aPropMap;
+ aPropMap.setProperty( PROP_IsLandscape, bLandscape);
+ aPropMap.setProperty( PROP_FirstPageNumber, getLimitedValue< sal_Int16, sal_Int32 >( rModel.mbUseFirstPage ? rModel.mnFirstPage : 0, 0, 9999 ));
+ aPropMap.setProperty( PROP_PrintDownFirst, (rModel.mnPageOrder == XML_downThenOver));
+ aPropMap.setProperty( PROP_PrintAnnotations, (rModel.mnCellComments == XML_asDisplayed));
+ aPropMap.setProperty( PROP_CenterHorizontally, rModel.mbHorCenter);
+ aPropMap.setProperty( PROP_CenterVertically, rModel.mbVerCenter);
+ aPropMap.setProperty( PROP_PrintGrid, (!bChartSheet && rModel.mbPrintGrid)); // no gridlines in chart sheets
+ aPropMap.setProperty( PROP_PrintHeaders, (!bChartSheet && rModel.mbPrintHeadings)); // no column/row headings in chart sheets
+ aPropMap.setProperty<sal_Int32>( PROP_LeftMargin, std::round(o3tl::convert( rModel.mfLeftMargin, o3tl::Length::in, o3tl::Length::mm100 )));
+ aPropMap.setProperty<sal_Int32>( PROP_RightMargin, std::round(o3tl::convert( rModel.mfRightMargin, o3tl::Length::in, o3tl::Length::mm100 )));
+ // #i23296# In Calc, "TopMargin" property is distance to top of header if enabled
+ aPropMap.setProperty<sal_Int32>( PROP_TopMargin, std::round(o3tl::convert( maHeaderData.mbHasContent ? rModel.mfHeaderMargin : rModel.mfTopMargin, o3tl::Length::in, o3tl::Length::mm100 )));
+ // #i23296# In Calc, "BottomMargin" property is distance to bottom of footer if enabled
+ aPropMap.setProperty<sal_Int32>( PROP_BottomMargin, std::round(o3tl::convert( maFooterData.mbHasContent ? rModel.mfFooterMargin : rModel.mfBottomMargin, o3tl::Length::in, o3tl::Length::mm100 )));
+ aPropMap.setProperty( PROP_HeaderIsOn, maHeaderData.mbHasContent);
+ aPropMap.setProperty( PROP_HeaderIsShared, maHeaderData.mbShareOddEven);
+ aPropMap.setProperty( PROP_FirstPageHeaderIsShared, maHeaderData.mbShareFirst);
+ aPropMap.setProperty( PROP_HeaderIsDynamicHeight, maHeaderData.mbDynamicHeight);
+ aPropMap.setProperty( PROP_HeaderHeight, maHeaderData.mnHeight);
+ aPropMap.setProperty( PROP_HeaderBodyDistance, maHeaderData.mnBodyDist);
+ aPropMap.setProperty( PROP_FooterIsOn, maFooterData.mbHasContent);
+ aPropMap.setProperty( PROP_FooterIsShared, maFooterData.mbShareOddEven);
+ aPropMap.setProperty( PROP_FirstPageFooterIsShared, maFooterData.mbShareFirst);
+ aPropMap.setProperty( PROP_FooterIsDynamicHeight, maFooterData.mbDynamicHeight);
+ aPropMap.setProperty( PROP_FooterHeight, maFooterData.mnHeight);
+ aPropMap.setProperty( PROP_FooterBodyDistance, maFooterData.mnBodyDist);
+ // background image
+ if (rModel.mxGraphic.is())
+ {
+ aPropMap.setProperty(PROP_BackGraphic, rModel.mxGraphic);
+ aPropMap.setProperty(PROP_BackGraphicLocation, css::style::GraphicLocation_TILED);
+ }
+
+ rPropSet.setProperties( aPropMap );
+}
+
+void PageSettingsConverter::convertHeaderFooterData(
+ PropertySet& rPropSet, HFHelperData& orHFData,
+ const OUString& rOddContent, const OUString& rEvenContent, const OUString& rFirstContent,
+ bool bUseEvenContent, bool bUseFirstContent,
+ double fPageMargin, double fContentMargin )
+{
+ bool bHasOddContent = !rOddContent.isEmpty();
+ bool bHasEvenContent = bUseEvenContent && !rEvenContent.isEmpty();
+ bool bHasFirstContent = bUseFirstContent && !rFirstContent.isEmpty();
+
+ sal_Int32 nOddHeight = bHasOddContent ? writeHeaderFooter( rPropSet, orHFData.mnRightPropId, rOddContent ) : 0;
+ sal_Int32 nEvenHeight = bHasEvenContent ? writeHeaderFooter( rPropSet, orHFData.mnLeftPropId, rEvenContent ) : 0;
+ sal_Int32 nFirstHeight = bHasFirstContent ? writeHeaderFooter( rPropSet, orHFData.mnFirstPropId, rFirstContent ) : 0;
+
+ orHFData.mnHeight = 750;
+ orHFData.mnBodyDist = 250;
+ orHFData.mbHasContent = bHasOddContent || bHasEvenContent || bHasFirstContent;
+ orHFData.mbShareOddEven = !bUseEvenContent;
+ orHFData.mbShareFirst = !bUseFirstContent;
+ orHFData.mbDynamicHeight = true;
+
+ if( !orHFData.mbHasContent )
+ return;
+
+ // use maximum height of odd/even/first header/footer
+ orHFData.mnHeight = ::std::max( ::std::max( nOddHeight, nEvenHeight ), nFirstHeight );
+ /* 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 = std::round(o3tl::convert( fPageMargin - fContentMargin, o3tl::Length::in, o3tl::Length::mm100 )) - 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.isEmpty(), "PageSettingsConverter::writeHeaderFooter - empty h/f string found" );
+ sal_Int32 nHeight = 0;
+ if( !rContent.isEmpty() )
+ {
+ Reference<sheet::XHeaderFooterContent> xHFContent(rPropSet.getAnyProperty(nPropId), UNO_QUERY);
+ if( xHFContent.is() )
+ {
+ double fTotalHeight = mxHFParser->parse( xHFContent, rContent );
+ rPropSet.setProperty( nPropId, xHFContent );
+ nHeight = std::round(o3tl::convert(fTotalHeight, o3tl::Length::pt, o3tl::Length::mm100));
+ }
+ }
+ return nHeight;
+}
+
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */