tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / ui / unoobj / funcuno.cxx
blob82ad1eeab815709d0029902be9685b3a0d26b550
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 <cppuhelper/supportsservice.hxx>
21 #include <sfx2/app.hxx>
22 #include <svl/itemprop.hxx>
23 #include <svl/sharedstringpool.hxx>
24 #include <unotools/charclass.hxx>
25 #include <osl/diagnose.h>
26 #include <vcl/svapp.hxx>
28 #include <funcuno.hxx>
29 #include <miscuno.hxx>
30 #include <cellsuno.hxx>
31 #include <scdll.hxx>
32 #include <document.hxx>
33 #include <compiler.hxx>
34 #include <formula/errorcodes.hxx>
35 #include <callform.hxx>
36 #include <addincol.hxx>
37 #include <rangeseq.hxx>
38 #include <formulacell.hxx>
39 #include <docoptio.hxx>
40 #include <optuno.hxx>
41 #include <markdata.hxx>
42 #include <patattr.hxx>
43 #include <docpool.hxx>
44 #include <attrib.hxx>
45 #include <clipparam.hxx>
46 #include <stringutil.hxx>
47 #include <tokenarray.hxx>
48 #include <unonames.hxx>
49 #include <memory>
51 using namespace com::sun::star;
53 // registered as implementation for service FunctionAccess,
54 // also supports service SpreadsheetDocumentSettings (to set null date etc.)
56 constexpr OUString SCFUNCTIONACCESS_SERVICE = u"com.sun.star.sheet.FunctionAccess"_ustr;
57 constexpr OUString SCDOCSETTINGS_SERVICE = u"com.sun.star.sheet.SpreadsheetDocumentSettings"_ustr;
59 // helper to use cached document if not in use, temporary document otherwise
61 namespace {
63 class ScTempDocSource
65 private:
66 ScTempDocCache& rCache;
67 ScDocumentUniquePtr pTempDoc;
69 static ScDocument* CreateDocument(); // create and initialize doc
71 public:
72 explicit ScTempDocSource( ScTempDocCache& rDocCache );
73 ~ScTempDocSource() COVERITY_NOEXCEPT_FALSE;
75 ScDocument* GetDocument();
80 ScDocument* ScTempDocSource::CreateDocument()
82 ScDocument* pDoc = new ScDocument( SCDOCMODE_FUNCTIONACCESS );
83 pDoc->MakeTable( 0 );
84 return pDoc;
87 ScTempDocSource::ScTempDocSource( ScTempDocCache& rDocCache ) :
88 rCache( rDocCache )
90 if ( rCache.IsInUse() )
91 pTempDoc.reset(CreateDocument());
92 else
94 rCache.SetInUse( true );
95 if ( !rCache.GetDocument() )
96 rCache.SetDocument( CreateDocument() );
100 ScTempDocSource::~ScTempDocSource() COVERITY_NOEXCEPT_FALSE
102 if ( !pTempDoc )
103 rCache.SetInUse( false );
106 ScDocument* ScTempDocSource::GetDocument()
108 if ( pTempDoc )
109 return pTempDoc.get();
110 else
111 return rCache.GetDocument();
114 ScTempDocCache::ScTempDocCache()
115 : bInUse(false)
119 void ScTempDocCache::SetDocument( ScDocument* pNew )
121 OSL_ENSURE(!xDoc, "ScTempDocCache::SetDocument: already set");
122 xDoc.reset(pNew);
125 void ScTempDocCache::Clear()
127 OSL_ENSURE( !bInUse, "ScTempDocCache::Clear: bInUse" );
128 xDoc.reset();
131 // copy results from one document into another
132 //! merge this with ScAreaLink::Refresh
133 //! copy directly without a clipboard document?
135 static bool lcl_CopyData( ScDocument* pSrcDoc, const ScRange& rSrcRange,
136 ScDocument* pDestDoc, const ScAddress& rDestPos )
138 SCTAB nSrcTab = rSrcRange.aStart.Tab();
139 SCTAB nDestTab = rDestPos.Tab();
141 ScRange aNewRange( rDestPos, ScAddress(
142 rSrcRange.aEnd.Col() - rSrcRange.aStart.Col() + rDestPos.Col(),
143 rSrcRange.aEnd.Row() - rSrcRange.aStart.Row() + rDestPos.Row(),
144 nDestTab ) );
146 ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
147 ScMarkData aSourceMark(pSrcDoc->GetSheetLimits());
148 aSourceMark.SelectOneTable( nSrcTab ); // for CopyToClip
149 aSourceMark.SetMarkArea( rSrcRange );
150 ScClipParam aClipParam(rSrcRange, false);
151 pSrcDoc->CopyToClip(aClipParam, pClipDoc.get(), &aSourceMark, false, false);
153 if ( pClipDoc->HasAttrib( 0,0,nSrcTab, pClipDoc->MaxCol(), pClipDoc->MaxRow(),nSrcTab,
154 HasAttrFlags::Merged | HasAttrFlags::Overlapped ) )
156 ScPatternAttr aPattern(pSrcDoc->getCellAttributeHelper());
157 aPattern.GetItemSet().Put( ScMergeAttr() ); // Defaults
158 aPattern.GetItemSet().Put( ScMergeFlagAttr() );
159 pClipDoc->ApplyPatternAreaTab( 0,0, pClipDoc->MaxCol(), pClipDoc->MaxRow(), nSrcTab, aPattern );
162 ScMarkData aDestMark(pDestDoc->GetSheetLimits());
163 aDestMark.SelectOneTable( nDestTab );
164 aDestMark.SetMarkArea( aNewRange );
165 pDestDoc->CopyFromClip( aNewRange, aDestMark, InsertDeleteFlags::ALL & ~InsertDeleteFlags::FORMULA, nullptr, pClipDoc.get(), false );
167 return true;
170 namespace
172 std::span<const SfxItemPropertyMapEntry> GetPropertyMap()
174 static const SfxItemPropertyMapEntry aMap[] =
176 { SC_UNO_CALCASSHOWN, PROP_UNO_CALCASSHOWN , cppu::UnoType<bool>::get(), 0, 0},
177 { SC_UNO_DEFTABSTOP, PROP_UNO_DEFTABSTOP , cppu::UnoType<sal_Int16>::get(), 0, 0},
178 { SC_UNO_IGNORECASE, PROP_UNO_IGNORECASE , cppu::UnoType<bool>::get(), 0, 0},
179 { SC_UNO_ITERENABLED, PROP_UNO_ITERENABLED , cppu::UnoType<bool>::get(), 0, 0},
180 { SC_UNO_ITERCOUNT, PROP_UNO_ITERCOUNT , cppu::UnoType<sal_Int32>::get(), 0, 0},
181 { SC_UNO_ITEREPSILON, PROP_UNO_ITEREPSILON , cppu::UnoType<double>::get(), 0, 0},
182 { SC_UNO_LOOKUPLABELS, PROP_UNO_LOOKUPLABELS, cppu::UnoType<bool>::get(), 0, 0},
183 { SC_UNO_MATCHWHOLE, PROP_UNO_MATCHWHOLE , cppu::UnoType<bool>::get(), 0, 0},
184 { SC_UNO_NULLDATE, PROP_UNO_NULLDATE , cppu::UnoType<util::Date>::get(), 0, 0},
185 // SpreadsheetDocumentSettings supports "SpellOnline" so we must claim to support this here too
186 { SC_UNO_SPELLONLINE, 0 , cppu::UnoType<bool>::get(), 0, 0},
187 { SC_UNO_STANDARDDEC, PROP_UNO_STANDARDDEC , cppu::UnoType<sal_Int16>::get(), 0, 0},
188 { SC_UNO_REGEXENABLED, PROP_UNO_REGEXENABLED, cppu::UnoType<bool>::get(), 0, 0},
189 { SC_UNO_WILDCARDSENABLED, PROP_UNO_WILDCARDSENABLED, cppu::UnoType<bool>::get(), 0, 0},
191 return aMap;
195 ScFunctionAccess::ScFunctionAccess() :
196 aPropertyMap( GetPropertyMap() ),
197 mbArray( true ), // default according to behaviour of older Office versions
198 mbValid( true ),
199 mbSpellOnline( false )
201 StartListening( *SfxGetpApp() ); // for SfxHintId::Deinitializing
204 ScFunctionAccess::~ScFunctionAccess()
206 pOptions.reset();
208 // SfxBroadcaster::RemoveListener checks DBG_TESTSOLARMUTEX():
209 SolarMutexGuard g;
210 EndListeningAll();
214 void ScFunctionAccess::Notify( SfxBroadcaster&, const SfxHint& rHint )
216 if ( rHint.GetId() == SfxHintId::Deinitializing )
218 // document must not be used anymore
219 aDocCache.Clear();
220 mbValid = false;
224 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
225 ScFunctionAccess_get_implementation(css::uno::XComponentContext*, css::uno::Sequence<css::uno::Any> const &)
227 SolarMutexGuard aGuard;
228 ScDLL::Init();
229 return cppu::acquire(new ScFunctionAccess);
232 // XServiceInfo
233 OUString SAL_CALL ScFunctionAccess::getImplementationName()
235 return u"stardiv.StarCalc.ScFunctionAccess"_ustr;
238 sal_Bool SAL_CALL ScFunctionAccess::supportsService( const OUString& rServiceName )
240 return cppu::supportsService(this, rServiceName);
243 uno::Sequence<OUString> SAL_CALL ScFunctionAccess::getSupportedServiceNames()
245 return {SCFUNCTIONACCESS_SERVICE, SCDOCSETTINGS_SERVICE};
248 // XPropertySet (document settings)
250 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScFunctionAccess::getPropertySetInfo()
252 SolarMutexGuard aGuard;
253 static uno::Reference<beans::XPropertySetInfo> aRef(
254 new SfxItemPropertySetInfo( aPropertyMap ));
255 return aRef;
258 void SAL_CALL ScFunctionAccess::setPropertyValue(
259 const OUString& aPropertyName, const uno::Any& aValue )
261 SolarMutexGuard aGuard;
263 if ( aPropertyName == "IsArrayFunction" )
265 if( !(aValue >>= mbArray) )
266 throw lang::IllegalArgumentException();
268 else if (aPropertyName == SC_UNO_SPELLONLINE)
270 // Allow this property because SpreadsheetDocumentSettings lists it
271 if( !(aValue >>= mbSpellOnline) )
272 throw lang::IllegalArgumentException();
274 else
276 if ( !pOptions )
277 pOptions.reset( new ScDocOptions() );
279 // options aren't initialized from configuration - always get the same default behaviour
280 bool bDone = ScDocOptionsHelper::setPropertyValue( *pOptions, aPropertyMap, aPropertyName, aValue );
281 if (!bDone)
282 throw beans::UnknownPropertyException(aPropertyName);
286 uno::Any SAL_CALL ScFunctionAccess::getPropertyValue( const OUString& aPropertyName )
288 SolarMutexGuard aGuard;
290 if ( aPropertyName == "IsArrayFunction" )
291 return uno::Any( mbArray );
293 // Allow this property because SpreadsheetDocumentSettings lists it
294 if (aPropertyName == SC_UNO_SPELLONLINE)
295 return uno::Any(mbSpellOnline);
297 if ( !pOptions )
298 pOptions.reset( new ScDocOptions() );
300 // options aren't initialized from configuration - always get the same default behaviour
302 return ScDocOptionsHelper::getPropertyValue( *pOptions, aPropertyMap, aPropertyName );
305 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFunctionAccess )
307 // XFunctionAccess
309 static bool lcl_AddFunctionToken( ScTokenArray& rArray, const OUString& rName,const ScCompiler& rCompiler )
311 // function names are always case-insensitive
312 OUString aUpper = ScGlobal::getCharClass().uppercase(rName);
314 // same options as in ScCompiler::IsOpCode:
315 // 1. built-in function name
317 OpCode eOp = rCompiler.GetEnglishOpCode( aUpper );
318 if ( eOp != ocNone )
320 rArray.AddOpCode( eOp );
321 return true;
324 // 2. old add in functions
326 if (ScGlobal::GetLegacyFuncCollection()->findByName(aUpper))
328 rArray.AddExternal(aUpper.getStr());
329 return true;
332 // 3. new (uno) add in functions
334 OUString aIntName =
335 ScGlobal::GetAddInCollection()->FindFunction(aUpper, false);
336 if (!aIntName.isEmpty())
338 rArray.AddExternal(aIntName.getStr()); // international name
339 return true;
342 return false; // no valid function name
345 static void lcl_AddRef( ScTokenArray& rArray, sal_Int32 nStartRow, sal_Int32 nColCount, sal_Int32 nRowCount )
347 ScComplexRefData aRef;
348 aRef.InitRange(ScRange(0,nStartRow,0,nColCount-1,nStartRow+nRowCount-1,0));
349 rArray.AddDoubleReference(aRef);
352 namespace {
354 class SimpleVisitor
356 protected:
357 bool mbArgError;
358 ScDocument* mpDoc;
359 public:
360 explicit SimpleVisitor( ScDocument* pDoc ) : mbArgError( false ), mpDoc( pDoc ) {}
361 // could possibly just get away with JUST the following overload
362 // 1) virtual void visitElem( long& nCol, long& nRow, const double& elem )
363 // 2) virtual void visitElem( long& nCol, long& nRow, const OUString& elem )
364 // 3) virtual void visitElem( long& nCol, long& nRow, const uno::Any& elem )
365 // the other types methods are here just to reflect the orig code and for
366 // completeness.
368 void visitElem( sal_Int32 nCol, sal_Int32 nRow, sal_Int16 elem )
370 mpDoc->SetValue( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), 0, elem );
372 void visitElem( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 elem )
374 mpDoc->SetValue( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), 0, elem );
376 void visitElem( sal_Int32 nCol, sal_Int32 nRow, const double& elem )
378 mpDoc->SetValue( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), 0, elem );
380 void visitElem( sal_Int32 nCol, sal_Int32 nRow, const OUString& elem )
382 if (!elem.isEmpty())
384 ScSetStringParam aParam;
385 aParam.setTextInput();
386 mpDoc->SetString(ScAddress(nCol,nRow,0), elem, &aParam);
389 void visitElem( sal_Int32 nCol, sal_Int32 nRow, const uno::Any& rElement )
391 uno::TypeClass eElemClass = rElement.getValueTypeClass();
392 if ( eElemClass == uno::TypeClass_VOID )
394 // leave empty
396 else if ( eElemClass == uno::TypeClass_BYTE ||
397 eElemClass == uno::TypeClass_SHORT ||
398 eElemClass == uno::TypeClass_UNSIGNED_SHORT ||
399 eElemClass == uno::TypeClass_LONG ||
400 eElemClass == uno::TypeClass_UNSIGNED_LONG ||
401 eElemClass == uno::TypeClass_FLOAT ||
402 eElemClass == uno::TypeClass_DOUBLE )
404 // accept integer types because Basic passes a floating point
405 // variable as byte, short or long if it's an integer number.
406 double fVal(0.0);
407 rElement >>= fVal;
408 visitElem( nCol, nRow, fVal );
410 else if ( eElemClass == uno::TypeClass_STRING )
412 OUString aUStr;
413 rElement >>= aUStr;
414 visitElem( nCol, nRow, aUStr );
416 else
417 mbArgError = true;
419 bool hasArgError() const { return mbArgError; }
422 template< class seq >
423 class SequencesContainer
425 uno::Sequence< uno::Sequence< seq > > maSeq;
427 sal_Int32& mrDocRow;
428 bool mbOverflow;
429 bool mbArgError;
430 ScDocument* mpDoc;
431 ScTokenArray& mrTokenArr;
433 public:
434 SequencesContainer( const uno::Any& rArg, ScTokenArray& rTokenArr, sal_Int32& rDocRow, ScDocument* pDoc ) :
435 mrDocRow( rDocRow ), mbOverflow(false), mbArgError(false), mpDoc( pDoc ), mrTokenArr( rTokenArr )
437 rArg >>= maSeq;
440 void process()
442 SimpleVisitor aVisitor(mpDoc);
443 sal_Int32 nStartRow = mrDocRow;
444 sal_Int32 nRowCount = maSeq.getLength();
445 sal_Int32 nMaxColCount = 0;
446 for (const uno::Sequence<seq>& rRow : maSeq)
448 sal_Int32 nColCount = rRow.getLength();
449 if ( nColCount > nMaxColCount )
450 nMaxColCount = nColCount;
451 for (sal_Int32 nCol=0; nCol<nColCount; nCol++)
452 if ( nCol <= mpDoc->MaxCol() && mrDocRow <= mpDoc->MaxRow() )
453 aVisitor.visitElem( nCol, mrDocRow, rRow[ nCol ] );
454 else
455 mbOverflow=true;
456 mrDocRow++;
458 mbArgError = aVisitor.hasArgError();
459 if (!mbOverflow)
461 if (nRowCount && nMaxColCount)
462 lcl_AddRef( mrTokenArr, nStartRow, nMaxColCount, nRowCount );
463 else if (nRowCount == 1 && !nMaxColCount)
464 // Empty Sequence<Sequence<Any>> is omitted argument.
465 mrTokenArr.AddOpCode( ocMissing);
468 bool getOverflow() const { return mbOverflow; }
469 bool getArgError() const { return mbArgError; }
472 template <class T>
473 class ArrayOfArrayProc
475 public:
476 static void processSequences( ScDocument* pDoc, const uno::Any& rArg, ScTokenArray& rTokenArr,
477 sal_Int32& rDocRow, bool& rArgErr, bool& rOverflow )
479 SequencesContainer< T > aContainer( rArg, rTokenArr, rDocRow, pDoc );
480 aContainer.process();
481 rArgErr = aContainer.getArgError();
482 rOverflow = aContainer.getOverflow();
488 uno::Any SAL_CALL ScFunctionAccess::callFunction( const OUString& aName,
489 const uno::Sequence<uno::Any>& aArguments )
491 SolarMutexGuard aGuard;
493 if (!mbValid)
494 throw uno::RuntimeException();
496 // use cached document if not in use, temporary document otherwise
497 // (deleted in ScTempDocSource dtor)
498 ScTempDocSource aSource( aDocCache );
499 ScDocument* pDoc = aSource.GetDocument();
500 const static SCTAB nTempSheet = 1;
501 // Create an extra tab to contain the Function Cell
502 // this will allow full rows to be used.
503 if ( !pDoc->HasTable( nTempSheet ) )
504 pDoc->MakeTable( nTempSheet );
506 /// TODO: check
507 ScAddress aAdr;
508 ScCompiler aCompiler(*pDoc, aAdr, pDoc->GetGrammar());
510 // find function
512 ScTokenArray aTokenArr(*pDoc);
513 if ( !lcl_AddFunctionToken( aTokenArr, aName,aCompiler ) )
515 // function not found
516 throw container::NoSuchElementException();
519 // set options (null date, etc.)
521 if ( pOptions )
522 pDoc->SetDocOptions( *pOptions );
524 // add arguments to token array
526 bool bArgErr = false;
527 bool bOverflow = false;
528 sal_Int32 nDocRow = 0;
529 tools::Long nArgCount = aArguments.getLength();
530 const uno::Any* pArgArr = aArguments.getConstArray();
532 svl::SharedStringPool& rSPool = pDoc->GetSharedStringPool();
533 aTokenArr.AddOpCode(ocOpen);
534 for (tools::Long nPos=0; nPos<nArgCount; nPos++)
536 if ( nPos > 0 )
537 aTokenArr.AddOpCode(ocSep);
539 const uno::Any& rArg = pArgArr[nPos];
541 uno::TypeClass eClass = rArg.getValueTypeClass();
542 const uno::Type& aType = rArg.getValueType();
543 if ( eClass == uno::TypeClass_BYTE ||
544 eClass == uno::TypeClass_BOOLEAN ||
545 eClass == uno::TypeClass_SHORT ||
546 eClass == uno::TypeClass_UNSIGNED_SHORT ||
547 eClass == uno::TypeClass_LONG ||
548 eClass == uno::TypeClass_UNSIGNED_LONG ||
549 eClass == uno::TypeClass_FLOAT ||
550 eClass == uno::TypeClass_DOUBLE )
552 // accept integer types because Basic passes a floating point
553 // variable as byte, short or long if it's an integer number.
554 double fVal = 0;
555 rArg >>= fVal;
556 aTokenArr.AddDouble( fVal );
558 else if ( eClass == uno::TypeClass_STRING )
560 OUString aUStr;
561 rArg >>= aUStr;
562 aTokenArr.AddString(rSPool.intern(aUStr));
564 else if ( aType.equals( cppu::UnoType<uno::Sequence< uno::Sequence<sal_Int16> >>::get() ) )
566 ArrayOfArrayProc<sal_Int16>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
568 else if ( aType.equals( cppu::UnoType<uno::Sequence< uno::Sequence<sal_Int32> >>::get() ) )
570 ArrayOfArrayProc<sal_Int32>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
572 else if ( aType.equals( cppu::UnoType<uno::Sequence< uno::Sequence<double> >>::get() ) )
574 ArrayOfArrayProc<double>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
576 else if ( aType.equals( cppu::UnoType<uno::Sequence< uno::Sequence<OUString> >>::get() ) )
578 ArrayOfArrayProc<OUString>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
580 else if ( aType.equals( cppu::UnoType<uno::Sequence< uno::Sequence<uno::Any> >>::get() ) )
582 ArrayOfArrayProc<uno::Any>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
584 else if (uno::Reference<table::XCellRange> xRange; rArg >>= xRange)
586 // currently, only our own cell ranges are supported
588 ScCellRangesBase* pImpl = dynamic_cast<ScCellRangesBase*>( xRange.get() );
589 if ( pImpl )
591 ScDocument* pSrcDoc = pImpl->GetDocument();
592 const ScRangeList& rRanges = pImpl->GetRangeList();
593 if ( pSrcDoc && rRanges.size() == 1 )
595 ScRange const & rSrcRange = rRanges[ 0 ];
597 sal_Int32 nStartRow = nDocRow;
598 sal_Int32 nColCount = rSrcRange.aEnd.Col() - rSrcRange.aStart.Col() + 1;
599 sal_Int32 nRowCount = rSrcRange.aEnd.Row() - rSrcRange.aStart.Row() + 1;
601 if ( nStartRow + nRowCount > pDoc->GetSheetLimits().GetMaxRowCount() )
602 bOverflow = true;
603 else
605 // copy data
606 if ( !lcl_CopyData( pSrcDoc, rSrcRange, pDoc, ScAddress( 0, static_cast<SCROW>(nDocRow), 0 ) ) )
607 bOverflow = true;
610 nDocRow += nRowCount;
611 if ( !bOverflow )
612 lcl_AddRef( aTokenArr, nStartRow, nColCount, nRowCount );
614 else
615 bArgErr = true;
617 else
618 bArgErr = true;
620 else
621 bArgErr = true; // invalid type
623 aTokenArr.AddOpCode(ocClose);
624 aTokenArr.AddOpCode(ocStop);
626 // execute formula
628 uno::Any aRet;
629 if ( !bArgErr && !bOverflow && nDocRow <= pDoc->GetSheetLimits().GetMaxRowCount() )
631 ScAddress aFormulaPos( 0, 0, nTempSheet );
632 // GRAM_API doesn't really matter for the token array but fits with
633 // other API compatibility grammars.
634 ScFormulaCell* pFormula = new ScFormulaCell(
635 *pDoc, aFormulaPos, aTokenArr, formula::FormulaGrammar::GRAM_API,
636 mbArray ? ScMatrixMode::Formula : ScMatrixMode::NONE );
637 pFormula = pDoc->SetFormulaCell(aFormulaPos, pFormula);
638 if (mbArray && pFormula)
639 pFormula->SetMatColsRows(1,1); // the cell dimensions (only one cell)
641 // call GetMatrix before GetErrCode because GetMatrix always recalculates
642 // if there is no matrix result
644 const ScMatrix* pMat = (mbArray && pFormula) ? pFormula->GetMatrix() : nullptr;
645 FormulaError nErrCode = pFormula ? pFormula->GetErrCode() : FormulaError::IllegalArgument;
646 if ( nErrCode == FormulaError::NONE )
648 if ( pMat )
650 // array result
651 ScRangeToSequence::FillMixedArray( aRet, pMat );
653 else if ( pFormula->IsValue() )
655 // numeric value
656 aRet <<= pFormula->GetValue();
658 else
660 // string result
661 OUString aStrVal = pFormula->GetString().getString();
662 aRet <<= aStrVal;
665 else if ( nErrCode == FormulaError::NotAvailable )
667 // #N/A: leave result empty, no exception
669 else
671 // any other error: IllegalArgumentException
672 bArgErr = true;
675 pDoc->DeleteAreaTab( 0, 0, pDoc->MaxCol(), pDoc->MaxRow(), 0, InsertDeleteFlags::ALL );
676 pDoc->DeleteAreaTab( 0, 0, 0, 0, nTempSheet, InsertDeleteFlags::ALL );
679 if (bOverflow)
680 throw uno::RuntimeException();
682 if (bArgErr)
683 throw lang::IllegalArgumentException();
685 return aRet;
688 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */