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