xref: /trunk/main/sc/source/ui/unoobj/tokenuno.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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 {
133     ScUnoGuard aGuard;
134     uno::Sequence<sheet::FormulaToken> aRet;
135 
136     if (mpDocShell)
137     {
138         ScDocument* pDoc = mpDocShell->GetDocument();
139         ScExternalRefManager::ApiGuard aExtRefGuard(pDoc);
140 
141         ScAddress aRefPos( ScAddress::UNINITIALIZED );
142         ScUnoConversion::FillScAddress( aRefPos, rReferencePos );
143         ScCompiler aCompiler( pDoc, aRefPos);
144         aCompiler.SetGrammar(pDoc->GetGrammar());
145         SetCompilerFlags( aCompiler );
146 
147         ScTokenArray* pCode = aCompiler.CompileString( aFormula );
148         (void)ScTokenConversion::ConvertToTokenSequence( *pDoc, aRet, *pCode );
149         delete pCode;
150     }
151 
152     return aRet;
153 }
154 
printFormula(const uno::Sequence<sheet::FormulaToken> & aTokens,const table::CellAddress & rReferencePos)155 rtl::OUString SAL_CALL ScFormulaParserObj::printFormula(
156         const uno::Sequence<sheet::FormulaToken>& aTokens, const table::CellAddress& rReferencePos )
157 {
158     ScUnoGuard aGuard;
159     rtl::OUString aRet;
160 
161     if (mpDocShell)
162     {
163         ScDocument* pDoc = mpDocShell->GetDocument();
164         ScTokenArray aCode;
165         (void)ScTokenConversion::ConvertToTokenArray( *pDoc, aCode, aTokens );
166         ScAddress aRefPos( ScAddress::UNINITIALIZED );
167         ScUnoConversion::FillScAddress( aRefPos, rReferencePos );
168         ScCompiler aCompiler( pDoc, aRefPos, aCode);
169         aCompiler.SetGrammar(pDoc->GetGrammar());
170         SetCompilerFlags( aCompiler );
171 
172         rtl::OUStringBuffer aBuffer;
173         aCompiler.CreateStringFromTokenArray( aBuffer );
174         aRet = aBuffer.makeStringAndClear();
175     }
176 
177     return aRet;
178 }
179 
180 // XPropertySet
181 
getPropertySetInfo()182 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScFormulaParserObj::getPropertySetInfo()
183 {
184     ScUnoGuard aGuard;
185     static uno::Reference< beans::XPropertySetInfo > aRef(new SfxItemPropertySetInfo( lcl_GetFormulaParserMap() ));
186     return aRef;
187 }
188 
setPropertyValue(const rtl::OUString & aPropertyName,const uno::Any & aValue)189 void SAL_CALL ScFormulaParserObj::setPropertyValue(
190                         const rtl::OUString& aPropertyName, const uno::Any& aValue )
191 {
192     ScUnoGuard aGuard;
193     String aString(aPropertyName);
194     if ( aString.EqualsAscii( SC_UNO_COMPILEFAP ) )
195     {
196         aValue >>= mbCompileFAP;
197     }
198     else if ( aString.EqualsAscii( SC_UNO_COMPILEENGLISH ) )
199     {
200         bool bOldEnglish = mbEnglish;
201         if (aValue >>= mbEnglish)
202         {
203             // Need to recreate the symbol map to change English property
204             // because the map is const. So for performance reasons set
205             // CompileEnglish _before_ OpCodeMap!
206             if (mxOpCodeMap.get() && mbEnglish != bOldEnglish)
207             {
208                 ScDocument* pDoc = mpDocShell->GetDocument();
209                 ScCompiler aCompiler( pDoc, ScAddress());
210                 aCompiler.SetGrammar(pDoc->GetGrammar());
211                 mxOpCodeMap = aCompiler.CreateOpCodeMap( maOpCodeMapping, mbEnglish);
212             }
213         }
214         else
215             throw lang::IllegalArgumentException();
216     }
217     else if ( aString.EqualsAscii( SC_UNO_FORMULACONVENTION ) )
218     {
219         aValue >>= mnConv;
220     }
221     else if ( aString.EqualsAscii( SC_UNO_IGNORELEADING ) )
222     {
223         aValue >>= mbIgnoreSpaces;
224     }
225     else if ( aString.EqualsAscii( SC_UNO_OPCODEMAP ) )
226     {
227         if (aValue >>= maOpCodeMapping)
228         {
229             ScDocument* pDoc = mpDocShell->GetDocument();
230             ScCompiler aCompiler( pDoc, ScAddress());
231             aCompiler.SetGrammar(pDoc->GetGrammar());
232             mxOpCodeMap = aCompiler.CreateOpCodeMap( maOpCodeMapping, mbEnglish);
233         }
234         else
235             throw lang::IllegalArgumentException();
236     }
237     else if ( aString.EqualsAscii( SC_UNO_EXTERNALLINKS ) )
238     {
239         if (!(aValue >>= maExternalLinks))
240             throw lang::IllegalArgumentException();
241     }
242     else
243         throw beans::UnknownPropertyException();
244 }
245 
getPropertyValue(const rtl::OUString & aPropertyName)246 uno::Any SAL_CALL ScFormulaParserObj::getPropertyValue( const rtl::OUString& aPropertyName )
247 {
248     ScUnoGuard aGuard;
249     uno::Any aRet;
250     String aString(aPropertyName);
251     if ( aString.EqualsAscii( SC_UNO_COMPILEFAP ) )
252     {
253         aRet <<= mbCompileFAP;
254     }
255     else if ( aString.EqualsAscii( SC_UNO_COMPILEENGLISH ) )
256     {
257         aRet <<= mbEnglish;
258     }
259     else if ( aString.EqualsAscii( SC_UNO_FORMULACONVENTION ) )
260     {
261         aRet <<= mnConv;
262     }
263     else if ( aString.EqualsAscii( SC_UNO_IGNORELEADING ) )
264     {
265         aRet <<= mbIgnoreSpaces;
266     }
267     else if ( aString.EqualsAscii( SC_UNO_OPCODEMAP ) )
268     {
269         aRet <<= maOpCodeMapping;
270     }
271     else if ( aString.EqualsAscii( SC_UNO_EXTERNALLINKS ) )
272     {
273         aRet <<= maExternalLinks;
274     }
275     else
276         throw beans::UnknownPropertyException();
277     return aRet;
278 }
279 
SC_IMPL_DUMMY_PROPERTY_LISTENER(ScFormulaParserObj)280 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFormulaParserObj )
281 
282 // ============================================================================
283 
284 void lcl_ExternalRefToApi( sheet::SingleReference& rAPI, const ScSingleRefData& rRef )
285 {
286     rAPI.Column         = rRef.nCol;
287     rAPI.Row            = rRef.nRow;
288     rAPI.Sheet          = 0;
289     rAPI.RelativeColumn = rRef.nRelCol;
290     rAPI.RelativeRow    = rRef.nRelRow;
291     rAPI.RelativeSheet  = 0;
292 
293     sal_Int32 nFlags = 0;
294     if ( rRef.IsColRel() )     nFlags |= sheet::ReferenceFlags::COLUMN_RELATIVE;
295     if ( rRef.IsRowRel() )     nFlags |= sheet::ReferenceFlags::ROW_RELATIVE;
296     if ( rRef.IsColDeleted() ) nFlags |= sheet::ReferenceFlags::COLUMN_DELETED;
297     if ( rRef.IsRowDeleted() ) nFlags |= sheet::ReferenceFlags::ROW_DELETED;
298     if ( rRef.IsFlag3D() )     nFlags |= sheet::ReferenceFlags::SHEET_3D;
299     if ( rRef.IsRelName() )    nFlags |= sheet::ReferenceFlags::RELATIVE_NAME;
300     rAPI.Flags = nFlags;
301 }
302 
lcl_SingleRefToApi(sheet::SingleReference & rAPI,const ScSingleRefData & rRef)303 void lcl_SingleRefToApi( sheet::SingleReference& rAPI, const ScSingleRefData& rRef )
304 {
305     rAPI.Column         = rRef.nCol;
306     rAPI.Row            = rRef.nRow;
307     rAPI.Sheet          = rRef.nTab;
308     rAPI.RelativeColumn = rRef.nRelCol;
309     rAPI.RelativeRow    = rRef.nRelRow;
310     rAPI.RelativeSheet  = rRef.nRelTab;
311 
312     sal_Int32 nFlags = 0;
313     if ( rRef.IsColRel() )     nFlags |= sheet::ReferenceFlags::COLUMN_RELATIVE;
314     if ( rRef.IsRowRel() )     nFlags |= sheet::ReferenceFlags::ROW_RELATIVE;
315     if ( rRef.IsTabRel() )     nFlags |= sheet::ReferenceFlags::SHEET_RELATIVE;
316     if ( rRef.IsColDeleted() ) nFlags |= sheet::ReferenceFlags::COLUMN_DELETED;
317     if ( rRef.IsRowDeleted() ) nFlags |= sheet::ReferenceFlags::ROW_DELETED;
318     if ( rRef.IsTabDeleted() ) nFlags |= sheet::ReferenceFlags::SHEET_DELETED;
319     if ( rRef.IsFlag3D() )     nFlags |= sheet::ReferenceFlags::SHEET_3D;
320     if ( rRef.IsRelName() )    nFlags |= sheet::ReferenceFlags::RELATIVE_NAME;
321     rAPI.Flags = nFlags;
322 }
323 
324 // static
ConvertToTokenArray(ScDocument & rDoc,ScTokenArray & rTokenArray,const uno::Sequence<sheet::FormulaToken> & rSequence)325 bool ScTokenConversion::ConvertToTokenArray( ScDocument& rDoc,
326         ScTokenArray& rTokenArray, const uno::Sequence<sheet::FormulaToken>& rSequence )
327 {
328     return !rTokenArray.Fill(rSequence,rDoc.GetExternalRefManager());
329 }
330 
331 // static
ConvertToTokenSequence(ScDocument & rDoc,uno::Sequence<sheet::FormulaToken> & rSequence,const ScTokenArray & rTokenArray)332 bool ScTokenConversion::ConvertToTokenSequence( ScDocument& rDoc,
333         uno::Sequence<sheet::FormulaToken>& rSequence, const ScTokenArray& rTokenArray )
334 {
335     bool bError = false;
336 
337     sal_Int32 nLen = static_cast<sal_Int32>(rTokenArray.GetLen());
338     formula::FormulaToken** pTokens = rTokenArray.GetArray();
339     if ( pTokens )
340     {
341         rSequence.realloc(nLen);
342         for (sal_Int32 nPos=0; nPos<nLen; nPos++)
343         {
344             const formula::FormulaToken& rToken = *pTokens[nPos];
345             sheet::FormulaToken& rAPI = rSequence[nPos];
346 
347             OpCode eOpCode = rToken.GetOpCode();
348             // eOpCode may be changed in the following switch/case
349             switch ( rToken.GetType() )
350             {
351                 case svByte:
352                     // Only the count of spaces is stored as "long". Parameter count is ignored.
353                     if ( eOpCode == ocSpaces )
354                         rAPI.Data <<= (sal_Int32) rToken.GetByte();
355                     else
356                         rAPI.Data.clear();      // no data
357                     break;
358                 case formula::svDouble:
359                     rAPI.Data <<= rToken.GetDouble();
360                     break;
361                 case formula::svString:
362                     rAPI.Data <<= rtl::OUString( rToken.GetString() );
363                     break;
364                 case svExternal:
365                     // Function name is stored as string.
366                     // Byte (parameter count) is ignored.
367                     rAPI.Data <<= rtl::OUString( rToken.GetExternal() );
368                     break;
369                 case svSingleRef:
370                     {
371                         sheet::SingleReference aSingleRef;
372                         lcl_SingleRefToApi( aSingleRef, static_cast<const ScToken&>(rToken).GetSingleRef() );
373                         rAPI.Data <<= aSingleRef;
374                     }
375                     break;
376                 case formula::svDoubleRef:
377                     {
378                         sheet::ComplexReference aCompRef;
379                         lcl_SingleRefToApi( aCompRef.Reference1, static_cast<const ScToken&>(rToken).GetSingleRef() );
380                         lcl_SingleRefToApi( aCompRef.Reference2, static_cast<const ScToken&>(rToken).GetSingleRef2() );
381                         rAPI.Data <<= aCompRef;
382                     }
383                     break;
384                 case svIndex:
385                     rAPI.Data <<= static_cast<sal_Int32>( rToken.GetIndex() );
386                     break;
387                 case svMatrix:
388                     if (!ScRangeToSequence::FillMixedArray( rAPI.Data, static_cast<const ScToken&>(rToken).GetMatrix(), true))
389                         rAPI.Data.clear();
390                     break;
391                 case svExternalSingleRef:
392                     {
393                         sheet::SingleReference aSingleRef;
394                         lcl_ExternalRefToApi( aSingleRef, static_cast<const ScToken&>(rToken).GetSingleRef() );
395                         size_t nCacheId;
396                         rDoc.GetExternalRefManager()->getCacheTable( rToken.GetIndex(), rToken.GetString(), false, &nCacheId );
397                         aSingleRef.Sheet = static_cast< sal_Int32 >( nCacheId );
398                         sheet::ExternalReference aExtRef;
399                         aExtRef.Index = rToken.GetIndex();
400                         aExtRef.Reference <<= aSingleRef;
401                         rAPI.Data <<= aExtRef;
402                         eOpCode = ocPush;
403                     }
404                     break;
405                 case svExternalDoubleRef:
406                     {
407                         sheet::ComplexReference aComplRef;
408                         lcl_ExternalRefToApi( aComplRef.Reference1, static_cast<const ScToken&>(rToken).GetSingleRef() );
409                         lcl_ExternalRefToApi( aComplRef.Reference2, static_cast<const ScToken&>(rToken).GetSingleRef2() );
410                         size_t nCacheId;
411                         rDoc.GetExternalRefManager()->getCacheTable( rToken.GetIndex(), rToken.GetString(), false, &nCacheId );
412                         aComplRef.Reference1.Sheet = static_cast< sal_Int32 >( nCacheId );
413                         // NOTE: This assumes that cached sheets are in consecutive order!
414                         aComplRef.Reference2.Sheet = aComplRef.Reference1.Sheet + (static_cast<const ScToken&>(rToken).GetSingleRef2().nTab - static_cast<const ScToken&>(rToken).GetSingleRef().nTab);
415                         sheet::ExternalReference aExtRef;
416                         aExtRef.Index = rToken.GetIndex();
417                         aExtRef.Reference <<= aComplRef;
418                         rAPI.Data <<= aExtRef;
419                         eOpCode = ocPush;
420                     }
421                     break;
422                 case svExternalName:
423                     {
424                         sheet::ExternalReference aExtRef;
425                         aExtRef.Index = rToken.GetIndex();
426                         aExtRef.Reference <<= ::rtl::OUString( rToken.GetString() );
427                         rAPI.Data <<= aExtRef;
428                         eOpCode = ocPush;
429                     }
430                     break;
431                 default:
432                     DBG_ERROR1( "ScTokenConversion::ConvertToTokenSequence: unhandled token type SvStackVar %d", rToken.GetType());
433                 case svSep:     // occurs with ocSep, ocOpen, ocClose, ocArray*
434                 case svJump:    // occurs with ocIf, ocChose
435                 case svMissing: // occurs with ocMissing
436                     rAPI.Data.clear();      // no data
437             }
438             rAPI.OpCode = static_cast<sal_Int32>(eOpCode);      //! assuming equal values for the moment
439         }
440     }
441     else
442         rSequence.realloc(0);
443 
444     return !bError;
445 }
446 
447 // ============================================================================
448 
ScFormulaOpCodeMapperObj(::std::auto_ptr<formula::FormulaCompiler> _pCompiler)449 ScFormulaOpCodeMapperObj::ScFormulaOpCodeMapperObj(::std::auto_ptr<formula::FormulaCompiler> _pCompiler)
450 : formula::FormulaOpCodeMapperObj(_pCompiler)
451 {
452 }
453 
454 // ============================================================================
455