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"
54 using namespace formula
;
56 using namespace com::sun::star
;
58 //------------------------------------------------------------------------
60 const SfxItemPropertyMap
* lcl_GetFormulaParserMap()
62 static SfxItemPropertyMap aFormulaParserMap_Impl
[] =
64 {MAP_CHAR_LEN(SC_UNO_REFERENCEPOS
), 0, &getCppuType((table::CellAddress
*)0), 0, 0 },
65 {MAP_CHAR_LEN(SC_UNO_COMPILEFAP
), 0, &getBooleanCppuType(), 0, 0 },
66 {MAP_CHAR_LEN(SC_UNO_COMPILEENGLISH
), 0, &getBooleanCppuType(), 0, 0 },
67 {MAP_CHAR_LEN(SC_UNO_IGNORELEADING
), 0, &getBooleanCppuType(), 0, 0 },
68 {MAP_CHAR_LEN(SC_UNO_FORMULACONVENTION
), 0, &getCppuType(&sheet::AddressConvention::UNSPECIFIED
), 0, 0 },
69 {MAP_CHAR_LEN(SC_UNO_OPCODEMAP
), 0, &getCppuType((uno::Sequence
< sheet::FormulaOpCodeMapEntry
>*)0), 0, 0 },
72 return aFormulaParserMap_Impl
;
75 SC_SIMPLE_SERVICE_INFO( ScFormulaParserObj
, "ScFormulaParserObj", SC_SERVICENAME_FORMULAPARS
)
77 //------------------------------------------------------------------------
79 ScFormulaParserObj::ScFormulaParserObj(ScDocShell
* pDocSh
) :
81 mnConv( sheet::AddressConvention::UNSPECIFIED
),
83 mbIgnoreSpaces( true ),
86 mpDocShell
->GetDocument()->AddUnoObject(*this);
89 ScFormulaParserObj::~ScFormulaParserObj()
92 mpDocShell
->GetDocument()->RemoveUnoObject(*this);
95 void ScFormulaParserObj::Notify( SfxBroadcaster
&, const SfxHint
& rHint
)
97 if ( rHint
.ISA( SfxSimpleHint
) && ((const SfxSimpleHint
&)rHint
).GetId() == SFX_HINT_DYING
)
103 void ScFormulaParserObj::SetCompilerFlags( ScCompiler
& rCompiler
) const
105 static const formula::FormulaGrammar::AddressConvention aConvMap
[] = {
106 formula::FormulaGrammar::CONV_OOO
, // <- AddressConvention::OOO
107 formula::FormulaGrammar::CONV_XL_A1
, // <- AddressConvention::XL_A1
108 formula::FormulaGrammar::CONV_XL_R1C1
, // <- AddressConvention::XL_R1C1
109 formula::FormulaGrammar::CONV_XL_OOX
, // <- AddressConvention::XL_OOX
110 formula::FormulaGrammar::CONV_LOTUS_A1
// <- AddressConvention::LOTUS_A1
112 static const sal_Int16 nConvMapCount
= sizeof(aConvMap
)/sizeof(aConvMap
[0]);
114 // If mxOpCodeMap is not empty it overrides mbEnglish, and vice versa. We
115 // don't need to initialize things twice.
116 if (mxOpCodeMap
.get())
117 rCompiler
.SetFormulaLanguage( mxOpCodeMap
);
120 sal_Int32 nFormulaLanguage
= mbEnglish
?
121 sheet::FormulaLanguage::ENGLISH
:
122 sheet::FormulaLanguage::NATIVE
;
123 ScCompiler::OpCodeMapPtr xMap
= rCompiler
.GetOpCodeMap( nFormulaLanguage
);
124 rCompiler
.SetFormulaLanguage( xMap
);
127 formula::FormulaGrammar::AddressConvention eConv
= formula::FormulaGrammar::CONV_UNSPECIFIED
;
128 if (mnConv
>= 0 && mnConv
< nConvMapCount
)
129 eConv
= aConvMap
[mnConv
];
131 rCompiler
.SetRefConvention( eConv
);
133 rCompiler
.SetCompileForFAP(mbCompileFAP
);
135 rCompiler
.SetExternalLinks( maExternalLinks
);
138 uno::Sequence
<sheet::FormulaToken
> SAL_CALL
ScFormulaParserObj::parseFormula( const rtl::OUString
& aFormula
)
139 throw (uno::RuntimeException
)
142 uno::Sequence
<sheet::FormulaToken
> aRet
;
146 ScDocument
* pDoc
= mpDocShell
->GetDocument();
147 ScCompiler
aCompiler( pDoc
, maRefPos
);
148 aCompiler
.SetGrammar(pDoc
->GetGrammar());
149 SetCompilerFlags( aCompiler
);
151 ScTokenArray
* pCode
= aCompiler
.CompileString( aFormula
);
152 (void)ScTokenConversion::ConvertToTokenSequence( *pDoc
, aRet
, *pCode
);
159 rtl::OUString SAL_CALL
ScFormulaParserObj::printFormula( const uno::Sequence
<sheet::FormulaToken
>& aTokens
)
160 throw (uno::RuntimeException
)
167 ScDocument
* pDoc
= mpDocShell
->GetDocument();
169 (void)ScTokenConversion::ConvertToTokenArray( *pDoc
, aCode
, aTokens
);
170 ScCompiler
aCompiler( pDoc
, maRefPos
, aCode
);
171 aCompiler
.SetGrammar(pDoc
->GetGrammar());
172 SetCompilerFlags( aCompiler
);
174 rtl::OUStringBuffer aBuffer
;
175 aCompiler
.CreateStringFromTokenArray( aBuffer
);
176 aRet
= aBuffer
.makeStringAndClear();
184 uno::Reference
<beans::XPropertySetInfo
> SAL_CALL
ScFormulaParserObj::getPropertySetInfo()
185 throw(uno::RuntimeException
)
188 static uno::Reference
< beans::XPropertySetInfo
> aRef(new SfxItemPropertySetInfo( lcl_GetFormulaParserMap() ));
192 void SAL_CALL
ScFormulaParserObj::setPropertyValue(
193 const rtl::OUString
& aPropertyName
, const uno::Any
& aValue
)
194 throw(beans::UnknownPropertyException
, beans::PropertyVetoException
,
195 lang::IllegalArgumentException
, lang::WrappedTargetException
,
196 uno::RuntimeException
)
199 String
aString(aPropertyName
);
200 if ( aString
.EqualsAscii( SC_UNO_REFERENCEPOS
) )
202 table::CellAddress aAddress
;
204 ScUnoConversion::FillScAddress( maRefPos
, aAddress
);
205 } // if ( aString.EqualsAscii( SC_UNO_REFERENCEPOS ) )
206 else if ( aString
.EqualsAscii( SC_UNO_COMPILEFAP
) )
208 aValue
>>= mbCompileFAP
;
210 else if ( aString
.EqualsAscii( SC_UNO_COMPILEENGLISH
) )
212 bool bOldEnglish
= mbEnglish
;
213 if (aValue
>>= mbEnglish
)
215 // Need to recreate the symbol map to change English property
216 // because the map is const. So for performance reasons set
217 // CompileEnglish _before_ OpCodeMap!
218 if (mxOpCodeMap
.get() && mbEnglish
!= bOldEnglish
)
220 ScDocument
* pDoc
= mpDocShell
->GetDocument();
221 ScCompiler
aCompiler( pDoc
, maRefPos
);
222 aCompiler
.SetGrammar(pDoc
->GetGrammar());
223 mxOpCodeMap
= aCompiler
.CreateOpCodeMap( maOpCodeMapping
, mbEnglish
);
227 throw lang::IllegalArgumentException();
229 else if ( aString
.EqualsAscii( SC_UNO_FORMULACONVENTION
) )
233 else if ( aString
.EqualsAscii( SC_UNO_IGNORELEADING
) )
235 aValue
>>= mbIgnoreSpaces
;
237 else if ( aString
.EqualsAscii( SC_UNO_OPCODEMAP
) )
239 if (aValue
>>= maOpCodeMapping
)
241 ScDocument
* pDoc
= mpDocShell
->GetDocument();
242 ScCompiler
aCompiler( pDoc
, maRefPos
);
243 aCompiler
.SetGrammar(pDoc
->GetGrammar());
244 mxOpCodeMap
= aCompiler
.CreateOpCodeMap( maOpCodeMapping
, mbEnglish
);
247 throw lang::IllegalArgumentException();
249 else if ( aString
.EqualsAscii( SC_UNO_EXTERNALLINKS
) )
251 if (!(aValue
>>= maExternalLinks
))
252 throw lang::IllegalArgumentException();
255 throw beans::UnknownPropertyException();
258 uno::Any SAL_CALL
ScFormulaParserObj::getPropertyValue( const rtl::OUString
& aPropertyName
)
259 throw(beans::UnknownPropertyException
, lang::WrappedTargetException
,
260 uno::RuntimeException
)
264 String
aString(aPropertyName
);
265 if ( aString
.EqualsAscii( SC_UNO_REFERENCEPOS
) )
267 table::CellAddress aAddress
;
268 ScUnoConversion::FillApiAddress( aAddress
, maRefPos
);
271 else if ( aString
.EqualsAscii( SC_UNO_COMPILEFAP
) )
273 aRet
<<= mbCompileFAP
;
275 else if ( aString
.EqualsAscii( SC_UNO_COMPILEENGLISH
) )
279 else if ( aString
.EqualsAscii( SC_UNO_FORMULACONVENTION
) )
283 else if ( aString
.EqualsAscii( SC_UNO_IGNORELEADING
) )
285 aRet
<<= mbIgnoreSpaces
;
287 else if ( aString
.EqualsAscii( SC_UNO_OPCODEMAP
) )
289 aRet
<<= maOpCodeMapping
;
291 else if ( aString
.EqualsAscii( SC_UNO_EXTERNALLINKS
) )
293 aRet
<<= maExternalLinks
;
296 throw beans::UnknownPropertyException();
300 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFormulaParserObj
)
302 //------------------------------------------------------------------------
304 void lcl_ExternalRefToApi( sheet::SingleReference
& rAPI
, const ScSingleRefData
& rRef
)
306 rAPI
.Column
= rRef
.nCol
;
307 rAPI
.Row
= rRef
.nRow
;
309 rAPI
.RelativeColumn
= rRef
.nRelCol
;
310 rAPI
.RelativeRow
= rRef
.nRelRow
;
311 rAPI
.RelativeSheet
= 0;
313 sal_Int32 nFlags
= 0;
314 if ( rRef
.IsColRel() ) nFlags
|= sheet::ReferenceFlags::COLUMN_RELATIVE
;
315 if ( rRef
.IsRowRel() ) nFlags
|= sheet::ReferenceFlags::ROW_RELATIVE
;
316 if ( rRef
.IsColDeleted() ) nFlags
|= sheet::ReferenceFlags::COLUMN_DELETED
;
317 if ( rRef
.IsRowDeleted() ) nFlags
|= sheet::ReferenceFlags::ROW_DELETED
;
318 if ( rRef
.IsFlag3D() ) nFlags
|= sheet::ReferenceFlags::SHEET_3D
;
319 if ( rRef
.IsRelName() ) nFlags
|= sheet::ReferenceFlags::RELATIVE_NAME
;
323 void lcl_SingleRefToApi( sheet::SingleReference
& rAPI
, const ScSingleRefData
& rRef
)
325 rAPI
.Column
= rRef
.nCol
;
326 rAPI
.Row
= rRef
.nRow
;
327 rAPI
.Sheet
= rRef
.nTab
;
328 rAPI
.RelativeColumn
= rRef
.nRelCol
;
329 rAPI
.RelativeRow
= rRef
.nRelRow
;
330 rAPI
.RelativeSheet
= rRef
.nRelTab
;
332 sal_Int32 nFlags
= 0;
333 if ( rRef
.IsColRel() ) nFlags
|= sheet::ReferenceFlags::COLUMN_RELATIVE
;
334 if ( rRef
.IsRowRel() ) nFlags
|= sheet::ReferenceFlags::ROW_RELATIVE
;
335 if ( rRef
.IsTabRel() ) nFlags
|= sheet::ReferenceFlags::SHEET_RELATIVE
;
336 if ( rRef
.IsColDeleted() ) nFlags
|= sheet::ReferenceFlags::COLUMN_DELETED
;
337 if ( rRef
.IsRowDeleted() ) nFlags
|= sheet::ReferenceFlags::ROW_DELETED
;
338 if ( rRef
.IsTabDeleted() ) nFlags
|= sheet::ReferenceFlags::SHEET_DELETED
;
339 if ( rRef
.IsFlag3D() ) nFlags
|= sheet::ReferenceFlags::SHEET_3D
;
340 if ( rRef
.IsRelName() ) nFlags
|= sheet::ReferenceFlags::RELATIVE_NAME
;
345 bool ScTokenConversion::ConvertToTokenArray( ScDocument
& rDoc
,
346 ScTokenArray
& rTokenArray
, const uno::Sequence
<sheet::FormulaToken
>& rSequence
)
348 return !rTokenArray
.Fill(rSequence
,rDoc
.GetExternalRefManager());
352 bool ScTokenConversion::ConvertToTokenSequence( ScDocument
& rDoc
,
353 uno::Sequence
<sheet::FormulaToken
>& rSequence
, const ScTokenArray
& rTokenArray
)
357 sal_Int32 nLen
= static_cast<sal_Int32
>(rTokenArray
.GetLen());
358 formula::FormulaToken
** pTokens
= rTokenArray
.GetArray();
361 rSequence
.realloc(nLen
);
362 for (sal_Int32 nPos
=0; nPos
<nLen
; nPos
++)
364 const formula::FormulaToken
& rToken
= *pTokens
[nPos
];
365 sheet::FormulaToken
& rAPI
= rSequence
[nPos
];
367 OpCode eOpCode
= rToken
.GetOpCode();
368 // eOpCode may be changed in the following switch/case
369 switch ( rToken
.GetType() )
372 // Only the count of spaces is stored as "long". Parameter count is ignored.
373 if ( eOpCode
== ocSpaces
)
374 rAPI
.Data
<<= (sal_Int32
) rToken
.GetByte();
376 rAPI
.Data
.clear(); // no data
378 case formula::svDouble
:
379 rAPI
.Data
<<= rToken
.GetDouble();
381 case formula::svString
:
382 rAPI
.Data
<<= rtl::OUString( rToken
.GetString() );
385 // Function name is stored as string.
386 // Byte (parameter count) is ignored.
387 rAPI
.Data
<<= rtl::OUString( rToken
.GetExternal() );
391 sheet::SingleReference aSingleRef
;
392 lcl_SingleRefToApi( aSingleRef
, static_cast<const ScToken
&>(rToken
).GetSingleRef() );
393 rAPI
.Data
<<= aSingleRef
;
396 case formula::svDoubleRef
:
398 sheet::ComplexReference aCompRef
;
399 lcl_SingleRefToApi( aCompRef
.Reference1
, static_cast<const ScToken
&>(rToken
).GetSingleRef() );
400 lcl_SingleRefToApi( aCompRef
.Reference2
, static_cast<const ScToken
&>(rToken
).GetSingleRef2() );
401 rAPI
.Data
<<= aCompRef
;
405 rAPI
.Data
<<= static_cast<sal_Int32
>( rToken
.GetIndex() );
408 if (!ScRangeToSequence::FillMixedArray( rAPI
.Data
, static_cast<const ScToken
&>(rToken
).GetMatrix(), true))
411 case svExternalSingleRef
:
413 sheet::SingleReference aSingleRef
;
414 lcl_ExternalRefToApi( aSingleRef
, static_cast<const ScToken
&>(rToken
).GetSingleRef() );
416 rDoc
.GetExternalRefManager()->getCacheTable( rToken
.GetIndex(), rToken
.GetString(), false, &nCacheId
);
417 aSingleRef
.Sheet
= static_cast< sal_Int32
>( nCacheId
);
418 sheet::ExternalReference aExtRef
;
419 aExtRef
.Index
= rToken
.GetIndex();
420 aExtRef
.Reference
<<= aSingleRef
;
421 rAPI
.Data
<<= aExtRef
;
425 case svExternalDoubleRef
:
427 sheet::ComplexReference aComplRef
;
428 lcl_ExternalRefToApi( aComplRef
.Reference1
, static_cast<const ScToken
&>(rToken
).GetSingleRef() );
429 lcl_ExternalRefToApi( aComplRef
.Reference2
, static_cast<const ScToken
&>(rToken
).GetSingleRef2() );
431 rDoc
.GetExternalRefManager()->getCacheTable( rToken
.GetIndex(), rToken
.GetString(), false, &nCacheId
);
432 aComplRef
.Reference1
.Sheet
= static_cast< sal_Int32
>( nCacheId
);
433 // NOTE: This assumes that cached sheets are in consecutive order!
434 aComplRef
.Reference2
.Sheet
= aComplRef
.Reference1
.Sheet
+ (static_cast<const ScToken
&>(rToken
).GetSingleRef2().nTab
- static_cast<const ScToken
&>(rToken
).GetSingleRef().nTab
);
435 sheet::ExternalReference aExtRef
;
436 aExtRef
.Index
= rToken
.GetIndex();
437 aExtRef
.Reference
<<= aComplRef
;
438 rAPI
.Data
<<= aExtRef
;
444 sheet::ExternalReference aExtRef
;
445 aExtRef
.Index
= rToken
.GetIndex();
446 aExtRef
.Reference
<<= ::rtl::OUString( rToken
.GetString() );
447 rAPI
.Data
<<= aExtRef
;
452 DBG_ERROR1( "ScTokenConversion::ConvertToTokenSequence: unhandled token type SvStackVar %d", rToken
.GetType());
453 case svSep
: // occurs with ocSep, ocOpen, ocClose, ocArray*
454 case svJump
: // occurs with ocIf, ocChose
455 case svMissing
: // occurs with ocMissing
456 rAPI
.Data
.clear(); // no data
458 rAPI
.OpCode
= static_cast<sal_Int32
>(eOpCode
); //! assuming equal values for the moment
462 rSequence
.realloc(0);
466 // -----------------------------------------------------------------------------
467 ScFormulaOpCodeMapperObj::ScFormulaOpCodeMapperObj(::std::auto_ptr
<formula::FormulaCompiler
> _pCompiler
)
468 : formula::FormulaOpCodeMapperObj(_pCompiler
)