Update ooo320-m1
[ooovba.git] / sc / source / core / tool / addincol.cxx
blob31f7fcd74ce6a827f1e7b743d8417d7e81f85cbc
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: addincol.cxx,v $
10 * $Revision: 1.27 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
36 #include <comphelper/processfactory.hxx>
37 #include <tools/debug.hxx>
38 #include <i18npool/mslangid.hxx>
39 #include <vcl/svapp.hxx>
40 #include <vos/xception.hxx>
41 #include <sfx2/objsh.hxx>
42 #include <unotools/charclass.hxx>
44 #include <com/sun/star/container/XContentEnumerationAccess.hpp>
45 #include <com/sun/star/lang/XServiceName.hpp>
46 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
47 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
48 #include <com/sun/star/reflection/XIdlClass.hpp>
49 #include <com/sun/star/reflection/XIdlClassProvider.hpp>
50 #include <com/sun/star/beans/XIntrospectionAccess.hpp>
51 #include <com/sun/star/beans/XIntrospection.hpp>
52 #include <com/sun/star/beans/MethodConcept.hpp>
53 #include <com/sun/star/beans/XPropertySet.hpp>
54 #include <com/sun/star/table/XCellRange.hpp>
55 #include <com/sun/star/lang/Locale.hpp>
56 #include <com/sun/star/sheet/XCompatibilityNames.hpp>
58 #include "addincol.hxx"
59 #include "addinhelpid.hxx"
60 #include "compiler.hxx"
61 #include "scmatrix.hxx"
62 #include "addinlis.hxx"
63 #include "formula/errorcodes.hxx"
64 #include "scfuncs.hrc"
65 #include "optutil.hxx"
66 #include "addincfg.hxx"
67 #include "scmod.hxx"
68 #include "rangeseq.hxx"
69 #include "funcdesc.hxx"
71 using namespace com::sun::star;
73 //------------------------------------------------------------------------
75 #define SC_CALLERPOS_NONE (-1)
77 #define SCADDINSUPPLIER_SERVICE "com.sun.star.sheet.AddIn"
79 //------------------------------------------------------------------------
84 //------------------------------------------------------------------------
86 ScUnoAddInFuncData::ScUnoAddInFuncData( const String& rNam, const String& rLoc,
87 const String& rDesc,
88 USHORT nCat, USHORT nHelp,
89 const uno::Reference<reflection::XIdlMethod>& rFunc,
90 const uno::Any& rO,
91 long nAC, const ScAddInArgDesc* pAD,
92 long nCP ) :
93 aOriginalName( rNam ),
94 aLocalName( rLoc ),
95 aUpperName( rNam ),
96 aUpperLocal( rLoc ),
97 aDescription( rDesc ),
98 xFunction( rFunc ),
99 aObject( rO ),
100 nArgCount( nAC ),
101 nCallerPos( nCP ),
102 nCategory( nCat ),
103 nHelpId( nHelp ),
104 bCompInitialized( FALSE )
106 if ( nArgCount )
108 pArgDescs = new ScAddInArgDesc[nArgCount];
109 for (long i=0; i<nArgCount; i++)
110 pArgDescs[i] = pAD[i];
112 else
113 pArgDescs = NULL;
115 ScGlobal::pCharClass->toUpper(aUpperName);
116 ScGlobal::pCharClass->toUpper(aUpperLocal);
119 ScUnoAddInFuncData::~ScUnoAddInFuncData()
121 delete[] pArgDescs;
124 const uno::Sequence<sheet::LocalizedName>& ScUnoAddInFuncData::GetCompNames() const
126 if ( !bCompInitialized )
128 // read sequence of compatibility names on demand
130 uno::Reference<sheet::XAddIn> xAddIn;
131 if ( aObject >>= xAddIn )
133 uno::Reference<sheet::XCompatibilityNames> xComp( xAddIn, uno::UNO_QUERY );
134 if ( xComp.is() && xFunction.is() )
136 rtl::OUString aMethodName = xFunction->getName();
137 aCompNames = xComp->getCompatibilityNames( aMethodName );
139 // change all locale entries to default case
140 // (language in lower case, country in upper case)
141 // for easier searching
143 long nSeqLen = aCompNames.getLength();
144 if ( nSeqLen )
146 sheet::LocalizedName* pArray = aCompNames.getArray();
147 for (long i=0; i<nSeqLen; i++)
149 lang::Locale& rLocale = pArray[i].Locale;
150 rLocale.Language = rLocale.Language.toAsciiLowerCase();
151 rLocale.Country = rLocale.Country.toAsciiUpperCase();
157 bCompInitialized = TRUE; // also if not successful
159 return aCompNames;
162 void ScUnoAddInFuncData::SetCompNames( const uno::Sequence< sheet::LocalizedName>& rNew )
164 DBG_ASSERT( !bCompInitialized, "SetCompNames after initializing" );
166 aCompNames = rNew;
168 // change all locale entries to default case
169 // (language in lower case, country in upper case)
170 // for easier searching
172 long nSeqLen = aCompNames.getLength();
173 if ( nSeqLen )
175 sheet::LocalizedName* pArray = aCompNames.getArray();
176 for (long i=0; i<nSeqLen; i++)
178 lang::Locale& rLocale = pArray[i].Locale;
179 rLocale.Language = rLocale.Language.toAsciiLowerCase();
180 rLocale.Country = rLocale.Country.toAsciiUpperCase();
184 bCompInitialized = TRUE;
187 BOOL ScUnoAddInFuncData::GetExcelName( LanguageType eDestLang, String& rRetExcelName ) const
189 const uno::Sequence<sheet::LocalizedName>& rSequence = GetCompNames();
190 long nSeqLen = rSequence.getLength();
191 if ( nSeqLen )
193 const sheet::LocalizedName* pArray = rSequence.getConstArray();
194 long i;
196 rtl::OUString aLangStr, aCountryStr;
197 MsLangId::convertLanguageToIsoNames( eDestLang, aLangStr, aCountryStr );
198 rtl::OUString aUserLang = aLangStr.toAsciiLowerCase();
199 rtl::OUString aUserCountry = aCountryStr.toAsciiUpperCase();
201 // first check for match of both language and country
203 for ( i=0; i<nSeqLen; i++)
204 if ( pArray[i].Locale.Language == aUserLang &&
205 pArray[i].Locale.Country == aUserCountry )
207 rRetExcelName = pArray[i].Name;
208 return TRUE;
211 // second: check only language
213 for ( i=0; i<nSeqLen; i++)
214 if ( pArray[i].Locale.Language == aUserLang )
216 rRetExcelName = pArray[i].Name;
217 return TRUE;
220 // third: #i57772# fall-back to en-US
222 if ( eDestLang != LANGUAGE_ENGLISH_US )
223 return GetExcelName( LANGUAGE_ENGLISH_US, rRetExcelName );
225 // forth: use first (default) entry
227 rRetExcelName = pArray[0].Name;
228 return TRUE;
230 return FALSE;
233 void ScUnoAddInFuncData::SetFunction( const uno::Reference< reflection::XIdlMethod>& rNewFunc, const uno::Any& rNewObj )
235 xFunction = rNewFunc;
236 aObject = rNewObj;
239 void ScUnoAddInFuncData::SetArguments( long nNewCount, const ScAddInArgDesc* pNewDescs )
241 delete[] pArgDescs;
243 nArgCount = nNewCount;
244 if ( nArgCount )
246 pArgDescs = new ScAddInArgDesc[nArgCount];
247 for (long i=0; i<nArgCount; i++)
248 pArgDescs[i] = pNewDescs[i];
250 else
251 pArgDescs = NULL;
254 void ScUnoAddInFuncData::SetCallerPos( long nNewPos )
256 nCallerPos = nNewPos;
259 //------------------------------------------------------------------------
261 ScUnoAddInCollection::ScUnoAddInCollection() :
262 nFuncCount( 0 ),
263 ppFuncData( NULL ),
264 pExactHashMap( NULL ),
265 pNameHashMap( NULL ),
266 pLocalHashMap( NULL ),
267 bInitialized( FALSE )
271 ScUnoAddInCollection::~ScUnoAddInCollection()
273 Clear();
276 void ScUnoAddInCollection::Clear()
278 DELETEZ( pExactHashMap );
279 DELETEZ( pNameHashMap );
280 DELETEZ( pLocalHashMap );
281 if ( ppFuncData )
283 for ( long i=0; i<nFuncCount; i++ )
284 delete ppFuncData[i];
285 delete[] ppFuncData;
287 ppFuncData = NULL;
288 nFuncCount = 0;
290 bInitialized = FALSE;
293 uno::Reference<uno::XComponentContext> getContext(uno::Reference<lang::XMultiServiceFactory> xMSF)
295 uno::Reference<uno::XComponentContext> xCtx;
296 try {
297 uno::Reference<beans::XPropertySet> xPropset(xMSF, uno::UNO_QUERY);
298 xPropset->getPropertyValue(
299 ::rtl::OUString::createFromAscii("DefaultContext")) >>= xCtx;
301 catch ( uno::Exception & ) {
303 return xCtx;
306 void ScUnoAddInCollection::Initialize()
308 DBG_ASSERT( !bInitialized, "Initialize twice?" );
310 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
311 uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
312 if ( xEnAc.is() )
314 uno::Reference<container::XEnumeration> xEnum =
315 xEnAc->createContentEnumeration(
316 rtl::OUString::createFromAscii(SCADDINSUPPLIER_SERVICE) );
317 if ( xEnum.is() )
319 // loop through all AddIns
320 while ( xEnum->hasMoreElements() )
322 uno::Any aAddInAny = xEnum->nextElement();
323 //? if ( aAddInAny.getReflection()->getTypeClass() == uno::TypeClass_INTERFACE )
325 uno::Reference<uno::XInterface> xIntFac;
326 aAddInAny >>= xIntFac;
327 if ( xIntFac.is() )
329 // #i59984# try XSingleComponentFactory in addition to (old) XSingleServiceFactory,
330 // passing the context to the component
332 uno::Reference<uno::XInterface> xInterface;
333 uno::Reference<uno::XComponentContext> xCtx = getContext(xManager);
334 uno::Reference<lang::XSingleComponentFactory> xCFac( xIntFac, uno::UNO_QUERY );
335 if (xCtx.is() && xCFac.is())
337 xInterface = xCFac->createInstanceWithContext(xCtx);
338 if (xInterface.is())
339 ReadFromAddIn( xInterface );
342 if (!xInterface.is())
344 uno::Reference<lang::XSingleServiceFactory> xFac( xIntFac, uno::UNO_QUERY );
345 if ( xFac.is() )
347 xInterface = xFac->createInstance();
348 if (xInterface.is())
349 ReadFromAddIn( xInterface );
358 // ReadConfiguration is called after looking at the AddIn implementations.
359 // Duplicated are skipped (by using the service information, they don't have to be updated again
360 // when argument information is needed).
361 ReadConfiguration();
363 bInitialized = TRUE; // with or without functions
365 // -----------------------------------------------------------------------------
367 USHORT lcl_GetCategory( const String& rName )
369 static const sal_Char* aFuncNames[SC_FUNCGROUP_COUNT] =
371 // array index = ID - 1 (ID starts at 1)
372 // all upper case
373 "Database", // ID_FUNCTION_GRP_DATABASE
374 "Date&Time", // ID_FUNCTION_GRP_DATETIME
375 "Financial", // ID_FUNCTION_GRP_FINANZ
376 "Information", // ID_FUNCTION_GRP_INFO
377 "Logical", // ID_FUNCTION_GRP_LOGIC
378 "Mathematical", // ID_FUNCTION_GRP_MATH
379 "Matrix", // ID_FUNCTION_GRP_MATRIX
380 "Statistical", // ID_FUNCTION_GRP_STATISTIC
381 "Spreadsheet", // ID_FUNCTION_GRP_TABLE
382 "Text", // ID_FUNCTION_GRP_TEXT
383 "Add-In" // ID_FUNCTION_GRP_ADDINS
385 for (USHORT i=0; i<SC_FUNCGROUP_COUNT; i++)
386 if ( rName.EqualsAscii( aFuncNames[i] ) )
387 return i+1; // IDs start at 1
389 return ID_FUNCTION_GRP_ADDINS; // if not found, use Add-In group
393 #define CFGPATH_ADDINS "Office.CalcAddIns/AddInInfo"
394 #define CFGSTR_ADDINFUNCTIONS "AddInFunctions"
396 #define CFG_FUNCPROP_DISPLAYNAME 0
397 #define CFG_FUNCPROP_DESCRIPTION 1
398 #define CFG_FUNCPROP_CATEGORY 2
399 #define CFG_FUNCPROP_COUNT 3
400 #define CFGSTR_DISPLAYNAME "DisplayName"
401 #define CFGSTR_DESCRIPTION "Description"
402 #define CFGSTR_CATEGORY "Category"
403 // CategoryDisplayName is ignored for now
405 #define CFGSTR_COMPATIBILITYNAME "CompatibilityName"
406 #define CFGSTR_PARAMETERS "Parameters"
409 void ScUnoAddInCollection::ReadConfiguration()
411 // called only from Initialize
413 ScAddInCfg& rAddInConfig = SC_MOD()->GetAddInCfg();
415 // additional, temporary config item for the compatibility names
416 ScLinkConfigItem aAllLocalesConfig( rtl::OUString::createFromAscii( CFGPATH_ADDINS ), CONFIG_MODE_ALL_LOCALES );
417 // CommitLink is not used (only reading values)
419 const rtl::OUString sSlash('/');
421 // get the list of add-ins (services)
422 rtl::OUString aEmptyString;
423 uno::Sequence<rtl::OUString> aServiceNames = rAddInConfig.GetNodeNames( aEmptyString );
425 sal_Int32 nServiceCount = aServiceNames.getLength();
426 for ( sal_Int32 nService = 0; nService < nServiceCount; nService++ )
428 rtl::OUString aServiceName = aServiceNames[nService];
429 ScUnoAddInHelpIdGenerator aHelpIdGenerator( aServiceName );
431 rtl::OUString aFunctionsPath = aServiceName;
432 aFunctionsPath += sSlash;
433 aFunctionsPath += rtl::OUString::createFromAscii( CFGSTR_ADDINFUNCTIONS );
435 uno::Sequence<rtl::OUString> aFunctionNames = rAddInConfig.GetNodeNames( aFunctionsPath );
436 sal_Int32 nNewCount = aFunctionNames.getLength();
438 // allocate pointers
440 long nOld = nFuncCount;
441 nFuncCount = nNewCount+nOld;
442 if ( nOld )
444 ScUnoAddInFuncData** ppNew = new ScUnoAddInFuncData*[nFuncCount];
445 for (long i=0; i<nOld; i++)
446 ppNew[i] = ppFuncData[i];
447 delete[] ppFuncData;
448 ppFuncData = ppNew;
450 else
451 ppFuncData = new ScUnoAddInFuncData*[nFuncCount];
453 //! TODO: adjust bucket count?
454 if ( !pExactHashMap )
455 pExactHashMap = new ScAddInHashMap;
456 if ( !pNameHashMap )
457 pNameHashMap = new ScAddInHashMap;
458 if ( !pLocalHashMap )
459 pLocalHashMap = new ScAddInHashMap;
461 //! get the function information in a single call for all functions?
463 const rtl::OUString* pFuncNameArray = aFunctionNames.getConstArray();
464 for ( sal_Int32 nFuncPos = 0; nFuncPos < nNewCount; nFuncPos++ )
466 ppFuncData[nFuncPos+nOld] = NULL;
468 // stored function name: (service name).(function)
469 String aFuncName( aServiceName );
470 aFuncName += '.';
471 aFuncName += String( pFuncNameArray[nFuncPos] );
473 // skip the function if already known (read from old AddIn service)
475 if ( pExactHashMap->find( aFuncName ) == pExactHashMap->end() )
477 rtl::OUString aLocalName;
478 rtl::OUString aDescription;
479 USHORT nCategory = ID_FUNCTION_GRP_ADDINS;
481 // get direct information on the function
483 rtl::OUString aFuncPropPath = aFunctionsPath;
484 aFuncPropPath += sSlash;
485 aFuncPropPath += pFuncNameArray[nFuncPos];
486 aFuncPropPath += sSlash;
488 uno::Sequence<rtl::OUString> aFuncPropNames(CFG_FUNCPROP_COUNT);
489 rtl::OUString* pNameArray = aFuncPropNames.getArray();
490 pNameArray[CFG_FUNCPROP_DISPLAYNAME] = aFuncPropPath;
491 pNameArray[CFG_FUNCPROP_DISPLAYNAME] += rtl::OUString::createFromAscii( CFGSTR_DISPLAYNAME );
492 pNameArray[CFG_FUNCPROP_DESCRIPTION] = aFuncPropPath;
493 pNameArray[CFG_FUNCPROP_DESCRIPTION] += rtl::OUString::createFromAscii( CFGSTR_DESCRIPTION );
494 pNameArray[CFG_FUNCPROP_CATEGORY] = aFuncPropPath;
495 pNameArray[CFG_FUNCPROP_CATEGORY] += rtl::OUString::createFromAscii( CFGSTR_CATEGORY );
497 uno::Sequence<uno::Any> aFuncProperties = rAddInConfig.GetProperties( aFuncPropNames );
498 if ( aFuncProperties.getLength() == CFG_FUNCPROP_COUNT )
500 aFuncProperties[CFG_FUNCPROP_DISPLAYNAME] >>= aLocalName;
501 aFuncProperties[CFG_FUNCPROP_DESCRIPTION] >>= aDescription;
503 rtl::OUString aCategoryName;
504 aFuncProperties[CFG_FUNCPROP_CATEGORY] >>= aCategoryName;
505 nCategory = lcl_GetCategory( aCategoryName );
508 // get compatibility names
510 uno::Sequence<sheet::LocalizedName> aCompNames;
512 rtl::OUString aCompPath = aFuncPropPath;
513 aCompPath += rtl::OUString::createFromAscii( CFGSTR_COMPATIBILITYNAME );
514 uno::Sequence<rtl::OUString> aCompPropNames( &aCompPath, 1 );
516 uno::Sequence<uno::Any> aCompProperties = aAllLocalesConfig.GetProperties( aCompPropNames );
517 if ( aCompProperties.getLength() == 1 )
519 uno::Sequence<beans::PropertyValue> aLocalEntries;
520 if ( aCompProperties[0] >>= aLocalEntries )
522 sal_Int32 nLocaleCount = aLocalEntries.getLength();
523 aCompNames.realloc( nLocaleCount );
524 const beans::PropertyValue* pConfigArray = aLocalEntries.getConstArray();
525 sheet::LocalizedName* pCompArray = aCompNames.getArray();
527 for ( sal_Int32 nLocale = 0; nLocale < nLocaleCount; nLocale++ )
529 const sal_Unicode cLocaleSep = '-'; // separator in configuration locale strings
531 // PropertyValue name is the locale (convert from string to Locale struct)
533 const rtl::OUString& rLocaleStr = pConfigArray[nLocale].Name;
534 lang::Locale& rLocale = pCompArray[nLocale].Locale;
535 sal_Int32 nSepPos = rLocaleStr.indexOf( cLocaleSep );
536 if ( nSepPos >= 0 )
538 rLocale.Language = rLocaleStr.copy( 0, nSepPos );
539 rLocale.Country = rLocaleStr.copy( nSepPos+1 );
541 else
542 rLocale.Language = rLocaleStr; // leave country empty (default ctor from sequence)
544 // PropertyValue value is the localized value (string in this case)
546 pConfigArray[nLocale].Value >>= pCompArray[nLocale].Name;
551 // get argument info
553 ScAddInArgDesc* pVisibleArgs = NULL;
554 long nVisibleCount = 0;
555 long nCallerPos = SC_CALLERPOS_NONE;
557 rtl::OUString aArgumentsPath = aFuncPropPath;
558 aArgumentsPath += rtl::OUString::createFromAscii( CFGSTR_PARAMETERS );
560 uno::Sequence<rtl::OUString> aArgumentNames = rAddInConfig.GetNodeNames( aArgumentsPath );
561 sal_Int32 nArgumentCount = aArgumentNames.getLength();
562 if ( nArgumentCount )
564 // get DisplayName and Description for each argument
565 uno::Sequence<rtl::OUString> aArgPropNames( nArgumentCount * 2 );
566 rtl::OUString* pPropNameArray = aArgPropNames.getArray();
568 sal_Int32 nArgument;
569 sal_Int32 nIndex = 0;
570 const rtl::OUString* pArgNameArray = aArgumentNames.getConstArray();
571 for ( nArgument = 0; nArgument < nArgumentCount; nArgument++ )
573 rtl::OUString aOneArgPath = aArgumentsPath;
574 aOneArgPath += sSlash;
575 aOneArgPath += pArgNameArray[nArgument];
576 aOneArgPath += sSlash;
578 pPropNameArray[nIndex] = aOneArgPath;
579 pPropNameArray[nIndex++] += rtl::OUString::createFromAscii( CFGSTR_DISPLAYNAME );
580 pPropNameArray[nIndex] = aOneArgPath;
581 pPropNameArray[nIndex++] += rtl::OUString::createFromAscii( CFGSTR_DESCRIPTION );
584 uno::Sequence<uno::Any> aArgProperties = rAddInConfig.GetProperties( aArgPropNames );
585 if ( aArgProperties.getLength() == aArgPropNames.getLength() )
587 const uno::Any* pPropArray = aArgProperties.getConstArray();
588 rtl::OUString sDisplayName;
589 rtl::OUString sDescription;
591 ScAddInArgDesc aDesc;
592 aDesc.eType = SC_ADDINARG_NONE; // arg type is not in configuration
593 aDesc.bOptional = FALSE;
595 nVisibleCount = nArgumentCount;
596 pVisibleArgs = new ScAddInArgDesc[nVisibleCount];
598 nIndex = 0;
599 for ( nArgument = 0; nArgument < nArgumentCount; nArgument++ )
601 pPropArray[nIndex++] >>= sDisplayName;
602 pPropArray[nIndex++] >>= sDescription;
604 aDesc.aInternalName = pArgNameArray[nArgument];
605 aDesc.aName = sDisplayName;
606 aDesc.aDescription = sDescription;
608 pVisibleArgs[nArgument] = aDesc;
613 USHORT nHelpId = aHelpIdGenerator.GetHelpId( pFuncNameArray[nFuncPos] );
615 uno::Reference<reflection::XIdlMethod> xFunc; // remains empty
616 uno::Any aObject; // also empty
618 // create and insert into the array
620 ScUnoAddInFuncData* pData = new ScUnoAddInFuncData(
621 aFuncName, aLocalName, aDescription,
622 nCategory, nHelpId,
623 xFunc, aObject,
624 nVisibleCount, pVisibleArgs, nCallerPos );
626 pData->SetCompNames( aCompNames );
628 ppFuncData[nFuncPos+nOld] = pData;
630 pExactHashMap->insert(
631 ScAddInHashMap::value_type(
632 pData->GetOriginalName(),
633 pData ) );
634 pNameHashMap->insert(
635 ScAddInHashMap::value_type(
636 pData->GetUpperName(),
637 pData ) );
638 pLocalHashMap->insert(
639 ScAddInHashMap::value_type(
640 pData->GetUpperLocal(),
641 pData ) );
643 delete[] pVisibleArgs;
649 void ScUnoAddInCollection::LoadComponent( const ScUnoAddInFuncData& rFuncData )
651 String aFullName = rFuncData.GetOriginalName();
652 xub_StrLen nPos = aFullName.SearchBackward( (sal_Unicode) '.' );
653 if ( nPos != STRING_NOTFOUND && nPos > 0 )
655 String aServiceName = aFullName.Copy( 0, nPos );
657 uno::Reference<lang::XMultiServiceFactory> xServiceFactory = comphelper::getProcessServiceFactory();
658 uno::Reference<uno::XInterface> xInterface( xServiceFactory->createInstance( aServiceName ) );
660 if (xInterface.is())
661 UpdateFromAddIn( xInterface, aServiceName );
665 BOOL ScUnoAddInCollection::GetExcelName( const String& rCalcName,
666 LanguageType eDestLang, String& rRetExcelName )
668 const ScUnoAddInFuncData* pFuncData = GetFuncData( rCalcName );
669 if ( pFuncData )
670 return pFuncData->GetExcelName( eDestLang, rRetExcelName);
671 return FALSE;
674 BOOL ScUnoAddInCollection::GetCalcName( const String& rExcelName, String& rRetCalcName )
676 if (!bInitialized)
677 Initialize();
679 String aUpperCmp = rExcelName;
680 ScGlobal::pCharClass->toUpper(aUpperCmp);
682 for (long i=0; i<nFuncCount; i++)
684 ScUnoAddInFuncData* pFuncData = ppFuncData[i];
685 if ( pFuncData )
687 const uno::Sequence<sheet::LocalizedName>& rSequence = pFuncData->GetCompNames();
688 long nSeqLen = rSequence.getLength();
689 if ( nSeqLen )
691 const sheet::LocalizedName* pArray = rSequence.getConstArray();
692 for ( long nName=0; nName<nSeqLen; nName++)
693 if ( ScGlobal::pCharClass->upper( pArray[nName].Name ) == aUpperCmp )
695 //! store upper case for comparing?
697 // use the first function that has this name for any language
698 rRetCalcName = pFuncData->GetOriginalName();
699 return TRUE;
704 return FALSE;
707 inline BOOL IsTypeName( const rtl::OUString& rName, const uno::Type& rType )
709 return rName == rType.getTypeName();
712 BOOL lcl_ValidReturnType( const uno::Reference<reflection::XIdlClass>& xClass )
714 // this must match with ScUnoAddInCall::SetResult
716 if ( !xClass.is() ) return FALSE;
718 switch (xClass->getTypeClass())
720 // case uno::TypeClass_VOID:
721 // ???
723 case uno::TypeClass_ANY: // variable type
724 case uno::TypeClass_ENUM: //! ???
725 case uno::TypeClass_BOOLEAN:
726 case uno::TypeClass_CHAR:
727 case uno::TypeClass_BYTE:
728 case uno::TypeClass_SHORT:
729 case uno::TypeClass_UNSIGNED_SHORT:
730 case uno::TypeClass_LONG:
731 case uno::TypeClass_UNSIGNED_LONG:
732 case uno::TypeClass_FLOAT:
733 case uno::TypeClass_DOUBLE:
734 case uno::TypeClass_STRING:
735 return TRUE; // values or string
737 case uno::TypeClass_INTERFACE:
739 // return type XInterface may contain a XVolatileResult
740 //! XIdlClass needs getType() method!
742 rtl::OUString sName = xClass->getName();
743 return (
744 IsTypeName( sName, getCppuType((uno::Reference<sheet::XVolatileResult>*)0) ) ||
745 IsTypeName( sName, getCppuType((uno::Reference<uno::XInterface>*)0) ) );
748 default:
750 // nested sequences for arrays
751 //! XIdlClass needs getType() method!
753 rtl::OUString sName = xClass->getName();
754 return (
755 IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<INT32> >*)0) ) ||
756 IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<double> >*)0) ) ||
757 IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<rtl::OUString> >*)0) ) ||
758 IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<uno::Any> >*)0) ) );
761 return FALSE;
764 ScAddInArgumentType lcl_GetArgType( const uno::Reference<reflection::XIdlClass>& xClass )
766 if (!xClass.is())
767 return SC_ADDINARG_NONE;
769 uno::TypeClass eType = xClass->getTypeClass();
771 if ( eType == uno::TypeClass_LONG ) //! other integer types?
772 return SC_ADDINARG_INTEGER;
774 if ( eType == uno::TypeClass_DOUBLE )
775 return SC_ADDINARG_DOUBLE;
777 if ( eType == uno::TypeClass_STRING )
778 return SC_ADDINARG_STRING;
780 //! XIdlClass needs getType() method!
781 rtl::OUString sName = xClass->getName();
783 if (IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<INT32> >*)0) ))
784 return SC_ADDINARG_INTEGER_ARRAY;
786 if (IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<double> >*)0) ))
787 return SC_ADDINARG_DOUBLE_ARRAY;
789 if (IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<rtl::OUString> >*)0) ))
790 return SC_ADDINARG_STRING_ARRAY;
792 if (IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<uno::Any> >*)0) ))
793 return SC_ADDINARG_MIXED_ARRAY;
795 if (IsTypeName( sName, getCppuType((uno::Any*)0) ))
796 return SC_ADDINARG_VALUE_OR_ARRAY;
798 if (IsTypeName( sName, getCppuType((uno::Reference<table::XCellRange>*)0) ))
799 return SC_ADDINARG_CELLRANGE;
801 if (IsTypeName( sName, getCppuType((uno::Reference<beans::XPropertySet>*)0) ))
802 return SC_ADDINARG_CALLER;
804 if (IsTypeName( sName, getCppuType((uno::Sequence<uno::Any>*)0) ))
805 return SC_ADDINARG_VARARGS;
807 return SC_ADDINARG_NONE;
810 void ScUnoAddInCollection::ReadFromAddIn( const uno::Reference<uno::XInterface>& xInterface )
812 uno::Reference<sheet::XAddIn> xAddIn( xInterface, uno::UNO_QUERY );
813 uno::Reference<lang::XServiceName> xName( xInterface, uno::UNO_QUERY );
814 if ( xAddIn.is() && xName.is() )
816 // AddIns must use the language for which the office is installed
817 LanguageType eOfficeLang = Application::GetSettings().GetUILanguage();
819 lang::Locale aLocale( MsLangId::convertLanguageToLocale( eOfficeLang ));
820 xAddIn->setLocale( aLocale );
822 String aServiceName = String( xName->getServiceName() );
823 ScUnoAddInHelpIdGenerator aHelpIdGenerator( xName->getServiceName() );
825 //! pass XIntrospection to ReadFromAddIn
827 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
828 if ( xManager.is() )
830 uno::Reference<beans::XIntrospection> xIntro(
831 xManager->createInstance(rtl::OUString::createFromAscii(
832 "com.sun.star.beans.Introspection" )),
833 uno::UNO_QUERY );
834 if ( xIntro.is() )
836 uno::Any aObject;
837 aObject <<= xAddIn;
838 uno::Reference<beans::XIntrospectionAccess> xAcc = xIntro->inspect(aObject);
839 if (xAcc.is())
841 uno::Sequence< uno::Reference<reflection::XIdlMethod> > aMethods =
842 xAcc->getMethods( beans::MethodConcept::ALL );
843 long nNewCount = aMethods.getLength();
844 if ( nNewCount )
846 long nOld = nFuncCount;
847 nFuncCount = nNewCount+nOld;
848 if ( nOld )
850 ScUnoAddInFuncData** ppNew = new ScUnoAddInFuncData*[nFuncCount];
851 for (long i=0; i<nOld; i++)
852 ppNew[i] = ppFuncData[i];
853 delete[] ppFuncData;
854 ppFuncData = ppNew;
856 else
857 ppFuncData = new ScUnoAddInFuncData*[nFuncCount];
859 //! TODO: adjust bucket count?
860 if ( !pExactHashMap )
861 pExactHashMap = new ScAddInHashMap;
862 if ( !pNameHashMap )
863 pNameHashMap = new ScAddInHashMap;
864 if ( !pLocalHashMap )
865 pLocalHashMap = new ScAddInHashMap;
867 const uno::Reference<reflection::XIdlMethod>* pArray = aMethods.getConstArray();
868 for (long nFuncPos=0; nFuncPos<nNewCount; nFuncPos++)
870 ppFuncData[nFuncPos+nOld] = NULL;
872 uno::Reference<reflection::XIdlMethod> xFunc = pArray[nFuncPos];
873 if (xFunc.is())
875 // leave out internal functions
876 uno::Reference<reflection::XIdlClass> xClass =
877 xFunc->getDeclaringClass();
878 BOOL bSkip = TRUE;
879 if ( xClass.is() )
881 //! XIdlClass needs getType() method!
882 rtl::OUString sName = xClass->getName();
883 bSkip = (
884 IsTypeName( sName,
885 getCppuType((uno::Reference<uno::XInterface>*)0) ) ||
886 IsTypeName( sName,
887 getCppuType((uno::Reference<reflection::XIdlClassProvider>*)0) ) ||
888 IsTypeName( sName,
889 getCppuType((uno::Reference<lang::XServiceName>*)0) ) ||
890 IsTypeName( sName,
891 getCppuType((uno::Reference<lang::XServiceInfo>*)0) ) ||
892 IsTypeName( sName,
893 getCppuType((uno::Reference<sheet::XAddIn>*)0) ) );
895 if (!bSkip)
897 uno::Reference<reflection::XIdlClass> xReturn =
898 xFunc->getReturnType();
899 if ( !lcl_ValidReturnType( xReturn ) )
900 bSkip = TRUE;
902 if (!bSkip)
904 rtl::OUString aFuncU = xFunc->getName();
906 // stored function name: (service name).(function)
907 String aFuncName = aServiceName;
908 aFuncName += '.';
909 aFuncName += String( aFuncU );
911 BOOL bValid = TRUE;
912 long nVisibleCount = 0;
913 long nCallerPos = SC_CALLERPOS_NONE;
915 uno::Sequence<reflection::ParamInfo> aParams =
916 xFunc->getParameterInfos();
917 long nParamCount = aParams.getLength();
918 const reflection::ParamInfo* pParArr = aParams.getConstArray();
919 long nParamPos;
920 for (nParamPos=0; nParamPos<nParamCount; nParamPos++)
922 if ( pParArr[nParamPos].aMode != reflection::ParamMode_IN )
923 bValid = FALSE;
924 uno::Reference<reflection::XIdlClass> xParClass =
925 pParArr[nParamPos].aType;
926 ScAddInArgumentType eArgType = lcl_GetArgType( xParClass );
927 if ( eArgType == SC_ADDINARG_NONE )
928 bValid = FALSE;
929 else if ( eArgType == SC_ADDINARG_CALLER )
930 nCallerPos = nParamPos;
931 else
932 ++nVisibleCount;
934 if (bValid)
936 USHORT nCategory = lcl_GetCategory(
937 String(
938 xAddIn->getProgrammaticCategoryName(
939 aFuncU ) ) );
941 USHORT nHelpId = aHelpIdGenerator.GetHelpId( aFuncU );
943 rtl::OUString aLocalU;
946 aLocalU = xAddIn->
947 getDisplayFunctionName( aFuncU );
949 catch(uno::Exception&)
951 aLocalU = rtl::OUString::createFromAscii( "###" );
953 String aLocalName = String( aLocalU );
955 rtl::OUString aDescU;
958 aDescU = xAddIn->
959 getFunctionDescription( aFuncU );
961 catch(uno::Exception&)
963 aDescU = rtl::OUString::createFromAscii( "###" );
965 String aDescription = String( aDescU );
967 ScAddInArgDesc* pVisibleArgs = NULL;
968 if ( nVisibleCount > 0 )
970 ScAddInArgDesc aDesc;
971 pVisibleArgs = new ScAddInArgDesc[nVisibleCount];
972 long nDestPos = 0;
973 for (nParamPos=0; nParamPos<nParamCount; nParamPos++)
975 uno::Reference<reflection::XIdlClass> xParClass =
976 pParArr[nParamPos].aType;
977 ScAddInArgumentType eArgType = lcl_GetArgType( xParClass );
978 if ( eArgType != SC_ADDINARG_CALLER )
980 rtl::OUString aArgName;
983 aArgName = xAddIn->
984 getDisplayArgumentName( aFuncU, nParamPos );
986 catch(uno::Exception&)
988 aArgName = rtl::OUString::createFromAscii( "###" );
990 rtl::OUString aArgDesc;
993 aArgDesc = xAddIn->
994 getArgumentDescription( aFuncU, nParamPos );
996 catch(uno::Exception&)
998 aArgName = rtl::OUString::createFromAscii( "###" );
1001 BOOL bOptional =
1002 ( eArgType == SC_ADDINARG_VALUE_OR_ARRAY ||
1003 eArgType == SC_ADDINARG_VARARGS );
1005 aDesc.eType = eArgType;
1006 aDesc.aName = String( aArgName );
1007 aDesc.aDescription = String( aArgDesc );
1008 aDesc.bOptional = bOptional;
1009 //! initialize aInternalName only from config?
1010 aDesc.aInternalName = pParArr[nParamPos].aName;
1012 pVisibleArgs[nDestPos++] = aDesc;
1015 DBG_ASSERT( nDestPos==nVisibleCount, "wrong count" );
1018 ppFuncData[nFuncPos+nOld] = new ScUnoAddInFuncData(
1019 aFuncName, aLocalName, aDescription,
1020 nCategory, nHelpId,
1021 xFunc, aObject,
1022 nVisibleCount, pVisibleArgs, nCallerPos );
1024 const ScUnoAddInFuncData* pData =
1025 ppFuncData[nFuncPos+nOld];
1026 pExactHashMap->insert(
1027 ScAddInHashMap::value_type(
1028 pData->GetOriginalName(),
1029 pData ) );
1030 pNameHashMap->insert(
1031 ScAddInHashMap::value_type(
1032 pData->GetUpperName(),
1033 pData ) );
1034 pLocalHashMap->insert(
1035 ScAddInHashMap::value_type(
1036 pData->GetUpperLocal(),
1037 pData ) );
1039 delete[] pVisibleArgs;
1051 void lcl_UpdateFunctionList( ScFunctionList& rFunctionList, const ScUnoAddInFuncData& rFuncData )
1053 String aCompare = rFuncData.GetUpperLocal(); // as used in FillFunctionDescFromData
1055 ULONG nCount = rFunctionList.GetCount();
1056 for (ULONG nPos=0; nPos<nCount; nPos++)
1058 const ScFuncDesc* pDesc = rFunctionList.GetFunction( nPos );
1059 if ( pDesc && pDesc->pFuncName && *pDesc->pFuncName == aCompare )
1061 ScUnoAddInCollection::FillFunctionDescFromData( rFuncData, *const_cast<ScFuncDesc*>(pDesc) );
1062 break;
1067 const ScAddInArgDesc* lcl_FindArgDesc( const ScUnoAddInFuncData& rFuncData, const String& rArgIntName )
1069 long nArgCount = rFuncData.GetArgumentCount();
1070 const ScAddInArgDesc* pArguments = rFuncData.GetArguments();
1071 for (long nPos=0; nPos<nArgCount; nPos++)
1073 if ( pArguments[nPos].aInternalName == rArgIntName )
1074 return &pArguments[nPos];
1076 return NULL;
1079 void ScUnoAddInCollection::UpdateFromAddIn( const uno::Reference<uno::XInterface>& xInterface,
1080 const String& rServiceName )
1082 uno::Reference<lang::XLocalizable> xLoc( xInterface, uno::UNO_QUERY );
1083 if ( xLoc.is() ) // optional in new add-ins
1085 LanguageType eOfficeLang = Application::GetSettings().GetUILanguage();
1086 lang::Locale aLocale( MsLangId::convertLanguageToLocale( eOfficeLang ));
1087 xLoc->setLocale( aLocale );
1090 // if function list was already initialized, it must be updated
1092 ScFunctionList* pFunctionList = NULL;
1093 if ( ScGlobal::HasStarCalcFunctionList() )
1094 pFunctionList = ScGlobal::GetStarCalcFunctionList();
1096 // only get the function information from Introspection
1098 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
1099 if ( xManager.is() )
1101 uno::Reference<beans::XIntrospection> xIntro(
1102 xManager->createInstance(rtl::OUString::createFromAscii(
1103 "com.sun.star.beans.Introspection" )),
1104 uno::UNO_QUERY );
1105 if ( xIntro.is() )
1107 uno::Any aObject;
1108 aObject <<= xInterface;
1109 uno::Reference<beans::XIntrospectionAccess> xAcc = xIntro->inspect(aObject);
1110 if (xAcc.is())
1112 uno::Sequence< uno::Reference<reflection::XIdlMethod> > aMethods =
1113 xAcc->getMethods( beans::MethodConcept::ALL );
1114 long nMethodCount = aMethods.getLength();
1115 const uno::Reference<reflection::XIdlMethod>* pArray = aMethods.getConstArray();
1116 for (long nFuncPos=0; nFuncPos<nMethodCount; nFuncPos++)
1118 uno::Reference<reflection::XIdlMethod> xFunc = pArray[nFuncPos];
1119 if (xFunc.is())
1121 rtl::OUString aFuncU = xFunc->getName();
1123 // stored function name: (service name).(function)
1124 String aFuncName = rServiceName;
1125 aFuncName += '.';
1126 aFuncName += String( aFuncU );
1128 // internal names are skipped because no FuncData exists
1129 ScUnoAddInFuncData* pOldData = const_cast<ScUnoAddInFuncData*>( GetFuncData( aFuncName ) );
1130 if ( pOldData )
1132 // Create new (complete) argument info.
1133 // As in ReadFromAddIn, the reflection information is authoritative.
1134 // Local names and descriptions from pOldData are looked up using the
1135 // internal argument name.
1137 BOOL bValid = TRUE;
1138 long nVisibleCount = 0;
1139 long nCallerPos = SC_CALLERPOS_NONE;
1141 uno::Sequence<reflection::ParamInfo> aParams =
1142 xFunc->getParameterInfos();
1143 long nParamCount = aParams.getLength();
1144 const reflection::ParamInfo* pParArr = aParams.getConstArray();
1145 long nParamPos;
1146 for (nParamPos=0; nParamPos<nParamCount; nParamPos++)
1148 if ( pParArr[nParamPos].aMode != reflection::ParamMode_IN )
1149 bValid = FALSE;
1150 uno::Reference<reflection::XIdlClass> xParClass =
1151 pParArr[nParamPos].aType;
1152 ScAddInArgumentType eArgType = lcl_GetArgType( xParClass );
1153 if ( eArgType == SC_ADDINARG_NONE )
1154 bValid = FALSE;
1155 else if ( eArgType == SC_ADDINARG_CALLER )
1156 nCallerPos = nParamPos;
1157 else
1158 ++nVisibleCount;
1160 if (bValid)
1162 ScAddInArgDesc* pVisibleArgs = NULL;
1163 if ( nVisibleCount > 0 )
1165 ScAddInArgDesc aDesc;
1166 pVisibleArgs = new ScAddInArgDesc[nVisibleCount];
1167 long nDestPos = 0;
1168 for (nParamPos=0; nParamPos<nParamCount; nParamPos++)
1170 uno::Reference<reflection::XIdlClass> xParClass =
1171 pParArr[nParamPos].aType;
1172 ScAddInArgumentType eArgType = lcl_GetArgType( xParClass );
1173 if ( eArgType != SC_ADDINARG_CALLER )
1175 const ScAddInArgDesc* pOldArgDesc =
1176 lcl_FindArgDesc( *pOldData, pParArr[nParamPos].aName );
1177 if ( pOldArgDesc )
1179 aDesc.aName = pOldArgDesc->aName;
1180 aDesc.aDescription = pOldArgDesc->aDescription;
1182 else
1183 aDesc.aName = aDesc.aDescription = String::CreateFromAscii( "###" );
1185 BOOL bOptional =
1186 ( eArgType == SC_ADDINARG_VALUE_OR_ARRAY ||
1187 eArgType == SC_ADDINARG_VARARGS );
1189 aDesc.eType = eArgType;
1190 aDesc.bOptional = bOptional;
1191 //! initialize aInternalName only from config?
1192 aDesc.aInternalName = pParArr[nParamPos].aName;
1194 pVisibleArgs[nDestPos++] = aDesc;
1197 DBG_ASSERT( nDestPos==nVisibleCount, "wrong count" );
1200 pOldData->SetFunction( xFunc, aObject );
1201 pOldData->SetArguments( nVisibleCount, pVisibleArgs );
1202 pOldData->SetCallerPos( nCallerPos );
1204 if ( pFunctionList )
1205 lcl_UpdateFunctionList( *pFunctionList, *pOldData );
1207 delete[] pVisibleArgs;
1217 String ScUnoAddInCollection::FindFunction( const String& rUpperName, BOOL bLocalFirst )
1219 if (!bInitialized)
1220 Initialize();
1222 if (nFuncCount == 0)
1223 return EMPTY_STRING;
1225 if ( bLocalFirst )
1227 // first scan all local names (used for entering formulas)
1229 ScAddInHashMap::const_iterator iLook( pLocalHashMap->find( rUpperName ) );
1230 if ( iLook != pLocalHashMap->end() )
1231 return iLook->second->GetOriginalName();
1233 #if 0
1234 // after that, scan international names (really?)
1236 iLook = pNameHashMap->find( rUpperName );
1237 if ( iLook != pNameHashMap->end() )
1238 return iLook->second->GetOriginalName();
1239 #endif
1241 else
1243 // first scan international names (used when calling a function)
1244 //! before that, check for exact match???
1246 ScAddInHashMap::const_iterator iLook( pNameHashMap->find( rUpperName ) );
1247 if ( iLook != pNameHashMap->end() )
1248 return iLook->second->GetOriginalName();
1250 // after that, scan all local names (to allow replacing old AddIns with Uno)
1252 iLook = pLocalHashMap->find( rUpperName );
1253 if ( iLook != pLocalHashMap->end() )
1254 return iLook->second->GetOriginalName();
1257 return EMPTY_STRING;
1260 const ScUnoAddInFuncData* ScUnoAddInCollection::GetFuncData( const String& rName, bool bComplete )
1262 if (!bInitialized)
1263 Initialize();
1265 // rName must be the exact internal name
1267 ScAddInHashMap::const_iterator iLook( pExactHashMap->find( rName ) );
1268 if ( iLook != pExactHashMap->end() )
1270 const ScUnoAddInFuncData* pFuncData = iLook->second;
1272 if ( bComplete && !pFuncData->GetFunction().is() ) //! extra flag?
1273 LoadComponent( *pFuncData );
1275 return pFuncData;
1278 return NULL;
1281 const ScUnoAddInFuncData* ScUnoAddInCollection::GetFuncData( long nIndex )
1283 if (!bInitialized)
1284 Initialize();
1286 if (nIndex < nFuncCount)
1287 return ppFuncData[nIndex];
1288 return NULL;
1291 void ScUnoAddInCollection::LocalizeString( String& rName )
1293 if (!bInitialized)
1294 Initialize();
1296 // modify rName - input: exact name
1298 ScAddInHashMap::const_iterator iLook( pExactHashMap->find( rName ) );
1299 if ( iLook != pExactHashMap->end() )
1300 rName = iLook->second->GetUpperLocal(); //! upper?
1304 long ScUnoAddInCollection::GetFuncCount()
1306 if (!bInitialized)
1307 Initialize();
1309 return nFuncCount;
1312 BOOL ScUnoAddInCollection::FillFunctionDesc( long nFunc, ScFuncDesc& rDesc )
1314 if (!bInitialized)
1315 Initialize();
1317 if (nFunc >= nFuncCount || !ppFuncData[nFunc])
1318 return FALSE;
1320 const ScUnoAddInFuncData& rFuncData = *ppFuncData[nFunc];
1322 return FillFunctionDescFromData( rFuncData, rDesc );
1325 // static
1326 BOOL ScUnoAddInCollection::FillFunctionDescFromData( const ScUnoAddInFuncData& rFuncData, ScFuncDesc& rDesc )
1328 rDesc.Clear();
1330 BOOL bIncomplete = !rFuncData.GetFunction().is(); //! extra flag?
1332 long nArgCount = rFuncData.GetArgumentCount();
1333 if ( nArgCount > USHRT_MAX )
1334 return FALSE;
1336 if ( bIncomplete )
1337 nArgCount = 0; // if incomplete, fill without argument info (no wrong order)
1339 // nFIndex is set from outside
1341 rDesc.pFuncName = new String( rFuncData.GetUpperLocal() ); //! upper?
1342 rDesc.nCategory = rFuncData.GetCategory();
1343 rDesc.nHelpId = rFuncData.GetHelpId();
1345 String aDesc = rFuncData.GetDescription();
1346 if (!aDesc.Len())
1347 aDesc = rFuncData.GetLocalName(); // use name if no description is available
1348 rDesc.pFuncDesc = new String( aDesc );
1350 // AddInArgumentType_CALLER is already left out in FuncData
1352 rDesc.nArgCount = (USHORT)nArgCount;
1353 if ( nArgCount )
1355 BOOL bMultiple = FALSE;
1356 const ScAddInArgDesc* pArgs = rFuncData.GetArguments();
1358 rDesc.ppDefArgNames = new String*[nArgCount];
1359 rDesc.ppDefArgDescs = new String*[nArgCount];
1360 rDesc.pDefArgFlags = new ScFuncDesc::ParameterFlags[nArgCount];
1361 for ( long nArg=0; nArg<nArgCount; nArg++ )
1363 rDesc.ppDefArgNames[nArg] = new String( pArgs[nArg].aName );
1364 rDesc.ppDefArgDescs[nArg] = new String( pArgs[nArg].aDescription );
1365 rDesc.pDefArgFlags[nArg].bOptional = pArgs[nArg].bOptional;
1366 rDesc.pDefArgFlags[nArg].bSuppress = false;
1368 // no empty names...
1369 if ( rDesc.ppDefArgNames[nArg]->Len() == 0 )
1371 String aDefName( RTL_CONSTASCII_USTRINGPARAM("arg") );
1372 aDefName += String::CreateFromInt32( nArg+1 );
1373 *rDesc.ppDefArgNames[nArg] = aDefName;
1376 // last argument repeated?
1377 if ( nArg+1 == nArgCount && ( pArgs[nArg].eType == SC_ADDINARG_VARARGS ) )
1378 bMultiple = TRUE;
1381 if ( bMultiple )
1382 rDesc.nArgCount += VAR_ARGS - 1; // VAR_ARGS means just one repeated arg
1385 rDesc.bIncomplete = bIncomplete;
1387 return TRUE;
1391 //------------------------------------------------------------------------
1393 ScUnoAddInCall::ScUnoAddInCall( ScUnoAddInCollection& rColl, const String& rName,
1394 long nParamCount ) :
1395 bValidCount( FALSE ),
1396 nErrCode( errNoCode ), // before function was called
1397 bHasString( TRUE ),
1398 fValue( 0.0 ),
1399 xMatrix( NULL )
1401 pFuncData = rColl.GetFuncData( rName, true ); // need fully initialized data
1402 DBG_ASSERT( pFuncData, "Function Data missing" );
1403 if ( pFuncData )
1405 long nDescCount = pFuncData->GetArgumentCount();
1406 const ScAddInArgDesc* pArgs = pFuncData->GetArguments();
1408 // is aVarArg sequence needed?
1409 if ( nParamCount >= nDescCount && nDescCount > 0 &&
1410 pArgs[nDescCount-1].eType == SC_ADDINARG_VARARGS )
1412 long nVarCount = nParamCount - ( nDescCount - 1 ); // size of last argument
1413 aVarArg.realloc( nVarCount );
1414 bValidCount = TRUE;
1416 else if ( nParamCount <= nDescCount )
1418 // all args behind nParamCount must be optional
1419 bValidCount = TRUE;
1420 for (long i=nParamCount; i<nDescCount; i++)
1421 if ( !pArgs[i].bOptional )
1422 bValidCount = FALSE;
1424 // else invalid (too many arguments)
1426 if ( bValidCount )
1427 aArgs.realloc( nDescCount ); // sequence must always match function signature
1431 ScUnoAddInCall::~ScUnoAddInCall()
1433 // pFuncData is deleted with ScUnoAddInCollection
1436 BOOL ScUnoAddInCall::ValidParamCount()
1438 return bValidCount;
1441 ScAddInArgumentType ScUnoAddInCall::GetArgType( long nPos )
1443 if ( pFuncData )
1445 long nCount = pFuncData->GetArgumentCount();
1446 const ScAddInArgDesc* pArgs = pFuncData->GetArguments();
1448 // if last arg is sequence, use "any" type
1449 if ( nCount > 0 && nPos >= nCount-1 && pArgs[nCount-1].eType == SC_ADDINARG_VARARGS )
1450 return SC_ADDINARG_VALUE_OR_ARRAY;
1452 if ( nPos < nCount )
1453 return pArgs[nPos].eType;
1455 return SC_ADDINARG_VALUE_OR_ARRAY; //! error code !!!!
1458 BOOL ScUnoAddInCall::NeedsCaller() const
1460 return pFuncData && pFuncData->GetCallerPos() != SC_CALLERPOS_NONE;
1463 void ScUnoAddInCall::SetCaller( const uno::Reference<uno::XInterface>& rInterface )
1465 xCaller = rInterface;
1468 void ScUnoAddInCall::SetCallerFromObjectShell( SfxObjectShell* pObjSh )
1470 if (pObjSh)
1472 uno::Reference<uno::XInterface> xInt( pObjSh->GetBaseModel(), uno::UNO_QUERY );
1473 SetCaller( xInt );
1477 void ScUnoAddInCall::SetParam( long nPos, const uno::Any& rValue )
1479 if ( pFuncData )
1481 long nCount = pFuncData->GetArgumentCount();
1482 const ScAddInArgDesc* pArgs = pFuncData->GetArguments();
1483 if ( nCount > 0 && nPos >= nCount-1 && pArgs[nCount-1].eType == SC_ADDINARG_VARARGS )
1485 long nVarPos = nPos-(nCount-1);
1486 if ( nVarPos < aVarArg.getLength() )
1487 aVarArg.getArray()[nVarPos] = rValue;
1488 else
1490 DBG_ERROR("wrong argument number");
1493 else if ( nPos < aArgs.getLength() )
1494 aArgs.getArray()[nPos] = rValue;
1495 else
1497 DBG_ERROR("wrong argument number");
1502 void ScUnoAddInCall::ExecuteCall()
1504 if ( !pFuncData )
1505 return;
1507 long nCount = pFuncData->GetArgumentCount();
1508 const ScAddInArgDesc* pArgs = pFuncData->GetArguments();
1509 if ( nCount > 0 && pArgs[nCount-1].eType == SC_ADDINARG_VARARGS )
1511 // insert aVarArg as last argument
1512 //! after inserting caller (to prevent copying twice)?
1514 DBG_ASSERT( aArgs.getLength() == nCount, "wrong argument count" );
1515 aArgs.getArray()[nCount-1] <<= aVarArg;
1518 if ( pFuncData->GetCallerPos() != SC_CALLERPOS_NONE )
1520 uno::Any aCallerAny;
1521 aCallerAny <<= xCaller;
1523 long nUserLen = aArgs.getLength();
1524 long nCallPos = pFuncData->GetCallerPos();
1525 if (nCallPos>nUserLen) // should not happen
1527 DBG_ERROR("wrong CallPos");
1528 nCallPos = nUserLen;
1531 long nDestLen = nUserLen + 1;
1532 uno::Sequence<uno::Any> aRealArgs( nDestLen );
1533 uno::Any* pDest = aRealArgs.getArray();
1535 const uno::Any* pSource = aArgs.getConstArray();
1536 long nSrcPos = 0;
1538 for ( long nDestPos = 0; nDestPos < nDestLen; nDestPos++ )
1540 if ( nDestPos == nCallPos )
1541 pDest[nDestPos] = aCallerAny;
1542 else
1543 pDest[nDestPos] = pSource[nSrcPos++];
1546 ExecuteCallWithArgs( aRealArgs );
1548 else
1549 ExecuteCallWithArgs( aArgs );
1552 void ScUnoAddInCall::ExecuteCallWithArgs(uno::Sequence<uno::Any>& rCallArgs)
1554 // rCallArgs may not match argument descriptions (because of caller)
1556 uno::Reference<reflection::XIdlMethod> xFunction;
1557 uno::Any aObject;
1558 if ( pFuncData )
1560 xFunction = pFuncData->GetFunction();
1561 aObject = pFuncData->GetObject();
1564 if ( xFunction.is() )
1566 uno::Any aAny;
1567 nErrCode = 0;
1571 aAny = xFunction->invoke( aObject, rCallArgs );
1573 catch(lang::IllegalArgumentException&)
1575 nErrCode = errIllegalArgument;
1577 #if 0
1578 catch(FloatingPointException&)
1580 nErrCode = errIllegalFPOperation;
1582 #endif
1583 catch(reflection::InvocationTargetException& rWrapped)
1585 if ( rWrapped.TargetException.getValueType().equals(
1586 getCppuType( (lang::IllegalArgumentException*)0 ) ) )
1587 nErrCode = errIllegalArgument;
1588 else
1589 nErrCode = errNoValue;
1591 catch(uno::Exception&)
1593 nErrCode = errNoValue;
1596 if (!nErrCode)
1597 SetResult( aAny ); // convert result to Calc types
1601 void ScUnoAddInCall::SetResult( const uno::Any& rNewRes )
1603 nErrCode = 0;
1604 xVarRes = NULL;
1606 // Reflection* pRefl = rNewRes.getReflection();
1608 uno::TypeClass eClass = rNewRes.getValueTypeClass();
1609 uno::Type aType = rNewRes.getValueType();
1610 switch (eClass)
1612 case uno::TypeClass_VOID:
1613 nErrCode = NOTAVAILABLE; // #NA
1614 break;
1616 case uno::TypeClass_ENUM:
1617 case uno::TypeClass_BOOLEAN:
1618 case uno::TypeClass_CHAR:
1619 case uno::TypeClass_BYTE:
1620 case uno::TypeClass_SHORT:
1621 case uno::TypeClass_UNSIGNED_SHORT:
1622 case uno::TypeClass_LONG:
1623 case uno::TypeClass_UNSIGNED_LONG:
1624 case uno::TypeClass_FLOAT:
1625 case uno::TypeClass_DOUBLE:
1627 uno::TypeClass eMyClass;
1628 ScApiTypeConversion::ConvertAnyToDouble( fValue, eMyClass, rNewRes);
1629 bHasString = FALSE;
1631 break;
1633 case uno::TypeClass_STRING:
1635 rtl::OUString aUStr;
1636 rNewRes >>= aUStr;
1637 aString = String( aUStr );
1638 bHasString = TRUE;
1640 break;
1642 case uno::TypeClass_INTERFACE:
1644 //! directly extract XVolatileResult from any?
1645 uno::Reference<uno::XInterface> xInterface;
1646 rNewRes >>= xInterface;
1647 if ( xInterface.is() )
1648 xVarRes = uno::Reference<sheet::XVolatileResult>( xInterface, uno::UNO_QUERY );
1650 if (!xVarRes.is())
1651 nErrCode = errNoValue; // unknown interface
1653 break;
1655 default:
1656 if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<INT32> > *)0 ) ) )
1658 const uno::Sequence< uno::Sequence<INT32> >* pRowSeq = NULL;
1660 //! use pointer from any!
1661 uno::Sequence< uno::Sequence<INT32> > aSequence;
1662 if ( rNewRes >>= aSequence )
1663 pRowSeq = &aSequence;
1665 if ( pRowSeq )
1667 long nRowCount = pRowSeq->getLength();
1668 const uno::Sequence<INT32>* pRowArr = pRowSeq->getConstArray();
1669 long nMaxColCount = 0;
1670 long nCol, nRow;
1671 for (nRow=0; nRow<nRowCount; nRow++)
1673 long nTmp = pRowArr[nRow].getLength();
1674 if ( nTmp > nMaxColCount )
1675 nMaxColCount = nTmp;
1677 if ( nMaxColCount && nRowCount )
1679 xMatrix = new ScMatrix(
1680 static_cast<SCSIZE>(nMaxColCount),
1681 static_cast<SCSIZE>(nRowCount) );
1682 ScMatrix* pMatrix = xMatrix;
1683 for (nRow=0; nRow<nRowCount; nRow++)
1685 long nColCount = pRowArr[nRow].getLength();
1686 const INT32* pColArr = pRowArr[nRow].getConstArray();
1687 for (nCol=0; nCol<nColCount; nCol++)
1688 pMatrix->PutDouble( pColArr[nCol],
1689 static_cast<SCSIZE>(nCol),
1690 static_cast<SCSIZE>(nRow) );
1691 for (nCol=nColCount; nCol<nMaxColCount; nCol++)
1692 pMatrix->PutDouble( 0.0,
1693 static_cast<SCSIZE>(nCol),
1694 static_cast<SCSIZE>(nRow) );
1699 else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<double> > *)0 ) ) )
1701 const uno::Sequence< uno::Sequence<double> >* pRowSeq = NULL;
1703 //! use pointer from any!
1704 uno::Sequence< uno::Sequence<double> > aSequence;
1705 if ( rNewRes >>= aSequence )
1706 pRowSeq = &aSequence;
1708 if ( pRowSeq )
1710 long nRowCount = pRowSeq->getLength();
1711 const uno::Sequence<double>* pRowArr = pRowSeq->getConstArray();
1712 long nMaxColCount = 0;
1713 long nCol, nRow;
1714 for (nRow=0; nRow<nRowCount; nRow++)
1716 long nTmp = pRowArr[nRow].getLength();
1717 if ( nTmp > nMaxColCount )
1718 nMaxColCount = nTmp;
1720 if ( nMaxColCount && nRowCount )
1722 xMatrix = new ScMatrix(
1723 static_cast<SCSIZE>(nMaxColCount),
1724 static_cast<SCSIZE>(nRowCount) );
1725 ScMatrix* pMatrix = xMatrix;
1726 for (nRow=0; nRow<nRowCount; nRow++)
1728 long nColCount = pRowArr[nRow].getLength();
1729 const double* pColArr = pRowArr[nRow].getConstArray();
1730 for (nCol=0; nCol<nColCount; nCol++)
1731 pMatrix->PutDouble( pColArr[nCol],
1732 static_cast<SCSIZE>(nCol),
1733 static_cast<SCSIZE>(nRow) );
1734 for (nCol=nColCount; nCol<nMaxColCount; nCol++)
1735 pMatrix->PutDouble( 0.0,
1736 static_cast<SCSIZE>(nCol),
1737 static_cast<SCSIZE>(nRow) );
1742 else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<rtl::OUString> > *)0 ) ) )
1744 const uno::Sequence< uno::Sequence<rtl::OUString> >* pRowSeq = NULL;
1746 //! use pointer from any!
1747 uno::Sequence< uno::Sequence<rtl::OUString> > aSequence;
1748 if ( rNewRes >>= aSequence )
1749 pRowSeq = &aSequence;
1751 if ( pRowSeq )
1753 long nRowCount = pRowSeq->getLength();
1754 const uno::Sequence<rtl::OUString>* pRowArr = pRowSeq->getConstArray();
1755 long nMaxColCount = 0;
1756 long nCol, nRow;
1757 for (nRow=0; nRow<nRowCount; nRow++)
1759 long nTmp = pRowArr[nRow].getLength();
1760 if ( nTmp > nMaxColCount )
1761 nMaxColCount = nTmp;
1763 if ( nMaxColCount && nRowCount )
1765 xMatrix = new ScMatrix(
1766 static_cast<SCSIZE>(nMaxColCount),
1767 static_cast<SCSIZE>(nRowCount) );
1768 ScMatrix* pMatrix = xMatrix;
1769 for (nRow=0; nRow<nRowCount; nRow++)
1771 long nColCount = pRowArr[nRow].getLength();
1772 const rtl::OUString* pColArr = pRowArr[nRow].getConstArray();
1773 for (nCol=0; nCol<nColCount; nCol++)
1774 pMatrix->PutString( String( pColArr[nCol] ),
1775 static_cast<SCSIZE>(nCol),
1776 static_cast<SCSIZE>(nRow) );
1777 for (nCol=nColCount; nCol<nMaxColCount; nCol++)
1778 pMatrix->PutString( EMPTY_STRING,
1779 static_cast<SCSIZE>(nCol),
1780 static_cast<SCSIZE>(nRow) );
1785 else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<uno::Any> > *)0 ) ) )
1787 xMatrix = ScSequenceToMatrix::CreateMixedMatrix( rNewRes );
1790 if (!xMatrix) // no array found
1791 nErrCode = errNoValue; //! code for error in return type???
1797 //------------------------------------------------------------------------