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()
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 {
281 String aServiceStr(rServiceName);
282 return aServiceStr.EqualsAscii( SCFUNCTIONACCESS_SERVICE ) ||
283 aServiceStr.EqualsAscii( SCDOCSETTINGS_SERVICE );
284 }
285
getSupportedServiceNames()286 uno::Sequence<rtl::OUString> SAL_CALL ScFunctionAccess::getSupportedServiceNames()
287 {
288 uno::Sequence<rtl::OUString> aRet(2);
289 rtl::OUString* pArray = aRet.getArray();
290 pArray[0] = rtl::OUString::createFromAscii( SCFUNCTIONACCESS_SERVICE );
291 pArray[1] = rtl::OUString::createFromAscii( SCDOCSETTINGS_SERVICE );
292 return aRet;
293 }
294
295 // XPropertySet (document settings)
296
getPropertySetInfo()297 uno::Reference<beans::XPropertySetInfo> SAL_CALL ScFunctionAccess::getPropertySetInfo()
298 {
299 ScUnoGuard aGuard;
300 static uno::Reference<beans::XPropertySetInfo> aRef(
301 new SfxItemPropertySetInfo( &aPropertyMap ));
302 return aRef;
303 }
304
setPropertyValue(const rtl::OUString & aPropertyName,const uno::Any & aValue)305 void SAL_CALL ScFunctionAccess::setPropertyValue(
306 const rtl::OUString& aPropertyName, const uno::Any& aValue )
307 {
308 ScUnoGuard aGuard;
309
310 if( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsArrayFunction" ) ) )
311 {
312 if( !(aValue >>= mbArray) )
313 throw lang::IllegalArgumentException();
314 }
315 else
316 {
317 if ( !pOptions )
318 pOptions = new ScDocOptions();
319
320 // options aren't initialized from configuration - always get the same default behaviour
321
322 sal_Bool bDone = ScDocOptionsHelper::setPropertyValue( *pOptions, aPropertyMap, aPropertyName, aValue );
323 if (!bDone)
324 throw beans::UnknownPropertyException();
325 }
326 }
327
getPropertyValue(const rtl::OUString & aPropertyName)328 uno::Any SAL_CALL ScFunctionAccess::getPropertyValue( const rtl::OUString& aPropertyName )
329 {
330 ScUnoGuard aGuard;
331
332 if( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsArrayFunction" ) ) )
333 return uno::Any( mbArray );
334
335 if ( !pOptions )
336 pOptions = new ScDocOptions();
337
338 // options aren't initialized from configuration - always get the same default behaviour
339
340 return ScDocOptionsHelper::getPropertyValue( *pOptions, aPropertyMap, aPropertyName );
341 }
342
SC_IMPL_DUMMY_PROPERTY_LISTENER(ScFunctionAccess)343 SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFunctionAccess )
344
345 // XFunctionAccess
346
347 sal_Bool lcl_AddFunctionToken( ScTokenArray& rArray, const rtl::OUString& rName,const ScCompiler& rCompiler )
348 {
349 // function names are always case-insensitive
350 String aUpper( ScGlobal::pCharClass->upper( rName ) );
351
352 // same options as in ScCompiler::IsOpCode:
353 // 1. built-in function name
354
355 OpCode eOp = rCompiler.GetEnglishOpCode( aUpper );
356 if ( eOp != ocNone )
357 {
358 rArray.AddOpCode( eOp );
359 return sal_True;
360 }
361
362 // 2. old add in functions
363
364 sal_uInt16 nIndex;
365 if ( ScGlobal::GetFuncCollection()->SearchFunc( aUpper, nIndex ) )
366 {
367 rArray.AddExternal( aUpper.GetBuffer() );
368 return sal_True;
369 }
370
371 // 3. new (uno) add in functions
372
373 String aIntName(ScGlobal::GetAddInCollection()->FindFunction( aUpper, sal_False ));
374 if (aIntName.Len())
375 {
376 rArray.AddExternal( aIntName.GetBuffer() ); // international name
377 return sal_True;
378 }
379
380 return sal_False; // no valid function name
381 }
382
lcl_AddRef(ScTokenArray & rArray,long nStartRow,long nColCount,long nRowCount)383 void lcl_AddRef( ScTokenArray& rArray, long nStartRow, long nColCount, long nRowCount )
384 {
385 ScComplexRefData aRef;
386 aRef.InitFlags();
387 aRef.Ref1.nTab = 0;
388 aRef.Ref2.nTab = 0;
389 aRef.Ref1.nCol = 0;
390 aRef.Ref1.nRow = (SCROW) nStartRow;
391 aRef.Ref2.nCol = (SCCOL) (nColCount - 1);
392 aRef.Ref2.nRow = (SCROW) (nStartRow + nRowCount - 1);
393 rArray.AddDoubleReference(aRef);
394 }
395
396 class SimpleVisitor
397 {
398 protected:
399 bool mbArgError;
400 ScDocument* mpDoc;
401 public:
SimpleVisitor(ScDocument * pDoc)402 SimpleVisitor( ScDocument* pDoc ) : mbArgError( false ), mpDoc( pDoc ) {}
403 // could possibly just get away with JUST the following overload
404 // 1) virtual void visitElem( long& nCol, long& nRow, const double& elem )
405 // 2) virtual void visitElem( long& nCol, long& nRow, const rtl::OUString& elem )
406 // 3) virtual void visitElem( long& nCol, long& nRow, const uno::Any& elem )
407 // the other types methods are here just to reflect the orig code and for
408 // completeness.
409
visitElem(long nCol,long nRow,const sal_Int16 & elem)410 void visitElem( long nCol, long nRow, const sal_Int16& elem )
411 {
412 mpDoc->SetValue( (SCCOL) nCol, (SCROW) nRow, 0, elem );
413 }
visitElem(long nCol,long nRow,const sal_Int32 & elem)414 void visitElem( long nCol, long nRow, const sal_Int32& elem )
415 {
416 mpDoc->SetValue( (SCCOL) nCol, (SCROW) nRow, 0, elem );
417 }
visitElem(long nCol,long nRow,const double & elem)418 void visitElem( long nCol, long nRow, const double& elem )
419 {
420 mpDoc->SetValue( (SCCOL) nCol, (SCROW) nRow, 0, elem );
421 }
visitElem(long nCol,long nRow,const rtl::OUString & elem)422 void visitElem( long nCol, long nRow, const rtl::OUString& elem )
423 {
424 if ( elem.getLength() )
425 mpDoc->PutCell( (SCCOL) nCol, (SCROW) nRow, 0,
426 new ScStringCell( elem ) );
427 }
visitElem(long nCol,long nRow,const uno::Any & rElement)428 void visitElem( long nCol, long nRow, const uno::Any& rElement )
429 {
430 uno::TypeClass eElemClass = rElement.getValueTypeClass();
431 if ( eElemClass == uno::TypeClass_VOID )
432 {
433 // leave empty
434 }
435 else if ( eElemClass == uno::TypeClass_BYTE ||
436 eElemClass == uno::TypeClass_SHORT ||
437 eElemClass == uno::TypeClass_UNSIGNED_SHORT ||
438 eElemClass == uno::TypeClass_LONG ||
439 eElemClass == uno::TypeClass_UNSIGNED_LONG ||
440 eElemClass == uno::TypeClass_FLOAT ||
441 eElemClass == uno::TypeClass_DOUBLE )
442 {
443 // #87871# accept integer types because Basic passes a floating point
444 // variable as byte, short or long if it's an integer number.
445 double fVal(0.0);
446 rElement >>= fVal;
447 visitElem( nCol, nRow, fVal );
448 }
449 else if ( eElemClass == uno::TypeClass_STRING )
450 {
451 rtl::OUString aUStr;
452 rElement >>= aUStr;
453 visitElem( nCol, nRow, aUStr );
454 }
455 else
456 mbArgError = true;
457 }
hasArgError()458 bool hasArgError() { return mbArgError; }
459 };
460
461 template< class seq >
462 class SequencesContainer
463 {
464 uno::Sequence< uno::Sequence< seq > > maSeq;
465
466 long& mrDocRow;
467 bool mbOverflow;
468 bool mbArgError;
469 ScDocument* mpDoc;
470 ScTokenArray& mrTokenArr;
471
472 public:
SequencesContainer(const uno::Any & rArg,ScTokenArray & rTokenArr,long & rDocRow,ScDocument * pDoc)473 SequencesContainer( const uno::Any& rArg, ScTokenArray& rTokenArr, long& rDocRow, ScDocument* pDoc ) :
474 mrDocRow( rDocRow ), mbOverflow(false), mbArgError(false), mpDoc( pDoc ), mrTokenArr( rTokenArr )
475 {
476 rArg >>= maSeq;
477 }
478
process()479 void process()
480 {
481 SimpleVisitor aVisitor(mpDoc);
482 long nStartRow = mrDocRow;
483 long nRowCount = maSeq.getLength();
484 long nMaxColCount = 0;
485 const uno::Sequence< seq >* pRowArr = maSeq.getConstArray();
486 for ( long nRow=0; nRow<nRowCount; nRow++ )
487 {
488 long nColCount = pRowArr[nRow].getLength();
489 if ( nColCount > nMaxColCount )
490 nMaxColCount = nColCount;
491 const seq* pColArr = pRowArr[nRow].getConstArray();
492 for (long nCol=0; nCol<nColCount; nCol++)
493 if ( nCol <= MAXCOL && mrDocRow <= MAXROW )
494 aVisitor.visitElem( nCol, mrDocRow, pColArr[ nCol ] );
495 else
496 mbOverflow=true;
497 mrDocRow++;
498 }
499 mbArgError = aVisitor.hasArgError();
500 if ( nRowCount && nMaxColCount && !mbOverflow )
501 lcl_AddRef( mrTokenArr, nStartRow, nMaxColCount, nRowCount );
502 }
getOverflow()503 bool getOverflow() { return mbOverflow; }
getArgError()504 bool getArgError() { return mbArgError; }
505 };
506
507 template <class T>
508 class ArrayOfArrayProc
509 {
510 public:
processSequences(ScDocument * pDoc,const uno::Any & rArg,ScTokenArray & rTokenArr,long & rDocRow,sal_Bool & rArgErr,sal_Bool & rOverflow)511 static void processSequences( ScDocument* pDoc, const uno::Any& rArg, ScTokenArray& rTokenArr,
512 long& rDocRow, sal_Bool& rArgErr, sal_Bool& rOverflow )
513 {
514 SequencesContainer< T > aContainer( rArg, rTokenArr, rDocRow, pDoc );
515 aContainer.process();
516 rArgErr = aContainer.getArgError();
517 rOverflow = aContainer.getOverflow();
518 }
519 };
520
callFunction(const rtl::OUString & aName,const uno::Sequence<uno::Any> & aArguments)521 uno::Any SAL_CALL ScFunctionAccess::callFunction( const rtl::OUString& aName,
522 const uno::Sequence<uno::Any>& aArguments )
523 {
524 ScUnoGuard aGuard;
525
526 if (!mbValid)
527 throw uno::RuntimeException();
528
529 // use cached document if not in use, temporary document otherwise
530 // (deleted in ScTempDocSource dtor)
531 ScTempDocSource aSource( aDocCache );
532 ScDocument* pDoc = aSource.GetDocument();
533 const static SCTAB nTempSheet = 1;
534 // Create an extra tab to contain the Function Cell
535 // this will allow full rows to be used.
536 if ( !pDoc->HasTable( nTempSheet ) )
537 pDoc->MakeTable( nTempSheet );
538
539 /// TODO: check
540 ScAddress aAdr;
541 ScCompiler aCompiler(pDoc,aAdr);
542 aCompiler.SetGrammar(pDoc->GetGrammar());
543 //if (!ScCompiler::IsInitialized())
544 // ScCompiler::InitSymbolsEnglish();
545
546 //
547 // find function
548 //
549
550 ScTokenArray aTokenArr;
551 if ( !lcl_AddFunctionToken( aTokenArr, aName,aCompiler ) )
552 {
553 // function not found
554 throw container::NoSuchElementException();
555 }
556
557 //
558 // set options (null date, etc.)
559 //
560
561 if ( pOptions )
562 pDoc->SetDocOptions( *pOptions );
563
564 //
565 // add arguments to token array
566 //
567
568 sal_Bool bArgErr = sal_False;
569 sal_Bool bOverflow = sal_False;
570 long nDocRow = 0;
571 long nArgCount = aArguments.getLength();
572 const uno::Any* pArgArr = aArguments.getConstArray();
573
574 aTokenArr.AddOpCode(ocOpen);
575 for (long nPos=0; nPos<nArgCount; nPos++)
576 {
577 if ( nPos > 0 )
578 aTokenArr.AddOpCode(ocSep);
579
580 const uno::Any& rArg = pArgArr[nPos];
581
582 uno::TypeClass eClass = rArg.getValueTypeClass();
583 uno::Type aType = rArg.getValueType();
584 if ( eClass == uno::TypeClass_BYTE ||
585 eClass == uno::TypeClass_BOOLEAN ||
586 eClass == uno::TypeClass_SHORT ||
587 eClass == uno::TypeClass_UNSIGNED_SHORT ||
588 eClass == uno::TypeClass_LONG ||
589 eClass == uno::TypeClass_UNSIGNED_LONG ||
590 eClass == uno::TypeClass_FLOAT ||
591 eClass == uno::TypeClass_DOUBLE )
592 {
593 // #87871# accept integer types because Basic passes a floating point
594 // variable as byte, short or long if it's an integer number.
595 double fVal = 0;
596 rArg >>= fVal;
597 aTokenArr.AddDouble( fVal );
598 }
599 else if ( eClass == uno::TypeClass_STRING )
600 {
601 rtl::OUString aUStr;
602 rArg >>= aUStr;
603 String aStr( aUStr );
604 aTokenArr.AddString( aStr.GetBuffer() );
605 }
606 else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<sal_Int16> > *)0 ) ) )
607 {
608 ArrayOfArrayProc<sal_Int16>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
609 }
610 else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<sal_Int32> > *)0 ) ) )
611 {
612 ArrayOfArrayProc<sal_Int32>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
613 }
614 else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<double> > *)0 ) ) )
615 {
616 ArrayOfArrayProc<double>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
617 }
618 else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<rtl::OUString> > *)0 ) ) )
619 {
620 ArrayOfArrayProc<rtl::OUString>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
621 }
622 else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<uno::Any> > *)0 ) ) )
623 {
624 ArrayOfArrayProc<uno::Any>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
625 }
626 else if ( aType.equals( getCppuType( (uno::Reference<table::XCellRange>*)0 ) ) )
627 {
628 // currently, only our own cell ranges are supported
629
630 uno::Reference<table::XCellRange> xRange(rArg, uno::UNO_QUERY);
631 ScCellRangesBase* pImpl = ScCellRangesBase::getImplementation( xRange );
632 if ( pImpl )
633 {
634 ScDocument* pSrcDoc = pImpl->GetDocument();
635 const ScRangeList& rRanges = pImpl->GetRangeList();
636 if ( pSrcDoc && rRanges.Count() == 1 )
637 {
638 ScRange aSrcRange = *rRanges.GetObject(0);
639
640 long nStartRow = nDocRow;
641 long nColCount = aSrcRange.aEnd.Col() - aSrcRange.aStart.Col() + 1;
642 long nRowCount = aSrcRange.aEnd.Row() - aSrcRange.aStart.Row() + 1;
643
644 if ( nStartRow + nRowCount > MAXROWCOUNT )
645 bOverflow = sal_True;
646 else
647 {
648 // copy data
649 if ( !lcl_CopyData( pSrcDoc, aSrcRange, pDoc, ScAddress( 0, (SCROW)nDocRow, 0 ) ) )
650 bOverflow = sal_True;
651 }
652
653 nDocRow += nRowCount;
654 if ( !bOverflow )
655 lcl_AddRef( aTokenArr, nStartRow, nColCount, nRowCount );
656 }
657 else
658 bArgErr = sal_True;
659 }
660 else
661 bArgErr = sal_True;
662 }
663 else
664 bArgErr = sal_True; // invalid type
665 }
666 aTokenArr.AddOpCode(ocClose);
667 aTokenArr.AddOpCode(ocStop);
668
669 //
670 // execute formula
671 //
672
673 uno::Any aRet;
674 if ( !bArgErr && !bOverflow && nDocRow <= MAXROWCOUNT )
675 {
676 ScAddress aFormulaPos( 0, 0, nTempSheet );
677 // GRAM_PODF_A1 doesn't really matter for the token array but fits with
678 // other API compatibility grammars.
679 ScFormulaCell* pFormula = new ScFormulaCell( pDoc, aFormulaPos,
680 &aTokenArr, formula::FormulaGrammar::GRAM_PODF_A1, (sal_uInt8)(mbArray ? MM_FORMULA : MM_NONE) );
681 pDoc->PutCell( aFormulaPos, pFormula ); //! necessary?
682
683 // call GetMatrix before GetErrCode because GetMatrix always recalculates
684 // if there is no matrix result
685
686 const ScMatrix* pMat = mbArray ? pFormula->GetMatrix() : 0;
687 sal_uInt16 nErrCode = pFormula->GetErrCode();
688 if ( nErrCode == 0 )
689 {
690 if ( pMat )
691 {
692 // array result
693 ScRangeToSequence::FillMixedArray( aRet, pMat );
694 }
695 else if ( pFormula->IsValue() )
696 {
697 // numeric value
698 aRet <<= (double) pFormula->GetValue();
699 }
700 else
701 {
702 // string result
703 String aStrVal;
704 pFormula->GetString( aStrVal );
705 aRet <<= rtl::OUString( aStrVal );
706 }
707 }
708 else if ( nErrCode == NOTAVAILABLE )
709 {
710 // #N/A: leave result empty, no exception
711 }
712 else
713 {
714 // any other error: IllegalArgumentException
715 bArgErr = sal_True;
716 }
717
718 pDoc->DeleteAreaTab( 0, 0, MAXCOL, MAXROW, 0, IDF_ALL );
719 pDoc->DeleteAreaTab( 0, 0, 0, 0, nTempSheet, IDF_ALL );
720 }
721
722 if (bOverflow)
723 throw uno::RuntimeException();
724
725 if (bArgErr)
726 throw lang::IllegalArgumentException();
727
728 return aRet;
729 }
730