fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / filter / oox / pagesettings.cxx
blob07afbe37bc1407a43ffffeed32fc0b30d56736c2
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 "biffinputstream.hxx"
41 #include "excelhandlers.hxx"
42 #include "stylesbuffer.hxx"
43 #include "unitconverter.hxx"
44 #include "document.hxx"
45 #include <filter/msfilter/util.hxx>
47 namespace oox {
48 namespace xls {
50 using namespace ::com::sun::star;
51 using namespace ::com::sun::star::lang;
52 using namespace ::com::sun::star::uno;
54 using ::oox::core::Relations;
56 namespace {
58 const double OOX_MARGIN_DEFAULT_LR = 0.748; /// Left/right default margin in inches.
59 const double OOX_MARGIN_DEFAULT_TB = 0.984; /// Top/bottom default margin in inches.
60 const double OOX_MARGIN_DEFAULT_HF = 0.512; /// Header/footer default margin in inches.
62 const sal_uInt16 BIFF12_PRINTOPT_HORCENTER = 0x0001;
63 const sal_uInt16 BIFF12_PRINTOPT_VERCENTER = 0x0002;
64 const sal_uInt16 BIFF12_PRINTOPT_PRINTHEADING = 0x0004;
65 const sal_uInt16 BIFF12_PRINTOPT_PRINTGRID = 0x0008;
67 const sal_uInt16 BIFF12_HEADERFOOTER_DIFFEVEN = 0x0001;
68 const sal_uInt16 BIFF12_HEADERFOOTER_DIFFFIRST = 0x0002;
70 const sal_uInt16 BIFF12_PAGESETUP_INROWS = 0x0001;
71 const sal_uInt16 BIFF12_PAGESETUP_LANDSCAPE = 0x0002;
72 const sal_uInt16 BIFF12_PAGESETUP_INVALID = 0x0004;
73 const sal_uInt16 BIFF12_PAGESETUP_BLACKWHITE = 0x0008;
74 const sal_uInt16 BIFF12_PAGESETUP_DRAFTQUALITY = 0x0010;
75 const sal_uInt16 BIFF12_PAGESETUP_PRINTNOTES = 0x0020;
76 const sal_uInt16 BIFF12_PAGESETUP_DEFAULTORIENT = 0x0040;
77 const sal_uInt16 BIFF12_PAGESETUP_USEFIRSTPAGE = 0x0080;
78 const sal_uInt16 BIFF12_PAGESETUP_NOTES_END = 0x0100; // different to BIFF flag
80 const sal_uInt16 BIFF12_CHARTPAGESETUP_LANDSCAPE = 0x0001;
81 const sal_uInt16 BIFF12_CHARTPAGESETUP_INVALID = 0x0002;
82 const sal_uInt16 BIFF12_CHARTPAGESETUP_BLACKWHITE = 0x0004;
83 const sal_uInt16 BIFF12_CHARTPAGESETUP_DEFAULTORIENT= 0x0008;
84 const sal_uInt16 BIFF12_CHARTPAGESETUP_USEFIRSTPAGE = 0x0010;
85 const sal_uInt16 BIFF12_CHARTPAGESETUP_DRAFTQUALITY = 0x0020;
87 } // namespace
89 PageSettingsModel::PageSettingsModel() :
90 mfLeftMargin( OOX_MARGIN_DEFAULT_LR ),
91 mfRightMargin( OOX_MARGIN_DEFAULT_LR ),
92 mfTopMargin( OOX_MARGIN_DEFAULT_TB ),
93 mfBottomMargin( OOX_MARGIN_DEFAULT_TB ),
94 mfHeaderMargin( OOX_MARGIN_DEFAULT_HF ),
95 mfFooterMargin( OOX_MARGIN_DEFAULT_HF ),
96 mnPaperSize( 1 ),
97 mnPaperWidth( 0 ),
98 mnPaperHeight( 0 ),
99 mnCopies( 1 ),
100 mnScale( 100 ),
101 mnFirstPage( 1 ),
102 mnFitToWidth( 1 ),
103 mnFitToHeight( 1 ),
104 mnHorPrintRes( 600 ),
105 mnVerPrintRes( 600 ),
106 mnOrientation( XML_default ),
107 mnPageOrder( XML_downThenOver ),
108 mnCellComments( XML_none ),
109 mnPrintErrors( XML_displayed ),
110 mbUseEvenHF( false ),
111 mbUseFirstHF( false ),
112 mbValidSettings( true ),
113 mbUseFirstPage( false ),
114 mbBlackWhite( false ),
115 mbDraftQuality( false ),
116 mbFitToPages( false ),
117 mbHorCenter( false ),
118 mbVerCenter( false ),
119 mbPrintGrid( false ),
120 mbPrintHeadings( false )
124 void PageSettingsModel::setBiffPrintErrors( sal_uInt8 nPrintErrors )
126 static const sal_Int32 spnErrorIds[] = { XML_displayed, XML_none, XML_dash, XML_NA };
127 mnPrintErrors = STATIC_ARRAY_SELECT( spnErrorIds, nPrintErrors, XML_none );
130 PageSettings::PageSettings( const WorksheetHelper& rHelper ) :
131 WorksheetHelper( rHelper )
135 void PageSettings::importPrintOptions( const AttributeList& rAttribs )
137 maModel.mbHorCenter = rAttribs.getBool( XML_horizontalCentered, false );
138 maModel.mbVerCenter = rAttribs.getBool( XML_verticalCentered, false );
139 maModel.mbPrintGrid = rAttribs.getBool( XML_gridLines, false );
140 maModel.mbPrintHeadings = rAttribs.getBool( XML_headings, false );
143 void PageSettings::importPageMargins( const AttributeList& rAttribs )
145 maModel.mfLeftMargin = rAttribs.getDouble( XML_left, OOX_MARGIN_DEFAULT_LR );
146 maModel.mfRightMargin = rAttribs.getDouble( XML_right, OOX_MARGIN_DEFAULT_LR );
147 maModel.mfTopMargin = rAttribs.getDouble( XML_top, OOX_MARGIN_DEFAULT_TB );
148 maModel.mfBottomMargin = rAttribs.getDouble( XML_bottom, OOX_MARGIN_DEFAULT_TB );
149 maModel.mfHeaderMargin = rAttribs.getDouble( XML_header, OOX_MARGIN_DEFAULT_HF );
150 maModel.mfFooterMargin = rAttribs.getDouble( XML_footer, OOX_MARGIN_DEFAULT_HF );
153 void PageSettings::importPageSetup( const Relations& rRelations, const AttributeList& rAttribs )
155 OUString aStr;
156 maModel.maBinSettPath = rRelations.getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) );
157 maModel.mnPaperSize = rAttribs.getInteger( XML_paperSize, 1 );
158 aStr = rAttribs.getString ( XML_paperWidth, OUString() );
159 ::sax::Converter::convertMeasure(
160 maModel.mnPaperWidth, aStr, util::MeasureUnit::MM_100TH);
161 aStr = rAttribs.getString ( XML_paperHeight, OUString() );
162 ::sax::Converter::convertMeasure(
163 maModel.mnPaperHeight, aStr, util::MeasureUnit::MM_100TH );
164 maModel.mnCopies = rAttribs.getInteger( XML_copies, 1 );
165 maModel.mnScale = rAttribs.getInteger( XML_scale, 100 );
166 maModel.mnFirstPage = rAttribs.getInteger( XML_firstPageNumber, 1 );
167 maModel.mnFitToWidth = rAttribs.getInteger( XML_fitToWidth, 1 );
168 maModel.mnFitToHeight = rAttribs.getInteger( XML_fitToHeight, 1 );
169 maModel.mnHorPrintRes = rAttribs.getInteger( XML_horizontalDpi, 600 );
170 maModel.mnVerPrintRes = rAttribs.getInteger( XML_verticalDpi, 600 );
171 maModel.mnOrientation = rAttribs.getToken( XML_orientation, XML_default );
172 maModel.mnPageOrder = rAttribs.getToken( XML_pageOrder, XML_downThenOver );
173 maModel.mnCellComments = rAttribs.getToken( XML_cellComments, XML_none );
174 maModel.mnPrintErrors = rAttribs.getToken( XML_errors, XML_displayed );
175 maModel.mbValidSettings = rAttribs.getBool( XML_usePrinterDefaults, false );
176 maModel.mbUseFirstPage = rAttribs.getBool( XML_useFirstPageNumber, false );
177 maModel.mbBlackWhite = rAttribs.getBool( XML_blackAndWhite, false );
178 maModel.mbDraftQuality = rAttribs.getBool( XML_draft, false );
181 void PageSettings::importChartPageSetup( const Relations& rRelations, const AttributeList& rAttribs )
183 OUString aStr;
184 maModel.maBinSettPath = rRelations.getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) );
185 maModel.mnPaperSize = rAttribs.getInteger( XML_paperSize, 1 );
186 aStr = rAttribs.getString ( XML_paperWidth, OUString() );
187 ::sax::Converter::convertMeasure(
188 maModel.mnPaperWidth, aStr, util::MeasureUnit::MM_100TH );
189 aStr = rAttribs.getString ( XML_paperHeight, OUString() );
190 ::sax::Converter::convertMeasure(
191 maModel.mnPaperHeight, aStr, util::MeasureUnit::MM_100TH );
192 maModel.mnCopies = rAttribs.getInteger( XML_copies, 1 );
193 maModel.mnFirstPage = rAttribs.getInteger( XML_firstPageNumber, 1 );
194 maModel.mnHorPrintRes = rAttribs.getInteger( XML_horizontalDpi, 600 );
195 maModel.mnVerPrintRes = rAttribs.getInteger( XML_verticalDpi, 600 );
196 maModel.mnOrientation = rAttribs.getToken( XML_orientation, XML_default );
197 maModel.mbValidSettings = rAttribs.getBool( XML_usePrinterDefaults, false );
198 maModel.mbUseFirstPage = rAttribs.getBool( XML_useFirstPageNumber, false );
199 maModel.mbBlackWhite = rAttribs.getBool( XML_blackAndWhite, false );
200 maModel.mbDraftQuality = rAttribs.getBool( XML_draft, false );
203 void PageSettings::importHeaderFooter( const AttributeList& rAttribs )
205 maModel.mbUseEvenHF = rAttribs.getBool( XML_differentOddEven, false );
206 maModel.mbUseFirstHF = rAttribs.getBool( XML_differentFirst, false );
209 void PageSettings::importHeaderFooterCharacters( const OUString& rChars, sal_Int32 nElement )
211 switch( nElement )
213 case XLS_TOKEN( oddHeader ): maModel.maOddHeader += rChars; break;
214 case XLS_TOKEN( oddFooter ): maModel.maOddFooter += rChars; break;
215 case XLS_TOKEN( evenHeader ): maModel.maEvenHeader += rChars; break;
216 case XLS_TOKEN( evenFooter ): maModel.maEvenFooter += rChars; break;
217 case XLS_TOKEN( firstHeader ): maModel.maFirstHeader += rChars; break;
218 case XLS_TOKEN( firstFooter ): maModel.maFirstFooter += rChars; break;
222 void PageSettings::importPicture( const Relations& rRelations, const AttributeList& rAttribs )
224 importPictureData( rRelations, rAttribs.getString( R_TOKEN( id ), OUString() ) );
227 void PageSettings::importPageMargins( SequenceInputStream& rStrm )
229 maModel.mfLeftMargin = rStrm.readDouble();
230 maModel.mfRightMargin = rStrm.readDouble();
231 maModel.mfTopMargin = rStrm.readDouble();
232 maModel.mfBottomMargin = rStrm.readDouble();
233 maModel.mfHeaderMargin = rStrm.readDouble();
234 maModel.mfFooterMargin = rStrm.readDouble();
237 void PageSettings::importPrintOptions( SequenceInputStream& rStrm )
239 sal_uInt16 nFlags;
240 nFlags = rStrm.readuInt16();
241 maModel.mbHorCenter = getFlag( nFlags, BIFF12_PRINTOPT_HORCENTER );
242 maModel.mbVerCenter = getFlag( nFlags, BIFF12_PRINTOPT_VERCENTER );
243 maModel.mbPrintGrid = getFlag( nFlags, BIFF12_PRINTOPT_PRINTGRID );
244 maModel.mbPrintHeadings = getFlag( nFlags, BIFF12_PRINTOPT_PRINTHEADING );
247 void PageSettings::importPageSetup( const Relations& rRelations, SequenceInputStream& rStrm )
249 OUString aRelId;
250 sal_uInt16 nFlags;
251 maModel.mnPaperSize = rStrm.readInt32();
252 maModel.mnScale = rStrm.readInt32();
253 maModel.mnHorPrintRes = rStrm.readInt32();
254 maModel.mnVerPrintRes = rStrm.readInt32();
255 maModel.mnCopies = rStrm.readInt32();
256 maModel.mnFirstPage = rStrm.readInt32();
257 maModel.mnFitToWidth = rStrm.readInt32();
258 maModel.mnFitToHeight = rStrm.readInt32();
259 nFlags = rStrm.readuInt16();
260 rStrm >> aRelId;
261 maModel.setBiffPrintErrors( extractValue< sal_uInt8 >( nFlags, 9, 2 ) );
262 maModel.maBinSettPath = rRelations.getFragmentPathFromRelId( aRelId );
263 maModel.mnOrientation = getFlagValue( nFlags, BIFF12_PAGESETUP_DEFAULTORIENT, XML_default, getFlagValue( nFlags, BIFF12_PAGESETUP_LANDSCAPE, XML_landscape, XML_portrait ) );
264 maModel.mnPageOrder = getFlagValue( nFlags, BIFF12_PAGESETUP_INROWS, XML_overThenDown, XML_downThenOver );
265 maModel.mnCellComments = getFlagValue( nFlags, BIFF12_PAGESETUP_PRINTNOTES, getFlagValue( nFlags, BIFF12_PAGESETUP_NOTES_END, XML_atEnd, XML_asDisplayed ), XML_none );
266 maModel.mbValidSettings = !getFlag( nFlags, BIFF12_PAGESETUP_INVALID );
267 maModel.mbUseFirstPage = getFlag( nFlags, BIFF12_PAGESETUP_USEFIRSTPAGE );
268 maModel.mbBlackWhite = getFlag( nFlags, BIFF12_PAGESETUP_BLACKWHITE );
269 maModel.mbDraftQuality = getFlag( nFlags, BIFF12_PAGESETUP_DRAFTQUALITY );
272 void PageSettings::importChartPageSetup( const Relations& rRelations, SequenceInputStream& rStrm )
274 OUString aRelId;
275 sal_uInt16 nFirstPage, nFlags;
276 maModel.mnPaperSize = rStrm.readInt32();
277 maModel.mnHorPrintRes = rStrm.readInt32();
278 maModel.mnVerPrintRes = rStrm.readInt32();
279 maModel.mnCopies = rStrm.readInt32();
280 nFirstPage = rStrm.readuInt16();
281 nFlags = rStrm.readuInt16();
282 rStrm >> aRelId;
283 maModel.maBinSettPath = rRelations.getFragmentPathFromRelId( aRelId );
284 maModel.mnFirstPage = nFirstPage; // 16-bit in CHARTPAGESETUP
285 maModel.mnOrientation = getFlagValue( nFlags, BIFF12_CHARTPAGESETUP_DEFAULTORIENT, XML_default, getFlagValue( nFlags, BIFF12_CHARTPAGESETUP_LANDSCAPE, XML_landscape, XML_portrait ) );
286 maModel.mbValidSettings = !getFlag( nFlags, BIFF12_CHARTPAGESETUP_INVALID );
287 maModel.mbUseFirstPage = getFlag( nFlags, BIFF12_CHARTPAGESETUP_USEFIRSTPAGE );
288 maModel.mbBlackWhite = getFlag( nFlags, BIFF12_CHARTPAGESETUP_BLACKWHITE );
289 maModel.mbDraftQuality = getFlag( nFlags, BIFF12_CHARTPAGESETUP_DRAFTQUALITY );
292 void PageSettings::importHeaderFooter( SequenceInputStream& rStrm )
294 sal_uInt16 nFlags;
295 nFlags = rStrm.readuInt16();
296 rStrm >> maModel.maOddHeader >> maModel.maOddFooter
297 >> maModel.maEvenHeader >> maModel.maEvenFooter
298 >> maModel.maFirstHeader >> maModel.maFirstFooter;
299 maModel.mbUseEvenHF = getFlag( nFlags, BIFF12_HEADERFOOTER_DIFFEVEN );
300 maModel.mbUseFirstHF = getFlag( nFlags, BIFF12_HEADERFOOTER_DIFFFIRST );
303 void PageSettings::importPicture( const Relations& rRelations, SequenceInputStream& rStrm )
305 importPictureData( rRelations, BiffHelper::readString( rStrm ) );
308 void PageSettings::setFitToPagesMode( bool bFitToPages )
310 maModel.mbFitToPages = bFitToPages;
313 void PageSettings::finalizeImport()
315 OUStringBuffer aStyleNameBuffer( "PageStyle_" );
316 Reference<container::XNamed> xSheetName(getSheet(), UNO_QUERY);
317 if( xSheetName.is() )
318 aStyleNameBuffer.append( xSheetName->getName() );
319 else
320 aStyleNameBuffer.append( static_cast< sal_Int32 >( getSheetIndex() + 1 ) );
321 OUString aStyleName = aStyleNameBuffer.makeStringAndClear();
323 Reference<style::XStyle> xStyle = createStyleObject(aStyleName, true);
324 PropertySet aStyleProps( xStyle );
325 getPageSettingsConverter().writePageSettingsProperties( aStyleProps, maModel, getSheetType() );
327 // Set page style name to the sheet.
328 SCTAB nTab = getSheetIndex();
329 getScDocument().SetPageStyle(nTab, aStyleName);
332 void PageSettings::importPictureData( const Relations& rRelations, const OUString& rRelId )
334 OUString aPicturePath = rRelations.getFragmentPathFromRelId( rRelId );
335 if( !aPicturePath.isEmpty() )
336 maModel.maGraphicUrl = getBaseFilter().getGraphicHelper().importEmbeddedGraphicObject( aPicturePath );
339 enum HFPortionId
341 HF_LEFT,
342 HF_CENTER,
343 HF_RIGHT,
344 HF_COUNT
347 struct HFPortionInfo
349 Reference<text::XText> mxText; /// XText interface of this portion.
350 Reference<text::XTextCursor> mxStart; /// Start position of current text range for formatting.
351 Reference<text::XTextCursor> mxEnd; /// End position of current text range for formatting.
352 double mfTotalHeight; /// Sum of heights of previous lines in points.
353 double mfCurrHeight; /// Height of the current text line in points.
355 bool initialize( const Reference<text::XText>& rxText );
358 bool HFPortionInfo::initialize( const Reference<text::XText>& rxText )
360 mfTotalHeight = mfCurrHeight = 0.0;
361 mxText = rxText;
362 if( mxText.is() )
364 mxStart = mxText->createTextCursor();
365 mxEnd = mxText->createTextCursor();
367 bool bRet = mxText.is() && mxStart.is() && mxEnd.is();
368 OSL_ENSURE( bRet, "HFPortionInfo::initialize - missing interfaces" );
369 return bRet;
372 class HeaderFooterParser : public WorkbookHelper
374 public:
375 explicit HeaderFooterParser( const WorkbookHelper& rHelper );
377 /** Parses the passed string and creates the header/footer contents.
378 @returns The total height of the converted header or footer in points. */
379 double parse(
380 const Reference<sheet::XHeaderFooterContent>& rxContext,
381 const OUString& rData );
383 private:
384 /** Returns the current edit engine text object. */
385 inline HFPortionInfo& getPortion() { return maPortions[ meCurrPortion ]; }
386 /** Returns the start cursor of the current text range. */
387 inline const Reference<text::XTextCursor>& getStartPos() { return getPortion().mxStart; }
388 /** Returns the end cursor of the current text range. */
389 inline const Reference<text::XTextCursor>& getEndPos() { return getPortion().mxEnd; }
391 /** Returns the current line height of the specified portion. */
392 double getCurrHeight( HFPortionId ePortion ) const;
393 /** Returns the current line height. */
394 double getCurrHeight() const;
396 /** Updates the current line height of the specified portion, using the current font size. */
397 void updateCurrHeight( HFPortionId ePortion );
398 /** Updates the current line height, using the current font size. */
399 void updateCurrHeight();
401 /** Sets the font attributes at the current selection. */
402 void setAttributes();
403 /** Appends and clears internal string buffer. */
404 void appendText();
405 /** Appends a line break and adjusts internal text height data. */
406 void appendLineBreak();
408 /** Creates a text field from the passed service name. */
409 Reference<text::XTextContent> createField( const OUString& rServiceName ) const;
410 /** Appends the passed text field. */
411 void appendField( const Reference<text::XTextContent>& rxContent );
413 /** Sets the passed font name if it is valid. */
414 void convertFontName( const OUString& rStyle );
415 /** Converts a font style given as string. */
416 void convertFontStyle( const OUString& rStyle );
417 /** Converts a font color given as string. */
418 void convertFontColor( const OUString& rColor );
420 /** Finalizes current portion: sets font attributes and updates text height data. */
421 void finalizePortion();
422 /** Changes current header/footer portion. */
423 void setNewPortion( HFPortionId ePortion );
425 private:
426 typedef ::std::vector< HFPortionInfo > HFPortionInfoVec;
427 typedef ::std::set< OString > OStringSet;
429 const OUString maPageNumberService;
430 const OUString maPageCountService;
431 const OUString maSheetNameService;
432 const OUString maFileNameService;
433 const OUString maDateTimeService;
434 const OStringSet maBoldNames; /// All names for bold font style in lowercase UTF-8.
435 const OStringSet maItalicNames; /// All names for italic font style in lowercase UTF-8.
436 HFPortionInfoVec maPortions;
437 HFPortionId meCurrPortion; /// Identifier of current H/F portion.
438 OUStringBuffer maBuffer; /// Text data to append to current text range.
439 FontModel maFontModel; /// Font attributes of current text range.
442 namespace {
444 // different names for bold font style (lowercase)
445 static const sal_Char* const sppcBoldNames[] =
447 "bold",
448 "fett", // German 'bold'
449 "demibold",
450 "halbfett", // German 'demibold'
451 "black",
452 "heavy"
455 // different names for italic font style (lowercase)
456 static const sal_Char* const sppcItalicNames[] =
458 "italic",
459 "kursiv", // German 'italic'
460 "oblique",
461 "schr\303\204g", // German 'oblique' with uppercase A umlaut
462 "schr\303\244g" // German 'oblique' with lowercase A umlaut
465 } // namespace
467 HeaderFooterParser::HeaderFooterParser( const WorkbookHelper& rHelper ) :
468 WorkbookHelper( rHelper ),
469 maPageNumberService( "com.sun.star.text.TextField.PageNumber" ),
470 maPageCountService( "com.sun.star.text.TextField.PageCount" ),
471 maSheetNameService( "com.sun.star.text.TextField.SheetName" ),
472 maFileNameService( "com.sun.star.text.TextField.FileName" ),
473 maDateTimeService( "com.sun.star.text.TextField.DateTime" ),
474 maBoldNames( sppcBoldNames, STATIC_ARRAY_END( sppcBoldNames ) ),
475 maItalicNames( sppcItalicNames, STATIC_ARRAY_END( 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() ) )
487 return 0.0;
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. */
497 enum
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).
505 eState = STATE_TEXT;
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;
512 switch( eState )
514 case STATE_TEXT:
516 switch( cChar )
518 case '&': // new token
519 appendText();
520 eState = STATE_TOKEN;
521 break;
522 case '\n': // line break
523 appendText();
524 appendLineBreak();
525 break;
526 default:
527 maBuffer.append( cChar );
530 break;
532 case STATE_TOKEN:
534 // default: back to text mode, may be changed in specific cases
535 eState = STATE_TEXT;
536 // ignore case of token codes
537 if( ('a' <= cChar) && (cChar <= 'z') )
538 (cChar -= 'a') += 'A';
539 switch( cChar )
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( maPageNumberService ) );
549 break;
550 case 'N': // total page count
551 appendField( createField( maPageCountService ) );
552 break;
553 case 'A': // current sheet name
554 appendField( createField( maSheetNameService ) );
555 break;
557 case 'F': // file name
559 Reference<text::XTextContent> xContent = createField( maFileNameService );
560 PropertySet aPropSet( xContent );
561 aPropSet.setProperty( PROP_FileFormat, ::com::sun::star::text::FilenameDisplayFormat::NAME_AND_EXT );
562 appendField( xContent );
564 break;
565 case 'Z': // file path (without file name), OOXML, BIFF12, and BIFF8 only
566 if( (getFilterType() == FILTER_OOXML) || ((getFilterType() == FILTER_BIFF) && (getBiff() == BIFF8)) )
568 Reference<text::XTextContent> xContent = createField( maFileNameService );
569 PropertySet aPropSet( xContent );
570 // FilenameDisplayFormat::PATH not supported by Calc
571 aPropSet.setProperty( PROP_FileFormat, ::com::sun::star::text::FilenameDisplayFormat::FULL );
572 appendField( xContent );
573 /* path only is not supported -- if we find a '&Z&F'
574 combination for path/name, skip the '&F' part */
575 if( (pcChar + 2 < pcEnd) && (pcChar[ 1 ] == '&') && ((pcChar[ 2 ] == 'f') || (pcChar[ 2 ] == 'F')) )
576 pcChar += 2;
578 break;
579 case 'D': // date
581 Reference<text::XTextContent> xContent = createField( maDateTimeService );
582 PropertySet aPropSet( xContent );
583 aPropSet.setProperty( PROP_IsDate, true );
584 appendField( xContent );
586 break;
587 case 'T': // time
589 Reference<text::XTextContent> xContent = createField( maDateTimeService );
590 PropertySet aPropSet( xContent );
591 aPropSet.setProperty( PROP_IsDate, false );
592 appendField( xContent );
594 break;
596 case 'B': // bold
597 setAttributes();
598 maFontModel.mbBold = !maFontModel.mbBold;
599 break;
600 case 'I': // italic
601 setAttributes();
602 maFontModel.mbItalic = !maFontModel.mbItalic;
603 break;
604 case 'U': // underline
605 setAttributes();
606 maFontModel.mnUnderline = (maFontModel.mnUnderline == XML_single) ? XML_none : XML_single;
607 break;
608 case 'E': // double underline
609 setAttributes();
610 maFontModel.mnUnderline = (maFontModel.mnUnderline == XML_double) ? XML_none : XML_double;
611 break;
612 case 'S': // strikeout
613 setAttributes();
614 maFontModel.mbStrikeout = !maFontModel.mbStrikeout;
615 break;
616 case 'X': // superscript
617 setAttributes();
618 maFontModel.mnEscapement = (maFontModel.mnEscapement == XML_superscript) ? XML_baseline : XML_superscript;
619 break;
620 case 'Y': // subsrcipt
621 setAttributes();
622 maFontModel.mnEscapement = (maFontModel.mnEscapement == XML_subscript) ? XML_baseline : XML_subscript;
623 break;
624 case 'O': // outlined
625 setAttributes();
626 maFontModel.mbOutline = !maFontModel.mbOutline;
627 break;
628 case 'H': // shadow
629 setAttributes();
630 maFontModel.mbShadow = !maFontModel.mbShadow;
631 break;
633 case 'K': // text color (not in BIFF)
634 if( (getFilterType() == FILTER_OOXML) && (pcChar + 6 < pcEnd) )
636 setAttributes();
637 // eat the following 6 characters
638 convertFontColor( OUString( pcChar + 1, 6 ) );
639 pcChar += 6;
641 break;
643 case '\"': // font name
644 aFontName.setLength( 0 );
645 aFontStyle.setLength( 0 );
646 eState = STATE_FONTNAME;
647 break;
648 default:
649 if( ('0' <= cChar) && (cChar <= '9') ) // font size
651 nFontHeight = cChar - '0';
652 eState = STATE_FONTHEIGHT;
656 break;
658 case STATE_FONTNAME:
660 switch( cChar )
662 case '\"':
663 setAttributes();
664 convertFontName( aFontName.makeStringAndClear() );
665 eState = STATE_TEXT;
666 break;
667 case ',':
668 eState = STATE_FONTSTYLE;
669 break;
670 default:
671 aFontName.append( cChar );
674 break;
676 case STATE_FONTSTYLE:
678 switch( cChar )
680 case '\"':
681 setAttributes();
682 convertFontName( aFontName.makeStringAndClear() );
683 convertFontStyle( aFontStyle.makeStringAndClear() );
684 eState = STATE_TEXT;
685 break;
686 default:
687 aFontStyle.append( cChar );
690 break;
692 case STATE_FONTHEIGHT:
694 if( ('0' <= cChar) && (cChar <= '9') )
696 if( nFontHeight >= 0 )
698 nFontHeight *= 10;
699 nFontHeight += (cChar - '0');
700 if( nFontHeight > 1000 )
701 nFontHeight = -1;
704 else
706 if( nFontHeight > 0 )
708 setAttributes();
709 maFontModel.mfHeight = nFontHeight;
711 --pcChar;
712 eState = STATE_TEXT;
715 break;
719 // finalize
720 finalizePortion();
721 maPortions[ HF_LEFT ].mfTotalHeight += getCurrHeight( HF_LEFT );
722 maPortions[ HF_CENTER ].mfTotalHeight += getCurrHeight( HF_CENTER );
723 maPortions[ HF_RIGHT ].mfTotalHeight += getCurrHeight( HF_RIGHT );
725 return ::std::max( maPortions[ HF_LEFT ].mfTotalHeight,
726 ::std::max( maPortions[ HF_CENTER ].mfTotalHeight, maPortions[ HF_RIGHT ].mfTotalHeight ) );
729 // private --------------------------------------------------------------------
731 double HeaderFooterParser::getCurrHeight( HFPortionId ePortion ) const
733 double fMaxHt = maPortions[ ePortion ].mfCurrHeight;
734 return (fMaxHt == 0.0) ? maFontModel.mfHeight : fMaxHt;
737 double HeaderFooterParser::getCurrHeight() const
739 return getCurrHeight( meCurrPortion );
742 void HeaderFooterParser::updateCurrHeight( HFPortionId ePortion )
744 double& rfMaxHt = maPortions[ ePortion ].mfCurrHeight;
745 rfMaxHt = ::std::max( rfMaxHt, maFontModel.mfHeight );
748 void HeaderFooterParser::updateCurrHeight()
750 updateCurrHeight( meCurrPortion );
753 void HeaderFooterParser::setAttributes()
755 Reference<text::XTextRange> xRange( getStartPos(), UNO_QUERY );
756 getEndPos()->gotoRange( xRange, sal_False );
757 getEndPos()->gotoEnd( sal_True );
758 if( !getEndPos()->isCollapsed() )
760 Font aFont( *this, maFontModel );
761 aFont.finalizeImport();
762 PropertySet aPropSet( getEndPos() );
763 aFont.writeToPropertySet( aPropSet, FONT_PROPTYPE_TEXT );
764 getStartPos()->gotoEnd( sal_False );
765 getEndPos()->gotoEnd( sal_False );
769 void HeaderFooterParser::appendText()
771 if( !maBuffer.isEmpty() )
773 getEndPos()->gotoEnd( sal_False );
774 getEndPos()->setString( maBuffer.makeStringAndClear() );
775 updateCurrHeight();
779 void HeaderFooterParser::appendLineBreak()
781 getEndPos()->gotoEnd( sal_False );
782 getEndPos()->setString( OUString( '\n' ) );
783 getPortion().mfTotalHeight += getCurrHeight();
784 getPortion().mfCurrHeight = 0;
787 Reference<text::XTextContent> HeaderFooterParser::createField( const OUString& rServiceName ) const
789 Reference<text::XTextContent> xContent;
792 xContent.set( getBaseFilter().getModelFactory()->createInstance( rServiceName ), UNO_QUERY_THROW );
794 catch( Exception& )
796 OSL_FAIL( OStringBuffer( "HeaderFooterParser::createField - error while creating text field \"" ).
797 append( OUStringToOString( rServiceName, RTL_TEXTENCODING_ASCII_US ) ).
798 append( '"' ).getStr() );
800 return xContent;
803 void HeaderFooterParser::appendField( const Reference<text::XTextContent>& rxContent )
805 getEndPos()->gotoEnd( sal_False );
808 Reference<text::XTextRange> xRange( getEndPos(), UNO_QUERY_THROW );
809 getPortion().mxText->insertTextContent( xRange, rxContent, sal_False );
810 updateCurrHeight();
812 catch( Exception& )
817 void HeaderFooterParser::convertFontName( const OUString& rName )
819 if( !rName.isEmpty() )
821 // single dash is document default font
822 if( (rName.getLength() == 1) && (rName[ 0 ] == '-') )
823 maFontModel.maName = getStyles().getDefaultFontModel().maName;
824 else
825 maFontModel.maName = rName;
829 void HeaderFooterParser::convertFontStyle( const OUString& rStyle )
831 maFontModel.mbBold = maFontModel.mbItalic = false;
832 sal_Int32 nPos = 0;
833 sal_Int32 nLen = rStyle.getLength();
834 while( (0 <= nPos) && (nPos < nLen) )
836 OString aToken = OUStringToOString( rStyle.getToken( 0, ' ', nPos ), RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase();
837 if( !aToken.isEmpty() )
839 if( maBoldNames.count( aToken ) > 0 )
840 maFontModel.mbBold = true;
841 else if( maItalicNames.count( aToken ) > 0 )
842 maFontModel.mbItalic = true;
847 void HeaderFooterParser::convertFontColor( const OUString& rColor )
849 OSL_ENSURE( rColor.getLength() == 6, "HeaderFooterParser::convertFontColor - invalid font color code" );
850 if( (rColor[ 2 ] == '+') || (rColor[ 2 ] == '-') )
851 // theme color: TTSNNN (TT = decimal theme index, S = +/-, NNN = decimal tint/shade in percent)
852 maFontModel.maColor.setTheme(
853 rColor.copy( 0, 2 ).toInt32(),
854 static_cast< double >( rColor.copy( 2 ).toInt32() ) / 100.0 );
855 else
856 // RGB color: RRGGBB
857 maFontModel.maColor.setRgb( rColor.toUInt32( 16 ) );
860 void HeaderFooterParser::finalizePortion()
862 appendText();
863 setAttributes();
866 void HeaderFooterParser::setNewPortion( HFPortionId ePortion )
868 if( ePortion != meCurrPortion )
870 finalizePortion();
871 meCurrPortion = ePortion;
872 maFontModel = getStyles().getDefaultFontModel();
876 PageSettingsConverter::HFHelperData::HFHelperData( sal_Int32 nLeftPropId, sal_Int32 nRightPropId ) :
877 mnLeftPropId( nLeftPropId ),
878 mnRightPropId( nRightPropId ),
879 mnHeight( 0 ),
880 mnBodyDist( 0 ),
881 mbHasContent( false ),
882 mbShareOddEven( false ),
883 mbDynamicHeight( false )
887 PageSettingsConverter::PageSettingsConverter( const WorkbookHelper& rHelper ) :
888 WorkbookHelper( rHelper ),
889 mxHFParser( new HeaderFooterParser( rHelper ) ),
890 maHeaderData( PROP_LeftPageHeaderContent, PROP_RightPageHeaderContent ),
891 maFooterData( PROP_LeftPageFooterContent, PROP_RightPageFooterContent )
895 PageSettingsConverter::~PageSettingsConverter()
899 void PageSettingsConverter::writePageSettingsProperties(
900 PropertySet& rPropSet, const PageSettingsModel& rModel, WorksheetType eSheetType )
902 // special handling for chart sheets
903 bool bChartSheet = eSheetType == SHEETTYPE_CHARTSHEET;
905 // printout scaling
906 if( bChartSheet )
908 // always fit chart sheet to 1 page
909 rPropSet.setProperty< sal_Int16 >( PROP_ScaleToPages, 1 );
911 else if( rModel.mbFitToPages )
913 // fit to number of pages
914 rPropSet.setProperty( PROP_ScaleToPagesX, getLimitedValue< sal_Int16, sal_Int32 >( rModel.mnFitToWidth, 0, 1000 ) );
915 rPropSet.setProperty( PROP_ScaleToPagesY, getLimitedValue< sal_Int16, sal_Int32 >( rModel.mnFitToHeight, 0, 1000 ) );
917 else
919 // scale may be 0 which indicates uninitialized
920 sal_Int16 nScale = (rModel.mbValidSettings && (rModel.mnScale > 0)) ? getLimitedValue< sal_Int16, sal_Int32 >( rModel.mnScale, 10, 400 ) : 100;
921 rPropSet.setProperty( PROP_PageScale, nScale );
924 // paper orientation
925 bool bLandscape = rModel.mnOrientation == XML_landscape;
926 // default orientation for current sheet type (chart sheets default to landscape)
927 if( bChartSheet && ( !rModel.mbValidSettings || (rModel.mnOrientation == XML_default) ) )
928 bLandscape = true;
930 // paper size
931 if( !rModel.mbValidSettings )
933 awt::Size aSize;
934 bool bValid = false;
936 if( (0 < rModel.mnPaperSize) )
938 const msfilter::util::ApiPaperSize& rPaperSize = msfilter::util::PaperSizeConv::getApiSizeForMSPaperSizeIndex( rModel.mnPaperSize );
939 aSize = awt::Size( rPaperSize.mnWidth, rPaperSize.mnHeight );
940 bValid = ( rPaperSize.mnWidth != 0 && rPaperSize.mnHeight != 0 );
942 if( rModel.mnPaperWidth > 0 && rModel.mnPaperHeight > 0 )
944 aSize = awt::Size( rModel.mnPaperWidth, rModel.mnPaperHeight );
945 bValid = true;
948 if( bValid )
950 if( bLandscape )
951 ::std::swap( aSize.Width, aSize.Height );
952 rPropSet.setProperty( PROP_Size, aSize );
956 // header/footer
957 convertHeaderFooterData( rPropSet, maHeaderData, rModel.maOddHeader, rModel.maEvenHeader, rModel.mbUseEvenHF, rModel.mfTopMargin, rModel.mfHeaderMargin );
958 convertHeaderFooterData( rPropSet, maFooterData, rModel.maOddFooter, rModel.maEvenFooter, rModel.mbUseEvenHF, rModel.mfBottomMargin, rModel.mfFooterMargin );
960 // write all properties to property set
961 const UnitConverter& rUnitConv = getUnitConverter();
962 PropertyMap aPropMap;
963 aPropMap.setProperty( PROP_IsLandscape, bLandscape);
964 aPropMap.setProperty( PROP_FirstPageNumber, getLimitedValue< sal_Int16, sal_Int32 >( rModel.mbUseFirstPage ? rModel.mnFirstPage : 0, 0, 9999 ));
965 aPropMap.setProperty( PROP_PrintDownFirst, (rModel.mnPageOrder == XML_downThenOver));
966 aPropMap.setProperty( PROP_PrintAnnotations, (rModel.mnCellComments == XML_asDisplayed));
967 aPropMap.setProperty( PROP_CenterHorizontally, rModel.mbHorCenter);
968 aPropMap.setProperty( PROP_CenterVertically, rModel.mbVerCenter);
969 aPropMap.setProperty( PROP_PrintGrid, (!bChartSheet && rModel.mbPrintGrid)); // no gridlines in chart sheets
970 aPropMap.setProperty( PROP_PrintHeaders, (!bChartSheet && rModel.mbPrintHeadings)); // no column/row headings in chart sheets
971 aPropMap.setProperty( PROP_LeftMargin, rUnitConv.scaleToMm100( rModel.mfLeftMargin, UNIT_INCH ));
972 aPropMap.setProperty( PROP_RightMargin, rUnitConv.scaleToMm100( rModel.mfRightMargin, UNIT_INCH ));
973 // #i23296# In Calc, "TopMargin" property is distance to top of header if enabled
974 aPropMap.setProperty( PROP_TopMargin, rUnitConv.scaleToMm100( maHeaderData.mbHasContent ? rModel.mfHeaderMargin : rModel.mfTopMargin, UNIT_INCH ));
975 // #i23296# In Calc, "BottomMargin" property is distance to bottom of footer if enabled
976 aPropMap.setProperty( PROP_BottomMargin, rUnitConv.scaleToMm100( maFooterData.mbHasContent ? rModel.mfFooterMargin : rModel.mfBottomMargin, UNIT_INCH ));
977 aPropMap.setProperty( PROP_HeaderIsOn, maHeaderData.mbHasContent);
978 aPropMap.setProperty( PROP_HeaderIsShared, maHeaderData.mbShareOddEven);
979 aPropMap.setProperty( PROP_HeaderIsDynamicHeight, maHeaderData.mbDynamicHeight);
980 aPropMap.setProperty( PROP_HeaderHeight, maHeaderData.mnHeight);
981 aPropMap.setProperty( PROP_HeaderBodyDistance, maHeaderData.mnBodyDist);
982 aPropMap.setProperty( PROP_FooterIsOn, maFooterData.mbHasContent);
983 aPropMap.setProperty( PROP_FooterIsShared, maFooterData.mbShareOddEven);
984 aPropMap.setProperty( PROP_FooterIsDynamicHeight, maFooterData.mbDynamicHeight);
985 aPropMap.setProperty( PROP_FooterHeight, maFooterData.mnHeight);
986 aPropMap.setProperty( PROP_FooterBodyDistance, maFooterData.mnBodyDist);
987 // background image
988 if( !rModel.maGraphicUrl.isEmpty() )
990 aPropMap.setProperty( PROP_BackGraphicURL, rModel.maGraphicUrl);
991 aPropMap.setProperty( PROP_BackGraphicLocation, ::com::sun::star::style::GraphicLocation_TILED);
994 rPropSet.setProperties( aPropMap );
997 void PageSettingsConverter::convertHeaderFooterData(
998 PropertySet& rPropSet, HFHelperData& orHFData,
999 const OUString& rOddContent, const OUString& rEvenContent, bool bUseEvenContent,
1000 double fPageMargin, double fContentMargin )
1002 bool bHasOddContent = !rOddContent.isEmpty();
1003 bool bHasEvenContent = bUseEvenContent && !rEvenContent.isEmpty();
1005 sal_Int32 nOddHeight = bHasOddContent ? writeHeaderFooter( rPropSet, orHFData.mnRightPropId, rOddContent ) : 0;
1006 sal_Int32 nEvenHeight = bHasEvenContent ? writeHeaderFooter( rPropSet, orHFData.mnLeftPropId, rEvenContent ) : 0;
1008 orHFData.mnHeight = 750;
1009 orHFData.mnBodyDist = 250;
1010 orHFData.mbHasContent = bHasOddContent || bHasEvenContent;
1011 orHFData.mbShareOddEven = !bUseEvenContent;
1012 orHFData.mbDynamicHeight = true;
1014 if( orHFData.mbHasContent )
1016 // use maximum height of odd/even header/footer
1017 orHFData.mnHeight = ::std::max( nOddHeight, nEvenHeight );
1018 /* Calc contains distance between bottom of header and top of page
1019 body in "HeaderBodyDistance" property, and distance between bottom
1020 of page body and top of footer in "FooterBodyDistance" property */
1021 orHFData.mnBodyDist = getUnitConverter().scaleToMm100( fPageMargin - fContentMargin, UNIT_INCH ) - orHFData.mnHeight;
1022 /* #i23296# Distance less than 0 means, header or footer overlays page
1023 body. As this is not possible in Calc, set fixed header or footer
1024 height (crop header/footer) to get correct top position of page body. */
1025 orHFData.mbDynamicHeight = orHFData.mnBodyDist >= 0;
1026 /* "HeaderHeight" property is in fact distance from top of header to
1027 top of page body (including "HeaderBodyDistance").
1028 "FooterHeight" property is in fact distance from bottom of page
1029 body to bottom of footer (including "FooterBodyDistance"). */
1030 orHFData.mnHeight += orHFData.mnBodyDist;
1031 // negative body distance not allowed
1032 orHFData.mnBodyDist = ::std::max< sal_Int32 >( orHFData.mnBodyDist, 0 );
1036 sal_Int32 PageSettingsConverter::writeHeaderFooter(
1037 PropertySet& rPropSet, sal_Int32 nPropId, const OUString& rContent )
1039 OSL_ENSURE( !rContent.isEmpty(), "PageSettingsConverter::writeHeaderFooter - empty h/f string found" );
1040 sal_Int32 nHeight = 0;
1041 if( !rContent.isEmpty() )
1043 Reference<sheet::XHeaderFooterContent> xHFContent(rPropSet.getAnyProperty(nPropId), UNO_QUERY);
1044 if( xHFContent.is() )
1046 double fTotalHeight = mxHFParser->parse( xHFContent, rContent );
1047 rPropSet.setProperty( nPropId, xHFContent );
1048 nHeight = getUnitConverter().scaleToMm100( fTotalHeight, UNIT_POINT );
1051 return nHeight;
1054 } // namespace xls
1055 } // namespace oox
1057 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */