xref: /trunk/main/sc/source/ui/unoobj/tokenuno.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 #include "tokenuno.hxx"
32 
33 #include <com/sun/star/sheet/ComplexReference.hpp>
34 #include <com/sun/star/sheet/ExternalReference.hpp>
35 #include <com/sun/star/sheet/ReferenceFlags.hpp>
36 #include <com/sun/star/sheet/AddressConvention.hpp>
37 #include <com/sun/star/table/CellAddress.hpp>
38 
39 #include <svl/itemprop.hxx>
40 
41 #include "miscuno.hxx"
42 #include "convuno.hxx"
43 #include "unonames.hxx"
44 #include "unoguard.hxx"
45 #include "token.hxx"
46 #include "compiler.hxx"
47 #include "tokenarray.hxx"
48 #include "docsh.hxx"
49 #include "rangeseq.hxx"
50 #include "externalrefmgr.hxx"
51 
52 using namespace ::formula;
53 using namespace ::com::sun::star;
54 
55 // ============================================================================
56 
57 const SfxItemPropertyMapEntry* lcl_GetFormulaParserMap()
58 {
59     static SfxItemPropertyMapEntry aFormulaParserMap_Impl[] =
60     {
61         {MAP_CHAR_LEN(SC_UNO_COMPILEFAP),           0,  &getBooleanCppuType(),                   0, 0 },
62         {MAP_CHAR_LEN(SC_UNO_COMPILEENGLISH),       0,  &getBooleanCppuType(),                   0, 0 },
63         {MAP_CHAR_LEN(SC_UNO_IGNORELEADING),        0,  &getBooleanCppuType(),                   0, 0 },
64         {MAP_CHAR_LEN(SC_UNO_FORMULACONVENTION),    0,  &getCppuType(&sheet::AddressConvention::UNSPECIFIED), 0, 0 },
65         {MAP_CHAR_LEN(SC_UNO_OPCODEMAP),            0,  &getCppuType((uno::Sequence< sheet::FormulaOpCodeMapEntry >*)0), 0, 0 },
66         {0,0,0,0,0,0}
67     };
68     return aFormulaParserMap_Impl;
69 }
70 
71 SC_SIMPLE_SERVICE_INFO( ScFormulaParserObj, "ScFormulaParserObj", SC_SERVICENAME_FORMULAPARS )
72 
73 // ============================================================================
74 
75 ScFormulaParserObj::ScFormulaParserObj(ScDocShell* pDocSh) :
76     mpDocShell( pDocSh ),
77     mnConv( sheet::AddressConvention::UNSPECIFIED ),
78     mbEnglish( false ),
79     mbIgnoreSpaces( true ),
80     mbCompileFAP( false )
81 {
82     mpDocShell->GetDocument()->AddUnoObject(*this);
83 }
84 
85 ScFormulaParserObj::~ScFormulaParserObj()
86 {
87     if (mpDocShell)
88         mpDocShell->GetDocument()->RemoveUnoObject(*this);
89 }
90 
91 void ScFormulaParserObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
92 {
93     if ( rHint.ISA( SfxSimpleHint ) && ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING )
94         mpDocShell = NULL;
95 }
96 
97 // XFormulaParser
98 
99 void ScFormulaParserObj::SetCompilerFlags( ScCompiler& rCompiler ) const
100 {
101     static const formula::FormulaGrammar::AddressConvention aConvMap[] = {
102         formula::FormulaGrammar::CONV_OOO,        // <- AddressConvention::OOO
103         formula::FormulaGrammar::CONV_XL_A1,      // <- AddressConvention::XL_A1
104         formula::FormulaGrammar::CONV_XL_R1C1,    // <- AddressConvention::XL_R1C1
105         formula::FormulaGrammar::CONV_XL_OOX,     // <- AddressConvention::XL_OOX
106         formula::FormulaGrammar::CONV_LOTUS_A1    // <- AddressConvention::LOTUS_A1
107     };
108     static const sal_Int16 nConvMapCount = sizeof(aConvMap)/sizeof(aConvMap[0]);
109 
110     // If mxOpCodeMap is not empty it overrides mbEnglish, and vice versa. We
111     // don't need to initialize things twice.
112     if (mxOpCodeMap.get())
113         rCompiler.SetFormulaLanguage( mxOpCodeMap );
114     else
115     {
116         sal_Int32 nFormulaLanguage = mbEnglish ?
117             sheet::FormulaLanguage::ENGLISH :
118             sheet::FormulaLanguage::NATIVE;
119         ScCompiler::OpCodeMapPtr xMap = rCompiler.GetOpCodeMap( nFormulaLanguage);
120         rCompiler.SetFormulaLanguage( xMap);
121     }
122 
123     formula::FormulaGrammar::AddressConvention eConv = formula::FormulaGrammar::CONV_UNSPECIFIED;
124     if (mnConv >= 0 && mnConv < nConvMapCount)
125         eConv = aConvMap[mnConv];
126 
127     rCompiler.SetRefConvention( eConv );
128 
129     rCompiler.SetCompileForFAP(mbCompileFAP);
130 
131     rCompiler.SetExternalLinks( maExternalLinks);
132 }
133 
134 uno::Sequence<sheet::FormulaToken> SAL_CALL ScFormulaParserObj::parseFormula(
135         const rtl::OUString& aFormula, const table::CellAddress& rReferencePos )
136                                 throw (uno::RuntimeException)
137 {
138     ScUnoGuard aGuard;
139     uno::Sequence<sheet::FormulaToken> aRet;
140 
141     if (mpDocShell)
142     {
143         ScDocument* pDoc = mpDocShell->GetDocument();
144         ScExternalRefManager::ApiGuard aExtRefGuard(pDoc);
145 
146         ScAddress aRefPos( ScAddress::UNINITIALIZED );
147         ScUnoConversion::FillScAddress( aRefPos, rReferencePos );
148         ScCompiler aCompiler( pDoc, aRefPos);
149         aCompiler.SetGrammar(pDoc->GetGrammar());
150         SetCompilerFlags( aCompiler );
151 
152         ScTokenArray* pCode = aCompiler.CompileString( aFormula );
153         (void)ScTokenConversion::ConvertToTokenSequence( *pDoc, aRet, *pCode );
154         delete pCode;
155     }
156 
157     return aRet;
158 }
159 
160 rtl::OUString SAL_CALL ScFormulaParserObj::printFormula(
161         const uno::Sequence<sheet::FormulaToken>& aTokens, const table::CellAddress& rReferencePos )
162                                 throw (uno::RuntimeException)
163 {
164     ScUnoGuard aGuard;
165     rtl::OUString aRet;
166 
167     if (mpDocShell)
168     {
169         ScDocument* pDoc = mpDocShell->GetDocument();
170         ScTokenArray aCode;
171         (void)ScTokenConversion::ConvertToTokenArray( *pDoc, aCode, aTokens );
172         ScAddress aRefPos( ScAddress::UNINITIALIZED );
173         ScUnoConversion::FillScAddress( aRefPos, rReferencePos );
174         ScCompiler aCompiler( pDoc, aRefPos, aCode);
175         aCompiler.SetGrammar(pDoc->GetGrammar());
176         SetCompilerFlags( aCompiler );
177 
178         rtl::OUStringBuffer aBuffer;
179         aCompiler.CreateStringFromTokenArray( aBuffer );
180         aRet = aBuffer.makeStringAndClear();
181     }
182 
183     return aRet;
184 }
185 
186 // XPropertySet
187 
188 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScFormulaParserObj::getPropertySetInfo()
189                                                         throw(uno::RuntimeException)
190 {
191     ScUnoGuard aGuard;
192     static uno::Reference< beans::XPropertySetInfo > aRef(new SfxItemPropertySetInfo( lcl_GetFormulaParserMap() ));
193     return aRef;
194 }
195 
196 void SAL_CALL ScFormulaParserObj::setPropertyValue(
197                         const rtl::OUString& aPropertyName, const uno::Any& aValue )
198                 throw(beans::UnknownPropertyException, beans::PropertyVetoException,
199                         lang::IllegalArgumentException, lang::WrappedTargetException,
200                         uno::RuntimeException)
201 {
202     ScUnoGuard aGuard;
203     String aString(aPropertyName);
204     if ( aString.EqualsAscii( SC_UNO_COMPILEFAP ) )
205     {
206         aValue >>= mbCompileFAP;
207     }
208     else if ( aString.EqualsAscii( SC_UNO_COMPILEENGLISH ) )
209     {
210         bool bOldEnglish = mbEnglish;
211         if (aValue >>= mbEnglish)
212         {
213             // Need to recreate the symbol map to change English property
214             // because the map is const. So for performance reasons set
215             // CompileEnglish _before_ OpCodeMap!
216             if (mxOpCodeMap.get() && mbEnglish != bOldEnglish)
217             {
218                 ScDocument* pDoc = mpDocShell->GetDocument();
219                 ScCompiler aCompiler( pDoc, ScAddress());
220                 aCompiler.SetGrammar(pDoc->GetGrammar());
221                 mxOpCodeMap = aCompiler.CreateOpCodeMap( maOpCodeMapping, mbEnglish);
222             }
223         }
224         else
225             throw lang::IllegalArgumentException();
226     }
227     else if ( aString.EqualsAscii( SC_UNO_FORMULACONVENTION ) )
228     {
229         aValue >>= mnConv;
230     }
231     else if ( aString.EqualsAscii( SC_UNO_IGNORELEADING ) )
232     {
233         aValue >>= mbIgnoreSpaces;
234     }
235     else if ( aString.EqualsAscii( SC_UNO_OPCODEMAP ) )
236     {
237         if (aValue >>= maOpCodeMapping)
238         {
239             ScDocument* pDoc = mpDocShell->GetDocument();
240             ScCompiler aCompiler( pDoc, ScAddress());
241             aCompiler.SetGrammar(pDoc->GetGrammar());
242             mxOpCodeMap = aCompiler.CreateOpCodeMap( maOpCodeMapping, mbEnglish);
243         }
244         else
245             throw lang::IllegalArgumentException();
246     }
247     else if ( aString.EqualsAscii( SC_UNO_EXTERNALLINKS ) )
248     {
249         if (!(aValue >>= maExternalLinks))
250             throw lang::IllegalArgumentException();
251     }
252     else
253         throw beans::UnknownPropertyException();
254 }
255 
256 uno::Any SAL_CALL ScFormulaParserObj::getPropertyValue( const rtl::OUString& aPropertyName )
257                 throw(beans::UnknownPropertyException, lang::WrappedTargetException,
258                         uno::RuntimeException)
259 {
260     ScUnoGuard aGuard;
261     uno::Any aRet;
262     String aString(aPropertyName);
263     if ( aString.EqualsAscii( SC_UNO_COMPILEFAP ) )
264     {
265         aRet <<= mbCompileFAP;
266     }
267     else if ( aString.EqualsAscii( SC_UNO_COMPILEENGLISH ) )
268     {
269         aRet <<= mbEnglish;
270     }
271     else if ( aString.EqualsAscii( SC_UNO_FORMULACONVENTION ) )
272     {
273         aRet <<= mnConv;
274     }
275     else if ( aString.EqualsAscii( SC_UNO_IGNORELEADING ) )
276     {
277         aRet <<= mbIgnoreSpaces;
278     }
279     else if ( aString.EqualsAscii( SC_UNO_OPCODEMAP ) )
280     {
281         aRet <<= maOpCodeMapping;
282     }
283     else if ( aString.EqualsAscii( SC_UNO_EXTERNALLINKS ) )
284     {
285         aRet <<= maExternalLinks;
286     }
287     else
288         throw beans::UnknownPropertyException();
289     return aRet;
290 }
291 
292 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFormulaParserObj )
293 
294 // ============================================================================
295 
296 void lcl_ExternalRefToApi( sheet::SingleReference& rAPI, const ScSingleRefData& rRef )
297 {
298     rAPI.Column         = rRef.nCol;
299     rAPI.Row            = rRef.nRow;
300     rAPI.Sheet          = 0;
301     rAPI.RelativeColumn = rRef.nRelCol;
302     rAPI.RelativeRow    = rRef.nRelRow;
303     rAPI.RelativeSheet  = 0;
304 
305     sal_Int32 nFlags = 0;
306     if ( rRef.IsColRel() )     nFlags |= sheet::ReferenceFlags::COLUMN_RELATIVE;
307     if ( rRef.IsRowRel() )     nFlags |= sheet::ReferenceFlags::ROW_RELATIVE;
308     if ( rRef.IsColDeleted() ) nFlags |= sheet::ReferenceFlags::COLUMN_DELETED;
309     if ( rRef.IsRowDeleted() ) nFlags |= sheet::ReferenceFlags::ROW_DELETED;
310     if ( rRef.IsFlag3D() )     nFlags |= sheet::ReferenceFlags::SHEET_3D;
311     if ( rRef.IsRelName() )    nFlags |= sheet::ReferenceFlags::RELATIVE_NAME;
312     rAPI.Flags = nFlags;
313 }
314 
315 void lcl_SingleRefToApi( sheet::SingleReference& rAPI, const ScSingleRefData& rRef )
316 {
317     rAPI.Column         = rRef.nCol;
318     rAPI.Row            = rRef.nRow;
319     rAPI.Sheet          = rRef.nTab;
320     rAPI.RelativeColumn = rRef.nRelCol;
321     rAPI.RelativeRow    = rRef.nRelRow;
322     rAPI.RelativeSheet  = rRef.nRelTab;
323 
324     sal_Int32 nFlags = 0;
325     if ( rRef.IsColRel() )     nFlags |= sheet::ReferenceFlags::COLUMN_RELATIVE;
326     if ( rRef.IsRowRel() )     nFlags |= sheet::ReferenceFlags::ROW_RELATIVE;
327     if ( rRef.IsTabRel() )     nFlags |= sheet::ReferenceFlags::SHEET_RELATIVE;
328     if ( rRef.IsColDeleted() ) nFlags |= sheet::ReferenceFlags::COLUMN_DELETED;
329     if ( rRef.IsRowDeleted() ) nFlags |= sheet::ReferenceFlags::ROW_DELETED;
330     if ( rRef.IsTabDeleted() ) nFlags |= sheet::ReferenceFlags::SHEET_DELETED;
331     if ( rRef.IsFlag3D() )     nFlags |= sheet::ReferenceFlags::SHEET_3D;
332     if ( rRef.IsRelName() )    nFlags |= sheet::ReferenceFlags::RELATIVE_NAME;
333     rAPI.Flags = nFlags;
334 }
335 
336 // static
337 bool ScTokenConversion::ConvertToTokenArray( ScDocument& rDoc,
338         ScTokenArray& rTokenArray, const uno::Sequence<sheet::FormulaToken>& rSequence )
339 {
340     return !rTokenArray.Fill(rSequence,rDoc.GetExternalRefManager());
341 }
342 
343 // static
344 bool ScTokenConversion::ConvertToTokenSequence( ScDocument& rDoc,
345         uno::Sequence<sheet::FormulaToken>& rSequence, const ScTokenArray& rTokenArray )
346 {
347     bool bError = false;
348 
349     sal_Int32 nLen = static_cast<sal_Int32>(rTokenArray.GetLen());
350     formula::FormulaToken** pTokens = rTokenArray.GetArray();
351     if ( pTokens )
352     {
353         rSequence.realloc(nLen);
354         for (sal_Int32 nPos=0; nPos<nLen; nPos++)
355         {
356             const formula::FormulaToken& rToken = *pTokens[nPos];
357             sheet::FormulaToken& rAPI = rSequence[nPos];
358 
359             OpCode eOpCode = rToken.GetOpCode();
360             // eOpCode may be changed in the following switch/case
361             switch ( rToken.GetType() )
362             {
363                 case svByte:
364                     // Only the count of spaces is stored as "long". Parameter count is ignored.
365                     if ( eOpCode == ocSpaces )
366                         rAPI.Data <<= (sal_Int32) rToken.GetByte();
367                     else
368                         rAPI.Data.clear();      // no data
369                     break;
370                 case formula::svDouble:
371                     rAPI.Data <<= rToken.GetDouble();
372                     break;
373                 case formula::svString:
374                     rAPI.Data <<= rtl::OUString( rToken.GetString() );
375                     break;
376                 case svExternal:
377                     // Function name is stored as string.
378                     // Byte (parameter count) is ignored.
379                     rAPI.Data <<= rtl::OUString( rToken.GetExternal() );
380                     break;
381                 case svSingleRef:
382                     {
383                         sheet::SingleReference aSingleRef;
384                         lcl_SingleRefToApi( aSingleRef, static_cast<const ScToken&>(rToken).GetSingleRef() );
385                         rAPI.Data <<= aSingleRef;
386                     }
387                     break;
388                 case formula::svDoubleRef:
389                     {
390                         sheet::ComplexReference aCompRef;
391                         lcl_SingleRefToApi( aCompRef.Reference1, static_cast<const ScToken&>(rToken).GetSingleRef() );
392                         lcl_SingleRefToApi( aCompRef.Reference2, static_cast<const ScToken&>(rToken).GetSingleRef2() );
393                         rAPI.Data <<= aCompRef;
394                     }
395                     break;
396                 case svIndex:
397                     rAPI.Data <<= static_cast<sal_Int32>( rToken.GetIndex() );
398                     break;
399                 case svMatrix:
400                     if (!ScRangeToSequence::FillMixedArray( rAPI.Data, static_cast<const ScToken&>(rToken).GetMatrix(), true))
401                         rAPI.Data.clear();
402                     break;
403                 case svExternalSingleRef:
404                     {
405                         sheet::SingleReference aSingleRef;
406                         lcl_ExternalRefToApi( aSingleRef, static_cast<const ScToken&>(rToken).GetSingleRef() );
407                         size_t nCacheId;
408                         rDoc.GetExternalRefManager()->getCacheTable( rToken.GetIndex(), rToken.GetString(), false, &nCacheId );
409                         aSingleRef.Sheet = static_cast< sal_Int32 >( nCacheId );
410                         sheet::ExternalReference aExtRef;
411                         aExtRef.Index = rToken.GetIndex();
412                         aExtRef.Reference <<= aSingleRef;
413                         rAPI.Data <<= aExtRef;
414                         eOpCode = ocPush;
415                     }
416                     break;
417                 case svExternalDoubleRef:
418                     {
419                         sheet::ComplexReference aComplRef;
420                         lcl_ExternalRefToApi( aComplRef.Reference1, static_cast<const ScToken&>(rToken).GetSingleRef() );
421                         lcl_ExternalRefToApi( aComplRef.Reference2, static_cast<const ScToken&>(rToken).GetSingleRef2() );
422                         size_t nCacheId;
423                         rDoc.GetExternalRefManager()->getCacheTable( rToken.GetIndex(), rToken.GetString(), false, &nCacheId );
424                         aComplRef.Reference1.Sheet = static_cast< sal_Int32 >( nCacheId );
425                         // NOTE: This assumes that cached sheets are in consecutive order!
426                         aComplRef.Reference2.Sheet = aComplRef.Reference1.Sheet + (static_cast<const ScToken&>(rToken).GetSingleRef2().nTab - static_cast<const ScToken&>(rToken).GetSingleRef().nTab);
427                         sheet::ExternalReference aExtRef;
428                         aExtRef.Index = rToken.GetIndex();
429                         aExtRef.Reference <<= aComplRef;
430                         rAPI.Data <<= aExtRef;
431                         eOpCode = ocPush;
432                     }
433                     break;
434                 case svExternalName:
435                     {
436                         sheet::ExternalReference aExtRef;
437                         aExtRef.Index = rToken.GetIndex();
438                         aExtRef.Reference <<= ::rtl::OUString( rToken.GetString() );
439                         rAPI.Data <<= aExtRef;
440                         eOpCode = ocPush;
441                     }
442                     break;
443                 default:
444                     DBG_ERROR1( "ScTokenConversion::ConvertToTokenSequence: unhandled token type SvStackVar %d", rToken.GetType());
445                 case svSep:     // occurs with ocSep, ocOpen, ocClose, ocArray*
446                 case svJump:    // occurs with ocIf, ocChose
447                 case svMissing: // occurs with ocMissing
448                     rAPI.Data.clear();      // no data
449             }
450             rAPI.OpCode = static_cast<sal_Int32>(eOpCode);      //! assuming equal values for the moment
451         }
452     }
453     else
454         rSequence.realloc(0);
455 
456     return !bError;
457 }
458 
459 // ============================================================================
460 
461 ScFormulaOpCodeMapperObj::ScFormulaOpCodeMapperObj(::std::auto_ptr<formula::FormulaCompiler> _pCompiler)
462 : formula::FormulaOpCodeMapperObj(_pCompiler)
463 {
464 }
465 
466 // ============================================================================
467 
468