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 const 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 OUString
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 OUString
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
)
294 rAPI
.RelativeColumn
= 0;
295 rAPI
.RelativeRow
= 0;
296 rAPI
.RelativeSheet
= 0;
298 sal_Int32 nFlags
= 0;
299 if ( rRef
.IsColRel() )
301 nFlags
|= sheet::ReferenceFlags::COLUMN_RELATIVE
;
302 rAPI
.RelativeColumn
= rRef
.Col();
305 rAPI
.Column
= rRef
.Col();
307 if ( rRef
.IsRowRel() )
309 nFlags
|= sheet::ReferenceFlags::ROW_RELATIVE
;
310 rAPI
.RelativeRow
= rRef
.Row();
313 rAPI
.Row
= rRef
.Row();
315 if ( rRef
.IsColDeleted() ) nFlags
|= sheet::ReferenceFlags::COLUMN_DELETED
;
316 if ( rRef
.IsRowDeleted() ) nFlags
|= sheet::ReferenceFlags::ROW_DELETED
;
317 if ( rRef
.IsFlag3D() ) nFlags
|= sheet::ReferenceFlags::SHEET_3D
;
318 if ( rRef
.IsRelName() ) nFlags
|= sheet::ReferenceFlags::RELATIVE_NAME
;
322 static void lcl_SingleRefToApi( sheet::SingleReference
& rAPI
, const ScSingleRefData
& rRef
)
324 sal_Int32 nFlags
= 0;
325 if ( rRef
.IsColRel() )
327 nFlags
|= sheet::ReferenceFlags::COLUMN_RELATIVE
;
328 rAPI
.RelativeColumn
= rRef
.Col();
333 rAPI
.RelativeColumn
= 0;
334 rAPI
.Column
= rRef
.Col();
337 if ( rRef
.IsRowRel() )
339 nFlags
|= sheet::ReferenceFlags::ROW_RELATIVE
;
340 rAPI
.RelativeRow
= rRef
.Row();
345 rAPI
.RelativeRow
= 0;
346 rAPI
.Row
= rRef
.Row();
349 if ( rRef
.IsTabRel() )
351 nFlags
|= sheet::ReferenceFlags::SHEET_RELATIVE
;
352 rAPI
.RelativeSheet
= rRef
.Tab();
357 rAPI
.RelativeSheet
= 0;
358 rAPI
.Sheet
= rRef
.Tab();
361 if ( rRef
.IsColDeleted() ) nFlags
|= sheet::ReferenceFlags::COLUMN_DELETED
;
362 if ( rRef
.IsRowDeleted() ) nFlags
|= sheet::ReferenceFlags::ROW_DELETED
;
363 if ( rRef
.IsTabDeleted() ) nFlags
|= sheet::ReferenceFlags::SHEET_DELETED
;
364 if ( rRef
.IsFlag3D() ) nFlags
|= sheet::ReferenceFlags::SHEET_3D
;
365 if ( rRef
.IsRelName() ) nFlags
|= sheet::ReferenceFlags::RELATIVE_NAME
;
369 bool ScTokenConversion::ConvertToTokenArray( ScDocument
& rDoc
,
370 ScTokenArray
& rTokenArray
, const uno::Sequence
<sheet::FormulaToken
>& rSequence
)
372 return !rTokenArray
.Fill(rSequence
,rDoc
.GetExternalRefManager());
375 bool ScTokenConversion::ConvertToTokenSequence( const ScDocument
& rDoc
,
376 uno::Sequence
<sheet::FormulaToken
>& rSequence
, const ScTokenArray
& rTokenArray
)
380 sal_Int32 nLen
= static_cast<sal_Int32
>(rTokenArray
.GetLen());
381 formula::FormulaToken
** pTokens
= rTokenArray
.GetArray();
384 rSequence
.realloc(nLen
);
385 for (sal_Int32 nPos
=0; nPos
<nLen
; nPos
++)
387 const formula::FormulaToken
& rToken
= *pTokens
[nPos
];
388 sheet::FormulaToken
& rAPI
= rSequence
[nPos
];
390 OpCode eOpCode
= rToken
.GetOpCode();
391 // eOpCode may be changed in the following switch/case
392 switch ( rToken
.GetType() )
395 // Only the count of spaces is stored as "long". Parameter count is ignored.
396 if ( eOpCode
== ocSpaces
)
397 rAPI
.Data
<<= (sal_Int32
) rToken
.GetByte();
399 rAPI
.Data
.clear(); // no data
401 case formula::svDouble
:
402 rAPI
.Data
<<= rToken
.GetDouble();
404 case formula::svString
:
405 rAPI
.Data
<<= rToken
.GetString().getString();
408 // Function name is stored as string.
409 // Byte (parameter count) is ignored.
410 rAPI
.Data
<<= OUString( rToken
.GetExternal() );
414 sheet::SingleReference aSingleRef
;
415 lcl_SingleRefToApi( aSingleRef
, static_cast<const ScToken
&>(rToken
).GetSingleRef() );
416 rAPI
.Data
<<= aSingleRef
;
419 case formula::svDoubleRef
:
421 sheet::ComplexReference aCompRef
;
422 lcl_SingleRefToApi( aCompRef
.Reference1
, static_cast<const ScToken
&>(rToken
).GetSingleRef() );
423 lcl_SingleRefToApi( aCompRef
.Reference2
, static_cast<const ScToken
&>(rToken
).GetSingleRef2() );
424 rAPI
.Data
<<= aCompRef
;
429 sheet::NameToken aNameToken
;
430 aNameToken
.Index
= static_cast<sal_Int32
>( rToken
.GetIndex() );
431 aNameToken
.Global
= static_cast<sal_Bool
>( rToken
.IsGlobal() );
432 rAPI
.Data
<<= aNameToken
;
436 if (!ScRangeToSequence::FillMixedArray( rAPI
.Data
, static_cast<const ScToken
&>(rToken
).GetMatrix(), true))
439 case svExternalSingleRef
:
441 sheet::SingleReference aSingleRef
;
442 lcl_ExternalRefToApi( aSingleRef
, static_cast<const ScToken
&>(rToken
).GetSingleRef() );
444 rDoc
.GetExternalRefManager()->getCacheTable(
445 rToken
.GetIndex(), rToken
.GetString().getString(), false, &nCacheId
);
446 aSingleRef
.Sheet
= static_cast< sal_Int32
>( nCacheId
);
447 sheet::ExternalReference aExtRef
;
448 aExtRef
.Index
= rToken
.GetIndex();
449 aExtRef
.Reference
<<= aSingleRef
;
450 rAPI
.Data
<<= aExtRef
;
454 case svExternalDoubleRef
:
456 sheet::ComplexReference aComplRef
;
457 lcl_ExternalRefToApi( aComplRef
.Reference1
, static_cast<const ScToken
&>(rToken
).GetSingleRef() );
458 lcl_ExternalRefToApi( aComplRef
.Reference2
, static_cast<const ScToken
&>(rToken
).GetSingleRef2() );
460 rDoc
.GetExternalRefManager()->getCacheTable(
461 rToken
.GetIndex(), rToken
.GetString().getString(), false, &nCacheId
);
462 aComplRef
.Reference1
.Sheet
= static_cast< sal_Int32
>( nCacheId
);
463 // NOTE: This assumes that cached sheets are in consecutive order!
464 aComplRef
.Reference2
.Sheet
=
465 aComplRef
.Reference1
.Sheet
+
466 (static_cast<const ScToken
&>(rToken
).GetSingleRef2().Tab() - static_cast<const ScToken
&>(rToken
).GetSingleRef().Tab());
467 sheet::ExternalReference aExtRef
;
468 aExtRef
.Index
= rToken
.GetIndex();
469 aExtRef
.Reference
<<= aComplRef
;
470 rAPI
.Data
<<= aExtRef
;
476 sheet::ExternalReference aExtRef
;
477 aExtRef
.Index
= rToken
.GetIndex();
478 aExtRef
.Reference
<<= rToken
.GetString().getString();
479 rAPI
.Data
<<= aExtRef
;
484 OSL_TRACE( "ScTokenConversion::ConvertToTokenSequence: unhandled token type SvStackVar %d", rToken
.GetType());
485 case svSep
: // occurs with ocSep, ocOpen, ocClose, ocArray*
486 case svJump
: // occurs with ocIf, ocChose
487 case svMissing
: // occurs with ocMissing
488 rAPI
.Data
.clear(); // no data
490 rAPI
.OpCode
= static_cast<sal_Int32
>(eOpCode
); //! assuming equal values for the moment
494 rSequence
.realloc(0);
499 // ============================================================================
501 SAL_WNODEPRECATED_DECLARATIONS_PUSH
502 ScFormulaOpCodeMapperObj::ScFormulaOpCodeMapperObj(::std::auto_ptr
<formula::FormulaCompiler
> _pCompiler
)
503 : formula::FormulaOpCodeMapperObj(_pCompiler
)
506 SAL_WNODEPRECATED_DECLARATIONS_POP
508 // ============================================================================
510 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */