xref: /aoo41x/main/oox/source/xls/pagesettings.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "oox/xls/pagesettings.hxx"
29 
30 #include <algorithm>
31 #include <set>
32 #include <com/sun/star/awt/Size.hpp>
33 #include <com/sun/star/container/XNamed.hpp>
34 #include <com/sun/star/sheet/XHeaderFooterContent.hpp>
35 #include <com/sun/star/style/GraphicLocation.hpp>
36 #include <com/sun/star/text/FilenameDisplayFormat.hpp>
37 #include <com/sun/star/text/XText.hpp>
38 #include <com/sun/star/text/XTextContent.hpp>
39 #include <com/sun/star/text/XTextCursor.hpp>
40 #include <rtl/strbuf.hxx>
41 #include <rtl/ustrbuf.hxx>
42 #include "oox/core/xmlfilterbase.hxx"
43 #include "oox/helper/attributelist.hxx"
44 #include "oox/helper/graphichelper.hxx"
45 #include "oox/helper/propertymap.hxx"
46 #include "oox/helper/propertyset.hxx"
47 #include "oox/xls/biffinputstream.hxx"
48 #include "oox/xls/excelhandlers.hxx"
49 #include "oox/xls/stylesbuffer.hxx"
50 #include "oox/xls/unitconverter.hxx"
51 
52 namespace oox {
53 namespace xls {
54 
55 // ============================================================================
56 
57 using namespace ::com::sun::star::awt;
58 using namespace ::com::sun::star::container;
59 using namespace ::com::sun::star::lang;
60 using namespace ::com::sun::star::sheet;
61 using namespace ::com::sun::star::style;
62 using namespace ::com::sun::star::text;
63 using namespace ::com::sun::star::uno;
64 
65 using ::oox::core::Relations;
66 using ::rtl::OString;
67 using ::rtl::OStringBuffer;
68 using ::rtl::OUString;
69 using ::rtl::OUStringBuffer;
70 
71 // ============================================================================
72 
73 namespace {
74 
75 const double OOX_MARGIN_DEFAULT_LR                  = 0.748;    /// Left/right default margin in inches.
76 const double OOX_MARGIN_DEFAULT_TB                  = 0.984;    /// Top/bottom default margin in inches.
77 const double OOX_MARGIN_DEFAULT_HF                  = 0.512;    /// Header/footer default margin in inches.
78 
79 const sal_uInt16 BIFF12_PRINTOPT_HORCENTER          = 0x0001;
80 const sal_uInt16 BIFF12_PRINTOPT_VERCENTER          = 0x0002;
81 const sal_uInt16 BIFF12_PRINTOPT_PRINTHEADING       = 0x0004;
82 const sal_uInt16 BIFF12_PRINTOPT_PRINTGRID          = 0x0008;
83 
84 const sal_uInt16 BIFF12_HEADERFOOTER_DIFFEVEN       = 0x0001;
85 const sal_uInt16 BIFF12_HEADERFOOTER_DIFFFIRST      = 0x0002;
86 const sal_uInt16 BIFF12_HEADERFOOTER_SCALEDOC       = 0x0004;
87 const sal_uInt16 BIFF12_HEADERFOOTER_ALIGNMARGIN    = 0x0008;
88 
89 const sal_uInt16 BIFF12_PAGESETUP_INROWS            = 0x0001;
90 const sal_uInt16 BIFF12_PAGESETUP_LANDSCAPE         = 0x0002;
91 const sal_uInt16 BIFF12_PAGESETUP_INVALID           = 0x0004;
92 const sal_uInt16 BIFF12_PAGESETUP_BLACKWHITE        = 0x0008;
93 const sal_uInt16 BIFF12_PAGESETUP_DRAFTQUALITY      = 0x0010;
94 const sal_uInt16 BIFF12_PAGESETUP_PRINTNOTES        = 0x0020;
95 const sal_uInt16 BIFF12_PAGESETUP_DEFAULTORIENT     = 0x0040;
96 const sal_uInt16 BIFF12_PAGESETUP_USEFIRSTPAGE      = 0x0080;
97 const sal_uInt16 BIFF12_PAGESETUP_NOTES_END         = 0x0100;   // different to BIFF flag
98 
99 const sal_uInt16 BIFF12_CHARTPAGESETUP_LANDSCAPE    = 0x0001;
100 const sal_uInt16 BIFF12_CHARTPAGESETUP_INVALID      = 0x0002;
101 const sal_uInt16 BIFF12_CHARTPAGESETUP_BLACKWHITE   = 0x0004;
102 const sal_uInt16 BIFF12_CHARTPAGESETUP_DEFAULTORIENT= 0x0008;
103 const sal_uInt16 BIFF12_CHARTPAGESETUP_USEFIRSTPAGE = 0x0010;
104 const sal_uInt16 BIFF12_CHARTPAGESETUP_DRAFTQUALITY = 0x0020;
105 
106 const sal_uInt16 BIFF_PAGESETUP_INROWS              = 0x0001;
107 const sal_uInt16 BIFF_PAGESETUP_PORTRAIT            = 0x0002;
108 const sal_uInt16 BIFF_PAGESETUP_INVALID             = 0x0004;
109 const sal_uInt16 BIFF_PAGESETUP_BLACKWHITE          = 0x0008;
110 const sal_uInt16 BIFF_PAGESETUP_DRAFTQUALITY        = 0x0010;
111 const sal_uInt16 BIFF_PAGESETUP_PRINTNOTES          = 0x0020;
112 const sal_uInt16 BIFF_PAGESETUP_DEFAULTORIENT       = 0x0040;
113 const sal_uInt16 BIFF_PAGESETUP_USEFIRSTPAGE        = 0x0080;
114 const sal_uInt16 BIFF_PAGESETUP_NOTES_END           = 0x0200;
115 
116 } // namespace
117 
118 // ============================================================================
119 
120 PageSettingsModel::PageSettingsModel() :
121     mfLeftMargin( OOX_MARGIN_DEFAULT_LR ),
122     mfRightMargin( OOX_MARGIN_DEFAULT_LR ),
123     mfTopMargin( OOX_MARGIN_DEFAULT_TB ),
124     mfBottomMargin( OOX_MARGIN_DEFAULT_TB ),
125     mfHeaderMargin( OOX_MARGIN_DEFAULT_HF ),
126     mfFooterMargin( OOX_MARGIN_DEFAULT_HF ),
127     mnPaperSize( 1 ),
128     mnCopies( 1 ),
129     mnScale( 100 ),
130     mnFirstPage( 1 ),
131     mnFitToWidth( 1 ),
132     mnFitToHeight( 1 ),
133     mnHorPrintRes( 600 ),
134     mnVerPrintRes( 600 ),
135     mnOrientation( XML_default ),
136     mnPageOrder( XML_downThenOver ),
137     mnCellComments( XML_none ),
138     mnPrintErrors( XML_displayed ),
139     mbUseEvenHF( false ),
140     mbUseFirstHF( false ),
141     mbValidSettings( true ),
142     mbUseFirstPage( false ),
143     mbBlackWhite( false ),
144     mbDraftQuality( false ),
145     mbFitToPages( false ),
146     mbHorCenter( false ),
147     mbVerCenter( false ),
148     mbPrintGrid( false ),
149     mbPrintHeadings( false )
150 {
151 }
152 
153 void PageSettingsModel::setBiffPrintErrors( sal_uInt8 nPrintErrors )
154 {
155     static const sal_Int32 spnErrorIds[] = { XML_displayed, XML_none, XML_dash, XML_NA };
156     mnPrintErrors = STATIC_ARRAY_SELECT( spnErrorIds, nPrintErrors, XML_none );
157 }
158 
159 // ============================================================================
160 
161 PageSettings::PageSettings( const WorksheetHelper& rHelper ) :
162     WorksheetHelper( rHelper )
163 {
164 }
165 
166 void PageSettings::importPrintOptions( const AttributeList& rAttribs )
167 {
168     maModel.mbHorCenter     = rAttribs.getBool( XML_horizontalCentered, false );
169     maModel.mbVerCenter     = rAttribs.getBool( XML_verticalCentered, false );
170     maModel.mbPrintGrid     = rAttribs.getBool( XML_gridLines, false );
171     maModel.mbPrintHeadings = rAttribs.getBool( XML_headings, false );
172 }
173 
174 void PageSettings::importPageMargins( const AttributeList& rAttribs )
175 {
176     maModel.mfLeftMargin   = rAttribs.getDouble( XML_left,   OOX_MARGIN_DEFAULT_LR );
177     maModel.mfRightMargin  = rAttribs.getDouble( XML_right,  OOX_MARGIN_DEFAULT_LR );
178     maModel.mfTopMargin    = rAttribs.getDouble( XML_top,    OOX_MARGIN_DEFAULT_TB );
179     maModel.mfBottomMargin = rAttribs.getDouble( XML_bottom, OOX_MARGIN_DEFAULT_TB );
180     maModel.mfHeaderMargin = rAttribs.getDouble( XML_header, OOX_MARGIN_DEFAULT_HF );
181     maModel.mfFooterMargin = rAttribs.getDouble( XML_footer, OOX_MARGIN_DEFAULT_HF );
182 }
183 
184 void PageSettings::importPageSetup( const Relations& rRelations, const AttributeList& rAttribs )
185 {
186     maModel.maBinSettPath   = rRelations.getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) );
187     maModel.mnPaperSize     = rAttribs.getInteger( XML_paperSize, 1 );
188     maModel.mnCopies        = rAttribs.getInteger( XML_copies, 1 );
189     maModel.mnScale         = rAttribs.getInteger( XML_scale, 100 );
190     maModel.mnFirstPage     = rAttribs.getInteger( XML_firstPageNumber, 1 );
191     maModel.mnFitToWidth    = rAttribs.getInteger( XML_fitToWidth, 1 );
192     maModel.mnFitToHeight   = rAttribs.getInteger( XML_fitToHeight, 1 );
193     maModel.mnHorPrintRes   = rAttribs.getInteger( XML_horizontalDpi, 600 );
194     maModel.mnVerPrintRes   = rAttribs.getInteger( XML_verticalDpi, 600 );
195     maModel.mnOrientation   = rAttribs.getToken( XML_orientation, XML_default );
196     maModel.mnPageOrder     = rAttribs.getToken( XML_pageOrder, XML_downThenOver );
197     maModel.mnCellComments  = rAttribs.getToken( XML_cellComments, XML_none );
198     maModel.mnPrintErrors   = rAttribs.getToken( XML_errors, XML_displayed );
199     maModel.mbValidSettings = rAttribs.getBool( XML_usePrinterDefaults, true );
200     maModel.mbUseFirstPage  = rAttribs.getBool( XML_useFirstPageNumber, false );
201     maModel.mbBlackWhite    = rAttribs.getBool( XML_blackAndWhite, false );
202     maModel.mbDraftQuality  = rAttribs.getBool( XML_draft, false );
203 }
204 
205 void PageSettings::importChartPageSetup( const Relations& rRelations, const AttributeList& rAttribs )
206 {
207     maModel.maBinSettPath   = rRelations.getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) );
208     maModel.mnPaperSize     = rAttribs.getInteger( XML_paperSize, 1 );
209     maModel.mnCopies        = rAttribs.getInteger( XML_copies, 1 );
210     maModel.mnFirstPage     = rAttribs.getInteger( XML_firstPageNumber, 1 );
211     maModel.mnHorPrintRes   = rAttribs.getInteger( XML_horizontalDpi, 600 );
212     maModel.mnVerPrintRes   = rAttribs.getInteger( XML_verticalDpi, 600 );
213     maModel.mnOrientation   = rAttribs.getToken( XML_orientation, XML_default );
214     maModel.mbValidSettings = rAttribs.getBool( XML_usePrinterDefaults, true );
215     maModel.mbUseFirstPage  = rAttribs.getBool( XML_useFirstPageNumber, false );
216     maModel.mbBlackWhite    = rAttribs.getBool( XML_blackAndWhite, false );
217     maModel.mbDraftQuality  = rAttribs.getBool( XML_draft, false );
218 }
219 
220 void PageSettings::importHeaderFooter( const AttributeList& rAttribs )
221 {
222     maModel.mbUseEvenHF  = rAttribs.getBool( XML_differentOddEven, false );
223     maModel.mbUseFirstHF = rAttribs.getBool( XML_differentFirst, false );
224 }
225 
226 void PageSettings::importHeaderFooterCharacters( const OUString& rChars, sal_Int32 nElement )
227 {
228     switch( nElement )
229     {
230         case XLS_TOKEN( oddHeader ):    maModel.maOddHeader += rChars;      break;
231         case XLS_TOKEN( oddFooter ):    maModel.maOddFooter += rChars;      break;
232         case XLS_TOKEN( evenHeader ):   maModel.maEvenHeader += rChars;     break;
233         case XLS_TOKEN( evenFooter ):   maModel.maEvenFooter += rChars;     break;
234         case XLS_TOKEN( firstHeader ):  maModel.maFirstHeader += rChars;    break;
235         case XLS_TOKEN( firstFooter ):  maModel.maFirstFooter += rChars;    break;
236     }
237 }
238 
239 void PageSettings::importPicture( const Relations& rRelations, const AttributeList& rAttribs )
240 {
241     importPictureData( rRelations, rAttribs.getString( R_TOKEN( id ), OUString() ) );
242 }
243 
244 void PageSettings::importPageMargins( SequenceInputStream& rStrm )
245 {
246     rStrm   >> maModel.mfLeftMargin   >> maModel.mfRightMargin
247             >> maModel.mfTopMargin    >> maModel.mfBottomMargin
248             >> maModel.mfHeaderMargin >> maModel.mfFooterMargin;
249 }
250 
251 void PageSettings::importPrintOptions( SequenceInputStream& rStrm )
252 {
253     sal_uInt16 nFlags;
254     rStrm >> nFlags;
255     maModel.mbHorCenter     = getFlag( nFlags, BIFF12_PRINTOPT_HORCENTER );
256     maModel.mbVerCenter     = getFlag( nFlags, BIFF12_PRINTOPT_VERCENTER );
257     maModel.mbPrintGrid     = getFlag( nFlags, BIFF12_PRINTOPT_PRINTGRID );
258     maModel.mbPrintHeadings = getFlag( nFlags, BIFF12_PRINTOPT_PRINTHEADING );
259 }
260 
261 void PageSettings::importPageSetup( const Relations& rRelations, SequenceInputStream& rStrm )
262 {
263     OUString aRelId;
264     sal_uInt16 nFlags;
265     rStrm   >> maModel.mnPaperSize >> maModel.mnScale
266             >> maModel.mnHorPrintRes >> maModel.mnVerPrintRes
267             >> maModel.mnCopies >> maModel.mnFirstPage
268             >> maModel.mnFitToWidth >> maModel.mnFitToHeight
269             >> nFlags >> aRelId;
270     maModel.setBiffPrintErrors( extractValue< sal_uInt8 >( nFlags, 9, 2 ) );
271     maModel.maBinSettPath   = rRelations.getFragmentPathFromRelId( aRelId );
272     maModel.mnOrientation   = getFlagValue( nFlags, BIFF12_PAGESETUP_DEFAULTORIENT, XML_default, getFlagValue( nFlags, BIFF12_PAGESETUP_LANDSCAPE, XML_landscape, XML_portrait ) );
273     maModel.mnPageOrder     = getFlagValue( nFlags, BIFF12_PAGESETUP_INROWS, XML_overThenDown, XML_downThenOver );
274     maModel.mnCellComments  = getFlagValue( nFlags, BIFF12_PAGESETUP_PRINTNOTES, getFlagValue( nFlags, BIFF12_PAGESETUP_NOTES_END, XML_atEnd, XML_asDisplayed ), XML_none );
275     maModel.mbValidSettings = !getFlag( nFlags, BIFF12_PAGESETUP_INVALID );
276     maModel.mbUseFirstPage  = getFlag( nFlags, BIFF12_PAGESETUP_USEFIRSTPAGE );
277     maModel.mbBlackWhite    = getFlag( nFlags, BIFF12_PAGESETUP_BLACKWHITE );
278     maModel.mbDraftQuality  = getFlag( nFlags, BIFF12_PAGESETUP_DRAFTQUALITY );
279 }
280 
281 void PageSettings::importChartPageSetup( const Relations& rRelations, SequenceInputStream& rStrm )
282 {
283     OUString aRelId;
284     sal_uInt16 nFirstPage, nFlags;
285     rStrm   >> maModel.mnPaperSize >> maModel.mnHorPrintRes >> maModel.mnVerPrintRes
286             >> maModel.mnCopies >> nFirstPage >> nFlags >> aRelId;
287     maModel.maBinSettPath   = rRelations.getFragmentPathFromRelId( aRelId );
288     maModel.mnFirstPage     = nFirstPage; // 16-bit in CHARTPAGESETUP
289     maModel.mnOrientation   = getFlagValue( nFlags, BIFF12_CHARTPAGESETUP_DEFAULTORIENT, XML_default, getFlagValue( nFlags, BIFF12_CHARTPAGESETUP_LANDSCAPE, XML_landscape, XML_portrait ) );
290     maModel.mbValidSettings = !getFlag( nFlags, BIFF12_CHARTPAGESETUP_INVALID );
291     maModel.mbUseFirstPage  = getFlag( nFlags, BIFF12_CHARTPAGESETUP_USEFIRSTPAGE );
292     maModel.mbBlackWhite    = getFlag( nFlags, BIFF12_CHARTPAGESETUP_BLACKWHITE );
293     maModel.mbDraftQuality  = getFlag( nFlags, BIFF12_CHARTPAGESETUP_DRAFTQUALITY );
294 }
295 
296 void PageSettings::importHeaderFooter( SequenceInputStream& rStrm )
297 {
298     sal_uInt16 nFlags;
299     rStrm   >> nFlags
300             >> maModel.maOddHeader   >> maModel.maOddFooter
301             >> maModel.maEvenHeader  >> maModel.maEvenFooter
302             >> maModel.maFirstHeader >> maModel.maFirstFooter;
303     maModel.mbUseEvenHF  = getFlag( nFlags, BIFF12_HEADERFOOTER_DIFFEVEN );
304     maModel.mbUseFirstHF = getFlag( nFlags, BIFF12_HEADERFOOTER_DIFFFIRST );
305 }
306 
307 void PageSettings::importPicture( const Relations& rRelations, SequenceInputStream& rStrm )
308 {
309     importPictureData( rRelations, BiffHelper::readString( rStrm ) );
310 }
311 
312 void PageSettings::importLeftMargin( BiffInputStream& rStrm )
313 {
314     rStrm >> maModel.mfLeftMargin;
315 }
316 
317 void PageSettings::importRightMargin( BiffInputStream& rStrm )
318 {
319     rStrm >> maModel.mfRightMargin;
320 }
321 
322 void PageSettings::importTopMargin( BiffInputStream& rStrm )
323 {
324     rStrm >> maModel.mfTopMargin;
325 }
326 
327 void PageSettings::importBottomMargin( BiffInputStream& rStrm )
328 {
329     rStrm >> maModel.mfBottomMargin;
330 }
331 
332 void PageSettings::importPageSetup( BiffInputStream& rStrm )
333 {
334     sal_uInt16 nPaperSize, nScale, nFirstPage, nFitToWidth, nFitToHeight, nFlags;
335     rStrm >> nPaperSize >> nScale >> nFirstPage >> nFitToWidth >> nFitToHeight >> nFlags;
336 
337     maModel.mnPaperSize      = nPaperSize;   // equal in BIFF and OOX
338     maModel.mnScale          = nScale;
339     maModel.mnFirstPage      = nFirstPage;
340     maModel.mnFitToWidth     = nFitToWidth;
341     maModel.mnFitToHeight    = nFitToHeight;
342     maModel.mnOrientation    = getFlagValue( nFlags, BIFF_PAGESETUP_PORTRAIT, XML_portrait, XML_landscape );
343     maModel.mnPageOrder      = getFlagValue( nFlags, BIFF_PAGESETUP_INROWS, XML_overThenDown, XML_downThenOver );
344     maModel.mbValidSettings  = !getFlag( nFlags, BIFF_PAGESETUP_INVALID );
345     maModel.mbUseFirstPage   = true;
346     maModel.mbBlackWhite     = getFlag( nFlags, BIFF_PAGESETUP_BLACKWHITE );
347 
348     if( getBiff() >= BIFF5 )
349     {
350         sal_uInt16 nHorPrintRes, nVerPrintRes, nCopies;
351         rStrm >> nHorPrintRes >> nVerPrintRes >> maModel.mfHeaderMargin >> maModel.mfFooterMargin >> nCopies;
352 
353         maModel.mnCopies       = nCopies;
354         maModel.mnOrientation  = getFlagValue( nFlags, BIFF_PAGESETUP_DEFAULTORIENT, XML_default, maModel.mnOrientation );
355         maModel.mnHorPrintRes  = nHorPrintRes;
356         maModel.mnVerPrintRes  = nVerPrintRes;
357         maModel.mnCellComments = getFlagValue( nFlags, BIFF_PAGESETUP_PRINTNOTES, XML_asDisplayed, XML_none );
358         maModel.mbUseFirstPage = getFlag( nFlags, BIFF_PAGESETUP_USEFIRSTPAGE );
359         maModel.mbDraftQuality = getFlag( nFlags, BIFF_PAGESETUP_DRAFTQUALITY );
360 
361         if( getBiff() == BIFF8 )
362         {
363             maModel.setBiffPrintErrors( extractValue< sal_uInt8 >( nFlags, 10, 2 ) );
364             maModel.mnCellComments = getFlagValue( nFlags, BIFF_PAGESETUP_PRINTNOTES, getFlagValue( nFlags, BIFF_PAGESETUP_NOTES_END, XML_atEnd, XML_asDisplayed ), XML_none );
365         }
366     }
367 }
368 
369 void PageSettings::importHorCenter( BiffInputStream& rStrm )
370 {
371     maModel.mbHorCenter = rStrm.readuInt16() != 0;
372 }
373 
374 void PageSettings::importVerCenter( BiffInputStream& rStrm )
375 {
376     maModel.mbVerCenter = rStrm.readuInt16() != 0;
377 }
378 
379 void PageSettings::importPrintHeaders( BiffInputStream& rStrm )
380 {
381     maModel.mbPrintHeadings = rStrm.readuInt16() != 0;
382 }
383 
384 void PageSettings::importPrintGridLines( BiffInputStream& rStrm )
385 {
386     maModel.mbPrintGrid = rStrm.readuInt16() != 0;
387 }
388 
389 void PageSettings::importHeader( BiffInputStream& rStrm )
390 {
391     if( rStrm.getRemaining() > 0 )
392         maModel.maOddHeader = (getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( false, getTextEncoding() );
393     else
394         maModel.maOddHeader = OUString();
395 }
396 
397 void PageSettings::importFooter( BiffInputStream& rStrm )
398 {
399     if( rStrm.getRemaining() > 0 )
400         maModel.maOddFooter = (getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( false, getTextEncoding() );
401     else
402         maModel.maOddFooter = OUString();
403 }
404 
405 void PageSettings::importPicture( BiffInputStream& rStrm )
406 {
407     StreamDataSequence aPictureData;
408     BiffHelper::importImgData( aPictureData, rStrm, getBiff() );
409     maModel.maGraphicUrl = getBaseFilter().getGraphicHelper().importGraphicObject( aPictureData );
410 }
411 
412 void PageSettings::setFitToPagesMode( bool bFitToPages )
413 {
414     maModel.mbFitToPages = bFitToPages;
415 }
416 
417 void PageSettings::finalizeImport()
418 {
419     OUStringBuffer aStyleNameBuffer( CREATE_OUSTRING( "PageStyle_" ) );
420     Reference< XNamed > xSheetName( getSheet(), UNO_QUERY );
421     if( xSheetName.is() )
422         aStyleNameBuffer.append( xSheetName->getName() );
423     else
424         aStyleNameBuffer.append( static_cast< sal_Int32 >( getSheetIndex() + 1 ) );
425     OUString aStyleName = aStyleNameBuffer.makeStringAndClear();
426 
427     Reference< XStyle > xStyle = createStyleObject( aStyleName, true );
428     PropertySet aStyleProps( xStyle );
429     getPageSettingsConverter().writePageSettingsProperties( aStyleProps, maModel, getSheetType() );
430 
431     PropertySet aSheetProps( getSheet() );
432     aSheetProps.setProperty( PROP_PageStyle, aStyleName );
433 }
434 
435 void PageSettings::importPictureData( const Relations& rRelations, const OUString& rRelId )
436 {
437     OUString aPicturePath = rRelations.getFragmentPathFromRelId( rRelId );
438     if( aPicturePath.getLength() > 0 )
439         maModel.maGraphicUrl = getBaseFilter().getGraphicHelper().importEmbeddedGraphicObject( aPicturePath );
440 }
441 
442 // ============================================================================
443 // ============================================================================
444 
445 enum HFPortionId
446 {
447     HF_LEFT,
448     HF_CENTER,
449     HF_RIGHT,
450     HF_COUNT
451 };
452 
453 // ----------------------------------------------------------------------------
454 
455 struct HFPortionInfo
456 {
457     Reference< XText >  mxText;                 /// XText interface of this portion.
458     Reference< XTextCursor > mxStart;           /// Start position of current text range for formatting.
459     Reference< XTextCursor > mxEnd;             /// End position of current text range for formatting.
460     double              mfTotalHeight;          /// Sum of heights of previous lines in points.
461     double              mfCurrHeight;           /// Height of the current text line in points.
462 
463     bool                initialize( const Reference< XText >& rxText );
464 };
465 
466 bool HFPortionInfo::initialize( const Reference< XText >& rxText )
467 {
468     mfTotalHeight = mfCurrHeight = 0.0;
469     mxText = rxText;
470     if( mxText.is() )
471     {
472         mxStart = mxText->createTextCursor();
473         mxEnd = mxText->createTextCursor();
474     }
475     bool bRet = mxText.is() && mxStart.is() && mxEnd.is();
476     OSL_ENSURE( bRet, "HFPortionInfo::initialize - missing interfaces" );
477     return bRet;
478 }
479 
480 // ============================================================================
481 
482 class HeaderFooterParser : public WorkbookHelper
483 {
484 public:
485     explicit            HeaderFooterParser( const WorkbookHelper& rHelper );
486 
487     /** Parses the passed string and creates the header/footer contents.
488         @returns  The total height of the converted header or footer in points. */
489     double              parse(
490                             const Reference< XHeaderFooterContent >& rxContext,
491                             const OUString& rData );
492 
493 private:
494     /** Returns the current edit engine text object. */
495     inline HFPortionInfo& getPortion() { return maPortions[ meCurrPortion ]; }
496     /** Returns the start cursor of the current text range. */
497     inline const Reference< XTextCursor >& getStartPos() { return getPortion().mxStart; }
498     /** Returns the end cursor of the current text range. */
499     inline const Reference< XTextCursor >& getEndPos() { return getPortion().mxEnd; }
500 
501     /** Returns the current line height of the specified portion. */
502     double              getCurrHeight( HFPortionId ePortion ) const;
503     /** Returns the current line height. */
504     double              getCurrHeight() const;
505 
506     /** Updates the current line height of the specified portion, using the current font size. */
507     void                updateCurrHeight( HFPortionId ePortion );
508     /** Updates the current line height, using the current font size. */
509     void                updateCurrHeight();
510 
511     /** Sets the font attributes at the current selection. */
512     void                setAttributes();
513     /** Appends and clears internal string buffer. */
514     void                appendText();
515     /** Appends a line break and adjusts internal text height data. */
516     void                appendLineBreak();
517 
518     /** Creates a text field from the passed service name. */
519     Reference< XTextContent > createField( const OUString& rServiceName ) const;
520     /** Appends the passed text field. */
521     void                appendField( const Reference< XTextContent >& rxContent );
522 
523     /** Sets the passed font name if it is valid. */
524     void                convertFontName( const OUString& rStyle );
525     /** Converts a font style given as string. */
526     void                convertFontStyle( const OUString& rStyle );
527     /** Converts a font color given as string. */
528     void                convertFontColor( const OUString& rColor );
529 
530     /** Finalizes current portion: sets font attributes and updates text height data. */
531     void                finalizePortion();
532     /** Changes current header/footer portion. */
533     void                setNewPortion( HFPortionId ePortion );
534 
535 private:
536     typedef ::std::vector< HFPortionInfo >  HFPortionInfoVec;
537     typedef ::std::set< OString >           OStringSet;
538 
539     const OUString      maPageNumberService;
540     const OUString      maPageCountService;
541     const OUString      maSheetNameService;
542     const OUString      maFileNameService;
543     const OUString      maDateTimeService;
544     const OStringSet    maBoldNames;            /// All names for bold font style in lowercase UTF-8.
545     const OStringSet    maItalicNames;          /// All names for italic font style in lowercase UTF-8.
546     HFPortionInfoVec    maPortions;
547     HFPortionId         meCurrPortion;          /// Identifier of current H/F portion.
548     OUStringBuffer      maBuffer;               /// Text data to append to current text range.
549     FontModel           maFontModel;            /// Font attributes of current text range.
550 };
551 
552 // ----------------------------------------------------------------------------
553 
554 namespace {
555 
556 // different names for bold font style (lowercase)
557 static const sal_Char* const sppcBoldNames[] =
558 {
559     "bold",
560     "fett",             // German 'bold'
561     "demibold",
562     "halbfett",         // German 'demibold'
563     "black",
564     "heavy"
565 };
566 
567 // different names for italic font style (lowercase)
568 static const sal_Char* const sppcItalicNames[] =
569 {
570     "italic",
571     "kursiv",           // German 'italic'
572     "oblique",
573     "schr\303\204g",    // German 'oblique' with uppercase A umlaut
574     "schr\303\244g"     // German 'oblique' with lowercase A umlaut
575 };
576 
577 } // namespace
578 
579 // ----------------------------------------------------------------------------
580 
581 HeaderFooterParser::HeaderFooterParser( const WorkbookHelper& rHelper ) :
582     WorkbookHelper( rHelper ),
583     maPageNumberService( CREATE_OUSTRING( "com.sun.star.text.TextField.PageNumber" ) ),
584     maPageCountService( CREATE_OUSTRING( "com.sun.star.text.TextField.PageCount" ) ),
585     maSheetNameService( CREATE_OUSTRING( "com.sun.star.text.TextField.SheetName" ) ),
586     maFileNameService( CREATE_OUSTRING( "com.sun.star.text.TextField.FileName" ) ),
587     maDateTimeService( CREATE_OUSTRING( "com.sun.star.text.TextField.DateTime" ) ),
588     maBoldNames( sppcBoldNames, STATIC_ARRAY_END( sppcBoldNames ) ),
589     maItalicNames( sppcItalicNames, STATIC_ARRAY_END( sppcItalicNames ) ),
590     maPortions( static_cast< size_t >( HF_COUNT ) ),
591     meCurrPortion( HF_CENTER )
592 {
593 }
594 
595 double HeaderFooterParser::parse( const Reference< XHeaderFooterContent >& rxContext, const OUString& rData )
596 {
597     if( !rxContext.is() || (rData.getLength() == 0) ||
598             !maPortions[ HF_LEFT ].initialize( rxContext->getLeftText() ) ||
599             !maPortions[ HF_CENTER ].initialize( rxContext->getCenterText() ) ||
600             !maPortions[ HF_RIGHT ].initialize( rxContext->getRightText() ) )
601         return 0.0;
602 
603     meCurrPortion = HF_CENTER;
604     maBuffer.setLength( 0 );
605     maFontModel = getStyles().getDefaultFontModel();
606     OUStringBuffer aFontName;           // current font name
607     OUStringBuffer aFontStyle;          // current font style
608     sal_Int32 nFontHeight = 0;          // current font height
609 
610     /** State of the parser. */
611     enum
612     {
613         STATE_TEXT,         /// Literal text data.
614         STATE_TOKEN,        /// Control token following a '&' character.
615         STATE_FONTNAME,     /// Font name ('&' is followed by '"', reads until next '"' or ',').
616         STATE_FONTSTYLE,    /// Font style name (font part after ',', reads until next '"').
617         STATE_FONTHEIGHT    /// Font height ('&' is followed by num. digits, reads until non-digit).
618     }
619     eState = STATE_TEXT;
620 
621     const sal_Unicode* pcChar = rData.getStr();
622     const sal_Unicode* pcEnd = pcChar + rData.getLength();
623     for( ; (pcChar != pcEnd) && (*pcChar != 0); ++pcChar )
624     {
625         sal_Unicode cChar = *pcChar;
626         switch( eState )
627         {
628             case STATE_TEXT:
629             {
630                 switch( cChar )
631                 {
632                     case '&':           // new token
633                         appendText();
634                         eState = STATE_TOKEN;
635                     break;
636                     case '\n':          // line break
637                         appendText();
638                         appendLineBreak();
639                     break;
640                     default:
641                         maBuffer.append( cChar );
642                 }
643             }
644             break;
645 
646             case STATE_TOKEN:
647             {
648                 // default: back to text mode, may be changed in specific cases
649                 eState = STATE_TEXT;
650                 // ignore case of token codes
651                 if( ('a' <= cChar) && (cChar <= 'z') )
652                     (cChar -= 'a') += 'A';
653                 switch( cChar )
654                 {
655                     case '&':   maBuffer.append( cChar );   break;  // the '&' character
656 
657                     case 'L':   setNewPortion( HF_LEFT );   break;  // left portion
658                     case 'C':   setNewPortion( HF_CENTER ); break;  // center portion
659                     case 'R':   setNewPortion( HF_RIGHT );  break;  // right portion
660 
661                     case 'P':   // page number
662                         appendField( createField( maPageNumberService ) );
663                     break;
664                     case 'N':   // total page count
665                         appendField( createField( maPageCountService ) );
666                     break;
667                     case 'A':   // current sheet name
668                         appendField( createField( maSheetNameService ) );
669                     break;
670 
671                     case 'F':   // file name
672                     {
673                         Reference< XTextContent > xContent = createField( maFileNameService );
674                         PropertySet aPropSet( xContent );
675                         aPropSet.setProperty( PROP_FileFormat, ::com::sun::star::text::FilenameDisplayFormat::NAME_AND_EXT );
676                         appendField( xContent );
677                     }
678                     break;
679                     case 'Z':   // file path (without file name), OOXML, BIFF12, and BIFF8 only
680                         if( (getFilterType() == FILTER_OOXML) || ((getFilterType() == FILTER_BIFF) && (getBiff() == BIFF8)) )
681                         {
682                             Reference< XTextContent > xContent = createField( maFileNameService );
683                             PropertySet aPropSet( xContent );
684                             // FilenameDisplayFormat::PATH not supported by Calc
685                             aPropSet.setProperty( PROP_FileFormat, ::com::sun::star::text::FilenameDisplayFormat::FULL );
686                             appendField( xContent );
687                             /*  path only is not supported -- if we find a '&Z&F'
688                                 combination for path/name, skip the '&F' part */
689                             if( (pcChar + 2 < pcEnd) && (pcChar[ 1 ] == '&') && ((pcChar[ 2 ] == 'f') || (pcChar[ 2 ] == 'F')) )
690                                 pcChar += 2;
691                         }
692                     break;
693                     case 'D':   // date
694                     {
695                         Reference< XTextContent > xContent = createField( maDateTimeService );
696                         PropertySet aPropSet( xContent );
697                         aPropSet.setProperty( PROP_IsDate, true );
698                         appendField( xContent );
699                     }
700                     break;
701                     case 'T':   // time
702                     {
703                         Reference< XTextContent > xContent = createField( maDateTimeService );
704                         PropertySet aPropSet( xContent );
705                         aPropSet.setProperty( PROP_IsDate, false );
706                         appendField( xContent );
707                     }
708                     break;
709 
710                     case 'B':   // bold
711                         setAttributes();
712                         maFontModel.mbBold = !maFontModel.mbBold;
713                     break;
714                     case 'I':   // italic
715                         setAttributes();
716                         maFontModel.mbItalic = !maFontModel.mbItalic;
717                     break;
718                     case 'U':   // underline
719                         setAttributes();
720                         maFontModel.mnUnderline = (maFontModel.mnUnderline == XML_single) ? XML_none : XML_single;
721                     break;
722                     case 'E':   // double underline
723                         setAttributes();
724                         maFontModel.mnUnderline = (maFontModel.mnUnderline == XML_double) ? XML_none : XML_double;
725                     break;
726                     case 'S':   // strikeout
727                         setAttributes();
728                         maFontModel.mbStrikeout = !maFontModel.mbStrikeout;
729                     break;
730                     case 'X':   // superscript
731                         setAttributes();
732                         maFontModel.mnEscapement = (maFontModel.mnEscapement == XML_superscript) ? XML_baseline : XML_superscript;
733                     break;
734                     case 'Y':   // subsrcipt
735                         setAttributes();
736                         maFontModel.mnEscapement = (maFontModel.mnEscapement == XML_subscript) ? XML_baseline : XML_subscript;
737                     break;
738                     case 'O':   // outlined
739                         setAttributes();
740                         maFontModel.mbOutline = !maFontModel.mbOutline;
741                     break;
742                     case 'H':   // shadow
743                         setAttributes();
744                         maFontModel.mbShadow = !maFontModel.mbShadow;
745                     break;
746 
747                     case 'K':   // text color (not in BIFF)
748                         if( (getFilterType() == FILTER_OOXML) && (pcChar + 6 < pcEnd) )
749                         {
750                             setAttributes();
751                             // eat the following 6 characters
752                             convertFontColor( OUString( pcChar + 1, 6 ) );
753                             pcChar += 6;
754                         }
755                     break;
756 
757                     case '\"':  // font name
758                         aFontName.setLength( 0 );
759                         aFontStyle.setLength( 0 );
760                         eState = STATE_FONTNAME;
761                     break;
762                     default:
763                         if( ('0' <= cChar) && (cChar <= '9') )    // font size
764                         {
765                             nFontHeight = cChar - '0';
766                             eState = STATE_FONTHEIGHT;
767                         }
768                 }
769             }
770             break;
771 
772             case STATE_FONTNAME:
773             {
774                 switch( cChar )
775                 {
776                     case '\"':
777                         setAttributes();
778                         convertFontName( aFontName.makeStringAndClear() );
779                         eState = STATE_TEXT;
780                     break;
781                     case ',':
782                         eState = STATE_FONTSTYLE;
783                     break;
784                     default:
785                         aFontName.append( cChar );
786                 }
787             }
788             break;
789 
790             case STATE_FONTSTYLE:
791             {
792                 switch( cChar )
793                 {
794                     case '\"':
795                         setAttributes();
796                         convertFontName( aFontName.makeStringAndClear() );
797                         convertFontStyle( aFontStyle.makeStringAndClear() );
798                         eState = STATE_TEXT;
799                     break;
800                     default:
801                         aFontStyle.append( cChar );
802                 }
803             }
804             break;
805 
806             case STATE_FONTHEIGHT:
807             {
808                 if( ('0' <= cChar) && (cChar <= '9') )
809                 {
810                     if( nFontHeight >= 0 )
811                     {
812                         nFontHeight *= 10;
813                         nFontHeight += (cChar - '0');
814                         if( nFontHeight > 1000 )
815                             nFontHeight = -1;
816                     }
817                 }
818                 else
819                 {
820                     if( nFontHeight > 0 )
821                     {
822                         setAttributes();
823                         maFontModel.mfHeight = nFontHeight;
824                     }
825                     --pcChar;
826                     eState = STATE_TEXT;
827                 }
828             }
829             break;
830         }
831     }
832 
833     // finalize
834     finalizePortion();
835     maPortions[ HF_LEFT   ].mfTotalHeight += getCurrHeight( HF_LEFT );
836     maPortions[ HF_CENTER ].mfTotalHeight += getCurrHeight( HF_CENTER );
837     maPortions[ HF_RIGHT  ].mfTotalHeight += getCurrHeight( HF_RIGHT );
838 
839     return ::std::max( maPortions[ HF_LEFT ].mfTotalHeight,
840         ::std::max( maPortions[ HF_CENTER ].mfTotalHeight, maPortions[ HF_RIGHT ].mfTotalHeight ) );
841 }
842 
843 // private --------------------------------------------------------------------
844 
845 double HeaderFooterParser::getCurrHeight( HFPortionId ePortion ) const
846 {
847     double fMaxHt = maPortions[ ePortion ].mfCurrHeight;
848     return (fMaxHt == 0.0) ? maFontModel.mfHeight : fMaxHt;
849 }
850 
851 double HeaderFooterParser::getCurrHeight() const
852 {
853     return getCurrHeight( meCurrPortion );
854 }
855 
856 void HeaderFooterParser::updateCurrHeight( HFPortionId ePortion )
857 {
858     double& rfMaxHt = maPortions[ ePortion ].mfCurrHeight;
859     rfMaxHt = ::std::max( rfMaxHt, maFontModel.mfHeight );
860 }
861 
862 void HeaderFooterParser::updateCurrHeight()
863 {
864     updateCurrHeight( meCurrPortion );
865 }
866 
867 void HeaderFooterParser::setAttributes()
868 {
869     Reference< XTextRange > xRange( getStartPos(), UNO_QUERY );
870     getEndPos()->gotoRange( xRange, sal_False );
871     getEndPos()->gotoEnd( sal_True );
872     if( !getEndPos()->isCollapsed() )
873     {
874         Font aFont( *this, maFontModel );
875         aFont.finalizeImport();
876         PropertySet aPropSet( getEndPos() );
877         aFont.writeToPropertySet( aPropSet, FONT_PROPTYPE_TEXT );
878         getStartPos()->gotoEnd( sal_False );
879         getEndPos()->gotoEnd( sal_False );
880     }
881 }
882 
883 void HeaderFooterParser::appendText()
884 {
885     if( maBuffer.getLength() > 0 )
886     {
887         getEndPos()->gotoEnd( sal_False );
888         getEndPos()->setString( maBuffer.makeStringAndClear() );
889         updateCurrHeight();
890     }
891 }
892 
893 void HeaderFooterParser::appendLineBreak()
894 {
895     getEndPos()->gotoEnd( sal_False );
896     getEndPos()->setString( OUString( sal_Unicode( '\n' ) ) );
897     getPortion().mfTotalHeight += getCurrHeight();
898     getPortion().mfCurrHeight = 0;
899 }
900 
901 Reference< XTextContent > HeaderFooterParser::createField( const OUString& rServiceName ) const
902 {
903     Reference< XTextContent > xContent;
904     try
905     {
906         xContent.set( getBaseFilter().getModelFactory()->createInstance( rServiceName ), UNO_QUERY_THROW );
907     }
908     catch( Exception& )
909     {
910         OSL_ENSURE( false,
911             OStringBuffer( "HeaderFooterParser::createField - error while creating text field \"" ).
912             append( OUStringToOString( rServiceName, RTL_TEXTENCODING_ASCII_US ) ).
913             append( '"' ).getStr() );
914     }
915     return xContent;
916 }
917 
918 void HeaderFooterParser::appendField( const Reference< XTextContent >& rxContent )
919 {
920     getEndPos()->gotoEnd( sal_False );
921     try
922     {
923         Reference< XTextRange > xRange( getEndPos(), UNO_QUERY_THROW );
924         getPortion().mxText->insertTextContent( xRange, rxContent, sal_False );
925         updateCurrHeight();
926     }
927     catch( Exception& )
928     {
929     }
930 }
931 
932 void HeaderFooterParser::convertFontName( const OUString& rName )
933 {
934     if( rName.getLength() > 0 )
935     {
936         // single dash is document default font
937         if( (rName.getLength() == 1) && (rName[ 0 ] == '-') )
938             maFontModel.maName = getStyles().getDefaultFontModel().maName;
939         else
940             maFontModel.maName = rName;
941     }
942 }
943 
944 void HeaderFooterParser::convertFontStyle( const OUString& rStyle )
945 {
946     maFontModel.mbBold = maFontModel.mbItalic = false;
947     sal_Int32 nPos = 0;
948     sal_Int32 nLen = rStyle.getLength();
949     while( (0 <= nPos) && (nPos < nLen) )
950     {
951         OString aToken = OUStringToOString( rStyle.getToken( 0, ' ', nPos ), RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase();
952         if( aToken.getLength() > 0 )
953         {
954             if( maBoldNames.count( aToken ) > 0 )
955                 maFontModel.mbBold = true;
956             else if( maItalicNames.count( aToken ) > 0 )
957                 maFontModel.mbItalic = true;
958         }
959     }
960 }
961 
962 void HeaderFooterParser::convertFontColor( const OUString& rColor )
963 {
964     OSL_ENSURE( rColor.getLength() == 6, "HeaderFooterParser::convertFontColor - invalid font color code" );
965     if( (rColor[ 2 ] == '+') || (rColor[ 2 ] == '-') )
966         // theme color: TTSNNN (TT = decimal theme index, S = +/-, NNN = decimal tint/shade in percent)
967         maFontModel.maColor.setTheme(
968             rColor.copy( 0, 2 ).toInt32(),
969             static_cast< double >( rColor.copy( 2 ).toInt32() ) / 100.0 );
970     else
971         // RGB color: RRGGBB
972         maFontModel.maColor.setRgb( rColor.toInt32( 16 ) );
973 }
974 
975 void HeaderFooterParser::finalizePortion()
976 {
977     appendText();
978     setAttributes();
979 }
980 
981 void HeaderFooterParser::setNewPortion( HFPortionId ePortion )
982 {
983     if( ePortion != meCurrPortion )
984     {
985         finalizePortion();
986         meCurrPortion = ePortion;
987         maFontModel = getStyles().getDefaultFontModel();
988     }
989 }
990 
991 // ============================================================================
992 
993 namespace {
994 
995 /** Paper size in 1/100 millimeters. */
996 struct ApiPaperSize
997 {
998     sal_Int32           mnWidth;
999     sal_Int32           mnHeight;
1000 };
1001 
1002 #define IN2MM100( v )    static_cast< sal_Int32 >( (v) * 2540.0 + 0.5 )
1003 #define MM2MM100( v )    static_cast< sal_Int32 >( (v) * 100.0 + 0.5 )
1004 
1005 static const ApiPaperSize spPaperSizeTable[] =
1006 {
1007     { 0, 0 },                                                //  0 - (undefined)
1008     { IN2MM100( 8.5 ),       IN2MM100( 11 )      },          //  1 - Letter paper
1009     { IN2MM100( 8.5 ),       IN2MM100( 11 )      },          //  2 - Letter small paper
1010     { IN2MM100( 11 ),        IN2MM100( 17 )      },          //  3 - Tabloid paper
1011     { IN2MM100( 17 ),        IN2MM100( 11 )      },          //  4 - Ledger paper
1012     { IN2MM100( 8.5 ),       IN2MM100( 14 )      },          //  5 - Legal paper
1013     { IN2MM100( 5.5 ),       IN2MM100( 8.5 )     },          //  6 - Statement paper
1014     { IN2MM100( 7.25 ),      IN2MM100( 10.5 )    },          //  7 - Executive paper
1015     { MM2MM100( 297 ),       MM2MM100( 420 )     },          //  8 - A3 paper
1016     { MM2MM100( 210 ),       MM2MM100( 297 )     },          //  9 - A4 paper
1017     { MM2MM100( 210 ),       MM2MM100( 297 )     },          // 10 - A4 small paper
1018     { MM2MM100( 148 ),       MM2MM100( 210 )     },          // 11 - A5 paper
1019     { MM2MM100( 250 ),       MM2MM100( 353 )     },          // 12 - B4 paper
1020     { MM2MM100( 176 ),       MM2MM100( 250 )     },          // 13 - B5 paper
1021     { IN2MM100( 8.5 ),       IN2MM100( 13 )      },          // 14 - Folio paper
1022     { MM2MM100( 215 ),       MM2MM100( 275 )     },          // 15 - Quarto paper
1023     { IN2MM100( 10 ),        IN2MM100( 14 )      },          // 16 - Standard paper
1024     { IN2MM100( 11 ),        IN2MM100( 17 )      },          // 17 - Standard paper
1025     { IN2MM100( 8.5 ),       IN2MM100( 11 )      },          // 18 - Note paper
1026     { IN2MM100( 3.875 ),     IN2MM100( 8.875 )   },          // 19 - #9 envelope
1027     { IN2MM100( 4.125 ),     IN2MM100( 9.5 )     },          // 20 - #10 envelope
1028     { IN2MM100( 4.5 ),       IN2MM100( 10.375 )  },          // 21 - #11 envelope
1029     { IN2MM100( 4.75 ),      IN2MM100( 11 )      },          // 22 - #12 envelope
1030     { IN2MM100( 5 ),         IN2MM100( 11.5 )    },          // 23 - #14 envelope
1031     { IN2MM100( 17 ),        IN2MM100( 22 )      },          // 24 - C paper
1032     { IN2MM100( 22 ),        IN2MM100( 34 )      },          // 25 - D paper
1033     { IN2MM100( 34 ),        IN2MM100( 44 )      },          // 26 - E paper
1034     { MM2MM100( 110 ),       MM2MM100( 220 )     },          // 27 - DL envelope
1035     { MM2MM100( 162 ),       MM2MM100( 229 )     },          // 28 - C5 envelope
1036     { MM2MM100( 324 ),       MM2MM100( 458 )     },          // 29 - C3 envelope
1037     { MM2MM100( 229 ),       MM2MM100( 324 )     },          // 30 - C4 envelope
1038     { MM2MM100( 114 ),       MM2MM100( 162 )     },          // 31 - C6 envelope
1039     { MM2MM100( 114 ),       MM2MM100( 229 )     },          // 32 - C65 envelope
1040     { MM2MM100( 250 ),       MM2MM100( 353 )     },          // 33 - B4 envelope
1041     { MM2MM100( 176 ),       MM2MM100( 250 )     },          // 34 - B5 envelope
1042     { MM2MM100( 176 ),       MM2MM100( 125 )     },          // 35 - B6 envelope
1043     { MM2MM100( 110 ),       MM2MM100( 230 )     },          // 36 - Italy envelope
1044     { IN2MM100( 3.875 ),     IN2MM100( 7.5 )     },          // 37 - Monarch envelope
1045     { IN2MM100( 3.625 ),     IN2MM100( 6.5 )     },          // 38 - 6 3/4 envelope
1046     { IN2MM100( 14.875 ),    IN2MM100( 11 )      },          // 39 - US standard fanfold
1047     { IN2MM100( 8.5 ),       IN2MM100( 12 )      },          // 40 - German standard fanfold
1048     { IN2MM100( 8.5 ),       IN2MM100( 13 )      },          // 41 - German legal fanfold
1049     { MM2MM100( 250 ),       MM2MM100( 353 )     },          // 42 - ISO B4
1050     { MM2MM100( 200 ),       MM2MM100( 148 )     },          // 43 - Japanese double postcard
1051     { IN2MM100( 9 ),         IN2MM100( 11 )      },          // 44 - Standard paper
1052     { IN2MM100( 10 ),        IN2MM100( 11 )      },          // 45 - Standard paper
1053     { IN2MM100( 15 ),        IN2MM100( 11 )      },          // 46 - Standard paper
1054     { MM2MM100( 220 ),       MM2MM100( 220 )     },          // 47 - Invite envelope
1055     { 0, 0 },                                                // 48 - (undefined)
1056     { 0, 0 },                                                // 49 - (undefined)
1057     { IN2MM100( 9.275 ),     IN2MM100( 12 )      },          // 50 - Letter extra paper
1058     { IN2MM100( 9.275 ),     IN2MM100( 15 )      },          // 51 - Legal extra paper
1059     { IN2MM100( 11.69 ),     IN2MM100( 18 )      },          // 52 - Tabloid extra paper
1060     { MM2MM100( 236 ),       MM2MM100( 322 )     },          // 53 - A4 extra paper
1061     { IN2MM100( 8.275 ),     IN2MM100( 11 )      },          // 54 - Letter transverse paper
1062     { MM2MM100( 210 ),       MM2MM100( 297 )     },          // 55 - A4 transverse paper
1063     { IN2MM100( 9.275 ),     IN2MM100( 12 )      },          // 56 - Letter extra transverse paper
1064     { MM2MM100( 227 ),       MM2MM100( 356 )     },          // 57 - SuperA/SuperA/A4 paper
1065     { MM2MM100( 305 ),       MM2MM100( 487 )     },          // 58 - SuperB/SuperB/A3 paper
1066     { IN2MM100( 8.5 ),       IN2MM100( 12.69 )   },          // 59 - Letter plus paper
1067     { MM2MM100( 210 ),       MM2MM100( 330 )     },          // 60 - A4 plus paper
1068     { MM2MM100( 148 ),       MM2MM100( 210 )     },          // 61 - A5 transverse paper
1069     { MM2MM100( 182 ),       MM2MM100( 257 )     },          // 62 - JIS B5 transverse paper
1070     { MM2MM100( 322 ),       MM2MM100( 445 )     },          // 63 - A3 extra paper
1071     { MM2MM100( 174 ),       MM2MM100( 235 )     },          // 64 - A5 extra paper
1072     { MM2MM100( 201 ),       MM2MM100( 276 )     },          // 65 - ISO B5 extra paper
1073     { MM2MM100( 420 ),       MM2MM100( 594 )     },          // 66 - A2 paper
1074     { MM2MM100( 297 ),       MM2MM100( 420 )     },          // 67 - A3 transverse paper
1075     { MM2MM100( 322 ),       MM2MM100( 445 )     }           // 68 - A3 extra transverse paper
1076 };
1077 
1078 } // namespace
1079 
1080 // ----------------------------------------------------------------------------
1081 
1082 PageSettingsConverter::HFHelperData::HFHelperData( sal_Int32 nLeftPropId, sal_Int32 nRightPropId ) :
1083     mnLeftPropId( nLeftPropId ),
1084     mnRightPropId( nRightPropId ),
1085     mnHeight( 0 ),
1086     mnBodyDist( 0 ),
1087     mbHasContent( false ),
1088     mbShareOddEven( false ),
1089     mbDynamicHeight( false )
1090 {
1091 }
1092 
1093 // ----------------------------------------------------------------------------
1094 
1095 PageSettingsConverter::PageSettingsConverter( const WorkbookHelper& rHelper ) :
1096     WorkbookHelper( rHelper ),
1097     mxHFParser( new HeaderFooterParser( rHelper ) ),
1098     maHeaderData( PROP_LeftPageHeaderContent, PROP_RightPageHeaderContent ),
1099     maFooterData( PROP_LeftPageFooterContent, PROP_RightPageFooterContent )
1100 {
1101 }
1102 
1103 PageSettingsConverter::~PageSettingsConverter()
1104 {
1105 }
1106 
1107 void PageSettingsConverter::writePageSettingsProperties(
1108         PropertySet& rPropSet, const PageSettingsModel& rModel, WorksheetType eSheetType )
1109 {
1110     // special handling for chart sheets
1111     bool bChartSheet = eSheetType == SHEETTYPE_CHARTSHEET;
1112 
1113     // printout scaling
1114     if( bChartSheet )
1115     {
1116         // always fit chart sheet to 1 page
1117         rPropSet.setProperty< sal_Int16 >( PROP_ScaleToPages, 1 );
1118     }
1119     else if( rModel.mbFitToPages )
1120     {
1121         // fit to number of pages
1122         rPropSet.setProperty( PROP_ScaleToPagesX, getLimitedValue< sal_Int16, sal_Int32 >( rModel.mnFitToWidth, 0, 1000 ) );
1123         rPropSet.setProperty( PROP_ScaleToPagesY, getLimitedValue< sal_Int16, sal_Int32 >( rModel.mnFitToHeight, 0, 1000 ) );
1124     }
1125     else
1126     {
1127         // scale may be 0 which indicates uninitialized
1128         sal_Int16 nScale = (rModel.mbValidSettings && (rModel.mnScale > 0)) ? getLimitedValue< sal_Int16, sal_Int32 >( rModel.mnScale, 10, 400 ) : 100;
1129         rPropSet.setProperty( PROP_PageScale, nScale );
1130     }
1131 
1132     // paper orientation
1133     bool bLandscape = rModel.mnOrientation == XML_landscape;
1134     // default orientation for current sheet type (chart sheets default to landscape)
1135     if( !rModel.mbValidSettings || (rModel.mnOrientation == XML_default) )
1136         bLandscape = bChartSheet;
1137 
1138     // paper size
1139     if( rModel.mbValidSettings && (0 < rModel.mnPaperSize) && (rModel.mnPaperSize < static_cast< sal_Int32 >( STATIC_ARRAY_SIZE( spPaperSizeTable ) )) )
1140     {
1141         const ApiPaperSize& rPaperSize = spPaperSizeTable[ rModel.mnPaperSize ];
1142         Size aSize( rPaperSize.mnWidth, rPaperSize.mnHeight );
1143         if( bLandscape )
1144             ::std::swap( aSize.Width, aSize.Height );
1145         rPropSet.setProperty( PROP_Size, aSize );
1146     }
1147 
1148     // header/footer
1149     convertHeaderFooterData( rPropSet, maHeaderData, rModel.maOddHeader, rModel.maEvenHeader, rModel.mbUseEvenHF, rModel.mfTopMargin,    rModel.mfHeaderMargin );
1150     convertHeaderFooterData( rPropSet, maFooterData, rModel.maOddFooter, rModel.maEvenFooter, rModel.mbUseEvenHF, rModel.mfBottomMargin, rModel.mfFooterMargin );
1151 
1152     // write all properties to property set
1153     const UnitConverter& rUnitConv = getUnitConverter();
1154     PropertyMap aPropMap;
1155     aPropMap[ PROP_IsLandscape ]           <<= bLandscape;
1156     aPropMap[ PROP_FirstPageNumber ]       <<= getLimitedValue< sal_Int16, sal_Int32 >( rModel.mbUseFirstPage ? rModel.mnFirstPage : 0, 0, 9999 );
1157     aPropMap[ PROP_PrintDownFirst ]        <<= (rModel.mnPageOrder == XML_downThenOver);
1158     aPropMap[ PROP_PrintAnnotations ]      <<= (rModel.mnCellComments == XML_asDisplayed);
1159     aPropMap[ PROP_CenterHorizontally ]    <<= rModel.mbHorCenter;
1160     aPropMap[ PROP_CenterVertically ]      <<= rModel.mbVerCenter;
1161     aPropMap[ PROP_PrintGrid ]             <<= (!bChartSheet && rModel.mbPrintGrid);     // no gridlines in chart sheets
1162     aPropMap[ PROP_PrintHeaders ]          <<= (!bChartSheet && rModel.mbPrintHeadings); // no column/row headings in chart sheets
1163     aPropMap[ PROP_LeftMargin ]            <<= rUnitConv.scaleToMm100( rModel.mfLeftMargin, UNIT_INCH );
1164     aPropMap[ PROP_RightMargin ]           <<= rUnitConv.scaleToMm100( rModel.mfRightMargin, UNIT_INCH );
1165     // #i23296# In Calc, "TopMargin" property is distance to top of header if enabled
1166     aPropMap[ PROP_TopMargin ]             <<= rUnitConv.scaleToMm100( maHeaderData.mbHasContent ? rModel.mfHeaderMargin : rModel.mfTopMargin, UNIT_INCH );
1167     // #i23296# In Calc, "BottomMargin" property is distance to bottom of footer if enabled
1168     aPropMap[ PROP_BottomMargin ]          <<= rUnitConv.scaleToMm100( maFooterData.mbHasContent ? rModel.mfFooterMargin : rModel.mfBottomMargin, UNIT_INCH );
1169     aPropMap[ PROP_HeaderIsOn ]            <<= maHeaderData.mbHasContent;
1170     aPropMap[ PROP_HeaderIsShared ]        <<= maHeaderData.mbShareOddEven;
1171     aPropMap[ PROP_HeaderIsDynamicHeight ] <<= maHeaderData.mbDynamicHeight;
1172     aPropMap[ PROP_HeaderHeight ]          <<= maHeaderData.mnHeight;
1173     aPropMap[ PROP_HeaderBodyDistance ]    <<= maHeaderData.mnBodyDist;
1174     aPropMap[ PROP_FooterIsOn ]            <<= maFooterData.mbHasContent;
1175     aPropMap[ PROP_FooterIsShared ]        <<= maFooterData.mbShareOddEven;
1176     aPropMap[ PROP_FooterIsDynamicHeight ] <<= maFooterData.mbDynamicHeight;
1177     aPropMap[ PROP_FooterHeight ]          <<= maFooterData.mnHeight;
1178     aPropMap[ PROP_FooterBodyDistance ]    <<= maFooterData.mnBodyDist;
1179     // background image
1180     if( rModel.maGraphicUrl.getLength() > 0 )
1181     {
1182         aPropMap[ PROP_BackGraphicURL ] <<= rModel.maGraphicUrl;
1183         aPropMap[ PROP_BackGraphicLocation ] <<= ::com::sun::star::style::GraphicLocation_TILED;
1184     }
1185 
1186     rPropSet.setProperties( aPropMap );
1187 }
1188 
1189 void PageSettingsConverter::convertHeaderFooterData(
1190         PropertySet& rPropSet, HFHelperData& orHFData,
1191         const OUString rOddContent, const OUString rEvenContent, bool bUseEvenContent,
1192         double fPageMargin, double fContentMargin )
1193 {
1194     bool bHasOddContent  = rOddContent.getLength() > 0;
1195     bool bHasEvenContent = bUseEvenContent && (rEvenContent.getLength() > 0);
1196 
1197     sal_Int32 nOddHeight  = bHasOddContent  ? writeHeaderFooter( rPropSet, orHFData.mnRightPropId, rOddContent  ) : 0;
1198     sal_Int32 nEvenHeight = bHasEvenContent ? writeHeaderFooter( rPropSet, orHFData.mnLeftPropId,  rEvenContent ) : 0;
1199 
1200     orHFData.mnHeight = 750;
1201     orHFData.mnBodyDist = 250;
1202     orHFData.mbHasContent = bHasOddContent || bHasEvenContent;
1203     orHFData.mbShareOddEven = !bUseEvenContent;
1204     orHFData.mbDynamicHeight = true;
1205 
1206     if( orHFData.mbHasContent )
1207     {
1208         // use maximum height of odd/even header/footer
1209         orHFData.mnHeight = ::std::max( nOddHeight, nEvenHeight );
1210         /*  Calc contains distance between bottom of header and top of page
1211             body in "HeaderBodyDistance" property, and distance between bottom
1212             of page body and top of footer in "FooterBodyDistance" property */
1213         orHFData.mnBodyDist = getUnitConverter().scaleToMm100( fPageMargin - fContentMargin, UNIT_INCH ) - orHFData.mnHeight;
1214         /*  #i23296# Distance less than 0 means, header or footer overlays page
1215             body. As this is not possible in Calc, set fixed header or footer
1216             height (crop header/footer) to get correct top position of page body. */
1217         orHFData.mbDynamicHeight = orHFData.mnBodyDist >= 0;
1218         /*  "HeaderHeight" property is in fact distance from top of header to
1219             top of page body (including "HeaderBodyDistance").
1220             "FooterHeight" property is in fact distance from bottom of page
1221             body to bottom of footer (including "FooterBodyDistance"). */
1222         orHFData.mnHeight += orHFData.mnBodyDist;
1223         // negative body distance not allowed
1224         orHFData.mnBodyDist = ::std::max< sal_Int32 >( orHFData.mnBodyDist, 0 );
1225     }
1226 }
1227 
1228 sal_Int32 PageSettingsConverter::writeHeaderFooter(
1229         PropertySet& rPropSet, sal_Int32 nPropId, const OUString& rContent )
1230 {
1231     OSL_ENSURE( rContent.getLength() > 0, "PageSettingsConverter::writeHeaderFooter - empty h/f string found" );
1232     sal_Int32 nHeight = 0;
1233     if( rContent.getLength() > 0 )
1234     {
1235         Reference< XHeaderFooterContent > xHFContent( rPropSet.getAnyProperty( nPropId ), UNO_QUERY );
1236         if( xHFContent.is() )
1237         {
1238             double fTotalHeight = mxHFParser->parse( xHFContent, rContent );
1239             rPropSet.setProperty( nPropId, xHFContent );
1240             nHeight = getUnitConverter().scaleToMm100( fTotalHeight, UNIT_POINT );
1241         }
1242     }
1243     return nHeight;
1244 }
1245 
1246 // ============================================================================
1247 
1248 } // namespace xls
1249 } // namespace oox
1250