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 <viewsettings.hxx>
21 
22 #include <com/sun/star/awt/Point.hpp>
23 #include <com/sun/star/awt/Size.hpp>
24 #include <com/sun/star/beans/XPropertySet.hpp>
25 #include <com/sun/star/container/XIndexContainer.hpp>
26 #include <com/sun/star/document/IndexedPropertyValues.hpp>
27 #include <com/sun/star/document/XViewDataSupplier.hpp>
28 #include <com/sun/star/document/NamedPropertyValues.hpp>
29 #include <osl/diagnose.h>
30 #include <unotools/mediadescriptor.hxx>
31 #include <oox/core/filterbase.hxx>
32 #include <oox/helper/binaryinputstream.hxx>
33 #include <oox/helper/attributelist.hxx>
34 #include <oox/helper/containerhelper.hxx>
35 #include <oox/helper/propertymap.hxx>
36 #include <oox/helper/propertyset.hxx>
37 #include <oox/token/properties.hxx>
38 #include <oox/token/tokens.hxx>
39 #include <addressconverter.hxx>
40 #include <workbooksettings.hxx>
41 #include <worksheetbuffer.hxx>
42 
43 namespace com { namespace sun { namespace star { namespace container { class XNameContainer; } } } }
44 
45 namespace oox {
46 namespace xls {
47 
48 using namespace ::com::sun::star::awt;
49 using namespace ::com::sun::star::container;
50 using namespace ::com::sun::star::document;
51 using namespace ::com::sun::star::uno;
52 
53 using ::oox::core::FilterBase;
54 
55 namespace {
56 
57 const sal_Int32 OOX_BOOKVIEW_TABBARRATIO_DEF        = 600;      /// Default tabbar ratio.
58 const sal_Int32 OOX_SHEETVIEW_NORMALZOOM_DEF        = 100;      /// Default zoom for normal view.
59 const sal_Int32 OOX_SHEETVIEW_SHEETLAYZOOM_DEF      = 60;       /// Default zoom for pagebreak preview.
60 
61 const sal_uInt8 BIFF12_PANE_FROZEN                  = 0x01;
62 const sal_uInt8 BIFF12_PANE_FROZENNOSPLIT           = 0x02;
63 
64 const sal_uInt16 BIFF12_SHEETVIEW_SHOWFORMULAS      = 0x0002;
65 const sal_uInt16 BIFF12_SHEETVIEW_SHOWGRID          = 0x0004;
66 const sal_uInt16 BIFF12_SHEETVIEW_SHOWHEADINGS      = 0x0008;
67 const sal_uInt16 BIFF12_SHEETVIEW_SHOWZEROS         = 0x0010;
68 const sal_uInt16 BIFF12_SHEETVIEW_RIGHTTOLEFT       = 0x0020;
69 const sal_uInt16 BIFF12_SHEETVIEW_SELECTED          = 0x0040;
70 const sal_uInt16 BIFF12_SHEETVIEW_SHOWOUTLINE       = 0x0100;
71 const sal_uInt16 BIFF12_SHEETVIEW_DEFGRIDCOLOR      = 0x0200;
72 
73 const sal_uInt16 BIFF12_CHARTSHEETVIEW_SELECTED     = 0x0001;
74 const sal_uInt16 BIFF12_CHARTSHEETVIEW_ZOOMTOFIT    = 0x0002;
75 
76 const sal_uInt8 BIFF12_WBVIEW_HIDDEN                = 0x01;
77 const sal_uInt8 BIFF12_WBVIEW_MINIMIZED             = 0x02;
78 const sal_uInt8 BIFF12_WBVIEW_SHOWHORSCROLL         = 0x08;
79 const sal_uInt8 BIFF12_WBVIEW_SHOWVERSCROLL         = 0x10;
80 const sal_uInt8 BIFF12_WBVIEW_SHOWTABBAR            = 0x20;
81 
82 // Attention: view settings in Calc do not use com.sun.star.view.DocumentZoomType!
83 const sal_Int16 API_ZOOMTYPE_PERCENT                = 0;        /// Zoom value in percent.
84 
85 const sal_Int32 API_ZOOMVALUE_MIN                   = 20;       /// Minimum zoom in Calc.
86 const sal_Int32 API_ZOOMVALUE_MAX                   = 400;      /// Maximum zoom in Calc.
87 
88 // no predefined constants for split mode
89 const sal_Int16 API_SPLITMODE_NONE                  = 0;        /// No splits in window.
90 const sal_Int16 API_SPLITMODE_SPLIT                 = 1;        /// Window is split.
91 const sal_Int16 API_SPLITMODE_FREEZE                = 2;        /// Window has frozen panes.
92 
93 // no predefined constants for pane identifiers
94 const sal_Int16 API_SPLITPANE_TOPLEFT               = 0;        /// Top-left, or top pane.
95 const sal_Int16 API_SPLITPANE_TOPRIGHT              = 1;        /// Top-right pane.
96 const sal_Int16 API_SPLITPANE_BOTTOMLEFT            = 2;        /// Bottom-left, bottom, left, or single pane.
97 const sal_Int16 API_SPLITPANE_BOTTOMRIGHT           = 3;        /// Bottom-right, or right pane.
98 
99 /** Returns the OOXML pane identifier from the passed BIFF pane id. */
lclGetOoxPaneId(sal_Int32 nBiffPaneId,sal_Int32 nDefaultPaneId)100 sal_Int32 lclGetOoxPaneId( sal_Int32 nBiffPaneId, sal_Int32 nDefaultPaneId )
101 {
102     static const sal_Int32 spnPaneIds[] = { XML_bottomRight, XML_topRight, XML_bottomLeft, XML_topLeft };
103     return STATIC_ARRAY_SELECT( spnPaneIds, nBiffPaneId, nDefaultPaneId );
104 }
105 
106 } // namespace
107 
PaneSelectionModel()108 PaneSelectionModel::PaneSelectionModel() :
109     mnActiveCellId( 0 )
110 {
111 }
112 
SheetViewModel()113 SheetViewModel::SheetViewModel() :
114     mnWorkbookViewId( 0 ),
115     mnViewType( XML_normal ),
116     mnActivePaneId( XML_topLeft ),
117     mnPaneState( XML_split ),
118     mfSplitX( 0.0 ),
119     mfSplitY( 0.0 ),
120     mnCurrentZoom( 0 ),
121     mnNormalZoom( 0 ),
122     mnSheetLayoutZoom( 0 ),
123     mnPageLayoutZoom( 0 ),
124     mbSelected( false ),
125     mbRightToLeft( false ),
126     mbDefGridColor( true ),
127     mbShowFormulas( false ),
128     mbShowGrid( true ),
129     mbShowHeadings( true ),
130     mbShowZeros( true ),
131     mbShowOutline( true ),
132     mbZoomToFit( false )
133 {
134     maGridColor.setIndexed( OOX_COLOR_WINDOWTEXT );
135 }
136 
isPageBreakPreview() const137 bool SheetViewModel::isPageBreakPreview() const
138 {
139     return mnViewType == XML_pageBreakPreview;
140 }
141 
getNormalZoom() const142 sal_Int32 SheetViewModel::getNormalZoom() const
143 {
144     const sal_Int32& rnZoom = isPageBreakPreview() ? mnNormalZoom : mnCurrentZoom;
145     sal_Int32 nZoom = (rnZoom > 0) ? rnZoom : OOX_SHEETVIEW_NORMALZOOM_DEF;
146     return getLimitedValue< sal_Int32 >( nZoom, API_ZOOMVALUE_MIN, API_ZOOMVALUE_MAX );
147 }
148 
getPageBreakZoom() const149 sal_Int32 SheetViewModel::getPageBreakZoom() const
150 {
151     const sal_Int32& rnZoom = isPageBreakPreview() ? mnCurrentZoom : mnSheetLayoutZoom;
152     sal_Int32 nZoom = (rnZoom > 0) ? rnZoom : OOX_SHEETVIEW_SHEETLAYZOOM_DEF;
153     return getLimitedValue< sal_Int32 >( nZoom, API_ZOOMVALUE_MIN, API_ZOOMVALUE_MAX );
154 }
155 
getGridColor(const FilterBase & rFilter) const156 ::Color SheetViewModel::getGridColor( const FilterBase& rFilter ) const
157 {
158     return mbDefGridColor ? API_RGB_TRANSPARENT : maGridColor.getColor( rFilter.getGraphicHelper() );
159 }
160 
getActiveSelection() const161 const PaneSelectionModel* SheetViewModel::getActiveSelection() const
162 {
163     return maPaneSelMap.get( mnActivePaneId ).get();
164 }
165 
createPaneSelection(sal_Int32 nPaneId)166 PaneSelectionModel& SheetViewModel::createPaneSelection( sal_Int32 nPaneId )
167 {
168     PaneSelectionModelMap::mapped_type& rxPaneSel = maPaneSelMap[ nPaneId ];
169     if( !rxPaneSel )
170         rxPaneSel.reset( new PaneSelectionModel );
171     return *rxPaneSel;
172 }
173 
SheetViewSettings(const WorksheetHelper & rHelper)174 SheetViewSettings::SheetViewSettings( const WorksheetHelper& rHelper ) :
175     WorksheetHelper( rHelper )
176 {
177 }
178 
importSheetView(const AttributeList & rAttribs)179 void SheetViewSettings::importSheetView( const AttributeList& rAttribs )
180 {
181     SheetViewModel& rModel = *createSheetView();
182     rModel.maGridColor.setIndexed( rAttribs.getInteger( XML_colorId, OOX_COLOR_WINDOWTEXT ) );
183     rModel.maFirstPos        = getAddressConverter().createValidCellAddress( rAttribs.getString( XML_topLeftCell, OUString() ), getSheetIndex(), false );
184     rModel.mnWorkbookViewId  = rAttribs.getToken( XML_workbookViewId, 0 );
185     rModel.mnViewType        = rAttribs.getToken( XML_view, XML_normal );
186     rModel.mnCurrentZoom     = rAttribs.getInteger( XML_zoomScale, 100 );
187     rModel.mnNormalZoom      = rAttribs.getInteger( XML_zoomScaleNormal, 0 );
188     rModel.mnSheetLayoutZoom = rAttribs.getInteger( XML_zoomScaleSheetLayoutView, 0 );
189     rModel.mnPageLayoutZoom  = rAttribs.getInteger( XML_zoomScalePageLayoutView, 0 );
190     rModel.mbSelected        = rAttribs.getBool( XML_tabSelected, false );
191     rModel.mbRightToLeft     = rAttribs.getBool( XML_rightToLeft, false );
192     rModel.mbDefGridColor    = rAttribs.getBool( XML_defaultGridColor, true );
193     rModel.mbShowFormulas    = rAttribs.getBool( XML_showFormulas, false );
194     rModel.mbShowGrid        = rAttribs.getBool( XML_showGridLines, true );
195     rModel.mbShowHeadings    = rAttribs.getBool( XML_showRowColHeaders, true );
196     rModel.mbShowZeros       = rAttribs.getBool( XML_showZeros, true );
197     rModel.mbShowOutline     = rAttribs.getBool( XML_showOutlineSymbols, true );
198 }
199 
importPane(const AttributeList & rAttribs)200 void SheetViewSettings::importPane( const AttributeList& rAttribs )
201 {
202     OSL_ENSURE( !maSheetViews.empty(), "SheetViewSettings::importPane - missing sheet view model" );
203     if( !maSheetViews.empty() )
204     {
205         SheetViewModel& rModel = *maSheetViews.back();
206         rModel.maSecondPos    = getAddressConverter().createValidCellAddress( rAttribs.getString( XML_topLeftCell, OUString() ), getSheetIndex(), false );
207         rModel.mnActivePaneId = rAttribs.getToken( XML_activePane, XML_topLeft );
208         rModel.mnPaneState    = rAttribs.getToken( XML_state, XML_split );
209         rModel.mfSplitX       = rAttribs.getDouble( XML_xSplit, 0.0 );
210         rModel.mfSplitY       = rAttribs.getDouble( XML_ySplit, 0.0 );
211     }
212 }
213 
importSelection(const AttributeList & rAttribs)214 void SheetViewSettings::importSelection( const AttributeList& rAttribs )
215 {
216     OSL_ENSURE( !maSheetViews.empty(), "SheetViewSettings::importSelection - missing sheet view model" );
217     if( !maSheetViews.empty() )
218     {
219         // pane this selection belongs to
220         sal_Int32 nPaneId = rAttribs.getToken( XML_pane, XML_topLeft );
221         PaneSelectionModel& rSelData = maSheetViews.back()->createPaneSelection( nPaneId );
222         // cursor position
223         rSelData.maActiveCell = getAddressConverter().createValidCellAddress( rAttribs.getString( XML_activeCell, OUString() ), getSheetIndex(), false );
224         rSelData.mnActiveCellId = rAttribs.getInteger( XML_activeCellId, 0 );
225         // selection
226         rSelData.maSelection.RemoveAll();
227         getAddressConverter().convertToCellRangeList( rSelData.maSelection, rAttribs.getString( XML_sqref, OUString() ), getSheetIndex(), false );
228     }
229 }
230 
importChartSheetView(const AttributeList & rAttribs)231 void SheetViewSettings::importChartSheetView( const AttributeList& rAttribs )
232 {
233     SheetViewModel& rModel = *createSheetView();
234     rModel.mnWorkbookViewId = rAttribs.getToken( XML_workbookViewId, 0 );
235     rModel.mnCurrentZoom    = rAttribs.getInteger( XML_zoomScale, 100 );
236     rModel.mbSelected       = rAttribs.getBool( XML_tabSelected, false );
237     rModel.mbZoomToFit      = rAttribs.getBool( XML_zoomToFit, false );
238 }
239 
importSheetView(SequenceInputStream & rStrm)240 void SheetViewSettings::importSheetView( SequenceInputStream& rStrm )
241 {
242     SheetViewModel& rModel = *createSheetView();
243     sal_uInt16 nFlags;
244     sal_Int32 nViewType;
245     BinAddress aFirstPos;
246     nFlags = rStrm.readuInt16();
247     nViewType = rStrm.readInt32();
248     rStrm >> aFirstPos;
249     rModel.maGridColor.importColorId( rStrm );
250     rModel.mnCurrentZoom = rStrm.readuInt16();
251     rModel.mnNormalZoom = rStrm.readuInt16();
252     rModel.mnSheetLayoutZoom = rStrm.readuInt16();
253     rModel.mnPageLayoutZoom = rStrm.readuInt16();
254     rModel.mnWorkbookViewId = rStrm.readInt32();
255 
256     rModel.maFirstPos = getAddressConverter().createValidCellAddress( aFirstPos, getSheetIndex(), false );
257     static const sal_Int32 spnViewTypes[] = { XML_normal, XML_pageBreakPreview, XML_pageLayout };
258     rModel.mnViewType = STATIC_ARRAY_SELECT( spnViewTypes, nViewType, XML_normal );
259     rModel.mbSelected     = getFlag( nFlags, BIFF12_SHEETVIEW_SELECTED );
260     rModel.mbRightToLeft  = getFlag( nFlags, BIFF12_SHEETVIEW_RIGHTTOLEFT );
261     rModel.mbDefGridColor = getFlag( nFlags, BIFF12_SHEETVIEW_DEFGRIDCOLOR );
262     rModel.mbShowFormulas = getFlag( nFlags, BIFF12_SHEETVIEW_SHOWFORMULAS );
263     rModel.mbShowGrid     = getFlag( nFlags, BIFF12_SHEETVIEW_SHOWGRID );
264     rModel.mbShowHeadings = getFlag( nFlags, BIFF12_SHEETVIEW_SHOWHEADINGS );
265     rModel.mbShowZeros    = getFlag( nFlags, BIFF12_SHEETVIEW_SHOWZEROS );
266     rModel.mbShowOutline  = getFlag( nFlags, BIFF12_SHEETVIEW_SHOWOUTLINE );
267 }
268 
importPane(SequenceInputStream & rStrm)269 void SheetViewSettings::importPane( SequenceInputStream& rStrm )
270 {
271     OSL_ENSURE( !maSheetViews.empty(), "SheetViewSettings::importPane - missing sheet view model" );
272     if( !maSheetViews.empty() )
273     {
274         SheetViewModel& rModel = *maSheetViews.back();
275 
276         BinAddress aSecondPos;
277         sal_Int32 nActivePaneId;
278         sal_uInt8 nFlags;
279         rModel.mfSplitX = rStrm.readDouble();
280         rModel.mfSplitY = rStrm.readDouble();
281         rStrm >> aSecondPos;
282         nActivePaneId = rStrm.readInt32();
283         nFlags = rStrm.readuChar();
284 
285         rModel.maSecondPos    = getAddressConverter().createValidCellAddress( aSecondPos, getSheetIndex(), false );
286         rModel.mnActivePaneId = lclGetOoxPaneId( nActivePaneId, XML_topLeft );
287         rModel.mnPaneState    = getFlagValue( nFlags, BIFF12_PANE_FROZEN, getFlagValue( nFlags, BIFF12_PANE_FROZENNOSPLIT, XML_frozen, XML_frozenSplit ), XML_split );
288     }
289 }
290 
importSelection(SequenceInputStream & rStrm)291 void SheetViewSettings::importSelection( SequenceInputStream& rStrm )
292 {
293     OSL_ENSURE( !maSheetViews.empty(), "SheetViewSettings::importSelection - missing sheet view model" );
294     if( !maSheetViews.empty() )
295     {
296         // pane this selection belongs to
297         sal_Int32 nPaneId = rStrm.readInt32();
298         PaneSelectionModel& rPaneSel = maSheetViews.back()->createPaneSelection( lclGetOoxPaneId( nPaneId, -1 ) );
299         // cursor position
300         BinAddress aActiveCell;
301         rStrm >> aActiveCell;
302         rPaneSel.mnActiveCellId = rStrm.readInt32();
303         rPaneSel.maActiveCell = getAddressConverter().createValidCellAddress( aActiveCell, getSheetIndex(), false );
304         // selection
305         BinRangeList aSelection;
306         rStrm >> aSelection;
307         rPaneSel.maSelection.RemoveAll();
308         getAddressConverter().convertToCellRangeList( rPaneSel.maSelection, aSelection, getSheetIndex(), false );
309     }
310 }
311 
importChartSheetView(SequenceInputStream & rStrm)312 void SheetViewSettings::importChartSheetView( SequenceInputStream& rStrm )
313 {
314     SheetViewModel& rModel = *createSheetView();
315     sal_uInt16 nFlags;
316     nFlags = rStrm.readuInt16();
317     rModel.mnCurrentZoom = rStrm.readInt32();
318     rModel.mnWorkbookViewId = rStrm.readInt32();
319 
320     rModel.mbSelected  = getFlag( nFlags, BIFF12_CHARTSHEETVIEW_SELECTED );
321     rModel.mbZoomToFit = getFlag( nFlags, BIFF12_CHARTSHEETVIEW_ZOOMTOFIT );
322 }
323 
finalizeImport()324 void SheetViewSettings::finalizeImport()
325 {
326     // force creation of sheet view model to get the Excel defaults
327     SheetViewModelRef xModel = maSheetViews.empty() ? createSheetView() : maSheetViews.front();
328 
329     // #i59590# #158194# special handling for chart sheets (Excel ignores some settings in chart sheets)
330     if( getSheetType() == WorksheetType::Chart )
331     {
332         xModel->maPaneSelMap.clear();
333         xModel->maFirstPos = xModel->maSecondPos = ScAddress( SCCOL ( 0 ), SCROW ( 0 ), getSheetIndex() );
334         xModel->mnViewType = XML_normal;
335         xModel->mnActivePaneId = XML_topLeft;
336         xModel->mnPaneState = XML_split;
337         xModel->mfSplitX = xModel->mfSplitY = 0.0;
338         xModel->mbRightToLeft = false;
339         xModel->mbDefGridColor = true;
340         xModel->mbShowFormulas = false;
341         xModel->mbShowGrid = true;
342         xModel->mbShowHeadings = true;
343         xModel->mbShowZeros = true;
344         xModel->mbShowOutline = true;
345     }
346 
347     // sheet selected (active sheet must be selected)
348     bool bSelected = xModel->mbSelected || (getSheetIndex() == getViewSettings().getActiveCalcSheet());
349     if ( bSelected )
350     {
351         // active tab/sheet cannot be hidden
352         // always force it to be displayed
353         PropertySet aPropSet( getSheet() );
354         aPropSet.setProperty( PROP_IsVisible, true );
355     }
356     // visible area and current cursor position (selection not supported via API)
357     ScAddress aFirstPos = xModel->maFirstPos;
358     const PaneSelectionModel* pPaneSel = xModel->getActiveSelection();
359     ScAddress aCursor = pPaneSel ? pPaneSel->maActiveCell : aFirstPos;
360 
361     // freeze/split position default
362     sal_Int16 nHSplitMode = API_SPLITMODE_NONE;
363     sal_Int16 nVSplitMode = API_SPLITMODE_NONE;
364     sal_Int32 nHSplitPos = 0;
365     sal_Int32 nVSplitPos = 0;
366     // active pane default
367     sal_Int16 nActivePane = API_SPLITPANE_BOTTOMLEFT;
368 
369     // freeze/split position
370     if( (xModel->mnPaneState == XML_frozen) || (xModel->mnPaneState == XML_frozenSplit) )
371     {
372         /*  Frozen panes: handle split position as row/column positions.
373             #i35812# Excel uses number of visible rows/columns in the
374                 frozen area (rows/columns scolled outside are not included),
375                 Calc uses absolute position of first unfrozen row/column. */
376         const ScAddress& rMaxApiPos = getAddressConverter().getMaxApiAddress();
377         if( (xModel->mfSplitX >= 1.0) && ( xModel->maFirstPos.Col() + xModel->mfSplitX <= rMaxApiPos.Col() ) )
378             nHSplitPos = static_cast< sal_Int32 >( xModel->maFirstPos.Col() + xModel->mfSplitX );
379         nHSplitMode = (nHSplitPos > 0) ? API_SPLITMODE_FREEZE : API_SPLITMODE_NONE;
380         if( (xModel->mfSplitY >= 1.0) && ( xModel->maFirstPos.Row() + xModel->mfSplitY <= rMaxApiPos.Row() ) )
381             nVSplitPos = static_cast< sal_Int32 >( xModel->maFirstPos.Row() + xModel->mfSplitY );
382         nVSplitMode = (nVSplitPos > 0) ? API_SPLITMODE_FREEZE : API_SPLITMODE_NONE;
383     }
384     else if( xModel->mnPaneState == XML_split )
385     {
386         // split window: view settings API uses twips...
387         nHSplitPos = getLimitedValue< sal_Int32, double >( xModel->mfSplitX + 0.5, 0, SAL_MAX_INT32 );
388         nHSplitMode = (nHSplitPos > 0) ? API_SPLITMODE_SPLIT : API_SPLITMODE_NONE;
389         nVSplitPos = getLimitedValue< sal_Int32, double >( xModel->mfSplitY + 0.5, 0, SAL_MAX_INT32 );
390         nVSplitMode = (nVSplitPos > 0) ? API_SPLITMODE_SPLIT : API_SPLITMODE_NONE;
391     }
392 
393     // active pane
394     switch( xModel->mnActivePaneId )
395     {
396         // no horizontal split -> always use left panes
397         // no vertical split -> always use *bottom* panes
398         case XML_topLeft:
399             nActivePane = (nVSplitMode == API_SPLITMODE_NONE) ? API_SPLITPANE_BOTTOMLEFT : API_SPLITPANE_TOPLEFT;
400         break;
401         case XML_topRight:
402             nActivePane = (nHSplitMode == API_SPLITMODE_NONE) ?
403                 ((nVSplitMode == API_SPLITMODE_NONE) ? API_SPLITPANE_BOTTOMLEFT : API_SPLITPANE_TOPLEFT) :
404                 ((nVSplitMode == API_SPLITMODE_NONE) ? API_SPLITPANE_BOTTOMRIGHT : API_SPLITPANE_TOPRIGHT);
405         break;
406         case XML_bottomLeft:
407             nActivePane = API_SPLITPANE_BOTTOMLEFT;
408         break;
409         case XML_bottomRight:
410             nActivePane = (nHSplitMode == API_SPLITMODE_NONE) ? API_SPLITPANE_BOTTOMLEFT : API_SPLITPANE_BOTTOMRIGHT;
411         break;
412     }
413 
414     // write the sheet view settings into the property sequence
415     PropertyMap aPropMap;
416     aPropMap.setProperty( PROP_TableSelected, bSelected);
417     aPropMap.setProperty( PROP_CursorPositionX, aCursor.Col() );
418     aPropMap.setProperty( PROP_CursorPositionY, aCursor.Row() );
419     aPropMap.setProperty( PROP_HorizontalSplitMode, nHSplitMode);
420     aPropMap.setProperty( PROP_VerticalSplitMode, nVSplitMode);
421     aPropMap.setProperty( PROP_HorizontalSplitPositionTwips, nHSplitPos);
422     aPropMap.setProperty( PROP_VerticalSplitPositionTwips, nVSplitPos);
423     aPropMap.setProperty( PROP_ActiveSplitRange, nActivePane);
424     aPropMap.setProperty( PROP_PositionLeft, aFirstPos.Col() );
425     aPropMap.setProperty( PROP_PositionTop, aFirstPos.Row() );
426     aPropMap.setProperty( PROP_PositionRight, xModel->maSecondPos.Col() );
427     aPropMap.setProperty( PROP_PositionBottom, ((nVSplitPos > 0) ? xModel->maSecondPos.Row() : xModel->maFirstPos.Row() ) );
428     aPropMap.setProperty( PROP_ZoomType, API_ZOOMTYPE_PERCENT);
429     aPropMap.setProperty( PROP_ZoomValue, static_cast< sal_Int16 >( xModel->getNormalZoom() ));
430     aPropMap.setProperty( PROP_PageViewZoomValue, static_cast< sal_Int16 >( xModel->getPageBreakZoom() ));
431     aPropMap.setProperty( PROP_GridColor, xModel->getGridColor( getBaseFilter() ));
432     aPropMap.setProperty( PROP_ShowPageBreakPreview, xModel->isPageBreakPreview());
433     aPropMap.setProperty( PROP_ShowFormulas, xModel->mbShowFormulas);
434     aPropMap.setProperty( PROP_ShowGrid, xModel->mbShowGrid);
435     aPropMap.setProperty( PROP_HasColumnRowHeaders, xModel->mbShowHeadings);
436     aPropMap.setProperty( PROP_ShowZeroValues, xModel->mbShowZeros);
437     aPropMap.setProperty( PROP_IsOutlineSymbolsSet, xModel->mbShowOutline);
438 
439     // store sheet view settings in global view settings object
440     getViewSettings().setSheetViewSettings( getSheetIndex(), xModel, Any( aPropMap.makePropertyValueSequence() ) );
441 }
442 
isSheetRightToLeft() const443 bool SheetViewSettings::isSheetRightToLeft() const
444 {
445     return !maSheetViews.empty() && maSheetViews.front()->mbRightToLeft;
446 }
447 
448 // private --------------------------------------------------------------------
449 
createSheetView()450 SheetViewModelRef SheetViewSettings::createSheetView()
451 {
452     SheetViewModelRef xModel( new SheetViewModel );
453     maSheetViews.push_back( xModel );
454     return xModel;
455 }
456 
WorkbookViewModel()457 WorkbookViewModel::WorkbookViewModel() :
458     mnWinX( 0 ),
459     mnWinY( 0 ),
460     mnWinWidth( 0 ),
461     mnWinHeight( 0 ),
462     mnActiveSheet( 0 ),
463     mnFirstVisSheet( 0 ),
464     mnTabBarWidth( OOX_BOOKVIEW_TABBARRATIO_DEF ),
465     mnVisibility( XML_visible ),
466     mbShowTabBar( true ),
467     mbShowHorScroll( true ),
468     mbShowVerScroll( true ),
469     mbMinimized( false )
470 {
471 }
472 
ViewSettings(const WorkbookHelper & rHelper)473 ViewSettings::ViewSettings( const WorkbookHelper& rHelper ) :
474     WorkbookHelper( rHelper ),
475     mbValidOleSize( false )
476 {
477 }
478 
importWorkbookView(const AttributeList & rAttribs)479 void ViewSettings::importWorkbookView( const AttributeList& rAttribs )
480 {
481     WorkbookViewModel& rModel = createWorkbookView();
482     rModel.mnWinX          = rAttribs.getInteger( XML_xWindow, 0 );
483     rModel.mnWinY          = rAttribs.getInteger( XML_yWindow, 0 );
484     rModel.mnWinWidth      = rAttribs.getInteger( XML_windowWidth, 0 );
485     rModel.mnWinHeight     = rAttribs.getInteger( XML_windowHeight, 0 );
486     rModel.mnActiveSheet   = rAttribs.getInteger( XML_activeTab, 0 );
487     rModel.mnFirstVisSheet = rAttribs.getInteger( XML_firstSheet, 0 );
488     rModel.mnTabBarWidth   = rAttribs.getInteger( XML_tabRatio, 600 );
489     rModel.mnVisibility    = rAttribs.getToken( XML_visibility, XML_visible );
490     rModel.mbShowTabBar    = rAttribs.getBool( XML_showSheetTabs, true );
491     rModel.mbShowHorScroll = rAttribs.getBool( XML_showHorizontalScroll, true );
492     rModel.mbShowVerScroll = rAttribs.getBool( XML_showVerticalScroll, true );
493     rModel.mbMinimized     = rAttribs.getBool( XML_minimized, false );
494 }
495 
importOleSize(const AttributeList & rAttribs)496 void ViewSettings::importOleSize( const AttributeList& rAttribs )
497 {
498     OUString aRange = rAttribs.getString( XML_ref, OUString() );
499     mbValidOleSize = getAddressConverter().convertToCellRange( maOleSize, aRange, 0, true, false );
500 }
501 
importWorkbookView(SequenceInputStream & rStrm)502 void ViewSettings::importWorkbookView( SequenceInputStream& rStrm )
503 {
504     WorkbookViewModel& rModel = createWorkbookView();
505     sal_uInt8 nFlags;
506     rModel.mnWinX = rStrm.readInt32();
507     rModel.mnWinY = rStrm.readInt32();
508     rModel.mnWinWidth = rStrm.readInt32();
509     rModel.mnWinHeight = rStrm.readInt32();
510     rModel.mnTabBarWidth = rStrm.readInt32();
511     rModel.mnFirstVisSheet = rStrm.readInt32();
512     rModel.mnActiveSheet = rStrm.readInt32();
513     nFlags = rStrm.readuChar();
514     rModel.mnVisibility    = getFlagValue( nFlags, BIFF12_WBVIEW_HIDDEN, XML_hidden, XML_visible );
515     rModel.mbShowTabBar    = getFlag( nFlags, BIFF12_WBVIEW_SHOWTABBAR );
516     rModel.mbShowHorScroll = getFlag( nFlags, BIFF12_WBVIEW_SHOWHORSCROLL );
517     rModel.mbShowVerScroll = getFlag( nFlags, BIFF12_WBVIEW_SHOWVERSCROLL );
518     rModel.mbMinimized     = getFlag( nFlags, BIFF12_WBVIEW_MINIMIZED );
519 }
520 
importOleSize(SequenceInputStream & rStrm)521 void ViewSettings::importOleSize( SequenceInputStream& rStrm )
522 {
523     BinRange aBinRange;
524     rStrm >> aBinRange;
525     mbValidOleSize = getAddressConverter().convertToCellRange( maOleSize, aBinRange, 0, true, false );
526 }
527 
setSheetViewSettings(sal_Int16 nSheet,const SheetViewModelRef & rxSheetView,const Any & rProperties)528 void ViewSettings::setSheetViewSettings( sal_Int16 nSheet, const SheetViewModelRef& rxSheetView, const Any& rProperties )
529 {
530     maSheetViews[ nSheet ] = rxSheetView;
531     maSheetProps[ nSheet ] = rProperties;
532 }
533 
setSheetUsedArea(const ScRange & rUsedArea)534 void ViewSettings::setSheetUsedArea( const ScRange& rUsedArea )
535 {
536     assert( rUsedArea.IsValid() );
537     maSheetUsedAreas[ rUsedArea.aStart.Tab() ] = rUsedArea;
538 }
539 
finalizeImport()540 void ViewSettings::finalizeImport()
541 {
542     const WorksheetBuffer& rWorksheets = getWorksheets();
543     if( rWorksheets.getWorksheetCount() <= 0 ) return;
544 
545     // force creation of workbook view model to get the Excel defaults
546     const WorkbookViewModel& rModel = maBookViews.empty() ? createWorkbookView() : *maBookViews.front();
547 
548     // show object mode is part of workbook settings
549     sal_Int16 nShowMode = getWorkbookSettings().getApiShowObjectMode();
550 
551     // view settings for all sheets
552     Reference< XNameContainer > xSheetsNC = NamedPropertyValues::create( getBaseFilter().getComponentContext() );
553     if( !xSheetsNC.is() ) return;
554     for( const auto& [rWorksheet, rObj] : maSheetProps )
555         ContainerHelper::insertByName( xSheetsNC, rWorksheets.getCalcSheetName( rWorksheet ), rObj );
556 
557     // use active sheet to set sheet properties that are document-global in Calc
558     sal_Int16 nActiveSheet = getActiveCalcSheet();
559     SheetViewModelRef& rxActiveSheetView = maSheetViews[ nActiveSheet ];
560     OSL_ENSURE( rxActiveSheetView.get(), "ViewSettings::finalizeImport - missing active sheet view settings" );
561     if( !rxActiveSheetView )
562         rxActiveSheetView.reset( new SheetViewModel );
563 
564     Reference< XIndexContainer > xContainer = IndexedPropertyValues::create( getBaseFilter().getComponentContext() );
565     if( xContainer.is() ) try
566     {
567         PropertyMap aPropMap;
568         aPropMap.setProperty( PROP_Tables, xSheetsNC);
569         aPropMap.setProperty( PROP_ActiveTable, rWorksheets.getCalcSheetName( nActiveSheet ));
570         aPropMap.setProperty( PROP_HasHorizontalScrollBar, rModel.mbShowHorScroll);
571         aPropMap.setProperty( PROP_HasVerticalScrollBar, rModel.mbShowVerScroll);
572         aPropMap.setProperty( PROP_HasSheetTabs, rModel.mbShowTabBar);
573         aPropMap.setProperty( PROP_RelativeHorizontalTabbarWidth, double( rModel.mnTabBarWidth / 1000.0 ));
574         aPropMap.setProperty( PROP_ShowObjects, nShowMode);
575         aPropMap.setProperty( PROP_ShowCharts, nShowMode);
576         aPropMap.setProperty( PROP_ShowDrawing, nShowMode);
577         aPropMap.setProperty( PROP_GridColor, rxActiveSheetView->getGridColor( getBaseFilter() ));
578         aPropMap.setProperty( PROP_ShowPageBreakPreview, rxActiveSheetView->isPageBreakPreview());
579         aPropMap.setProperty( PROP_ShowFormulas, rxActiveSheetView->mbShowFormulas);
580         aPropMap.setProperty( PROP_ShowGrid, rxActiveSheetView->mbShowGrid);
581         aPropMap.setProperty( PROP_HasColumnRowHeaders, rxActiveSheetView->mbShowHeadings);
582         aPropMap.setProperty( PROP_ShowZeroValues, rxActiveSheetView->mbShowZeros);
583         aPropMap.setProperty( PROP_IsOutlineSymbolsSet, rxActiveSheetView->mbShowOutline);
584 
585         xContainer->insertByIndex( 0, Any( aPropMap.makePropertyValueSequence() ) );
586         Reference< XViewDataSupplier > xViewDataSuppl( getDocument(), UNO_QUERY_THROW );
587         xViewDataSuppl->setViewData( xContainer );
588     }
589     catch( Exception& )
590     {
591         OSL_FAIL( "ViewSettings::finalizeImport - cannot create document view settings" );
592     }
593 
594     /*  Set visible area to be used if this document is an embedded OLE object.
595         #i44077# If a new OLE object is inserted from file, there is no OLESIZE
596         record in the Excel file. In this case, use the used area calculated
597         from file contents (used cells and drawing objects). */
598     maOleSize.aStart.SetTab( nActiveSheet );
599     maOleSize.aEnd.SetTab( nActiveSheet );
600     const ScRange* pVisibleArea = mbValidOleSize ?
601         &maOleSize : ContainerHelper::getMapElement( maSheetUsedAreas, nActiveSheet );
602     if( pVisibleArea )
603     {
604         // calculate the visible area in units of 1/100 mm
605         PropertySet aRangeProp( getCellRangeFromDoc( *pVisibleArea ) );
606         css::awt::Point aPos;
607         css::awt::Size aSize;
608         if( aRangeProp.getProperty( aPos, PROP_Position ) && aRangeProp.getProperty( aSize, PROP_Size ) )
609         {
610             // set the visible area as sequence of long at the media descriptor
611             Sequence< sal_Int32 > aWinExtent( 4 );
612             aWinExtent[ 0 ] = aPos.X;
613             aWinExtent[ 1 ] = aPos.Y;
614             aWinExtent[ 2 ] = aPos.X + aSize.Width;
615             aWinExtent[ 3 ] = aPos.Y + aSize.Height;
616             getBaseFilter().getMediaDescriptor()[ "WinExtent" ] <<= aWinExtent;
617         }
618     }
619 }
620 
getActiveCalcSheet() const621 sal_Int16 ViewSettings::getActiveCalcSheet() const
622 {
623     return maBookViews.empty() ? 0 : ::std::max< sal_Int16 >( getWorksheets().getCalcSheetIndex( maBookViews.front()->mnActiveSheet ), 0 );
624 }
625 
626 // private --------------------------------------------------------------------
627 
createWorkbookView()628 WorkbookViewModel& ViewSettings::createWorkbookView()
629 {
630     WorkbookViewModelRef xModel( new WorkbookViewModel );
631     maBookViews.push_back( xModel );
632     return *xModel;
633 }
634 
635 } // namespace xls
636 } // namespace oox
637 
638 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
639