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 60 ScenarioCellModel::ScenarioCellModel() : 61 mnNumFmtId( 0 ), 62 mbDeleted( false ) 63 { 64 } 65 66 // ---------------------------------------------------------------------------- 67 68 ScenarioModel::ScenarioModel() : 69 mbLocked( false ), 70 mbHidden( false ) 71 { 72 } 73 74 // ---------------------------------------------------------------------------- 75 76 Scenario::Scenario( const WorkbookHelper& rHelper, sal_Int16 nSheet ) : 77 WorkbookHelper( rHelper ), 78 mnSheet( nSheet ) 79 { 80 } 81 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 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 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 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 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 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 211 SheetScenariosModel::SheetScenariosModel() : 212 mnCurrent( 0 ), 213 mnShown( 0 ) 214 { 215 } 216 217 // ---------------------------------------------------------------------------- 218 219 SheetScenarios::SheetScenarios( const WorkbookHelper& rHelper, sal_Int16 nSheet ) : 220 WorkbookHelper( rHelper ), 221 mnSheet( nSheet ) 222 { 223 } 224 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 231 void SheetScenarios::importScenarios( SequenceInputStream& rStrm ) 232 { 233 maModel.mnCurrent = rStrm.readuInt16(); 234 maModel.mnShown = rStrm.readuInt16(); 235 } 236 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 248 Scenario& SheetScenarios::createScenario() 249 { 250 ScenarioVector::value_type xScenario( new Scenario( *this, mnSheet ) ); 251 maScenarios.push_back( xScenario ); 252 return *xScenario; 253 } 254 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 274 ScenarioBuffer::ScenarioBuffer( const WorkbookHelper& rHelper ) : 275 WorkbookHelper( rHelper ) 276 { 277 } 278 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 287 void ScenarioBuffer::finalizeImport() 288 { 289 maSheetScenarios.forEachMem( &SheetScenarios::finalizeImport ); 290 } 291 292 // ============================================================================ 293 294 } // namespace xls 295 } // namespace oox 296