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/style/GraphicLocation.hpp>
28 #include <com/sun/star/text/FilenameDisplayFormat.hpp>
29 #include <com/sun/star/text/XText.hpp>
30 #include <com/sun/star/text/XTextContent.hpp>
31 #include <com/sun/star/text/XTextCursor.hpp>
32 #include <rtl/strbuf.hxx>
33 #include <rtl/ustrbuf.hxx>
34 #include <sax/tools/converter.hxx>
35 #include <oox/core/xmlfilterbase.hxx>
36 #include <oox/helper/attributelist.hxx>
37 #include <oox/helper/graphichelper.hxx>
38 #include <oox/helper/propertymap.hxx>
39 #include <oox/helper/propertyset.hxx>
40 #include <oox/token/namespaces.hxx>
41 #include <oox/token/properties.hxx>
42 #include <oox/token/tokens.hxx>
43 #include "biffinputstream.hxx"
44 #include "excelhandlers.hxx"
45 #include "stylesbuffer.hxx"
46 #include "unitconverter.hxx"
47 #include "document.hxx"
48 #include <filter/msfilter/util.hxx>
53 using namespace ::com::sun::star
;
54 using namespace ::com::sun::star::lang
;
55 using namespace ::com::sun::star::uno
;
57 using ::oox::core::Relations
;
61 const double OOX_MARGIN_DEFAULT_LR
= 0.748; /// Left/right default margin in inches.
62 const double OOX_MARGIN_DEFAULT_TB
= 0.984; /// Top/bottom default margin in inches.
63 const double OOX_MARGIN_DEFAULT_HF
= 0.512; /// Header/footer default margin in inches.
65 const sal_uInt16 BIFF12_PRINTOPT_HORCENTER
= 0x0001;
66 const sal_uInt16 BIFF12_PRINTOPT_VERCENTER
= 0x0002;
67 const sal_uInt16 BIFF12_PRINTOPT_PRINTHEADING
= 0x0004;
68 const sal_uInt16 BIFF12_PRINTOPT_PRINTGRID
= 0x0008;
70 const sal_uInt16 BIFF12_HEADERFOOTER_DIFFEVEN
= 0x0001;
71 const sal_uInt16 BIFF12_HEADERFOOTER_DIFFFIRST
= 0x0002;
73 const sal_uInt16 BIFF12_PAGESETUP_INROWS
= 0x0001;
74 const sal_uInt16 BIFF12_PAGESETUP_LANDSCAPE
= 0x0002;
75 const sal_uInt16 BIFF12_PAGESETUP_INVALID
= 0x0004;
76 const sal_uInt16 BIFF12_PAGESETUP_BLACKWHITE
= 0x0008;
77 const sal_uInt16 BIFF12_PAGESETUP_DRAFTQUALITY
= 0x0010;
78 const sal_uInt16 BIFF12_PAGESETUP_PRINTNOTES
= 0x0020;
79 const sal_uInt16 BIFF12_PAGESETUP_DEFAULTORIENT
= 0x0040;
80 const sal_uInt16 BIFF12_PAGESETUP_USEFIRSTPAGE
= 0x0080;
81 const sal_uInt16 BIFF12_PAGESETUP_NOTES_END
= 0x0100; // different to BIFF flag
83 const sal_uInt16 BIFF12_CHARTPAGESETUP_LANDSCAPE
= 0x0001;
84 const sal_uInt16 BIFF12_CHARTPAGESETUP_INVALID
= 0x0002;
85 const sal_uInt16 BIFF12_CHARTPAGESETUP_BLACKWHITE
= 0x0004;
86 const sal_uInt16 BIFF12_CHARTPAGESETUP_DEFAULTORIENT
= 0x0008;
87 const sal_uInt16 BIFF12_CHARTPAGESETUP_USEFIRSTPAGE
= 0x0010;
88 const sal_uInt16 BIFF12_CHARTPAGESETUP_DRAFTQUALITY
= 0x0020;
92 PageSettingsModel::PageSettingsModel() :
93 mfLeftMargin( OOX_MARGIN_DEFAULT_LR
),
94 mfRightMargin( OOX_MARGIN_DEFAULT_LR
),
95 mfTopMargin( OOX_MARGIN_DEFAULT_TB
),
96 mfBottomMargin( OOX_MARGIN_DEFAULT_TB
),
97 mfHeaderMargin( OOX_MARGIN_DEFAULT_HF
),
98 mfFooterMargin( OOX_MARGIN_DEFAULT_HF
),
107 mnHorPrintRes( 600 ),
108 mnVerPrintRes( 600 ),
109 mnOrientation( XML_default
),
110 mnPageOrder( XML_downThenOver
),
111 mnCellComments( XML_none
),
112 mnPrintErrors( XML_displayed
),
113 mbUseEvenHF( false ),
114 mbUseFirstHF( false ),
115 mbValidSettings( true ),
116 mbUseFirstPage( false ),
117 mbBlackWhite( false ),
118 mbDraftQuality( false ),
119 mbFitToPages( false ),
120 mbHorCenter( false ),
121 mbVerCenter( false ),
122 mbPrintGrid( false ),
123 mbPrintHeadings( false )
127 void PageSettingsModel::setBiffPrintErrors( sal_uInt8 nPrintErrors
)
129 static const sal_Int32 spnErrorIds
[] = { XML_displayed
, XML_none
, XML_dash
, XML_NA
};
130 mnPrintErrors
= STATIC_ARRAY_SELECT( spnErrorIds
, nPrintErrors
, XML_none
);
133 PageSettings::PageSettings( const WorksheetHelper
& rHelper
) :
134 WorksheetHelper( rHelper
)
138 void PageSettings::importPrintOptions( const AttributeList
& rAttribs
)
140 maModel
.mbHorCenter
= rAttribs
.getBool( XML_horizontalCentered
, false );
141 maModel
.mbVerCenter
= rAttribs
.getBool( XML_verticalCentered
, false );
142 maModel
.mbPrintGrid
= rAttribs
.getBool( XML_gridLines
, false );
143 maModel
.mbPrintHeadings
= rAttribs
.getBool( XML_headings
, false );
146 void PageSettings::importPageMargins( const AttributeList
& rAttribs
)
148 maModel
.mfLeftMargin
= rAttribs
.getDouble( XML_left
, OOX_MARGIN_DEFAULT_LR
);
149 maModel
.mfRightMargin
= rAttribs
.getDouble( XML_right
, OOX_MARGIN_DEFAULT_LR
);
150 maModel
.mfTopMargin
= rAttribs
.getDouble( XML_top
, OOX_MARGIN_DEFAULT_TB
);
151 maModel
.mfBottomMargin
= rAttribs
.getDouble( XML_bottom
, OOX_MARGIN_DEFAULT_TB
);
152 maModel
.mfHeaderMargin
= rAttribs
.getDouble( XML_header
, OOX_MARGIN_DEFAULT_HF
);
153 maModel
.mfFooterMargin
= rAttribs
.getDouble( XML_footer
, OOX_MARGIN_DEFAULT_HF
);
156 void PageSettings::importPageSetup( const Relations
& rRelations
, const AttributeList
& rAttribs
)
159 maModel
.maBinSettPath
= rRelations
.getFragmentPathFromRelId( rAttribs
.getString( R_TOKEN( id
), OUString() ) );
160 maModel
.mnPaperSize
= rAttribs
.getInteger( XML_paperSize
, 1 );
161 aStr
= rAttribs
.getString ( XML_paperWidth
, OUString() );
162 ::sax::Converter::convertMeasure(
163 maModel
.mnPaperWidth
, aStr
);
164 aStr
= rAttribs
.getString ( XML_paperHeight
, OUString() );
165 ::sax::Converter::convertMeasure(
166 maModel
.mnPaperHeight
, aStr
);
167 maModel
.mnCopies
= rAttribs
.getInteger( XML_copies
, 1 );
168 maModel
.mnScale
= rAttribs
.getInteger( XML_scale
, 100 );
169 maModel
.mnFirstPage
= rAttribs
.getInteger( XML_firstPageNumber
, 1 );
170 maModel
.mnFitToWidth
= rAttribs
.getInteger( XML_fitToWidth
, 1 );
171 maModel
.mnFitToHeight
= rAttribs
.getInteger( XML_fitToHeight
, 1 );
172 maModel
.mnHorPrintRes
= rAttribs
.getInteger( XML_horizontalDpi
, 600 );
173 maModel
.mnVerPrintRes
= rAttribs
.getInteger( XML_verticalDpi
, 600 );
174 maModel
.mnOrientation
= rAttribs
.getToken( XML_orientation
, XML_default
);
175 maModel
.mnPageOrder
= rAttribs
.getToken( XML_pageOrder
, XML_downThenOver
);
176 maModel
.mnCellComments
= rAttribs
.getToken( XML_cellComments
, XML_none
);
177 maModel
.mnPrintErrors
= rAttribs
.getToken( XML_errors
, XML_displayed
);
178 maModel
.mbValidSettings
= rAttribs
.getBool( XML_usePrinterDefaults
, false );
179 maModel
.mbUseFirstPage
= rAttribs
.getBool( XML_useFirstPageNumber
, false );
180 maModel
.mbBlackWhite
= rAttribs
.getBool( XML_blackAndWhite
, false );
181 maModel
.mbDraftQuality
= rAttribs
.getBool( XML_draft
, false );
184 void PageSettings::importChartPageSetup( const Relations
& rRelations
, const AttributeList
& rAttribs
)
187 maModel
.maBinSettPath
= rRelations
.getFragmentPathFromRelId( rAttribs
.getString( R_TOKEN( id
), OUString() ) );
188 maModel
.mnPaperSize
= rAttribs
.getInteger( XML_paperSize
, 1 );
189 aStr
= rAttribs
.getString ( XML_paperWidth
, OUString() );
190 ::sax::Converter::convertMeasure(
191 maModel
.mnPaperWidth
, aStr
);
192 aStr
= rAttribs
.getString ( XML_paperHeight
, OUString() );
193 ::sax::Converter::convertMeasure(
194 maModel
.mnPaperHeight
, aStr
);
195 maModel
.mnCopies
= rAttribs
.getInteger( XML_copies
, 1 );
196 maModel
.mnFirstPage
= rAttribs
.getInteger( XML_firstPageNumber
, 1 );
197 maModel
.mnHorPrintRes
= rAttribs
.getInteger( XML_horizontalDpi
, 600 );
198 maModel
.mnVerPrintRes
= rAttribs
.getInteger( XML_verticalDpi
, 600 );
199 maModel
.mnOrientation
= rAttribs
.getToken( XML_orientation
, XML_default
);
200 maModel
.mbValidSettings
= rAttribs
.getBool( XML_usePrinterDefaults
, false );
201 maModel
.mbUseFirstPage
= rAttribs
.getBool( XML_useFirstPageNumber
, false );
202 maModel
.mbBlackWhite
= rAttribs
.getBool( XML_blackAndWhite
, false );
203 maModel
.mbDraftQuality
= rAttribs
.getBool( XML_draft
, false );
206 void PageSettings::importHeaderFooter( const AttributeList
& rAttribs
)
208 maModel
.mbUseEvenHF
= rAttribs
.getBool( XML_differentOddEven
, false );
209 maModel
.mbUseFirstHF
= rAttribs
.getBool( XML_differentFirst
, false );
212 void PageSettings::importHeaderFooterCharacters( const OUString
& rChars
, sal_Int32 nElement
)
216 case XLS_TOKEN( oddHeader
): maModel
.maOddHeader
+= rChars
; break;
217 case XLS_TOKEN( oddFooter
): maModel
.maOddFooter
+= rChars
; break;
218 case XLS_TOKEN( evenHeader
): maModel
.maEvenHeader
+= rChars
; break;
219 case XLS_TOKEN( evenFooter
): maModel
.maEvenFooter
+= rChars
; break;
220 case XLS_TOKEN( firstHeader
): maModel
.maFirstHeader
+= rChars
; break;
221 case XLS_TOKEN( firstFooter
): maModel
.maFirstFooter
+= rChars
; break;
225 void PageSettings::importPicture( const Relations
& rRelations
, const AttributeList
& rAttribs
)
227 importPictureData( rRelations
, rAttribs
.getString( R_TOKEN( id
), OUString() ) );
230 void PageSettings::importPageMargins( SequenceInputStream
& rStrm
)
232 maModel
.mfLeftMargin
= rStrm
.readDouble();
233 maModel
.mfRightMargin
= rStrm
.readDouble();
234 maModel
.mfTopMargin
= rStrm
.readDouble();
235 maModel
.mfBottomMargin
= rStrm
.readDouble();
236 maModel
.mfHeaderMargin
= rStrm
.readDouble();
237 maModel
.mfFooterMargin
= rStrm
.readDouble();
240 void PageSettings::importPrintOptions( SequenceInputStream
& rStrm
)
243 nFlags
= rStrm
.readuInt16();
244 maModel
.mbHorCenter
= getFlag( nFlags
, BIFF12_PRINTOPT_HORCENTER
);
245 maModel
.mbVerCenter
= getFlag( nFlags
, BIFF12_PRINTOPT_VERCENTER
);
246 maModel
.mbPrintGrid
= getFlag( nFlags
, BIFF12_PRINTOPT_PRINTGRID
);
247 maModel
.mbPrintHeadings
= getFlag( nFlags
, BIFF12_PRINTOPT_PRINTHEADING
);
250 void PageSettings::importPageSetup( const Relations
& rRelations
, SequenceInputStream
& rStrm
)
254 maModel
.mnPaperSize
= rStrm
.readInt32();
255 maModel
.mnScale
= rStrm
.readInt32();
256 maModel
.mnHorPrintRes
= rStrm
.readInt32();
257 maModel
.mnVerPrintRes
= rStrm
.readInt32();
258 maModel
.mnCopies
= rStrm
.readInt32();
259 maModel
.mnFirstPage
= rStrm
.readInt32();
260 maModel
.mnFitToWidth
= rStrm
.readInt32();
261 maModel
.mnFitToHeight
= rStrm
.readInt32();
262 nFlags
= rStrm
.readuInt16();
264 maModel
.setBiffPrintErrors( extractValue
< sal_uInt8
>( nFlags
, 9, 2 ) );
265 maModel
.maBinSettPath
= rRelations
.getFragmentPathFromRelId( aRelId
);
266 maModel
.mnOrientation
= getFlagValue( nFlags
, BIFF12_PAGESETUP_DEFAULTORIENT
, XML_default
, getFlagValue( nFlags
, BIFF12_PAGESETUP_LANDSCAPE
, XML_landscape
, XML_portrait
) );
267 maModel
.mnPageOrder
= getFlagValue( nFlags
, BIFF12_PAGESETUP_INROWS
, XML_overThenDown
, XML_downThenOver
);
268 maModel
.mnCellComments
= getFlagValue( nFlags
, BIFF12_PAGESETUP_PRINTNOTES
, getFlagValue( nFlags
, BIFF12_PAGESETUP_NOTES_END
, XML_atEnd
, XML_asDisplayed
), XML_none
);
269 maModel
.mbValidSettings
= !getFlag( nFlags
, BIFF12_PAGESETUP_INVALID
);
270 maModel
.mbUseFirstPage
= getFlag( nFlags
, BIFF12_PAGESETUP_USEFIRSTPAGE
);
271 maModel
.mbBlackWhite
= getFlag( nFlags
, BIFF12_PAGESETUP_BLACKWHITE
);
272 maModel
.mbDraftQuality
= getFlag( nFlags
, BIFF12_PAGESETUP_DRAFTQUALITY
);
275 void PageSettings::importChartPageSetup( const Relations
& rRelations
, SequenceInputStream
& rStrm
)
278 sal_uInt16 nFirstPage
, nFlags
;
279 maModel
.mnPaperSize
= rStrm
.readInt32();
280 maModel
.mnHorPrintRes
= rStrm
.readInt32();
281 maModel
.mnVerPrintRes
= rStrm
.readInt32();
282 maModel
.mnCopies
= rStrm
.readInt32();
283 nFirstPage
= rStrm
.readuInt16();
284 nFlags
= rStrm
.readuInt16();
286 maModel
.maBinSettPath
= rRelations
.getFragmentPathFromRelId( aRelId
);
287 maModel
.mnFirstPage
= nFirstPage
; // 16-bit in CHARTPAGESETUP
288 maModel
.mnOrientation
= getFlagValue( nFlags
, BIFF12_CHARTPAGESETUP_DEFAULTORIENT
, XML_default
, getFlagValue( nFlags
, BIFF12_CHARTPAGESETUP_LANDSCAPE
, XML_landscape
, XML_portrait
) );
289 maModel
.mbValidSettings
= !getFlag( nFlags
, BIFF12_CHARTPAGESETUP_INVALID
);
290 maModel
.mbUseFirstPage
= getFlag( nFlags
, BIFF12_CHARTPAGESETUP_USEFIRSTPAGE
);
291 maModel
.mbBlackWhite
= getFlag( nFlags
, BIFF12_CHARTPAGESETUP_BLACKWHITE
);
292 maModel
.mbDraftQuality
= getFlag( nFlags
, BIFF12_CHARTPAGESETUP_DRAFTQUALITY
);
295 void PageSettings::importHeaderFooter( SequenceInputStream
& rStrm
)
298 nFlags
= rStrm
.readuInt16();
299 rStrm
>> maModel
.maOddHeader
>> maModel
.maOddFooter
300 >> maModel
.maEvenHeader
>> maModel
.maEvenFooter
301 >> maModel
.maFirstHeader
>> maModel
.maFirstFooter
;
302 maModel
.mbUseEvenHF
= getFlag( nFlags
, BIFF12_HEADERFOOTER_DIFFEVEN
);
303 maModel
.mbUseFirstHF
= getFlag( nFlags
, BIFF12_HEADERFOOTER_DIFFFIRST
);
306 void PageSettings::importPicture( const Relations
& rRelations
, SequenceInputStream
& rStrm
)
308 importPictureData( rRelations
, BiffHelper::readString( rStrm
) );
311 void PageSettings::setFitToPagesMode( bool bFitToPages
)
313 maModel
.mbFitToPages
= bFitToPages
;
316 void PageSettings::finalizeImport()
318 OUStringBuffer
aStyleNameBuffer( "PageStyle_" );
319 Reference
<container::XNamed
> xSheetName(getSheet(), UNO_QUERY
);
320 if( xSheetName
.is() )
321 aStyleNameBuffer
.append( xSheetName
->getName() );
323 aStyleNameBuffer
.append( static_cast< sal_Int32
>( getSheetIndex() + 1 ) );
324 OUString aStyleName
= aStyleNameBuffer
.makeStringAndClear();
326 Reference
<style::XStyle
> xStyle
= createStyleObject(aStyleName
, true);
327 PropertySet
aStyleProps( xStyle
);
328 getPageSettingsConverter().writePageSettingsProperties( aStyleProps
, maModel
, getSheetType() );
330 // Set page style name to the sheet.
331 SCTAB nTab
= getSheetIndex();
332 getScDocument().SetPageStyle(nTab
, aStyleName
);
335 void PageSettings::importPictureData( const Relations
& rRelations
, const OUString
& rRelId
)
337 OUString aPicturePath
= rRelations
.getFragmentPathFromRelId( rRelId
);
338 if( !aPicturePath
.isEmpty() )
339 maModel
.maGraphicUrl
= getBaseFilter().getGraphicHelper().importEmbeddedGraphicObject( aPicturePath
);
352 Reference
<text::XText
> mxText
; /// XText interface of this portion.
353 Reference
<text::XTextCursor
> mxStart
; /// Start position of current text range for formatting.
354 Reference
<text::XTextCursor
> mxEnd
; /// End position of current text range for formatting.
355 double mfTotalHeight
; /// Sum of heights of previous lines in points.
356 double mfCurrHeight
; /// Height of the current text line in points.
358 bool initialize( const Reference
<text::XText
>& rxText
);
361 bool HFPortionInfo::initialize( const Reference
<text::XText
>& rxText
)
363 mfTotalHeight
= mfCurrHeight
= 0.0;
367 mxStart
= mxText
->createTextCursor();
368 mxEnd
= mxText
->createTextCursor();
370 bool bRet
= mxText
.is() && mxStart
.is() && mxEnd
.is();
371 OSL_ENSURE( bRet
, "HFPortionInfo::initialize - missing interfaces" );
375 class HeaderFooterParser
: public WorkbookHelper
378 explicit HeaderFooterParser( const WorkbookHelper
& rHelper
);
380 /** Parses the passed string and creates the header/footer contents.
381 @returns The total height of the converted header or footer in points. */
383 const Reference
<sheet::XHeaderFooterContent
>& rxContext
,
384 const OUString
& rData
);
387 /** Returns the current edit engine text object. */
388 inline HFPortionInfo
& getPortion() { return maPortions
[ meCurrPortion
]; }
389 /** Returns the start cursor of the current text range. */
390 inline const Reference
<text::XTextCursor
>& getStartPos() { return getPortion().mxStart
; }
391 /** Returns the end cursor of the current text range. */
392 inline const Reference
<text::XTextCursor
>& getEndPos() { return getPortion().mxEnd
; }
394 /** Returns the current line height of the specified portion. */
395 double getCurrHeight( HFPortionId ePortion
) const;
396 /** Returns the current line height. */
397 double getCurrHeight() const;
399 /** Updates the current line height of the specified portion, using the current font size. */
400 void updateCurrHeight( HFPortionId ePortion
);
401 /** Updates the current line height, using the current font size. */
402 void updateCurrHeight();
404 /** Sets the font attributes at the current selection. */
405 void setAttributes();
406 /** Appends and clears internal string buffer. */
408 /** Appends a line break and adjusts internal text height data. */
409 void appendLineBreak();
411 /** Creates a text field from the passed service name. */
412 Reference
<text::XTextContent
> createField( const OUString
& rServiceName
) const;
413 /** Appends the passed text field. */
414 void appendField( const Reference
<text::XTextContent
>& rxContent
);
416 /** Sets the passed font name if it is valid. */
417 void convertFontName( const OUString
& rStyle
);
418 /** Converts a font style given as string. */
419 void convertFontStyle( const OUString
& rStyle
);
420 /** Converts a font color given as string. */
421 void convertFontColor( const OUString
& rColor
);
423 /** Finalizes current portion: sets font attributes and updates text height data. */
424 void finalizePortion();
425 /** Changes current header/footer portion. */
426 void setNewPortion( HFPortionId ePortion
);
429 typedef ::std::vector
< HFPortionInfo
> HFPortionInfoVec
;
430 typedef ::std::set
< OString
> OStringSet
;
432 const OUString maPageNumberService
;
433 const OUString maPageCountService
;
434 const OUString maSheetNameService
;
435 const OUString maFileNameService
;
436 const OUString maDateTimeService
;
437 const OStringSet maBoldNames
; /// All names for bold font style in lowercase UTF-8.
438 const OStringSet maItalicNames
; /// All names for italic font style in lowercase UTF-8.
439 HFPortionInfoVec maPortions
;
440 HFPortionId meCurrPortion
; /// Identifier of current H/F portion.
441 OUStringBuffer maBuffer
; /// Text data to append to current text range.
442 FontModel maFontModel
; /// Font attributes of current text range.
447 // different names for bold font style (lowercase)
448 static const sal_Char
* const sppcBoldNames
[] =
451 "fett", // German 'bold'
453 "halbfett", // German 'demibold'
458 // different names for italic font style (lowercase)
459 static const sal_Char
* const sppcItalicNames
[] =
462 "kursiv", // German 'italic'
464 "schr\303\204g", // German 'oblique' with uppercase A umlaut
465 "schr\303\244g" // German 'oblique' with lowercase A umlaut
470 HeaderFooterParser::HeaderFooterParser( const WorkbookHelper
& rHelper
) :
471 WorkbookHelper( rHelper
),
472 maPageNumberService( "com.sun.star.text.TextField.PageNumber" ),
473 maPageCountService( "com.sun.star.text.TextField.PageCount" ),
474 maSheetNameService( "com.sun.star.text.TextField.SheetName" ),
475 maFileNameService( "com.sun.star.text.TextField.FileName" ),
476 maDateTimeService( "com.sun.star.text.TextField.DateTime" ),
477 maBoldNames( sppcBoldNames
, ::std::end(sppcBoldNames
) ),
478 maItalicNames( sppcItalicNames
, ::std::end(sppcItalicNames
) ),
479 maPortions( static_cast< size_t >( HF_COUNT
) ),
480 meCurrPortion( HF_CENTER
)
484 double HeaderFooterParser::parse( const Reference
<sheet::XHeaderFooterContent
>& rxContext
, const OUString
& rData
)
486 if( !rxContext
.is() || rData
.isEmpty() ||
487 !maPortions
[ HF_LEFT
].initialize( rxContext
->getLeftText() ) ||
488 !maPortions
[ HF_CENTER
].initialize( rxContext
->getCenterText() ) ||
489 !maPortions
[ HF_RIGHT
].initialize( rxContext
->getRightText() ) )
492 meCurrPortion
= HF_CENTER
;
493 maBuffer
.setLength( 0 );
494 maFontModel
= getStyles().getDefaultFontModel();
495 OUStringBuffer aFontName
; // current font name
496 OUStringBuffer aFontStyle
; // current font style
497 sal_Int32 nFontHeight
= 0; // current font height
499 /** State of the parser. */
502 STATE_TEXT
, /// Literal text data.
503 STATE_TOKEN
, /// Control token following a '&' character.
504 STATE_FONTNAME
, /// Font name ('&' is followed by '"', reads until next '"' or ',').
505 STATE_FONTSTYLE
, /// Font style name (font part after ',', reads until next '"').
506 STATE_FONTHEIGHT
/// Font height ('&' is followed by num. digits, reads until non-digit).
510 const sal_Unicode
* pcChar
= rData
.getStr();
511 const sal_Unicode
* pcEnd
= pcChar
+ rData
.getLength();
512 for( ; (pcChar
!= pcEnd
) && (*pcChar
!= 0); ++pcChar
)
514 sal_Unicode cChar
= *pcChar
;
521 case '&': // new token
523 eState
= STATE_TOKEN
;
525 case '\n': // line break
530 maBuffer
.append( cChar
);
537 // default: back to text mode, may be changed in specific cases
539 // ignore case of token codes
540 if( ('a' <= cChar
) && (cChar
<= 'z') )
541 (cChar
-= 'a') += 'A';
544 case '&': maBuffer
.append( cChar
); break; // the '&' character
546 case 'L': setNewPortion( HF_LEFT
); break; // left portion
547 case 'C': setNewPortion( HF_CENTER
); break; // center portion
548 case 'R': setNewPortion( HF_RIGHT
); break; // right portion
550 case 'P': // page number
551 appendField( createField( maPageNumberService
) );
553 case 'N': // total page count
554 appendField( createField( maPageCountService
) );
556 case 'A': // current sheet name
557 appendField( createField( maSheetNameService
) );
560 case 'F': // file name
562 Reference
<text::XTextContent
> xContent
= createField( maFileNameService
);
563 PropertySet
aPropSet( xContent
);
564 aPropSet
.setProperty( PROP_FileFormat
, css::text::FilenameDisplayFormat::NAME_AND_EXT
);
565 appendField( xContent
);
568 case 'Z': // file path (without file name), OOXML, BIFF12, and BIFF8 only
569 if( (getFilterType() == FILTER_OOXML
) || ((getFilterType() == FILTER_BIFF
) && (getBiff() == BIFF8
)) )
571 Reference
<text::XTextContent
> xContent
= createField( maFileNameService
);
572 PropertySet
aPropSet( xContent
);
573 // FilenameDisplayFormat::PATH not supported by Calc
574 aPropSet
.setProperty( PROP_FileFormat
, css::text::FilenameDisplayFormat::FULL
);
575 appendField( xContent
);
576 /* path only is not supported -- if we find a '&Z&F'
577 combination for path/name, skip the '&F' part */
578 if( (pcChar
+ 2 < pcEnd
) && (pcChar
[ 1 ] == '&') && ((pcChar
[ 2 ] == 'f') || (pcChar
[ 2 ] == 'F')) )
584 Reference
<text::XTextContent
> xContent
= createField( maDateTimeService
);
585 PropertySet
aPropSet( xContent
);
586 aPropSet
.setProperty( PROP_IsDate
, true );
587 appendField( xContent
);
592 Reference
<text::XTextContent
> xContent
= createField( maDateTimeService
);
593 PropertySet
aPropSet( xContent
);
594 aPropSet
.setProperty( PROP_IsDate
, false );
595 appendField( xContent
);
601 maFontModel
.mbBold
= !maFontModel
.mbBold
;
605 maFontModel
.mbItalic
= !maFontModel
.mbItalic
;
607 case 'U': // underline
609 maFontModel
.mnUnderline
= (maFontModel
.mnUnderline
== XML_single
) ? XML_none
: XML_single
;
611 case 'E': // double underline
613 maFontModel
.mnUnderline
= (maFontModel
.mnUnderline
== XML_double
) ? XML_none
: XML_double
;
615 case 'S': // strikeout
617 maFontModel
.mbStrikeout
= !maFontModel
.mbStrikeout
;
619 case 'X': // superscript
621 maFontModel
.mnEscapement
= (maFontModel
.mnEscapement
== XML_superscript
) ? XML_baseline
: XML_superscript
;
623 case 'Y': // subsrcipt
625 maFontModel
.mnEscapement
= (maFontModel
.mnEscapement
== XML_subscript
) ? XML_baseline
: XML_subscript
;
627 case 'O': // outlined
629 maFontModel
.mbOutline
= !maFontModel
.mbOutline
;
633 maFontModel
.mbShadow
= !maFontModel
.mbShadow
;
636 case 'K': // text color (not in BIFF)
637 if( (getFilterType() == FILTER_OOXML
) && (pcChar
+ 6 < pcEnd
) )
640 // eat the following 6 characters
641 convertFontColor( OUString( pcChar
+ 1, 6 ) );
646 case '\"': // font name
647 aFontName
.setLength( 0 );
648 aFontStyle
.setLength( 0 );
649 eState
= STATE_FONTNAME
;
652 if( ('0' <= cChar
) && (cChar
<= '9') ) // font size
654 nFontHeight
= cChar
- '0';
655 eState
= STATE_FONTHEIGHT
;
667 convertFontName( aFontName
.makeStringAndClear() );
671 eState
= STATE_FONTSTYLE
;
674 aFontName
.append( cChar
);
679 case STATE_FONTSTYLE
:
685 convertFontName( aFontName
.makeStringAndClear() );
686 convertFontStyle( aFontStyle
.makeStringAndClear() );
690 aFontStyle
.append( cChar
);
695 case STATE_FONTHEIGHT
:
697 if( ('0' <= cChar
) && (cChar
<= '9') )
699 if( nFontHeight
>= 0 )
702 nFontHeight
+= (cChar
- '0');
703 if( nFontHeight
> 1000 )
709 if( nFontHeight
> 0 )
712 maFontModel
.mfHeight
= nFontHeight
;
724 maPortions
[ HF_LEFT
].mfTotalHeight
+= getCurrHeight( HF_LEFT
);
725 maPortions
[ HF_CENTER
].mfTotalHeight
+= getCurrHeight( HF_CENTER
);
726 maPortions
[ HF_RIGHT
].mfTotalHeight
+= getCurrHeight( HF_RIGHT
);
728 return ::std::max( maPortions
[ HF_LEFT
].mfTotalHeight
,
729 ::std::max( maPortions
[ HF_CENTER
].mfTotalHeight
, maPortions
[ HF_RIGHT
].mfTotalHeight
) );
732 // private --------------------------------------------------------------------
734 double HeaderFooterParser::getCurrHeight( HFPortionId ePortion
) const
736 double fMaxHt
= maPortions
[ ePortion
].mfCurrHeight
;
737 return (fMaxHt
== 0.0) ? maFontModel
.mfHeight
: fMaxHt
;
740 double HeaderFooterParser::getCurrHeight() const
742 return getCurrHeight( meCurrPortion
);
745 void HeaderFooterParser::updateCurrHeight( HFPortionId ePortion
)
747 double& rfMaxHt
= maPortions
[ ePortion
].mfCurrHeight
;
748 rfMaxHt
= ::std::max( rfMaxHt
, maFontModel
.mfHeight
);
751 void HeaderFooterParser::updateCurrHeight()
753 updateCurrHeight( meCurrPortion
);
756 void HeaderFooterParser::setAttributes()
758 Reference
<text::XTextRange
> xRange( getStartPos(), UNO_QUERY
);
759 getEndPos()->gotoRange( xRange
, false );
760 getEndPos()->gotoEnd( true );
761 if( !getEndPos()->isCollapsed() )
763 Font
aFont( *this, maFontModel
);
764 aFont
.finalizeImport();
765 PropertySet
aPropSet( getEndPos() );
766 aFont
.writeToPropertySet( aPropSet
, FONT_PROPTYPE_TEXT
);
767 getStartPos()->gotoEnd( false );
768 getEndPos()->gotoEnd( false );
772 void HeaderFooterParser::appendText()
774 if( !maBuffer
.isEmpty() )
776 getEndPos()->gotoEnd( false );
777 getEndPos()->setString( maBuffer
.makeStringAndClear() );
782 void HeaderFooterParser::appendLineBreak()
784 getEndPos()->gotoEnd( false );
785 getEndPos()->setString( OUString( '\n' ) );
786 getPortion().mfTotalHeight
+= getCurrHeight();
787 getPortion().mfCurrHeight
= 0;
790 Reference
<text::XTextContent
> HeaderFooterParser::createField( const OUString
& rServiceName
) const
792 Reference
<text::XTextContent
> xContent
;
795 xContent
.set( getBaseFilter().getModelFactory()->createInstance( rServiceName
), UNO_QUERY_THROW
);
799 OSL_FAIL( OStringBuffer( "HeaderFooterParser::createField - error while creating text field \"" ).
800 append( OUStringToOString( rServiceName
, RTL_TEXTENCODING_ASCII_US
) ).
801 append( '"' ).getStr() );
806 void HeaderFooterParser::appendField( const Reference
<text::XTextContent
>& rxContent
)
808 getEndPos()->gotoEnd( false );
811 Reference
<text::XTextRange
> xRange( getEndPos(), UNO_QUERY_THROW
);
812 getPortion().mxText
->insertTextContent( xRange
, rxContent
, false );
820 void HeaderFooterParser::convertFontName( const OUString
& rName
)
822 if( !rName
.isEmpty() )
824 // single dash is document default font
825 if( (rName
.getLength() == 1) && (rName
[ 0 ] == '-') )
826 maFontModel
.maName
= getStyles().getDefaultFontModel().maName
;
828 maFontModel
.maName
= rName
;
832 void HeaderFooterParser::convertFontStyle( const OUString
& rStyle
)
834 maFontModel
.mbBold
= maFontModel
.mbItalic
= false;
836 sal_Int32 nLen
= rStyle
.getLength();
837 while( (0 <= nPos
) && (nPos
< nLen
) )
839 OString aToken
= OUStringToOString( rStyle
.getToken( 0, ' ', nPos
), RTL_TEXTENCODING_UTF8
).toAsciiLowerCase();
840 if( !aToken
.isEmpty() )
842 if( maBoldNames
.count( aToken
) > 0 )
843 maFontModel
.mbBold
= true;
844 else if( maItalicNames
.count( aToken
) > 0 )
845 maFontModel
.mbItalic
= true;
850 void HeaderFooterParser::convertFontColor( const OUString
& rColor
)
852 OSL_ENSURE( rColor
.getLength() == 6, "HeaderFooterParser::convertFontColor - invalid font color code" );
853 if( (rColor
[ 2 ] == '+') || (rColor
[ 2 ] == '-') )
854 // theme color: TTSNNN (TT = decimal theme index, S = +/-, NNN = decimal tint/shade in percent)
855 maFontModel
.maColor
.setTheme(
856 rColor
.copy( 0, 2 ).toInt32(),
857 static_cast< double >( rColor
.copy( 2 ).toInt32() ) / 100.0 );
860 maFontModel
.maColor
.setRgb( rColor
.toUInt32( 16 ) );
863 void HeaderFooterParser::finalizePortion()
869 void HeaderFooterParser::setNewPortion( HFPortionId ePortion
)
871 if( ePortion
!= meCurrPortion
)
874 meCurrPortion
= ePortion
;
875 maFontModel
= getStyles().getDefaultFontModel();
879 PageSettingsConverter::HFHelperData::HFHelperData( sal_Int32 nLeftPropId
, sal_Int32 nRightPropId
) :
880 mnLeftPropId( nLeftPropId
),
881 mnRightPropId( nRightPropId
),
884 mbHasContent( false ),
885 mbShareOddEven( false ),
886 mbDynamicHeight( false )
890 PageSettingsConverter::PageSettingsConverter( const WorkbookHelper
& rHelper
) :
891 WorkbookHelper( rHelper
),
892 mxHFParser( new HeaderFooterParser( rHelper
) ),
893 maHeaderData( PROP_LeftPageHeaderContent
, PROP_RightPageHeaderContent
),
894 maFooterData( PROP_LeftPageFooterContent
, PROP_RightPageFooterContent
)
898 PageSettingsConverter::~PageSettingsConverter()
902 void PageSettingsConverter::writePageSettingsProperties(
903 PropertySet
& rPropSet
, const PageSettingsModel
& rModel
, WorksheetType eSheetType
)
905 // special handling for chart sheets
906 bool bChartSheet
= eSheetType
== SHEETTYPE_CHARTSHEET
;
911 // always fit chart sheet to 1 page
912 rPropSet
.setProperty
< sal_Int16
>( PROP_ScaleToPages
, 1 );
914 else if( rModel
.mbFitToPages
)
916 // fit to number of pages
917 rPropSet
.setProperty( PROP_ScaleToPagesX
, getLimitedValue
< sal_Int16
, sal_Int32
>( rModel
.mnFitToWidth
, 0, 1000 ) );
918 rPropSet
.setProperty( PROP_ScaleToPagesY
, getLimitedValue
< sal_Int16
, sal_Int32
>( rModel
.mnFitToHeight
, 0, 1000 ) );
922 // scale may be 0 which indicates uninitialized
923 sal_Int16 nScale
= (rModel
.mbValidSettings
&& (rModel
.mnScale
> 0)) ? getLimitedValue
< sal_Int16
, sal_Int32
>( rModel
.mnScale
, 10, 400 ) : 100;
924 rPropSet
.setProperty( PROP_PageScale
, nScale
);
928 bool bLandscape
= rModel
.mnOrientation
== XML_landscape
;
929 // default orientation for current sheet type (chart sheets default to landscape)
930 if( bChartSheet
&& ( !rModel
.mbValidSettings
|| (rModel
.mnOrientation
== XML_default
) ) )
934 if( !rModel
.mbValidSettings
)
939 if( (0 < rModel
.mnPaperSize
) )
941 const msfilter::util::ApiPaperSize
& rPaperSize
= msfilter::util::PaperSizeConv::getApiSizeForMSPaperSizeIndex( rModel
.mnPaperSize
);
942 aSize
= awt::Size( rPaperSize
.mnWidth
, rPaperSize
.mnHeight
);
943 bValid
= ( rPaperSize
.mnWidth
!= 0 && rPaperSize
.mnHeight
!= 0 );
945 if( rModel
.mnPaperWidth
> 0 && rModel
.mnPaperHeight
> 0 )
947 aSize
= awt::Size( rModel
.mnPaperWidth
, rModel
.mnPaperHeight
);
954 ::std::swap( aSize
.Width
, aSize
.Height
);
955 rPropSet
.setProperty( PROP_Size
, aSize
);
960 convertHeaderFooterData( rPropSet
, maHeaderData
, rModel
.maOddHeader
, rModel
.maEvenHeader
, rModel
.mbUseEvenHF
, rModel
.mfTopMargin
, rModel
.mfHeaderMargin
);
961 convertHeaderFooterData( rPropSet
, maFooterData
, rModel
.maOddFooter
, rModel
.maEvenFooter
, rModel
.mbUseEvenHF
, rModel
.mfBottomMargin
, rModel
.mfFooterMargin
);
963 // write all properties to property set
964 const UnitConverter
& rUnitConv
= getUnitConverter();
965 PropertyMap aPropMap
;
966 aPropMap
.setProperty( PROP_IsLandscape
, bLandscape
);
967 aPropMap
.setProperty( PROP_FirstPageNumber
, getLimitedValue
< sal_Int16
, sal_Int32
>( rModel
.mbUseFirstPage
? rModel
.mnFirstPage
: 0, 0, 9999 ));
968 aPropMap
.setProperty( PROP_PrintDownFirst
, (rModel
.mnPageOrder
== XML_downThenOver
));
969 aPropMap
.setProperty( PROP_PrintAnnotations
, (rModel
.mnCellComments
== XML_asDisplayed
));
970 aPropMap
.setProperty( PROP_CenterHorizontally
, rModel
.mbHorCenter
);
971 aPropMap
.setProperty( PROP_CenterVertically
, rModel
.mbVerCenter
);
972 aPropMap
.setProperty( PROP_PrintGrid
, (!bChartSheet
&& rModel
.mbPrintGrid
)); // no gridlines in chart sheets
973 aPropMap
.setProperty( PROP_PrintHeaders
, (!bChartSheet
&& rModel
.mbPrintHeadings
)); // no column/row headings in chart sheets
974 aPropMap
.setProperty( PROP_LeftMargin
, rUnitConv
.scaleToMm100( rModel
.mfLeftMargin
, UNIT_INCH
));
975 aPropMap
.setProperty( PROP_RightMargin
, rUnitConv
.scaleToMm100( rModel
.mfRightMargin
, UNIT_INCH
));
976 // #i23296# In Calc, "TopMargin" property is distance to top of header if enabled
977 aPropMap
.setProperty( PROP_TopMargin
, rUnitConv
.scaleToMm100( maHeaderData
.mbHasContent
? rModel
.mfHeaderMargin
: rModel
.mfTopMargin
, UNIT_INCH
));
978 // #i23296# In Calc, "BottomMargin" property is distance to bottom of footer if enabled
979 aPropMap
.setProperty( PROP_BottomMargin
, rUnitConv
.scaleToMm100( maFooterData
.mbHasContent
? rModel
.mfFooterMargin
: rModel
.mfBottomMargin
, UNIT_INCH
));
980 aPropMap
.setProperty( PROP_HeaderIsOn
, maHeaderData
.mbHasContent
);
981 aPropMap
.setProperty( PROP_HeaderIsShared
, maHeaderData
.mbShareOddEven
);
982 aPropMap
.setProperty( PROP_HeaderIsDynamicHeight
, maHeaderData
.mbDynamicHeight
);
983 aPropMap
.setProperty( PROP_HeaderHeight
, maHeaderData
.mnHeight
);
984 aPropMap
.setProperty( PROP_HeaderBodyDistance
, maHeaderData
.mnBodyDist
);
985 aPropMap
.setProperty( PROP_FooterIsOn
, maFooterData
.mbHasContent
);
986 aPropMap
.setProperty( PROP_FooterIsShared
, maFooterData
.mbShareOddEven
);
987 aPropMap
.setProperty( PROP_FooterIsDynamicHeight
, maFooterData
.mbDynamicHeight
);
988 aPropMap
.setProperty( PROP_FooterHeight
, maFooterData
.mnHeight
);
989 aPropMap
.setProperty( PROP_FooterBodyDistance
, maFooterData
.mnBodyDist
);
991 if( !rModel
.maGraphicUrl
.isEmpty() )
993 aPropMap
.setProperty( PROP_BackGraphicURL
, rModel
.maGraphicUrl
);
994 aPropMap
.setProperty( PROP_BackGraphicLocation
, css::style::GraphicLocation_TILED
);
997 rPropSet
.setProperties( aPropMap
);
1000 void PageSettingsConverter::convertHeaderFooterData(
1001 PropertySet
& rPropSet
, HFHelperData
& orHFData
,
1002 const OUString
& rOddContent
, const OUString
& rEvenContent
, bool bUseEvenContent
,
1003 double fPageMargin
, double fContentMargin
)
1005 bool bHasOddContent
= !rOddContent
.isEmpty();
1006 bool bHasEvenContent
= bUseEvenContent
&& !rEvenContent
.isEmpty();
1008 sal_Int32 nOddHeight
= bHasOddContent
? writeHeaderFooter( rPropSet
, orHFData
.mnRightPropId
, rOddContent
) : 0;
1009 sal_Int32 nEvenHeight
= bHasEvenContent
? writeHeaderFooter( rPropSet
, orHFData
.mnLeftPropId
, rEvenContent
) : 0;
1011 orHFData
.mnHeight
= 750;
1012 orHFData
.mnBodyDist
= 250;
1013 orHFData
.mbHasContent
= bHasOddContent
|| bHasEvenContent
;
1014 orHFData
.mbShareOddEven
= !bUseEvenContent
;
1015 orHFData
.mbDynamicHeight
= true;
1017 if( orHFData
.mbHasContent
)
1019 // use maximum height of odd/even header/footer
1020 orHFData
.mnHeight
= ::std::max( nOddHeight
, nEvenHeight
);
1021 /* Calc contains distance between bottom of header and top of page
1022 body in "HeaderBodyDistance" property, and distance between bottom
1023 of page body and top of footer in "FooterBodyDistance" property */
1024 orHFData
.mnBodyDist
= getUnitConverter().scaleToMm100( fPageMargin
- fContentMargin
, UNIT_INCH
) - orHFData
.mnHeight
;
1025 /* #i23296# Distance less than 0 means, header or footer overlays page
1026 body. As this is not possible in Calc, set fixed header or footer
1027 height (crop header/footer) to get correct top position of page body. */
1028 orHFData
.mbDynamicHeight
= orHFData
.mnBodyDist
>= 0;
1029 /* "HeaderHeight" property is in fact distance from top of header to
1030 top of page body (including "HeaderBodyDistance").
1031 "FooterHeight" property is in fact distance from bottom of page
1032 body to bottom of footer (including "FooterBodyDistance"). */
1033 orHFData
.mnHeight
+= orHFData
.mnBodyDist
;
1034 // negative body distance not allowed
1035 orHFData
.mnBodyDist
= ::std::max
< sal_Int32
>( orHFData
.mnBodyDist
, 0 );
1039 sal_Int32
PageSettingsConverter::writeHeaderFooter(
1040 PropertySet
& rPropSet
, sal_Int32 nPropId
, const OUString
& rContent
)
1042 OSL_ENSURE( !rContent
.isEmpty(), "PageSettingsConverter::writeHeaderFooter - empty h/f string found" );
1043 sal_Int32 nHeight
= 0;
1044 if( !rContent
.isEmpty() )
1046 Reference
<sheet::XHeaderFooterContent
> xHFContent(rPropSet
.getAnyProperty(nPropId
), UNO_QUERY
);
1047 if( xHFContent
.is() )
1049 double fTotalHeight
= mxHFParser
->parse( xHFContent
, rContent
);
1050 rPropSet
.setProperty( nPropId
, xHFContent
);
1051 nHeight
= getUnitConverter().scaleToMm100( fTotalHeight
, UNIT_POINT
);
1060 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */