tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / unoobj / tokenuno.cxx
blobb8e4e133a11341b101c9da21384991d35434ac95
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 .
20 #include <memory>
21 #include <tokenuno.hxx>
23 #include <sal/macros.h>
24 #include <sal/log.hxx>
26 #include <com/sun/star/sheet/ComplexReference.hpp>
27 #include <com/sun/star/sheet/ExternalReference.hpp>
28 #include <com/sun/star/sheet/ReferenceFlags.hpp>
29 #include <com/sun/star/sheet/AddressConvention.hpp>
30 #include <com/sun/star/sheet/NameToken.hpp>
31 #include <com/sun/star/sheet/TableRefToken.hpp>
32 #include <com/sun/star/table/CellAddress.hpp>
34 #include <svl/itemprop.hxx>
35 #include <vcl/svapp.hxx>
36 #include <comphelper/string.hxx>
38 #include <miscuno.hxx>
39 #include <convuno.hxx>
40 #include <unonames.hxx>
41 #include <compiler.hxx>
42 #include <tokenarray.hxx>
43 #include <docsh.hxx>
44 #include <rangeseq.hxx>
45 #include <externalrefmgr.hxx>
47 using namespace ::formula;
48 using namespace ::com::sun::star;
50 static std::span<const SfxItemPropertyMapEntry> lcl_GetFormulaParserMap()
52 static const SfxItemPropertyMapEntry aFormulaParserMap_Impl[] =
54 { SC_UNO_COMPILEFAP, 0, cppu::UnoType<bool>::get(), 0, 0 },
55 { SC_UNO_COMPILEENGLISH, 0, cppu::UnoType<bool>::get(), 0, 0 },
56 { SC_UNO_IGNORELEADING, 0, cppu::UnoType<bool>::get(), 0, 0 },
57 { SC_UNO_FORMULACONVENTION, 0, cppu::UnoType<decltype(sheet::AddressConvention::UNSPECIFIED)>::get(), 0, 0 },
58 { SC_UNO_OPCODEMAP, 0, cppu::UnoType<uno::Sequence< sheet::FormulaOpCodeMapEntry >>::get(), 0, 0 },
60 return aFormulaParserMap_Impl;
63 const formula::FormulaGrammar::AddressConvention aConvMap[] = {
64 formula::FormulaGrammar::CONV_OOO, // <- AddressConvention::OOO
65 formula::FormulaGrammar::CONV_XL_A1, // <- AddressConvention::XL_A1
66 formula::FormulaGrammar::CONV_XL_R1C1, // <- AddressConvention::XL_R1C1
67 formula::FormulaGrammar::CONV_XL_OOX, // <- AddressConvention::XL_OOX
68 formula::FormulaGrammar::CONV_LOTUS_A1 // <- AddressConvention::LOTUS_A1
70 // sal_Int16 because of comparison of integer expressions below.
71 constexpr sal_Int16 nConvMapCount = SAL_N_ELEMENTS(aConvMap);
74 SC_SIMPLE_SERVICE_INFO( ScFormulaParserObj, u"ScFormulaParserObj"_ustr, SC_SERVICENAME_FORMULAPARS )
76 ScFormulaParserObj::ScFormulaParserObj(ScDocShell* pDocSh) :
77 mpDocShell( pDocSh ),
78 mnConv( sheet::AddressConvention::UNSPECIFIED ),
79 mbEnglish( false ),
80 mbIgnoreSpaces( true ),
81 mbCompileFAP( false ),
82 mbRefConventionChartOOXML( false )
84 mpDocShell->GetDocument().AddUnoObject(*this);
87 ScFormulaParserObj::~ScFormulaParserObj()
89 SolarMutexGuard g;
91 if (mpDocShell)
92 mpDocShell->GetDocument().RemoveUnoObject(*this);
95 void ScFormulaParserObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
97 if ( rHint.GetId() == SfxHintId::Dying )
98 mpDocShell = nullptr;
101 // XFormulaParser
103 void ScFormulaParserObj::SetCompilerFlags( ScCompiler& rCompiler ) const
105 formula::FormulaGrammar::AddressConvention eConv = formula::FormulaGrammar::CONV_UNSPECIFIED;
106 if (mnConv >= 0 && mnConv < nConvMapCount)
107 eConv = aConvMap[mnConv];
109 // If mxOpCodeMap is not empty it overrides mbEnglish, and vice versa. We
110 // don't need to initialize things twice.
111 if (mxOpCodeMap)
112 rCompiler.SetFormulaLanguage( mxOpCodeMap );
113 else
115 const sal_Int32 nFormulaLanguage = (eConv == formula::FormulaGrammar::CONV_XL_OOX ?
116 sheet::FormulaLanguage::OOXML :
117 (mbEnglish ? sheet::FormulaLanguage::ENGLISH : sheet::FormulaLanguage::NATIVE));
118 ScCompiler::OpCodeMapPtr xMap = rCompiler.GetOpCodeMap( nFormulaLanguage);
119 rCompiler.SetFormulaLanguage( xMap);
122 rCompiler.SetRefConvention( eConv );
123 rCompiler.EnableJumpCommandReorder(!mbCompileFAP);
124 rCompiler.EnableStopOnError(!mbCompileFAP);
126 rCompiler.SetExternalLinks(maExternalLinks);
127 rCompiler.SetRefConventionChartOOXML(mbRefConventionChartOOXML);
130 uno::Sequence<sheet::FormulaToken> SAL_CALL ScFormulaParserObj::parseFormula(
131 const OUString& aFormula, const table::CellAddress& rReferencePos )
133 SolarMutexGuard aGuard;
134 uno::Sequence<sheet::FormulaToken> aRet;
136 if (mpDocShell)
138 ScDocument& rDoc = mpDocShell->GetDocument();
139 ScExternalRefManager::ApiGuard aExtRefGuard(rDoc);
141 ScAddress aRefPos( ScAddress::UNINITIALIZED );
142 ScUnoConversion::FillScAddress( aRefPos, rReferencePos );
143 ScCompiler aCompiler( rDoc, aRefPos, rDoc.GetGrammar());
144 SetCompilerFlags( aCompiler );
146 std::unique_ptr<ScTokenArray> pCode = aCompiler.CompileString( aFormula );
147 if (pCode->HasOpCode(ocTableRef))
149 FormulaError nErr = pCode->GetCodeError();
150 aCompiler.EnableJumpCommandReorder(true);
151 aCompiler.CompileTokenArray(); // needed for corresponding inner reference
152 pCode->DelRPN(); // can be discarded
153 pCode->SetCodeError(nErr); // reset to parsing error, if any
155 ScTokenConversion::ConvertToTokenSequence( rDoc, aRet, *pCode );
158 return aRet;
161 OUString SAL_CALL ScFormulaParserObj::printFormula(
162 const uno::Sequence<sheet::FormulaToken>& aTokens, const table::CellAddress& rReferencePos )
164 SolarMutexGuard aGuard;
165 OUString aRet;
167 if (mpDocShell)
169 ScDocument& rDoc = mpDocShell->GetDocument();
170 ScTokenArray aCode(rDoc);
171 (void)ScTokenConversion::ConvertToTokenArray( rDoc, aCode, aTokens );
172 ScAddress aRefPos( ScAddress::UNINITIALIZED );
173 ScUnoConversion::FillScAddress( aRefPos, rReferencePos );
174 ScCompiler aCompiler(rDoc, aRefPos, aCode, rDoc.GetGrammar());
175 SetCompilerFlags( aCompiler );
177 OUStringBuffer aBuffer;
178 aCompiler.CreateStringFromTokenArray( aBuffer );
179 aRet = aBuffer.makeStringAndClear();
182 return aRet;
185 // XPropertySet
187 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScFormulaParserObj::getPropertySetInfo()
189 static uno::Reference< beans::XPropertySetInfo > aRef(new SfxItemPropertySetInfo( lcl_GetFormulaParserMap() ));
190 return aRef;
193 void SAL_CALL ScFormulaParserObj::setPropertyValue(
194 const OUString& aPropertyName, const uno::Any& aValue )
196 SolarMutexGuard aGuard;
197 if ( aPropertyName == SC_UNO_COMPILEFAP )
199 aValue >>= mbCompileFAP;
201 else if ( aPropertyName == SC_UNO_COMPILEENGLISH )
203 bool bOldEnglish = mbEnglish;
204 if (!(aValue >>= mbEnglish))
205 throw lang::IllegalArgumentException();
207 // Need to recreate the symbol map to change English property
208 // because the map is const. So for performance reasons set
209 // CompileEnglish _before_ OpCodeMap!
210 if (mxOpCodeMap && mbEnglish != bOldEnglish)
212 mxOpCodeMap = formula::FormulaCompiler::CreateOpCodeMap( maOpCodeMapping, mbEnglish);
216 else if ( aPropertyName == SC_UNO_FORMULACONVENTION )
218 aValue >>= mnConv;
220 bool bOldEnglish = mbEnglish;
221 if (mnConv >= 0 && mnConv < nConvMapCount
222 && aConvMap[mnConv] == formula::FormulaGrammar::CONV_XL_OOX)
223 mbEnglish = true;
225 // Same as for SC_UNO_COMPILEENGLISH, though an OpCodeMap should not
226 // had been set for CONV_XL_OOX.
227 if (mxOpCodeMap && mbEnglish != bOldEnglish)
229 mxOpCodeMap = formula::FormulaCompiler::CreateOpCodeMap( maOpCodeMapping, mbEnglish);
232 else if ( aPropertyName == SC_UNO_IGNORELEADING )
234 aValue >>= mbIgnoreSpaces;
236 else if ( aPropertyName == SC_UNO_OPCODEMAP )
238 if (!(aValue >>= maOpCodeMapping))
239 throw lang::IllegalArgumentException();
241 mxOpCodeMap = formula::FormulaCompiler::CreateOpCodeMap( maOpCodeMapping, mbEnglish);
244 else if ( aPropertyName == SC_UNO_EXTERNALLINKS )
246 if (!(aValue >>= maExternalLinks))
247 throw lang::IllegalArgumentException();
249 else if ( aPropertyName == SC_UNO_REF_CONV_CHARTOOXML )
251 if (!(aValue >>= mbRefConventionChartOOXML))
252 throw lang::IllegalArgumentException();
254 else
255 throw beans::UnknownPropertyException(aPropertyName);
258 uno::Any SAL_CALL ScFormulaParserObj::getPropertyValue( const OUString& aPropertyName )
260 SolarMutexGuard aGuard;
261 uno::Any aRet;
262 if ( aPropertyName == SC_UNO_COMPILEFAP )
264 aRet <<= mbCompileFAP;
266 else if ( aPropertyName == SC_UNO_COMPILEENGLISH )
268 aRet <<= mbEnglish;
270 else if ( aPropertyName == SC_UNO_FORMULACONVENTION )
272 aRet <<= mnConv;
274 else if ( aPropertyName == SC_UNO_IGNORELEADING )
276 aRet <<= mbIgnoreSpaces;
278 else if ( aPropertyName == SC_UNO_OPCODEMAP )
280 aRet <<= maOpCodeMapping;
282 else if ( aPropertyName == SC_UNO_EXTERNALLINKS )
284 aRet <<= maExternalLinks;
286 else if ( aPropertyName == SC_UNO_REF_CONV_CHARTOOXML )
288 aRet <<= mbRefConventionChartOOXML;
290 else
291 throw beans::UnknownPropertyException(aPropertyName);
292 return aRet;
295 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFormulaParserObj )
297 static void lcl_ExternalRefToApi( sheet::SingleReference& rAPI, const ScSingleRefData& rRef )
299 rAPI.Column = 0;
300 rAPI.Row = 0;
301 rAPI.Sheet = 0;
302 rAPI.RelativeColumn = 0;
303 rAPI.RelativeRow = 0;
304 rAPI.RelativeSheet = 0;
306 sal_Int32 nFlags = 0;
307 if ( rRef.IsColRel() )
309 nFlags |= sheet::ReferenceFlags::COLUMN_RELATIVE;
310 rAPI.RelativeColumn = rRef.Col();
312 else
313 rAPI.Column = rRef.Col();
315 if ( rRef.IsRowRel() )
317 nFlags |= sheet::ReferenceFlags::ROW_RELATIVE;
318 rAPI.RelativeRow = rRef.Row();
320 else
321 rAPI.Row = rRef.Row();
323 if ( rRef.IsColDeleted() ) nFlags |= sheet::ReferenceFlags::COLUMN_DELETED;
324 if ( rRef.IsRowDeleted() ) nFlags |= sheet::ReferenceFlags::ROW_DELETED;
325 if ( rRef.IsFlag3D() ) nFlags |= sheet::ReferenceFlags::SHEET_3D;
326 if ( rRef.IsRelName() ) nFlags |= sheet::ReferenceFlags::RELATIVE_NAME;
327 rAPI.Flags = nFlags;
330 static void lcl_SingleRefToApi( sheet::SingleReference& rAPI, const ScSingleRefData& rRef )
332 sal_Int32 nFlags = 0;
333 if ( rRef.IsColRel() )
335 nFlags |= sheet::ReferenceFlags::COLUMN_RELATIVE;
336 rAPI.RelativeColumn = rRef.Col();
337 rAPI.Column = 0;
339 else
341 rAPI.RelativeColumn = 0;
342 rAPI.Column = rRef.Col();
345 if ( rRef.IsRowRel() )
347 nFlags |= sheet::ReferenceFlags::ROW_RELATIVE;
348 rAPI.RelativeRow = rRef.Row();
349 rAPI.Row = 0;
351 else
353 rAPI.RelativeRow = 0;
354 rAPI.Row = rRef.Row();
357 if ( rRef.IsTabRel() )
359 nFlags |= sheet::ReferenceFlags::SHEET_RELATIVE;
360 rAPI.RelativeSheet = rRef.Tab();
361 rAPI.Sheet = 0;
363 else
365 rAPI.RelativeSheet = 0;
366 rAPI.Sheet = rRef.Tab();
369 if ( rRef.IsColDeleted() ) nFlags |= sheet::ReferenceFlags::COLUMN_DELETED;
370 if ( rRef.IsRowDeleted() ) nFlags |= sheet::ReferenceFlags::ROW_DELETED;
371 if ( rRef.IsTabDeleted() ) nFlags |= sheet::ReferenceFlags::SHEET_DELETED;
372 if ( rRef.IsFlag3D() ) nFlags |= sheet::ReferenceFlags::SHEET_3D;
373 if ( rRef.IsRelName() ) nFlags |= sheet::ReferenceFlags::RELATIVE_NAME;
374 rAPI.Flags = nFlags;
377 bool ScTokenConversion::ConvertToTokenArray( ScDocument& rDoc,
378 ScTokenArray& rTokenArray, const uno::Sequence<sheet::FormulaToken>& rSequence )
380 return !rTokenArray.Fill(rSequence, rDoc.GetSharedStringPool(), rDoc.GetExternalRefManager());
383 void ScTokenConversion::ConvertToTokenSequence( const ScDocument& rDoc,
384 uno::Sequence<sheet::FormulaToken>& rSequence, const ScTokenArray& rTokenArray,
385 bool bIgnoreTableRefNoInnerReference )
387 sal_Int32 nLen = static_cast<sal_Int32>(rTokenArray.GetLen());
388 formula::FormulaToken** pTokens = rTokenArray.GetArray();
389 if ( pTokens )
391 rSequence.realloc(nLen);
392 auto pSequence = rSequence.getArray();
393 for (sal_Int32 nPos=0; nPos<nLen; nPos++)
395 const formula::FormulaToken& rToken = *pTokens[nPos];
396 sheet::FormulaToken& rAPI = pSequence[nPos];
398 OpCode eOpCode = rToken.GetOpCode();
399 // eOpCode may be changed in the following switch/case
400 switch ( rToken.GetType() )
402 case svByte:
403 // Only the count of spaces is stored as "long". Parameter count is ignored.
404 if ( eOpCode == ocSpaces )
405 rAPI.Data <<= static_cast<sal_Int32>(rToken.GetByte());
406 else if (eOpCode == ocWhitespace)
408 // Convention is one character repeated.
409 if (rToken.GetByte() == 1)
410 rAPI.Data <<= OUString( rToken.GetChar());
411 else
413 OUStringBuffer aBuf( rToken.GetByte());
414 comphelper::string::padToLength( aBuf, rToken.GetByte(), rToken.GetChar());
415 rAPI.Data <<= aBuf.makeStringAndClear();
418 else
419 rAPI.Data.clear(); // no data
420 break;
421 case formula::svDouble:
422 rAPI.Data <<= rToken.GetDouble();
423 break;
424 case formula::svString:
425 rAPI.Data <<= rToken.GetString().getString();
426 break;
427 case svExternal:
428 // Function name is stored as string.
429 // Byte (parameter count) is ignored.
430 rAPI.Data <<= rToken.GetExternal();
431 break;
432 case svSingleRef:
434 sheet::SingleReference aSingleRef;
435 lcl_SingleRefToApi( aSingleRef, *rToken.GetSingleRef() );
436 rAPI.Data <<= aSingleRef;
438 break;
439 case formula::svDoubleRef:
441 sheet::ComplexReference aCompRef;
442 lcl_SingleRefToApi( aCompRef.Reference1, *rToken.GetSingleRef() );
443 lcl_SingleRefToApi( aCompRef.Reference2, *rToken.GetSingleRef2() );
444 rAPI.Data <<= aCompRef;
446 break;
447 case svIndex:
449 const ScTableRefToken* pTR;
450 if (rToken.GetOpCode() == ocTableRef && (pTR = dynamic_cast<const ScTableRefToken*>(&rToken)))
452 sheet::TableRefToken aTableRefToken;
453 aTableRefToken.Index = static_cast<sal_Int32>( pTR->GetIndex());
454 aTableRefToken.Item = static_cast<sal_Int16>( pTR->GetItem());
455 const FormulaToken* pRef = pTR->GetAreaRefRPN();
456 assert((pRef || bIgnoreTableRefNoInnerReference)
457 && "something forgot to create RPN for ocTableRef inner reference");
458 (void)bIgnoreTableRefNoInnerReference;
459 if (pRef)
461 switch (pRef->GetType())
463 case svSingleRef:
464 lcl_SingleRefToApi( aTableRefToken.Reference.Reference1, *pRef->GetSingleRef());
465 aTableRefToken.Reference.Reference2 = aTableRefToken.Reference.Reference1;
466 break;
467 case svDoubleRef:
468 lcl_SingleRefToApi( aTableRefToken.Reference.Reference1, *pRef->GetSingleRef());
469 lcl_SingleRefToApi( aTableRefToken.Reference.Reference2, *pRef->GetSingleRef2());
470 break;
471 default:
472 ; // nothing
475 rAPI.Data <<= aTableRefToken;
477 else
479 sheet::NameToken aNameToken;
480 aNameToken.Index = static_cast<sal_Int32>( rToken.GetIndex() );
481 aNameToken.Sheet = rToken.GetSheet();
482 rAPI.Data <<= aNameToken;
485 break;
486 case svMatrix:
487 if (!ScRangeToSequence::FillMixedArray( rAPI.Data, rToken.GetMatrix(), true))
488 rAPI.Data.clear();
489 break;
490 case svExternalSingleRef:
492 sheet::SingleReference aSingleRef;
493 lcl_ExternalRefToApi( aSingleRef, *rToken.GetSingleRef() );
494 size_t nCacheId;
495 rDoc.GetExternalRefManager()->getCacheTable(
496 rToken.GetIndex(), rToken.GetString().getString(), false, &nCacheId);
497 aSingleRef.Sheet = static_cast< sal_Int32 >( nCacheId );
498 sheet::ExternalReference aExtRef;
499 aExtRef.Index = rToken.GetIndex();
500 aExtRef.Reference <<= aSingleRef;
501 rAPI.Data <<= aExtRef;
502 eOpCode = ocPush;
504 break;
505 case svExternalDoubleRef:
507 sheet::ComplexReference aComplRef;
508 lcl_ExternalRefToApi( aComplRef.Reference1, *rToken.GetSingleRef() );
509 lcl_ExternalRefToApi( aComplRef.Reference2, *rToken.GetSingleRef2() );
510 size_t nCacheId;
511 rDoc.GetExternalRefManager()->getCacheTable(
512 rToken.GetIndex(), rToken.GetString().getString(), false, &nCacheId);
513 aComplRef.Reference1.Sheet = static_cast< sal_Int32 >( nCacheId );
514 // NOTE: This assumes that cached sheets are in consecutive order!
515 aComplRef.Reference2.Sheet =
516 aComplRef.Reference1.Sheet +
517 (rToken.GetSingleRef2()->Tab() - rToken.GetSingleRef()->Tab());
518 sheet::ExternalReference aExtRef;
519 aExtRef.Index = rToken.GetIndex();
520 aExtRef.Reference <<= aComplRef;
521 rAPI.Data <<= aExtRef;
522 eOpCode = ocPush;
524 break;
525 case svExternalName:
527 sheet::ExternalReference aExtRef;
528 aExtRef.Index = rToken.GetIndex();
529 aExtRef.Reference <<= rToken.GetString().getString();
530 rAPI.Data <<= aExtRef;
531 eOpCode = ocPush;
533 break;
534 default:
535 SAL_WARN("sc", "ScTokenConversion::ConvertToTokenSequence: unhandled token type " << StackVarEnumToString(rToken.GetType()));
536 [[fallthrough]];
537 case svJump: // occurs with ocIf, ocChoose
538 case svError: // seems to be fairly common, and probably not exceptional and not worth a warning?
539 case svMissing: // occurs with ocMissing
540 case svSep: // occurs with ocSep, ocOpen, ocClose, ocArray*
541 rAPI.Data.clear(); // no data
543 rAPI.OpCode = static_cast<sal_Int32>(eOpCode); //! assuming equal values for the moment
546 else
547 rSequence.realloc(0);
550 ScFormulaOpCodeMapperObj::ScFormulaOpCodeMapperObj(::std::unique_ptr<formula::FormulaCompiler> && _pCompiler)
551 : formula::FormulaOpCodeMapperObj(std::move(_pCompiler))
555 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */