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