Version 5.2.6.1, tag libreoffice-5.2.6.1
[LibreOffice.git] / sc / source / filter / oox / pagesettings.cxx
blobf9f733c47bf1269e4dd423965516504dd78973ec
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
22 #include <algorithm>
23 #include <set>
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>
50 namespace oox {
51 namespace xls {
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;
59 namespace {
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;
90 } // namespace
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 ),
99 mnPaperSize( 1 ),
100 mnPaperWidth( 0 ),
101 mnPaperHeight( 0 ),
102 mnCopies( 1 ),
103 mnScale( 100 ),
104 mnFirstPage( 1 ),
105 mnFitToWidth( 1 ),
106 mnFitToHeight( 1 ),
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 )
158 OUString aStr;
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 )
186 OUString aStr;
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 )
214 switch( 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 )
242 sal_uInt16 nFlags;
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 )
252 OUString aRelId;
253 sal_uInt16 nFlags;
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();
263 rStrm >> aRelId;
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 )
277 OUString aRelId;
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();
285 rStrm >> aRelId;
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 )
297 sal_uInt16 nFlags;
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() );
322 else
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 );
342 enum HFPortionId
344 HF_LEFT,
345 HF_CENTER,
346 HF_RIGHT,
347 HF_COUNT
350 struct HFPortionInfo
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;
364 mxText = rxText;
365 if( mxText.is() )
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" );
372 return bRet;
375 class HeaderFooterParser : public WorkbookHelper
377 public:
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. */
382 double parse(
383 const Reference<sheet::XHeaderFooterContent>& rxContext,
384 const OUString& rData );
386 private:
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. */
407 void appendText();
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 );
428 private:
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.
445 namespace {
447 // different names for bold font style (lowercase)
448 static const sal_Char* const sppcBoldNames[] =
450 "bold",
451 "fett", // German 'bold'
452 "demibold",
453 "halbfett", // German 'demibold'
454 "black",
455 "heavy"
458 // different names for italic font style (lowercase)
459 static const sal_Char* const sppcItalicNames[] =
461 "italic",
462 "kursiv", // German 'italic'
463 "oblique",
464 "schr\303\204g", // German 'oblique' with uppercase A umlaut
465 "schr\303\244g" // German 'oblique' with lowercase A umlaut
468 } // namespace
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() ) )
490 return 0.0;
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. */
500 enum
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).
508 eState = STATE_TEXT;
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;
515 switch( eState )
517 case STATE_TEXT:
519 switch( cChar )
521 case '&': // new token
522 appendText();
523 eState = STATE_TOKEN;
524 break;
525 case '\n': // line break
526 appendText();
527 appendLineBreak();
528 break;
529 default:
530 maBuffer.append( cChar );
533 break;
535 case STATE_TOKEN:
537 // default: back to text mode, may be changed in specific cases
538 eState = STATE_TEXT;
539 // ignore case of token codes
540 if( ('a' <= cChar) && (cChar <= 'z') )
541 (cChar -= 'a') += 'A';
542 switch( cChar )
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 ) );
552 break;
553 case 'N': // total page count
554 appendField( createField( maPageCountService ) );
555 break;
556 case 'A': // current sheet name
557 appendField( createField( maSheetNameService ) );
558 break;
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 );
567 break;
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')) )
579 pcChar += 2;
581 break;
582 case 'D': // date
584 Reference<text::XTextContent> xContent = createField( maDateTimeService );
585 PropertySet aPropSet( xContent );
586 aPropSet.setProperty( PROP_IsDate, true );
587 appendField( xContent );
589 break;
590 case 'T': // time
592 Reference<text::XTextContent> xContent = createField( maDateTimeService );
593 PropertySet aPropSet( xContent );
594 aPropSet.setProperty( PROP_IsDate, false );
595 appendField( xContent );
597 break;
599 case 'B': // bold
600 setAttributes();
601 maFontModel.mbBold = !maFontModel.mbBold;
602 break;
603 case 'I': // italic
604 setAttributes();
605 maFontModel.mbItalic = !maFontModel.mbItalic;
606 break;
607 case 'U': // underline
608 setAttributes();
609 maFontModel.mnUnderline = (maFontModel.mnUnderline == XML_single) ? XML_none : XML_single;
610 break;
611 case 'E': // double underline
612 setAttributes();
613 maFontModel.mnUnderline = (maFontModel.mnUnderline == XML_double) ? XML_none : XML_double;
614 break;
615 case 'S': // strikeout
616 setAttributes();
617 maFontModel.mbStrikeout = !maFontModel.mbStrikeout;
618 break;
619 case 'X': // superscript
620 setAttributes();
621 maFontModel.mnEscapement = (maFontModel.mnEscapement == XML_superscript) ? XML_baseline : XML_superscript;
622 break;
623 case 'Y': // subsrcipt
624 setAttributes();
625 maFontModel.mnEscapement = (maFontModel.mnEscapement == XML_subscript) ? XML_baseline : XML_subscript;
626 break;
627 case 'O': // outlined
628 setAttributes();
629 maFontModel.mbOutline = !maFontModel.mbOutline;
630 break;
631 case 'H': // shadow
632 setAttributes();
633 maFontModel.mbShadow = !maFontModel.mbShadow;
634 break;
636 case 'K': // text color (not in BIFF)
637 if( (getFilterType() == FILTER_OOXML) && (pcChar + 6 < pcEnd) )
639 setAttributes();
640 // eat the following 6 characters
641 convertFontColor( OUString( pcChar + 1, 6 ) );
642 pcChar += 6;
644 break;
646 case '\"': // font name
647 aFontName.setLength( 0 );
648 aFontStyle.setLength( 0 );
649 eState = STATE_FONTNAME;
650 break;
651 default:
652 if( ('0' <= cChar) && (cChar <= '9') ) // font size
654 nFontHeight = cChar - '0';
655 eState = STATE_FONTHEIGHT;
659 break;
661 case STATE_FONTNAME:
663 switch( cChar )
665 case '\"':
666 setAttributes();
667 convertFontName( aFontName.makeStringAndClear() );
668 eState = STATE_TEXT;
669 break;
670 case ',':
671 eState = STATE_FONTSTYLE;
672 break;
673 default:
674 aFontName.append( cChar );
677 break;
679 case STATE_FONTSTYLE:
681 switch( cChar )
683 case '\"':
684 setAttributes();
685 convertFontName( aFontName.makeStringAndClear() );
686 convertFontStyle( aFontStyle.makeStringAndClear() );
687 eState = STATE_TEXT;
688 break;
689 default:
690 aFontStyle.append( cChar );
693 break;
695 case STATE_FONTHEIGHT:
697 if( ('0' <= cChar) && (cChar <= '9') )
699 if( nFontHeight >= 0 )
701 nFontHeight *= 10;
702 nFontHeight += (cChar - '0');
703 if( nFontHeight > 1000 )
704 nFontHeight = -1;
707 else
709 if( nFontHeight > 0 )
711 setAttributes();
712 maFontModel.mfHeight = nFontHeight;
714 --pcChar;
715 eState = STATE_TEXT;
718 break;
722 // finalize
723 finalizePortion();
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() );
778 updateCurrHeight();
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 );
797 catch( Exception& )
799 OSL_FAIL( OStringBuffer( "HeaderFooterParser::createField - error while creating text field \"" ).
800 append( OUStringToOString( rServiceName, RTL_TEXTENCODING_ASCII_US ) ).
801 append( '"' ).getStr() );
803 return xContent;
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 );
813 updateCurrHeight();
815 catch( Exception& )
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;
827 else
828 maFontModel.maName = rName;
832 void HeaderFooterParser::convertFontStyle( const OUString& rStyle )
834 maFontModel.mbBold = maFontModel.mbItalic = false;
835 sal_Int32 nPos = 0;
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 );
858 else
859 // RGB color: RRGGBB
860 maFontModel.maColor.setRgb( rColor.toUInt32( 16 ) );
863 void HeaderFooterParser::finalizePortion()
865 appendText();
866 setAttributes();
869 void HeaderFooterParser::setNewPortion( HFPortionId ePortion )
871 if( ePortion != meCurrPortion )
873 finalizePortion();
874 meCurrPortion = ePortion;
875 maFontModel = getStyles().getDefaultFontModel();
879 PageSettingsConverter::HFHelperData::HFHelperData( sal_Int32 nLeftPropId, sal_Int32 nRightPropId ) :
880 mnLeftPropId( nLeftPropId ),
881 mnRightPropId( nRightPropId ),
882 mnHeight( 0 ),
883 mnBodyDist( 0 ),
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;
908 // printout scaling
909 if( bChartSheet )
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 ) );
920 else
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 );
927 // paper orientation
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) ) )
931 bLandscape = true;
933 // paper size
934 if( !rModel.mbValidSettings )
936 awt::Size aSize;
937 bool bValid = false;
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 );
948 bValid = true;
951 if( bValid )
953 if( bLandscape )
954 ::std::swap( aSize.Width, aSize.Height );
955 rPropSet.setProperty( PROP_Size, aSize );
959 // header/footer
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);
990 // background image
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 );
1054 return nHeight;
1057 } // namespace xls
1058 } // namespace oox
1060 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */