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 89 ScDocument* ScTempDocSource::CreateDocument() 90 { 91 ScDocument* pDoc = new ScDocument; // SCDOCMODE_DOCUMENT 92 pDoc->MakeTable( 0 ); 93 return pDoc; 94 } 95 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 110 ScTempDocSource::~ScTempDocSource() 111 { 112 if ( pTempDoc ) 113 delete pTempDoc; 114 else 115 rCache.SetInUse( sal_False ); 116 } 117 118 ScDocument* ScTempDocSource::GetDocument() 119 { 120 if ( pTempDoc ) 121 return pTempDoc; 122 else 123 return rCache.GetDocument(); 124 } 125 126 //------------------------------------------------------------------------ 127 128 ScTempDocCache::ScTempDocCache() : 129 pDoc( NULL ), 130 bInUse( sal_False ) 131 { 132 } 133 134 ScTempDocCache::~ScTempDocCache() 135 { 136 DBG_ASSERT( !bInUse, "ScTempDocCache dtor: bInUse" ); 137 delete pDoc; 138 } 139 140 void ScTempDocCache::SetDocument( ScDocument* pNew ) 141 { 142 DBG_ASSERT( !pDoc, "ScTempDocCache::SetDocument: already set" ); 143 pDoc = pNew; 144 } 145 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 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 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 232 ScFunctionAccess::~ScFunctionAccess() 233 { 234 delete pOptions; 235 } 236 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 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 259 rtl::OUString ScFunctionAccess::getImplementationName_Static() 260 { 261 return rtl::OUString::createFromAscii( "stardiv.StarCalc.ScFunctionAccess" ); 262 } 263 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 274 rtl::OUString SAL_CALL ScFunctionAccess::getImplementationName() throw(uno::RuntimeException) 275 { 276 return rtl::OUString::createFromAscii( "ScFunctionAccess" ); 277 } 278 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 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 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 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 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 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 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: 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 418 void visitElem( long nCol, long nRow, const sal_Int16& elem ) 419 { 420 mpDoc->SetValue( (SCCOL) nCol, (SCROW) nRow, 0, elem ); 421 } 422 void visitElem( long nCol, long nRow, const sal_Int32& elem ) 423 { 424 mpDoc->SetValue( (SCCOL) nCol, (SCROW) nRow, 0, elem ); 425 } 426 void visitElem( long nCol, long nRow, const double& elem ) 427 { 428 mpDoc->SetValue( (SCCOL) nCol, (SCROW) nRow, 0, elem ); 429 } 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 } 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 } 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: 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 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 } 511 bool getOverflow() { return mbOverflow; } 512 bool getArgError() { return mbArgError; } 513 }; 514 515 template <class T> 516 class ArrayOfArrayProc 517 { 518 public: 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 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