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