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 <comphelper/processfactory.hxx> 34 #include <tools/debug.hxx> 35 #include <i18npool/mslangid.hxx> 36 #include <vcl/svapp.hxx> 37 #include <vos/xception.hxx> 38 #include <sfx2/objsh.hxx> 39 #include <unotools/charclass.hxx> 40 41 #include <com/sun/star/container/XContentEnumerationAccess.hpp> 42 #include <com/sun/star/lang/XServiceName.hpp> 43 #include <com/sun/star/lang/XSingleServiceFactory.hpp> 44 #include <com/sun/star/lang/XSingleComponentFactory.hpp> 45 #include <com/sun/star/reflection/XIdlClass.hpp> 46 #include <com/sun/star/reflection/XIdlClassProvider.hpp> 47 #include <com/sun/star/beans/XIntrospectionAccess.hpp> 48 #include <com/sun/star/beans/XIntrospection.hpp> 49 #include <com/sun/star/beans/MethodConcept.hpp> 50 #include <com/sun/star/beans/XPropertySet.hpp> 51 #include <com/sun/star/table/XCellRange.hpp> 52 #include <com/sun/star/lang/Locale.hpp> 53 #include <com/sun/star/sheet/XCompatibilityNames.hpp> 54 #include <com/sun/star/sheet/NoConvergenceException.hpp> 55 56 #include "addincol.hxx" 57 #include "addinhelpid.hxx" 58 #include "compiler.hxx" 59 #include "scmatrix.hxx" 60 #include "addinlis.hxx" 61 #include "formula/errorcodes.hxx" 62 #include "scfuncs.hrc" 63 #include "optutil.hxx" 64 #include "addincfg.hxx" 65 #include "scmod.hxx" 66 #include "rangeseq.hxx" 67 #include "funcdesc.hxx" 68 69 using namespace com::sun::star; 70 71 //------------------------------------------------------------------------ 72 73 #define SC_CALLERPOS_NONE (-1) 74 75 #define SCADDINSUPPLIER_SERVICE "com.sun.star.sheet.AddIn" 76 77 //------------------------------------------------------------------------ 78 79 80 81 82 //------------------------------------------------------------------------ 83 84 ScUnoAddInFuncData::ScUnoAddInFuncData( const String& rNam, const String& rLoc, 85 const String& rDesc, 86 sal_uInt16 nCat, const rtl::OString& sHelp, 87 const uno::Reference<reflection::XIdlMethod>& rFunc, 88 const uno::Any& rO, 89 long nAC, const ScAddInArgDesc* pAD, 90 long nCP ) : 91 aOriginalName( rNam ), 92 aLocalName( rLoc ), 93 aUpperName( rNam ), 94 aUpperLocal( rLoc ), 95 aDescription( rDesc ), 96 xFunction( rFunc ), 97 aObject( rO ), 98 nArgCount( nAC ), 99 nCallerPos( nCP ), 100 nCategory( nCat ), 101 sHelpId( sHelp ), 102 bCompInitialized( sal_False ) 103 { 104 if ( nArgCount ) 105 { 106 pArgDescs = new ScAddInArgDesc[nArgCount]; 107 for (long i=0; i<nArgCount; i++) 108 pArgDescs[i] = pAD[i]; 109 } 110 else 111 pArgDescs = NULL; 112 113 ScGlobal::pCharClass->toUpper(aUpperName); 114 ScGlobal::pCharClass->toUpper(aUpperLocal); 115 } 116 117 ScUnoAddInFuncData::~ScUnoAddInFuncData() 118 { 119 delete[] pArgDescs; 120 } 121 122 const uno::Sequence<sheet::LocalizedName>& ScUnoAddInFuncData::GetCompNames() const 123 { 124 if ( !bCompInitialized ) 125 { 126 // read sequence of compatibility names on demand 127 128 uno::Reference<sheet::XAddIn> xAddIn; 129 if ( aObject >>= xAddIn ) 130 { 131 uno::Reference<sheet::XCompatibilityNames> xComp( xAddIn, uno::UNO_QUERY ); 132 if ( xComp.is() && xFunction.is() ) 133 { 134 rtl::OUString aMethodName = xFunction->getName(); 135 aCompNames = xComp->getCompatibilityNames( aMethodName ); 136 137 // change all locale entries to default case 138 // (language in lower case, country in upper case) 139 // for easier searching 140 141 long nSeqLen = aCompNames.getLength(); 142 if ( nSeqLen ) 143 { 144 sheet::LocalizedName* pArray = aCompNames.getArray(); 145 for (long i=0; i<nSeqLen; i++) 146 { 147 lang::Locale& rLocale = pArray[i].Locale; 148 rLocale.Language = rLocale.Language.toAsciiLowerCase(); 149 rLocale.Country = rLocale.Country.toAsciiUpperCase(); 150 } 151 } 152 } 153 } 154 155 bCompInitialized = sal_True; // also if not successful 156 } 157 return aCompNames; 158 } 159 160 void ScUnoAddInFuncData::SetCompNames( const uno::Sequence< sheet::LocalizedName>& rNew ) 161 { 162 DBG_ASSERT( !bCompInitialized, "SetCompNames after initializing" ); 163 164 aCompNames = rNew; 165 166 // change all locale entries to default case 167 // (language in lower case, country in upper case) 168 // for easier searching 169 170 long nSeqLen = aCompNames.getLength(); 171 if ( nSeqLen ) 172 { 173 sheet::LocalizedName* pArray = aCompNames.getArray(); 174 for (long i=0; i<nSeqLen; i++) 175 { 176 lang::Locale& rLocale = pArray[i].Locale; 177 rLocale.Language = rLocale.Language.toAsciiLowerCase(); 178 rLocale.Country = rLocale.Country.toAsciiUpperCase(); 179 } 180 } 181 182 bCompInitialized = sal_True; 183 } 184 185 sal_Bool ScUnoAddInFuncData::GetExcelName( LanguageType eDestLang, String& rRetExcelName ) const 186 { 187 const uno::Sequence<sheet::LocalizedName>& rSequence = GetCompNames(); 188 long nSeqLen = rSequence.getLength(); 189 if ( nSeqLen ) 190 { 191 const sheet::LocalizedName* pArray = rSequence.getConstArray(); 192 long i; 193 194 rtl::OUString aLangStr, aCountryStr; 195 MsLangId::convertLanguageToIsoNames( eDestLang, aLangStr, aCountryStr ); 196 rtl::OUString aUserLang = aLangStr.toAsciiLowerCase(); 197 rtl::OUString aUserCountry = aCountryStr.toAsciiUpperCase(); 198 199 // first check for match of both language and country 200 201 for ( i=0; i<nSeqLen; i++) 202 if ( pArray[i].Locale.Language == aUserLang && 203 pArray[i].Locale.Country == aUserCountry ) 204 { 205 rRetExcelName = pArray[i].Name; 206 return sal_True; 207 } 208 209 // second: check only language 210 211 for ( i=0; i<nSeqLen; i++) 212 if ( pArray[i].Locale.Language == aUserLang ) 213 { 214 rRetExcelName = pArray[i].Name; 215 return sal_True; 216 } 217 218 // third: #i57772# fall-back to en-US 219 220 if ( eDestLang != LANGUAGE_ENGLISH_US ) 221 return GetExcelName( LANGUAGE_ENGLISH_US, rRetExcelName ); 222 223 // forth: use first (default) entry 224 225 rRetExcelName = pArray[0].Name; 226 return sal_True; 227 } 228 return sal_False; 229 } 230 231 void ScUnoAddInFuncData::SetFunction( const uno::Reference< reflection::XIdlMethod>& rNewFunc, const uno::Any& rNewObj ) 232 { 233 xFunction = rNewFunc; 234 aObject = rNewObj; 235 } 236 237 void ScUnoAddInFuncData::SetArguments( long nNewCount, const ScAddInArgDesc* pNewDescs ) 238 { 239 delete[] pArgDescs; 240 241 nArgCount = nNewCount; 242 if ( nArgCount ) 243 { 244 pArgDescs = new ScAddInArgDesc[nArgCount]; 245 for (long i=0; i<nArgCount; i++) 246 pArgDescs[i] = pNewDescs[i]; 247 } 248 else 249 pArgDescs = NULL; 250 } 251 252 void ScUnoAddInFuncData::SetCallerPos( long nNewPos ) 253 { 254 nCallerPos = nNewPos; 255 } 256 257 //------------------------------------------------------------------------ 258 259 ScUnoAddInCollection::ScUnoAddInCollection() : 260 nFuncCount( 0 ), 261 ppFuncData( NULL ), 262 pExactHashMap( NULL ), 263 pNameHashMap( NULL ), 264 pLocalHashMap( NULL ), 265 bInitialized( sal_False ) 266 { 267 } 268 269 ScUnoAddInCollection::~ScUnoAddInCollection() 270 { 271 Clear(); 272 } 273 274 void ScUnoAddInCollection::Clear() 275 { 276 DELETEZ( pExactHashMap ); 277 DELETEZ( pNameHashMap ); 278 DELETEZ( pLocalHashMap ); 279 if ( ppFuncData ) 280 { 281 for ( long i=0; i<nFuncCount; i++ ) 282 delete ppFuncData[i]; 283 delete[] ppFuncData; 284 } 285 ppFuncData = NULL; 286 nFuncCount = 0; 287 288 bInitialized = sal_False; 289 } 290 291 uno::Reference<uno::XComponentContext> getContext(uno::Reference<lang::XMultiServiceFactory> xMSF) 292 { 293 uno::Reference<uno::XComponentContext> xCtx; 294 try { 295 uno::Reference<beans::XPropertySet> xPropset(xMSF, uno::UNO_QUERY); 296 xPropset->getPropertyValue( 297 ::rtl::OUString::createFromAscii("DefaultContext")) >>= xCtx; 298 } 299 catch ( uno::Exception & ) { 300 } 301 return xCtx; 302 } 303 304 void ScUnoAddInCollection::Initialize() 305 { 306 DBG_ASSERT( !bInitialized, "Initialize twice?" ); 307 308 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory(); 309 uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY ); 310 if ( xEnAc.is() ) 311 { 312 uno::Reference<container::XEnumeration> xEnum = 313 xEnAc->createContentEnumeration( 314 rtl::OUString::createFromAscii(SCADDINSUPPLIER_SERVICE) ); 315 if ( xEnum.is() ) 316 { 317 // loop through all AddIns 318 while ( xEnum->hasMoreElements() ) 319 { 320 uno::Any aAddInAny = xEnum->nextElement(); 321 //? if ( aAddInAny.getReflection()->getTypeClass() == uno::TypeClass_INTERFACE ) 322 { 323 uno::Reference<uno::XInterface> xIntFac; 324 aAddInAny >>= xIntFac; 325 if ( xIntFac.is() ) 326 { 327 // #i59984# try XSingleComponentFactory in addition to (old) XSingleServiceFactory, 328 // passing the context to the component 329 330 uno::Reference<uno::XInterface> xInterface; 331 uno::Reference<uno::XComponentContext> xCtx = getContext(xManager); 332 uno::Reference<lang::XSingleComponentFactory> xCFac( xIntFac, uno::UNO_QUERY ); 333 if (xCtx.is() && xCFac.is()) 334 { 335 xInterface = xCFac->createInstanceWithContext(xCtx); 336 if (xInterface.is()) 337 ReadFromAddIn( xInterface ); 338 } 339 340 if (!xInterface.is()) 341 { 342 uno::Reference<lang::XSingleServiceFactory> xFac( xIntFac, uno::UNO_QUERY ); 343 if ( xFac.is() ) 344 { 345 xInterface = xFac->createInstance(); 346 if (xInterface.is()) 347 ReadFromAddIn( xInterface ); 348 } 349 } 350 } 351 } 352 } 353 } 354 } 355 356 // ReadConfiguration is called after looking at the AddIn implementations. 357 // Duplicated are skipped (by using the service information, they don't have to be updated again 358 // when argument information is needed). 359 ReadConfiguration(); 360 361 bInitialized = sal_True; // with or without functions 362 } 363 // ----------------------------------------------------------------------------- 364 365 sal_uInt16 lcl_GetCategory( const String& rName ) 366 { 367 static const sal_Char* aFuncNames[SC_FUNCGROUP_COUNT] = 368 { 369 // array index = ID - 1 (ID starts at 1) 370 // all upper case 371 "Database", // ID_FUNCTION_GRP_DATABASE 372 "Date&Time", // ID_FUNCTION_GRP_DATETIME 373 "Financial", // ID_FUNCTION_GRP_FINANZ 374 "Information", // ID_FUNCTION_GRP_INFO 375 "Logical", // ID_FUNCTION_GRP_LOGIC 376 "Mathematical", // ID_FUNCTION_GRP_MATH 377 "Matrix", // ID_FUNCTION_GRP_MATRIX 378 "Statistical", // ID_FUNCTION_GRP_STATISTIC 379 "Spreadsheet", // ID_FUNCTION_GRP_TABLE 380 "Text", // ID_FUNCTION_GRP_TEXT 381 "Add-In" // ID_FUNCTION_GRP_ADDINS 382 }; 383 for (sal_uInt16 i=0; i<SC_FUNCGROUP_COUNT; i++) 384 if ( rName.EqualsAscii( aFuncNames[i] ) ) 385 return i+1; // IDs start at 1 386 387 return ID_FUNCTION_GRP_ADDINS; // if not found, use Add-In group 388 } 389 390 391 #define CFGPATH_ADDINS "Office.CalcAddIns/AddInInfo" 392 #define CFGSTR_ADDINFUNCTIONS "AddInFunctions" 393 394 #define CFG_FUNCPROP_DISPLAYNAME 0 395 #define CFG_FUNCPROP_DESCRIPTION 1 396 #define CFG_FUNCPROP_CATEGORY 2 397 #define CFG_FUNCPROP_COUNT 3 398 #define CFGSTR_DISPLAYNAME "DisplayName" 399 #define CFGSTR_DESCRIPTION "Description" 400 #define CFGSTR_CATEGORY "Category" 401 // CategoryDisplayName is ignored for now 402 403 #define CFGSTR_COMPATIBILITYNAME "CompatibilityName" 404 #define CFGSTR_PARAMETERS "Parameters" 405 406 407 void ScUnoAddInCollection::ReadConfiguration() 408 { 409 // called only from Initialize 410 411 ScAddInCfg& rAddInConfig = SC_MOD()->GetAddInCfg(); 412 413 // additional, temporary config item for the compatibility names 414 ScLinkConfigItem aAllLocalesConfig( rtl::OUString::createFromAscii( CFGPATH_ADDINS ), CONFIG_MODE_ALL_LOCALES ); 415 // CommitLink is not used (only reading values) 416 417 const rtl::OUString sSlash('/'); 418 419 // get the list of add-ins (services) 420 rtl::OUString aEmptyString; 421 uno::Sequence<rtl::OUString> aServiceNames = rAddInConfig.GetNodeNames( aEmptyString ); 422 423 sal_Int32 nServiceCount = aServiceNames.getLength(); 424 for ( sal_Int32 nService = 0; nService < nServiceCount; nService++ ) 425 { 426 rtl::OUString aServiceName = aServiceNames[nService]; 427 ScUnoAddInHelpIdGenerator aHelpIdGenerator( aServiceName ); 428 429 rtl::OUString aFunctionsPath = aServiceName; 430 aFunctionsPath += sSlash; 431 aFunctionsPath += rtl::OUString::createFromAscii( CFGSTR_ADDINFUNCTIONS ); 432 433 uno::Sequence<rtl::OUString> aFunctionNames = rAddInConfig.GetNodeNames( aFunctionsPath ); 434 sal_Int32 nNewCount = aFunctionNames.getLength(); 435 436 // allocate pointers 437 438 long nOld = nFuncCount; 439 nFuncCount = nNewCount+nOld; 440 if ( nOld ) 441 { 442 ScUnoAddInFuncData** ppNew = new ScUnoAddInFuncData*[nFuncCount]; 443 for (long i=0; i<nOld; i++) 444 ppNew[i] = ppFuncData[i]; 445 delete[] ppFuncData; 446 ppFuncData = ppNew; 447 } 448 else 449 ppFuncData = new ScUnoAddInFuncData*[nFuncCount]; 450 451 //! TODO: adjust bucket count? 452 if ( !pExactHashMap ) 453 pExactHashMap = new ScAddInHashMap; 454 if ( !pNameHashMap ) 455 pNameHashMap = new ScAddInHashMap; 456 if ( !pLocalHashMap ) 457 pLocalHashMap = new ScAddInHashMap; 458 459 //! get the function information in a single call for all functions? 460 461 const rtl::OUString* pFuncNameArray = aFunctionNames.getConstArray(); 462 for ( sal_Int32 nFuncPos = 0; nFuncPos < nNewCount; nFuncPos++ ) 463 { 464 ppFuncData[nFuncPos+nOld] = NULL; 465 466 // stored function name: (service name).(function) 467 String aFuncName( aServiceName ); 468 aFuncName += '.'; 469 aFuncName += String( pFuncNameArray[nFuncPos] ); 470 471 // skip the function if already known (read from old AddIn service) 472 473 if ( pExactHashMap->find( aFuncName ) == pExactHashMap->end() ) 474 { 475 rtl::OUString aLocalName; 476 rtl::OUString aDescription; 477 sal_uInt16 nCategory = ID_FUNCTION_GRP_ADDINS; 478 479 // get direct information on the function 480 481 rtl::OUString aFuncPropPath = aFunctionsPath; 482 aFuncPropPath += sSlash; 483 aFuncPropPath += pFuncNameArray[nFuncPos]; 484 aFuncPropPath += sSlash; 485 486 uno::Sequence<rtl::OUString> aFuncPropNames(CFG_FUNCPROP_COUNT); 487 rtl::OUString* pNameArray = aFuncPropNames.getArray(); 488 pNameArray[CFG_FUNCPROP_DISPLAYNAME] = aFuncPropPath; 489 pNameArray[CFG_FUNCPROP_DISPLAYNAME] += rtl::OUString::createFromAscii( CFGSTR_DISPLAYNAME ); 490 pNameArray[CFG_FUNCPROP_DESCRIPTION] = aFuncPropPath; 491 pNameArray[CFG_FUNCPROP_DESCRIPTION] += rtl::OUString::createFromAscii( CFGSTR_DESCRIPTION ); 492 pNameArray[CFG_FUNCPROP_CATEGORY] = aFuncPropPath; 493 pNameArray[CFG_FUNCPROP_CATEGORY] += rtl::OUString::createFromAscii( CFGSTR_CATEGORY ); 494 495 uno::Sequence<uno::Any> aFuncProperties = rAddInConfig.GetProperties( aFuncPropNames ); 496 if ( aFuncProperties.getLength() == CFG_FUNCPROP_COUNT ) 497 { 498 aFuncProperties[CFG_FUNCPROP_DISPLAYNAME] >>= aLocalName; 499 aFuncProperties[CFG_FUNCPROP_DESCRIPTION] >>= aDescription; 500 501 rtl::OUString aCategoryName; 502 aFuncProperties[CFG_FUNCPROP_CATEGORY] >>= aCategoryName; 503 nCategory = lcl_GetCategory( aCategoryName ); 504 } 505 506 // get compatibility names 507 508 uno::Sequence<sheet::LocalizedName> aCompNames; 509 510 rtl::OUString aCompPath = aFuncPropPath; 511 aCompPath += rtl::OUString::createFromAscii( CFGSTR_COMPATIBILITYNAME ); 512 uno::Sequence<rtl::OUString> aCompPropNames( &aCompPath, 1 ); 513 514 uno::Sequence<uno::Any> aCompProperties = aAllLocalesConfig.GetProperties( aCompPropNames ); 515 if ( aCompProperties.getLength() == 1 ) 516 { 517 uno::Sequence<beans::PropertyValue> aLocalEntries; 518 if ( aCompProperties[0] >>= aLocalEntries ) 519 { 520 sal_Int32 nLocaleCount = aLocalEntries.getLength(); 521 aCompNames.realloc( nLocaleCount ); 522 const beans::PropertyValue* pConfigArray = aLocalEntries.getConstArray(); 523 sheet::LocalizedName* pCompArray = aCompNames.getArray(); 524 525 for ( sal_Int32 nLocale = 0; nLocale < nLocaleCount; nLocale++ ) 526 { 527 const sal_Unicode cLocaleSep = '-'; // separator in configuration locale strings 528 529 // PropertyValue name is the locale (convert from string to Locale struct) 530 531 const rtl::OUString& rLocaleStr = pConfigArray[nLocale].Name; 532 lang::Locale& rLocale = pCompArray[nLocale].Locale; 533 sal_Int32 nSepPos = rLocaleStr.indexOf( cLocaleSep ); 534 if ( nSepPos >= 0 ) 535 { 536 rLocale.Language = rLocaleStr.copy( 0, nSepPos ); 537 rLocale.Country = rLocaleStr.copy( nSepPos+1 ); 538 } 539 else 540 rLocale.Language = rLocaleStr; // leave country empty (default ctor from sequence) 541 542 // PropertyValue value is the localized value (string in this case) 543 544 pConfigArray[nLocale].Value >>= pCompArray[nLocale].Name; 545 } 546 } 547 } 548 549 // get argument info 550 551 ScAddInArgDesc* pVisibleArgs = NULL; 552 long nVisibleCount = 0; 553 long nCallerPos = SC_CALLERPOS_NONE; 554 555 rtl::OUString aArgumentsPath = aFuncPropPath; 556 aArgumentsPath += rtl::OUString::createFromAscii( CFGSTR_PARAMETERS ); 557 558 uno::Sequence<rtl::OUString> aArgumentNames = rAddInConfig.GetNodeNames( aArgumentsPath ); 559 sal_Int32 nArgumentCount = aArgumentNames.getLength(); 560 if ( nArgumentCount ) 561 { 562 // get DisplayName and Description for each argument 563 uno::Sequence<rtl::OUString> aArgPropNames( nArgumentCount * 2 ); 564 rtl::OUString* pPropNameArray = aArgPropNames.getArray(); 565 566 sal_Int32 nArgument; 567 sal_Int32 nIndex = 0; 568 const rtl::OUString* pArgNameArray = aArgumentNames.getConstArray(); 569 for ( nArgument = 0; nArgument < nArgumentCount; nArgument++ ) 570 { 571 rtl::OUString aOneArgPath = aArgumentsPath; 572 aOneArgPath += sSlash; 573 aOneArgPath += pArgNameArray[nArgument]; 574 aOneArgPath += sSlash; 575 576 pPropNameArray[nIndex] = aOneArgPath; 577 pPropNameArray[nIndex++] += rtl::OUString::createFromAscii( CFGSTR_DISPLAYNAME ); 578 pPropNameArray[nIndex] = aOneArgPath; 579 pPropNameArray[nIndex++] += rtl::OUString::createFromAscii( CFGSTR_DESCRIPTION ); 580 } 581 582 uno::Sequence<uno::Any> aArgProperties = rAddInConfig.GetProperties( aArgPropNames ); 583 if ( aArgProperties.getLength() == aArgPropNames.getLength() ) 584 { 585 const uno::Any* pPropArray = aArgProperties.getConstArray(); 586 rtl::OUString sDisplayName; 587 rtl::OUString sDescription; 588 589 ScAddInArgDesc aDesc; 590 aDesc.eType = SC_ADDINARG_NONE; // arg type is not in configuration 591 aDesc.bOptional = sal_False; 592 593 nVisibleCount = nArgumentCount; 594 pVisibleArgs = new ScAddInArgDesc[nVisibleCount]; 595 596 nIndex = 0; 597 for ( nArgument = 0; nArgument < nArgumentCount; nArgument++ ) 598 { 599 pPropArray[nIndex++] >>= sDisplayName; 600 pPropArray[nIndex++] >>= sDescription; 601 602 aDesc.aInternalName = pArgNameArray[nArgument]; 603 aDesc.aName = sDisplayName; 604 aDesc.aDescription = sDescription; 605 606 pVisibleArgs[nArgument] = aDesc; 607 } 608 } 609 } 610 611 rtl::OString sHelpId = aHelpIdGenerator.GetHelpId( pFuncNameArray[nFuncPos] ); 612 613 uno::Reference<reflection::XIdlMethod> xFunc; // remains empty 614 uno::Any aObject; // also empty 615 616 // create and insert into the array 617 618 ScUnoAddInFuncData* pData = new ScUnoAddInFuncData( 619 aFuncName, aLocalName, aDescription, 620 nCategory, sHelpId, 621 xFunc, aObject, 622 nVisibleCount, pVisibleArgs, nCallerPos ); 623 624 pData->SetCompNames( aCompNames ); 625 626 ppFuncData[nFuncPos+nOld] = pData; 627 628 pExactHashMap->insert( 629 ScAddInHashMap::value_type( 630 pData->GetOriginalName(), 631 pData ) ); 632 pNameHashMap->insert( 633 ScAddInHashMap::value_type( 634 pData->GetUpperName(), 635 pData ) ); 636 pLocalHashMap->insert( 637 ScAddInHashMap::value_type( 638 pData->GetUpperLocal(), 639 pData ) ); 640 641 delete[] pVisibleArgs; 642 } 643 } 644 } 645 } 646 647 void ScUnoAddInCollection::LoadComponent( const ScUnoAddInFuncData& rFuncData ) 648 { 649 String aFullName = rFuncData.GetOriginalName(); 650 xub_StrLen nPos = aFullName.SearchBackward( (sal_Unicode) '.' ); 651 if ( nPos != STRING_NOTFOUND && nPos > 0 ) 652 { 653 String aServiceName = aFullName.Copy( 0, nPos ); 654 655 uno::Reference<lang::XMultiServiceFactory> xServiceFactory = comphelper::getProcessServiceFactory(); 656 uno::Reference<uno::XInterface> xInterface( xServiceFactory->createInstance( aServiceName ) ); 657 658 if (xInterface.is()) 659 UpdateFromAddIn( xInterface, aServiceName ); 660 } 661 } 662 663 sal_Bool ScUnoAddInCollection::GetExcelName( const String& rCalcName, 664 LanguageType eDestLang, String& rRetExcelName ) 665 { 666 const ScUnoAddInFuncData* pFuncData = GetFuncData( rCalcName ); 667 if ( pFuncData ) 668 return pFuncData->GetExcelName( eDestLang, rRetExcelName); 669 return sal_False; 670 } 671 672 sal_Bool ScUnoAddInCollection::GetCalcName( const String& rExcelName, String& rRetCalcName ) 673 { 674 if (!bInitialized) 675 Initialize(); 676 677 String aUpperCmp = rExcelName; 678 ScGlobal::pCharClass->toUpper(aUpperCmp); 679 680 for (long i=0; i<nFuncCount; i++) 681 { 682 ScUnoAddInFuncData* pFuncData = ppFuncData[i]; 683 if ( pFuncData ) 684 { 685 const uno::Sequence<sheet::LocalizedName>& rSequence = pFuncData->GetCompNames(); 686 long nSeqLen = rSequence.getLength(); 687 if ( nSeqLen ) 688 { 689 const sheet::LocalizedName* pArray = rSequence.getConstArray(); 690 for ( long nName=0; nName<nSeqLen; nName++) 691 if ( ScGlobal::pCharClass->upper( pArray[nName].Name ) == aUpperCmp ) 692 { 693 //! store upper case for comparing? 694 695 // use the first function that has this name for any language 696 rRetCalcName = pFuncData->GetOriginalName(); 697 return sal_True; 698 } 699 } 700 } 701 } 702 return sal_False; 703 } 704 705 inline sal_Bool IsTypeName( const rtl::OUString& rName, const uno::Type& rType ) 706 { 707 return rName == rType.getTypeName(); 708 } 709 710 sal_Bool lcl_ValidReturnType( const uno::Reference<reflection::XIdlClass>& xClass ) 711 { 712 // this must match with ScUnoAddInCall::SetResult 713 714 if ( !xClass.is() ) return sal_False; 715 716 switch (xClass->getTypeClass()) 717 { 718 // case uno::TypeClass_VOID: 719 // ??? 720 721 case uno::TypeClass_ANY: // variable type 722 case uno::TypeClass_ENUM: //! ??? 723 case uno::TypeClass_BOOLEAN: 724 case uno::TypeClass_CHAR: 725 case uno::TypeClass_BYTE: 726 case uno::TypeClass_SHORT: 727 case uno::TypeClass_UNSIGNED_SHORT: 728 case uno::TypeClass_LONG: 729 case uno::TypeClass_UNSIGNED_LONG: 730 case uno::TypeClass_FLOAT: 731 case uno::TypeClass_DOUBLE: 732 case uno::TypeClass_STRING: 733 return sal_True; // values or string 734 735 case uno::TypeClass_INTERFACE: 736 { 737 // return type XInterface may contain a XVolatileResult 738 //! XIdlClass needs getType() method! 739 740 rtl::OUString sName = xClass->getName(); 741 return ( 742 IsTypeName( sName, getCppuType((uno::Reference<sheet::XVolatileResult>*)0) ) || 743 IsTypeName( sName, getCppuType((uno::Reference<uno::XInterface>*)0) ) ); 744 } 745 746 default: 747 { 748 // nested sequences for arrays 749 //! XIdlClass needs getType() method! 750 751 rtl::OUString sName = xClass->getName(); 752 return ( 753 IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<sal_Int32> >*)0) ) || 754 IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<double> >*)0) ) || 755 IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<rtl::OUString> >*)0) ) || 756 IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<uno::Any> >*)0) ) ); 757 } 758 } 759 return sal_False; 760 } 761 762 ScAddInArgumentType lcl_GetArgType( const uno::Reference<reflection::XIdlClass>& xClass ) 763 { 764 if (!xClass.is()) 765 return SC_ADDINARG_NONE; 766 767 uno::TypeClass eType = xClass->getTypeClass(); 768 769 if ( eType == uno::TypeClass_LONG ) //! other integer types? 770 return SC_ADDINARG_INTEGER; 771 772 if ( eType == uno::TypeClass_DOUBLE ) 773 return SC_ADDINARG_DOUBLE; 774 775 if ( eType == uno::TypeClass_STRING ) 776 return SC_ADDINARG_STRING; 777 778 //! XIdlClass needs getType() method! 779 rtl::OUString sName = xClass->getName(); 780 781 if (IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<sal_Int32> >*)0) )) 782 return SC_ADDINARG_INTEGER_ARRAY; 783 784 if (IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<double> >*)0) )) 785 return SC_ADDINARG_DOUBLE_ARRAY; 786 787 if (IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<rtl::OUString> >*)0) )) 788 return SC_ADDINARG_STRING_ARRAY; 789 790 if (IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<uno::Any> >*)0) )) 791 return SC_ADDINARG_MIXED_ARRAY; 792 793 if (IsTypeName( sName, getCppuType((uno::Any*)0) )) 794 return SC_ADDINARG_VALUE_OR_ARRAY; 795 796 if (IsTypeName( sName, getCppuType((uno::Reference<table::XCellRange>*)0) )) 797 return SC_ADDINARG_CELLRANGE; 798 799 if (IsTypeName( sName, getCppuType((uno::Reference<beans::XPropertySet>*)0) )) 800 return SC_ADDINARG_CALLER; 801 802 if (IsTypeName( sName, getCppuType((uno::Sequence<uno::Any>*)0) )) 803 return SC_ADDINARG_VARARGS; 804 805 return SC_ADDINARG_NONE; 806 } 807 808 void ScUnoAddInCollection::ReadFromAddIn( const uno::Reference<uno::XInterface>& xInterface ) 809 { 810 uno::Reference<sheet::XAddIn> xAddIn( xInterface, uno::UNO_QUERY ); 811 uno::Reference<lang::XServiceName> xName( xInterface, uno::UNO_QUERY ); 812 if ( xAddIn.is() && xName.is() ) 813 { 814 // AddIns must use the language for which the office is installed 815 LanguageType eOfficeLang = Application::GetSettings().GetUILanguage(); 816 817 lang::Locale aLocale( MsLangId::convertLanguageToLocale( eOfficeLang )); 818 xAddIn->setLocale( aLocale ); 819 820 String aServiceName = String( xName->getServiceName() ); 821 ScUnoAddInHelpIdGenerator aHelpIdGenerator( xName->getServiceName() ); 822 823 //! pass XIntrospection to ReadFromAddIn 824 825 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory(); 826 if ( xManager.is() ) 827 { 828 uno::Reference<beans::XIntrospection> xIntro( 829 xManager->createInstance(rtl::OUString::createFromAscii( 830 "com.sun.star.beans.Introspection" )), 831 uno::UNO_QUERY ); 832 if ( xIntro.is() ) 833 { 834 uno::Any aObject; 835 aObject <<= xAddIn; 836 uno::Reference<beans::XIntrospectionAccess> xAcc = xIntro->inspect(aObject); 837 if (xAcc.is()) 838 { 839 uno::Sequence< uno::Reference<reflection::XIdlMethod> > aMethods = 840 xAcc->getMethods( beans::MethodConcept::ALL ); 841 long nNewCount = aMethods.getLength(); 842 if ( nNewCount ) 843 { 844 long nOld = nFuncCount; 845 nFuncCount = nNewCount+nOld; 846 if ( nOld ) 847 { 848 ScUnoAddInFuncData** ppNew = new ScUnoAddInFuncData*[nFuncCount]; 849 for (long i=0; i<nOld; i++) 850 ppNew[i] = ppFuncData[i]; 851 delete[] ppFuncData; 852 ppFuncData = ppNew; 853 } 854 else 855 ppFuncData = new ScUnoAddInFuncData*[nFuncCount]; 856 857 //! TODO: adjust bucket count? 858 if ( !pExactHashMap ) 859 pExactHashMap = new ScAddInHashMap; 860 if ( !pNameHashMap ) 861 pNameHashMap = new ScAddInHashMap; 862 if ( !pLocalHashMap ) 863 pLocalHashMap = new ScAddInHashMap; 864 865 const uno::Reference<reflection::XIdlMethod>* pArray = aMethods.getConstArray(); 866 for (long nFuncPos=0; nFuncPos<nNewCount; nFuncPos++) 867 { 868 ppFuncData[nFuncPos+nOld] = NULL; 869 870 uno::Reference<reflection::XIdlMethod> xFunc = pArray[nFuncPos]; 871 if (xFunc.is()) 872 { 873 // leave out internal functions 874 uno::Reference<reflection::XIdlClass> xClass = 875 xFunc->getDeclaringClass(); 876 sal_Bool bSkip = sal_True; 877 if ( xClass.is() ) 878 { 879 //! XIdlClass needs getType() method! 880 rtl::OUString sName = xClass->getName(); 881 bSkip = ( 882 IsTypeName( sName, 883 getCppuType((uno::Reference<uno::XInterface>*)0) ) || 884 IsTypeName( sName, 885 getCppuType((uno::Reference<reflection::XIdlClassProvider>*)0) ) || 886 IsTypeName( sName, 887 getCppuType((uno::Reference<lang::XServiceName>*)0) ) || 888 IsTypeName( sName, 889 getCppuType((uno::Reference<lang::XServiceInfo>*)0) ) || 890 IsTypeName( sName, 891 getCppuType((uno::Reference<sheet::XAddIn>*)0) ) ); 892 } 893 if (!bSkip) 894 { 895 uno::Reference<reflection::XIdlClass> xReturn = 896 xFunc->getReturnType(); 897 if ( !lcl_ValidReturnType( xReturn ) ) 898 bSkip = sal_True; 899 } 900 if (!bSkip) 901 { 902 rtl::OUString aFuncU = xFunc->getName(); 903 904 // stored function name: (service name).(function) 905 String aFuncName = aServiceName; 906 aFuncName += '.'; 907 aFuncName += String( aFuncU ); 908 909 sal_Bool bValid = sal_True; 910 long nVisibleCount = 0; 911 long nCallerPos = SC_CALLERPOS_NONE; 912 913 uno::Sequence<reflection::ParamInfo> aParams = 914 xFunc->getParameterInfos(); 915 long nParamCount = aParams.getLength(); 916 const reflection::ParamInfo* pParArr = aParams.getConstArray(); 917 long nParamPos; 918 for (nParamPos=0; nParamPos<nParamCount; nParamPos++) 919 { 920 if ( pParArr[nParamPos].aMode != reflection::ParamMode_IN ) 921 bValid = sal_False; 922 uno::Reference<reflection::XIdlClass> xParClass = 923 pParArr[nParamPos].aType; 924 ScAddInArgumentType eArgType = lcl_GetArgType( xParClass ); 925 if ( eArgType == SC_ADDINARG_NONE ) 926 bValid = sal_False; 927 else if ( eArgType == SC_ADDINARG_CALLER ) 928 nCallerPos = nParamPos; 929 else 930 ++nVisibleCount; 931 } 932 if (bValid) 933 { 934 sal_uInt16 nCategory = lcl_GetCategory( 935 String( 936 xAddIn->getProgrammaticCategoryName( 937 aFuncU ) ) ); 938 939 rtl::OString sHelpId = aHelpIdGenerator.GetHelpId( aFuncU ); 940 941 rtl::OUString aLocalU; 942 try 943 { 944 aLocalU = xAddIn-> 945 getDisplayFunctionName( aFuncU ); 946 } 947 catch(uno::Exception&) 948 { 949 aLocalU = rtl::OUString::createFromAscii( "###" ); 950 } 951 String aLocalName = String( aLocalU ); 952 953 rtl::OUString aDescU; 954 try 955 { 956 aDescU = xAddIn-> 957 getFunctionDescription( aFuncU ); 958 } 959 catch(uno::Exception&) 960 { 961 aDescU = rtl::OUString::createFromAscii( "###" ); 962 } 963 String aDescription = String( aDescU ); 964 965 ScAddInArgDesc* pVisibleArgs = NULL; 966 if ( nVisibleCount > 0 ) 967 { 968 ScAddInArgDesc aDesc; 969 pVisibleArgs = new ScAddInArgDesc[nVisibleCount]; 970 long nDestPos = 0; 971 for (nParamPos=0; nParamPos<nParamCount; nParamPos++) 972 { 973 uno::Reference<reflection::XIdlClass> xParClass = 974 pParArr[nParamPos].aType; 975 ScAddInArgumentType eArgType = lcl_GetArgType( xParClass ); 976 if ( eArgType != SC_ADDINARG_CALLER ) 977 { 978 rtl::OUString aArgName; 979 try 980 { 981 aArgName = xAddIn-> 982 getDisplayArgumentName( aFuncU, nParamPos ); 983 } 984 catch(uno::Exception&) 985 { 986 aArgName = rtl::OUString::createFromAscii( "###" ); 987 } 988 rtl::OUString aArgDesc; 989 try 990 { 991 aArgDesc = xAddIn-> 992 getArgumentDescription( aFuncU, nParamPos ); 993 } 994 catch(uno::Exception&) 995 { 996 aArgName = rtl::OUString::createFromAscii( "###" ); 997 } 998 999 sal_Bool bOptional = 1000 ( eArgType == SC_ADDINARG_VALUE_OR_ARRAY || 1001 eArgType == SC_ADDINARG_VARARGS ); 1002 1003 aDesc.eType = eArgType; 1004 aDesc.aName = String( aArgName ); 1005 aDesc.aDescription = String( aArgDesc ); 1006 aDesc.bOptional = bOptional; 1007 //! initialize aInternalName only from config? 1008 aDesc.aInternalName = pParArr[nParamPos].aName; 1009 1010 pVisibleArgs[nDestPos++] = aDesc; 1011 } 1012 } 1013 DBG_ASSERT( nDestPos==nVisibleCount, "wrong count" ); 1014 } 1015 1016 ppFuncData[nFuncPos+nOld] = new ScUnoAddInFuncData( 1017 aFuncName, aLocalName, aDescription, 1018 nCategory, sHelpId, 1019 xFunc, aObject, 1020 nVisibleCount, pVisibleArgs, nCallerPos ); 1021 1022 const ScUnoAddInFuncData* pData = 1023 ppFuncData[nFuncPos+nOld]; 1024 pExactHashMap->insert( 1025 ScAddInHashMap::value_type( 1026 pData->GetOriginalName(), 1027 pData ) ); 1028 pNameHashMap->insert( 1029 ScAddInHashMap::value_type( 1030 pData->GetUpperName(), 1031 pData ) ); 1032 pLocalHashMap->insert( 1033 ScAddInHashMap::value_type( 1034 pData->GetUpperLocal(), 1035 pData ) ); 1036 1037 delete[] pVisibleArgs; 1038 } 1039 } 1040 } 1041 } 1042 } 1043 } 1044 } 1045 } 1046 } 1047 } 1048 1049 void lcl_UpdateFunctionList( ScFunctionList& rFunctionList, const ScUnoAddInFuncData& rFuncData ) 1050 { 1051 String aCompare = rFuncData.GetUpperLocal(); // as used in FillFunctionDescFromData 1052 1053 sal_uLong nCount = rFunctionList.GetCount(); 1054 for (sal_uLong nPos=0; nPos<nCount; nPos++) 1055 { 1056 const ScFuncDesc* pDesc = rFunctionList.GetFunction( nPos ); 1057 if ( pDesc && pDesc->pFuncName && *pDesc->pFuncName == aCompare ) 1058 { 1059 ScUnoAddInCollection::FillFunctionDescFromData( rFuncData, *const_cast<ScFuncDesc*>(pDesc) ); 1060 break; 1061 } 1062 } 1063 } 1064 1065 const ScAddInArgDesc* lcl_FindArgDesc( const ScUnoAddInFuncData& rFuncData, const String& rArgIntName ) 1066 { 1067 long nArgCount = rFuncData.GetArgumentCount(); 1068 const ScAddInArgDesc* pArguments = rFuncData.GetArguments(); 1069 for (long nPos=0; nPos<nArgCount; nPos++) 1070 { 1071 if ( pArguments[nPos].aInternalName == rArgIntName ) 1072 return &pArguments[nPos]; 1073 } 1074 return NULL; 1075 } 1076 1077 void ScUnoAddInCollection::UpdateFromAddIn( const uno::Reference<uno::XInterface>& xInterface, 1078 const String& rServiceName ) 1079 { 1080 uno::Reference<lang::XLocalizable> xLoc( xInterface, uno::UNO_QUERY ); 1081 if ( xLoc.is() ) // optional in new add-ins 1082 { 1083 LanguageType eOfficeLang = Application::GetSettings().GetUILanguage(); 1084 lang::Locale aLocale( MsLangId::convertLanguageToLocale( eOfficeLang )); 1085 xLoc->setLocale( aLocale ); 1086 } 1087 1088 // if function list was already initialized, it must be updated 1089 1090 ScFunctionList* pFunctionList = NULL; 1091 if ( ScGlobal::HasStarCalcFunctionList() ) 1092 pFunctionList = ScGlobal::GetStarCalcFunctionList(); 1093 1094 // only get the function information from Introspection 1095 1096 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory(); 1097 if ( xManager.is() ) 1098 { 1099 uno::Reference<beans::XIntrospection> xIntro( 1100 xManager->createInstance(rtl::OUString::createFromAscii( 1101 "com.sun.star.beans.Introspection" )), 1102 uno::UNO_QUERY ); 1103 if ( xIntro.is() ) 1104 { 1105 uno::Any aObject; 1106 aObject <<= xInterface; 1107 uno::Reference<beans::XIntrospectionAccess> xAcc = xIntro->inspect(aObject); 1108 if (xAcc.is()) 1109 { 1110 uno::Sequence< uno::Reference<reflection::XIdlMethod> > aMethods = 1111 xAcc->getMethods( beans::MethodConcept::ALL ); 1112 long nMethodCount = aMethods.getLength(); 1113 const uno::Reference<reflection::XIdlMethod>* pArray = aMethods.getConstArray(); 1114 for (long nFuncPos=0; nFuncPos<nMethodCount; nFuncPos++) 1115 { 1116 uno::Reference<reflection::XIdlMethod> xFunc = pArray[nFuncPos]; 1117 if (xFunc.is()) 1118 { 1119 rtl::OUString aFuncU = xFunc->getName(); 1120 1121 // stored function name: (service name).(function) 1122 String aFuncName = rServiceName; 1123 aFuncName += '.'; 1124 aFuncName += String( aFuncU ); 1125 1126 // internal names are skipped because no FuncData exists 1127 ScUnoAddInFuncData* pOldData = const_cast<ScUnoAddInFuncData*>( GetFuncData( aFuncName ) ); 1128 if ( pOldData ) 1129 { 1130 // Create new (complete) argument info. 1131 // As in ReadFromAddIn, the reflection information is authoritative. 1132 // Local names and descriptions from pOldData are looked up using the 1133 // internal argument name. 1134 1135 sal_Bool bValid = sal_True; 1136 long nVisibleCount = 0; 1137 long nCallerPos = SC_CALLERPOS_NONE; 1138 1139 uno::Sequence<reflection::ParamInfo> aParams = 1140 xFunc->getParameterInfos(); 1141 long nParamCount = aParams.getLength(); 1142 const reflection::ParamInfo* pParArr = aParams.getConstArray(); 1143 long nParamPos; 1144 for (nParamPos=0; nParamPos<nParamCount; nParamPos++) 1145 { 1146 if ( pParArr[nParamPos].aMode != reflection::ParamMode_IN ) 1147 bValid = sal_False; 1148 uno::Reference<reflection::XIdlClass> xParClass = 1149 pParArr[nParamPos].aType; 1150 ScAddInArgumentType eArgType = lcl_GetArgType( xParClass ); 1151 if ( eArgType == SC_ADDINARG_NONE ) 1152 bValid = sal_False; 1153 else if ( eArgType == SC_ADDINARG_CALLER ) 1154 nCallerPos = nParamPos; 1155 else 1156 ++nVisibleCount; 1157 } 1158 if (bValid) 1159 { 1160 ScAddInArgDesc* pVisibleArgs = NULL; 1161 if ( nVisibleCount > 0 ) 1162 { 1163 ScAddInArgDesc aDesc; 1164 pVisibleArgs = new ScAddInArgDesc[nVisibleCount]; 1165 long nDestPos = 0; 1166 for (nParamPos=0; nParamPos<nParamCount; nParamPos++) 1167 { 1168 uno::Reference<reflection::XIdlClass> xParClass = 1169 pParArr[nParamPos].aType; 1170 ScAddInArgumentType eArgType = lcl_GetArgType( xParClass ); 1171 if ( eArgType != SC_ADDINARG_CALLER ) 1172 { 1173 const ScAddInArgDesc* pOldArgDesc = 1174 lcl_FindArgDesc( *pOldData, pParArr[nParamPos].aName ); 1175 if ( pOldArgDesc ) 1176 { 1177 aDesc.aName = pOldArgDesc->aName; 1178 aDesc.aDescription = pOldArgDesc->aDescription; 1179 } 1180 else 1181 aDesc.aName = aDesc.aDescription = String::CreateFromAscii( "###" ); 1182 1183 sal_Bool bOptional = 1184 ( eArgType == SC_ADDINARG_VALUE_OR_ARRAY || 1185 eArgType == SC_ADDINARG_VARARGS ); 1186 1187 aDesc.eType = eArgType; 1188 aDesc.bOptional = bOptional; 1189 //! initialize aInternalName only from config? 1190 aDesc.aInternalName = pParArr[nParamPos].aName; 1191 1192 pVisibleArgs[nDestPos++] = aDesc; 1193 } 1194 } 1195 DBG_ASSERT( nDestPos==nVisibleCount, "wrong count" ); 1196 } 1197 1198 pOldData->SetFunction( xFunc, aObject ); 1199 pOldData->SetArguments( nVisibleCount, pVisibleArgs ); 1200 pOldData->SetCallerPos( nCallerPos ); 1201 1202 if ( pFunctionList ) 1203 lcl_UpdateFunctionList( *pFunctionList, *pOldData ); 1204 1205 delete[] pVisibleArgs; 1206 } 1207 } 1208 } 1209 } 1210 } 1211 } 1212 } 1213 } 1214 1215 String ScUnoAddInCollection::FindFunction( const String& rUpperName, sal_Bool bLocalFirst ) 1216 { 1217 if (!bInitialized) 1218 Initialize(); 1219 1220 if (nFuncCount == 0) 1221 return EMPTY_STRING; 1222 1223 if ( bLocalFirst ) 1224 { 1225 // first scan all local names (used for entering formulas) 1226 1227 ScAddInHashMap::const_iterator iLook( pLocalHashMap->find( rUpperName ) ); 1228 if ( iLook != pLocalHashMap->end() ) 1229 return iLook->second->GetOriginalName(); 1230 1231 #if 0 1232 // after that, scan international names (really?) 1233 1234 iLook = pNameHashMap->find( rUpperName ); 1235 if ( iLook != pNameHashMap->end() ) 1236 return iLook->second->GetOriginalName(); 1237 #endif 1238 } 1239 else 1240 { 1241 // first scan international names (used when calling a function) 1242 //! before that, check for exact match??? 1243 1244 ScAddInHashMap::const_iterator iLook( pNameHashMap->find( rUpperName ) ); 1245 if ( iLook != pNameHashMap->end() ) 1246 return iLook->second->GetOriginalName(); 1247 1248 // after that, scan all local names (to allow replacing old AddIns with Uno) 1249 1250 iLook = pLocalHashMap->find( rUpperName ); 1251 if ( iLook != pLocalHashMap->end() ) 1252 return iLook->second->GetOriginalName(); 1253 } 1254 1255 return EMPTY_STRING; 1256 } 1257 1258 const ScUnoAddInFuncData* ScUnoAddInCollection::GetFuncData( const String& rName, bool bComplete ) 1259 { 1260 if (!bInitialized) 1261 Initialize(); 1262 1263 // rName must be the exact internal name 1264 1265 ScAddInHashMap::const_iterator iLook( pExactHashMap->find( rName ) ); 1266 if ( iLook != pExactHashMap->end() ) 1267 { 1268 const ScUnoAddInFuncData* pFuncData = iLook->second; 1269 1270 if ( bComplete && !pFuncData->GetFunction().is() ) //! extra flag? 1271 LoadComponent( *pFuncData ); 1272 1273 return pFuncData; 1274 } 1275 1276 return NULL; 1277 } 1278 1279 const ScUnoAddInFuncData* ScUnoAddInCollection::GetFuncData( long nIndex ) 1280 { 1281 if (!bInitialized) 1282 Initialize(); 1283 1284 if (nIndex < nFuncCount) 1285 return ppFuncData[nIndex]; 1286 return NULL; 1287 } 1288 1289 void ScUnoAddInCollection::LocalizeString( String& rName ) 1290 { 1291 if (!bInitialized) 1292 Initialize(); 1293 1294 // modify rName - input: exact name 1295 1296 ScAddInHashMap::const_iterator iLook( pExactHashMap->find( rName ) ); 1297 if ( iLook != pExactHashMap->end() ) 1298 rName = iLook->second->GetUpperLocal(); //! upper? 1299 } 1300 1301 1302 long ScUnoAddInCollection::GetFuncCount() 1303 { 1304 if (!bInitialized) 1305 Initialize(); 1306 1307 return nFuncCount; 1308 } 1309 1310 sal_Bool ScUnoAddInCollection::FillFunctionDesc( long nFunc, ScFuncDesc& rDesc ) 1311 { 1312 if (!bInitialized) 1313 Initialize(); 1314 1315 if (nFunc >= nFuncCount || !ppFuncData[nFunc]) 1316 return sal_False; 1317 1318 const ScUnoAddInFuncData& rFuncData = *ppFuncData[nFunc]; 1319 1320 return FillFunctionDescFromData( rFuncData, rDesc ); 1321 } 1322 1323 // static 1324 sal_Bool ScUnoAddInCollection::FillFunctionDescFromData( const ScUnoAddInFuncData& rFuncData, ScFuncDesc& rDesc ) 1325 { 1326 rDesc.Clear(); 1327 1328 sal_Bool bIncomplete = !rFuncData.GetFunction().is(); //! extra flag? 1329 1330 long nArgCount = rFuncData.GetArgumentCount(); 1331 if ( nArgCount > USHRT_MAX ) 1332 return sal_False; 1333 1334 if ( bIncomplete ) 1335 nArgCount = 0; // if incomplete, fill without argument info (no wrong order) 1336 1337 // nFIndex is set from outside 1338 1339 rDesc.pFuncName = new String( rFuncData.GetUpperLocal() ); //! upper? 1340 rDesc.nCategory = rFuncData.GetCategory(); 1341 rDesc.sHelpId = rFuncData.GetHelpId(); 1342 1343 String aDesc = rFuncData.GetDescription(); 1344 if (!aDesc.Len()) 1345 aDesc = rFuncData.GetLocalName(); // use name if no description is available 1346 rDesc.pFuncDesc = new String( aDesc ); 1347 1348 // AddInArgumentType_CALLER is already left out in FuncData 1349 1350 rDesc.nArgCount = (sal_uInt16)nArgCount; 1351 if ( nArgCount ) 1352 { 1353 sal_Bool bMultiple = sal_False; 1354 const ScAddInArgDesc* pArgs = rFuncData.GetArguments(); 1355 1356 rDesc.ppDefArgNames = new String*[nArgCount]; 1357 rDesc.ppDefArgDescs = new String*[nArgCount]; 1358 rDesc.pDefArgFlags = new ScFuncDesc::ParameterFlags[nArgCount]; 1359 for ( long nArg=0; nArg<nArgCount; nArg++ ) 1360 { 1361 rDesc.ppDefArgNames[nArg] = new String( pArgs[nArg].aName ); 1362 rDesc.ppDefArgDescs[nArg] = new String( pArgs[nArg].aDescription ); 1363 rDesc.pDefArgFlags[nArg].bOptional = pArgs[nArg].bOptional; 1364 rDesc.pDefArgFlags[nArg].bSuppress = false; 1365 1366 // no empty names... 1367 if ( rDesc.ppDefArgNames[nArg]->Len() == 0 ) 1368 { 1369 String aDefName( RTL_CONSTASCII_USTRINGPARAM("arg") ); 1370 aDefName += String::CreateFromInt32( nArg+1 ); 1371 *rDesc.ppDefArgNames[nArg] = aDefName; 1372 } 1373 1374 // last argument repeated? 1375 if ( nArg+1 == nArgCount && ( pArgs[nArg].eType == SC_ADDINARG_VARARGS ) ) 1376 bMultiple = sal_True; 1377 } 1378 1379 if ( bMultiple ) 1380 rDesc.nArgCount += VAR_ARGS - 1; // VAR_ARGS means just one repeated arg 1381 } 1382 1383 rDesc.bIncomplete = bIncomplete; 1384 1385 return sal_True; 1386 } 1387 1388 1389 //------------------------------------------------------------------------ 1390 1391 ScUnoAddInCall::ScUnoAddInCall( ScUnoAddInCollection& rColl, const String& rName, 1392 long nParamCount ) : 1393 bValidCount( sal_False ), 1394 nErrCode( errNoCode ), // before function was called 1395 bHasString( sal_True ), 1396 fValue( 0.0 ), 1397 xMatrix( NULL ) 1398 { 1399 pFuncData = rColl.GetFuncData( rName, true ); // need fully initialized data 1400 DBG_ASSERT( pFuncData, "Function Data missing" ); 1401 if ( pFuncData ) 1402 { 1403 long nDescCount = pFuncData->GetArgumentCount(); 1404 const ScAddInArgDesc* pArgs = pFuncData->GetArguments(); 1405 1406 // is aVarArg sequence needed? 1407 if ( nParamCount >= nDescCount && nDescCount > 0 && 1408 pArgs[nDescCount-1].eType == SC_ADDINARG_VARARGS ) 1409 { 1410 long nVarCount = nParamCount - ( nDescCount - 1 ); // size of last argument 1411 aVarArg.realloc( nVarCount ); 1412 bValidCount = sal_True; 1413 } 1414 else if ( nParamCount <= nDescCount ) 1415 { 1416 // all args behind nParamCount must be optional 1417 bValidCount = sal_True; 1418 for (long i=nParamCount; i<nDescCount; i++) 1419 if ( !pArgs[i].bOptional ) 1420 bValidCount = sal_False; 1421 } 1422 // else invalid (too many arguments) 1423 1424 if ( bValidCount ) 1425 aArgs.realloc( nDescCount ); // sequence must always match function signature 1426 } 1427 } 1428 1429 ScUnoAddInCall::~ScUnoAddInCall() 1430 { 1431 // pFuncData is deleted with ScUnoAddInCollection 1432 } 1433 1434 sal_Bool ScUnoAddInCall::ValidParamCount() 1435 { 1436 return bValidCount; 1437 } 1438 1439 ScAddInArgumentType ScUnoAddInCall::GetArgType( long nPos ) 1440 { 1441 if ( pFuncData ) 1442 { 1443 long nCount = pFuncData->GetArgumentCount(); 1444 const ScAddInArgDesc* pArgs = pFuncData->GetArguments(); 1445 1446 // if last arg is sequence, use "any" type 1447 if ( nCount > 0 && nPos >= nCount-1 && pArgs[nCount-1].eType == SC_ADDINARG_VARARGS ) 1448 return SC_ADDINARG_VALUE_OR_ARRAY; 1449 1450 if ( nPos < nCount ) 1451 return pArgs[nPos].eType; 1452 } 1453 return SC_ADDINARG_VALUE_OR_ARRAY; //! error code !!!! 1454 } 1455 1456 sal_Bool ScUnoAddInCall::NeedsCaller() const 1457 { 1458 return pFuncData && pFuncData->GetCallerPos() != SC_CALLERPOS_NONE; 1459 } 1460 1461 void ScUnoAddInCall::SetCaller( const uno::Reference<uno::XInterface>& rInterface ) 1462 { 1463 xCaller = rInterface; 1464 } 1465 1466 void ScUnoAddInCall::SetCallerFromObjectShell( SfxObjectShell* pObjSh ) 1467 { 1468 if (pObjSh) 1469 { 1470 uno::Reference<uno::XInterface> xInt( pObjSh->GetBaseModel(), uno::UNO_QUERY ); 1471 SetCaller( xInt ); 1472 } 1473 } 1474 1475 void ScUnoAddInCall::SetParam( long nPos, const uno::Any& rValue ) 1476 { 1477 if ( pFuncData ) 1478 { 1479 long nCount = pFuncData->GetArgumentCount(); 1480 const ScAddInArgDesc* pArgs = pFuncData->GetArguments(); 1481 if ( nCount > 0 && nPos >= nCount-1 && pArgs[nCount-1].eType == SC_ADDINARG_VARARGS ) 1482 { 1483 long nVarPos = nPos-(nCount-1); 1484 if ( nVarPos < aVarArg.getLength() ) 1485 aVarArg.getArray()[nVarPos] = rValue; 1486 else 1487 { 1488 DBG_ERROR("wrong argument number"); 1489 } 1490 } 1491 else if ( nPos < aArgs.getLength() ) 1492 aArgs.getArray()[nPos] = rValue; 1493 else 1494 { 1495 DBG_ERROR("wrong argument number"); 1496 } 1497 } 1498 } 1499 1500 void ScUnoAddInCall::ExecuteCall() 1501 { 1502 if ( !pFuncData ) 1503 return; 1504 1505 long nCount = pFuncData->GetArgumentCount(); 1506 const ScAddInArgDesc* pArgs = pFuncData->GetArguments(); 1507 if ( nCount > 0 && pArgs[nCount-1].eType == SC_ADDINARG_VARARGS ) 1508 { 1509 // insert aVarArg as last argument 1510 //! after inserting caller (to prevent copying twice)? 1511 1512 DBG_ASSERT( aArgs.getLength() == nCount, "wrong argument count" ); 1513 aArgs.getArray()[nCount-1] <<= aVarArg; 1514 } 1515 1516 if ( pFuncData->GetCallerPos() != SC_CALLERPOS_NONE ) 1517 { 1518 uno::Any aCallerAny; 1519 aCallerAny <<= xCaller; 1520 1521 long nUserLen = aArgs.getLength(); 1522 long nCallPos = pFuncData->GetCallerPos(); 1523 if (nCallPos>nUserLen) // should not happen 1524 { 1525 DBG_ERROR("wrong CallPos"); 1526 nCallPos = nUserLen; 1527 } 1528 1529 long nDestLen = nUserLen + 1; 1530 uno::Sequence<uno::Any> aRealArgs( nDestLen ); 1531 uno::Any* pDest = aRealArgs.getArray(); 1532 1533 const uno::Any* pSource = aArgs.getConstArray(); 1534 long nSrcPos = 0; 1535 1536 for ( long nDestPos = 0; nDestPos < nDestLen; nDestPos++ ) 1537 { 1538 if ( nDestPos == nCallPos ) 1539 pDest[nDestPos] = aCallerAny; 1540 else 1541 pDest[nDestPos] = pSource[nSrcPos++]; 1542 } 1543 1544 ExecuteCallWithArgs( aRealArgs ); 1545 } 1546 else 1547 ExecuteCallWithArgs( aArgs ); 1548 } 1549 1550 void ScUnoAddInCall::ExecuteCallWithArgs(uno::Sequence<uno::Any>& rCallArgs) 1551 { 1552 // rCallArgs may not match argument descriptions (because of caller) 1553 1554 uno::Reference<reflection::XIdlMethod> xFunction; 1555 uno::Any aObject; 1556 if ( pFuncData ) 1557 { 1558 xFunction = pFuncData->GetFunction(); 1559 aObject = pFuncData->GetObject(); 1560 } 1561 1562 if ( xFunction.is() ) 1563 { 1564 uno::Any aAny; 1565 nErrCode = 0; 1566 1567 try 1568 { 1569 aAny = xFunction->invoke( aObject, rCallArgs ); 1570 } 1571 catch(lang::IllegalArgumentException&) 1572 { 1573 nErrCode = errIllegalArgument; 1574 } 1575 #if 0 1576 catch(FloatingPointException&) 1577 { 1578 nErrCode = errIllegalFPOperation; 1579 } 1580 #endif 1581 catch(reflection::InvocationTargetException& rWrapped) 1582 { 1583 if ( rWrapped.TargetException.getValueType().equals( 1584 getCppuType( (lang::IllegalArgumentException*)0 ) ) ) 1585 nErrCode = errIllegalArgument; 1586 else if ( rWrapped.TargetException.getValueType().equals( 1587 getCppuType( (sheet::NoConvergenceException*)0 ) ) ) 1588 nErrCode = errNoConvergence; 1589 else 1590 nErrCode = errNoValue; 1591 } 1592 1593 catch(uno::Exception&) 1594 { 1595 nErrCode = errNoValue; 1596 } 1597 1598 if (!nErrCode) 1599 SetResult( aAny ); // convert result to Calc types 1600 } 1601 } 1602 1603 void ScUnoAddInCall::SetResult( const uno::Any& rNewRes ) 1604 { 1605 nErrCode = 0; 1606 xVarRes = NULL; 1607 1608 // Reflection* pRefl = rNewRes.getReflection(); 1609 1610 uno::TypeClass eClass = rNewRes.getValueTypeClass(); 1611 uno::Type aType = rNewRes.getValueType(); 1612 switch (eClass) 1613 { 1614 case uno::TypeClass_VOID: 1615 nErrCode = NOTAVAILABLE; // #NA 1616 break; 1617 1618 case uno::TypeClass_ENUM: 1619 case uno::TypeClass_BOOLEAN: 1620 case uno::TypeClass_CHAR: 1621 case uno::TypeClass_BYTE: 1622 case uno::TypeClass_SHORT: 1623 case uno::TypeClass_UNSIGNED_SHORT: 1624 case uno::TypeClass_LONG: 1625 case uno::TypeClass_UNSIGNED_LONG: 1626 case uno::TypeClass_FLOAT: 1627 case uno::TypeClass_DOUBLE: 1628 { 1629 uno::TypeClass eMyClass; 1630 ScApiTypeConversion::ConvertAnyToDouble( fValue, eMyClass, rNewRes); 1631 bHasString = sal_False; 1632 } 1633 break; 1634 1635 case uno::TypeClass_STRING: 1636 { 1637 rtl::OUString aUStr; 1638 rNewRes >>= aUStr; 1639 aString = String( aUStr ); 1640 bHasString = sal_True; 1641 } 1642 break; 1643 1644 case uno::TypeClass_INTERFACE: 1645 { 1646 //! directly extract XVolatileResult from any? 1647 uno::Reference<uno::XInterface> xInterface; 1648 rNewRes >>= xInterface; 1649 if ( xInterface.is() ) 1650 xVarRes = uno::Reference<sheet::XVolatileResult>( xInterface, uno::UNO_QUERY ); 1651 1652 if (!xVarRes.is()) 1653 nErrCode = errNoValue; // unknown interface 1654 } 1655 break; 1656 1657 default: 1658 if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<sal_Int32> > *)0 ) ) ) 1659 { 1660 const uno::Sequence< uno::Sequence<sal_Int32> >* pRowSeq = NULL; 1661 1662 //! use pointer from any! 1663 uno::Sequence< uno::Sequence<sal_Int32> > aSequence; 1664 if ( rNewRes >>= aSequence ) 1665 pRowSeq = &aSequence; 1666 1667 if ( pRowSeq ) 1668 { 1669 long nRowCount = pRowSeq->getLength(); 1670 const uno::Sequence<sal_Int32>* pRowArr = pRowSeq->getConstArray(); 1671 long nMaxColCount = 0; 1672 long nCol, nRow; 1673 for (nRow=0; nRow<nRowCount; nRow++) 1674 { 1675 long nTmp = pRowArr[nRow].getLength(); 1676 if ( nTmp > nMaxColCount ) 1677 nMaxColCount = nTmp; 1678 } 1679 if ( nMaxColCount && nRowCount ) 1680 { 1681 xMatrix = new ScMatrix( 1682 static_cast<SCSIZE>(nMaxColCount), 1683 static_cast<SCSIZE>(nRowCount) ); 1684 ScMatrix* pMatrix = xMatrix; 1685 for (nRow=0; nRow<nRowCount; nRow++) 1686 { 1687 long nColCount = pRowArr[nRow].getLength(); 1688 const sal_Int32* pColArr = pRowArr[nRow].getConstArray(); 1689 for (nCol=0; nCol<nColCount; nCol++) 1690 pMatrix->PutDouble( pColArr[nCol], 1691 static_cast<SCSIZE>(nCol), 1692 static_cast<SCSIZE>(nRow) ); 1693 for (nCol=nColCount; nCol<nMaxColCount; nCol++) 1694 pMatrix->PutDouble( 0.0, 1695 static_cast<SCSIZE>(nCol), 1696 static_cast<SCSIZE>(nRow) ); 1697 } 1698 } 1699 } 1700 } 1701 else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<double> > *)0 ) ) ) 1702 { 1703 const uno::Sequence< uno::Sequence<double> >* pRowSeq = NULL; 1704 1705 //! use pointer from any! 1706 uno::Sequence< uno::Sequence<double> > aSequence; 1707 if ( rNewRes >>= aSequence ) 1708 pRowSeq = &aSequence; 1709 1710 if ( pRowSeq ) 1711 { 1712 long nRowCount = pRowSeq->getLength(); 1713 const uno::Sequence<double>* pRowArr = pRowSeq->getConstArray(); 1714 long nMaxColCount = 0; 1715 long nCol, nRow; 1716 for (nRow=0; nRow<nRowCount; nRow++) 1717 { 1718 long nTmp = pRowArr[nRow].getLength(); 1719 if ( nTmp > nMaxColCount ) 1720 nMaxColCount = nTmp; 1721 } 1722 if ( nMaxColCount && nRowCount ) 1723 { 1724 xMatrix = new ScMatrix( 1725 static_cast<SCSIZE>(nMaxColCount), 1726 static_cast<SCSIZE>(nRowCount) ); 1727 ScMatrix* pMatrix = xMatrix; 1728 for (nRow=0; nRow<nRowCount; nRow++) 1729 { 1730 long nColCount = pRowArr[nRow].getLength(); 1731 const double* pColArr = pRowArr[nRow].getConstArray(); 1732 for (nCol=0; nCol<nColCount; nCol++) 1733 pMatrix->PutDouble( pColArr[nCol], 1734 static_cast<SCSIZE>(nCol), 1735 static_cast<SCSIZE>(nRow) ); 1736 for (nCol=nColCount; nCol<nMaxColCount; nCol++) 1737 pMatrix->PutDouble( 0.0, 1738 static_cast<SCSIZE>(nCol), 1739 static_cast<SCSIZE>(nRow) ); 1740 } 1741 } 1742 } 1743 } 1744 else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<rtl::OUString> > *)0 ) ) ) 1745 { 1746 const uno::Sequence< uno::Sequence<rtl::OUString> >* pRowSeq = NULL; 1747 1748 //! use pointer from any! 1749 uno::Sequence< uno::Sequence<rtl::OUString> > aSequence; 1750 if ( rNewRes >>= aSequence ) 1751 pRowSeq = &aSequence; 1752 1753 if ( pRowSeq ) 1754 { 1755 long nRowCount = pRowSeq->getLength(); 1756 const uno::Sequence<rtl::OUString>* pRowArr = pRowSeq->getConstArray(); 1757 long nMaxColCount = 0; 1758 long nCol, nRow; 1759 for (nRow=0; nRow<nRowCount; nRow++) 1760 { 1761 long nTmp = pRowArr[nRow].getLength(); 1762 if ( nTmp > nMaxColCount ) 1763 nMaxColCount = nTmp; 1764 } 1765 if ( nMaxColCount && nRowCount ) 1766 { 1767 xMatrix = new ScMatrix( 1768 static_cast<SCSIZE>(nMaxColCount), 1769 static_cast<SCSIZE>(nRowCount) ); 1770 ScMatrix* pMatrix = xMatrix; 1771 for (nRow=0; nRow<nRowCount; nRow++) 1772 { 1773 long nColCount = pRowArr[nRow].getLength(); 1774 const rtl::OUString* pColArr = pRowArr[nRow].getConstArray(); 1775 for (nCol=0; nCol<nColCount; nCol++) 1776 pMatrix->PutString( String( pColArr[nCol] ), 1777 static_cast<SCSIZE>(nCol), 1778 static_cast<SCSIZE>(nRow) ); 1779 for (nCol=nColCount; nCol<nMaxColCount; nCol++) 1780 pMatrix->PutString( EMPTY_STRING, 1781 static_cast<SCSIZE>(nCol), 1782 static_cast<SCSIZE>(nRow) ); 1783 } 1784 } 1785 } 1786 } 1787 else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<uno::Any> > *)0 ) ) ) 1788 { 1789 xMatrix = ScSequenceToMatrix::CreateMixedMatrix( rNewRes ); 1790 } 1791 1792 if (!xMatrix) // no array found 1793 nErrCode = errNoValue; //! code for error in return type??? 1794 } 1795 } 1796 1797 1798 1799 //------------------------------------------------------------------------ 1800 1801 1802 1803