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