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