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