merge the formfield patch from ooo-build
[ooovba.git] / sc / source / ui / unoobj / funcuno.cxx
blob0042325c449e5ead80adc2bb86b8c922ecd38ae7
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: funcuno.cxx,v $
10 * $Revision: 1.21 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
36 #include <tools/debug.hxx>
37 #include <sfx2/app.hxx>
38 #include <svtools/itemprop.hxx>
40 #include "funcuno.hxx"
41 #include "miscuno.hxx"
42 #include "cellsuno.hxx"
43 #include "unoguard.hxx"
44 #include "scdll.hxx"
45 #include "document.hxx"
46 #include "compiler.hxx"
47 #include "formula/errorcodes.hxx"
48 #include "callform.hxx"
49 #include "addincol.hxx"
50 #include "rangeseq.hxx"
51 #include "cell.hxx"
52 #include "docoptio.hxx"
53 #include "optuno.hxx"
54 #include <docuno.hxx>
55 // for lcl_CopyData:
56 #include "markdata.hxx"
57 #include "patattr.hxx"
58 #include "docpool.hxx"
59 #include "attrib.hxx"
60 #include "clipparam.hxx"
62 using namespace com::sun::star;
64 //------------------------------------------------------------------------
66 // registered as implementation for service FunctionAccess,
67 // also supports service SpreadsheetDocumentSettings (to set null date etc.)
69 #define SCFUNCTIONACCESS_SERVICE "com.sun.star.sheet.FunctionAccess"
70 #define SCDOCSETTINGS_SERVICE "com.sun.star.sheet.SpreadsheetDocumentSettings"
72 //------------------------------------------------------------------------
74 // helper to use cached document if not in use, temporary document otherwise
76 class ScTempDocSource
78 private:
79 ScTempDocCache& rCache;
80 ScDocument* pTempDoc;
82 static ScDocument* CreateDocument(); // create and initialize doc
84 public:
85 ScTempDocSource( ScTempDocCache& rDocCache );
86 ~ScTempDocSource();
88 ScDocument* GetDocument();
91 //------------------------------------------------------------------------
93 // static
94 ScDocument* ScTempDocSource::CreateDocument()
96 ScDocument* pDoc = new ScDocument; // SCDOCMODE_DOCUMENT
97 pDoc->MakeTable( 0 );
98 return pDoc;
101 ScTempDocSource::ScTempDocSource( ScTempDocCache& rDocCache ) :
102 rCache( rDocCache ),
103 pTempDoc( NULL )
105 if ( rCache.IsInUse() )
106 pTempDoc = CreateDocument();
107 else
109 rCache.SetInUse( TRUE );
110 if ( !rCache.GetDocument() )
111 rCache.SetDocument( CreateDocument() );
115 ScTempDocSource::~ScTempDocSource()
117 if ( pTempDoc )
118 delete pTempDoc;
119 else
120 rCache.SetInUse( FALSE );
123 ScDocument* ScTempDocSource::GetDocument()
125 if ( pTempDoc )
126 return pTempDoc;
127 else
128 return rCache.GetDocument();
131 //------------------------------------------------------------------------
133 ScTempDocCache::ScTempDocCache() :
134 pDoc( NULL ),
135 bInUse( FALSE )
139 ScTempDocCache::~ScTempDocCache()
141 DBG_ASSERT( !bInUse, "ScTempDocCache dtor: bInUse" );
142 delete pDoc;
145 void ScTempDocCache::SetDocument( ScDocument* pNew )
147 DBG_ASSERT( !pDoc, "ScTempDocCache::SetDocument: already set" );
148 pDoc = pNew;
151 void ScTempDocCache::Clear()
153 DBG_ASSERT( !bInUse, "ScTempDocCache::Clear: bInUse" );
154 delete pDoc;
155 pDoc = NULL;
158 //------------------------------------------------------------------------
160 // copy results from one document into another
161 //! merge this with ScAreaLink::Refresh
162 //! copy directly without a clipboard document?
164 BOOL lcl_CopyData( ScDocument* pSrcDoc, const ScRange& rSrcRange,
165 ScDocument* pDestDoc, const ScAddress& rDestPos )
167 SCTAB nSrcTab = rSrcRange.aStart.Tab();
168 SCTAB nDestTab = rDestPos.Tab();
170 ScRange aNewRange( rDestPos, ScAddress(
171 rSrcRange.aEnd.Col() - rSrcRange.aStart.Col() + rDestPos.Col(),
172 rSrcRange.aEnd.Row() - rSrcRange.aStart.Row() + rDestPos.Row(),
173 nDestTab ) );
175 ScDocument* pClipDoc = new ScDocument( SCDOCMODE_CLIP );
176 ScMarkData aSourceMark;
177 aSourceMark.SelectOneTable( nSrcTab ); // for CopyToClip
178 aSourceMark.SetMarkArea( rSrcRange );
179 ScClipParam aClipParam(rSrcRange, false);
180 pSrcDoc->CopyToClip(aClipParam, pClipDoc, &aSourceMark, false);
182 if ( pClipDoc->HasAttrib( 0,0,nSrcTab, MAXCOL,MAXROW,nSrcTab,
183 HASATTR_MERGED | HASATTR_OVERLAPPED ) )
185 ScPatternAttr aPattern( pSrcDoc->GetPool() );
186 aPattern.GetItemSet().Put( ScMergeAttr() ); // Defaults
187 aPattern.GetItemSet().Put( ScMergeFlagAttr() );
188 pClipDoc->ApplyPatternAreaTab( 0,0, MAXCOL,MAXROW, nSrcTab, aPattern );
191 ScMarkData aDestMark;
192 aDestMark.SelectOneTable( nDestTab );
193 aDestMark.SetMarkArea( aNewRange );
194 pDestDoc->CopyFromClip( aNewRange, aDestMark, IDF_ALL & ~IDF_FORMULA, NULL, pClipDoc, FALSE );
196 delete pClipDoc;
197 return TRUE;
200 //------------------------------------------------------------------------
202 ScFunctionAccess::ScFunctionAccess() :
203 pOptions( NULL ),
204 aPropertyMap( ScDocOptionsHelper::GetPropertyMap() ),
205 bInvalid( FALSE )
207 StartListening( *SFX_APP() ); // for SFX_HINT_DEINITIALIZING
210 ScFunctionAccess::~ScFunctionAccess()
212 delete pOptions;
215 void ScFunctionAccess::Notify( SfxBroadcaster&, const SfxHint& rHint )
217 if ( rHint.ISA(SfxSimpleHint) &&
218 ((SfxSimpleHint&)rHint).GetId() == SFX_HINT_DEINITIALIZING )
220 // document must not be used anymore
221 aDocCache.Clear();
222 bInvalid = TRUE;
226 // stuff for exService_...
228 uno::Reference<uno::XInterface> SAL_CALL ScFunctionAccess_CreateInstance(
229 const uno::Reference<lang::XMultiServiceFactory>& )
231 ScUnoGuard aGuard;
232 ScDLL::Init();
233 static uno::Reference< uno::XInterface > xInst((::cppu::OWeakObject*) new ScFunctionAccess);
234 return xInst;
237 rtl::OUString ScFunctionAccess::getImplementationName_Static()
239 return rtl::OUString::createFromAscii( "stardiv.StarCalc.ScFunctionAccess" );
242 uno::Sequence<rtl::OUString> ScFunctionAccess::getSupportedServiceNames_Static()
244 uno::Sequence<rtl::OUString> aRet(1);
245 rtl::OUString* pArray = aRet.getArray();
246 pArray[0] = rtl::OUString::createFromAscii( SCFUNCTIONACCESS_SERVICE );
247 return aRet;
250 // XServiceInfo
252 rtl::OUString SAL_CALL ScFunctionAccess::getImplementationName() throw(uno::RuntimeException)
254 return rtl::OUString::createFromAscii( "ScFunctionAccess" );
257 sal_Bool SAL_CALL ScFunctionAccess::supportsService( const rtl::OUString& rServiceName )
258 throw(uno::RuntimeException)
260 String aServiceStr(rServiceName);
261 return aServiceStr.EqualsAscii( SCFUNCTIONACCESS_SERVICE ) ||
262 aServiceStr.EqualsAscii( SCDOCSETTINGS_SERVICE );
265 uno::Sequence<rtl::OUString> SAL_CALL ScFunctionAccess::getSupportedServiceNames()
266 throw(uno::RuntimeException)
268 uno::Sequence<rtl::OUString> aRet(2);
269 rtl::OUString* pArray = aRet.getArray();
270 pArray[0] = rtl::OUString::createFromAscii( SCFUNCTIONACCESS_SERVICE );
271 pArray[1] = rtl::OUString::createFromAscii( SCDOCSETTINGS_SERVICE );
272 return aRet;
275 // XPropertySet (document settings)
277 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScFunctionAccess::getPropertySetInfo()
278 throw(uno::RuntimeException)
280 ScUnoGuard aGuard;
281 static uno::Reference<beans::XPropertySetInfo> aRef(
282 new SfxItemPropertySetInfo( &aPropertyMap ));
283 return aRef;
286 void SAL_CALL ScFunctionAccess::setPropertyValue(
287 const rtl::OUString& aPropertyName, const uno::Any& aValue )
288 throw(beans::UnknownPropertyException, beans::PropertyVetoException,
289 lang::IllegalArgumentException, lang::WrappedTargetException,
290 uno::RuntimeException)
292 ScUnoGuard aGuard;
294 if ( !pOptions )
295 pOptions = new ScDocOptions();
297 // options aren't initialized from configuration - always get the same default behaviour
299 BOOL bDone = ScDocOptionsHelper::setPropertyValue( *pOptions, aPropertyMap, aPropertyName, aValue );
300 if (!bDone)
301 throw beans::UnknownPropertyException();
304 uno::Any SAL_CALL ScFunctionAccess::getPropertyValue( const rtl::OUString& aPropertyName )
305 throw(beans::UnknownPropertyException, lang::WrappedTargetException,
306 uno::RuntimeException)
308 ScUnoGuard aGuard;
310 if ( !pOptions )
311 pOptions = new ScDocOptions();
313 // options aren't initialized from configuration - always get the same default behaviour
315 return ScDocOptionsHelper::getPropertyValue( *pOptions, aPropertyMap, aPropertyName );
318 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFunctionAccess )
320 // XFunctionAccess
322 BOOL lcl_AddFunctionToken( ScTokenArray& rArray, const rtl::OUString& rName,const ScCompiler& rCompiler )
324 // function names are always case-insensitive
325 String aUpper( ScGlobal::pCharClass->upper( rName ) );
327 // same options as in ScCompiler::IsOpCode:
328 // 1. built-in function name
330 OpCode eOp = rCompiler.GetEnglishOpCode( aUpper );
331 if ( eOp != ocNone )
333 rArray.AddOpCode( eOp );
334 return TRUE;
337 // 2. old add in functions
339 USHORT nIndex;
340 if ( ScGlobal::GetFuncCollection()->SearchFunc( aUpper, nIndex ) )
342 rArray.AddExternal( aUpper.GetBuffer() );
343 return TRUE;
346 // 3. new (uno) add in functions
348 String aIntName(ScGlobal::GetAddInCollection()->FindFunction( aUpper, FALSE ));
349 if (aIntName.Len())
351 rArray.AddExternal( aIntName.GetBuffer() ); // international name
352 return TRUE;
355 return FALSE; // no valid function name
358 void lcl_AddRef( ScTokenArray& rArray, long nStartRow, long nColCount, long nRowCount )
360 ScComplexRefData aRef;
361 aRef.InitFlags();
362 aRef.Ref1.nTab = 0;
363 aRef.Ref2.nTab = 0;
364 aRef.Ref1.nCol = 0;
365 aRef.Ref1.nRow = (SCROW) nStartRow;
366 aRef.Ref2.nCol = (SCCOL) (nColCount - 1);
367 aRef.Ref2.nRow = (SCROW) (nStartRow + nRowCount - 1);
368 rArray.AddDoubleReference(aRef);
371 class SimpleVisitor
373 protected:
374 bool mbArgError;
375 ScDocument* mpDoc;
376 public:
377 SimpleVisitor( ScDocument* pDoc ) : mbArgError( false ), mpDoc( pDoc ) {}
378 // could possibly just get away with JUST the following overload
379 // 1) virtual void visitElem( long& nCol, long& nRow, const double& elem )
380 // 2) virtual void visitElem( long& nCol, long& nRow, const rtl::OUString& elem )
381 // 3) virtual void visitElem( long& nCol, long& nRow, const uno::Any& elem )
382 // the other types methods are here just to reflect the orig code and for
383 // completeness.
385 void visitElem( long nCol, long nRow, const sal_Int16& elem )
387 mpDoc->SetValue( (SCCOL) nCol, (SCROW) nRow, 0, elem );
389 void visitElem( long nCol, long nRow, const sal_Int32& elem )
391 mpDoc->SetValue( (SCCOL) nCol, (SCROW) nRow, 0, elem );
393 void visitElem( long nCol, long nRow, const double& elem )
395 mpDoc->SetValue( (SCCOL) nCol, (SCROW) nRow, 0, elem );
397 void visitElem( long nCol, long nRow, const rtl::OUString& elem )
399 if ( elem.getLength() )
400 mpDoc->PutCell( (SCCOL) nCol, (SCROW) nRow, 0,
401 new ScStringCell( elem ) );
403 void visitElem( long nCol, long nRow, const uno::Any& rElement )
405 uno::TypeClass eElemClass = rElement.getValueTypeClass();
406 if ( eElemClass == uno::TypeClass_VOID )
408 // leave empty
410 else if ( eElemClass == uno::TypeClass_BYTE ||
411 eElemClass == uno::TypeClass_SHORT ||
412 eElemClass == uno::TypeClass_UNSIGNED_SHORT ||
413 eElemClass == uno::TypeClass_LONG ||
414 eElemClass == uno::TypeClass_UNSIGNED_LONG ||
415 eElemClass == uno::TypeClass_FLOAT ||
416 eElemClass == uno::TypeClass_DOUBLE )
418 // #87871# accept integer types because Basic passes a floating point
419 // variable as byte, short or long if it's an integer number.
420 double fVal;
421 rElement >>= fVal;
422 visitElem( nCol, nRow, fVal );
424 else if ( eElemClass == uno::TypeClass_STRING )
426 rtl::OUString aUStr;
427 rElement >>= aUStr;
428 visitElem( nCol, nRow, aUStr );
430 else
431 mbArgError = true;
433 bool hasArgError() { return mbArgError; }
436 template< class seq >
437 class SequencesContainer
439 uno::Sequence< uno::Sequence< seq > > maSeq;
441 long& mrDocRow;
442 bool mbOverflow;
443 bool mbArgError;
444 ScDocument* mpDoc;
445 ScTokenArray& mrTokenArr;
447 public:
448 SequencesContainer( const uno::Any& rArg, ScTokenArray& rTokenArr, long& rDocRow, ScDocument* pDoc ) :
449 mrDocRow( rDocRow ), mbOverflow(false), mbArgError(false), mpDoc( pDoc ), mrTokenArr( rTokenArr )
451 rArg >>= maSeq;
454 void process()
456 SimpleVisitor aVisitor(mpDoc);
457 long nStartRow = mrDocRow;
458 long nRowCount = maSeq.getLength();
459 long nMaxColCount = 0;
460 const uno::Sequence< seq >* pRowArr = maSeq.getConstArray();
461 for ( long nRow=0; nRow<nRowCount; nRow++ )
463 long nColCount = pRowArr[nRow].getLength();
464 if ( nColCount > nMaxColCount )
465 nMaxColCount = nColCount;
466 const seq* pColArr = pRowArr[nRow].getConstArray();
467 for (long nCol=0; nCol<nColCount; nCol++)
468 if ( nCol <= MAXCOL && mrDocRow <= MAXROW )
469 aVisitor.visitElem( nCol, mrDocRow, pColArr[ nCol ] );
470 else
471 mbOverflow=true;
472 mrDocRow++;
474 mbArgError = aVisitor.hasArgError();
475 if ( nRowCount && nMaxColCount && !mbOverflow )
476 lcl_AddRef( mrTokenArr, nStartRow, nMaxColCount, nRowCount );
478 bool getOverflow() { return mbOverflow; }
479 bool getArgError() { return mbArgError; }
482 template <class T>
483 class ArrayOfArrayProc
485 public:
486 static void processSequences( ScDocument* pDoc, const uno::Any& rArg, ScTokenArray& rTokenArr,
487 long& rDocRow, BOOL& rArgErr, BOOL& rOverflow )
489 SequencesContainer< T > aContainer( rArg, rTokenArr, rDocRow, pDoc );
490 aContainer.process();
491 rArgErr = aContainer.getArgError();
492 rOverflow = aContainer.getOverflow();
496 uno::Any SAL_CALL ScFunctionAccess::callFunction( const rtl::OUString& aName,
497 const uno::Sequence<uno::Any>& aArguments )
498 throw(container::NoSuchElementException, lang::IllegalArgumentException,
499 uno::RuntimeException)
501 ScUnoGuard aGuard;
503 if (bInvalid)
504 throw uno::RuntimeException();
506 // use cached document if not in use, temporary document otherwise
507 // (deleted in ScTempDocSource dtor)
508 ScTempDocSource aSource( aDocCache );
509 ScDocument* pDoc = aSource.GetDocument();
510 const static SCTAB nTempSheet = 1;
511 // Create an extra tab to contain the Function Cell
512 // this will allow full rows to be used.
513 if ( !pDoc->HasTable( nTempSheet ) )
514 pDoc->MakeTable( nTempSheet );
516 /// TODO: check
517 ScAddress aAdr;
518 ScCompiler aCompiler(pDoc,aAdr);
519 aCompiler.SetGrammar(pDoc->GetGrammar());
520 //if (!ScCompiler::IsInitialized())
521 // ScCompiler::InitSymbolsEnglish();
524 // find function
527 ScTokenArray aTokenArr;
528 if ( !lcl_AddFunctionToken( aTokenArr, aName,aCompiler ) )
530 // function not found
531 throw container::NoSuchElementException();
535 // set options (null date, etc.)
538 if ( pOptions )
539 pDoc->SetDocOptions( *pOptions );
542 // add arguments to token array
545 BOOL bArgErr = FALSE;
546 BOOL bOverflow = FALSE;
547 long nDocRow = 0;
548 long nArgCount = aArguments.getLength();
549 const uno::Any* pArgArr = aArguments.getConstArray();
551 aTokenArr.AddOpCode(ocOpen);
552 for (long nPos=0; nPos<nArgCount; nPos++)
554 if ( nPos > 0 )
555 aTokenArr.AddOpCode(ocSep);
557 const uno::Any& rArg = pArgArr[nPos];
559 uno::TypeClass eClass = rArg.getValueTypeClass();
560 uno::Type aType = rArg.getValueType();
561 if ( eClass == uno::TypeClass_BYTE ||
562 eClass == uno::TypeClass_SHORT ||
563 eClass == uno::TypeClass_UNSIGNED_SHORT ||
564 eClass == uno::TypeClass_LONG ||
565 eClass == uno::TypeClass_UNSIGNED_LONG ||
566 eClass == uno::TypeClass_FLOAT ||
567 eClass == uno::TypeClass_DOUBLE )
569 // #87871# accept integer types because Basic passes a floating point
570 // variable as byte, short or long if it's an integer number.
571 double fVal = 0;
572 rArg >>= fVal;
573 aTokenArr.AddDouble( fVal );
575 else if ( eClass == uno::TypeClass_STRING )
577 rtl::OUString aUStr;
578 rArg >>= aUStr;
579 String aStr( aUStr );
580 aTokenArr.AddString( aStr.GetBuffer() );
582 else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<sal_Int16> > *)0 ) ) )
584 ArrayOfArrayProc<sal_Int16>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
586 else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<sal_Int32> > *)0 ) ) )
588 ArrayOfArrayProc<sal_Int32>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
590 else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<double> > *)0 ) ) )
592 ArrayOfArrayProc<double>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
594 else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<rtl::OUString> > *)0 ) ) )
596 ArrayOfArrayProc<rtl::OUString>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
598 else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<uno::Any> > *)0 ) ) )
600 ArrayOfArrayProc<uno::Any>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
602 else if ( aType.equals( getCppuType( (uno::Reference<table::XCellRange>*)0 ) ) )
604 // currently, only our own cell ranges are supported
606 uno::Reference<table::XCellRange> xRange(rArg, uno::UNO_QUERY);
607 ScCellRangesBase* pImpl = ScCellRangesBase::getImplementation( xRange );
608 if ( pImpl )
610 ScDocument* pSrcDoc = pImpl->GetDocument();
611 const ScRangeList& rRanges = pImpl->GetRangeList();
612 if ( pSrcDoc && rRanges.Count() == 1 )
614 ScRange aSrcRange = *rRanges.GetObject(0);
616 long nStartRow = nDocRow;
617 long nColCount = aSrcRange.aEnd.Col() - aSrcRange.aStart.Col() + 1;
618 long nRowCount = aSrcRange.aEnd.Row() - aSrcRange.aStart.Row() + 1;
620 if ( nStartRow + nRowCount > MAXROWCOUNT )
621 bOverflow = TRUE;
622 else
624 // copy data
625 if ( !lcl_CopyData( pSrcDoc, aSrcRange, pDoc, ScAddress( 0, (SCROW)nDocRow, 0 ) ) )
626 bOverflow = TRUE;
629 nDocRow += nRowCount;
630 if ( !bOverflow )
631 lcl_AddRef( aTokenArr, nStartRow, nColCount, nRowCount );
633 else
634 bArgErr = TRUE;
636 else
637 bArgErr = TRUE;
639 else
640 bArgErr = TRUE; // invalid type
642 aTokenArr.AddOpCode(ocClose);
643 aTokenArr.AddOpCode(ocStop);
646 // execute formula
649 uno::Any aRet;
650 if ( !bArgErr && !bOverflow && nDocRow <= MAXROWCOUNT )
652 ScAddress aFormulaPos( 0, 0, nTempSheet );
653 // GRAM_PODF_A1 doesn't really matter for the token array but fits with
654 // other API compatibility grammars.
655 ScFormulaCell* pFormula = new ScFormulaCell( pDoc, aFormulaPos,
656 &aTokenArr,formula::FormulaGrammar::GRAM_PODF_A1, MM_FORMULA );
657 pDoc->PutCell( aFormulaPos, pFormula ); //! necessary?
659 // call GetMatrix before GetErrCode because GetMatrix always recalculates
660 // if there is no matrix result
662 const ScMatrix* pMat = pFormula->GetMatrix();
663 USHORT nErrCode = pFormula->GetErrCode();
664 if ( nErrCode == 0 )
666 if ( pMat )
668 // array result
669 ScRangeToSequence::FillMixedArray( aRet, pMat );
671 else if ( pFormula->IsValue() )
673 // numeric value
674 aRet <<= (double) pFormula->GetValue();
676 else
678 // string result
679 String aStrVal;
680 pFormula->GetString( aStrVal );
681 aRet <<= rtl::OUString( aStrVal );
684 else if ( nErrCode == NOTAVAILABLE )
686 // #N/A: leave result empty, no exception
688 else
690 // any other error: IllegalArgumentException
691 bArgErr = TRUE;
694 pDoc->DeleteAreaTab( 0, 0, MAXCOL, MAXROW, 0, IDF_ALL );
695 pDoc->DeleteAreaTab( 0, 0, 0, 0, nTempSheet, IDF_ALL );
698 if (bOverflow)
699 throw uno::RuntimeException();
701 if (bArgErr)
702 throw lang::IllegalArgumentException();
704 return aRet;