1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: tokenuno.cxx,v $
10 * $Revision: 1.6.108.8 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 #include "tokenuno.hxx"
36 #include <com/sun/star/sheet/ComplexReference.hpp>
37 #include <com/sun/star/sheet/ExternalReference.hpp>
38 #include <com/sun/star/sheet/ReferenceFlags.hpp>
39 #include <com/sun/star/sheet/AddressConvention.hpp>
40 #include <com/sun/star/table/CellAddress.hpp>
42 #include <svtools/itemprop.hxx>
44 #include "miscuno.hxx"
45 #include "convuno.hxx"
46 #include "unonames.hxx"
47 #include "unoguard.hxx"
49 #include "compiler.hxx"
50 #include "tokenarray.hxx"
52 #include "rangeseq.hxx"
53 #include "externalrefmgr.hxx"
55 using namespace ::formula
;
56 using namespace ::com::sun::star
;
58 // ============================================================================
60 const SfxItemPropertyMapEntry
* lcl_GetFormulaParserMap()
62 static SfxItemPropertyMapEntry aFormulaParserMap_Impl
[] =
64 {MAP_CHAR_LEN(SC_UNO_COMPILEFAP
), 0, &getBooleanCppuType(), 0, 0 },
65 {MAP_CHAR_LEN(SC_UNO_COMPILEENGLISH
), 0, &getBooleanCppuType(), 0, 0 },
66 {MAP_CHAR_LEN(SC_UNO_IGNORELEADING
), 0, &getBooleanCppuType(), 0, 0 },
67 {MAP_CHAR_LEN(SC_UNO_FORMULACONVENTION
), 0, &getCppuType(&sheet::AddressConvention::UNSPECIFIED
), 0, 0 },
68 {MAP_CHAR_LEN(SC_UNO_OPCODEMAP
), 0, &getCppuType((uno::Sequence
< sheet::FormulaOpCodeMapEntry
>*)0), 0, 0 },
71 return aFormulaParserMap_Impl
;
74 SC_SIMPLE_SERVICE_INFO( ScFormulaParserObj
, "ScFormulaParserObj", SC_SERVICENAME_FORMULAPARS
)
76 // ============================================================================
78 ScFormulaParserObj::ScFormulaParserObj(ScDocShell
* pDocSh
) :
80 mnConv( sheet::AddressConvention::UNSPECIFIED
),
82 mbIgnoreSpaces( true ),
85 mpDocShell
->GetDocument()->AddUnoObject(*this);
88 ScFormulaParserObj::~ScFormulaParserObj()
91 mpDocShell
->GetDocument()->RemoveUnoObject(*this);
94 void ScFormulaParserObj::Notify( SfxBroadcaster
&, const SfxHint
& rHint
)
96 if ( rHint
.ISA( SfxSimpleHint
) && ((const SfxSimpleHint
&)rHint
).GetId() == SFX_HINT_DYING
)
102 void ScFormulaParserObj::SetCompilerFlags( ScCompiler
& rCompiler
) const
104 static const formula::FormulaGrammar::AddressConvention aConvMap
[] = {
105 formula::FormulaGrammar::CONV_OOO
, // <- AddressConvention::OOO
106 formula::FormulaGrammar::CONV_XL_A1
, // <- AddressConvention::XL_A1
107 formula::FormulaGrammar::CONV_XL_R1C1
, // <- AddressConvention::XL_R1C1
108 formula::FormulaGrammar::CONV_XL_OOX
, // <- AddressConvention::XL_OOX
109 formula::FormulaGrammar::CONV_LOTUS_A1
// <- AddressConvention::LOTUS_A1
111 static const sal_Int16 nConvMapCount
= sizeof(aConvMap
)/sizeof(aConvMap
[0]);
113 // If mxOpCodeMap is not empty it overrides mbEnglish, and vice versa. We
114 // don't need to initialize things twice.
115 if (mxOpCodeMap
.get())
116 rCompiler
.SetFormulaLanguage( mxOpCodeMap
);
119 sal_Int32 nFormulaLanguage
= mbEnglish
?
120 sheet::FormulaLanguage::ENGLISH
:
121 sheet::FormulaLanguage::NATIVE
;
122 ScCompiler::OpCodeMapPtr xMap
= rCompiler
.GetOpCodeMap( nFormulaLanguage
);
123 rCompiler
.SetFormulaLanguage( xMap
);
126 formula::FormulaGrammar::AddressConvention eConv
= formula::FormulaGrammar::CONV_UNSPECIFIED
;
127 if (mnConv
>= 0 && mnConv
< nConvMapCount
)
128 eConv
= aConvMap
[mnConv
];
130 rCompiler
.SetRefConvention( eConv
);
132 rCompiler
.SetCompileForFAP(mbCompileFAP
);
134 rCompiler
.SetExternalLinks( maExternalLinks
);
137 uno::Sequence
<sheet::FormulaToken
> SAL_CALL
ScFormulaParserObj::parseFormula(
138 const rtl::OUString
& aFormula
, const table::CellAddress
& rReferencePos
)
139 throw (uno::RuntimeException
)
142 uno::Sequence
<sheet::FormulaToken
> aRet
;
146 ScAddress
aRefPos( ScAddress::UNINITIALIZED
);
147 ScUnoConversion::FillScAddress( aRefPos
, rReferencePos
);
148 ScDocument
* pDoc
= mpDocShell
->GetDocument();
149 ScCompiler
aCompiler( pDoc
, aRefPos
);
150 aCompiler
.SetGrammar(pDoc
->GetGrammar());
151 SetCompilerFlags( aCompiler
);
153 ScTokenArray
* pCode
= aCompiler
.CompileString( aFormula
);
154 (void)ScTokenConversion::ConvertToTokenSequence( *pDoc
, aRet
, *pCode
);
161 rtl::OUString SAL_CALL
ScFormulaParserObj::printFormula(
162 const uno::Sequence
<sheet::FormulaToken
>& aTokens
, const table::CellAddress
& rReferencePos
)
163 throw (uno::RuntimeException
)
170 ScDocument
* pDoc
= mpDocShell
->GetDocument();
172 (void)ScTokenConversion::ConvertToTokenArray( *pDoc
, aCode
, aTokens
);
173 ScAddress
aRefPos( ScAddress::UNINITIALIZED
);
174 ScUnoConversion::FillScAddress( aRefPos
, rReferencePos
);
175 ScCompiler
aCompiler( pDoc
, aRefPos
, aCode
);
176 aCompiler
.SetGrammar(pDoc
->GetGrammar());
177 SetCompilerFlags( aCompiler
);
179 rtl::OUStringBuffer aBuffer
;
180 aCompiler
.CreateStringFromTokenArray( aBuffer
);
181 aRet
= aBuffer
.makeStringAndClear();
189 uno::Reference
<beans::XPropertySetInfo
> SAL_CALL
ScFormulaParserObj::getPropertySetInfo()
190 throw(uno::RuntimeException
)
193 static uno::Reference
< beans::XPropertySetInfo
> aRef(new SfxItemPropertySetInfo( lcl_GetFormulaParserMap() ));
197 void SAL_CALL
ScFormulaParserObj::setPropertyValue(
198 const rtl::OUString
& aPropertyName
, const uno::Any
& aValue
)
199 throw(beans::UnknownPropertyException
, beans::PropertyVetoException
,
200 lang::IllegalArgumentException
, lang::WrappedTargetException
,
201 uno::RuntimeException
)
204 String
aString(aPropertyName
);
205 if ( aString
.EqualsAscii( SC_UNO_COMPILEFAP
) )
207 aValue
>>= mbCompileFAP
;
209 else if ( aString
.EqualsAscii( SC_UNO_COMPILEENGLISH
) )
211 bool bOldEnglish
= mbEnglish
;
212 if (aValue
>>= mbEnglish
)
214 // Need to recreate the symbol map to change English property
215 // because the map is const. So for performance reasons set
216 // CompileEnglish _before_ OpCodeMap!
217 if (mxOpCodeMap
.get() && mbEnglish
!= bOldEnglish
)
219 ScDocument
* pDoc
= mpDocShell
->GetDocument();
220 ScCompiler
aCompiler( pDoc
, ScAddress());
221 aCompiler
.SetGrammar(pDoc
->GetGrammar());
222 mxOpCodeMap
= aCompiler
.CreateOpCodeMap( maOpCodeMapping
, mbEnglish
);
226 throw lang::IllegalArgumentException();
228 else if ( aString
.EqualsAscii( SC_UNO_FORMULACONVENTION
) )
232 else if ( aString
.EqualsAscii( SC_UNO_IGNORELEADING
) )
234 aValue
>>= mbIgnoreSpaces
;
236 else if ( aString
.EqualsAscii( SC_UNO_OPCODEMAP
) )
238 if (aValue
>>= maOpCodeMapping
)
240 ScDocument
* pDoc
= mpDocShell
->GetDocument();
241 ScCompiler
aCompiler( pDoc
, ScAddress());
242 aCompiler
.SetGrammar(pDoc
->GetGrammar());
243 mxOpCodeMap
= aCompiler
.CreateOpCodeMap( maOpCodeMapping
, mbEnglish
);
246 throw lang::IllegalArgumentException();
248 else if ( aString
.EqualsAscii( SC_UNO_EXTERNALLINKS
) )
250 if (!(aValue
>>= maExternalLinks
))
251 throw lang::IllegalArgumentException();
254 throw beans::UnknownPropertyException();
257 uno::Any SAL_CALL
ScFormulaParserObj::getPropertyValue( const rtl::OUString
& aPropertyName
)
258 throw(beans::UnknownPropertyException
, lang::WrappedTargetException
,
259 uno::RuntimeException
)
263 String
aString(aPropertyName
);
264 if ( aString
.EqualsAscii( SC_UNO_COMPILEFAP
) )
266 aRet
<<= mbCompileFAP
;
268 else if ( aString
.EqualsAscii( SC_UNO_COMPILEENGLISH
) )
272 else if ( aString
.EqualsAscii( SC_UNO_FORMULACONVENTION
) )
276 else if ( aString
.EqualsAscii( SC_UNO_IGNORELEADING
) )
278 aRet
<<= mbIgnoreSpaces
;
280 else if ( aString
.EqualsAscii( SC_UNO_OPCODEMAP
) )
282 aRet
<<= maOpCodeMapping
;
284 else if ( aString
.EqualsAscii( SC_UNO_EXTERNALLINKS
) )
286 aRet
<<= maExternalLinks
;
289 throw beans::UnknownPropertyException();
293 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFormulaParserObj
)
295 // ============================================================================
297 void lcl_ExternalRefToApi( sheet::SingleReference
& rAPI
, const ScSingleRefData
& rRef
)
299 rAPI
.Column
= rRef
.nCol
;
300 rAPI
.Row
= rRef
.nRow
;
302 rAPI
.RelativeColumn
= rRef
.nRelCol
;
303 rAPI
.RelativeRow
= rRef
.nRelRow
;
304 rAPI
.RelativeSheet
= 0;
306 sal_Int32 nFlags
= 0;
307 if ( rRef
.IsColRel() ) nFlags
|= sheet::ReferenceFlags::COLUMN_RELATIVE
;
308 if ( rRef
.IsRowRel() ) nFlags
|= sheet::ReferenceFlags::ROW_RELATIVE
;
309 if ( rRef
.IsColDeleted() ) nFlags
|= sheet::ReferenceFlags::COLUMN_DELETED
;
310 if ( rRef
.IsRowDeleted() ) nFlags
|= sheet::ReferenceFlags::ROW_DELETED
;
311 if ( rRef
.IsFlag3D() ) nFlags
|= sheet::ReferenceFlags::SHEET_3D
;
312 if ( rRef
.IsRelName() ) nFlags
|= sheet::ReferenceFlags::RELATIVE_NAME
;
316 void lcl_SingleRefToApi( sheet::SingleReference
& rAPI
, const ScSingleRefData
& rRef
)
318 rAPI
.Column
= rRef
.nCol
;
319 rAPI
.Row
= rRef
.nRow
;
320 rAPI
.Sheet
= rRef
.nTab
;
321 rAPI
.RelativeColumn
= rRef
.nRelCol
;
322 rAPI
.RelativeRow
= rRef
.nRelRow
;
323 rAPI
.RelativeSheet
= rRef
.nRelTab
;
325 sal_Int32 nFlags
= 0;
326 if ( rRef
.IsColRel() ) nFlags
|= sheet::ReferenceFlags::COLUMN_RELATIVE
;
327 if ( rRef
.IsRowRel() ) nFlags
|= sheet::ReferenceFlags::ROW_RELATIVE
;
328 if ( rRef
.IsTabRel() ) nFlags
|= sheet::ReferenceFlags::SHEET_RELATIVE
;
329 if ( rRef
.IsColDeleted() ) nFlags
|= sheet::ReferenceFlags::COLUMN_DELETED
;
330 if ( rRef
.IsRowDeleted() ) nFlags
|= sheet::ReferenceFlags::ROW_DELETED
;
331 if ( rRef
.IsTabDeleted() ) nFlags
|= sheet::ReferenceFlags::SHEET_DELETED
;
332 if ( rRef
.IsFlag3D() ) nFlags
|= sheet::ReferenceFlags::SHEET_3D
;
333 if ( rRef
.IsRelName() ) nFlags
|= sheet::ReferenceFlags::RELATIVE_NAME
;
338 bool ScTokenConversion::ConvertToTokenArray( ScDocument
& rDoc
,
339 ScTokenArray
& rTokenArray
, const uno::Sequence
<sheet::FormulaToken
>& rSequence
)
341 return !rTokenArray
.Fill(rSequence
,rDoc
.GetExternalRefManager());
345 bool ScTokenConversion::ConvertToTokenSequence( ScDocument
& rDoc
,
346 uno::Sequence
<sheet::FormulaToken
>& rSequence
, const ScTokenArray
& rTokenArray
)
350 sal_Int32 nLen
= static_cast<sal_Int32
>(rTokenArray
.GetLen());
351 formula::FormulaToken
** pTokens
= rTokenArray
.GetArray();
354 rSequence
.realloc(nLen
);
355 for (sal_Int32 nPos
=0; nPos
<nLen
; nPos
++)
357 const formula::FormulaToken
& rToken
= *pTokens
[nPos
];
358 sheet::FormulaToken
& rAPI
= rSequence
[nPos
];
360 OpCode eOpCode
= rToken
.GetOpCode();
361 // eOpCode may be changed in the following switch/case
362 switch ( rToken
.GetType() )
365 // Only the count of spaces is stored as "long". Parameter count is ignored.
366 if ( eOpCode
== ocSpaces
)
367 rAPI
.Data
<<= (sal_Int32
) rToken
.GetByte();
369 rAPI
.Data
.clear(); // no data
371 case formula::svDouble
:
372 rAPI
.Data
<<= rToken
.GetDouble();
374 case formula::svString
:
375 rAPI
.Data
<<= rtl::OUString( rToken
.GetString() );
378 // Function name is stored as string.
379 // Byte (parameter count) is ignored.
380 rAPI
.Data
<<= rtl::OUString( rToken
.GetExternal() );
384 sheet::SingleReference aSingleRef
;
385 lcl_SingleRefToApi( aSingleRef
, static_cast<const ScToken
&>(rToken
).GetSingleRef() );
386 rAPI
.Data
<<= aSingleRef
;
389 case formula::svDoubleRef
:
391 sheet::ComplexReference aCompRef
;
392 lcl_SingleRefToApi( aCompRef
.Reference1
, static_cast<const ScToken
&>(rToken
).GetSingleRef() );
393 lcl_SingleRefToApi( aCompRef
.Reference2
, static_cast<const ScToken
&>(rToken
).GetSingleRef2() );
394 rAPI
.Data
<<= aCompRef
;
398 rAPI
.Data
<<= static_cast<sal_Int32
>( rToken
.GetIndex() );
401 if (!ScRangeToSequence::FillMixedArray( rAPI
.Data
, static_cast<const ScToken
&>(rToken
).GetMatrix(), true))
404 case svExternalSingleRef
:
406 sheet::SingleReference aSingleRef
;
407 lcl_ExternalRefToApi( aSingleRef
, static_cast<const ScToken
&>(rToken
).GetSingleRef() );
409 rDoc
.GetExternalRefManager()->getCacheTable( rToken
.GetIndex(), rToken
.GetString(), false, &nCacheId
);
410 aSingleRef
.Sheet
= static_cast< sal_Int32
>( nCacheId
);
411 sheet::ExternalReference aExtRef
;
412 aExtRef
.Index
= rToken
.GetIndex();
413 aExtRef
.Reference
<<= aSingleRef
;
414 rAPI
.Data
<<= aExtRef
;
418 case svExternalDoubleRef
:
420 sheet::ComplexReference aComplRef
;
421 lcl_ExternalRefToApi( aComplRef
.Reference1
, static_cast<const ScToken
&>(rToken
).GetSingleRef() );
422 lcl_ExternalRefToApi( aComplRef
.Reference2
, static_cast<const ScToken
&>(rToken
).GetSingleRef2() );
424 rDoc
.GetExternalRefManager()->getCacheTable( rToken
.GetIndex(), rToken
.GetString(), false, &nCacheId
);
425 aComplRef
.Reference1
.Sheet
= static_cast< sal_Int32
>( nCacheId
);
426 // NOTE: This assumes that cached sheets are in consecutive order!
427 aComplRef
.Reference2
.Sheet
= aComplRef
.Reference1
.Sheet
+ (static_cast<const ScToken
&>(rToken
).GetSingleRef2().nTab
- static_cast<const ScToken
&>(rToken
).GetSingleRef().nTab
);
428 sheet::ExternalReference aExtRef
;
429 aExtRef
.Index
= rToken
.GetIndex();
430 aExtRef
.Reference
<<= aComplRef
;
431 rAPI
.Data
<<= aExtRef
;
437 sheet::ExternalReference aExtRef
;
438 aExtRef
.Index
= rToken
.GetIndex();
439 aExtRef
.Reference
<<= ::rtl::OUString( rToken
.GetString() );
440 rAPI
.Data
<<= aExtRef
;
445 DBG_ERROR1( "ScTokenConversion::ConvertToTokenSequence: unhandled token type SvStackVar %d", rToken
.GetType());
446 case svSep
: // occurs with ocSep, ocOpen, ocClose, ocArray*
447 case svJump
: // occurs with ocIf, ocChose
448 case svMissing
: // occurs with ocMissing
449 rAPI
.Data
.clear(); // no data
451 rAPI
.OpCode
= static_cast<sal_Int32
>(eOpCode
); //! assuming equal values for the moment
455 rSequence
.realloc(0);
460 // ============================================================================
462 ScFormulaOpCodeMapperObj::ScFormulaOpCodeMapperObj(::std::auto_ptr
<formula::FormulaCompiler
> _pCompiler
)
463 : formula::FormulaOpCodeMapperObj(_pCompiler
)
467 // ============================================================================