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