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 <xipage.hxx>
21 #include <svl/itemset.hxx>
22 #include <vcl/graph.hxx>
23 #include <scitems.hxx>
24 #include <svl/eitem.hxx>
25 #include <svl/intitem.hxx>
26 #include <svx/pageitem.hxx>
27 #include <editeng/sizeitem.hxx>
28 #include <editeng/lrspitem.hxx>
29 #include <editeng/ulspitem.hxx>
30 #include <editeng/brushitem.hxx>
31 #include <unotools/configmgr.hxx>
32 #include <document.hxx>
33 #include <stlsheet.hxx>
34 #include <attrib.hxx>
35 #include <xistream.hxx>
36 #include <xihelper.hxx>
37 #include <xiescher.hxx>
38 
39 // Page settings ==============================================================
40 
XclImpPageSettings(const XclImpRoot & rRoot)41 XclImpPageSettings::XclImpPageSettings( const XclImpRoot& rRoot ) :
42     XclImpRoot( rRoot )
43 {
44     Initialize();
45 }
46 
Initialize()47 void XclImpPageSettings::Initialize()
48 {
49     maData.SetDefaults();
50     mbValidPaper = false;
51 }
52 
ReadSetup(XclImpStream & rStrm)53 void XclImpPageSettings::ReadSetup( XclImpStream& rStrm )
54 {
55     OSL_ENSURE_BIFF( GetBiff() >= EXC_BIFF4 );
56     if( GetBiff() < EXC_BIFF4 )
57         return;
58 
59     // BIFF4 - BIFF8
60     sal_uInt16 nFlags;
61     maData.mnPaperSize = rStrm.ReaduInt16();
62     maData.mnScaling = rStrm.ReaduInt16();
63     maData.mnStartPage = rStrm.ReaduInt16();
64     maData.mnFitToWidth = rStrm.ReaduInt16();
65     maData.mnFitToHeight = rStrm.ReaduInt16();
66     nFlags = rStrm.ReaduInt16();
67 
68     mbValidPaper = maData.mbValid = !::get_flag( nFlags, EXC_SETUP_INVALID );
69     maData.mbPrintInRows = ::get_flag( nFlags, EXC_SETUP_INROWS );
70     maData.mbPortrait = ::get_flag( nFlags, EXC_SETUP_PORTRAIT );
71     maData.mbBlackWhite = ::get_flag( nFlags, EXC_SETUP_BLACKWHITE );
72     maData.mbManualStart = true;
73 
74     // new in BIFF5 - BIFF8
75     if( GetBiff() >= EXC_BIFF5 )
76     {
77         maData.mnHorPrintRes = rStrm.ReaduInt16();
78         maData.mnVerPrintRes = rStrm.ReaduInt16();
79         maData.mfHeaderMargin = rStrm.ReadDouble();
80         maData.mfFooterMargin = rStrm.ReadDouble();
81         maData.mnCopies = rStrm.ReaduInt16();
82 
83         maData.mbDraftQuality = ::get_flag( nFlags, EXC_SETUP_DRAFT );
84         maData.mbPrintNotes = ::get_flag( nFlags, EXC_SETUP_PRINTNOTES );
85         maData.mbManualStart = ::get_flag( nFlags, EXC_SETUP_STARTPAGE );
86     }
87 }
88 
ReadMargin(XclImpStream & rStrm)89 void XclImpPageSettings::ReadMargin( XclImpStream& rStrm )
90 {
91     switch( rStrm.GetRecId() )
92     {
93         case EXC_ID_LEFTMARGIN:     maData.mfLeftMargin = rStrm.ReadDouble();   break;
94         case EXC_ID_RIGHTMARGIN:    maData.mfRightMargin = rStrm.ReadDouble();  break;
95         case EXC_ID_TOPMARGIN:      maData.mfTopMargin = rStrm.ReadDouble();    break;
96         case EXC_ID_BOTTOMMARGIN:   maData.mfBottomMargin = rStrm.ReadDouble(); break;
97         default:    OSL_FAIL( "XclImpPageSettings::ReadMargin - unknown record" );
98     }
99 }
100 
ReadCenter(XclImpStream & rStrm)101 void XclImpPageSettings::ReadCenter( XclImpStream& rStrm )
102 {
103     OSL_ENSURE_BIFF( GetBiff() >= EXC_BIFF3 );  // read it anyway
104     bool bCenter = (rStrm.ReaduInt16() != 0);
105     switch( rStrm.GetRecId() )
106     {
107         case EXC_ID_HCENTER:    maData.mbHorCenter = bCenter;   break;
108         case EXC_ID_VCENTER:    maData.mbVerCenter = bCenter;   break;
109         default:    OSL_FAIL( "XclImpPageSettings::ReadCenter - unknown record" );
110     }
111 }
112 
ReadHeaderFooter(XclImpStream & rStrm)113 void XclImpPageSettings::ReadHeaderFooter( XclImpStream& rStrm )
114 {
115     OUString aString;
116     if( rStrm.GetRecLeft() )
117         aString = (GetBiff() <= EXC_BIFF5) ? rStrm.ReadByteString( false ) : rStrm.ReadUniString();
118 
119     switch( rStrm.GetRecId() )
120     {
121         case EXC_ID_HEADER:     maData.maHeader = aString;  break;
122         case EXC_ID_FOOTER:     maData.maFooter = aString;  break;
123         default:    OSL_FAIL( "XclImpPageSettings::ReadHeaderFooter - unknown record" );
124     }
125 
126     if (maData.maHeader.getLength() > 10 && utl::ConfigManager::IsFuzzing())
127         maData.maHeader = maData.maHeader.copy(0, 10);
128 }
129 
ReadPageBreaks(XclImpStream & rStrm)130 void XclImpPageSettings::ReadPageBreaks( XclImpStream& rStrm )
131 {
132     ScfUInt16Vec* pVec = nullptr;
133     switch( rStrm.GetRecId() )
134     {
135         case EXC_ID_HORPAGEBREAKS:  pVec = &maData.maHorPageBreaks;     break;
136         case EXC_ID_VERPAGEBREAKS:  pVec = &maData.maVerPageBreaks;     break;
137         default:    OSL_FAIL( "XclImpPageSettings::ReadPageBreaks - unknown record" );
138     }
139 
140     if( pVec )
141     {
142         bool bIgnore = GetBiff() == EXC_BIFF8;  // ignore start/end columns or rows in BIFF8
143 
144         sal_uInt16 nCount, nBreak;
145         nCount = rStrm.ReaduInt16();
146         pVec->clear();
147         pVec->reserve( nCount );
148 
149         while( nCount-- )
150         {
151             nBreak = rStrm.ReaduInt16();
152             if( nBreak )
153                 pVec->push_back( nBreak );
154             if( bIgnore )
155                 rStrm.Ignore( 4 );
156         }
157     }
158 }
159 
ReadPrintHeaders(XclImpStream & rStrm)160 void XclImpPageSettings::ReadPrintHeaders( XclImpStream& rStrm )
161 {
162     maData.mbPrintHeadings = (rStrm.ReaduInt16() != 0);
163 }
164 
ReadPrintGridLines(XclImpStream & rStrm)165 void XclImpPageSettings::ReadPrintGridLines( XclImpStream& rStrm )
166 {
167     maData.mbPrintGrid = (rStrm.ReaduInt16() != 0);
168 }
169 
ReadImgData(XclImpStream & rStrm)170 void XclImpPageSettings::ReadImgData( XclImpStream& rStrm )
171 {
172     Graphic aGraphic = XclImpDrawing::ReadImgData( GetRoot(), rStrm );
173     if( aGraphic.GetType() != GraphicType::NONE )
174         maData.mxBrushItem.reset( new SvxBrushItem( aGraphic, GPOS_TILED, ATTR_BACKGROUND ) );
175 }
176 
SetPaperSize(sal_uInt16 nXclPaperSize,bool bPortrait)177 void XclImpPageSettings::SetPaperSize( sal_uInt16 nXclPaperSize, bool bPortrait )
178 {
179     maData.mnPaperSize = nXclPaperSize;
180     maData.mbPortrait = bPortrait;
181     mbValidPaper = true;
182 }
183 
184 namespace {
185 
lclPutMarginItem(SfxItemSet & rItemSet,sal_uInt16 nRecId,double fMarginInch)186 void lclPutMarginItem( SfxItemSet& rItemSet, sal_uInt16 nRecId, double fMarginInch )
187 {
188     sal_uInt16 nMarginTwips = XclTools::GetTwipsFromInch( fMarginInch );
189     switch( nRecId )
190     {
191         case EXC_ID_TOPMARGIN:
192         case EXC_ID_BOTTOMMARGIN:
193         {
194             SvxULSpaceItem aItem( rItemSet.Get( ATTR_ULSPACE ) );
195             if( nRecId == EXC_ID_TOPMARGIN )
196                 aItem.SetUpperValue( nMarginTwips );
197             else
198                 aItem.SetLowerValue( nMarginTwips );
199             rItemSet.Put( aItem );
200         }
201         break;
202         case EXC_ID_LEFTMARGIN:
203         case EXC_ID_RIGHTMARGIN:
204         {
205             SvxLRSpaceItem aItem( rItemSet.Get( ATTR_LRSPACE ) );
206             if( nRecId == EXC_ID_LEFTMARGIN )
207                 aItem.SetLeftValue( nMarginTwips );
208             else
209                 aItem.SetRightValue( nMarginTwips );
210             rItemSet.Put( aItem );
211         }
212         break;
213         default:
214             OSL_FAIL( "XclImpPageSettings::SetMarginItem - unknown record id" );
215     }
216 }
217 
218 } // namespace
219 
Finalize()220 void XclImpPageSettings::Finalize()
221 {
222     ScDocument& rDoc = GetDoc();
223     SCTAB nScTab = GetCurrScTab();
224 
225     // *** create page style sheet ***
226 
227     OUString aStyleName;
228     OUString aTableName;
229     if( GetDoc().GetName( nScTab, aTableName ) )
230         aStyleName = "PageStyle_" + aTableName;
231     else
232         aStyleName = "PageStyle_" + OUString::number(static_cast<sal_Int32>(nScTab+1));
233 
234     ScStyleSheet& rStyleSheet = ScfTools::MakePageStyleSheet(
235         GetStyleSheetPool(), aStyleName, false);
236 
237     SfxItemSet& rItemSet = rStyleSheet.GetItemSet();
238 
239     // *** page settings ***
240 
241     ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_PAGE_TOPDOWN,    !maData.mbPrintInRows ),    true );
242     ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_PAGE_HORCENTER,  maData.mbHorCenter ),       true );
243     ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_PAGE_VERCENTER,  maData.mbVerCenter ),       true );
244     ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_PAGE_HEADERS,    maData.mbPrintHeadings ),   true );
245     ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_PAGE_GRID,       maData.mbPrintGrid ),       true );
246     ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_PAGE_NOTES,      maData.mbPrintNotes ),      true );
247 
248     sal_uInt16 nStartPage = maData.mbManualStart ? maData.mnStartPage : 0;
249     ScfTools::PutItem( rItemSet, SfxUInt16Item( ATTR_PAGE_FIRSTPAGENO, nStartPage ), true );
250 
251     if( maData.mxBrushItem.get() )
252         rItemSet.Put( *maData.mxBrushItem );
253 
254     if( mbValidPaper )
255     {
256         SvxPageItem aPageItem( rItemSet.Get( ATTR_PAGE ) );
257         aPageItem.SetLandscape( !maData.mbPortrait );
258         rItemSet.Put( aPageItem );
259         ScfTools::PutItem( rItemSet, SvxSizeItem( ATTR_PAGE_SIZE, maData.GetScPaperSize() ), true );
260     }
261 
262     if( maData.mbFitToPages )
263         rItemSet.Put( ScPageScaleToItem( maData.mnFitToWidth, maData.mnFitToHeight ) );
264     else if( maData.mbValid )
265         rItemSet.Put( SfxUInt16Item( ATTR_PAGE_SCALE, maData.mnScaling ) );
266 
267     // *** margin preparations ***
268 
269     double fLeftMargin   = maData.mfLeftMargin;
270     double fRightMargin  = maData.mfRightMargin;
271     double fTopMargin    = maData.mfTopMargin;
272     double fBottomMargin = maData.mfBottomMargin;
273     // distances between header/footer and page area
274     double fHeaderHeight = 0.0;
275     double fHeaderDist = 0.0;
276     double fFooterHeight = 0.0;
277     double fFooterDist = 0.0;
278     // in Calc, "header/footer left/right margin" is X distance between header/footer and page margin
279     double fHdrLeftMargin  = maData.mfHdrLeftMargin  - maData.mfLeftMargin;
280     double fHdrRightMargin = maData.mfHdrRightMargin - maData.mfRightMargin;
281     double fFtrLeftMargin  = maData.mfFtrLeftMargin  - maData.mfLeftMargin;
282     double fFtrRightMargin = maData.mfFtrRightMargin - maData.mfRightMargin;
283 
284     // *** header and footer ***
285 
286     XclImpHFConverter aHFConv( GetRoot() );
287 
288     // header
289     bool bHasHeader = !maData.maHeader.isEmpty();
290     SvxSetItem aHdrSetItem( rItemSet.Get( ATTR_PAGE_HEADERSET ) );
291     SfxItemSet& rHdrItemSet = aHdrSetItem.GetItemSet();
292     rHdrItemSet.Put( SfxBoolItem( ATTR_PAGE_ON, bHasHeader ) );
293     if( bHasHeader )
294     {
295         aHFConv.ParseString( maData.maHeader );
296         aHFConv.FillToItemSet( rItemSet, ATTR_PAGE_HEADERLEFT );
297         aHFConv.FillToItemSet( rItemSet, ATTR_PAGE_HEADERRIGHT );
298         // #i23296# In Calc, "top margin" is distance to header
299         fTopMargin = maData.mfHeaderMargin;
300         // Calc uses distance between header and sheet data area
301         fHeaderHeight = XclTools::GetInchFromTwips( aHFConv.GetTotalHeight() );
302         fHeaderDist = maData.mfTopMargin - maData.mfHeaderMargin - fHeaderHeight;
303     }
304     if( fHeaderDist < 0.0 )
305     {
306         /*  #i23296# Header overlays sheet data:
307             -> set fixed header height to get correct sheet data position. */
308         ScfTools::PutItem( rHdrItemSet, SfxBoolItem( ATTR_PAGE_DYNAMIC, false ), true );
309         // shrink header height
310         long nHdrHeight = XclTools::GetTwipsFromInch( fHeaderHeight + fHeaderDist );
311         ScfTools::PutItem( rHdrItemSet, SvxSizeItem( ATTR_PAGE_SIZE, Size( 0, nHdrHeight ) ), true );
312         lclPutMarginItem( rHdrItemSet, EXC_ID_BOTTOMMARGIN, 0.0 );
313     }
314     else
315     {
316         // use dynamic header height
317         ScfTools::PutItem( rHdrItemSet, SfxBoolItem( ATTR_PAGE_DYNAMIC, true ), true );
318         lclPutMarginItem( rHdrItemSet, EXC_ID_BOTTOMMARGIN, fHeaderDist );
319     }
320     lclPutMarginItem( rHdrItemSet, EXC_ID_LEFTMARGIN,   fHdrLeftMargin );
321     lclPutMarginItem( rHdrItemSet, EXC_ID_RIGHTMARGIN,  fHdrRightMargin );
322     rItemSet.Put( aHdrSetItem );
323 
324     // footer
325     bool bHasFooter = !maData.maFooter.isEmpty();
326     SvxSetItem aFtrSetItem( rItemSet.Get( ATTR_PAGE_FOOTERSET ) );
327     SfxItemSet& rFtrItemSet = aFtrSetItem.GetItemSet();
328     rFtrItemSet.Put( SfxBoolItem( ATTR_PAGE_ON, bHasFooter ) );
329     if( bHasFooter )
330     {
331         aHFConv.ParseString( maData.maFooter );
332         aHFConv.FillToItemSet( rItemSet, ATTR_PAGE_FOOTERLEFT );
333         aHFConv.FillToItemSet( rItemSet, ATTR_PAGE_FOOTERRIGHT );
334         // #i23296# In Calc, "bottom margin" is distance to footer
335         fBottomMargin = maData.mfFooterMargin;
336         // Calc uses distance between footer and sheet data area
337         fFooterHeight = XclTools::GetInchFromTwips( aHFConv.GetTotalHeight() );
338         fFooterDist = maData.mfBottomMargin - maData.mfFooterMargin - fFooterHeight;
339     }
340     if( fFooterDist < 0.0 )
341     {
342         /*  #i23296# Footer overlays sheet data:
343             -> set fixed footer height to get correct sheet data end position. */
344         ScfTools::PutItem( rFtrItemSet, SfxBoolItem( ATTR_PAGE_DYNAMIC, false ), true );
345         // shrink footer height
346         long nFtrHeight = XclTools::GetTwipsFromInch( fFooterHeight + fFooterDist );
347         ScfTools::PutItem( rFtrItemSet, SvxSizeItem( ATTR_PAGE_SIZE, Size( 0, nFtrHeight ) ), true );
348         lclPutMarginItem( rFtrItemSet, EXC_ID_TOPMARGIN, 0.0 );
349     }
350     else
351     {
352         // use dynamic footer height
353         ScfTools::PutItem( rFtrItemSet, SfxBoolItem( ATTR_PAGE_DYNAMIC, true ), true );
354         lclPutMarginItem( rFtrItemSet, EXC_ID_TOPMARGIN, fFooterDist );
355     }
356     lclPutMarginItem( rFtrItemSet, EXC_ID_LEFTMARGIN,   fFtrLeftMargin );
357     lclPutMarginItem( rFtrItemSet, EXC_ID_RIGHTMARGIN,  fFtrRightMargin );
358     rItemSet.Put( aFtrSetItem );
359 
360     // *** set final margins ***
361 
362     lclPutMarginItem( rItemSet, EXC_ID_LEFTMARGIN,   fLeftMargin );
363     lclPutMarginItem( rItemSet, EXC_ID_RIGHTMARGIN,  fRightMargin );
364     lclPutMarginItem( rItemSet, EXC_ID_TOPMARGIN,    fTopMargin );
365     lclPutMarginItem( rItemSet, EXC_ID_BOTTOMMARGIN, fBottomMargin );
366 
367     // *** put style sheet into document ***
368 
369     rDoc.SetPageStyle( nScTab, rStyleSheet.GetName() );
370 
371     // *** page breaks ***
372 
373     for( const auto& rHorPageBreak : maData.maHorPageBreaks )
374     {
375         SCROW nScRow = static_cast< SCROW >( rHorPageBreak );
376         if( nScRow <= rDoc.MaxRow() )
377             rDoc.SetRowBreak(nScRow, nScTab, false, true);
378     }
379 
380     for( const auto& rVerPageBreak : maData.maVerPageBreaks )
381     {
382         SCCOL nScCol = static_cast< SCCOL >( rVerPageBreak );
383         if( nScCol <= rDoc.MaxCol() )
384             rDoc.SetColBreak(nScCol, nScTab, false, true);
385     }
386 }
387 
388 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
389