xref: /aoo41x/main/sc/source/ui/unoobj/funcuno.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 
32 
33 #include <tools/debug.hxx>
34 #include <sfx2/app.hxx>
35 #include <svl/itemprop.hxx>
36 
37 #include "scitems.hxx"
38 #include "funcuno.hxx"
39 #include "miscuno.hxx"
40 #include "cellsuno.hxx"
41 #include "unoguard.hxx"
42 #include "scdll.hxx"
43 #include "document.hxx"
44 #include "compiler.hxx"
45 #include "formula/errorcodes.hxx"
46 #include "callform.hxx"
47 #include "addincol.hxx"
48 #include "rangeseq.hxx"
49 #include "cell.hxx"
50 #include "docoptio.hxx"
51 #include "optuno.hxx"
52 #include <docuno.hxx>
53 // for lcl_CopyData:
54 #include "markdata.hxx"
55 #include "patattr.hxx"
56 #include "docpool.hxx"
57 #include "attrib.hxx"
58 #include "clipparam.hxx"
59 #include "dociter.hxx"
60 
61 using namespace com::sun::star;
62 
63 //------------------------------------------------------------------------
64 
65 //	registered as implementation for service FunctionAccess,
66 //	also supports service SpreadsheetDocumentSettings (to set null date etc.)
67 
68 #define SCFUNCTIONACCESS_SERVICE	"com.sun.star.sheet.FunctionAccess"
69 #define SCDOCSETTINGS_SERVICE		"com.sun.star.sheet.SpreadsheetDocumentSettings"
70 
71 //------------------------------------------------------------------------
72 
73 // helper to use cached document if not in use, temporary document otherwise
74 
75 class ScTempDocSource
76 {
77 private:
78 	ScTempDocCache&	rCache;
79 	ScDocument*		pTempDoc;
80 
81 	static ScDocument*	CreateDocument();		// create and initialize doc
82 
83 public:
84 				ScTempDocSource( ScTempDocCache& rDocCache );
85 				~ScTempDocSource();
86 
87 	ScDocument*		GetDocument();
88 };
89 
90 //------------------------------------------------------------------------
91 
92 // static
93 ScDocument* ScTempDocSource::CreateDocument()
94 {
95 	ScDocument* pDoc = new ScDocument;					// SCDOCMODE_DOCUMENT
96 	pDoc->MakeTable( 0 );
97 	return pDoc;
98 }
99 
100 ScTempDocSource::ScTempDocSource( ScTempDocCache& rDocCache ) :
101 	rCache( rDocCache ),
102 	pTempDoc( NULL )
103 {
104 	if ( rCache.IsInUse() )
105 		pTempDoc = CreateDocument();
106 	else
107 	{
108 		rCache.SetInUse( sal_True );
109 		if ( !rCache.GetDocument() )
110 			rCache.SetDocument( CreateDocument() );
111 	}
112 }
113 
114 ScTempDocSource::~ScTempDocSource()
115 {
116 	if ( pTempDoc )
117 		delete pTempDoc;
118 	else
119 		rCache.SetInUse( sal_False );
120 }
121 
122 ScDocument* ScTempDocSource::GetDocument()
123 {
124 	if ( pTempDoc )
125 		return pTempDoc;
126 	else
127 		return rCache.GetDocument();
128 }
129 
130 //------------------------------------------------------------------------
131 
132 ScTempDocCache::ScTempDocCache() :
133 	pDoc( NULL ),
134 	bInUse( sal_False )
135 {
136 }
137 
138 ScTempDocCache::~ScTempDocCache()
139 {
140 	DBG_ASSERT( !bInUse, "ScTempDocCache dtor: bInUse" );
141 	delete pDoc;
142 }
143 
144 void ScTempDocCache::SetDocument( ScDocument* pNew )
145 {
146 	DBG_ASSERT( !pDoc, "ScTempDocCache::SetDocument: already set" );
147 	pDoc = pNew;
148 }
149 
150 void ScTempDocCache::Clear()
151 {
152 	DBG_ASSERT( !bInUse, "ScTempDocCache::Clear: bInUse" );
153 	delete pDoc;
154 	pDoc = NULL;
155 }
156 
157 //------------------------------------------------------------------------
158 
159 //	copy results from one document into another
160 //!	merge this with ScAreaLink::Refresh
161 //!	copy directly without a clipboard document?
162 
163 sal_Bool lcl_CopyData( ScDocument* pSrcDoc, const ScRange& rSrcRange,
164 					ScDocument* pDestDoc, const ScAddress& rDestPos )
165 {
166 	SCTAB nSrcTab = rSrcRange.aStart.Tab();
167 	SCTAB nDestTab = rDestPos.Tab();
168 
169 	ScRange aNewRange( rDestPos, ScAddress(
170 				rSrcRange.aEnd.Col() - rSrcRange.aStart.Col() + rDestPos.Col(),
171 				rSrcRange.aEnd.Row() - rSrcRange.aStart.Row() + rDestPos.Row(),
172 				nDestTab ) );
173 
174 	ScDocument* pClipDoc = new ScDocument( SCDOCMODE_CLIP );
175 	ScMarkData aSourceMark;
176 	aSourceMark.SelectOneTable( nSrcTab );		// for CopyToClip
177 	aSourceMark.SetMarkArea( rSrcRange );
178     ScClipParam aClipParam(rSrcRange, false);
179     pSrcDoc->CopyToClip(aClipParam, pClipDoc, &aSourceMark, false);
180 
181 	if ( pClipDoc->HasAttrib( 0,0,nSrcTab, MAXCOL,MAXROW,nSrcTab,
182 								HASATTR_MERGED | HASATTR_OVERLAPPED ) )
183 	{
184 		ScPatternAttr aPattern( pSrcDoc->GetPool() );
185 		aPattern.GetItemSet().Put( ScMergeAttr() );				// Defaults
186 		aPattern.GetItemSet().Put( ScMergeFlagAttr() );
187 		pClipDoc->ApplyPatternAreaTab( 0,0, MAXCOL,MAXROW, nSrcTab, aPattern );
188 	}
189 
190     // If the range contains formula cells with default number format,
191     // apply a number format for the formula result
192     ScCellIterator aIter( pClipDoc, rSrcRange );
193     ScBaseCell* pCell = aIter.GetFirst();
194     while (pCell)
195     {
196         if (pCell->GetCellType() == CELLTYPE_FORMULA)
197         {
198             ScAddress aCellPos = aIter.GetPos();
199             sal_uInt32 nFormat = pClipDoc->GetNumberFormat(aCellPos);
200             if ( (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
201             {
202                 ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
203                 sal_uInt16 nErrCode = pFCell->GetErrCode();
204                 if ( nErrCode == 0 && pFCell->IsValue() )
205                 {
206                     sal_uInt32 nNewFormat = pFCell->GetStandardFormat( *pClipDoc->GetFormatTable(), nFormat );
207                     if ( nNewFormat != nFormat )
208                         pClipDoc->ApplyAttr( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(),
209                                              SfxUInt32Item( ATTR_VALUE_FORMAT, nNewFormat ) );
210                 }
211             }
212         }
213         pCell = aIter.GetNext();
214     }
215 
216 	ScMarkData aDestMark;
217 	aDestMark.SelectOneTable( nDestTab );
218 	aDestMark.SetMarkArea( aNewRange );
219 	pDestDoc->CopyFromClip( aNewRange, aDestMark, IDF_ALL & ~IDF_FORMULA, NULL, pClipDoc, sal_False );
220 
221 	delete pClipDoc;
222 	return sal_True;
223 }
224 
225 //------------------------------------------------------------------------
226 
227 ScFunctionAccess::ScFunctionAccess() :
228 	pOptions( NULL ),
229     aPropertyMap( ScDocOptionsHelper::GetPropertyMap() ),
230     mbArray( true ),    // default according to behaviour of older Office versions
231 	mbValid( true )
232 {
233 	StartListening( *SFX_APP() );		// for SFX_HINT_DEINITIALIZING
234 }
235 
236 ScFunctionAccess::~ScFunctionAccess()
237 {
238 	delete pOptions;
239 }
240 
241 void ScFunctionAccess::Notify( SfxBroadcaster&, const SfxHint& rHint )
242 {
243 	if ( rHint.ISA(SfxSimpleHint) &&
244 		((SfxSimpleHint&)rHint).GetId() == SFX_HINT_DEINITIALIZING )
245 	{
246 		//	document must not be used anymore
247 		aDocCache.Clear();
248 		mbValid = false;
249 	}
250 }
251 
252 // stuff for exService_...
253 
254 uno::Reference<uno::XInterface>	SAL_CALL ScFunctionAccess_CreateInstance(
255 						const uno::Reference<lang::XMultiServiceFactory>& )
256 {
257 	ScUnoGuard aGuard;
258 	ScDLL::Init();
259 	static uno::Reference< uno::XInterface > xInst((::cppu::OWeakObject*) new ScFunctionAccess);
260 	return xInst;
261 }
262 
263 rtl::OUString ScFunctionAccess::getImplementationName_Static()
264 {
265 	return rtl::OUString::createFromAscii( "stardiv.StarCalc.ScFunctionAccess" );
266 }
267 
268 uno::Sequence<rtl::OUString> ScFunctionAccess::getSupportedServiceNames_Static()
269 {
270 	uno::Sequence<rtl::OUString> aRet(1);
271 	rtl::OUString* pArray = aRet.getArray();
272 	pArray[0] = rtl::OUString::createFromAscii( SCFUNCTIONACCESS_SERVICE );
273 	return aRet;
274 }
275 
276 // XServiceInfo
277 
278 rtl::OUString SAL_CALL ScFunctionAccess::getImplementationName() throw(uno::RuntimeException)
279 {
280 	return rtl::OUString::createFromAscii( "ScFunctionAccess" );
281 }
282 
283 sal_Bool SAL_CALL ScFunctionAccess::supportsService( const rtl::OUString& rServiceName )
284 													throw(uno::RuntimeException)
285 {
286 	String aServiceStr(rServiceName);
287 	return aServiceStr.EqualsAscii( SCFUNCTIONACCESS_SERVICE ) ||
288 		   aServiceStr.EqualsAscii( SCDOCSETTINGS_SERVICE );
289 }
290 
291 uno::Sequence<rtl::OUString> SAL_CALL ScFunctionAccess::getSupportedServiceNames()
292 													throw(uno::RuntimeException)
293 {
294 	uno::Sequence<rtl::OUString> aRet(2);
295 	rtl::OUString* pArray = aRet.getArray();
296 	pArray[0] = rtl::OUString::createFromAscii( SCFUNCTIONACCESS_SERVICE );
297 	pArray[1] = rtl::OUString::createFromAscii( SCDOCSETTINGS_SERVICE );
298 	return aRet;
299 }
300 
301 // XPropertySet (document settings)
302 
303 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScFunctionAccess::getPropertySetInfo()
304 														throw(uno::RuntimeException)
305 {
306 	ScUnoGuard aGuard;
307 	static uno::Reference<beans::XPropertySetInfo> aRef(
308         new SfxItemPropertySetInfo( &aPropertyMap ));
309 	return aRef;
310 }
311 
312 void SAL_CALL ScFunctionAccess::setPropertyValue(
313 						const rtl::OUString& aPropertyName, const uno::Any& aValue )
314 				throw(beans::UnknownPropertyException, beans::PropertyVetoException,
315 						lang::IllegalArgumentException, lang::WrappedTargetException,
316 						uno::RuntimeException)
317 {
318 	ScUnoGuard aGuard;
319 
320     if( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsArrayFunction" ) ) )
321     {
322         if( !(aValue >>= mbArray) )
323             throw lang::IllegalArgumentException();
324     }
325     else
326     {
327     	if ( !pOptions )
328     		pOptions = new ScDocOptions();
329 
330     	// options aren't initialized from configuration - always get the same default behaviour
331 
332         sal_Bool bDone = ScDocOptionsHelper::setPropertyValue( *pOptions, aPropertyMap, aPropertyName, aValue );
333     	if (!bDone)
334     		throw beans::UnknownPropertyException();
335     }
336 }
337 
338 uno::Any SAL_CALL ScFunctionAccess::getPropertyValue( const rtl::OUString& aPropertyName )
339 				throw(beans::UnknownPropertyException, lang::WrappedTargetException,
340 						uno::RuntimeException)
341 {
342 	ScUnoGuard aGuard;
343 
344     if( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsArrayFunction" ) ) )
345         return uno::Any( mbArray );
346 
347 	if ( !pOptions )
348 		pOptions = new ScDocOptions();
349 
350 	// options aren't initialized from configuration - always get the same default behaviour
351 
352     return ScDocOptionsHelper::getPropertyValue( *pOptions, aPropertyMap, aPropertyName );
353 }
354 
355 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFunctionAccess )
356 
357 // XFunctionAccess
358 
359 sal_Bool lcl_AddFunctionToken( ScTokenArray& rArray, const rtl::OUString& rName,const ScCompiler& rCompiler )
360 {
361 	// function names are always case-insensitive
362 	String aUpper( ScGlobal::pCharClass->upper( rName ) );
363 
364 	// same options as in ScCompiler::IsOpCode:
365 	// 1. built-in function name
366 
367     OpCode eOp = rCompiler.GetEnglishOpCode( aUpper );
368     if ( eOp != ocNone )
369     {
370         rArray.AddOpCode( eOp );
371         return sal_True;
372     }
373 
374 	// 2. old add in functions
375 
376 	sal_uInt16 nIndex;
377 	if ( ScGlobal::GetFuncCollection()->SearchFunc( aUpper, nIndex ) )
378 	{
379 		rArray.AddExternal( aUpper.GetBuffer() );
380 		return sal_True;
381 	}
382 
383 	// 3. new (uno) add in functions
384 
385 	String aIntName(ScGlobal::GetAddInCollection()->FindFunction( aUpper, sal_False ));
386 	if (aIntName.Len())
387 	{
388 		rArray.AddExternal( aIntName.GetBuffer() );		// international name
389 		return sal_True;
390 	}
391 
392 	return sal_False;		// no valid function name
393 }
394 
395 void lcl_AddRef( ScTokenArray& rArray, long nStartRow, long nColCount, long nRowCount )
396 {
397 	ScComplexRefData aRef;
398 	aRef.InitFlags();
399 	aRef.Ref1.nTab = 0;
400 	aRef.Ref2.nTab = 0;
401 	aRef.Ref1.nCol = 0;
402 	aRef.Ref1.nRow = (SCROW) nStartRow;
403 	aRef.Ref2.nCol = (SCCOL) (nColCount - 1);
404 	aRef.Ref2.nRow = (SCROW) (nStartRow + nRowCount - 1);
405 	rArray.AddDoubleReference(aRef);
406 }
407 
408 class SimpleVisitor
409 {
410 protected:
411 	bool mbArgError;
412 	ScDocument* mpDoc;
413 public:
414     SimpleVisitor( ScDocument* pDoc ) : mbArgError( false ), mpDoc( pDoc ) {}
415 	// could possibly just get away with JUST the following overload
416 	// 1) virtual void visitElem( long& nCol, long& nRow, const double& elem )
417 	// 2) virtual void visitElem( long& nCol, long& nRow, const rtl::OUString& elem )
418 	// 3) virtual void visitElem( long& nCol, long& nRow, const uno::Any& elem )
419 	// the other types methods are here just to reflect the orig code and for
420 	// completeness.
421 
422 	void visitElem( long nCol, long nRow, const sal_Int16& elem )
423 	{
424 		mpDoc->SetValue( (SCCOL) nCol, (SCROW) nRow, 0, elem );
425 	}
426 	void visitElem( long nCol, long nRow, const sal_Int32& elem )
427 	{
428 		mpDoc->SetValue( (SCCOL) nCol, (SCROW) nRow, 0, elem );
429 	}
430 	void visitElem( long nCol, long nRow, const double& elem )
431 	{
432 		mpDoc->SetValue( (SCCOL) nCol, (SCROW) nRow, 0, elem );
433 	}
434 	void visitElem( long nCol, long nRow, const rtl::OUString& elem )
435 	{
436 		if ( elem.getLength() )
437 			mpDoc->PutCell( (SCCOL) nCol, (SCROW) nRow, 0,
438 										new ScStringCell( elem ) );
439 	}
440 	void visitElem( long nCol, long nRow, const uno::Any& rElement )
441 	{
442 		uno::TypeClass eElemClass = rElement.getValueTypeClass();
443 		if ( eElemClass == uno::TypeClass_VOID )
444 		{
445 			// leave empty
446 		}
447 		else if ( eElemClass == uno::TypeClass_BYTE ||
448 					eElemClass == uno::TypeClass_SHORT ||
449 					eElemClass == uno::TypeClass_UNSIGNED_SHORT ||
450 					eElemClass == uno::TypeClass_LONG ||
451 					eElemClass == uno::TypeClass_UNSIGNED_LONG ||
452 					eElemClass == uno::TypeClass_FLOAT ||
453 					eElemClass == uno::TypeClass_DOUBLE )
454 		{
455 			//	#87871# accept integer types because Basic passes a floating point
456 			//	variable as byte, short or long if it's an integer number.
457 			double fVal(0.0);
458 			rElement >>= fVal;
459 			visitElem( nCol, nRow, fVal );
460 		}
461 		else if ( eElemClass == uno::TypeClass_STRING )
462 		{
463 			rtl::OUString aUStr;
464 			rElement >>= aUStr;
465 			visitElem( nCol, nRow, aUStr );
466 		}
467 		else
468 			mbArgError = true;
469 	}
470 	bool hasArgError() { return mbArgError; }
471 };
472 
473 template< class seq >
474 class SequencesContainer
475 {
476 	uno::Sequence< uno::Sequence< seq > > maSeq;
477 
478 	long& mrDocRow;
479 	bool mbOverflow;
480 	bool mbArgError;
481 	ScDocument* mpDoc;
482 	ScTokenArray& mrTokenArr;
483 
484 public:
485 	SequencesContainer( const uno::Any& rArg, ScTokenArray& rTokenArr, long& rDocRow, ScDocument* pDoc ) :
486         mrDocRow( rDocRow ), mbOverflow(false), mbArgError(false), mpDoc( pDoc ), mrTokenArr( rTokenArr )
487 	{
488 		rArg >>= maSeq;
489 	}
490 
491 	void process()
492 	{
493 		SimpleVisitor aVisitor(mpDoc);
494 		long nStartRow = mrDocRow;
495 		long nRowCount = maSeq.getLength();
496 		long nMaxColCount = 0;
497 		const uno::Sequence< seq >* pRowArr = maSeq.getConstArray();
498 		for ( long nRow=0; nRow<nRowCount; nRow++ )
499 		{
500 			long nColCount = pRowArr[nRow].getLength();
501 			if ( nColCount > nMaxColCount )
502 				nMaxColCount = nColCount;
503 			const seq* pColArr = pRowArr[nRow].getConstArray();
504 			for (long nCol=0; nCol<nColCount; nCol++)
505 				if ( nCol <= MAXCOL && mrDocRow <= MAXROW )
506 					aVisitor.visitElem( nCol, mrDocRow, pColArr[ nCol ] );
507 				else
508 					mbOverflow=true;
509 			mrDocRow++;
510 		}
511 		mbArgError = aVisitor.hasArgError();
512 		if ( nRowCount && nMaxColCount && !mbOverflow )
513 			lcl_AddRef( mrTokenArr, nStartRow, nMaxColCount, nRowCount );
514 	}
515 	bool getOverflow() { return mbOverflow; }
516 	bool getArgError() { return mbArgError; }
517 };
518 
519 template <class T>
520 class ArrayOfArrayProc
521 {
522 public:
523 static void processSequences( ScDocument* pDoc, const uno::Any& rArg, ScTokenArray& rTokenArr,
524 								long& rDocRow, sal_Bool& rArgErr, sal_Bool& rOverflow )
525 {
526 	SequencesContainer< T > aContainer( rArg, rTokenArr, rDocRow, pDoc );
527 	aContainer.process();
528 	rArgErr = aContainer.getArgError();
529 	rOverflow = aContainer.getOverflow();
530 }
531 };
532 
533 uno::Any SAL_CALL ScFunctionAccess::callFunction( const rtl::OUString& aName,
534 							const uno::Sequence<uno::Any>& aArguments )
535 				throw(container::NoSuchElementException, lang::IllegalArgumentException,
536 						uno::RuntimeException)
537 {
538 	ScUnoGuard aGuard;
539 
540 	if (!mbValid)
541 		throw uno::RuntimeException();
542 
543 	// use cached document if not in use, temporary document otherwise
544 	//	(deleted in ScTempDocSource dtor)
545 	ScTempDocSource aSource( aDocCache );
546 	ScDocument* pDoc = aSource.GetDocument();
547 	const static SCTAB nTempSheet = 1;
548 	// Create an extra tab to contain the Function Cell
549 	// this will allow full rows to be used.
550 	if ( !pDoc->HasTable( nTempSheet ) )
551 		pDoc->MakeTable( nTempSheet );
552 
553     /// TODO: check
554     ScAddress aAdr;
555     ScCompiler aCompiler(pDoc,aAdr);
556     aCompiler.SetGrammar(pDoc->GetGrammar());
557 	//if (!ScCompiler::IsInitialized())
558  //       ScCompiler::InitSymbolsEnglish();
559 
560 	//
561 	//	find function
562 	//
563 
564 	ScTokenArray aTokenArr;
565 	if ( !lcl_AddFunctionToken( aTokenArr, aName,aCompiler ) )
566 	{
567 		// function not found
568 		throw container::NoSuchElementException();
569 	}
570 
571 	//
572 	//	set options (null date, etc.)
573 	//
574 
575 	if ( pOptions )
576 		pDoc->SetDocOptions( *pOptions );
577 
578 	//
579 	//	add arguments to token array
580 	//
581 
582 	sal_Bool bArgErr = sal_False;
583 	sal_Bool bOverflow = sal_False;
584 	long nDocRow = 0;
585 	long nArgCount = aArguments.getLength();
586 	const uno::Any* pArgArr = aArguments.getConstArray();
587 
588 	aTokenArr.AddOpCode(ocOpen);
589 	for (long nPos=0; nPos<nArgCount; nPos++)
590 	{
591 		if ( nPos > 0 )
592 			aTokenArr.AddOpCode(ocSep);
593 
594 		const uno::Any& rArg = pArgArr[nPos];
595 
596 		uno::TypeClass eClass = rArg.getValueTypeClass();
597 		uno::Type aType = rArg.getValueType();
598 		if ( eClass == uno::TypeClass_BYTE ||
599 		     eClass == uno::TypeClass_BOOLEAN ||
600 			 eClass == uno::TypeClass_SHORT ||
601 			 eClass == uno::TypeClass_UNSIGNED_SHORT ||
602 			 eClass == uno::TypeClass_LONG ||
603 			 eClass == uno::TypeClass_UNSIGNED_LONG ||
604 			 eClass == uno::TypeClass_FLOAT ||
605 			 eClass == uno::TypeClass_DOUBLE )
606 		{
607 			//	#87871# accept integer types because Basic passes a floating point
608 			//	variable as byte, short or long if it's an integer number.
609 			double fVal = 0;
610 			rArg >>= fVal;
611 			aTokenArr.AddDouble( fVal );
612 		}
613 		else if ( eClass == uno::TypeClass_STRING )
614 		{
615 			rtl::OUString aUStr;
616 			rArg >>= aUStr;
617 			String aStr( aUStr );
618 			aTokenArr.AddString( aStr.GetBuffer() );
619 		}
620 		else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<sal_Int16> > *)0 ) ) )
621 		{
622 			ArrayOfArrayProc<sal_Int16>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
623 		}
624 		else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<sal_Int32> > *)0 ) ) )
625 		{
626 			ArrayOfArrayProc<sal_Int32>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
627 		}
628 		else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<double> > *)0 ) ) )
629 		{
630 			ArrayOfArrayProc<double>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
631 		}
632 		else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<rtl::OUString> > *)0 ) ) )
633 		{
634 			ArrayOfArrayProc<rtl::OUString>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
635 		}
636 		else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<uno::Any> > *)0 ) ) )
637 		{
638 			ArrayOfArrayProc<uno::Any>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
639 		}
640 		else if ( aType.equals( getCppuType( (uno::Reference<table::XCellRange>*)0 ) ) )
641 		{
642 			// currently, only our own cell ranges are supported
643 
644             uno::Reference<table::XCellRange> xRange(rArg, uno::UNO_QUERY);
645 			ScCellRangesBase* pImpl = ScCellRangesBase::getImplementation( xRange );
646 			if ( pImpl )
647 			{
648 				ScDocument* pSrcDoc = pImpl->GetDocument();
649 				const ScRangeList& rRanges = pImpl->GetRangeList();
650 				if ( pSrcDoc && rRanges.Count() == 1 )
651 				{
652 					ScRange aSrcRange = *rRanges.GetObject(0);
653 
654 					long nStartRow = nDocRow;
655 					long nColCount = aSrcRange.aEnd.Col() - aSrcRange.aStart.Col() + 1;
656 					long nRowCount = aSrcRange.aEnd.Row() - aSrcRange.aStart.Row() + 1;
657 
658 					if ( nStartRow + nRowCount > MAXROWCOUNT )
659 						bOverflow = sal_True;
660 					else
661 					{
662 						// copy data
663 						if ( !lcl_CopyData( pSrcDoc, aSrcRange, pDoc, ScAddress( 0, (SCROW)nDocRow, 0 ) ) )
664 							bOverflow = sal_True;
665 					}
666 
667 					nDocRow += nRowCount;
668 					if ( !bOverflow )
669 						lcl_AddRef( aTokenArr, nStartRow, nColCount, nRowCount );
670 				}
671 				else
672 					bArgErr = sal_True;
673 			}
674 			else
675 				bArgErr = sal_True;
676 		}
677 		else
678 			bArgErr = sal_True;					// invalid type
679 	}
680 	aTokenArr.AddOpCode(ocClose);
681 	aTokenArr.AddOpCode(ocStop);
682 
683 	//
684 	//	execute formula
685 	//
686 
687 	uno::Any aRet;
688 	if ( !bArgErr && !bOverflow && nDocRow <= MAXROWCOUNT )
689 	{
690 		ScAddress aFormulaPos( 0, 0, nTempSheet );
691         // GRAM_PODF_A1 doesn't really matter for the token array but fits with
692         // other API compatibility grammars.
693         ScFormulaCell* pFormula = new ScFormulaCell( pDoc, aFormulaPos,
694                 &aTokenArr, formula::FormulaGrammar::GRAM_PODF_A1, (sal_uInt8)(mbArray ? MM_FORMULA : MM_NONE) );
695 		pDoc->PutCell( aFormulaPos, pFormula );		//! necessary?
696 
697 		//	call GetMatrix before GetErrCode because GetMatrix always recalculates
698 		//	if there is no matrix result
699 
700 		const ScMatrix* pMat = mbArray ? pFormula->GetMatrix() : 0;
701 		sal_uInt16 nErrCode = pFormula->GetErrCode();
702 		if ( nErrCode == 0 )
703 		{
704 			if ( pMat )
705 			{
706 				// array result
707 				ScRangeToSequence::FillMixedArray( aRet, pMat );
708 			}
709 			else if ( pFormula->IsValue() )
710 			{
711 				// numeric value
712 				aRet <<= (double) pFormula->GetValue();
713 			}
714 			else
715 			{
716 				// string result
717 				String aStrVal;
718 				pFormula->GetString( aStrVal );
719 				aRet <<= rtl::OUString( aStrVal );
720 			}
721 		}
722 		else if ( nErrCode == NOTAVAILABLE )
723 		{
724 			// #N/A: leave result empty, no exception
725 		}
726 		else
727 		{
728 			//	any other error: IllegalArgumentException
729 			bArgErr = sal_True;
730 		}
731 
732 		pDoc->DeleteAreaTab( 0, 0, MAXCOL, MAXROW, 0, IDF_ALL );
733 		pDoc->DeleteAreaTab( 0, 0, 0, 0, nTempSheet, IDF_ALL );
734 	}
735 
736 	if (bOverflow)
737 		throw uno::RuntimeException();
738 
739 	if (bArgErr)
740 		throw lang::IllegalArgumentException();
741 
742 	return aRet;
743 }
744 
745 
746