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/worksheetbuffer.hxx" 29 30 #include <com/sun/star/container/XIndexAccess.hpp> 31 #include <com/sun/star/container/XNameAccess.hpp> 32 #include <com/sun/star/container/XNamed.hpp> 33 #include <com/sun/star/sheet/XExternalSheetName.hpp> 34 #include <com/sun/star/sheet/XSheetLinkable.hpp> 35 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp> 36 #include <rtl/ustrbuf.hxx> 37 #include "oox/core/filterbase.hxx" 38 #include "oox/helper/attributelist.hxx" 39 #include "oox/helper/containerhelper.hxx" 40 #include "oox/helper/propertyset.hxx" 41 #include "oox/xls/biffinputstream.hxx" 42 #include "oox/xls/excelhandlers.hxx" 43 44 namespace oox { 45 namespace xls { 46 47 // ============================================================================ 48 49 using namespace ::com::sun::star::container; 50 using namespace ::com::sun::star::sheet; 51 using namespace ::com::sun::star::uno; 52 53 using ::rtl::OUString; 54 using ::rtl::OUStringBuffer; 55 56 // ============================================================================ 57 58 SheetInfoModel::SheetInfoModel() : 59 mnBiffHandle( -1 ), 60 mnSheetId( -1 ), 61 mnState( XML_visible ) 62 { 63 } 64 65 // ============================================================================ 66 67 WorksheetBuffer::WorksheetBuffer( const WorkbookHelper& rHelper ) : 68 WorkbookHelper( rHelper ) 69 { 70 } 71 72 /*static*/ OUString WorksheetBuffer::getBaseFileName( const OUString& rUrl ) 73 { 74 sal_Int32 nFileNamePos = ::std::max< sal_Int32 >( rUrl.lastIndexOf( '/' ) + 1, 0 ); 75 sal_Int32 nExtPos = rUrl.lastIndexOf( '.' ); 76 if( nExtPos <= nFileNamePos ) nExtPos = rUrl.getLength(); 77 return rUrl.copy( nFileNamePos, nExtPos - nFileNamePos ); 78 } 79 80 void WorksheetBuffer::initializeSingleSheet() 81 { 82 OSL_ENSURE( maSheetInfos.empty(), "WorksheetBuffer::initializeSingleSheet - invalid call" ); 83 SheetInfoModel aModel; 84 aModel.maName = getBaseFileName( getBaseFilter().getFileUrl() ); 85 insertSheet( aModel ); 86 } 87 88 void WorksheetBuffer::importSheet( const AttributeList& rAttribs ) 89 { 90 SheetInfoModel aModel; 91 aModel.maRelId = rAttribs.getString( R_TOKEN( id ), OUString() ); 92 aModel.maName = rAttribs.getXString( XML_name, OUString() ); 93 aModel.mnSheetId = rAttribs.getInteger( XML_sheetId, -1 ); 94 aModel.mnState = rAttribs.getToken( XML_state, XML_visible ); 95 insertSheet( aModel ); 96 } 97 98 void WorksheetBuffer::importSheet( SequenceInputStream& rStrm ) 99 { 100 sal_Int32 nState; 101 SheetInfoModel aModel; 102 rStrm >> nState >> aModel.mnSheetId >> aModel.maRelId >> aModel.maName; 103 static const sal_Int32 spnStates[] = { XML_visible, XML_hidden, XML_veryHidden }; 104 aModel.mnState = STATIC_ARRAY_SELECT( spnStates, nState, XML_visible ); 105 insertSheet( aModel ); 106 } 107 108 void WorksheetBuffer::importSheet( BiffInputStream& rStrm ) 109 { 110 SheetInfoModel aModel; 111 if( getBiff() >= BIFF5 ) 112 { 113 rStrm.enableDecoder( false ); 114 aModel.mnBiffHandle = rStrm.readuInt32(); 115 rStrm.enableDecoder( true ); 116 sal_uInt16 nState = rStrm.readuInt16(); 117 static const sal_Int32 spnStates[] = { XML_visible, XML_hidden, XML_veryHidden }; 118 aModel.mnState = STATIC_ARRAY_SELECT( spnStates, nState, XML_visible ); 119 } 120 aModel.maName = (getBiff() == BIFF8) ? 121 rStrm.readUniStringBody( rStrm.readuInt8() ) : 122 rStrm.readByteStringUC( false, getTextEncoding() ); 123 insertSheet( aModel ); 124 } 125 126 sal_Int16 WorksheetBuffer::insertEmptySheet( const OUString& rPreferredName, bool bVisible ) 127 { 128 return createSheet( rPreferredName, SAL_MAX_INT32, bVisible ).first; 129 } 130 131 sal_Int32 WorksheetBuffer::getWorksheetCount() const 132 { 133 return static_cast< sal_Int32 >( maSheetInfos.size() ); 134 } 135 136 OUString WorksheetBuffer::getWorksheetRelId( sal_Int32 nWorksheet ) const 137 { 138 const SheetInfo* pSheetInfo = maSheetInfos.get( nWorksheet ).get(); 139 return pSheetInfo ? pSheetInfo->maRelId : OUString(); 140 } 141 142 sal_Int64 WorksheetBuffer::getBiffRecordHandle( sal_Int32 nWorksheet ) const 143 { 144 const SheetInfo* pSheetInfo = maSheetInfos.get( nWorksheet ).get(); 145 return pSheetInfo ? pSheetInfo->mnBiffHandle : -1; 146 } 147 148 sal_Int16 WorksheetBuffer::getCalcSheetIndex( sal_Int32 nWorksheet ) const 149 { 150 const SheetInfo* pSheetInfo = maSheetInfos.get( nWorksheet ).get(); 151 return pSheetInfo ? pSheetInfo->mnCalcSheet : -1; 152 } 153 154 OUString WorksheetBuffer::getCalcSheetName( sal_Int32 nWorksheet ) const 155 { 156 const SheetInfo* pSheetInfo = maSheetInfos.get( nWorksheet ).get(); 157 return pSheetInfo ? pSheetInfo->maCalcName : OUString(); 158 } 159 160 sal_Int16 WorksheetBuffer::getCalcSheetIndex( const OUString& rWorksheetName ) const 161 { 162 const SheetInfo* pSheetInfo = maSheetInfosByName.get( rWorksheetName ).get(); 163 return pSheetInfo ? pSheetInfo->mnCalcSheet : -1; 164 } 165 166 OUString WorksheetBuffer::getCalcSheetName( const OUString& rWorksheetName ) const 167 { 168 if( const SheetInfo* pSheetInfo = maSheetInfosByName.get( rWorksheetName ).get() ) 169 { 170 bool bIsQuoted = pSheetInfo->maName != rWorksheetName; 171 return bIsQuoted ? pSheetInfo->maCalcQuotedName : pSheetInfo->maCalcName; 172 } 173 return OUString(); 174 } 175 176 // private -------------------------------------------------------------------- 177 178 namespace { 179 180 OUString lclQuoteName( const OUString& rName ) 181 { 182 OUStringBuffer aBuffer( rName ); 183 // duplicate all quote characters 184 for( sal_Int32 nPos = aBuffer.getLength() - 1; nPos >= 0; --nPos ) 185 if( aBuffer.charAt( nPos ) == '\'' ) 186 aBuffer.insert( nPos, sal_Unicode( '\'' ) ); 187 // add outer quotes and return 188 return aBuffer.insert( 0, sal_Unicode( '\'' ) ).append( sal_Unicode( '\'' ) ).makeStringAndClear(); 189 } 190 191 } // namespace 192 193 WorksheetBuffer::SheetInfo::SheetInfo( const SheetInfoModel& rModel, sal_Int16 nCalcSheet, const OUString& rCalcName ) : 194 SheetInfoModel( rModel ), 195 maCalcName( rCalcName ), 196 maCalcQuotedName( lclQuoteName( rCalcName ) ), 197 mnCalcSheet( nCalcSheet ) 198 { 199 } 200 201 WorksheetBuffer::IndexNamePair WorksheetBuffer::createSheet( const OUString& rPreferredName, sal_Int32 nSheetPos, bool bVisible ) 202 { 203 try 204 { 205 Reference< XSpreadsheets > xSheets( getDocument()->getSheets(), UNO_QUERY_THROW ); 206 Reference< XIndexAccess > xSheetsIA( xSheets, UNO_QUERY_THROW ); 207 Reference< XNameAccess > xSheetsNA( xSheets, UNO_QUERY_THROW ); 208 sal_Int16 nCalcSheet = -1; 209 OUString aSheetName = (rPreferredName.getLength() == 0) ? CREATE_OUSTRING( "Sheet" ) : rPreferredName; 210 PropertySet aPropSet; 211 if( nSheetPos < xSheetsIA->getCount() ) 212 { 213 nCalcSheet = static_cast< sal_Int16 >( nSheetPos ); 214 // existing sheet - try to rename 215 Reference< XNamed > xSheetName( xSheetsIA->getByIndex( nSheetPos ), UNO_QUERY_THROW ); 216 if( xSheetName->getName() != aSheetName ) 217 { 218 aSheetName = ContainerHelper::getUnusedName( xSheetsNA, aSheetName, ' ' ); 219 xSheetName->setName( aSheetName ); 220 } 221 aPropSet.set( xSheetName ); 222 } 223 else 224 { 225 nCalcSheet = static_cast< sal_Int16 >( xSheetsIA->getCount() ); 226 // new sheet - insert with unused name 227 aSheetName = ContainerHelper::getUnusedName( xSheetsNA, aSheetName, ' ' ); 228 xSheets->insertNewByName( aSheetName, nCalcSheet ); 229 aPropSet.set( xSheetsIA->getByIndex( nCalcSheet ) ); 230 } 231 232 // sheet properties 233 aPropSet.setProperty( PROP_IsVisible, bVisible ); 234 235 // return final sheet index if sheet exists 236 return IndexNamePair( nCalcSheet, aSheetName ); 237 } 238 catch( Exception& ) 239 { 240 OSL_ENSURE( false, "WorksheetBuffer::createSheet - cannot insert or rename worksheet" ); 241 } 242 return IndexNamePair( -1, OUString() ); 243 } 244 245 void WorksheetBuffer::insertSheet( const SheetInfoModel& rModel ) 246 { 247 sal_Int32 nWorksheet = static_cast< sal_Int32 >( maSheetInfos.size() ); 248 IndexNamePair aIndexName = createSheet( rModel.maName, nWorksheet, rModel.mnState == XML_visible ); 249 ::boost::shared_ptr< SheetInfo > xSheetInfo( new SheetInfo( rModel, aIndexName.first, aIndexName.second ) ); 250 maSheetInfos.push_back( xSheetInfo ); 251 maSheetInfosByName[ rModel.maName ] = xSheetInfo; 252 maSheetInfosByName[ lclQuoteName( rModel.maName ) ] = xSheetInfo; 253 } 254 255 // ============================================================================ 256 257 } // namespace xls 258 } // namespace oox 259