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