1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp> 21 #include <com/sun/star/container/XEnumerationAccess.hpp> 22 #include <com/sun/star/frame/XModel.hpp> 23 #include <com/sun/star/uno/XComponentContext.hpp> 24 #include <com/sun/star/document/XTypeDetection.hpp> 25 26 #include <tools/urlobj.hxx> 27 28 #include "excelvbahelper.hxx" 29 #include "vbaworkbook.hxx" 30 #include "vbaworkbooks.hxx" 31 #include <vbahelper/vbahelper.hxx> 32 33 #include <osl/file.hxx> 34 using namespace ::ooo::vba; 35 using namespace ::com::sun::star; 36 37 const sal_Int16 CUSTOM_CHAR = 5; 38 39 static uno::Any 40 getWorkbook( const uno::Reference< uno::XComponentContext >& xContext, 41 const uno::Reference< sheet::XSpreadsheetDocument > &xDoc, 42 const uno::Reference< XHelperInterface >& xParent ) 43 { 44 // FIXME: fine as long as ScVbaWorkbook is stateless ... 45 uno::Reference< frame::XModel > xModel( xDoc, uno::UNO_QUERY ); 46 if( !xModel.is() ) 47 return uno::Any(); 48 49 uno::Reference< excel::XWorkbook > xWb( getVBADocument( xModel ), uno::UNO_QUERY ); 50 if ( xWb.is() ) 51 { 52 return uno::Any( xWb ); 53 } 54 55 ScVbaWorkbook *pWb = new ScVbaWorkbook( xParent, xContext, xModel ); 56 return uno::Any( uno::Reference< excel::XWorkbook > (pWb) ); 57 } 58 59 class WorkBookEnumImpl : public EnumerationHelperImpl 60 { 61 public: 62 /// @throws uno::RuntimeException 63 WorkBookEnumImpl( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration ) : EnumerationHelperImpl( xParent, xContext, xEnumeration ) {} 64 65 virtual uno::Any SAL_CALL nextElement( ) override 66 { 67 uno::Reference< sheet::XSpreadsheetDocument > xDoc( m_xEnumeration->nextElement(), uno::UNO_QUERY_THROW ); 68 return getWorkbook( m_xContext, xDoc, m_xParent ); 69 } 70 71 }; 72 73 ScVbaWorkbooks::ScVbaWorkbooks( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< css::uno::XComponentContext >& xContext ) : ScVbaWorkbooks_BASE( xParent, xContext, VbaDocumentsBase::EXCEL_DOCUMENT ) 74 { 75 } 76 // XEnumerationAccess 77 uno::Type 78 ScVbaWorkbooks::getElementType() 79 { 80 return cppu::UnoType<excel::XWorkbook>::get(); 81 } 82 uno::Reference< container::XEnumeration > 83 ScVbaWorkbooks::createEnumeration() 84 { 85 // #FIXME its possible the WorkBookEnumImpl here doesn't reflect 86 // the state of this object ( although it should ) would be 87 // safer to create an enumeration based on this objects state 88 // rather than one effectively based of the desktop component 89 uno::Reference< container::XEnumerationAccess > xEnumerationAccess( m_xIndexAccess, uno::UNO_QUERY_THROW ); 90 return new WorkBookEnumImpl( mxParent, mxContext, xEnumerationAccess->createEnumeration() ); 91 } 92 93 uno::Any 94 ScVbaWorkbooks::createCollectionObject( const css::uno::Any& aSource ) 95 { 96 uno::Reference< sheet::XSpreadsheetDocument > xDoc( aSource, uno::UNO_QUERY_THROW ); 97 return getWorkbook( mxContext, xDoc, mxParent ); 98 } 99 100 uno::Any SAL_CALL 101 ScVbaWorkbooks::Add( const uno::Any& Template ) 102 { 103 uno::Reference< sheet::XSpreadsheetDocument > xSpreadDoc; 104 sal_Int32 nWorkbookType = 0; 105 OUString aTemplateFileName; 106 if( Template >>= nWorkbookType ) 107 { 108 // nWorkbookType is a constant from XlWBATemplate (added in Excel 2007) 109 // TODO: create chart-sheet if supported by Calc 110 111 xSpreadDoc.set( createDocument(), uno::UNO_QUERY_THROW ); 112 // create a document with one sheet only 113 uno::Reference< sheet::XSpreadsheets > xSheets( xSpreadDoc->getSheets(), uno::UNO_SET_THROW ); 114 uno::Reference< container::XIndexAccess > xSheetsIA( xSheets, uno::UNO_QUERY_THROW ); 115 while( xSheetsIA->getCount() > 1 ) 116 { 117 uno::Reference< container::XNamed > xSheetName( xSheetsIA->getByIndex( xSheetsIA->getCount() - 1 ), uno::UNO_QUERY_THROW ); 118 xSheets->removeByName( xSheetName->getName() ); 119 } 120 } 121 else if( Template >>= aTemplateFileName ) 122 { 123 // TODO: create document from template 124 xSpreadDoc.set( createDocument(), uno::UNO_QUERY_THROW ); 125 } 126 else if( !Template.hasValue() ) 127 { 128 // regular spreadsheet document with configured number of sheets 129 xSpreadDoc.set( createDocument(), uno::UNO_QUERY_THROW ); 130 } 131 else 132 { 133 // illegal argument 134 throw uno::RuntimeException(); 135 } 136 137 // need to set up the document modules ( and vba mode ) here 138 excel::setUpDocumentModules( xSpreadDoc ); 139 if( xSpreadDoc.is() ) 140 return getWorkbook( mxContext, xSpreadDoc, mxParent ); 141 return uno::Any(); 142 } 143 144 void SAL_CALL 145 ScVbaWorkbooks::Close() 146 { 147 } 148 149 bool 150 ScVbaWorkbooks::isTextFile( const OUString& sType ) 151 { 152 // will return true if the file is 153 // a) a variant of a text file 154 // b) a csv file 155 // c) unknown 156 // returning true basically means treat this like a csv file 157 return sType == "generic_Text" || sType.isEmpty(); 158 } 159 160 bool 161 ScVbaWorkbooks::isSpreadSheetFile( const OUString& sType ) 162 { 163 // include calc_QPro etc. ? ( not for the moment anyway ) 164 return sType.startsWith( "calc_MS" ) 165 || sType.startsWith( "MS Excel" ) 166 || sType.startsWith( "calc8" ) 167 || sType.startsWith( "calc_StarOffice" ); 168 } 169 170 OUString 171 ScVbaWorkbooks::getFileFilterType( const OUString& rFileName ) 172 { 173 uno::Reference< document::XTypeDetection > xTypeDetect( mxContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.TypeDetection", mxContext), uno::UNO_QUERY_THROW ); 174 uno::Sequence< beans::PropertyValue > aMediaDesc(1); 175 aMediaDesc[ 0 ].Name = "URL"; 176 aMediaDesc[ 0 ].Value <<= rFileName; 177 OUString sType = xTypeDetect->queryTypeByDescriptor( aMediaDesc, true ); 178 return sType; 179 } 180 181 // #TODO# #FIXME# can any of the unused params below be used? 182 uno::Any SAL_CALL 183 ScVbaWorkbooks::Open( const OUString& rFileName, const uno::Any& /*UpdateLinks*/, const uno::Any& ReadOnly, const uno::Any& Format, const uno::Any& /*Password*/, const uno::Any& /*WriteResPassword*/, const uno::Any& /*IgnoreReadOnlyRecommended*/, const uno::Any& /*Origin*/, const uno::Any& Delimiter, const uno::Any& /*Editable*/, const uno::Any& /*Notify*/, const uno::Any& /*Converter*/, const uno::Any& /*AddToMru*/ ) 184 { 185 // we need to detect if this is a URL, if not then assume it's a file path 186 OUString aURL; 187 INetURLObject aObj; 188 aObj.SetURL( rFileName ); 189 bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid; 190 if ( bIsURL ) 191 aURL = rFileName; 192 else 193 osl::FileBase::getFileURLFromSystemPath( rFileName, aURL ); 194 195 uno::Sequence< beans::PropertyValue > sProps(0); 196 197 OUString sType = getFileFilterType( aURL ); 198 // A text file means it needs to be processed as a csv file 199 if ( isTextFile( sType ) ) 200 { 201 sal_Int32 nIndex = 0; 202 // Values for format 203 // 1 Tabs 204 // 2 Commas 205 // 3 Spaces 206 // 4 Semicolons 207 // 5 Nothing 208 // 6 Custom character (see the Delimiter argument 209 // no format means use the current delimiter 210 sProps.realloc( 3 ); 211 sProps[ nIndex ].Name = "FilterOptions"; 212 sal_Int16 const delims[] { 0 /*default not used*/, 9/*tab*/, 44/*comma*/, 32/*space*/, 59/*semicolon*/ }; 213 214 OUString sFormat; 215 sal_Int16 nFormat = 0; // default indicator 216 217 if ( Format.hasValue() ) 218 { 219 Format >>= nFormat; // val of nFormat overwritten if extracted 220 // validate param 221 if ( nFormat < 1 || nFormat > 6 ) 222 throw uno::RuntimeException("Illegal value for Format" ); 223 } 224 225 sal_Int16 nDelim = getCurrentDelim(); 226 227 if ( nFormat > 0 && nFormat < CUSTOM_CHAR ) 228 { 229 nDelim = delims[ nFormat ]; 230 } 231 else if ( nFormat > CUSTOM_CHAR ) 232 { 233 // Need to check Delimiter param 234 if ( !Delimiter.hasValue() ) 235 throw uno::RuntimeException("Expected value for Delimiter" ); 236 OUString sStr; 237 Delimiter >>= sStr; 238 if ( sStr.isEmpty() ) 239 throw uno::RuntimeException("Incorrect value for Delimiter" ); 240 241 nDelim = sStr[0]; 242 243 } 244 245 getCurrentDelim() = nDelim; //set new current 246 247 sFormat = OUString::number( nDelim ) + ",34,0,1"; 248 sProps[ nIndex++ ].Value <<= sFormat; 249 sProps[ nIndex ].Name = "FilterName"; 250 sProps[ nIndex++ ].Value <<= OUString( SC_TEXT_CSV_FILTER_NAME ); 251 // Ensure WORKAROUND_CSV_TXT_BUG_i60158 gets called in typedetection.cxx so 252 // csv is forced for deep detected 'writerxxx' types 253 sProps[ nIndex ].Name = "DocumentService"; 254 sProps[ nIndex ].Value <<= OUString("com.sun.star.sheet.SpreadsheetDocument"); 255 } 256 else if ( !isSpreadSheetFile( sType ) ) 257 throw uno::RuntimeException("Bad Format" ); 258 259 uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( openDocument( rFileName, ReadOnly, sProps ), uno::UNO_QUERY_THROW ); 260 uno::Any aRet = getWorkbook( mxContext, xSpreadDoc, mxParent ); 261 uno::Reference< excel::XWorkbook > xWBook( aRet, uno::UNO_QUERY ); 262 if ( xWBook.is() ) 263 xWBook->Activate(); 264 return aRet; 265 } 266 267 OUString 268 ScVbaWorkbooks::getServiceImplName() 269 { 270 return "ScVbaWorkbooks"; 271 } 272 273 css::uno::Sequence<OUString> 274 ScVbaWorkbooks::getServiceNames() 275 { 276 static uno::Sequence< OUString > const sNames 277 { 278 "ooo.vba.excel.Workbooks" 279 }; 280 return sNames; 281 } 282 283 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 284
