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 } 756 757 ScAddInArgumentType lcl_GetArgType( const uno::Reference<reflection::XIdlClass>& xClass ) 758 { 759 if (!xClass.is()) 760 return SC_ADDINARG_NONE; 761 762 uno::TypeClass eType = xClass->getTypeClass(); 763 764 if ( eType == uno::TypeClass_LONG ) //! other integer types? 765 return SC_ADDINARG_INTEGER; 766 767 if ( eType == uno::TypeClass_DOUBLE ) 768 return SC_ADDINARG_DOUBLE; 769 770 if ( eType == uno::TypeClass_STRING ) 771 return SC_ADDINARG_STRING; 772 773 //! XIdlClass needs getType() method! 774 rtl::OUString sName = xClass->getName(); 775 776 if (IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<sal_Int32> >*)0) )) 777 return SC_ADDINARG_INTEGER_ARRAY; 778 779 if (IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<double> >*)0) )) 780 return SC_ADDINARG_DOUBLE_ARRAY; 781 782 if (IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<rtl::OUString> >*)0) )) 783 return SC_ADDINARG_STRING_ARRAY; 784 785 if (IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<uno::Any> >*)0) )) 786 return SC_ADDINARG_MIXED_ARRAY; 787 788 if (IsTypeName( sName, getCppuType((uno::Any*)0) )) 789 return SC_ADDINARG_VALUE_OR_ARRAY; 790 791 if (IsTypeName( sName, getCppuType((uno::Reference<table::XCellRange>*)0) )) 792 return SC_ADDINARG_CELLRANGE; 793 794 if (IsTypeName( sName, getCppuType((uno::Reference<beans::XPropertySet>*)0) )) 795 return SC_ADDINARG_CALLER; 796 797 if (IsTypeName( sName, getCppuType((uno::Sequence<uno::Any>*)0) )) 798 return SC_ADDINARG_VARARGS; 799 800 return SC_ADDINARG_NONE; 801 } 802 803 void ScUnoAddInCollection::ReadFromAddIn( const uno::Reference<uno::XInterface>& xInterface ) 804 { 805 uno::Reference<sheet::XAddIn> xAddIn( xInterface, uno::UNO_QUERY ); 806 uno::Reference<lang::XServiceName> xName( xInterface, uno::UNO_QUERY ); 807 if ( xAddIn.is() && xName.is() ) 808 { 809 // AddIns must use the language for which the office is installed 810 LanguageType eOfficeLang = Application::GetSettings().GetUILanguage(); 811 812 lang::Locale aLocale( MsLangId::convertLanguageToLocale( eOfficeLang )); 813 xAddIn->setLocale( aLocale ); 814 815 String aServiceName = String( xName->getServiceName() ); 816 ScUnoAddInHelpIdGenerator aHelpIdGenerator( xName->getServiceName() ); 817 818 //! pass XIntrospection to ReadFromAddIn 819 820 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory(); 821 if ( xManager.is() ) 822 { 823 uno::Reference<beans::XIntrospection> xIntro( 824 xManager->createInstance(rtl::OUString::createFromAscii( 825 "com.sun.star.beans.Introspection" )), 826 uno::UNO_QUERY ); 827 if ( xIntro.is() ) 828 { 829 uno::Any aObject; 830 aObject <<= xAddIn; 831 uno::Reference<beans::XIntrospectionAccess> xAcc = xIntro->inspect(aObject); 832 if (xAcc.is()) 833 { 834 uno::Sequence< uno::Reference<reflection::XIdlMethod> > aMethods = 835 xAcc->getMethods( beans::MethodConcept::ALL ); 836 long nNewCount = aMethods.getLength(); 837 if ( nNewCount ) 838 { 839 long nOld = nFuncCount; 840 nFuncCount = nNewCount+nOld; 841 if ( nOld ) 842 { 843 ScUnoAddInFuncData** ppNew = new ScUnoAddInFuncData*[nFuncCount]; 844 for (long i=0; i<nOld; i++) 845 ppNew[i] = ppFuncData[i]; 846 delete[] ppFuncData; 847 ppFuncData = ppNew; 848 } 849 else 850 ppFuncData = new ScUnoAddInFuncData*[nFuncCount]; 851 852 //! TODO: adjust bucket count? 853 if ( !pExactHashMap ) 854 pExactHashMap = new ScAddInHashMap; 855 if ( !pNameHashMap ) 856 pNameHashMap = new ScAddInHashMap; 857 if ( !pLocalHashMap ) 858 pLocalHashMap = new ScAddInHashMap; 859 860 const uno::Reference<reflection::XIdlMethod>* pArray = aMethods.getConstArray(); 861 for (long nFuncPos=0; nFuncPos<nNewCount; nFuncPos++) 862 { 863 ppFuncData[nFuncPos+nOld] = NULL; 864 865 uno::Reference<reflection::XIdlMethod> xFunc = pArray[nFuncPos]; 866 if (xFunc.is()) 867 { 868 // leave out internal functions 869 uno::Reference<reflection::XIdlClass> xClass = 870 xFunc->getDeclaringClass(); 871 sal_Bool bSkip = sal_True; 872 if ( xClass.is() ) 873 { 874 //! XIdlClass needs getType() method! 875 rtl::OUString sName = xClass->getName(); 876 bSkip = ( 877 IsTypeName( sName, 878 getCppuType((uno::Reference<uno::XInterface>*)0) ) || 879 IsTypeName( sName, 880 getCppuType((uno::Reference<reflection::XIdlClassProvider>*)0) ) || 881 IsTypeName( sName, 882 getCppuType((uno::Reference<lang::XServiceName>*)0) ) || 883 IsTypeName( sName, 884 getCppuType((uno::Reference<lang::XServiceInfo>*)0) ) || 885 IsTypeName( sName, 886 getCppuType((uno::Reference<sheet::XAddIn>*)0) ) ); 887 } 888 if (!bSkip) 889 { 890 uno::Reference<reflection::XIdlClass> xReturn = 891 xFunc->getReturnType(); 892 if ( !lcl_ValidReturnType( xReturn ) ) 893 bSkip = sal_True; 894 } 895 if (!bSkip) 896 { 897 rtl::OUString aFuncU = xFunc->getName(); 898 899 // stored function name: (service name).(function) 900 String aFuncName = aServiceName; 901 aFuncName += '.'; 902 aFuncName += String( aFuncU ); 903 904 sal_Bool bValid = sal_True; 905 long nVisibleCount = 0; 906 long nCallerPos = SC_CALLERPOS_NONE; 907 908 uno::Sequence<reflection::ParamInfo> aParams = 909 xFunc->getParameterInfos(); 910 long nParamCount = aParams.getLength(); 911 const reflection::ParamInfo* pParArr = aParams.getConstArray(); 912 long nParamPos; 913 for (nParamPos=0; nParamPos<nParamCount; nParamPos++) 914 { 915 if ( pParArr[nParamPos].aMode != reflection::ParamMode_IN ) 916 bValid = sal_False; 917 uno::Reference<reflection::XIdlClass> xParClass = 918 pParArr[nParamPos].aType; 919 ScAddInArgumentType eArgType = lcl_GetArgType( xParClass ); 920 if ( eArgType == SC_ADDINARG_NONE ) 921 bValid = sal_False; 922 else if ( eArgType == SC_ADDINARG_CALLER ) 923 nCallerPos = nParamPos; 924 else 925 ++nVisibleCount; 926 } 927 if (bValid) 928 { 929 sal_uInt16 nCategory = lcl_GetCategory( 930 String( 931 xAddIn->getProgrammaticCategoryName( 932 aFuncU ) ) ); 933 934 rtl::OString sHelpId = aHelpIdGenerator.GetHelpId( aFuncU ); 935 936 rtl::OUString aLocalU; 937 try 938 { 939 aLocalU = xAddIn-> 940 getDisplayFunctionName( aFuncU ); 941 } 942 catch(uno::Exception&) 943 { 944 aLocalU = rtl::OUString::createFromAscii( "###" ); 945 } 946 String aLocalName = String( aLocalU ); 947 948 rtl::OUString aDescU; 949 try 950 { 951 aDescU = xAddIn-> 952 getFunctionDescription( aFuncU ); 953 } 954 catch(uno::Exception&) 955 { 956 aDescU = rtl::OUString::createFromAscii( "###" ); 957 } 958 String aDescription = String( aDescU ); 959 960 ScAddInArgDesc* pVisibleArgs = NULL; 961 if ( nVisibleCount > 0 ) 962 { 963 ScAddInArgDesc aDesc; 964 pVisibleArgs = new ScAddInArgDesc[nVisibleCount]; 965 long nDestPos = 0; 966 for (nParamPos=0; nParamPos<nParamCount; nParamPos++) 967 { 968 uno::Reference<reflection::XIdlClass> xParClass = 969 pParArr[nParamPos].aType; 970 ScAddInArgumentType eArgType = lcl_GetArgType( xParClass ); 971 if ( eArgType != SC_ADDINARG_CALLER ) 972 { 973 rtl::OUString aArgName; 974 try 975 { 976 aArgName = xAddIn-> 977 getDisplayArgumentName( aFuncU, nParamPos ); 978 } 979 catch(uno::Exception&) 980 { 981 aArgName = rtl::OUString::createFromAscii( "###" ); 982 } 983 rtl::OUString aArgDesc; 984 try 985 { 986 aArgDesc = xAddIn-> 987 getArgumentDescription( aFuncU, nParamPos ); 988 } 989 catch(uno::Exception&) 990 { 991 aArgName = rtl::OUString::createFromAscii( "###" ); 992 } 993 994 sal_Bool bOptional = 995 ( eArgType == SC_ADDINARG_VALUE_OR_ARRAY || 996 eArgType == SC_ADDINARG_VARARGS ); 997 998 aDesc.eType = eArgType; 999 aDesc.aName = String( aArgName ); 1000 aDesc.aDescription = String( aArgDesc ); 1001 aDesc.bOptional = bOptional; 1002 //! initialize aInternalName only from config? 1003 aDesc.aInternalName = pParArr[nParamPos].aName; 1004 1005 pVisibleArgs[nDestPos++] = aDesc; 1006 } 1007 } 1008 DBG_ASSERT( nDestPos==nVisibleCount, "wrong count" ); 1009 } 1010 1011 ppFuncData[nFuncPos+nOld] = new ScUnoAddInFuncData( 1012 aFuncName, aLocalName, aDescription, 1013 nCategory, sHelpId, 1014 xFunc, aObject, 1015 nVisibleCount, pVisibleArgs, nCallerPos ); 1016 1017 const ScUnoAddInFuncData* pData = 1018 ppFuncData[nFuncPos+nOld]; 1019 pExactHashMap->insert( 1020 ScAddInHashMap::value_type( 1021 pData->GetOriginalName(), 1022 pData ) ); 1023 pNameHashMap->insert( 1024 ScAddInHashMap::value_type( 1025 pData->GetUpperName(), 1026 pData ) ); 1027 pLocalHashMap->insert( 1028 ScAddInHashMap::value_type( 1029 pData->GetUpperLocal(), 1030 pData ) ); 1031 1032 delete[] pVisibleArgs; 1033 } 1034 } 1035 } 1036 } 1037 } 1038 } 1039 } 1040 } 1041 } 1042 } 1043 1044 void lcl_UpdateFunctionList( ScFunctionList& rFunctionList, const ScUnoAddInFuncData& rFuncData ) 1045 { 1046 String aCompare = rFuncData.GetUpperLocal(); // as used in FillFunctionDescFromData 1047 1048 sal_uLong nCount = rFunctionList.GetCount(); 1049 for (sal_uLong nPos=0; nPos<nCount; nPos++) 1050 { 1051 const ScFuncDesc* pDesc = rFunctionList.GetFunction( nPos ); 1052 if ( pDesc && pDesc->pFuncName && *pDesc->pFuncName == aCompare ) 1053 { 1054 ScUnoAddInCollection::FillFunctionDescFromData( rFuncData, *const_cast<ScFuncDesc*>(pDesc) ); 1055 break; 1056 } 1057 } 1058 } 1059 1060 const ScAddInArgDesc* lcl_FindArgDesc( const ScUnoAddInFuncData& rFuncData, const String& rArgIntName ) 1061 { 1062 long nArgCount = rFuncData.GetArgumentCount(); 1063 const ScAddInArgDesc* pArguments = rFuncData.GetArguments(); 1064 for (long nPos=0; nPos<nArgCount; nPos++) 1065 { 1066 if ( pArguments[nPos].aInternalName == rArgIntName ) 1067 return &pArguments[nPos]; 1068 } 1069 return NULL; 1070 } 1071 1072 void ScUnoAddInCollection::UpdateFromAddIn( const uno::Reference<uno::XInterface>& xInterface, 1073 const String& rServiceName ) 1074 { 1075 uno::Reference<lang::XLocalizable> xLoc( xInterface, uno::UNO_QUERY ); 1076 if ( xLoc.is() ) // optional in new add-ins 1077 { 1078 LanguageType eOfficeLang = Application::GetSettings().GetUILanguage(); 1079 lang::Locale aLocale( MsLangId::convertLanguageToLocale( eOfficeLang )); 1080 xLoc->setLocale( aLocale ); 1081 } 1082 1083 // if function list was already initialized, it must be updated 1084 1085 ScFunctionList* pFunctionList = NULL; 1086 if ( ScGlobal::HasStarCalcFunctionList() ) 1087 pFunctionList = ScGlobal::GetStarCalcFunctionList(); 1088 1089 // only get the function information from Introspection 1090 1091 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory(); 1092 if ( xManager.is() ) 1093 { 1094 uno::Reference<beans::XIntrospection> xIntro( 1095 xManager->createInstance(rtl::OUString::createFromAscii( 1096 "com.sun.star.beans.Introspection" )), 1097 uno::UNO_QUERY ); 1098 if ( xIntro.is() ) 1099 { 1100 uno::Any aObject; 1101 aObject <<= xInterface; 1102 uno::Reference<beans::XIntrospectionAccess> xAcc = xIntro->inspect(aObject); 1103 if (xAcc.is()) 1104 { 1105 uno::Sequence< uno::Reference<reflection::XIdlMethod> > aMethods = 1106 xAcc->getMethods( beans::MethodConcept::ALL ); 1107 long nMethodCount = aMethods.getLength(); 1108 const uno::Reference<reflection::XIdlMethod>* pArray = aMethods.getConstArray(); 1109 for (long nFuncPos=0; nFuncPos<nMethodCount; nFuncPos++) 1110 { 1111 uno::Reference<reflection::XIdlMethod> xFunc = pArray[nFuncPos]; 1112 if (xFunc.is()) 1113 { 1114 rtl::OUString aFuncU = xFunc->getName(); 1115 1116 // stored function name: (service name).(function) 1117 String aFuncName = rServiceName; 1118 aFuncName += '.'; 1119 aFuncName += String( aFuncU ); 1120 1121 // internal names are skipped because no FuncData exists 1122 ScUnoAddInFuncData* pOldData = const_cast<ScUnoAddInFuncData*>( GetFuncData( aFuncName ) ); 1123 if ( pOldData ) 1124 { 1125 // Create new (complete) argument info. 1126 // As in ReadFromAddIn, the reflection information is authoritative. 1127 // Local names and descriptions from pOldData are looked up using the 1128 // internal argument name. 1129 1130 sal_Bool bValid = sal_True; 1131 long nVisibleCount = 0; 1132 long nCallerPos = SC_CALLERPOS_NONE; 1133 1134 uno::Sequence<reflection::ParamInfo> aParams = 1135 xFunc->getParameterInfos(); 1136 long nParamCount = aParams.getLength(); 1137 const reflection::ParamInfo* pParArr = aParams.getConstArray(); 1138 long nParamPos; 1139 for (nParamPos=0; nParamPos<nParamCount; nParamPos++) 1140 { 1141 if ( pParArr[nParamPos].aMode != reflection::ParamMode_IN ) 1142 bValid = sal_False; 1143 uno::Reference<reflection::XIdlClass> xParClass = 1144 pParArr[nParamPos].aType; 1145 ScAddInArgumentType eArgType = lcl_GetArgType( xParClass ); 1146 if ( eArgType == SC_ADDINARG_NONE ) 1147 bValid = sal_False; 1148 else if ( eArgType == SC_ADDINARG_CALLER ) 1149 nCallerPos = nParamPos; 1150 else 1151 ++nVisibleCount; 1152 } 1153 if (bValid) 1154 { 1155 ScAddInArgDesc* pVisibleArgs = NULL; 1156 if ( nVisibleCount > 0 ) 1157 { 1158 ScAddInArgDesc aDesc; 1159 pVisibleArgs = new ScAddInArgDesc[nVisibleCount]; 1160 long nDestPos = 0; 1161 for (nParamPos=0; nParamPos<nParamCount; nParamPos++) 1162 { 1163 uno::Reference<reflection::XIdlClass> xParClass = 1164 pParArr[nParamPos].aType; 1165 ScAddInArgumentType eArgType = lcl_GetArgType( xParClass ); 1166 if ( eArgType != SC_ADDINARG_CALLER ) 1167 { 1168 const ScAddInArgDesc* pOldArgDesc = 1169 lcl_FindArgDesc( *pOldData, pParArr[nParamPos].aName ); 1170 if ( pOldArgDesc ) 1171 { 1172 aDesc.aName = pOldArgDesc->aName; 1173 aDesc.aDescription = pOldArgDesc->aDescription; 1174 } 1175 else 1176 aDesc.aName = aDesc.aDescription = String::CreateFromAscii( "###" ); 1177 1178 sal_Bool bOptional = 1179 ( eArgType == SC_ADDINARG_VALUE_OR_ARRAY || 1180 eArgType == SC_ADDINARG_VARARGS ); 1181 1182 aDesc.eType = eArgType; 1183 aDesc.bOptional = bOptional; 1184 //! initialize aInternalName only from config? 1185 aDesc.aInternalName = pParArr[nParamPos].aName; 1186 1187 pVisibleArgs[nDestPos++] = aDesc; 1188 } 1189 } 1190 DBG_ASSERT( nDestPos==nVisibleCount, "wrong count" ); 1191 } 1192 1193 pOldData->SetFunction( xFunc, aObject ); 1194 pOldData->SetArguments( nVisibleCount, pVisibleArgs ); 1195 pOldData->SetCallerPos( nCallerPos ); 1196 1197 if ( pFunctionList ) 1198 lcl_UpdateFunctionList( *pFunctionList, *pOldData ); 1199 1200 delete[] pVisibleArgs; 1201 } 1202 } 1203 } 1204 } 1205 } 1206 } 1207 } 1208 } 1209 1210 String ScUnoAddInCollection::FindFunction( const String& rUpperName, sal_Bool bLocalFirst ) 1211 { 1212 if (!bInitialized) 1213 Initialize(); 1214 1215 if (nFuncCount == 0) 1216 return EMPTY_STRING; 1217 1218 if ( bLocalFirst ) 1219 { 1220 // first scan all local names (used for entering formulas) 1221 1222 ScAddInHashMap::const_iterator iLook( pLocalHashMap->find( rUpperName ) ); 1223 if ( iLook != pLocalHashMap->end() ) 1224 return iLook->second->GetOriginalName(); 1225 1226 #if 0 1227 // after that, scan international names (really?) 1228 1229 iLook = pNameHashMap->find( rUpperName ); 1230 if ( iLook != pNameHashMap->end() ) 1231 return iLook->second->GetOriginalName(); 1232 #endif 1233 } 1234 else 1235 { 1236 // first scan international names (used when calling a function) 1237 //! before that, check for exact match??? 1238 1239 ScAddInHashMap::const_iterator iLook( pNameHashMap->find( rUpperName ) ); 1240 if ( iLook != pNameHashMap->end() ) 1241 return iLook->second->GetOriginalName(); 1242 1243 // after that, scan all local names (to allow replacing old AddIns with Uno) 1244 1245 iLook = pLocalHashMap->find( rUpperName ); 1246 if ( iLook != pLocalHashMap->end() ) 1247 return iLook->second->GetOriginalName(); 1248 } 1249 1250 return EMPTY_STRING; 1251 } 1252 1253 const ScUnoAddInFuncData* ScUnoAddInCollection::GetFuncData( const String& rName, bool bComplete ) 1254 { 1255 if (!bInitialized) 1256 Initialize(); 1257 1258 // rName must be the exact internal name 1259 1260 ScAddInHashMap::const_iterator iLook( pExactHashMap->find( rName ) ); 1261 if ( iLook != pExactHashMap->end() ) 1262 { 1263 const ScUnoAddInFuncData* pFuncData = iLook->second; 1264 1265 if ( bComplete && !pFuncData->GetFunction().is() ) //! extra flag? 1266 LoadComponent( *pFuncData ); 1267 1268 return pFuncData; 1269 } 1270 1271 return NULL; 1272 } 1273 1274 const ScUnoAddInFuncData* ScUnoAddInCollection::GetFuncData( long nIndex ) 1275 { 1276 if (!bInitialized) 1277 Initialize(); 1278 1279 if (nIndex < nFuncCount) 1280 return ppFuncData[nIndex]; 1281 return NULL; 1282 } 1283 1284 void ScUnoAddInCollection::LocalizeString( String& rName ) 1285 { 1286 if (!bInitialized) 1287 Initialize(); 1288 1289 // modify rName - input: exact name 1290 1291 ScAddInHashMap::const_iterator iLook( pExactHashMap->find( rName ) ); 1292 if ( iLook != pExactHashMap->end() ) 1293 rName = iLook->second->GetUpperLocal(); //! upper? 1294 } 1295 1296 1297 long ScUnoAddInCollection::GetFuncCount() 1298 { 1299 if (!bInitialized) 1300 Initialize(); 1301 1302 return nFuncCount; 1303 } 1304 1305 sal_Bool ScUnoAddInCollection::FillFunctionDesc( long nFunc, ScFuncDesc& rDesc ) 1306 { 1307 if (!bInitialized) 1308 Initialize(); 1309 1310 if (nFunc >= nFuncCount || !ppFuncData[nFunc]) 1311 return sal_False; 1312 1313 const ScUnoAddInFuncData& rFuncData = *ppFuncData[nFunc]; 1314 1315 return FillFunctionDescFromData( rFuncData, rDesc ); 1316 } 1317 1318 // static 1319 sal_Bool ScUnoAddInCollection::FillFunctionDescFromData( const ScUnoAddInFuncData& rFuncData, ScFuncDesc& rDesc ) 1320 { 1321 rDesc.Clear(); 1322 1323 sal_Bool bIncomplete = !rFuncData.GetFunction().is(); //! extra flag? 1324 1325 long nArgCount = rFuncData.GetArgumentCount(); 1326 if ( nArgCount > USHRT_MAX ) 1327 return sal_False; 1328 1329 if ( bIncomplete ) 1330 nArgCount = 0; // if incomplete, fill without argument info (no wrong order) 1331 1332 // nFIndex is set from outside 1333 1334 rDesc.pFuncName = new String( rFuncData.GetUpperLocal() ); //! upper? 1335 rDesc.nCategory = rFuncData.GetCategory(); 1336 rDesc.sHelpId = rFuncData.GetHelpId(); 1337 1338 String aDesc = rFuncData.GetDescription(); 1339 if (!aDesc.Len()) 1340 aDesc = rFuncData.GetLocalName(); // use name if no description is available 1341 rDesc.pFuncDesc = new String( aDesc ); 1342 1343 // AddInArgumentType_CALLER is already left out in FuncData 1344 1345 rDesc.nArgCount = (sal_uInt16)nArgCount; 1346 if ( nArgCount ) 1347 { 1348 sal_Bool bMultiple = sal_False; 1349 const ScAddInArgDesc* pArgs = rFuncData.GetArguments(); 1350 1351 rDesc.ppDefArgNames = new String*[nArgCount]; 1352 rDesc.ppDefArgDescs = new String*[nArgCount]; 1353 rDesc.pDefArgFlags = new ScFuncDesc::ParameterFlags[nArgCount]; 1354 for ( long nArg=0; nArg<nArgCount; nArg++ ) 1355 { 1356 rDesc.ppDefArgNames[nArg] = new String( pArgs[nArg].aName ); 1357 rDesc.ppDefArgDescs[nArg] = new String( pArgs[nArg].aDescription ); 1358 rDesc.pDefArgFlags[nArg].bOptional = pArgs[nArg].bOptional; 1359 rDesc.pDefArgFlags[nArg].bSuppress = false; 1360 1361 // no empty names... 1362 if ( rDesc.ppDefArgNames[nArg]->Len() == 0 ) 1363 { 1364 String aDefName( RTL_CONSTASCII_USTRINGPARAM("arg") ); 1365 aDefName += String::CreateFromInt32( nArg+1 ); 1366 *rDesc.ppDefArgNames[nArg] = aDefName; 1367 } 1368 1369 // last argument repeated? 1370 if ( nArg+1 == nArgCount && ( pArgs[nArg].eType == SC_ADDINARG_VARARGS ) ) 1371 bMultiple = sal_True; 1372 } 1373 1374 if ( bMultiple ) 1375 rDesc.nArgCount += VAR_ARGS - 1; // VAR_ARGS means just one repeated arg 1376 } 1377 1378 rDesc.bIncomplete = bIncomplete; 1379 1380 return sal_True; 1381 } 1382 1383 1384 //------------------------------------------------------------------------ 1385 1386 ScUnoAddInCall::ScUnoAddInCall( ScUnoAddInCollection& rColl, const String& rName, 1387 long nParamCount ) : 1388 bValidCount( sal_False ), 1389 nErrCode( errNoCode ), // before function was called 1390 bHasString( sal_True ), 1391 fValue( 0.0 ), 1392 xMatrix( NULL ) 1393 { 1394 pFuncData = rColl.GetFuncData( rName, true ); // need fully initialized data 1395 DBG_ASSERT( pFuncData, "Function Data missing" ); 1396 if ( pFuncData ) 1397 { 1398 long nDescCount = pFuncData->GetArgumentCount(); 1399 const ScAddInArgDesc* pArgs = pFuncData->GetArguments(); 1400 1401 // is aVarArg sequence needed? 1402 if ( nParamCount >= nDescCount && nDescCount > 0 && 1403 pArgs[nDescCount-1].eType == SC_ADDINARG_VARARGS ) 1404 { 1405 long nVarCount = nParamCount - ( nDescCount - 1 ); // size of last argument 1406 aVarArg.realloc( nVarCount ); 1407 bValidCount = sal_True; 1408 } 1409 else if ( nParamCount <= nDescCount ) 1410 { 1411 // all args behind nParamCount must be optional 1412 bValidCount = sal_True; 1413 for (long i=nParamCount; i<nDescCount; i++) 1414 if ( !pArgs[i].bOptional ) 1415 bValidCount = sal_False; 1416 } 1417 // else invalid (too many arguments) 1418 1419 if ( bValidCount ) 1420 aArgs.realloc( nDescCount ); // sequence must always match function signature 1421 } 1422 } 1423 1424 ScUnoAddInCall::~ScUnoAddInCall() 1425 { 1426 // pFuncData is deleted with ScUnoAddInCollection 1427 } 1428 1429 sal_Bool ScUnoAddInCall::ValidParamCount() 1430 { 1431 return bValidCount; 1432 } 1433 1434 ScAddInArgumentType ScUnoAddInCall::GetArgType( long nPos ) 1435 { 1436 if ( pFuncData ) 1437 { 1438 long nCount = pFuncData->GetArgumentCount(); 1439 const ScAddInArgDesc* pArgs = pFuncData->GetArguments(); 1440 1441 // if last arg is sequence, use "any" type 1442 if ( nCount > 0 && nPos >= nCount-1 && pArgs[nCount-1].eType == SC_ADDINARG_VARARGS ) 1443 return SC_ADDINARG_VALUE_OR_ARRAY; 1444 1445 if ( nPos < nCount ) 1446 return pArgs[nPos].eType; 1447 } 1448 return SC_ADDINARG_VALUE_OR_ARRAY; //! error code !!!! 1449 } 1450 1451 sal_Bool ScUnoAddInCall::NeedsCaller() const 1452 { 1453 return pFuncData && pFuncData->GetCallerPos() != SC_CALLERPOS_NONE; 1454 } 1455 1456 void ScUnoAddInCall::SetCaller( const uno::Reference<uno::XInterface>& rInterface ) 1457 { 1458 xCaller = rInterface; 1459 } 1460 1461 void ScUnoAddInCall::SetCallerFromObjectShell( SfxObjectShell* pObjSh ) 1462 { 1463 if (pObjSh) 1464 { 1465 uno::Reference<uno::XInterface> xInt( pObjSh->GetBaseModel(), uno::UNO_QUERY ); 1466 SetCaller( xInt ); 1467 } 1468 } 1469 1470 void ScUnoAddInCall::SetParam( long nPos, const uno::Any& rValue ) 1471 { 1472 if ( pFuncData ) 1473 { 1474 long nCount = pFuncData->GetArgumentCount(); 1475 const ScAddInArgDesc* pArgs = pFuncData->GetArguments(); 1476 if ( nCount > 0 && nPos >= nCount-1 && pArgs[nCount-1].eType == SC_ADDINARG_VARARGS ) 1477 { 1478 long nVarPos = nPos-(nCount-1); 1479 if ( nVarPos < aVarArg.getLength() ) 1480 aVarArg.getArray()[nVarPos] = rValue; 1481 else 1482 { 1483 DBG_ERROR("wrong argument number"); 1484 } 1485 } 1486 else if ( nPos < aArgs.getLength() ) 1487 aArgs.getArray()[nPos] = rValue; 1488 else 1489 { 1490 DBG_ERROR("wrong argument number"); 1491 } 1492 } 1493 } 1494 1495 void ScUnoAddInCall::ExecuteCall() 1496 { 1497 if ( !pFuncData ) 1498 return; 1499 1500 long nCount = pFuncData->GetArgumentCount(); 1501 const ScAddInArgDesc* pArgs = pFuncData->GetArguments(); 1502 if ( nCount > 0 && pArgs[nCount-1].eType == SC_ADDINARG_VARARGS ) 1503 { 1504 // insert aVarArg as last argument 1505 //! after inserting caller (to prevent copying twice)? 1506 1507 DBG_ASSERT( aArgs.getLength() == nCount, "wrong argument count" ); 1508 aArgs.getArray()[nCount-1] <<= aVarArg; 1509 } 1510 1511 if ( pFuncData->GetCallerPos() != SC_CALLERPOS_NONE ) 1512 { 1513 uno::Any aCallerAny; 1514 aCallerAny <<= xCaller; 1515 1516 long nUserLen = aArgs.getLength(); 1517 long nCallPos = pFuncData->GetCallerPos(); 1518 if (nCallPos>nUserLen) // should not happen 1519 { 1520 DBG_ERROR("wrong CallPos"); 1521 nCallPos = nUserLen; 1522 } 1523 1524 long nDestLen = nUserLen + 1; 1525 uno::Sequence<uno::Any> aRealArgs( nDestLen ); 1526 uno::Any* pDest = aRealArgs.getArray(); 1527 1528 const uno::Any* pSource = aArgs.getConstArray(); 1529 long nSrcPos = 0; 1530 1531 for ( long nDestPos = 0; nDestPos < nDestLen; nDestPos++ ) 1532 { 1533 if ( nDestPos == nCallPos ) 1534 pDest[nDestPos] = aCallerAny; 1535 else 1536 pDest[nDestPos] = pSource[nSrcPos++]; 1537 } 1538 1539 ExecuteCallWithArgs( aRealArgs ); 1540 } 1541 else 1542 ExecuteCallWithArgs( aArgs ); 1543 } 1544 1545 void ScUnoAddInCall::ExecuteCallWithArgs(uno::Sequence<uno::Any>& rCallArgs) 1546 { 1547 // rCallArgs may not match argument descriptions (because of caller) 1548 1549 uno::Reference<reflection::XIdlMethod> xFunction; 1550 uno::Any aObject; 1551 if ( pFuncData ) 1552 { 1553 xFunction = pFuncData->GetFunction(); 1554 aObject = pFuncData->GetObject(); 1555 } 1556 1557 if ( xFunction.is() ) 1558 { 1559 uno::Any aAny; 1560 nErrCode = 0; 1561 1562 try 1563 { 1564 aAny = xFunction->invoke( aObject, rCallArgs ); 1565 } 1566 catch(lang::IllegalArgumentException&) 1567 { 1568 nErrCode = errIllegalArgument; 1569 } 1570 #if 0 1571 catch(FloatingPointException&) 1572 { 1573 nErrCode = errIllegalFPOperation; 1574 } 1575 #endif 1576 catch(reflection::InvocationTargetException& rWrapped) 1577 { 1578 if ( rWrapped.TargetException.getValueType().equals( 1579 getCppuType( (lang::IllegalArgumentException*)0 ) ) ) 1580 nErrCode = errIllegalArgument; 1581 else if ( rWrapped.TargetException.getValueType().equals( 1582 getCppuType( (sheet::NoConvergenceException*)0 ) ) ) 1583 nErrCode = errNoConvergence; 1584 else 1585 nErrCode = errNoValue; 1586 } 1587 1588 catch(uno::Exception&) 1589 { 1590 nErrCode = errNoValue; 1591 } 1592 1593 if (!nErrCode) 1594 SetResult( aAny ); // convert result to Calc types 1595 } 1596 } 1597 1598 void ScUnoAddInCall::SetResult( const uno::Any& rNewRes ) 1599 { 1600 nErrCode = 0; 1601 xVarRes = NULL; 1602 1603 // Reflection* pRefl = rNewRes.getReflection(); 1604 1605 uno::TypeClass eClass = rNewRes.getValueTypeClass(); 1606 uno::Type aType = rNewRes.getValueType(); 1607 switch (eClass) 1608 { 1609 case uno::TypeClass_VOID: 1610 nErrCode = NOTAVAILABLE; // #NA 1611 break; 1612 1613 case uno::TypeClass_ENUM: 1614 case uno::TypeClass_BOOLEAN: 1615 case uno::TypeClass_CHAR: 1616 case uno::TypeClass_BYTE: 1617 case uno::TypeClass_SHORT: 1618 case uno::TypeClass_UNSIGNED_SHORT: 1619 case uno::TypeClass_LONG: 1620 case uno::TypeClass_UNSIGNED_LONG: 1621 case uno::TypeClass_FLOAT: 1622 case uno::TypeClass_DOUBLE: 1623 { 1624 uno::TypeClass eMyClass; 1625 ScApiTypeConversion::ConvertAnyToDouble( fValue, eMyClass, rNewRes); 1626 bHasString = sal_False; 1627 } 1628 break; 1629 1630 case uno::TypeClass_STRING: 1631 { 1632 rtl::OUString aUStr; 1633 rNewRes >>= aUStr; 1634 aString = String( aUStr ); 1635 bHasString = sal_True; 1636 } 1637 break; 1638 1639 case uno::TypeClass_INTERFACE: 1640 { 1641 //! directly extract XVolatileResult from any? 1642 uno::Reference<uno::XInterface> xInterface; 1643 rNewRes >>= xInterface; 1644 if ( xInterface.is() ) 1645 xVarRes = uno::Reference<sheet::XVolatileResult>( xInterface, uno::UNO_QUERY ); 1646 1647 if (!xVarRes.is()) 1648 nErrCode = errNoValue; // unknown interface 1649 } 1650 break; 1651 1652 default: 1653 if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<sal_Int32> > *)0 ) ) ) 1654 { 1655 const uno::Sequence< uno::Sequence<sal_Int32> >* pRowSeq = NULL; 1656 1657 //! use pointer from any! 1658 uno::Sequence< uno::Sequence<sal_Int32> > aSequence; 1659 if ( rNewRes >>= aSequence ) 1660 pRowSeq = &aSequence; 1661 1662 if ( pRowSeq ) 1663 { 1664 long nRowCount = pRowSeq->getLength(); 1665 const uno::Sequence<sal_Int32>* pRowArr = pRowSeq->getConstArray(); 1666 long nMaxColCount = 0; 1667 long nCol, nRow; 1668 for (nRow=0; nRow<nRowCount; nRow++) 1669 { 1670 long nTmp = pRowArr[nRow].getLength(); 1671 if ( nTmp > nMaxColCount ) 1672 nMaxColCount = nTmp; 1673 } 1674 if ( nMaxColCount && nRowCount ) 1675 { 1676 xMatrix = new ScMatrix( 1677 static_cast<SCSIZE>(nMaxColCount), 1678 static_cast<SCSIZE>(nRowCount) ); 1679 ScMatrix* pMatrix = xMatrix; 1680 for (nRow=0; nRow<nRowCount; nRow++) 1681 { 1682 long nColCount = pRowArr[nRow].getLength(); 1683 const sal_Int32* pColArr = pRowArr[nRow].getConstArray(); 1684 for (nCol=0; nCol<nColCount; nCol++) 1685 pMatrix->PutDouble( pColArr[nCol], 1686 static_cast<SCSIZE>(nCol), 1687 static_cast<SCSIZE>(nRow) ); 1688 for (nCol=nColCount; nCol<nMaxColCount; nCol++) 1689 pMatrix->PutDouble( 0.0, 1690 static_cast<SCSIZE>(nCol), 1691 static_cast<SCSIZE>(nRow) ); 1692 } 1693 } 1694 } 1695 } 1696 else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<double> > *)0 ) ) ) 1697 { 1698 const uno::Sequence< uno::Sequence<double> >* pRowSeq = NULL; 1699 1700 //! use pointer from any! 1701 uno::Sequence< uno::Sequence<double> > aSequence; 1702 if ( rNewRes >>= aSequence ) 1703 pRowSeq = &aSequence; 1704 1705 if ( pRowSeq ) 1706 { 1707 long nRowCount = pRowSeq->getLength(); 1708 const uno::Sequence<double>* pRowArr = pRowSeq->getConstArray(); 1709 long nMaxColCount = 0; 1710 long nCol, nRow; 1711 for (nRow=0; nRow<nRowCount; nRow++) 1712 { 1713 long nTmp = pRowArr[nRow].getLength(); 1714 if ( nTmp > nMaxColCount ) 1715 nMaxColCount = nTmp; 1716 } 1717 if ( nMaxColCount && nRowCount ) 1718 { 1719 xMatrix = new ScMatrix( 1720 static_cast<SCSIZE>(nMaxColCount), 1721 static_cast<SCSIZE>(nRowCount) ); 1722 ScMatrix* pMatrix = xMatrix; 1723 for (nRow=0; nRow<nRowCount; nRow++) 1724 { 1725 long nColCount = pRowArr[nRow].getLength(); 1726 const double* pColArr = pRowArr[nRow].getConstArray(); 1727 for (nCol=0; nCol<nColCount; nCol++) 1728 pMatrix->PutDouble( pColArr[nCol], 1729 static_cast<SCSIZE>(nCol), 1730 static_cast<SCSIZE>(nRow) ); 1731 for (nCol=nColCount; nCol<nMaxColCount; nCol++) 1732 pMatrix->PutDouble( 0.0, 1733 static_cast<SCSIZE>(nCol), 1734 static_cast<SCSIZE>(nRow) ); 1735 } 1736 } 1737 } 1738 } 1739 else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<rtl::OUString> > *)0 ) ) ) 1740 { 1741 const uno::Sequence< uno::Sequence<rtl::OUString> >* pRowSeq = NULL; 1742 1743 //! use pointer from any! 1744 uno::Sequence< uno::Sequence<rtl::OUString> > aSequence; 1745 if ( rNewRes >>= aSequence ) 1746 pRowSeq = &aSequence; 1747 1748 if ( pRowSeq ) 1749 { 1750 long nRowCount = pRowSeq->getLength(); 1751 const uno::Sequence<rtl::OUString>* pRowArr = pRowSeq->getConstArray(); 1752 long nMaxColCount = 0; 1753 long nCol, nRow; 1754 for (nRow=0; nRow<nRowCount; nRow++) 1755 { 1756 long nTmp = pRowArr[nRow].getLength(); 1757 if ( nTmp > nMaxColCount ) 1758 nMaxColCount = nTmp; 1759 } 1760 if ( nMaxColCount && nRowCount ) 1761 { 1762 xMatrix = new ScMatrix( 1763 static_cast<SCSIZE>(nMaxColCount), 1764 static_cast<SCSIZE>(nRowCount) ); 1765 ScMatrix* pMatrix = xMatrix; 1766 for (nRow=0; nRow<nRowCount; nRow++) 1767 { 1768 long nColCount = pRowArr[nRow].getLength(); 1769 const rtl::OUString* pColArr = pRowArr[nRow].getConstArray(); 1770 for (nCol=0; nCol<nColCount; nCol++) 1771 pMatrix->PutString( String( pColArr[nCol] ), 1772 static_cast<SCSIZE>(nCol), 1773 static_cast<SCSIZE>(nRow) ); 1774 for (nCol=nColCount; nCol<nMaxColCount; nCol++) 1775 pMatrix->PutString( EMPTY_STRING, 1776 static_cast<SCSIZE>(nCol), 1777 static_cast<SCSIZE>(nRow) ); 1778 } 1779 } 1780 } 1781 } 1782 else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<uno::Any> > *)0 ) ) ) 1783 { 1784 xMatrix = ScSequenceToMatrix::CreateMixedMatrix( rNewRes ); 1785 } 1786 1787 if (!xMatrix) // no array found 1788 nErrCode = errNoValue; //! code for error in return type??? 1789 } 1790 } 1791 1792 1793 1794 //------------------------------------------------------------------------ 1795 1796 1797 1798