1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include "tokenuno.hxx"
23 #include <sal/macros.h>
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>
32 #include <svl/itemprop.hxx>
33 #include <vcl/svapp.hxx>
35 #include "miscuno.hxx"
36 #include "convuno.hxx"
37 #include "unonames.hxx"
39 #include "compiler.hxx"
40 #include "tokenarray.hxx"
42 #include "rangeseq.hxx"
43 #include "externalrefmgr.hxx"
45 using namespace ::formula
;
46 using namespace ::com::sun::star
;
48 // ============================================================================
50 static const SfxItemPropertyMapEntry
* lcl_GetFormulaParserMap()
52 static SfxItemPropertyMapEntry aFormulaParserMap_Impl
[] =
54 {MAP_CHAR_LEN(SC_UNO_COMPILEFAP
), 0, &getBooleanCppuType(), 0, 0 },
55 {MAP_CHAR_LEN(SC_UNO_COMPILEENGLISH
), 0, &getBooleanCppuType(), 0, 0 },
56 {MAP_CHAR_LEN(SC_UNO_IGNORELEADING
), 0, &getBooleanCppuType(), 0, 0 },
57 {MAP_CHAR_LEN(SC_UNO_FORMULACONVENTION
), 0, &getCppuType(&sheet::AddressConvention::UNSPECIFIED
), 0, 0 },
58 {MAP_CHAR_LEN(SC_UNO_OPCODEMAP
), 0, &getCppuType((uno::Sequence
< sheet::FormulaOpCodeMapEntry
>*)0), 0, 0 },
61 return aFormulaParserMap_Impl
;
64 SC_SIMPLE_SERVICE_INFO( ScFormulaParserObj
, "ScFormulaParserObj", SC_SERVICENAME_FORMULAPARS
)
66 // ============================================================================
68 ScFormulaParserObj::ScFormulaParserObj(ScDocShell
* pDocSh
) :
70 mnConv( sheet::AddressConvention::UNSPECIFIED
),
72 mbIgnoreSpaces( true ),
75 mpDocShell
->GetDocument()->AddUnoObject(*this);
78 ScFormulaParserObj::~ScFormulaParserObj()
81 mpDocShell
->GetDocument()->RemoveUnoObject(*this);
84 void ScFormulaParserObj::Notify( SfxBroadcaster
&, const SfxHint
& rHint
)
86 if ( rHint
.ISA( SfxSimpleHint
) && ((const SfxSimpleHint
&)rHint
).GetId() == SFX_HINT_DYING
)
92 void ScFormulaParserObj::SetCompilerFlags( ScCompiler
& rCompiler
) const
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
101 static const sal_Int16 nConvMapCount
= sizeof(aConvMap
)/sizeof(aConvMap
[0]);
103 // If mxOpCodeMap is not empty it overrides mbEnglish, and vice versa. We
104 // don't need to initialize things twice.
105 if (mxOpCodeMap
.get())
106 rCompiler
.SetFormulaLanguage( mxOpCodeMap
);
109 sal_Int32 nFormulaLanguage
= mbEnglish
?
110 sheet::FormulaLanguage::ENGLISH
:
111 sheet::FormulaLanguage::NATIVE
;
112 ScCompiler::OpCodeMapPtr xMap
= rCompiler
.GetOpCodeMap( nFormulaLanguage
);
113 rCompiler
.SetFormulaLanguage( xMap
);
116 formula::FormulaGrammar::AddressConvention eConv
= formula::FormulaGrammar::CONV_UNSPECIFIED
;
117 if (mnConv
>= 0 && mnConv
< nConvMapCount
)
118 eConv
= aConvMap
[mnConv
];
120 rCompiler
.SetRefConvention( eConv
);
122 rCompiler
.SetCompileForFAP(mbCompileFAP
);
124 rCompiler
.SetExternalLinks( maExternalLinks
);
127 uno::Sequence
<sheet::FormulaToken
> SAL_CALL
ScFormulaParserObj::parseFormula(
128 const OUString
& aFormula
, const table::CellAddress
& rReferencePos
)
129 throw (uno::RuntimeException
)
131 SolarMutexGuard aGuard
;
132 uno::Sequence
<sheet::FormulaToken
> aRet
;
136 ScDocument
* pDoc
= mpDocShell
->GetDocument();
137 ScExternalRefManager::ApiGuard
aExtRefGuard(pDoc
);
139 ScAddress
aRefPos( ScAddress::UNINITIALIZED
);
140 ScUnoConversion::FillScAddress( aRefPos
, rReferencePos
);
141 ScCompiler
aCompiler( pDoc
, aRefPos
);
142 aCompiler
.SetGrammar(pDoc
->GetGrammar());
143 SetCompilerFlags( aCompiler
);
145 ScTokenArray
* pCode
= aCompiler
.CompileString( aFormula
);
146 (void)ScTokenConversion::ConvertToTokenSequence( *pDoc
, aRet
, *pCode
);
153 OUString SAL_CALL
ScFormulaParserObj::printFormula(
154 const uno::Sequence
<sheet::FormulaToken
>& aTokens
, const table::CellAddress
& rReferencePos
)
155 throw (uno::RuntimeException
)
157 SolarMutexGuard aGuard
;
162 ScDocument
* pDoc
= mpDocShell
->GetDocument();
164 (void)ScTokenConversion::ConvertToTokenArray( *pDoc
, aCode
, aTokens
);
165 ScAddress
aRefPos( ScAddress::UNINITIALIZED
);
166 ScUnoConversion::FillScAddress( aRefPos
, rReferencePos
);
167 ScCompiler
aCompiler( pDoc
, aRefPos
, aCode
);
168 aCompiler
.SetGrammar(pDoc
->GetGrammar());
169 SetCompilerFlags( aCompiler
);
171 OUStringBuffer aBuffer
;
172 aCompiler
.CreateStringFromTokenArray( aBuffer
);
173 aRet
= aBuffer
.makeStringAndClear();
181 uno::Reference
<beans::XPropertySetInfo
> SAL_CALL
ScFormulaParserObj::getPropertySetInfo()
182 throw(uno::RuntimeException
)
184 SolarMutexGuard aGuard
;
185 static uno::Reference
< beans::XPropertySetInfo
> aRef(new SfxItemPropertySetInfo( lcl_GetFormulaParserMap() ));
189 void SAL_CALL
ScFormulaParserObj::setPropertyValue(
190 const OUString
& aPropertyName
, const uno::Any
& aValue
)
191 throw(beans::UnknownPropertyException
, beans::PropertyVetoException
,
192 lang::IllegalArgumentException
, lang::WrappedTargetException
,
193 uno::RuntimeException
)
195 SolarMutexGuard aGuard
;
196 String
aString(aPropertyName
);
197 if ( aString
.EqualsAscii( SC_UNO_COMPILEFAP
) )
199 aValue
>>= mbCompileFAP
;
201 else if ( aString
.EqualsAscii( SC_UNO_COMPILEENGLISH
) )
203 bool bOldEnglish
= mbEnglish
;
204 if (aValue
>>= mbEnglish
)
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 if (mxOpCodeMap
.get() && mbEnglish
!= bOldEnglish
)
211 ScDocument
* pDoc
= mpDocShell
->GetDocument();
212 ScCompiler
aCompiler( pDoc
, ScAddress());
213 aCompiler
.SetGrammar(pDoc
->GetGrammar());
214 mxOpCodeMap
= aCompiler
.CreateOpCodeMap( maOpCodeMapping
, mbEnglish
);
218 throw lang::IllegalArgumentException();
220 else if ( aString
.EqualsAscii( SC_UNO_FORMULACONVENTION
) )
224 else if ( aString
.EqualsAscii( SC_UNO_IGNORELEADING
) )
226 aValue
>>= mbIgnoreSpaces
;
228 else if ( aString
.EqualsAscii( SC_UNO_OPCODEMAP
) )
230 if (aValue
>>= maOpCodeMapping
)
232 ScDocument
* pDoc
= mpDocShell
->GetDocument();
233 ScCompiler
aCompiler( pDoc
, ScAddress());
234 aCompiler
.SetGrammar(pDoc
->GetGrammar());
235 mxOpCodeMap
= aCompiler
.CreateOpCodeMap( maOpCodeMapping
, mbEnglish
);
238 throw lang::IllegalArgumentException();
240 else if ( aString
.EqualsAscii( SC_UNO_EXTERNALLINKS
) )
242 if (!(aValue
>>= maExternalLinks
))
243 throw lang::IllegalArgumentException();
246 throw beans::UnknownPropertyException();
249 uno::Any SAL_CALL
ScFormulaParserObj::getPropertyValue( const OUString
& aPropertyName
)
250 throw(beans::UnknownPropertyException
, lang::WrappedTargetException
,
251 uno::RuntimeException
)
253 SolarMutexGuard aGuard
;
255 String
aString(aPropertyName
);
256 if ( aString
.EqualsAscii( SC_UNO_COMPILEFAP
) )
258 aRet
<<= mbCompileFAP
;
260 else if ( aString
.EqualsAscii( SC_UNO_COMPILEENGLISH
) )
264 else if ( aString
.EqualsAscii( SC_UNO_FORMULACONVENTION
) )
268 else if ( aString
.EqualsAscii( SC_UNO_IGNORELEADING
) )
270 aRet
<<= mbIgnoreSpaces
;
272 else if ( aString
.EqualsAscii( SC_UNO_OPCODEMAP
) )
274 aRet
<<= maOpCodeMapping
;
276 else if ( aString
.EqualsAscii( SC_UNO_EXTERNALLINKS
) )
278 aRet
<<= maExternalLinks
;
281 throw beans::UnknownPropertyException();
285 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFormulaParserObj
)
287 // ============================================================================
289 static void lcl_ExternalRefToApi( sheet::SingleReference
& rAPI
, const ScSingleRefData
& rRef
)
291 rAPI
.Column
= rRef
.nCol
;
292 rAPI
.Row
= rRef
.nRow
;
294 rAPI
.RelativeColumn
= rRef
.nRelCol
;
295 rAPI
.RelativeRow
= rRef
.nRelRow
;
296 rAPI
.RelativeSheet
= 0;
298 sal_Int32 nFlags
= 0;
299 if ( rRef
.IsColRel() ) nFlags
|= sheet::ReferenceFlags::COLUMN_RELATIVE
;
300 if ( rRef
.IsRowRel() ) nFlags
|= sheet::ReferenceFlags::ROW_RELATIVE
;
301 if ( rRef
.IsColDeleted() ) nFlags
|= sheet::ReferenceFlags::COLUMN_DELETED
;
302 if ( rRef
.IsRowDeleted() ) nFlags
|= sheet::ReferenceFlags::ROW_DELETED
;
303 if ( rRef
.IsFlag3D() ) nFlags
|= sheet::ReferenceFlags::SHEET_3D
;
304 if ( rRef
.IsRelName() ) nFlags
|= sheet::ReferenceFlags::RELATIVE_NAME
;
308 static void lcl_SingleRefToApi( sheet::SingleReference
& rAPI
, const ScSingleRefData
& rRef
)
310 rAPI
.Column
= rRef
.nCol
;
311 rAPI
.Row
= rRef
.nRow
;
312 rAPI
.Sheet
= rRef
.nTab
;
313 rAPI
.RelativeColumn
= rRef
.nRelCol
;
314 rAPI
.RelativeRow
= rRef
.nRelRow
;
315 rAPI
.RelativeSheet
= rRef
.nRelTab
;
317 sal_Int32 nFlags
= 0;
318 if ( rRef
.IsColRel() ) nFlags
|= sheet::ReferenceFlags::COLUMN_RELATIVE
;
319 if ( rRef
.IsRowRel() ) nFlags
|= sheet::ReferenceFlags::ROW_RELATIVE
;
320 if ( rRef
.IsTabRel() ) nFlags
|= sheet::ReferenceFlags::SHEET_RELATIVE
;
321 if ( rRef
.IsColDeleted() ) nFlags
|= sheet::ReferenceFlags::COLUMN_DELETED
;
322 if ( rRef
.IsRowDeleted() ) nFlags
|= sheet::ReferenceFlags::ROW_DELETED
;
323 if ( rRef
.IsTabDeleted() ) nFlags
|= sheet::ReferenceFlags::SHEET_DELETED
;
324 if ( rRef
.IsFlag3D() ) nFlags
|= sheet::ReferenceFlags::SHEET_3D
;
325 if ( rRef
.IsRelName() ) nFlags
|= sheet::ReferenceFlags::RELATIVE_NAME
;
329 bool ScTokenConversion::ConvertToTokenArray( ScDocument
& rDoc
,
330 ScTokenArray
& rTokenArray
, const uno::Sequence
<sheet::FormulaToken
>& rSequence
)
332 return !rTokenArray
.Fill(rSequence
,rDoc
.GetExternalRefManager());
335 bool ScTokenConversion::ConvertToTokenSequence( ScDocument
& rDoc
,
336 uno::Sequence
<sheet::FormulaToken
>& rSequence
, const ScTokenArray
& rTokenArray
)
340 sal_Int32 nLen
= static_cast<sal_Int32
>(rTokenArray
.GetLen());
341 formula::FormulaToken
** pTokens
= rTokenArray
.GetArray();
344 rSequence
.realloc(nLen
);
345 for (sal_Int32 nPos
=0; nPos
<nLen
; nPos
++)
347 const formula::FormulaToken
& rToken
= *pTokens
[nPos
];
348 sheet::FormulaToken
& rAPI
= rSequence
[nPos
];
350 OpCode eOpCode
= rToken
.GetOpCode();
351 // eOpCode may be changed in the following switch/case
352 switch ( rToken
.GetType() )
355 // Only the count of spaces is stored as "long". Parameter count is ignored.
356 if ( eOpCode
== ocSpaces
)
357 rAPI
.Data
<<= (sal_Int32
) rToken
.GetByte();
359 rAPI
.Data
.clear(); // no data
361 case formula::svDouble
:
362 rAPI
.Data
<<= rToken
.GetDouble();
364 case formula::svString
:
365 rAPI
.Data
<<= OUString( rToken
.GetString() );
368 // Function name is stored as string.
369 // Byte (parameter count) is ignored.
370 rAPI
.Data
<<= OUString( rToken
.GetExternal() );
374 sheet::SingleReference aSingleRef
;
375 lcl_SingleRefToApi( aSingleRef
, static_cast<const ScToken
&>(rToken
).GetSingleRef() );
376 rAPI
.Data
<<= aSingleRef
;
379 case formula::svDoubleRef
:
381 sheet::ComplexReference aCompRef
;
382 lcl_SingleRefToApi( aCompRef
.Reference1
, static_cast<const ScToken
&>(rToken
).GetSingleRef() );
383 lcl_SingleRefToApi( aCompRef
.Reference2
, static_cast<const ScToken
&>(rToken
).GetSingleRef2() );
384 rAPI
.Data
<<= aCompRef
;
389 sheet::NameToken aNameToken
;
390 aNameToken
.Index
= static_cast<sal_Int32
>( rToken
.GetIndex() );
391 aNameToken
.Global
= static_cast<sal_Bool
>( rToken
.IsGlobal() );
392 rAPI
.Data
<<= aNameToken
;
396 if (!ScRangeToSequence::FillMixedArray( rAPI
.Data
, static_cast<const ScToken
&>(rToken
).GetMatrix(), true))
399 case svExternalSingleRef
:
401 sheet::SingleReference aSingleRef
;
402 lcl_ExternalRefToApi( aSingleRef
, static_cast<const ScToken
&>(rToken
).GetSingleRef() );
404 rDoc
.GetExternalRefManager()->getCacheTable( rToken
.GetIndex(), rToken
.GetString(), false, &nCacheId
);
405 aSingleRef
.Sheet
= static_cast< sal_Int32
>( nCacheId
);
406 sheet::ExternalReference aExtRef
;
407 aExtRef
.Index
= rToken
.GetIndex();
408 aExtRef
.Reference
<<= aSingleRef
;
409 rAPI
.Data
<<= aExtRef
;
413 case svExternalDoubleRef
:
415 sheet::ComplexReference aComplRef
;
416 lcl_ExternalRefToApi( aComplRef
.Reference1
, static_cast<const ScToken
&>(rToken
).GetSingleRef() );
417 lcl_ExternalRefToApi( aComplRef
.Reference2
, static_cast<const ScToken
&>(rToken
).GetSingleRef2() );
419 rDoc
.GetExternalRefManager()->getCacheTable( rToken
.GetIndex(), rToken
.GetString(), false, &nCacheId
);
420 aComplRef
.Reference1
.Sheet
= static_cast< sal_Int32
>( nCacheId
);
421 // NOTE: This assumes that cached sheets are in consecutive order!
422 aComplRef
.Reference2
.Sheet
= aComplRef
.Reference1
.Sheet
+ (static_cast<const ScToken
&>(rToken
).GetSingleRef2().nTab
- static_cast<const ScToken
&>(rToken
).GetSingleRef().nTab
);
423 sheet::ExternalReference aExtRef
;
424 aExtRef
.Index
= rToken
.GetIndex();
425 aExtRef
.Reference
<<= aComplRef
;
426 rAPI
.Data
<<= aExtRef
;
432 sheet::ExternalReference aExtRef
;
433 aExtRef
.Index
= rToken
.GetIndex();
434 aExtRef
.Reference
<<= OUString( rToken
.GetString() );
435 rAPI
.Data
<<= aExtRef
;
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 rAPI
.Data
.clear(); // no data
446 rAPI
.OpCode
= static_cast<sal_Int32
>(eOpCode
); //! assuming equal values for the moment
450 rSequence
.realloc(0);
455 // ============================================================================
457 SAL_WNODEPRECATED_DECLARATIONS_PUSH
458 ScFormulaOpCodeMapperObj::ScFormulaOpCodeMapperObj(::std::auto_ptr
<formula::FormulaCompiler
> _pCompiler
)
459 : formula::FormulaOpCodeMapperObj(_pCompiler
)
462 SAL_WNODEPRECATED_DECLARATIONS_POP
464 // ============================================================================
466 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */