1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <pagesettings.hxx>
24 #include <com/sun/star/awt/Size.hpp>
25 #include <com/sun/star/container/XNamed.hpp>
26 #include <com/sun/star/sheet/XHeaderFooterContent.hpp>
27 #include <com/sun/star/sheet/XSpreadsheet.hpp>
28 #include <com/sun/star/style/GraphicLocation.hpp>
29 #include <com/sun/star/style/XStyle.hpp>
30 #include <com/sun/star/text/FilenameDisplayFormat.hpp>
31 #include <com/sun/star/text/XText.hpp>
32 #include <com/sun/star/text/XTextCursor.hpp>
33 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
34 #include <osl/diagnose.h>
35 #include <rtl/strbuf.hxx>
36 #include <rtl/ustrbuf.hxx>
37 #include <sax/tools/converter.hxx>
38 #include <oox/helper/attributelist.hxx>
39 #include <oox/helper/binaryinputstream.hxx>
40 #include <oox/helper/graphichelper.hxx>
41 #include <oox/helper/propertymap.hxx>
42 #include <oox/helper/propertyset.hxx>
43 #include <oox/token/namespaces.hxx>
44 #include <oox/token/properties.hxx>
45 #include <oox/token/tokens.hxx>
46 #include <oox/core/filterbase.hxx>
47 #include <oox/core/relations.hxx>
48 #include <stylesbuffer.hxx>
49 #include <unitconverter.hxx>
50 #include <document.hxx>
51 #include <biffhelper.hxx>
52 #include <filter/msfilter/util.hxx>
56 using namespace ::com::sun::star
;
57 using namespace ::com::sun::star::lang
;
58 using namespace ::com::sun::star::uno
;
60 using ::oox::core::Relations
;
64 const double OOX_MARGIN_DEFAULT_LR
= 0.748; /// Left/right default margin in inches.
65 const double OOX_MARGIN_DEFAULT_TB
= 0.984; /// Top/bottom default margin in inches.
66 const double OOX_MARGIN_DEFAULT_HF
= 0.512; /// Header/footer default margin in inches.
68 const sal_uInt16 BIFF12_PRINTOPT_HORCENTER
= 0x0001;
69 const sal_uInt16 BIFF12_PRINTOPT_VERCENTER
= 0x0002;
70 const sal_uInt16 BIFF12_PRINTOPT_PRINTHEADING
= 0x0004;
71 const sal_uInt16 BIFF12_PRINTOPT_PRINTGRID
= 0x0008;
73 const sal_uInt16 BIFF12_HEADERFOOTER_DIFFEVEN
= 0x0001;
74 const sal_uInt16 BIFF12_HEADERFOOTER_DIFFFIRST
= 0x0002;
76 const sal_uInt16 BIFF12_PAGESETUP_INROWS
= 0x0001;
77 const sal_uInt16 BIFF12_PAGESETUP_LANDSCAPE
= 0x0002;
78 const sal_uInt16 BIFF12_PAGESETUP_INVALID
= 0x0004;
79 const sal_uInt16 BIFF12_PAGESETUP_BLACKWHITE
= 0x0008;
80 const sal_uInt16 BIFF12_PAGESETUP_DRAFTQUALITY
= 0x0010;
81 const sal_uInt16 BIFF12_PAGESETUP_PRINTNOTES
= 0x0020;
82 const sal_uInt16 BIFF12_PAGESETUP_DEFAULTORIENT
= 0x0040;
83 const sal_uInt16 BIFF12_PAGESETUP_USEFIRSTPAGE
= 0x0080;
84 const sal_uInt16 BIFF12_PAGESETUP_NOTES_END
= 0x0100; // different to BIFF flag
86 const sal_uInt16 BIFF12_CHARTPAGESETUP_LANDSCAPE
= 0x0001;
87 const sal_uInt16 BIFF12_CHARTPAGESETUP_INVALID
= 0x0002;
88 const sal_uInt16 BIFF12_CHARTPAGESETUP_BLACKWHITE
= 0x0004;
89 const sal_uInt16 BIFF12_CHARTPAGESETUP_DEFAULTORIENT
= 0x0008;
90 const sal_uInt16 BIFF12_CHARTPAGESETUP_USEFIRSTPAGE
= 0x0010;
91 const sal_uInt16 BIFF12_CHARTPAGESETUP_DRAFTQUALITY
= 0x0020;
95 PageSettingsModel::PageSettingsModel() :
96 mfLeftMargin( OOX_MARGIN_DEFAULT_LR
),
97 mfRightMargin( OOX_MARGIN_DEFAULT_LR
),
98 mfTopMargin( OOX_MARGIN_DEFAULT_TB
),
99 mfBottomMargin( OOX_MARGIN_DEFAULT_TB
),
100 mfHeaderMargin( OOX_MARGIN_DEFAULT_HF
),
101 mfFooterMargin( OOX_MARGIN_DEFAULT_HF
),
110 mnHorPrintRes( 600 ),
111 mnVerPrintRes( 600 ),
112 mnOrientation( XML_default
),
113 mnPageOrder( XML_downThenOver
),
114 mnCellComments( XML_none
),
115 mnPrintErrors( XML_displayed
),
116 mbUseEvenHF( false ),
117 mbUseFirstHF( false ),
118 mbValidSettings( true ),
119 mbUseFirstPage( false ),
120 mbBlackWhite( false ),
121 mbDraftQuality( false ),
122 mbFitToPages( false ),
123 mbHorCenter( false ),
124 mbVerCenter( false ),
125 mbPrintGrid( false ),
126 mbPrintHeadings( false )
130 void PageSettingsModel::setBiffPrintErrors( sal_uInt8 nPrintErrors
)
132 static const sal_Int32 spnErrorIds
[] = { XML_displayed
, XML_none
, XML_dash
, XML_NA
};
133 mnPrintErrors
= STATIC_ARRAY_SELECT( spnErrorIds
, nPrintErrors
, XML_none
);
136 PageSettings::PageSettings( const WorksheetHelper
& rHelper
) :
137 WorksheetHelper( rHelper
)
141 void PageSettings::importPrintOptions( const AttributeList
& rAttribs
)
143 maModel
.mbHorCenter
= rAttribs
.getBool( XML_horizontalCentered
, false );
144 maModel
.mbVerCenter
= rAttribs
.getBool( XML_verticalCentered
, false );
145 maModel
.mbPrintGrid
= rAttribs
.getBool( XML_gridLines
, false );
146 maModel
.mbPrintHeadings
= rAttribs
.getBool( XML_headings
, false );
149 void PageSettings::importPageMargins( const AttributeList
& rAttribs
)
151 maModel
.mfLeftMargin
= rAttribs
.getDouble( XML_left
, OOX_MARGIN_DEFAULT_LR
);
152 maModel
.mfRightMargin
= rAttribs
.getDouble( XML_right
, OOX_MARGIN_DEFAULT_LR
);
153 maModel
.mfTopMargin
= rAttribs
.getDouble( XML_top
, OOX_MARGIN_DEFAULT_TB
);
154 maModel
.mfBottomMargin
= rAttribs
.getDouble( XML_bottom
, OOX_MARGIN_DEFAULT_TB
);
155 maModel
.mfHeaderMargin
= rAttribs
.getDouble( XML_header
, OOX_MARGIN_DEFAULT_HF
);
156 maModel
.mfFooterMargin
= rAttribs
.getDouble( XML_footer
, OOX_MARGIN_DEFAULT_HF
);
159 void PageSettings::importPageSetup( const Relations
& rRelations
, const AttributeList
& rAttribs
)
162 maModel
.maBinSettPath
= rRelations
.getFragmentPathFromRelId( rAttribs
.getString( R_TOKEN( id
), OUString() ) );
163 maModel
.mnPaperSize
= rAttribs
.getInteger( XML_paperSize
, 1 );
164 aStr
= rAttribs
.getString ( XML_paperWidth
, OUString() );
165 ::sax::Converter::convertMeasure(
166 maModel
.mnPaperWidth
, aStr
);
167 aStr
= rAttribs
.getString ( XML_paperHeight
, OUString() );
168 ::sax::Converter::convertMeasure(
169 maModel
.mnPaperHeight
, aStr
);
170 maModel
.mnCopies
= rAttribs
.getInteger( XML_copies
, 1 );
171 maModel
.mnScale
= rAttribs
.getInteger( XML_scale
, 100 );
172 maModel
.mnFirstPage
= rAttribs
.getInteger( XML_firstPageNumber
, 1 );
173 maModel
.mnFitToWidth
= rAttribs
.getInteger( XML_fitToWidth
, 1 );
174 maModel
.mnFitToHeight
= rAttribs
.getInteger( XML_fitToHeight
, 1 );
175 maModel
.mnHorPrintRes
= rAttribs
.getInteger( XML_horizontalDpi
, 600 );
176 maModel
.mnVerPrintRes
= rAttribs
.getInteger( XML_verticalDpi
, 600 );
177 maModel
.mnOrientation
= rAttribs
.getToken( XML_orientation
, XML_default
);
178 maModel
.mnPageOrder
= rAttribs
.getToken( XML_pageOrder
, XML_downThenOver
);
179 maModel
.mnCellComments
= rAttribs
.getToken( XML_cellComments
, XML_none
);
180 maModel
.mnPrintErrors
= rAttribs
.getToken( XML_errors
, XML_displayed
);
181 maModel
.mbValidSettings
= rAttribs
.getBool( XML_usePrinterDefaults
, false );
182 maModel
.mbUseFirstPage
= rAttribs
.getBool( XML_useFirstPageNumber
, false );
183 maModel
.mbBlackWhite
= rAttribs
.getBool( XML_blackAndWhite
, false );
184 maModel
.mbDraftQuality
= rAttribs
.getBool( XML_draft
, false );
187 void PageSettings::importChartPageSetup( const Relations
& rRelations
, const AttributeList
& rAttribs
)
190 maModel
.maBinSettPath
= rRelations
.getFragmentPathFromRelId( rAttribs
.getString( R_TOKEN( id
), OUString() ) );
191 maModel
.mnPaperSize
= rAttribs
.getInteger( XML_paperSize
, 1 );
192 aStr
= rAttribs
.getString ( XML_paperWidth
, OUString() );
193 ::sax::Converter::convertMeasure(
194 maModel
.mnPaperWidth
, aStr
);
195 aStr
= rAttribs
.getString ( XML_paperHeight
, OUString() );
196 ::sax::Converter::convertMeasure(
197 maModel
.mnPaperHeight
, aStr
);
198 maModel
.mnCopies
= rAttribs
.getInteger( XML_copies
, 1 );
199 maModel
.mnFirstPage
= rAttribs
.getInteger( XML_firstPageNumber
, 1 );
200 maModel
.mnHorPrintRes
= rAttribs
.getInteger( XML_horizontalDpi
, 600 );
201 maModel
.mnVerPrintRes
= rAttribs
.getInteger( XML_verticalDpi
, 600 );
202 maModel
.mnOrientation
= rAttribs
.getToken( XML_orientation
, XML_default
);
203 maModel
.mbValidSettings
= rAttribs
.getBool( XML_usePrinterDefaults
, false );
204 maModel
.mbUseFirstPage
= rAttribs
.getBool( XML_useFirstPageNumber
, false );
205 maModel
.mbBlackWhite
= rAttribs
.getBool( XML_blackAndWhite
, false );
206 maModel
.mbDraftQuality
= rAttribs
.getBool( XML_draft
, false );
209 void PageSettings::importHeaderFooter( const AttributeList
& rAttribs
)
211 maModel
.mbUseEvenHF
= rAttribs
.getBool( XML_differentOddEven
, false );
212 maModel
.mbUseFirstHF
= rAttribs
.getBool( XML_differentFirst
, false );
215 void PageSettings::importHeaderFooterCharacters( const OUString
& rChars
, sal_Int32 nElement
)
219 case XLS_TOKEN( oddHeader
): maModel
.maOddHeader
+= rChars
; break;
220 case XLS_TOKEN( oddFooter
): maModel
.maOddFooter
+= rChars
; break;
221 case XLS_TOKEN( evenHeader
): maModel
.maEvenHeader
+= rChars
; break;
222 case XLS_TOKEN( evenFooter
): maModel
.maEvenFooter
+= rChars
; break;
223 case XLS_TOKEN( firstHeader
): maModel
.maFirstHeader
+= rChars
; break;
224 case XLS_TOKEN( firstFooter
): maModel
.maFirstFooter
+= rChars
; break;
228 void PageSettings::importPicture( const Relations
& rRelations
, const AttributeList
& rAttribs
)
230 importPictureData( rRelations
, rAttribs
.getString( R_TOKEN( id
), OUString() ) );
233 void PageSettings::importPageMargins( SequenceInputStream
& rStrm
)
235 maModel
.mfLeftMargin
= rStrm
.readDouble();
236 maModel
.mfRightMargin
= rStrm
.readDouble();
237 maModel
.mfTopMargin
= rStrm
.readDouble();
238 maModel
.mfBottomMargin
= rStrm
.readDouble();
239 maModel
.mfHeaderMargin
= rStrm
.readDouble();
240 maModel
.mfFooterMargin
= rStrm
.readDouble();
243 void PageSettings::importPrintOptions( SequenceInputStream
& rStrm
)
246 nFlags
= rStrm
.readuInt16();
247 maModel
.mbHorCenter
= getFlag( nFlags
, BIFF12_PRINTOPT_HORCENTER
);
248 maModel
.mbVerCenter
= getFlag( nFlags
, BIFF12_PRINTOPT_VERCENTER
);
249 maModel
.mbPrintGrid
= getFlag( nFlags
, BIFF12_PRINTOPT_PRINTGRID
);
250 maModel
.mbPrintHeadings
= getFlag( nFlags
, BIFF12_PRINTOPT_PRINTHEADING
);
253 void PageSettings::importPageSetup( const Relations
& rRelations
, SequenceInputStream
& rStrm
)
257 maModel
.mnPaperSize
= rStrm
.readInt32();
258 maModel
.mnScale
= rStrm
.readInt32();
259 maModel
.mnHorPrintRes
= rStrm
.readInt32();
260 maModel
.mnVerPrintRes
= rStrm
.readInt32();
261 maModel
.mnCopies
= rStrm
.readInt32();
262 maModel
.mnFirstPage
= rStrm
.readInt32();
263 maModel
.mnFitToWidth
= rStrm
.readInt32();
264 maModel
.mnFitToHeight
= rStrm
.readInt32();
265 nFlags
= rStrm
.readuInt16();
267 maModel
.setBiffPrintErrors( extractValue
< sal_uInt8
>( nFlags
, 9, 2 ) );
268 maModel
.maBinSettPath
= rRelations
.getFragmentPathFromRelId( aRelId
);
269 maModel
.mnOrientation
= getFlagValue( nFlags
, BIFF12_PAGESETUP_DEFAULTORIENT
, XML_default
, getFlagValue( nFlags
, BIFF12_PAGESETUP_LANDSCAPE
, XML_landscape
, XML_portrait
) );
270 maModel
.mnPageOrder
= getFlagValue( nFlags
, BIFF12_PAGESETUP_INROWS
, XML_overThenDown
, XML_downThenOver
);
271 maModel
.mnCellComments
= getFlagValue( nFlags
, BIFF12_PAGESETUP_PRINTNOTES
, getFlagValue( nFlags
, BIFF12_PAGESETUP_NOTES_END
, XML_atEnd
, XML_asDisplayed
), XML_none
);
272 maModel
.mbValidSettings
= !getFlag( nFlags
, BIFF12_PAGESETUP_INVALID
);
273 maModel
.mbUseFirstPage
= getFlag( nFlags
, BIFF12_PAGESETUP_USEFIRSTPAGE
);
274 maModel
.mbBlackWhite
= getFlag( nFlags
, BIFF12_PAGESETUP_BLACKWHITE
);
275 maModel
.mbDraftQuality
= getFlag( nFlags
, BIFF12_PAGESETUP_DRAFTQUALITY
);
278 void PageSettings::importChartPageSetup( const Relations
& rRelations
, SequenceInputStream
& rStrm
)
281 sal_uInt16 nFirstPage
, nFlags
;
282 maModel
.mnPaperSize
= rStrm
.readInt32();
283 maModel
.mnHorPrintRes
= rStrm
.readInt32();
284 maModel
.mnVerPrintRes
= rStrm
.readInt32();
285 maModel
.mnCopies
= rStrm
.readInt32();
286 nFirstPage
= rStrm
.readuInt16();
287 nFlags
= rStrm
.readuInt16();
289 maModel
.maBinSettPath
= rRelations
.getFragmentPathFromRelId( aRelId
);
290 maModel
.mnFirstPage
= nFirstPage
; // 16-bit in CHARTPAGESETUP
291 maModel
.mnOrientation
= getFlagValue( nFlags
, BIFF12_CHARTPAGESETUP_DEFAULTORIENT
, XML_default
, getFlagValue( nFlags
, BIFF12_CHARTPAGESETUP_LANDSCAPE
, XML_landscape
, XML_portrait
) );
292 maModel
.mbValidSettings
= !getFlag( nFlags
, BIFF12_CHARTPAGESETUP_INVALID
);
293 maModel
.mbUseFirstPage
= getFlag( nFlags
, BIFF12_CHARTPAGESETUP_USEFIRSTPAGE
);
294 maModel
.mbBlackWhite
= getFlag( nFlags
, BIFF12_CHARTPAGESETUP_BLACKWHITE
);
295 maModel
.mbDraftQuality
= getFlag( nFlags
, BIFF12_CHARTPAGESETUP_DRAFTQUALITY
);
298 void PageSettings::importHeaderFooter( SequenceInputStream
& rStrm
)
301 nFlags
= rStrm
.readuInt16();
302 rStrm
>> maModel
.maOddHeader
>> maModel
.maOddFooter
303 >> maModel
.maEvenHeader
>> maModel
.maEvenFooter
304 >> maModel
.maFirstHeader
>> maModel
.maFirstFooter
;
305 maModel
.mbUseEvenHF
= getFlag( nFlags
, BIFF12_HEADERFOOTER_DIFFEVEN
);
306 maModel
.mbUseFirstHF
= getFlag( nFlags
, BIFF12_HEADERFOOTER_DIFFFIRST
);
309 void PageSettings::importPicture( const Relations
& rRelations
, SequenceInputStream
& rStrm
)
311 importPictureData( rRelations
, BiffHelper::readString( rStrm
) );
314 void PageSettings::setFitToPagesMode( bool bFitToPages
)
316 maModel
.mbFitToPages
= bFitToPages
;
319 void PageSettings::finalizeImport()
321 OUStringBuffer
aStyleNameBuffer( "PageStyle_" );
322 Reference
<container::XNamed
> xSheetName(getSheet(), UNO_QUERY
);
323 if( xSheetName
.is() )
324 aStyleNameBuffer
.append( xSheetName
->getName() );
326 aStyleNameBuffer
.append( static_cast< sal_Int32
>( getSheetIndex() + 1 ) );
327 OUString aStyleName
= aStyleNameBuffer
.makeStringAndClear();
329 Reference
<style::XStyle
> xStyle
= createStyleObject(aStyleName
, true);
330 PropertySet
aStyleProps( xStyle
);
331 getPageSettingsConverter().writePageSettingsProperties( aStyleProps
, maModel
, getSheetType() );
333 // Set page style name to the sheet.
334 SCTAB nTab
= getSheetIndex();
335 getScDocument().SetPageStyle(nTab
, aStyleName
);
338 void PageSettings::importPictureData( const Relations
& rRelations
, const OUString
& rRelId
)
340 OUString aPicturePath
= rRelations
.getFragmentPathFromRelId(rRelId
);
341 if (!aPicturePath
.isEmpty())
343 maModel
.mxGraphic
= getBaseFilter().getGraphicHelper().importEmbeddedGraphic(aPicturePath
);
359 Reference
<text::XText
> mxText
; /// XText interface of this portion.
360 Reference
<text::XTextCursor
> mxStart
; /// Start position of current text range for formatting.
361 Reference
<text::XTextCursor
> mxEnd
; /// End position of current text range for formatting.
362 double mfTotalHeight
; /// Sum of heights of previous lines in points.
363 double mfCurrHeight
; /// Height of the current text line in points.
365 bool initialize( const Reference
<text::XText
>& rxText
);
370 bool HFPortionInfo::initialize( const Reference
<text::XText
>& rxText
)
372 mfTotalHeight
= mfCurrHeight
= 0.0;
376 mxStart
= mxText
->createTextCursor();
377 mxEnd
= mxText
->createTextCursor();
379 bool bRet
= mxText
.is() && mxStart
.is() && mxEnd
.is();
380 OSL_ENSURE( bRet
, "HFPortionInfo::initialize - missing interfaces" );
384 class HeaderFooterParser
: public WorkbookHelper
387 explicit HeaderFooterParser( const WorkbookHelper
& rHelper
);
389 /** Parses the passed string and creates the header/footer contents.
390 @returns The total height of the converted header or footer in points. */
392 const Reference
<sheet::XHeaderFooterContent
>& rxContext
,
393 const OUString
& rData
);
396 /** Returns the current edit engine text object. */
397 HFPortionInfo
& getPortion() { return maPortions
[ meCurrPortion
]; }
398 /** Returns the start cursor of the current text range. */
399 const Reference
<text::XTextCursor
>& getStartPos() { return getPortion().mxStart
; }
400 /** Returns the end cursor of the current text range. */
401 const Reference
<text::XTextCursor
>& getEndPos() { return getPortion().mxEnd
; }
403 /** Returns the current line height of the specified portion. */
404 double getCurrHeight( HFPortionId ePortion
) const;
406 /** Updates the current line height of the specified portion, using the current font size. */
407 void updateCurrHeight( HFPortionId ePortion
);
408 /** Updates the current line height, using the current font size. */
409 void updateCurrHeight();
411 /** Sets the font attributes at the current selection. */
412 void setAttributes();
413 /** Appends and clears internal string buffer. */
415 /** Appends a line break and adjusts internal text height data. */
416 void appendLineBreak();
418 /** Creates a text field from the passed service name. */
419 Reference
<text::XTextContent
> createField( const OUString
& rServiceName
) const;
420 /** Appends the passed text field. */
421 void appendField( const Reference
<text::XTextContent
>& rxContent
);
423 /** Sets the passed font name if it is valid. */
424 void convertFontName( const OUString
& rStyle
);
425 /** Converts a font style given as string. */
426 void convertFontStyle( const OUString
& rStyle
);
427 /** Converts a font color given as string. */
428 void convertFontColor( const OUString
& rColor
);
430 /** Finalizes current portion: sets font attributes and updates text height data. */
431 void finalizePortion();
432 /** Changes current header/footer portion. */
433 void setNewPortion( HFPortionId ePortion
);
436 typedef ::std::vector
< HFPortionInfo
> HFPortionInfoVec
;
438 const std::set
< OString
> maBoldNames
; /// All names for bold font style in lowercase UTF-8.
439 const std::set
< OString
> maItalicNames
; /// All names for italic font style in lowercase UTF-8.
440 HFPortionInfoVec maPortions
;
441 HFPortionId meCurrPortion
; /// Identifier of current H/F portion.
442 OUStringBuffer maBuffer
; /// Text data to append to current text range.
443 FontModel maFontModel
; /// Font attributes of current text range.
448 // different names for bold font style (lowercase)
449 const char* const sppcBoldNames
[] =
452 "fett", // German 'bold'
454 "halbfett", // German 'demibold'
457 "f\303\251lk\303\266v\303\251r" // Hungarian 'bold'
460 // different names for italic font style (lowercase)
461 const char* const sppcItalicNames
[] =
464 "kursiv", // German 'italic'
466 "schr\303\204g", // German 'oblique' with uppercase A umlaut
467 "schr\303\244g", // German 'oblique' with lowercase A umlaut
468 "d\305\221lt" // Hungarian 'italic'
473 constexpr OUStringLiteral
gaPageNumberService( u
"com.sun.star.text.TextField.PageNumber" );
474 constexpr OUStringLiteral
gaPageCountService( u
"com.sun.star.text.TextField.PageCount" );
475 constexpr OUStringLiteral
gaSheetNameService( u
"com.sun.star.text.TextField.SheetName" );
476 constexpr OUStringLiteral
gaFileNameService( u
"com.sun.star.text.TextField.FileName" );
477 constexpr OUStringLiteral
gaDateTimeService( u
"com.sun.star.text.TextField.DateTime" );
479 HeaderFooterParser::HeaderFooterParser( const WorkbookHelper
& rHelper
) :
480 WorkbookHelper( rHelper
),
481 maBoldNames( sppcBoldNames
, sppcBoldNames
+ SAL_N_ELEMENTS(sppcBoldNames
) ),
482 maItalicNames( sppcItalicNames
, sppcItalicNames
+ SAL_N_ELEMENTS(sppcItalicNames
) ),
483 maPortions( static_cast< size_t >( HF_COUNT
) ),
484 meCurrPortion( HF_CENTER
)
488 double HeaderFooterParser::parse( const Reference
<sheet::XHeaderFooterContent
>& rxContext
, const OUString
& rData
)
490 if( !rxContext
.is() || rData
.isEmpty() ||
491 !maPortions
[ HF_LEFT
].initialize( rxContext
->getLeftText() ) ||
492 !maPortions
[ HF_CENTER
].initialize( rxContext
->getCenterText() ) ||
493 !maPortions
[ HF_RIGHT
].initialize( rxContext
->getRightText() ) )
496 meCurrPortion
= HF_CENTER
;
497 maBuffer
.setLength( 0 );
498 maFontModel
= getStyles().getDefaultFontModel();
499 OUStringBuffer aFontName
; // current font name
500 OUStringBuffer aFontStyle
; // current font style
501 sal_Int32 nFontHeight
= 0; // current font height
503 /** State of the parser. */
506 STATE_TEXT
, /// Literal text data.
507 STATE_TOKEN
, /// Control token following a '&' character.
508 STATE_FONTNAME
, /// Font name ('&' is followed by '"', reads until next '"' or ',').
509 STATE_FONTSTYLE
, /// Font style name (font part after ',', reads until next '"').
510 STATE_FONTHEIGHT
/// Font height ('&' is followed by num. digits, reads until non-digit).
514 const sal_Unicode
* pcChar
= rData
.getStr();
515 const sal_Unicode
* pcEnd
= pcChar
+ rData
.getLength();
516 for( ; (pcChar
!= pcEnd
) && (*pcChar
!= 0); ++pcChar
)
518 sal_Unicode cChar
= *pcChar
;
525 case '&': // new token
527 eState
= STATE_TOKEN
;
529 case '\n': // line break
534 maBuffer
.append( cChar
);
541 // default: back to text mode, may be changed in specific cases
543 // ignore case of token codes
544 if( ('a' <= cChar
) && (cChar
<= 'z') )
545 cChar
= (cChar
- 'a') + 'A';
548 case '&': maBuffer
.append( cChar
); break; // the '&' character
550 case 'L': setNewPortion( HF_LEFT
); break; // left portion
551 case 'C': setNewPortion( HF_CENTER
); break; // center portion
552 case 'R': setNewPortion( HF_RIGHT
); break; // right portion
554 case 'P': // page number
555 appendField( createField( gaPageNumberService
) );
557 case 'N': // total page count
558 appendField( createField( gaPageCountService
) );
560 case 'A': // current sheet name
561 appendField( createField( gaSheetNameService
) );
564 case 'F': // file name
566 Reference
<text::XTextContent
> xContent
= createField( gaFileNameService
);
567 PropertySet
aPropSet( xContent
);
568 aPropSet
.setProperty( PROP_FileFormat
, css::text::FilenameDisplayFormat::NAME_AND_EXT
);
569 appendField( xContent
);
572 case 'Z': // file path (without file name), OOXML, BIFF12, and BIFF8 only
574 Reference
<text::XTextContent
> xContent
= createField( gaFileNameService
);
575 PropertySet
aPropSet( xContent
);
576 // FilenameDisplayFormat::PATH not supported by Calc
577 aPropSet
.setProperty( PROP_FileFormat
, css::text::FilenameDisplayFormat::FULL
);
578 appendField( xContent
);
579 /* path only is not supported -- if we find a '&Z&F'
580 combination for path/name, skip the '&F' part */
581 if( (pcChar
+ 2 < pcEnd
) && (pcChar
[ 1 ] == '&') && ((pcChar
[ 2 ] == 'f') || (pcChar
[ 2 ] == 'F')) )
587 Reference
<text::XTextContent
> xContent
= createField( gaDateTimeService
);
588 PropertySet
aPropSet( xContent
);
589 aPropSet
.setProperty( PROP_IsDate
, true );
590 appendField( xContent
);
595 Reference
<text::XTextContent
> xContent
= createField( gaDateTimeService
);
596 PropertySet
aPropSet( xContent
);
597 aPropSet
.setProperty( PROP_IsDate
, false );
598 appendField( xContent
);
604 maFontModel
.mbBold
= !maFontModel
.mbBold
;
608 maFontModel
.mbItalic
= !maFontModel
.mbItalic
;
610 case 'U': // underline
612 maFontModel
.mnUnderline
= (maFontModel
.mnUnderline
== XML_single
) ? XML_none
: XML_single
;
614 case 'E': // double underline
616 maFontModel
.mnUnderline
= (maFontModel
.mnUnderline
== XML_double
) ? XML_none
: XML_double
;
618 case 'S': // strikeout
620 maFontModel
.mbStrikeout
= !maFontModel
.mbStrikeout
;
622 case 'X': // superscript
624 maFontModel
.mnEscapement
= (maFontModel
.mnEscapement
== XML_superscript
) ? XML_baseline
: XML_superscript
;
626 case 'Y': // subscript
628 maFontModel
.mnEscapement
= (maFontModel
.mnEscapement
== XML_subscript
) ? XML_baseline
: XML_subscript
;
630 case 'O': // outlined
632 maFontModel
.mbOutline
= !maFontModel
.mbOutline
;
636 maFontModel
.mbShadow
= !maFontModel
.mbShadow
;
639 case 'K': // text color (not in BIFF)
640 if( pcChar
+ 6 < pcEnd
)
643 // eat the following 6 characters
644 convertFontColor( OUString( pcChar
+ 1, 6 ) );
649 case '\"': // font name
650 aFontName
.setLength( 0 );
651 aFontStyle
.setLength( 0 );
652 eState
= STATE_FONTNAME
;
655 if( ('0' <= cChar
) && (cChar
<= '9') ) // font size
657 nFontHeight
= cChar
- '0';
658 eState
= STATE_FONTHEIGHT
;
670 convertFontName( aFontName
.makeStringAndClear() );
674 eState
= STATE_FONTSTYLE
;
677 aFontName
.append( cChar
);
682 case STATE_FONTSTYLE
:
688 convertFontName( aFontName
.makeStringAndClear() );
689 convertFontStyle( aFontStyle
.makeStringAndClear() );
693 aFontStyle
.append( cChar
);
698 case STATE_FONTHEIGHT
:
700 if( ('0' <= cChar
) && (cChar
<= '9') )
702 if( nFontHeight
>= 0 )
705 nFontHeight
+= (cChar
- '0');
706 if( nFontHeight
> 1000 )
712 if( nFontHeight
> 0 )
715 maFontModel
.mfHeight
= nFontHeight
;
727 maPortions
[ HF_LEFT
].mfTotalHeight
+= getCurrHeight( HF_LEFT
);
728 maPortions
[ HF_CENTER
].mfTotalHeight
+= getCurrHeight( HF_CENTER
);
729 maPortions
[ HF_RIGHT
].mfTotalHeight
+= getCurrHeight( HF_RIGHT
);
731 return ::std::max( maPortions
[ HF_LEFT
].mfTotalHeight
,
732 ::std::max( maPortions
[ HF_CENTER
].mfTotalHeight
, maPortions
[ HF_RIGHT
].mfTotalHeight
) );
735 // private --------------------------------------------------------------------
737 double HeaderFooterParser::getCurrHeight( HFPortionId ePortion
) const
739 double fMaxHt
= maPortions
[ ePortion
].mfCurrHeight
;
740 return (fMaxHt
== 0.0) ? maFontModel
.mfHeight
: fMaxHt
;
743 void HeaderFooterParser::updateCurrHeight( HFPortionId ePortion
)
745 double& rfMaxHt
= maPortions
[ ePortion
].mfCurrHeight
;
746 rfMaxHt
= ::std::max( rfMaxHt
, maFontModel
.mfHeight
);
749 void HeaderFooterParser::updateCurrHeight()
751 updateCurrHeight( meCurrPortion
);
754 void HeaderFooterParser::setAttributes()
756 Reference
<text::XTextRange
> xRange
= getStartPos();
757 getEndPos()->gotoRange( xRange
, false );
758 getEndPos()->gotoEnd( true );
759 if( !getEndPos()->isCollapsed() )
761 Font
aFont( *this, maFontModel
);
762 aFont
.finalizeImport();
763 PropertySet
aPropSet( getEndPos() );
764 aFont
.writeToPropertySet( aPropSet
);
765 getStartPos()->gotoEnd( false );
766 getEndPos()->gotoEnd( false );
770 void HeaderFooterParser::appendText()
772 if( !maBuffer
.isEmpty() )
774 getEndPos()->gotoEnd( false );
775 getEndPos()->setString( maBuffer
.makeStringAndClear() );
780 void HeaderFooterParser::appendLineBreak()
782 getEndPos()->gotoEnd( false );
783 getEndPos()->setString( OUString( '\n' ) );
784 getPortion().mfTotalHeight
+= getCurrHeight( meCurrPortion
); // add the current line height.
785 getPortion().mfCurrHeight
= 0;
788 Reference
<text::XTextContent
> HeaderFooterParser::createField( const OUString
& rServiceName
) const
790 Reference
<text::XTextContent
> xContent
;
793 xContent
.set( getBaseFilter().getModelFactory()->createInstance( rServiceName
), UNO_QUERY_THROW
);
797 OSL_FAIL( OStringBuffer( "HeaderFooterParser::createField - error while creating text field \"" ).
798 append( OUStringToOString( rServiceName
, RTL_TEXTENCODING_ASCII_US
) ).
799 append( '"' ).getStr() );
804 void HeaderFooterParser::appendField( const Reference
<text::XTextContent
>& rxContent
)
806 getEndPos()->gotoEnd( false );
809 Reference
<text::XTextRange
> xRange( getEndPos(), UNO_QUERY_THROW
);
810 getPortion().mxText
->insertTextContent( xRange
, rxContent
, false );
818 void HeaderFooterParser::convertFontName( const OUString
& rName
)
820 if( !rName
.isEmpty() )
822 // single dash is document default font
823 if( (rName
.getLength() == 1) && (rName
[ 0 ] == '-') )
824 maFontModel
.maName
= getStyles().getDefaultFontModel().maName
;
826 maFontModel
.maName
= rName
;
830 void HeaderFooterParser::convertFontStyle( const OUString
& rStyle
)
832 maFontModel
.mbBold
= maFontModel
.mbItalic
= false;
833 if (rStyle
.isEmpty())
835 for( sal_Int32 nPos
{ 0 }; nPos
>=0; )
837 OString aToken
= OUStringToOString( rStyle
.getToken( 0, ' ', nPos
), RTL_TEXTENCODING_UTF8
).toAsciiLowerCase();
838 if( !aToken
.isEmpty() )
840 if( maBoldNames
.count( aToken
) > 0 )
841 maFontModel
.mbBold
= true;
842 else if( maItalicNames
.count( aToken
) > 0 )
843 maFontModel
.mbItalic
= true;
848 void HeaderFooterParser::convertFontColor( const OUString
& rColor
)
850 OSL_ENSURE( rColor
.getLength() == 6, "HeaderFooterParser::convertFontColor - invalid font color code" );
851 if( (rColor
[ 2 ] == '+') || (rColor
[ 2 ] == '-') )
852 // theme color: TTSNNN (TT = decimal theme index, S = +/-, NNN = decimal tint/shade in percent)
853 maFontModel
.maColor
.setTheme(
854 rColor
.copy( 0, 2 ).toInt32(),
855 static_cast< double >( rColor
.copy( 2 ).toInt32() ) / 100.0 );
858 maFontModel
.maColor
.setRgb( ::Color(rColor
.toUInt32( 16 )) );
861 void HeaderFooterParser::finalizePortion()
867 void HeaderFooterParser::setNewPortion( HFPortionId ePortion
)
869 if( ePortion
!= meCurrPortion
)
872 meCurrPortion
= ePortion
;
873 maFontModel
= getStyles().getDefaultFontModel();
877 PageSettingsConverter::HFHelperData::HFHelperData( sal_Int32 nLeftPropId
, sal_Int32 nRightPropId
) :
878 mnLeftPropId( nLeftPropId
),
879 mnRightPropId( nRightPropId
),
882 mbHasContent( false ),
883 mbShareOddEven( false ),
884 mbDynamicHeight( false )
888 PageSettingsConverter::PageSettingsConverter( const WorkbookHelper
& rHelper
) :
889 WorkbookHelper( rHelper
),
890 mxHFParser( new HeaderFooterParser( rHelper
) ),
891 maHeaderData( PROP_LeftPageHeaderContent
, PROP_RightPageHeaderContent
),
892 maFooterData( PROP_LeftPageFooterContent
, PROP_RightPageFooterContent
)
896 PageSettingsConverter::~PageSettingsConverter()
900 void PageSettingsConverter::writePageSettingsProperties(
901 PropertySet
& rPropSet
, const PageSettingsModel
& rModel
, WorksheetType eSheetType
)
903 // special handling for chart sheets
904 bool bChartSheet
= eSheetType
== WorksheetType::Chart
;
909 // always fit chart sheet to 1 page
910 rPropSet
.setProperty
< sal_Int16
>( PROP_ScaleToPages
, 1 );
912 else if( rModel
.mbFitToPages
)
914 // fit to number of pages
915 rPropSet
.setProperty( PROP_ScaleToPagesX
, getLimitedValue
< sal_Int16
, sal_Int32
>( rModel
.mnFitToWidth
, 0, 1000 ) );
916 rPropSet
.setProperty( PROP_ScaleToPagesY
, getLimitedValue
< sal_Int16
, sal_Int32
>( rModel
.mnFitToHeight
, 0, 1000 ) );
920 // scale may be 0 which indicates uninitialized
921 sal_Int16 nScale
= (rModel
.mnScale
> 0) ? getLimitedValue
< sal_Int16
, sal_Int32
>( rModel
.mnScale
, 10, 400 ) : 100;
922 rPropSet
.setProperty( PROP_PageScale
, nScale
);
926 bool bLandscape
= rModel
.mnOrientation
== XML_landscape
;
927 // default orientation for current sheet type (chart sheets default to landscape)
928 if( bChartSheet
&& ( !rModel
.mbValidSettings
|| (rModel
.mnOrientation
== XML_default
) ) )
932 if( !rModel
.mbValidSettings
)
937 if( 0 < rModel
.mnPaperSize
)
939 const msfilter::util::ApiPaperSize
& rPaperSize
= msfilter::util::PaperSizeConv::getApiSizeForMSPaperSizeIndex( rModel
.mnPaperSize
);
940 aSize
= awt::Size( rPaperSize
.mnWidth
, rPaperSize
.mnHeight
);
941 bValid
= ( rPaperSize
.mnWidth
!= 0 && rPaperSize
.mnHeight
!= 0 );
943 if( rModel
.mnPaperWidth
> 0 && rModel
.mnPaperHeight
> 0 )
945 aSize
= awt::Size( rModel
.mnPaperWidth
, rModel
.mnPaperHeight
);
952 ::std::swap( aSize
.Width
, aSize
.Height
);
953 rPropSet
.setProperty( PROP_Size
, aSize
);
958 convertHeaderFooterData( rPropSet
, maHeaderData
, rModel
.maOddHeader
, rModel
.maEvenHeader
, rModel
.mbUseEvenHF
, rModel
.mfTopMargin
, rModel
.mfHeaderMargin
);
959 convertHeaderFooterData( rPropSet
, maFooterData
, rModel
.maOddFooter
, rModel
.maEvenFooter
, rModel
.mbUseEvenHF
, rModel
.mfBottomMargin
, rModel
.mfFooterMargin
);
961 // write all properties to property set
962 const UnitConverter
& rUnitConv
= getUnitConverter();
963 PropertyMap aPropMap
;
964 aPropMap
.setProperty( PROP_IsLandscape
, bLandscape
);
965 aPropMap
.setProperty( PROP_FirstPageNumber
, getLimitedValue
< sal_Int16
, sal_Int32
>( rModel
.mbUseFirstPage
? rModel
.mnFirstPage
: 0, 0, 9999 ));
966 aPropMap
.setProperty( PROP_PrintDownFirst
, (rModel
.mnPageOrder
== XML_downThenOver
));
967 aPropMap
.setProperty( PROP_PrintAnnotations
, (rModel
.mnCellComments
== XML_asDisplayed
));
968 aPropMap
.setProperty( PROP_CenterHorizontally
, rModel
.mbHorCenter
);
969 aPropMap
.setProperty( PROP_CenterVertically
, rModel
.mbVerCenter
);
970 aPropMap
.setProperty( PROP_PrintGrid
, (!bChartSheet
&& rModel
.mbPrintGrid
)); // no gridlines in chart sheets
971 aPropMap
.setProperty( PROP_PrintHeaders
, (!bChartSheet
&& rModel
.mbPrintHeadings
)); // no column/row headings in chart sheets
972 aPropMap
.setProperty( PROP_LeftMargin
, rUnitConv
.scaleToMm100( rModel
.mfLeftMargin
, Unit::Inch
));
973 aPropMap
.setProperty( PROP_RightMargin
, rUnitConv
.scaleToMm100( rModel
.mfRightMargin
, Unit::Inch
));
974 // #i23296# In Calc, "TopMargin" property is distance to top of header if enabled
975 aPropMap
.setProperty( PROP_TopMargin
, rUnitConv
.scaleToMm100( maHeaderData
.mbHasContent
? rModel
.mfHeaderMargin
: rModel
.mfTopMargin
, Unit::Inch
));
976 // #i23296# In Calc, "BottomMargin" property is distance to bottom of footer if enabled
977 aPropMap
.setProperty( PROP_BottomMargin
, rUnitConv
.scaleToMm100( maFooterData
.mbHasContent
? rModel
.mfFooterMargin
: rModel
.mfBottomMargin
, Unit::Inch
));
978 aPropMap
.setProperty( PROP_HeaderIsOn
, maHeaderData
.mbHasContent
);
979 aPropMap
.setProperty( PROP_HeaderIsShared
, maHeaderData
.mbShareOddEven
);
980 aPropMap
.setProperty( PROP_HeaderIsDynamicHeight
, maHeaderData
.mbDynamicHeight
);
981 aPropMap
.setProperty( PROP_HeaderHeight
, maHeaderData
.mnHeight
);
982 aPropMap
.setProperty( PROP_HeaderBodyDistance
, maHeaderData
.mnBodyDist
);
983 aPropMap
.setProperty( PROP_FooterIsOn
, maFooterData
.mbHasContent
);
984 aPropMap
.setProperty( PROP_FooterIsShared
, maFooterData
.mbShareOddEven
);
985 aPropMap
.setProperty( PROP_FooterIsDynamicHeight
, maFooterData
.mbDynamicHeight
);
986 aPropMap
.setProperty( PROP_FooterHeight
, maFooterData
.mnHeight
);
987 aPropMap
.setProperty( PROP_FooterBodyDistance
, maFooterData
.mnBodyDist
);
989 if (rModel
.mxGraphic
.is())
991 aPropMap
.setProperty(PROP_BackGraphic
, rModel
.mxGraphic
);
992 aPropMap
.setProperty(PROP_BackGraphicLocation
, css::style::GraphicLocation_TILED
);
995 rPropSet
.setProperties( aPropMap
);
998 void PageSettingsConverter::convertHeaderFooterData(
999 PropertySet
& rPropSet
, HFHelperData
& orHFData
,
1000 const OUString
& rOddContent
, const OUString
& rEvenContent
, bool bUseEvenContent
,
1001 double fPageMargin
, double fContentMargin
)
1003 bool bHasOddContent
= !rOddContent
.isEmpty();
1004 bool bHasEvenContent
= bUseEvenContent
&& !rEvenContent
.isEmpty();
1006 sal_Int32 nOddHeight
= bHasOddContent
? writeHeaderFooter( rPropSet
, orHFData
.mnRightPropId
, rOddContent
) : 0;
1007 sal_Int32 nEvenHeight
= bHasEvenContent
? writeHeaderFooter( rPropSet
, orHFData
.mnLeftPropId
, rEvenContent
) : 0;
1009 orHFData
.mnHeight
= 750;
1010 orHFData
.mnBodyDist
= 250;
1011 orHFData
.mbHasContent
= bHasOddContent
|| bHasEvenContent
;
1012 orHFData
.mbShareOddEven
= !bUseEvenContent
;
1013 orHFData
.mbDynamicHeight
= true;
1015 if( !orHFData
.mbHasContent
)
1018 // use maximum height of odd/even header/footer
1019 orHFData
.mnHeight
= ::std::max( nOddHeight
, nEvenHeight
);
1020 /* Calc contains distance between bottom of header and top of page
1021 body in "HeaderBodyDistance" property, and distance between bottom
1022 of page body and top of footer in "FooterBodyDistance" property */
1023 orHFData
.mnBodyDist
= getUnitConverter().scaleToMm100( fPageMargin
- fContentMargin
, Unit::Inch
) - orHFData
.mnHeight
;
1024 /* #i23296# Distance less than 0 means, header or footer overlays page
1025 body. As this is not possible in Calc, set fixed header or footer
1026 height (crop header/footer) to get correct top position of page body. */
1027 orHFData
.mbDynamicHeight
= orHFData
.mnBodyDist
>= 0;
1028 /* "HeaderHeight" property is in fact distance from top of header to
1029 top of page body (including "HeaderBodyDistance").
1030 "FooterHeight" property is in fact distance from bottom of page
1031 body to bottom of footer (including "FooterBodyDistance"). */
1032 orHFData
.mnHeight
+= orHFData
.mnBodyDist
;
1033 // negative body distance not allowed
1034 orHFData
.mnBodyDist
= ::std::max
< sal_Int32
>( orHFData
.mnBodyDist
, 0 );
1037 sal_Int32
PageSettingsConverter::writeHeaderFooter(
1038 PropertySet
& rPropSet
, sal_Int32 nPropId
, const OUString
& rContent
)
1040 OSL_ENSURE( !rContent
.isEmpty(), "PageSettingsConverter::writeHeaderFooter - empty h/f string found" );
1041 sal_Int32 nHeight
= 0;
1042 if( !rContent
.isEmpty() )
1044 Reference
<sheet::XHeaderFooterContent
> xHFContent(rPropSet
.getAnyProperty(nPropId
), UNO_QUERY
);
1045 if( xHFContent
.is() )
1047 double fTotalHeight
= mxHFParser
->parse( xHFContent
, rContent
);
1048 rPropSet
.setProperty( nPropId
, xHFContent
);
1049 nHeight
= getUnitConverter().scaleToMm100( fTotalHeight
, Unit::Point
);
1057 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */