Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / ui / unoobj / tokenuno.cxx
blobff1b41731b1271d381c626d7948ef2995ce719a3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "tokenuno.hxx"
23 #include <sal/macros.h>
25 #include <com/sun/star/sheet/ComplexReference.hpp>
26 #include <com/sun/star/sheet/ExternalReference.hpp>
27 #include <com/sun/star/sheet/ReferenceFlags.hpp>
28 #include <com/sun/star/sheet/AddressConvention.hpp>
29 #include <com/sun/star/sheet/NameToken.hpp>
30 #include <com/sun/star/table/CellAddress.hpp>
32 #include <svl/itemprop.hxx>
33 #include <vcl/svapp.hxx>
35 #include "miscuno.hxx"
36 #include "convuno.hxx"
37 #include "unonames.hxx"
38 #include "token.hxx"
39 #include "compiler.hxx"
40 #include "tokenarray.hxx"
41 #include "docsh.hxx"
42 #include "rangeseq.hxx"
43 #include "externalrefmgr.hxx"
45 using namespace ::formula;
46 using namespace ::com::sun::star;
48 // ============================================================================
50 static const SfxItemPropertyMapEntry* lcl_GetFormulaParserMap()
52 static const SfxItemPropertyMapEntry aFormulaParserMap_Impl[] =
54 {MAP_CHAR_LEN(SC_UNO_COMPILEFAP), 0, &getBooleanCppuType(), 0, 0 },
55 {MAP_CHAR_LEN(SC_UNO_COMPILEENGLISH), 0, &getBooleanCppuType(), 0, 0 },
56 {MAP_CHAR_LEN(SC_UNO_IGNORELEADING), 0, &getBooleanCppuType(), 0, 0 },
57 {MAP_CHAR_LEN(SC_UNO_FORMULACONVENTION), 0, &getCppuType(&sheet::AddressConvention::UNSPECIFIED), 0, 0 },
58 {MAP_CHAR_LEN(SC_UNO_OPCODEMAP), 0, &getCppuType((uno::Sequence< sheet::FormulaOpCodeMapEntry >*)0), 0, 0 },
59 {0,0,0,0,0,0}
61 return aFormulaParserMap_Impl;
64 SC_SIMPLE_SERVICE_INFO( ScFormulaParserObj, "ScFormulaParserObj", SC_SERVICENAME_FORMULAPARS )
66 // ============================================================================
68 ScFormulaParserObj::ScFormulaParserObj(ScDocShell* pDocSh) :
69 mpDocShell( pDocSh ),
70 mnConv( sheet::AddressConvention::UNSPECIFIED ),
71 mbEnglish( false ),
72 mbIgnoreSpaces( true ),
73 mbCompileFAP( false )
75 mpDocShell->GetDocument()->AddUnoObject(*this);
78 ScFormulaParserObj::~ScFormulaParserObj()
80 if (mpDocShell)
81 mpDocShell->GetDocument()->RemoveUnoObject(*this);
84 void ScFormulaParserObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
86 if ( rHint.ISA( SfxSimpleHint ) && ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING )
87 mpDocShell = NULL;
90 // XFormulaParser
92 void ScFormulaParserObj::SetCompilerFlags( ScCompiler& rCompiler ) const
94 static const formula::FormulaGrammar::AddressConvention aConvMap[] = {
95 formula::FormulaGrammar::CONV_OOO, // <- AddressConvention::OOO
96 formula::FormulaGrammar::CONV_XL_A1, // <- AddressConvention::XL_A1
97 formula::FormulaGrammar::CONV_XL_R1C1, // <- AddressConvention::XL_R1C1
98 formula::FormulaGrammar::CONV_XL_OOX, // <- AddressConvention::XL_OOX
99 formula::FormulaGrammar::CONV_LOTUS_A1 // <- AddressConvention::LOTUS_A1
101 static const sal_Int16 nConvMapCount = sizeof(aConvMap)/sizeof(aConvMap[0]);
103 // If mxOpCodeMap is not empty it overrides mbEnglish, and vice versa. We
104 // don't need to initialize things twice.
105 if (mxOpCodeMap.get())
106 rCompiler.SetFormulaLanguage( mxOpCodeMap );
107 else
109 sal_Int32 nFormulaLanguage = mbEnglish ?
110 sheet::FormulaLanguage::ENGLISH :
111 sheet::FormulaLanguage::NATIVE;
112 ScCompiler::OpCodeMapPtr xMap = rCompiler.GetOpCodeMap( nFormulaLanguage);
113 rCompiler.SetFormulaLanguage( xMap);
116 formula::FormulaGrammar::AddressConvention eConv = formula::FormulaGrammar::CONV_UNSPECIFIED;
117 if (mnConv >= 0 && mnConv < nConvMapCount)
118 eConv = aConvMap[mnConv];
120 rCompiler.SetRefConvention( eConv );
122 rCompiler.SetCompileForFAP(mbCompileFAP);
124 rCompiler.SetExternalLinks( maExternalLinks);
127 uno::Sequence<sheet::FormulaToken> SAL_CALL ScFormulaParserObj::parseFormula(
128 const OUString& aFormula, const table::CellAddress& rReferencePos )
129 throw (uno::RuntimeException)
131 SolarMutexGuard aGuard;
132 uno::Sequence<sheet::FormulaToken> aRet;
134 if (mpDocShell)
136 ScDocument* pDoc = mpDocShell->GetDocument();
137 ScExternalRefManager::ApiGuard aExtRefGuard(pDoc);
139 ScAddress aRefPos( ScAddress::UNINITIALIZED );
140 ScUnoConversion::FillScAddress( aRefPos, rReferencePos );
141 ScCompiler aCompiler( pDoc, aRefPos);
142 aCompiler.SetGrammar(pDoc->GetGrammar());
143 SetCompilerFlags( aCompiler );
145 ScTokenArray* pCode = aCompiler.CompileString( aFormula );
146 (void)ScTokenConversion::ConvertToTokenSequence( *pDoc, aRet, *pCode );
147 delete pCode;
150 return aRet;
153 OUString SAL_CALL ScFormulaParserObj::printFormula(
154 const uno::Sequence<sheet::FormulaToken>& aTokens, const table::CellAddress& rReferencePos )
155 throw (uno::RuntimeException)
157 SolarMutexGuard aGuard;
158 OUString aRet;
160 if (mpDocShell)
162 ScDocument* pDoc = mpDocShell->GetDocument();
163 ScTokenArray aCode;
164 (void)ScTokenConversion::ConvertToTokenArray( *pDoc, aCode, aTokens );
165 ScAddress aRefPos( ScAddress::UNINITIALIZED );
166 ScUnoConversion::FillScAddress( aRefPos, rReferencePos );
167 ScCompiler aCompiler( pDoc, aRefPos, aCode);
168 aCompiler.SetGrammar(pDoc->GetGrammar());
169 SetCompilerFlags( aCompiler );
171 OUStringBuffer aBuffer;
172 aCompiler.CreateStringFromTokenArray( aBuffer );
173 aRet = aBuffer.makeStringAndClear();
176 return aRet;
179 // XPropertySet
181 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScFormulaParserObj::getPropertySetInfo()
182 throw(uno::RuntimeException)
184 SolarMutexGuard aGuard;
185 static uno::Reference< beans::XPropertySetInfo > aRef(new SfxItemPropertySetInfo( lcl_GetFormulaParserMap() ));
186 return aRef;
189 void SAL_CALL ScFormulaParserObj::setPropertyValue(
190 const OUString& aPropertyName, const uno::Any& aValue )
191 throw(beans::UnknownPropertyException, beans::PropertyVetoException,
192 lang::IllegalArgumentException, lang::WrappedTargetException,
193 uno::RuntimeException)
195 SolarMutexGuard aGuard;
196 OUString aString(aPropertyName);
197 if ( aString.equalsAscii( SC_UNO_COMPILEFAP ) )
199 aValue >>= mbCompileFAP;
201 else if ( aString.equalsAscii( SC_UNO_COMPILEENGLISH ) )
203 bool bOldEnglish = mbEnglish;
204 if (aValue >>= mbEnglish)
206 // Need to recreate the symbol map to change English property
207 // because the map is const. So for performance reasons set
208 // CompileEnglish _before_ OpCodeMap!
209 if (mxOpCodeMap.get() && mbEnglish != bOldEnglish)
211 ScDocument* pDoc = mpDocShell->GetDocument();
212 ScCompiler aCompiler( pDoc, ScAddress());
213 aCompiler.SetGrammar(pDoc->GetGrammar());
214 mxOpCodeMap = aCompiler.CreateOpCodeMap( maOpCodeMapping, mbEnglish);
217 else
218 throw lang::IllegalArgumentException();
220 else if ( aString.equalsAscii( SC_UNO_FORMULACONVENTION ) )
222 aValue >>= mnConv;
224 else if ( aString.equalsAscii( SC_UNO_IGNORELEADING ) )
226 aValue >>= mbIgnoreSpaces;
228 else if ( aString.equalsAscii( SC_UNO_OPCODEMAP ) )
230 if (aValue >>= maOpCodeMapping)
232 ScDocument* pDoc = mpDocShell->GetDocument();
233 ScCompiler aCompiler( pDoc, ScAddress());
234 aCompiler.SetGrammar(pDoc->GetGrammar());
235 mxOpCodeMap = aCompiler.CreateOpCodeMap( maOpCodeMapping, mbEnglish);
237 else
238 throw lang::IllegalArgumentException();
240 else if ( aString.equalsAscii( SC_UNO_EXTERNALLINKS ) )
242 if (!(aValue >>= maExternalLinks))
243 throw lang::IllegalArgumentException();
245 else
246 throw beans::UnknownPropertyException();
249 uno::Any SAL_CALL ScFormulaParserObj::getPropertyValue( const OUString& aPropertyName )
250 throw(beans::UnknownPropertyException, lang::WrappedTargetException,
251 uno::RuntimeException)
253 SolarMutexGuard aGuard;
254 uno::Any aRet;
255 OUString aString(aPropertyName);
256 if ( aString.equalsAscii( SC_UNO_COMPILEFAP ) )
258 aRet <<= mbCompileFAP;
260 else if ( aString.equalsAscii( SC_UNO_COMPILEENGLISH ) )
262 aRet <<= mbEnglish;
264 else if ( aString.equalsAscii( SC_UNO_FORMULACONVENTION ) )
266 aRet <<= mnConv;
268 else if ( aString.equalsAscii( SC_UNO_IGNORELEADING ) )
270 aRet <<= mbIgnoreSpaces;
272 else if ( aString.equalsAscii( SC_UNO_OPCODEMAP ) )
274 aRet <<= maOpCodeMapping;
276 else if ( aString.equalsAscii( SC_UNO_EXTERNALLINKS ) )
278 aRet <<= maExternalLinks;
280 else
281 throw beans::UnknownPropertyException();
282 return aRet;
285 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFormulaParserObj )
287 // ============================================================================
289 static void lcl_ExternalRefToApi( sheet::SingleReference& rAPI, const ScSingleRefData& rRef )
291 rAPI.Column = 0;
292 rAPI.Row = 0;
293 rAPI.Sheet = 0;
294 rAPI.RelativeColumn = 0;
295 rAPI.RelativeRow = 0;
296 rAPI.RelativeSheet = 0;
298 sal_Int32 nFlags = 0;
299 if ( rRef.IsColRel() )
301 nFlags |= sheet::ReferenceFlags::COLUMN_RELATIVE;
302 rAPI.RelativeColumn = rRef.Col();
304 else
305 rAPI.Column = rRef.Col();
307 if ( rRef.IsRowRel() )
309 nFlags |= sheet::ReferenceFlags::ROW_RELATIVE;
310 rAPI.RelativeRow = rRef.Row();
312 else
313 rAPI.Row = rRef.Row();
315 if ( rRef.IsColDeleted() ) nFlags |= sheet::ReferenceFlags::COLUMN_DELETED;
316 if ( rRef.IsRowDeleted() ) nFlags |= sheet::ReferenceFlags::ROW_DELETED;
317 if ( rRef.IsFlag3D() ) nFlags |= sheet::ReferenceFlags::SHEET_3D;
318 if ( rRef.IsRelName() ) nFlags |= sheet::ReferenceFlags::RELATIVE_NAME;
319 rAPI.Flags = nFlags;
322 static void lcl_SingleRefToApi( sheet::SingleReference& rAPI, const ScSingleRefData& rRef )
324 sal_Int32 nFlags = 0;
325 if ( rRef.IsColRel() )
327 nFlags |= sheet::ReferenceFlags::COLUMN_RELATIVE;
328 rAPI.RelativeColumn = rRef.Col();
329 rAPI.Column = 0;
331 else
333 rAPI.RelativeColumn = 0;
334 rAPI.Column = rRef.Col();
337 if ( rRef.IsRowRel() )
339 nFlags |= sheet::ReferenceFlags::ROW_RELATIVE;
340 rAPI.RelativeRow = rRef.Row();
341 rAPI.Row = 0;
343 else
345 rAPI.RelativeRow = 0;
346 rAPI.Row = rRef.Row();
349 if ( rRef.IsTabRel() )
351 nFlags |= sheet::ReferenceFlags::SHEET_RELATIVE;
352 rAPI.RelativeSheet = rRef.Tab();
353 rAPI.Sheet = 0;
355 else
357 rAPI.RelativeSheet = 0;
358 rAPI.Sheet = rRef.Tab();
361 if ( rRef.IsColDeleted() ) nFlags |= sheet::ReferenceFlags::COLUMN_DELETED;
362 if ( rRef.IsRowDeleted() ) nFlags |= sheet::ReferenceFlags::ROW_DELETED;
363 if ( rRef.IsTabDeleted() ) nFlags |= sheet::ReferenceFlags::SHEET_DELETED;
364 if ( rRef.IsFlag3D() ) nFlags |= sheet::ReferenceFlags::SHEET_3D;
365 if ( rRef.IsRelName() ) nFlags |= sheet::ReferenceFlags::RELATIVE_NAME;
366 rAPI.Flags = nFlags;
369 bool ScTokenConversion::ConvertToTokenArray( ScDocument& rDoc,
370 ScTokenArray& rTokenArray, const uno::Sequence<sheet::FormulaToken>& rSequence )
372 return !rTokenArray.Fill(rSequence,rDoc.GetExternalRefManager());
375 bool ScTokenConversion::ConvertToTokenSequence( const ScDocument& rDoc,
376 uno::Sequence<sheet::FormulaToken>& rSequence, const ScTokenArray& rTokenArray )
378 bool bError = false;
380 sal_Int32 nLen = static_cast<sal_Int32>(rTokenArray.GetLen());
381 formula::FormulaToken** pTokens = rTokenArray.GetArray();
382 if ( pTokens )
384 rSequence.realloc(nLen);
385 for (sal_Int32 nPos=0; nPos<nLen; nPos++)
387 const formula::FormulaToken& rToken = *pTokens[nPos];
388 sheet::FormulaToken& rAPI = rSequence[nPos];
390 OpCode eOpCode = rToken.GetOpCode();
391 // eOpCode may be changed in the following switch/case
392 switch ( rToken.GetType() )
394 case svByte:
395 // Only the count of spaces is stored as "long". Parameter count is ignored.
396 if ( eOpCode == ocSpaces )
397 rAPI.Data <<= (sal_Int32) rToken.GetByte();
398 else
399 rAPI.Data.clear(); // no data
400 break;
401 case formula::svDouble:
402 rAPI.Data <<= rToken.GetDouble();
403 break;
404 case formula::svString:
405 rAPI.Data <<= rToken.GetString().getString();
406 break;
407 case svExternal:
408 // Function name is stored as string.
409 // Byte (parameter count) is ignored.
410 rAPI.Data <<= OUString( rToken.GetExternal() );
411 break;
412 case svSingleRef:
414 sheet::SingleReference aSingleRef;
415 lcl_SingleRefToApi( aSingleRef, static_cast<const ScToken&>(rToken).GetSingleRef() );
416 rAPI.Data <<= aSingleRef;
418 break;
419 case formula::svDoubleRef:
421 sheet::ComplexReference aCompRef;
422 lcl_SingleRefToApi( aCompRef.Reference1, static_cast<const ScToken&>(rToken).GetSingleRef() );
423 lcl_SingleRefToApi( aCompRef.Reference2, static_cast<const ScToken&>(rToken).GetSingleRef2() );
424 rAPI.Data <<= aCompRef;
426 break;
427 case svIndex:
429 sheet::NameToken aNameToken;
430 aNameToken.Index = static_cast<sal_Int32>( rToken.GetIndex() );
431 aNameToken.Global = static_cast<sal_Bool>( rToken.IsGlobal() );
432 rAPI.Data <<= aNameToken;
434 break;
435 case svMatrix:
436 if (!ScRangeToSequence::FillMixedArray( rAPI.Data, static_cast<const ScToken&>(rToken).GetMatrix(), true))
437 rAPI.Data.clear();
438 break;
439 case svExternalSingleRef:
441 sheet::SingleReference aSingleRef;
442 lcl_ExternalRefToApi( aSingleRef, static_cast<const ScToken&>(rToken).GetSingleRef() );
443 size_t nCacheId;
444 rDoc.GetExternalRefManager()->getCacheTable(
445 rToken.GetIndex(), rToken.GetString().getString(), false, &nCacheId);
446 aSingleRef.Sheet = static_cast< sal_Int32 >( nCacheId );
447 sheet::ExternalReference aExtRef;
448 aExtRef.Index = rToken.GetIndex();
449 aExtRef.Reference <<= aSingleRef;
450 rAPI.Data <<= aExtRef;
451 eOpCode = ocPush;
453 break;
454 case svExternalDoubleRef:
456 sheet::ComplexReference aComplRef;
457 lcl_ExternalRefToApi( aComplRef.Reference1, static_cast<const ScToken&>(rToken).GetSingleRef() );
458 lcl_ExternalRefToApi( aComplRef.Reference2, static_cast<const ScToken&>(rToken).GetSingleRef2() );
459 size_t nCacheId;
460 rDoc.GetExternalRefManager()->getCacheTable(
461 rToken.GetIndex(), rToken.GetString().getString(), false, &nCacheId);
462 aComplRef.Reference1.Sheet = static_cast< sal_Int32 >( nCacheId );
463 // NOTE: This assumes that cached sheets are in consecutive order!
464 aComplRef.Reference2.Sheet =
465 aComplRef.Reference1.Sheet +
466 (static_cast<const ScToken&>(rToken).GetSingleRef2().Tab() - static_cast<const ScToken&>(rToken).GetSingleRef().Tab());
467 sheet::ExternalReference aExtRef;
468 aExtRef.Index = rToken.GetIndex();
469 aExtRef.Reference <<= aComplRef;
470 rAPI.Data <<= aExtRef;
471 eOpCode = ocPush;
473 break;
474 case svExternalName:
476 sheet::ExternalReference aExtRef;
477 aExtRef.Index = rToken.GetIndex();
478 aExtRef.Reference <<= rToken.GetString().getString();
479 rAPI.Data <<= aExtRef;
480 eOpCode = ocPush;
482 break;
483 default:
484 OSL_TRACE( "ScTokenConversion::ConvertToTokenSequence: unhandled token type SvStackVar %d", rToken.GetType());
485 case svSep: // occurs with ocSep, ocOpen, ocClose, ocArray*
486 case svJump: // occurs with ocIf, ocChose
487 case svMissing: // occurs with ocMissing
488 rAPI.Data.clear(); // no data
490 rAPI.OpCode = static_cast<sal_Int32>(eOpCode); //! assuming equal values for the moment
493 else
494 rSequence.realloc(0);
496 return !bError;
499 // ============================================================================
501 SAL_WNODEPRECATED_DECLARATIONS_PUSH
502 ScFormulaOpCodeMapperObj::ScFormulaOpCodeMapperObj(::std::auto_ptr<formula::FormulaCompiler> _pCompiler)
503 : formula::FormulaOpCodeMapperObj(_pCompiler)
506 SAL_WNODEPRECATED_DECLARATIONS_POP
508 // ============================================================================
510 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */