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