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/XTextCursor.hpp>
31 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
32 #include <osl/diagnose.h>
33 #include <rtl/strbuf.hxx>
34 #include <rtl/ustrbuf.hxx>
35 #include <sax/tools/converter.hxx>
36 #include <oox/helper/attributelist.hxx>
37 #include <oox/helper/binaryinputstream.hxx>
38 #include <oox/helper/graphichelper.hxx>
39 #include <oox/helper/propertymap.hxx>
40 #include <oox/helper/propertyset.hxx>
41 #include <oox/token/namespaces.hxx>
42 #include <oox/token/properties.hxx>
43 #include <oox/token/tokens.hxx>
44 #include <oox/core/filterbase.hxx>
45 #include <oox/core/relations.hxx>
46 #include <stylesbuffer.hxx>
47 #include <unitconverter.hxx>
48 #include <document.hxx>
49 #include <biffhelper.hxx>
50 #include <filter/msfilter/util.hxx>
55 using namespace ::com::sun::star
;
56 using namespace ::com::sun::star::lang
;
57 using namespace ::com::sun::star::uno
;
59 using ::oox::core::Relations
;
63 const double OOX_MARGIN_DEFAULT_LR
= 0.748; /// Left/right default margin in inches.
64 const double OOX_MARGIN_DEFAULT_TB
= 0.984; /// Top/bottom default margin in inches.
65 const double OOX_MARGIN_DEFAULT_HF
= 0.512; /// Header/footer default margin in inches.
67 const sal_uInt16 BIFF12_PRINTOPT_HORCENTER
= 0x0001;
68 const sal_uInt16 BIFF12_PRINTOPT_VERCENTER
= 0x0002;
69 const sal_uInt16 BIFF12_PRINTOPT_PRINTHEADING
= 0x0004;
70 const sal_uInt16 BIFF12_PRINTOPT_PRINTGRID
= 0x0008;
72 const sal_uInt16 BIFF12_HEADERFOOTER_DIFFEVEN
= 0x0001;
73 const sal_uInt16 BIFF12_HEADERFOOTER_DIFFFIRST
= 0x0002;
75 const sal_uInt16 BIFF12_PAGESETUP_INROWS
= 0x0001;
76 const sal_uInt16 BIFF12_PAGESETUP_LANDSCAPE
= 0x0002;
77 const sal_uInt16 BIFF12_PAGESETUP_INVALID
= 0x0004;
78 const sal_uInt16 BIFF12_PAGESETUP_BLACKWHITE
= 0x0008;
79 const sal_uInt16 BIFF12_PAGESETUP_DRAFTQUALITY
= 0x0010;
80 const sal_uInt16 BIFF12_PAGESETUP_PRINTNOTES
= 0x0020;
81 const sal_uInt16 BIFF12_PAGESETUP_DEFAULTORIENT
= 0x0040;
82 const sal_uInt16 BIFF12_PAGESETUP_USEFIRSTPAGE
= 0x0080;
83 const sal_uInt16 BIFF12_PAGESETUP_NOTES_END
= 0x0100; // different to BIFF flag
85 const sal_uInt16 BIFF12_CHARTPAGESETUP_LANDSCAPE
= 0x0001;
86 const sal_uInt16 BIFF12_CHARTPAGESETUP_INVALID
= 0x0002;
87 const sal_uInt16 BIFF12_CHARTPAGESETUP_BLACKWHITE
= 0x0004;
88 const sal_uInt16 BIFF12_CHARTPAGESETUP_DEFAULTORIENT
= 0x0008;
89 const sal_uInt16 BIFF12_CHARTPAGESETUP_USEFIRSTPAGE
= 0x0010;
90 const sal_uInt16 BIFF12_CHARTPAGESETUP_DRAFTQUALITY
= 0x0020;
94 PageSettingsModel::PageSettingsModel() :
95 mfLeftMargin( OOX_MARGIN_DEFAULT_LR
),
96 mfRightMargin( OOX_MARGIN_DEFAULT_LR
),
97 mfTopMargin( OOX_MARGIN_DEFAULT_TB
),
98 mfBottomMargin( OOX_MARGIN_DEFAULT_TB
),
99 mfHeaderMargin( OOX_MARGIN_DEFAULT_HF
),
100 mfFooterMargin( OOX_MARGIN_DEFAULT_HF
),
109 mnHorPrintRes( 600 ),
110 mnVerPrintRes( 600 ),
111 mnOrientation( XML_default
),
112 mnPageOrder( XML_downThenOver
),
113 mnCellComments( XML_none
),
114 mnPrintErrors( XML_displayed
),
115 mbUseEvenHF( false ),
116 mbUseFirstHF( false ),
117 mbValidSettings( true ),
118 mbUseFirstPage( false ),
119 mbBlackWhite( false ),
120 mbDraftQuality( false ),
121 mbFitToPages( false ),
122 mbHorCenter( false ),
123 mbVerCenter( false ),
124 mbPrintGrid( false ),
125 mbPrintHeadings( false )
129 void PageSettingsModel::setBiffPrintErrors( sal_uInt8 nPrintErrors
)
131 static const sal_Int32 spnErrorIds
[] = { XML_displayed
, XML_none
, XML_dash
, XML_NA
};
132 mnPrintErrors
= STATIC_ARRAY_SELECT( spnErrorIds
, nPrintErrors
, XML_none
);
135 PageSettings::PageSettings( const WorksheetHelper
& rHelper
) :
136 WorksheetHelper( rHelper
)
140 void PageSettings::importPrintOptions( const AttributeList
& rAttribs
)
142 maModel
.mbHorCenter
= rAttribs
.getBool( XML_horizontalCentered
, false );
143 maModel
.mbVerCenter
= rAttribs
.getBool( XML_verticalCentered
, false );
144 maModel
.mbPrintGrid
= rAttribs
.getBool( XML_gridLines
, false );
145 maModel
.mbPrintHeadings
= rAttribs
.getBool( XML_headings
, false );
148 void PageSettings::importPageMargins( const AttributeList
& rAttribs
)
150 maModel
.mfLeftMargin
= rAttribs
.getDouble( XML_left
, OOX_MARGIN_DEFAULT_LR
);
151 maModel
.mfRightMargin
= rAttribs
.getDouble( XML_right
, OOX_MARGIN_DEFAULT_LR
);
152 maModel
.mfTopMargin
= rAttribs
.getDouble( XML_top
, OOX_MARGIN_DEFAULT_TB
);
153 maModel
.mfBottomMargin
= rAttribs
.getDouble( XML_bottom
, OOX_MARGIN_DEFAULT_TB
);
154 maModel
.mfHeaderMargin
= rAttribs
.getDouble( XML_header
, OOX_MARGIN_DEFAULT_HF
);
155 maModel
.mfFooterMargin
= rAttribs
.getDouble( XML_footer
, OOX_MARGIN_DEFAULT_HF
);
158 void PageSettings::importPageSetup( const Relations
& rRelations
, const AttributeList
& rAttribs
)
161 maModel
.maBinSettPath
= rRelations
.getFragmentPathFromRelId( rAttribs
.getString( R_TOKEN( id
), OUString() ) );
162 maModel
.mnPaperSize
= rAttribs
.getInteger( XML_paperSize
, 1 );
163 aStr
= rAttribs
.getString ( XML_paperWidth
, OUString() );
164 ::sax::Converter::convertMeasure(
165 maModel
.mnPaperWidth
, aStr
);
166 aStr
= rAttribs
.getString ( XML_paperHeight
, OUString() );
167 ::sax::Converter::convertMeasure(
168 maModel
.mnPaperHeight
, aStr
);
169 maModel
.mnCopies
= rAttribs
.getInteger( XML_copies
, 1 );
170 maModel
.mnScale
= rAttribs
.getInteger( XML_scale
, 100 );
171 maModel
.mnFirstPage
= rAttribs
.getInteger( XML_firstPageNumber
, 1 );
172 maModel
.mnFitToWidth
= rAttribs
.getInteger( XML_fitToWidth
, 1 );
173 maModel
.mnFitToHeight
= rAttribs
.getInteger( XML_fitToHeight
, 1 );
174 maModel
.mnHorPrintRes
= rAttribs
.getInteger( XML_horizontalDpi
, 600 );
175 maModel
.mnVerPrintRes
= rAttribs
.getInteger( XML_verticalDpi
, 600 );
176 maModel
.mnOrientation
= rAttribs
.getToken( XML_orientation
, XML_default
);
177 maModel
.mnPageOrder
= rAttribs
.getToken( XML_pageOrder
, XML_downThenOver
);
178 maModel
.mnCellComments
= rAttribs
.getToken( XML_cellComments
, XML_none
);
179 maModel
.mnPrintErrors
= rAttribs
.getToken( XML_errors
, XML_displayed
);
180 maModel
.mbValidSettings
= rAttribs
.getBool( XML_usePrinterDefaults
, false );
181 maModel
.mbUseFirstPage
= rAttribs
.getBool( XML_useFirstPageNumber
, false );
182 maModel
.mbBlackWhite
= rAttribs
.getBool( XML_blackAndWhite
, false );
183 maModel
.mbDraftQuality
= rAttribs
.getBool( XML_draft
, false );
186 void PageSettings::importChartPageSetup( const Relations
& rRelations
, const AttributeList
& rAttribs
)
189 maModel
.maBinSettPath
= rRelations
.getFragmentPathFromRelId( rAttribs
.getString( R_TOKEN( id
), OUString() ) );
190 maModel
.mnPaperSize
= rAttribs
.getInteger( XML_paperSize
, 1 );
191 aStr
= rAttribs
.getString ( XML_paperWidth
, OUString() );
192 ::sax::Converter::convertMeasure(
193 maModel
.mnPaperWidth
, aStr
);
194 aStr
= rAttribs
.getString ( XML_paperHeight
, OUString() );
195 ::sax::Converter::convertMeasure(
196 maModel
.mnPaperHeight
, aStr
);
197 maModel
.mnCopies
= rAttribs
.getInteger( XML_copies
, 1 );
198 maModel
.mnFirstPage
= rAttribs
.getInteger( XML_firstPageNumber
, 1 );
199 maModel
.mnHorPrintRes
= rAttribs
.getInteger( XML_horizontalDpi
, 600 );
200 maModel
.mnVerPrintRes
= rAttribs
.getInteger( XML_verticalDpi
, 600 );
201 maModel
.mnOrientation
= rAttribs
.getToken( XML_orientation
, XML_default
);
202 maModel
.mbValidSettings
= rAttribs
.getBool( XML_usePrinterDefaults
, false );
203 maModel
.mbUseFirstPage
= rAttribs
.getBool( XML_useFirstPageNumber
, false );
204 maModel
.mbBlackWhite
= rAttribs
.getBool( XML_blackAndWhite
, false );
205 maModel
.mbDraftQuality
= rAttribs
.getBool( XML_draft
, false );
208 void PageSettings::importHeaderFooter( const AttributeList
& rAttribs
)
210 maModel
.mbUseEvenHF
= rAttribs
.getBool( XML_differentOddEven
, false );
211 maModel
.mbUseFirstHF
= rAttribs
.getBool( XML_differentFirst
, false );
214 void PageSettings::importHeaderFooterCharacters( const OUString
& rChars
, sal_Int32 nElement
)
218 case XLS_TOKEN( oddHeader
): maModel
.maOddHeader
+= rChars
; break;
219 case XLS_TOKEN( oddFooter
): maModel
.maOddFooter
+= rChars
; break;
220 case XLS_TOKEN( evenHeader
): maModel
.maEvenHeader
+= rChars
; break;
221 case XLS_TOKEN( evenFooter
): maModel
.maEvenFooter
+= rChars
; break;
222 case XLS_TOKEN( firstHeader
): maModel
.maFirstHeader
+= rChars
; break;
223 case XLS_TOKEN( firstFooter
): maModel
.maFirstFooter
+= rChars
; break;
227 void PageSettings::importPicture( const Relations
& rRelations
, const AttributeList
& rAttribs
)
229 importPictureData( rRelations
, rAttribs
.getString( R_TOKEN( id
), OUString() ) );
232 void PageSettings::importPageMargins( SequenceInputStream
& rStrm
)
234 maModel
.mfLeftMargin
= rStrm
.readDouble();
235 maModel
.mfRightMargin
= rStrm
.readDouble();
236 maModel
.mfTopMargin
= rStrm
.readDouble();
237 maModel
.mfBottomMargin
= rStrm
.readDouble();
238 maModel
.mfHeaderMargin
= rStrm
.readDouble();
239 maModel
.mfFooterMargin
= rStrm
.readDouble();
242 void PageSettings::importPrintOptions( SequenceInputStream
& rStrm
)
245 nFlags
= rStrm
.readuInt16();
246 maModel
.mbHorCenter
= getFlag( nFlags
, BIFF12_PRINTOPT_HORCENTER
);
247 maModel
.mbVerCenter
= getFlag( nFlags
, BIFF12_PRINTOPT_VERCENTER
);
248 maModel
.mbPrintGrid
= getFlag( nFlags
, BIFF12_PRINTOPT_PRINTGRID
);
249 maModel
.mbPrintHeadings
= getFlag( nFlags
, BIFF12_PRINTOPT_PRINTHEADING
);
252 void PageSettings::importPageSetup( const Relations
& rRelations
, SequenceInputStream
& rStrm
)
256 maModel
.mnPaperSize
= rStrm
.readInt32();
257 maModel
.mnScale
= rStrm
.readInt32();
258 maModel
.mnHorPrintRes
= rStrm
.readInt32();
259 maModel
.mnVerPrintRes
= rStrm
.readInt32();
260 maModel
.mnCopies
= rStrm
.readInt32();
261 maModel
.mnFirstPage
= rStrm
.readInt32();
262 maModel
.mnFitToWidth
= rStrm
.readInt32();
263 maModel
.mnFitToHeight
= rStrm
.readInt32();
264 nFlags
= rStrm
.readuInt16();
266 maModel
.setBiffPrintErrors( extractValue
< sal_uInt8
>( nFlags
, 9, 2 ) );
267 maModel
.maBinSettPath
= rRelations
.getFragmentPathFromRelId( aRelId
);
268 maModel
.mnOrientation
= getFlagValue( nFlags
, BIFF12_PAGESETUP_DEFAULTORIENT
, XML_default
, getFlagValue( nFlags
, BIFF12_PAGESETUP_LANDSCAPE
, XML_landscape
, XML_portrait
) );
269 maModel
.mnPageOrder
= getFlagValue( nFlags
, BIFF12_PAGESETUP_INROWS
, XML_overThenDown
, XML_downThenOver
);
270 maModel
.mnCellComments
= getFlagValue( nFlags
, BIFF12_PAGESETUP_PRINTNOTES
, getFlagValue( nFlags
, BIFF12_PAGESETUP_NOTES_END
, XML_atEnd
, XML_asDisplayed
), XML_none
);
271 maModel
.mbValidSettings
= !getFlag( nFlags
, BIFF12_PAGESETUP_INVALID
);
272 maModel
.mbUseFirstPage
= getFlag( nFlags
, BIFF12_PAGESETUP_USEFIRSTPAGE
);
273 maModel
.mbBlackWhite
= getFlag( nFlags
, BIFF12_PAGESETUP_BLACKWHITE
);
274 maModel
.mbDraftQuality
= getFlag( nFlags
, BIFF12_PAGESETUP_DRAFTQUALITY
);
277 void PageSettings::importChartPageSetup( const Relations
& rRelations
, SequenceInputStream
& rStrm
)
280 sal_uInt16 nFirstPage
, nFlags
;
281 maModel
.mnPaperSize
= rStrm
.readInt32();
282 maModel
.mnHorPrintRes
= rStrm
.readInt32();
283 maModel
.mnVerPrintRes
= rStrm
.readInt32();
284 maModel
.mnCopies
= rStrm
.readInt32();
285 nFirstPage
= rStrm
.readuInt16();
286 nFlags
= rStrm
.readuInt16();
288 maModel
.maBinSettPath
= rRelations
.getFragmentPathFromRelId( aRelId
);
289 maModel
.mnFirstPage
= nFirstPage
; // 16-bit in CHARTPAGESETUP
290 maModel
.mnOrientation
= getFlagValue( nFlags
, BIFF12_CHARTPAGESETUP_DEFAULTORIENT
, XML_default
, getFlagValue( nFlags
, BIFF12_CHARTPAGESETUP_LANDSCAPE
, XML_landscape
, XML_portrait
) );
291 maModel
.mbValidSettings
= !getFlag( nFlags
, BIFF12_CHARTPAGESETUP_INVALID
);
292 maModel
.mbUseFirstPage
= getFlag( nFlags
, BIFF12_CHARTPAGESETUP_USEFIRSTPAGE
);
293 maModel
.mbBlackWhite
= getFlag( nFlags
, BIFF12_CHARTPAGESETUP_BLACKWHITE
);
294 maModel
.mbDraftQuality
= getFlag( nFlags
, BIFF12_CHARTPAGESETUP_DRAFTQUALITY
);
297 void PageSettings::importHeaderFooter( SequenceInputStream
& rStrm
)
300 nFlags
= rStrm
.readuInt16();
301 rStrm
>> maModel
.maOddHeader
>> maModel
.maOddFooter
302 >> maModel
.maEvenHeader
>> maModel
.maEvenFooter
303 >> maModel
.maFirstHeader
>> maModel
.maFirstFooter
;
304 maModel
.mbUseEvenHF
= getFlag( nFlags
, BIFF12_HEADERFOOTER_DIFFEVEN
);
305 maModel
.mbUseFirstHF
= getFlag( nFlags
, BIFF12_HEADERFOOTER_DIFFFIRST
);
308 void PageSettings::importPicture( const Relations
& rRelations
, SequenceInputStream
& rStrm
)
310 importPictureData( rRelations
, BiffHelper::readString( rStrm
) );
313 void PageSettings::setFitToPagesMode( bool bFitToPages
)
315 maModel
.mbFitToPages
= bFitToPages
;
318 void PageSettings::finalizeImport()
320 OUStringBuffer
aStyleNameBuffer( "PageStyle_" );
321 Reference
<container::XNamed
> xSheetName(getSheet(), UNO_QUERY
);
322 if( xSheetName
.is() )
323 aStyleNameBuffer
.append( xSheetName
->getName() );
325 aStyleNameBuffer
.append( static_cast< sal_Int32
>( getSheetIndex() + 1 ) );
326 OUString aStyleName
= aStyleNameBuffer
.makeStringAndClear();
328 Reference
<style::XStyle
> xStyle
= createStyleObject(aStyleName
, true);
329 PropertySet
aStyleProps( xStyle
);
330 getPageSettingsConverter().writePageSettingsProperties( aStyleProps
, maModel
, getSheetType() );
332 // Set page style name to the sheet.
333 SCTAB nTab
= getSheetIndex();
334 getScDocument().SetPageStyle(nTab
, aStyleName
);
337 void PageSettings::importPictureData( const Relations
& rRelations
, const OUString
& rRelId
)
339 OUString aPicturePath
= rRelations
.getFragmentPathFromRelId(rRelId
);
340 if (!aPicturePath
.isEmpty())
342 maModel
.mxGraphic
= getBaseFilter().getGraphicHelper().importEmbeddedGraphic(aPicturePath
);
356 Reference
<text::XText
> mxText
; /// XText interface of this portion.
357 Reference
<text::XTextCursor
> mxStart
; /// Start position of current text range for formatting.
358 Reference
<text::XTextCursor
> mxEnd
; /// End position of current text range for formatting.
359 double mfTotalHeight
; /// Sum of heights of previous lines in points.
360 double mfCurrHeight
; /// Height of the current text line in points.
362 bool initialize( const Reference
<text::XText
>& rxText
);
365 bool HFPortionInfo::initialize( const Reference
<text::XText
>& rxText
)
367 mfTotalHeight
= mfCurrHeight
= 0.0;
371 mxStart
= mxText
->createTextCursor();
372 mxEnd
= mxText
->createTextCursor();
374 bool bRet
= mxText
.is() && mxStart
.is() && mxEnd
.is();
375 OSL_ENSURE( bRet
, "HFPortionInfo::initialize - missing interfaces" );
379 class HeaderFooterParser
: public WorkbookHelper
382 explicit HeaderFooterParser( const WorkbookHelper
& rHelper
);
384 /** Parses the passed string and creates the header/footer contents.
385 @returns The total height of the converted header or footer in points. */
387 const Reference
<sheet::XHeaderFooterContent
>& rxContext
,
388 const OUString
& rData
);
391 /** Returns the current edit engine text object. */
392 HFPortionInfo
& getPortion() { return maPortions
[ meCurrPortion
]; }
393 /** Returns the start cursor of the current text range. */
394 const Reference
<text::XTextCursor
>& getStartPos() { return getPortion().mxStart
; }
395 /** Returns the end cursor of the current text range. */
396 const Reference
<text::XTextCursor
>& getEndPos() { return getPortion().mxEnd
; }
398 /** Returns the current line height of the specified portion. */
399 double getCurrHeight( HFPortionId ePortion
) const;
401 /** Updates the current line height of the specified portion, using the current font size. */
402 void updateCurrHeight( HFPortionId ePortion
);
403 /** Updates the current line height, using the current font size. */
404 void updateCurrHeight();
406 /** Sets the font attributes at the current selection. */
407 void setAttributes();
408 /** Appends and clears internal string buffer. */
410 /** Appends a line break and adjusts internal text height data. */
411 void appendLineBreak();
413 /** Creates a text field from the passed service name. */
414 Reference
<text::XTextContent
> createField( const OUString
& rServiceName
) const;
415 /** Appends the passed text field. */
416 void appendField( const Reference
<text::XTextContent
>& rxContent
);
418 /** Sets the passed font name if it is valid. */
419 void convertFontName( const OUString
& rStyle
);
420 /** Converts a font style given as string. */
421 void convertFontStyle( const OUString
& rStyle
);
422 /** Converts a font color given as string. */
423 void convertFontColor( const OUString
& rColor
);
425 /** Finalizes current portion: sets font attributes and updates text height data. */
426 void finalizePortion();
427 /** Changes current header/footer portion. */
428 void setNewPortion( HFPortionId ePortion
);
431 typedef ::std::vector
< HFPortionInfo
> HFPortionInfoVec
;
433 const std::set
< OString
> maBoldNames
; /// All names for bold font style in lowercase UTF-8.
434 const std::set
< OString
> maItalicNames
; /// All names for italic font style in lowercase UTF-8.
435 HFPortionInfoVec maPortions
;
436 HFPortionId meCurrPortion
; /// Identifier of current H/F portion.
437 OUStringBuffer maBuffer
; /// Text data to append to current text range.
438 FontModel maFontModel
; /// Font attributes of current text range.
443 // different names for bold font style (lowercase)
444 static const sal_Char
* const sppcBoldNames
[] =
447 "fett", // German 'bold'
449 "halbfett", // German 'demibold'
454 // different names for italic font style (lowercase)
455 static const sal_Char
* const sppcItalicNames
[] =
458 "kursiv", // German 'italic'
460 "schr\303\204g", // German 'oblique' with uppercase A umlaut
461 "schr\303\244g" // German 'oblique' with lowercase A umlaut
466 static const OUStringLiteral
gaPageNumberService( "com.sun.star.text.TextField.PageNumber" );
467 static const OUStringLiteral
gaPageCountService( "com.sun.star.text.TextField.PageCount" );
468 static const OUStringLiteral
gaSheetNameService( "com.sun.star.text.TextField.SheetName" );
469 static const OUStringLiteral
gaFileNameService( "com.sun.star.text.TextField.FileName" );
470 static const OUStringLiteral
gaDateTimeService( "com.sun.star.text.TextField.DateTime" );
472 HeaderFooterParser::HeaderFooterParser( const WorkbookHelper
& rHelper
) :
473 WorkbookHelper( rHelper
),
474 maBoldNames( sppcBoldNames
, sppcBoldNames
+ SAL_N_ELEMENTS(sppcBoldNames
) ),
475 maItalicNames( sppcItalicNames
, sppcItalicNames
+ SAL_N_ELEMENTS(sppcItalicNames
) ),
476 maPortions( static_cast< size_t >( HF_COUNT
) ),
477 meCurrPortion( HF_CENTER
)
481 double HeaderFooterParser::parse( const Reference
<sheet::XHeaderFooterContent
>& rxContext
, const OUString
& rData
)
483 if( !rxContext
.is() || rData
.isEmpty() ||
484 !maPortions
[ HF_LEFT
].initialize( rxContext
->getLeftText() ) ||
485 !maPortions
[ HF_CENTER
].initialize( rxContext
->getCenterText() ) ||
486 !maPortions
[ HF_RIGHT
].initialize( rxContext
->getRightText() ) )
489 meCurrPortion
= HF_CENTER
;
490 maBuffer
.setLength( 0 );
491 maFontModel
= getStyles().getDefaultFontModel();
492 OUStringBuffer aFontName
; // current font name
493 OUStringBuffer aFontStyle
; // current font style
494 sal_Int32 nFontHeight
= 0; // current font height
496 /** State of the parser. */
499 STATE_TEXT
, /// Literal text data.
500 STATE_TOKEN
, /// Control token following a '&' character.
501 STATE_FONTNAME
, /// Font name ('&' is followed by '"', reads until next '"' or ',').
502 STATE_FONTSTYLE
, /// Font style name (font part after ',', reads until next '"').
503 STATE_FONTHEIGHT
/// Font height ('&' is followed by num. digits, reads until non-digit).
507 const sal_Unicode
* pcChar
= rData
.getStr();
508 const sal_Unicode
* pcEnd
= pcChar
+ rData
.getLength();
509 for( ; (pcChar
!= pcEnd
) && (*pcChar
!= 0); ++pcChar
)
511 sal_Unicode cChar
= *pcChar
;
518 case '&': // new token
520 eState
= STATE_TOKEN
;
522 case '\n': // line break
527 maBuffer
.append( cChar
);
534 // default: back to text mode, may be changed in specific cases
536 // ignore case of token codes
537 if( ('a' <= cChar
) && (cChar
<= 'z') )
538 cChar
= (cChar
- 'a') + 'A';
541 case '&': maBuffer
.append( cChar
); break; // the '&' character
543 case 'L': setNewPortion( HF_LEFT
); break; // left portion
544 case 'C': setNewPortion( HF_CENTER
); break; // center portion
545 case 'R': setNewPortion( HF_RIGHT
); break; // right portion
547 case 'P': // page number
548 appendField( createField( gaPageNumberService
) );
550 case 'N': // total page count
551 appendField( createField( gaPageCountService
) );
553 case 'A': // current sheet name
554 appendField( createField( gaSheetNameService
) );
557 case 'F': // file name
559 Reference
<text::XTextContent
> xContent
= createField( gaFileNameService
);
560 PropertySet
aPropSet( xContent
);
561 aPropSet
.setProperty( PROP_FileFormat
, css::text::FilenameDisplayFormat::NAME_AND_EXT
);
562 appendField( xContent
);
565 case 'Z': // file path (without file name), OOXML, BIFF12, and BIFF8 only
567 Reference
<text::XTextContent
> xContent
= createField( gaFileNameService
);
568 PropertySet
aPropSet( xContent
);
569 // FilenameDisplayFormat::PATH not supported by Calc
570 aPropSet
.setProperty( PROP_FileFormat
, css::text::FilenameDisplayFormat::FULL
);
571 appendField( xContent
);
572 /* path only is not supported -- if we find a '&Z&F'
573 combination for path/name, skip the '&F' part */
574 if( (pcChar
+ 2 < pcEnd
) && (pcChar
[ 1 ] == '&') && ((pcChar
[ 2 ] == 'f') || (pcChar
[ 2 ] == 'F')) )
580 Reference
<text::XTextContent
> xContent
= createField( gaDateTimeService
);
581 PropertySet
aPropSet( xContent
);
582 aPropSet
.setProperty( PROP_IsDate
, true );
583 appendField( xContent
);
588 Reference
<text::XTextContent
> xContent
= createField( gaDateTimeService
);
589 PropertySet
aPropSet( xContent
);
590 aPropSet
.setProperty( PROP_IsDate
, false );
591 appendField( xContent
);
597 maFontModel
.mbBold
= !maFontModel
.mbBold
;
601 maFontModel
.mbItalic
= !maFontModel
.mbItalic
;
603 case 'U': // underline
605 maFontModel
.mnUnderline
= (maFontModel
.mnUnderline
== XML_single
) ? XML_none
: XML_single
;
607 case 'E': // double underline
609 maFontModel
.mnUnderline
= (maFontModel
.mnUnderline
== XML_double
) ? XML_none
: XML_double
;
611 case 'S': // strikeout
613 maFontModel
.mbStrikeout
= !maFontModel
.mbStrikeout
;
615 case 'X': // superscript
617 maFontModel
.mnEscapement
= (maFontModel
.mnEscapement
== XML_superscript
) ? XML_baseline
: XML_superscript
;
619 case 'Y': // subsrcipt
621 maFontModel
.mnEscapement
= (maFontModel
.mnEscapement
== XML_subscript
) ? XML_baseline
: XML_subscript
;
623 case 'O': // outlined
625 maFontModel
.mbOutline
= !maFontModel
.mbOutline
;
629 maFontModel
.mbShadow
= !maFontModel
.mbShadow
;
632 case 'K': // text color (not in BIFF)
633 if( pcChar
+ 6 < pcEnd
)
636 // eat the following 6 characters
637 convertFontColor( OUString( pcChar
+ 1, 6 ) );
642 case '\"': // font name
643 aFontName
.setLength( 0 );
644 aFontStyle
.setLength( 0 );
645 eState
= STATE_FONTNAME
;
648 if( ('0' <= cChar
) && (cChar
<= '9') ) // font size
650 nFontHeight
= cChar
- '0';
651 eState
= STATE_FONTHEIGHT
;
663 convertFontName( aFontName
.makeStringAndClear() );
667 eState
= STATE_FONTSTYLE
;
670 aFontName
.append( cChar
);
675 case STATE_FONTSTYLE
:
681 convertFontName( aFontName
.makeStringAndClear() );
682 convertFontStyle( aFontStyle
.makeStringAndClear() );
686 aFontStyle
.append( cChar
);
691 case STATE_FONTHEIGHT
:
693 if( ('0' <= cChar
) && (cChar
<= '9') )
695 if( nFontHeight
>= 0 )
698 nFontHeight
+= (cChar
- '0');
699 if( nFontHeight
> 1000 )
705 if( nFontHeight
> 0 )
708 maFontModel
.mfHeight
= nFontHeight
;
720 maPortions
[ HF_LEFT
].mfTotalHeight
+= getCurrHeight( HF_LEFT
);
721 maPortions
[ HF_CENTER
].mfTotalHeight
+= getCurrHeight( HF_CENTER
);
722 maPortions
[ HF_RIGHT
].mfTotalHeight
+= getCurrHeight( HF_RIGHT
);
724 return ::std::max( maPortions
[ HF_LEFT
].mfTotalHeight
,
725 ::std::max( maPortions
[ HF_CENTER
].mfTotalHeight
, maPortions
[ HF_RIGHT
].mfTotalHeight
) );
728 // private --------------------------------------------------------------------
730 double HeaderFooterParser::getCurrHeight( HFPortionId ePortion
) const
732 double fMaxHt
= maPortions
[ ePortion
].mfCurrHeight
;
733 return (fMaxHt
== 0.0) ? maFontModel
.mfHeight
: fMaxHt
;
736 void HeaderFooterParser::updateCurrHeight( HFPortionId ePortion
)
738 double& rfMaxHt
= maPortions
[ ePortion
].mfCurrHeight
;
739 rfMaxHt
= ::std::max( rfMaxHt
, maFontModel
.mfHeight
);
742 void HeaderFooterParser::updateCurrHeight()
744 updateCurrHeight( meCurrPortion
);
747 void HeaderFooterParser::setAttributes()
749 Reference
<text::XTextRange
> xRange
= getStartPos();
750 getEndPos()->gotoRange( xRange
, false );
751 getEndPos()->gotoEnd( true );
752 if( !getEndPos()->isCollapsed() )
754 Font
aFont( *this, maFontModel
);
755 aFont
.finalizeImport();
756 PropertySet
aPropSet( getEndPos() );
757 aFont
.writeToPropertySet( aPropSet
);
758 getStartPos()->gotoEnd( false );
759 getEndPos()->gotoEnd( false );
763 void HeaderFooterParser::appendText()
765 if( !maBuffer
.isEmpty() )
767 getEndPos()->gotoEnd( false );
768 getEndPos()->setString( maBuffer
.makeStringAndClear() );
773 void HeaderFooterParser::appendLineBreak()
775 getEndPos()->gotoEnd( false );
776 getEndPos()->setString( OUString( '\n' ) );
777 getPortion().mfTotalHeight
+= getCurrHeight( meCurrPortion
); // add the current line height.
778 getPortion().mfCurrHeight
= 0;
781 Reference
<text::XTextContent
> HeaderFooterParser::createField( const OUString
& rServiceName
) const
783 Reference
<text::XTextContent
> xContent
;
786 xContent
.set( getBaseFilter().getModelFactory()->createInstance( rServiceName
), UNO_QUERY_THROW
);
790 OSL_FAIL( OStringBuffer( "HeaderFooterParser::createField - error while creating text field \"" ).
791 append( OUStringToOString( rServiceName
, RTL_TEXTENCODING_ASCII_US
) ).
792 append( '"' ).getStr() );
797 void HeaderFooterParser::appendField( const Reference
<text::XTextContent
>& rxContent
)
799 getEndPos()->gotoEnd( false );
802 Reference
<text::XTextRange
> xRange( getEndPos(), UNO_QUERY_THROW
);
803 getPortion().mxText
->insertTextContent( xRange
, rxContent
, false );
811 void HeaderFooterParser::convertFontName( const OUString
& rName
)
813 if( !rName
.isEmpty() )
815 // single dash is document default font
816 if( (rName
.getLength() == 1) && (rName
[ 0 ] == '-') )
817 maFontModel
.maName
= getStyles().getDefaultFontModel().maName
;
819 maFontModel
.maName
= rName
;
823 void HeaderFooterParser::convertFontStyle( const OUString
& rStyle
)
825 maFontModel
.mbBold
= maFontModel
.mbItalic
= false;
826 if (rStyle
.isEmpty())
828 for( sal_Int32 nPos
{ 0 }; nPos
>=0; )
830 OString aToken
= OUStringToOString( rStyle
.getToken( 0, ' ', nPos
), RTL_TEXTENCODING_UTF8
).toAsciiLowerCase();
831 if( !aToken
.isEmpty() )
833 if( maBoldNames
.count( aToken
) > 0 )
834 maFontModel
.mbBold
= true;
835 else if( maItalicNames
.count( aToken
) > 0 )
836 maFontModel
.mbItalic
= true;
841 void HeaderFooterParser::convertFontColor( const OUString
& rColor
)
843 OSL_ENSURE( rColor
.getLength() == 6, "HeaderFooterParser::convertFontColor - invalid font color code" );
844 if( (rColor
[ 2 ] == '+') || (rColor
[ 2 ] == '-') )
845 // theme color: TTSNNN (TT = decimal theme index, S = +/-, NNN = decimal tint/shade in percent)
846 maFontModel
.maColor
.setTheme(
847 rColor
.copy( 0, 2 ).toInt32(),
848 static_cast< double >( rColor
.copy( 2 ).toInt32() ) / 100.0 );
851 maFontModel
.maColor
.setRgb( ::Color(rColor
.toUInt32( 16 )) );
854 void HeaderFooterParser::finalizePortion()
860 void HeaderFooterParser::setNewPortion( HFPortionId ePortion
)
862 if( ePortion
!= meCurrPortion
)
865 meCurrPortion
= ePortion
;
866 maFontModel
= getStyles().getDefaultFontModel();
870 PageSettingsConverter::HFHelperData::HFHelperData( sal_Int32 nLeftPropId
, sal_Int32 nRightPropId
) :
871 mnLeftPropId( nLeftPropId
),
872 mnRightPropId( nRightPropId
),
875 mbHasContent( false ),
876 mbShareOddEven( false ),
877 mbDynamicHeight( false )
881 PageSettingsConverter::PageSettingsConverter( const WorkbookHelper
& rHelper
) :
882 WorkbookHelper( rHelper
),
883 mxHFParser( new HeaderFooterParser( rHelper
) ),
884 maHeaderData( PROP_LeftPageHeaderContent
, PROP_RightPageHeaderContent
),
885 maFooterData( PROP_LeftPageFooterContent
, PROP_RightPageFooterContent
)
889 PageSettingsConverter::~PageSettingsConverter()
893 void PageSettingsConverter::writePageSettingsProperties(
894 PropertySet
& rPropSet
, const PageSettingsModel
& rModel
, WorksheetType eSheetType
)
896 // special handling for chart sheets
897 bool bChartSheet
= eSheetType
== WorksheetType::Chart
;
902 // always fit chart sheet to 1 page
903 rPropSet
.setProperty
< sal_Int16
>( PROP_ScaleToPages
, 1 );
905 else if( rModel
.mbFitToPages
)
907 // fit to number of pages
908 rPropSet
.setProperty( PROP_ScaleToPagesX
, getLimitedValue
< sal_Int16
, sal_Int32
>( rModel
.mnFitToWidth
, 0, 1000 ) );
909 rPropSet
.setProperty( PROP_ScaleToPagesY
, getLimitedValue
< sal_Int16
, sal_Int32
>( rModel
.mnFitToHeight
, 0, 1000 ) );
913 // scale may be 0 which indicates uninitialized
914 sal_Int16 nScale
= (rModel
.mnScale
> 0) ? getLimitedValue
< sal_Int16
, sal_Int32
>( rModel
.mnScale
, 10, 400 ) : 100;
915 rPropSet
.setProperty( PROP_PageScale
, nScale
);
919 bool bLandscape
= rModel
.mnOrientation
== XML_landscape
;
920 // default orientation for current sheet type (chart sheets default to landscape)
921 if( bChartSheet
&& ( !rModel
.mbValidSettings
|| (rModel
.mnOrientation
== XML_default
) ) )
925 if( !rModel
.mbValidSettings
)
930 if( 0 < rModel
.mnPaperSize
)
932 const msfilter::util::ApiPaperSize
& rPaperSize
= msfilter::util::PaperSizeConv::getApiSizeForMSPaperSizeIndex( rModel
.mnPaperSize
);
933 aSize
= awt::Size( rPaperSize
.mnWidth
, rPaperSize
.mnHeight
);
934 bValid
= ( rPaperSize
.mnWidth
!= 0 && rPaperSize
.mnHeight
!= 0 );
936 if( rModel
.mnPaperWidth
> 0 && rModel
.mnPaperHeight
> 0 )
938 aSize
= awt::Size( rModel
.mnPaperWidth
, rModel
.mnPaperHeight
);
945 ::std::swap( aSize
.Width
, aSize
.Height
);
946 rPropSet
.setProperty( PROP_Size
, aSize
);
951 convertHeaderFooterData( rPropSet
, maHeaderData
, rModel
.maOddHeader
, rModel
.maEvenHeader
, rModel
.mbUseEvenHF
, rModel
.mfTopMargin
, rModel
.mfHeaderMargin
);
952 convertHeaderFooterData( rPropSet
, maFooterData
, rModel
.maOddFooter
, rModel
.maEvenFooter
, rModel
.mbUseEvenHF
, rModel
.mfBottomMargin
, rModel
.mfFooterMargin
);
954 // write all properties to property set
955 const UnitConverter
& rUnitConv
= getUnitConverter();
956 PropertyMap aPropMap
;
957 aPropMap
.setProperty( PROP_IsLandscape
, bLandscape
);
958 aPropMap
.setProperty( PROP_FirstPageNumber
, getLimitedValue
< sal_Int16
, sal_Int32
>( rModel
.mbUseFirstPage
? rModel
.mnFirstPage
: 0, 0, 9999 ));
959 aPropMap
.setProperty( PROP_PrintDownFirst
, (rModel
.mnPageOrder
== XML_downThenOver
));
960 aPropMap
.setProperty( PROP_PrintAnnotations
, (rModel
.mnCellComments
== XML_asDisplayed
));
961 aPropMap
.setProperty( PROP_CenterHorizontally
, rModel
.mbHorCenter
);
962 aPropMap
.setProperty( PROP_CenterVertically
, rModel
.mbVerCenter
);
963 aPropMap
.setProperty( PROP_PrintGrid
, (!bChartSheet
&& rModel
.mbPrintGrid
)); // no gridlines in chart sheets
964 aPropMap
.setProperty( PROP_PrintHeaders
, (!bChartSheet
&& rModel
.mbPrintHeadings
)); // no column/row headings in chart sheets
965 aPropMap
.setProperty( PROP_LeftMargin
, rUnitConv
.scaleToMm100( rModel
.mfLeftMargin
, Unit::Inch
));
966 aPropMap
.setProperty( PROP_RightMargin
, rUnitConv
.scaleToMm100( rModel
.mfRightMargin
, Unit::Inch
));
967 // #i23296# In Calc, "TopMargin" property is distance to top of header if enabled
968 aPropMap
.setProperty( PROP_TopMargin
, rUnitConv
.scaleToMm100( maHeaderData
.mbHasContent
? rModel
.mfHeaderMargin
: rModel
.mfTopMargin
, Unit::Inch
));
969 // #i23296# In Calc, "BottomMargin" property is distance to bottom of footer if enabled
970 aPropMap
.setProperty( PROP_BottomMargin
, rUnitConv
.scaleToMm100( maFooterData
.mbHasContent
? rModel
.mfFooterMargin
: rModel
.mfBottomMargin
, Unit::Inch
));
971 aPropMap
.setProperty( PROP_HeaderIsOn
, maHeaderData
.mbHasContent
);
972 aPropMap
.setProperty( PROP_HeaderIsShared
, maHeaderData
.mbShareOddEven
);
973 aPropMap
.setProperty( PROP_HeaderIsDynamicHeight
, maHeaderData
.mbDynamicHeight
);
974 aPropMap
.setProperty( PROP_HeaderHeight
, maHeaderData
.mnHeight
);
975 aPropMap
.setProperty( PROP_HeaderBodyDistance
, maHeaderData
.mnBodyDist
);
976 aPropMap
.setProperty( PROP_FooterIsOn
, maFooterData
.mbHasContent
);
977 aPropMap
.setProperty( PROP_FooterIsShared
, maFooterData
.mbShareOddEven
);
978 aPropMap
.setProperty( PROP_FooterIsDynamicHeight
, maFooterData
.mbDynamicHeight
);
979 aPropMap
.setProperty( PROP_FooterHeight
, maFooterData
.mnHeight
);
980 aPropMap
.setProperty( PROP_FooterBodyDistance
, maFooterData
.mnBodyDist
);
982 if (rModel
.mxGraphic
.is())
984 aPropMap
.setProperty(PROP_BackGraphic
, rModel
.mxGraphic
);
985 aPropMap
.setProperty(PROP_BackGraphicLocation
, css::style::GraphicLocation_TILED
);
988 rPropSet
.setProperties( aPropMap
);
991 void PageSettingsConverter::convertHeaderFooterData(
992 PropertySet
& rPropSet
, HFHelperData
& orHFData
,
993 const OUString
& rOddContent
, const OUString
& rEvenContent
, bool bUseEvenContent
,
994 double fPageMargin
, double fContentMargin
)
996 bool bHasOddContent
= !rOddContent
.isEmpty();
997 bool bHasEvenContent
= bUseEvenContent
&& !rEvenContent
.isEmpty();
999 sal_Int32 nOddHeight
= bHasOddContent
? writeHeaderFooter( rPropSet
, orHFData
.mnRightPropId
, rOddContent
) : 0;
1000 sal_Int32 nEvenHeight
= bHasEvenContent
? writeHeaderFooter( rPropSet
, orHFData
.mnLeftPropId
, rEvenContent
) : 0;
1002 orHFData
.mnHeight
= 750;
1003 orHFData
.mnBodyDist
= 250;
1004 orHFData
.mbHasContent
= bHasOddContent
|| bHasEvenContent
;
1005 orHFData
.mbShareOddEven
= !bUseEvenContent
;
1006 orHFData
.mbDynamicHeight
= true;
1008 if( orHFData
.mbHasContent
)
1010 // use maximum height of odd/even header/footer
1011 orHFData
.mnHeight
= ::std::max( nOddHeight
, nEvenHeight
);
1012 /* Calc contains distance between bottom of header and top of page
1013 body in "HeaderBodyDistance" property, and distance between bottom
1014 of page body and top of footer in "FooterBodyDistance" property */
1015 orHFData
.mnBodyDist
= getUnitConverter().scaleToMm100( fPageMargin
- fContentMargin
, Unit::Inch
) - orHFData
.mnHeight
;
1016 /* #i23296# Distance less than 0 means, header or footer overlays page
1017 body. As this is not possible in Calc, set fixed header or footer
1018 height (crop header/footer) to get correct top position of page body. */
1019 orHFData
.mbDynamicHeight
= orHFData
.mnBodyDist
>= 0;
1020 /* "HeaderHeight" property is in fact distance from top of header to
1021 top of page body (including "HeaderBodyDistance").
1022 "FooterHeight" property is in fact distance from bottom of page
1023 body to bottom of footer (including "FooterBodyDistance"). */
1024 orHFData
.mnHeight
+= orHFData
.mnBodyDist
;
1025 // negative body distance not allowed
1026 orHFData
.mnBodyDist
= ::std::max
< sal_Int32
>( orHFData
.mnBodyDist
, 0 );
1030 sal_Int32
PageSettingsConverter::writeHeaderFooter(
1031 PropertySet
& rPropSet
, sal_Int32 nPropId
, const OUString
& rContent
)
1033 OSL_ENSURE( !rContent
.isEmpty(), "PageSettingsConverter::writeHeaderFooter - empty h/f string found" );
1034 sal_Int32 nHeight
= 0;
1035 if( !rContent
.isEmpty() )
1037 Reference
<sheet::XHeaderFooterContent
> xHFContent(rPropSet
.getAnyProperty(nPropId
), UNO_QUERY
);
1038 if( xHFContent
.is() )
1040 double fTotalHeight
= mxHFParser
->parse( xHFContent
, rContent
);
1041 rPropSet
.setProperty( nPropId
, xHFContent
);
1042 nHeight
= getUnitConverter().scaleToMm100( fTotalHeight
, Unit::Point
);
1051 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */