1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include "oox/xls/scenariobuffer.hxx"
25
26 #include <com/sun/star/container/XIndexAccess.hpp>
27 #include <com/sun/star/sheet/XScenario.hpp>
28 #include <com/sun/star/sheet/XScenarios.hpp>
29 #include <com/sun/star/sheet/XScenariosSupplier.hpp>
30 #include <com/sun/star/sheet/XSpreadsheet.hpp>
31 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
32 #include "oox/helper/attributelist.hxx"
33 #include "oox/helper/containerhelper.hxx"
34 #include "oox/helper/propertyset.hxx"
35 #include "oox/xls/addressconverter.hxx"
36 #include "oox/xls/biffinputstream.hxx"
37
38 namespace oox {
39 namespace xls {
40
41 // ============================================================================
42
43 using namespace ::com::sun::star::container;
44 using namespace ::com::sun::star::sheet;
45 using namespace ::com::sun::star::table;
46 using namespace ::com::sun::star::uno;
47
48 using ::rtl::OUString;
49
50 // ============================================================================
51
52 namespace {
53
54 const sal_Int32 BIFF_SCENARIO_DELETED = 0x4000;
55
56 } // namespace
57
58 // ============================================================================
59
ScenarioCellModel()60 ScenarioCellModel::ScenarioCellModel() :
61 mnNumFmtId( 0 ),
62 mbDeleted( false )
63 {
64 }
65
66 // ----------------------------------------------------------------------------
67
ScenarioModel()68 ScenarioModel::ScenarioModel() :
69 mbLocked( false ),
70 mbHidden( false )
71 {
72 }
73
74 // ----------------------------------------------------------------------------
75
Scenario(const WorkbookHelper & rHelper,sal_Int16 nSheet)76 Scenario::Scenario( const WorkbookHelper& rHelper, sal_Int16 nSheet ) :
77 WorkbookHelper( rHelper ),
78 mnSheet( nSheet )
79 {
80 }
81
importScenario(const AttributeList & rAttribs)82 void Scenario::importScenario( const AttributeList& rAttribs )
83 {
84 maModel.maName = rAttribs.getXString( XML_name, OUString() );
85 maModel.maComment = rAttribs.getXString( XML_comment, OUString() );
86 maModel.maUser = rAttribs.getXString( XML_user, OUString() );
87 maModel.mbLocked = rAttribs.getBool( XML_locked, false );
88 maModel.mbHidden = rAttribs.getBool( XML_hidden, false );
89 }
90
importInputCells(const AttributeList & rAttribs)91 void Scenario::importInputCells( const AttributeList& rAttribs )
92 {
93 ScenarioCellModel aModel;
94 getAddressConverter().convertToCellAddressUnchecked( aModel.maPos, rAttribs.getString( XML_r, OUString() ), mnSheet );
95 aModel.maValue = rAttribs.getXString( XML_val, OUString() );
96 aModel.mnNumFmtId = rAttribs.getInteger( XML_numFmtId, 0 );
97 aModel.mbDeleted = rAttribs.getBool( XML_deleted, false );
98 maCells.push_back( aModel );
99 }
100
importScenario(SequenceInputStream & rStrm)101 void Scenario::importScenario( SequenceInputStream& rStrm )
102 {
103 rStrm.skip( 2 ); // cell count
104 // two longs instead of flag field
105 maModel.mbLocked = rStrm.readInt32() != 0;
106 maModel.mbHidden = rStrm.readInt32() != 0;
107 rStrm >> maModel.maName >> maModel.maComment >> maModel.maUser;
108 }
109
importInputCells(SequenceInputStream & rStrm)110 void Scenario::importInputCells( SequenceInputStream& rStrm )
111 {
112 // TODO: where is the deleted flag?
113 ScenarioCellModel aModel;
114 BinAddress aPos;
115 rStrm >> aPos;
116 rStrm.skip( 8 );
117 aModel.mnNumFmtId = rStrm.readuInt16();
118 rStrm >> aModel.maValue;
119 getAddressConverter().convertToCellAddressUnchecked( aModel.maPos, aPos, mnSheet );
120 maCells.push_back( aModel );
121 }
122
importScenario(BiffInputStream & rStrm)123 void Scenario::importScenario( BiffInputStream& rStrm )
124 {
125 sal_uInt16 nCellCount;
126 sal_uInt8 nNameLen, nCommentLen, nUserLen;
127 rStrm >> nCellCount;
128 // two bytes instead of flag field
129 maModel.mbLocked = rStrm.readuInt8() != 0;
130 maModel.mbHidden = rStrm.readuInt8() != 0;
131 rStrm >> nNameLen >> nCommentLen >> nUserLen;
132 maModel.maName = rStrm.readUniStringBody( nNameLen );
133 // user name: before comment (in difference to leading length field), repeated length
134 if( nUserLen > 0 )
135 maModel.maUser = rStrm.readUniString();
136 // comment: repeated length
137 if( nCommentLen > 0 )
138 maModel.maComment = rStrm.readUniString();
139
140 // list of cell addresses
141 for( sal_uInt16 nCell = 0; !rStrm.isEof() && (nCell < nCellCount); ++nCell )
142 {
143 ScenarioCellModel aModel;
144 BinAddress aPos;
145 rStrm >> aPos;
146 // deleted flag is encoded in column index
147 aModel.mbDeleted = getFlag( aPos.mnCol, BIFF_SCENARIO_DELETED );
148 setFlag( aPos.mnCol, BIFF_SCENARIO_DELETED, false );
149 getAddressConverter().convertToCellAddressUnchecked( aModel.maPos, aPos, mnSheet );
150 maCells.push_back( aModel );
151 }
152
153 // list of cell values
154 for( ScenarioCellVector::iterator aIt = maCells.begin(), aEnd = maCells.end(); !rStrm.isEof() && (aIt != aEnd); ++aIt )
155 aIt->maValue = rStrm.readUniString();
156 }
157
finalizeImport()158 void Scenario::finalizeImport()
159 {
160 AddressConverter& rAddrConv = getAddressConverter();
161 ::std::vector< CellRangeAddress > aRanges;
162 for( ScenarioCellVector::iterator aIt = maCells.begin(), aEnd = maCells.end(); aIt != aEnd; ++aIt )
163 if( !aIt->mbDeleted && rAddrConv.checkCellAddress( aIt->maPos, true ) )
164 aRanges.push_back( CellRangeAddress( aIt->maPos.Sheet, aIt->maPos.Column, aIt->maPos.Row, aIt->maPos.Column, aIt->maPos.Row ) );
165
166 if( !aRanges.empty() && (maModel.maName.getLength() > 0) ) try
167 {
168 /* Find an unused name for the scenario (Calc stores scenario data in
169 hidden sheets named after the scenario following the base sheet). */
170 Reference< XNameAccess > xSheetsNA( getDocument()->getSheets(), UNO_QUERY_THROW );
171 OUString aScenName = ContainerHelper::getUnusedName( xSheetsNA, maModel.maName, '_' );
172
173 // create the new scenario sheet
174 Reference< XScenariosSupplier > xScenariosSupp( getSheetFromDoc( mnSheet ), UNO_QUERY_THROW );
175 Reference< XScenarios > xScenarios( xScenariosSupp->getScenarios(), UNO_SET_THROW );
176 xScenarios->addNewByName( aScenName, ContainerHelper::vectorToSequence( aRanges ), maModel.maComment );
177
178 // write scenario cell values
179 Reference< XSpreadsheet > xSheet( getSheetFromDoc( aScenName ), UNO_SET_THROW );
180 for( ScenarioCellVector::iterator aIt = maCells.begin(), aEnd = maCells.end(); aIt != aEnd; ++aIt )
181 {
182 if( !aIt->mbDeleted ) try
183 {
184 // use XCell::setFormula to auto-detect values and strings
185 Reference< XCell > xCell( xSheet->getCellByPosition( aIt->maPos.Column, aIt->maPos.Row ), UNO_SET_THROW );
186 xCell->setFormula( aIt->maValue );
187 }
188 catch( Exception& )
189 {
190 }
191 }
192
193 // scenario properties
194 PropertySet aPropSet( xScenarios->getByName( aScenName ) );
195 aPropSet.setProperty( PROP_IsActive, false );
196 aPropSet.setProperty( PROP_CopyBack, false );
197 aPropSet.setProperty( PROP_CopyStyles, false );
198 aPropSet.setProperty( PROP_CopyFormulas, false );
199 aPropSet.setProperty( PROP_Protected, maModel.mbLocked );
200 // #112621# do not show/print scenario border
201 aPropSet.setProperty( PROP_ShowBorder, false );
202 aPropSet.setProperty( PROP_PrintBorder, false );
203 }
204 catch( Exception& )
205 {
206 }
207 }
208
209 // ============================================================================
210
SheetScenariosModel()211 SheetScenariosModel::SheetScenariosModel() :
212 mnCurrent( 0 ),
213 mnShown( 0 )
214 {
215 }
216
217 // ----------------------------------------------------------------------------
218
SheetScenarios(const WorkbookHelper & rHelper,sal_Int16 nSheet)219 SheetScenarios::SheetScenarios( const WorkbookHelper& rHelper, sal_Int16 nSheet ) :
220 WorkbookHelper( rHelper ),
221 mnSheet( nSheet )
222 {
223 }
224
importScenarios(const AttributeList & rAttribs)225 void SheetScenarios::importScenarios( const AttributeList& rAttribs )
226 {
227 maModel.mnCurrent = rAttribs.getInteger( XML_current, 0 );
228 maModel.mnShown = rAttribs.getInteger( XML_show, 0 );
229 }
230
importScenarios(SequenceInputStream & rStrm)231 void SheetScenarios::importScenarios( SequenceInputStream& rStrm )
232 {
233 maModel.mnCurrent = rStrm.readuInt16();
234 maModel.mnShown = rStrm.readuInt16();
235 }
236
importScenarios(BiffInputStream & rStrm)237 void SheetScenarios::importScenarios( BiffInputStream& rStrm )
238 {
239 rStrm.skip( 2 ); // scenario count
240 maModel.mnCurrent = rStrm.readuInt16();
241 maModel.mnShown = rStrm.readuInt16();
242
243 // read following SCENARIO records
244 while( (rStrm.getNextRecId() == BIFF_ID_SCENARIO) && rStrm.startNextRecord() )
245 createScenario().importScenario( rStrm );
246 }
247
createScenario()248 Scenario& SheetScenarios::createScenario()
249 {
250 ScenarioVector::value_type xScenario( new Scenario( *this, mnSheet ) );
251 maScenarios.push_back( xScenario );
252 return *xScenario;
253 }
254
finalizeImport()255 void SheetScenarios::finalizeImport()
256 {
257 maScenarios.forEachMem( &Scenario::finalizeImport );
258
259 // activate a scenario
260 try
261 {
262 Reference< XScenariosSupplier > xScenariosSupp( getSheetFromDoc( mnSheet ), UNO_QUERY_THROW );
263 Reference< XIndexAccess > xScenariosIA( xScenariosSupp->getScenarios(), UNO_QUERY_THROW );
264 Reference< XScenario > xScenario( xScenariosIA->getByIndex( maModel.mnShown ), UNO_QUERY_THROW );
265 xScenario->apply();
266 }
267 catch( Exception& )
268 {
269 }
270 }
271
272 // ============================================================================
273
ScenarioBuffer(const WorkbookHelper & rHelper)274 ScenarioBuffer::ScenarioBuffer( const WorkbookHelper& rHelper ) :
275 WorkbookHelper( rHelper )
276 {
277 }
278
createSheetScenarios(sal_Int16 nSheet)279 SheetScenarios& ScenarioBuffer::createSheetScenarios( sal_Int16 nSheet )
280 {
281 SheetScenariosMap::mapped_type& rxSheetScens = maSheetScenarios[ nSheet ];
282 if( !rxSheetScens )
283 rxSheetScens.reset( new SheetScenarios( *this, nSheet ) );
284 return *rxSheetScens;
285 }
286
finalizeImport()287 void ScenarioBuffer::finalizeImport()
288 {
289 maSheetScenarios.forEachMem( &SheetScenarios::finalizeImport );
290 }
291
292 // ============================================================================
293
294 } // namespace xls
295 } // namespace oox
296