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 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sc.hxx" 30 31 #include "tokenuno.hxx" 32 33 #include <com/sun/star/sheet/ComplexReference.hpp> 34 #include <com/sun/star/sheet/ExternalReference.hpp> 35 #include <com/sun/star/sheet/ReferenceFlags.hpp> 36 #include <com/sun/star/sheet/AddressConvention.hpp> 37 #include <com/sun/star/table/CellAddress.hpp> 38 39 #include <svl/itemprop.hxx> 40 41 #include "miscuno.hxx" 42 #include "convuno.hxx" 43 #include "unonames.hxx" 44 #include "unoguard.hxx" 45 #include "token.hxx" 46 #include "compiler.hxx" 47 #include "tokenarray.hxx" 48 #include "docsh.hxx" 49 #include "rangeseq.hxx" 50 #include "externalrefmgr.hxx" 51 52 using namespace ::formula; 53 using namespace ::com::sun::star; 54 55 // ============================================================================ 56 57 const SfxItemPropertyMapEntry* lcl_GetFormulaParserMap() 58 { 59 static SfxItemPropertyMapEntry aFormulaParserMap_Impl[] = 60 { 61 {MAP_CHAR_LEN(SC_UNO_COMPILEFAP), 0, &getBooleanCppuType(), 0, 0 }, 62 {MAP_CHAR_LEN(SC_UNO_COMPILEENGLISH), 0, &getBooleanCppuType(), 0, 0 }, 63 {MAP_CHAR_LEN(SC_UNO_IGNORELEADING), 0, &getBooleanCppuType(), 0, 0 }, 64 {MAP_CHAR_LEN(SC_UNO_FORMULACONVENTION), 0, &getCppuType(&sheet::AddressConvention::UNSPECIFIED), 0, 0 }, 65 {MAP_CHAR_LEN(SC_UNO_OPCODEMAP), 0, &getCppuType((uno::Sequence< sheet::FormulaOpCodeMapEntry >*)0), 0, 0 }, 66 {0,0,0,0,0,0} 67 }; 68 return aFormulaParserMap_Impl; 69 } 70 71 SC_SIMPLE_SERVICE_INFO( ScFormulaParserObj, "ScFormulaParserObj", SC_SERVICENAME_FORMULAPARS ) 72 73 // ============================================================================ 74 75 ScFormulaParserObj::ScFormulaParserObj(ScDocShell* pDocSh) : 76 mpDocShell( pDocSh ), 77 mnConv( sheet::AddressConvention::UNSPECIFIED ), 78 mbEnglish( false ), 79 mbIgnoreSpaces( true ), 80 mbCompileFAP( false ) 81 { 82 mpDocShell->GetDocument()->AddUnoObject(*this); 83 } 84 85 ScFormulaParserObj::~ScFormulaParserObj() 86 { 87 if (mpDocShell) 88 mpDocShell->GetDocument()->RemoveUnoObject(*this); 89 } 90 91 void ScFormulaParserObj::Notify( SfxBroadcaster&, const SfxHint& rHint ) 92 { 93 if ( rHint.ISA( SfxSimpleHint ) && ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING ) 94 mpDocShell = NULL; 95 } 96 97 // XFormulaParser 98 99 void ScFormulaParserObj::SetCompilerFlags( ScCompiler& rCompiler ) const 100 { 101 static const formula::FormulaGrammar::AddressConvention aConvMap[] = { 102 formula::FormulaGrammar::CONV_OOO, // <- AddressConvention::OOO 103 formula::FormulaGrammar::CONV_XL_A1, // <- AddressConvention::XL_A1 104 formula::FormulaGrammar::CONV_XL_R1C1, // <- AddressConvention::XL_R1C1 105 formula::FormulaGrammar::CONV_XL_OOX, // <- AddressConvention::XL_OOX 106 formula::FormulaGrammar::CONV_LOTUS_A1 // <- AddressConvention::LOTUS_A1 107 }; 108 static const sal_Int16 nConvMapCount = sizeof(aConvMap)/sizeof(aConvMap[0]); 109 110 // If mxOpCodeMap is not empty it overrides mbEnglish, and vice versa. We 111 // don't need to initialize things twice. 112 if (mxOpCodeMap.get()) 113 rCompiler.SetFormulaLanguage( mxOpCodeMap ); 114 else 115 { 116 sal_Int32 nFormulaLanguage = mbEnglish ? 117 sheet::FormulaLanguage::ENGLISH : 118 sheet::FormulaLanguage::NATIVE; 119 ScCompiler::OpCodeMapPtr xMap = rCompiler.GetOpCodeMap( nFormulaLanguage); 120 rCompiler.SetFormulaLanguage( xMap); 121 } 122 123 formula::FormulaGrammar::AddressConvention eConv = formula::FormulaGrammar::CONV_UNSPECIFIED; 124 if (mnConv >= 0 && mnConv < nConvMapCount) 125 eConv = aConvMap[mnConv]; 126 127 rCompiler.SetRefConvention( eConv ); 128 129 rCompiler.SetCompileForFAP(mbCompileFAP); 130 131 rCompiler.SetExternalLinks( maExternalLinks); 132 } 133 134 uno::Sequence<sheet::FormulaToken> SAL_CALL ScFormulaParserObj::parseFormula( 135 const rtl::OUString& aFormula, const table::CellAddress& rReferencePos ) 136 throw (uno::RuntimeException) 137 { 138 ScUnoGuard aGuard; 139 uno::Sequence<sheet::FormulaToken> aRet; 140 141 if (mpDocShell) 142 { 143 ScDocument* pDoc = mpDocShell->GetDocument(); 144 ScExternalRefManager::ApiGuard aExtRefGuard(pDoc); 145 146 ScAddress aRefPos( ScAddress::UNINITIALIZED ); 147 ScUnoConversion::FillScAddress( aRefPos, rReferencePos ); 148 ScCompiler aCompiler( pDoc, aRefPos); 149 aCompiler.SetGrammar(pDoc->GetGrammar()); 150 SetCompilerFlags( aCompiler ); 151 152 ScTokenArray* pCode = aCompiler.CompileString( aFormula ); 153 (void)ScTokenConversion::ConvertToTokenSequence( *pDoc, aRet, *pCode ); 154 delete pCode; 155 } 156 157 return aRet; 158 } 159 160 rtl::OUString SAL_CALL ScFormulaParserObj::printFormula( 161 const uno::Sequence<sheet::FormulaToken>& aTokens, const table::CellAddress& rReferencePos ) 162 throw (uno::RuntimeException) 163 { 164 ScUnoGuard aGuard; 165 rtl::OUString aRet; 166 167 if (mpDocShell) 168 { 169 ScDocument* pDoc = mpDocShell->GetDocument(); 170 ScTokenArray aCode; 171 (void)ScTokenConversion::ConvertToTokenArray( *pDoc, aCode, aTokens ); 172 ScAddress aRefPos( ScAddress::UNINITIALIZED ); 173 ScUnoConversion::FillScAddress( aRefPos, rReferencePos ); 174 ScCompiler aCompiler( pDoc, aRefPos, aCode); 175 aCompiler.SetGrammar(pDoc->GetGrammar()); 176 SetCompilerFlags( aCompiler ); 177 178 rtl::OUStringBuffer aBuffer; 179 aCompiler.CreateStringFromTokenArray( aBuffer ); 180 aRet = aBuffer.makeStringAndClear(); 181 } 182 183 return aRet; 184 } 185 186 // XPropertySet 187 188 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScFormulaParserObj::getPropertySetInfo() 189 throw(uno::RuntimeException) 190 { 191 ScUnoGuard aGuard; 192 static uno::Reference< beans::XPropertySetInfo > aRef(new SfxItemPropertySetInfo( lcl_GetFormulaParserMap() )); 193 return aRef; 194 } 195 196 void SAL_CALL ScFormulaParserObj::setPropertyValue( 197 const rtl::OUString& aPropertyName, const uno::Any& aValue ) 198 throw(beans::UnknownPropertyException, beans::PropertyVetoException, 199 lang::IllegalArgumentException, lang::WrappedTargetException, 200 uno::RuntimeException) 201 { 202 ScUnoGuard aGuard; 203 String aString(aPropertyName); 204 if ( aString.EqualsAscii( SC_UNO_COMPILEFAP ) ) 205 { 206 aValue >>= mbCompileFAP; 207 } 208 else if ( aString.EqualsAscii( SC_UNO_COMPILEENGLISH ) ) 209 { 210 bool bOldEnglish = mbEnglish; 211 if (aValue >>= mbEnglish) 212 { 213 // Need to recreate the symbol map to change English property 214 // because the map is const. So for performance reasons set 215 // CompileEnglish _before_ OpCodeMap! 216 if (mxOpCodeMap.get() && mbEnglish != bOldEnglish) 217 { 218 ScDocument* pDoc = mpDocShell->GetDocument(); 219 ScCompiler aCompiler( pDoc, ScAddress()); 220 aCompiler.SetGrammar(pDoc->GetGrammar()); 221 mxOpCodeMap = aCompiler.CreateOpCodeMap( maOpCodeMapping, mbEnglish); 222 } 223 } 224 else 225 throw lang::IllegalArgumentException(); 226 } 227 else if ( aString.EqualsAscii( SC_UNO_FORMULACONVENTION ) ) 228 { 229 aValue >>= mnConv; 230 } 231 else if ( aString.EqualsAscii( SC_UNO_IGNORELEADING ) ) 232 { 233 aValue >>= mbIgnoreSpaces; 234 } 235 else if ( aString.EqualsAscii( SC_UNO_OPCODEMAP ) ) 236 { 237 if (aValue >>= maOpCodeMapping) 238 { 239 ScDocument* pDoc = mpDocShell->GetDocument(); 240 ScCompiler aCompiler( pDoc, ScAddress()); 241 aCompiler.SetGrammar(pDoc->GetGrammar()); 242 mxOpCodeMap = aCompiler.CreateOpCodeMap( maOpCodeMapping, mbEnglish); 243 } 244 else 245 throw lang::IllegalArgumentException(); 246 } 247 else if ( aString.EqualsAscii( SC_UNO_EXTERNALLINKS ) ) 248 { 249 if (!(aValue >>= maExternalLinks)) 250 throw lang::IllegalArgumentException(); 251 } 252 else 253 throw beans::UnknownPropertyException(); 254 } 255 256 uno::Any SAL_CALL ScFormulaParserObj::getPropertyValue( const rtl::OUString& aPropertyName ) 257 throw(beans::UnknownPropertyException, lang::WrappedTargetException, 258 uno::RuntimeException) 259 { 260 ScUnoGuard aGuard; 261 uno::Any aRet; 262 String aString(aPropertyName); 263 if ( aString.EqualsAscii( SC_UNO_COMPILEFAP ) ) 264 { 265 aRet <<= mbCompileFAP; 266 } 267 else if ( aString.EqualsAscii( SC_UNO_COMPILEENGLISH ) ) 268 { 269 aRet <<= mbEnglish; 270 } 271 else if ( aString.EqualsAscii( SC_UNO_FORMULACONVENTION ) ) 272 { 273 aRet <<= mnConv; 274 } 275 else if ( aString.EqualsAscii( SC_UNO_IGNORELEADING ) ) 276 { 277 aRet <<= mbIgnoreSpaces; 278 } 279 else if ( aString.EqualsAscii( SC_UNO_OPCODEMAP ) ) 280 { 281 aRet <<= maOpCodeMapping; 282 } 283 else if ( aString.EqualsAscii( SC_UNO_EXTERNALLINKS ) ) 284 { 285 aRet <<= maExternalLinks; 286 } 287 else 288 throw beans::UnknownPropertyException(); 289 return aRet; 290 } 291 292 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFormulaParserObj ) 293 294 // ============================================================================ 295 296 void lcl_ExternalRefToApi( sheet::SingleReference& rAPI, const ScSingleRefData& rRef ) 297 { 298 rAPI.Column = rRef.nCol; 299 rAPI.Row = rRef.nRow; 300 rAPI.Sheet = 0; 301 rAPI.RelativeColumn = rRef.nRelCol; 302 rAPI.RelativeRow = rRef.nRelRow; 303 rAPI.RelativeSheet = 0; 304 305 sal_Int32 nFlags = 0; 306 if ( rRef.IsColRel() ) nFlags |= sheet::ReferenceFlags::COLUMN_RELATIVE; 307 if ( rRef.IsRowRel() ) nFlags |= sheet::ReferenceFlags::ROW_RELATIVE; 308 if ( rRef.IsColDeleted() ) nFlags |= sheet::ReferenceFlags::COLUMN_DELETED; 309 if ( rRef.IsRowDeleted() ) nFlags |= sheet::ReferenceFlags::ROW_DELETED; 310 if ( rRef.IsFlag3D() ) nFlags |= sheet::ReferenceFlags::SHEET_3D; 311 if ( rRef.IsRelName() ) nFlags |= sheet::ReferenceFlags::RELATIVE_NAME; 312 rAPI.Flags = nFlags; 313 } 314 315 void lcl_SingleRefToApi( sheet::SingleReference& rAPI, const ScSingleRefData& rRef ) 316 { 317 rAPI.Column = rRef.nCol; 318 rAPI.Row = rRef.nRow; 319 rAPI.Sheet = rRef.nTab; 320 rAPI.RelativeColumn = rRef.nRelCol; 321 rAPI.RelativeRow = rRef.nRelRow; 322 rAPI.RelativeSheet = rRef.nRelTab; 323 324 sal_Int32 nFlags = 0; 325 if ( rRef.IsColRel() ) nFlags |= sheet::ReferenceFlags::COLUMN_RELATIVE; 326 if ( rRef.IsRowRel() ) nFlags |= sheet::ReferenceFlags::ROW_RELATIVE; 327 if ( rRef.IsTabRel() ) nFlags |= sheet::ReferenceFlags::SHEET_RELATIVE; 328 if ( rRef.IsColDeleted() ) nFlags |= sheet::ReferenceFlags::COLUMN_DELETED; 329 if ( rRef.IsRowDeleted() ) nFlags |= sheet::ReferenceFlags::ROW_DELETED; 330 if ( rRef.IsTabDeleted() ) nFlags |= sheet::ReferenceFlags::SHEET_DELETED; 331 if ( rRef.IsFlag3D() ) nFlags |= sheet::ReferenceFlags::SHEET_3D; 332 if ( rRef.IsRelName() ) nFlags |= sheet::ReferenceFlags::RELATIVE_NAME; 333 rAPI.Flags = nFlags; 334 } 335 336 // static 337 bool ScTokenConversion::ConvertToTokenArray( ScDocument& rDoc, 338 ScTokenArray& rTokenArray, const uno::Sequence<sheet::FormulaToken>& rSequence ) 339 { 340 return !rTokenArray.Fill(rSequence,rDoc.GetExternalRefManager()); 341 } 342 343 // static 344 bool ScTokenConversion::ConvertToTokenSequence( ScDocument& rDoc, 345 uno::Sequence<sheet::FormulaToken>& rSequence, const ScTokenArray& rTokenArray ) 346 { 347 bool bError = false; 348 349 sal_Int32 nLen = static_cast<sal_Int32>(rTokenArray.GetLen()); 350 formula::FormulaToken** pTokens = rTokenArray.GetArray(); 351 if ( pTokens ) 352 { 353 rSequence.realloc(nLen); 354 for (sal_Int32 nPos=0; nPos<nLen; nPos++) 355 { 356 const formula::FormulaToken& rToken = *pTokens[nPos]; 357 sheet::FormulaToken& rAPI = rSequence[nPos]; 358 359 OpCode eOpCode = rToken.GetOpCode(); 360 // eOpCode may be changed in the following switch/case 361 switch ( rToken.GetType() ) 362 { 363 case svByte: 364 // Only the count of spaces is stored as "long". Parameter count is ignored. 365 if ( eOpCode == ocSpaces ) 366 rAPI.Data <<= (sal_Int32) rToken.GetByte(); 367 else 368 rAPI.Data.clear(); // no data 369 break; 370 case formula::svDouble: 371 rAPI.Data <<= rToken.GetDouble(); 372 break; 373 case formula::svString: 374 rAPI.Data <<= rtl::OUString( rToken.GetString() ); 375 break; 376 case svExternal: 377 // Function name is stored as string. 378 // Byte (parameter count) is ignored. 379 rAPI.Data <<= rtl::OUString( rToken.GetExternal() ); 380 break; 381 case svSingleRef: 382 { 383 sheet::SingleReference aSingleRef; 384 lcl_SingleRefToApi( aSingleRef, static_cast<const ScToken&>(rToken).GetSingleRef() ); 385 rAPI.Data <<= aSingleRef; 386 } 387 break; 388 case formula::svDoubleRef: 389 { 390 sheet::ComplexReference aCompRef; 391 lcl_SingleRefToApi( aCompRef.Reference1, static_cast<const ScToken&>(rToken).GetSingleRef() ); 392 lcl_SingleRefToApi( aCompRef.Reference2, static_cast<const ScToken&>(rToken).GetSingleRef2() ); 393 rAPI.Data <<= aCompRef; 394 } 395 break; 396 case svIndex: 397 rAPI.Data <<= static_cast<sal_Int32>( rToken.GetIndex() ); 398 break; 399 case svMatrix: 400 if (!ScRangeToSequence::FillMixedArray( rAPI.Data, static_cast<const ScToken&>(rToken).GetMatrix(), true)) 401 rAPI.Data.clear(); 402 break; 403 case svExternalSingleRef: 404 { 405 sheet::SingleReference aSingleRef; 406 lcl_ExternalRefToApi( aSingleRef, static_cast<const ScToken&>(rToken).GetSingleRef() ); 407 size_t nCacheId; 408 rDoc.GetExternalRefManager()->getCacheTable( rToken.GetIndex(), rToken.GetString(), false, &nCacheId ); 409 aSingleRef.Sheet = static_cast< sal_Int32 >( nCacheId ); 410 sheet::ExternalReference aExtRef; 411 aExtRef.Index = rToken.GetIndex(); 412 aExtRef.Reference <<= aSingleRef; 413 rAPI.Data <<= aExtRef; 414 eOpCode = ocPush; 415 } 416 break; 417 case svExternalDoubleRef: 418 { 419 sheet::ComplexReference aComplRef; 420 lcl_ExternalRefToApi( aComplRef.Reference1, static_cast<const ScToken&>(rToken).GetSingleRef() ); 421 lcl_ExternalRefToApi( aComplRef.Reference2, static_cast<const ScToken&>(rToken).GetSingleRef2() ); 422 size_t nCacheId; 423 rDoc.GetExternalRefManager()->getCacheTable( rToken.GetIndex(), rToken.GetString(), false, &nCacheId ); 424 aComplRef.Reference1.Sheet = static_cast< sal_Int32 >( nCacheId ); 425 // NOTE: This assumes that cached sheets are in consecutive order! 426 aComplRef.Reference2.Sheet = aComplRef.Reference1.Sheet + (static_cast<const ScToken&>(rToken).GetSingleRef2().nTab - static_cast<const ScToken&>(rToken).GetSingleRef().nTab); 427 sheet::ExternalReference aExtRef; 428 aExtRef.Index = rToken.GetIndex(); 429 aExtRef.Reference <<= aComplRef; 430 rAPI.Data <<= aExtRef; 431 eOpCode = ocPush; 432 } 433 break; 434 case svExternalName: 435 { 436 sheet::ExternalReference aExtRef; 437 aExtRef.Index = rToken.GetIndex(); 438 aExtRef.Reference <<= ::rtl::OUString( rToken.GetString() ); 439 rAPI.Data <<= aExtRef; 440 eOpCode = ocPush; 441 } 442 break; 443 default: 444 DBG_ERROR1( "ScTokenConversion::ConvertToTokenSequence: unhandled token type SvStackVar %d", rToken.GetType()); 445 case svSep: // occurs with ocSep, ocOpen, ocClose, ocArray* 446 case svJump: // occurs with ocIf, ocChose 447 case svMissing: // occurs with ocMissing 448 rAPI.Data.clear(); // no data 449 } 450 rAPI.OpCode = static_cast<sal_Int32>(eOpCode); //! assuming equal values for the moment 451 } 452 } 453 else 454 rSequence.realloc(0); 455 456 return !bError; 457 } 458 459 // ============================================================================ 460 461 ScFormulaOpCodeMapperObj::ScFormulaOpCodeMapperObj(::std::auto_ptr<formula::FormulaCompiler> _pCompiler) 462 : formula::FormulaOpCodeMapperObj(_pCompiler) 463 { 464 } 465 466 // ============================================================================ 467 468