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