Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / core / tool / addincol.cxx
blob2e100964eb9303abd4bc9b78b0589141d74e9510
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <comphelper/processfactory.hxx>
21 #include <i18nlangtag/languagetag.hxx>
22 #include <vcl/svapp.hxx>
23 #include <sfx2/objsh.hxx>
24 #include <unotools/charclass.hxx>
26 #include <com/sun/star/container/XContentEnumerationAccess.hpp>
27 #include <com/sun/star/lang/XServiceName.hpp>
28 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
29 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
30 #include <com/sun/star/reflection/XIdlClass.hpp>
31 #include <com/sun/star/beans/XIntrospectionAccess.hpp>
32 #include <com/sun/star/beans/Introspection.hpp>
33 #include <com/sun/star/beans/MethodConcept.hpp>
34 #include <com/sun/star/beans/XPropertySet.hpp>
35 #include <com/sun/star/table/XCellRange.hpp>
36 #include <com/sun/star/lang/Locale.hpp>
37 #include <com/sun/star/sheet/XCompatibilityNames.hpp>
38 #include <com/sun/star/sheet/NoConvergenceException.hpp>
40 #include "addincol.hxx"
41 #include "addinhelpid.hxx"
42 #include "compiler.hxx"
43 #include "scmatrix.hxx"
44 #include "addinlis.hxx"
45 #include "formula/errorcodes.hxx"
46 #include "scfuncs.hrc"
47 #include "optutil.hxx"
48 #include "addincfg.hxx"
49 #include "scmod.hxx"
50 #include "rangeseq.hxx"
51 #include "funcdesc.hxx"
52 #include "svl/sharedstring.hxx"
53 #include "formulaopt.hxx"
55 using namespace com::sun::star;
57 #define SC_CALLERPOS_NONE (-1)
59 ScUnoAddInFuncData::ScUnoAddInFuncData( const OUString& rNam, const OUString& rLoc,
60 const OUString& rDesc,
61 sal_uInt16 nCat, const OString& sHelp,
62 const uno::Reference<reflection::XIdlMethod>& rFunc,
63 const uno::Any& rO,
64 long nAC, const ScAddInArgDesc* pAD,
65 long nCP ) :
66 aOriginalName( rNam ),
67 aLocalName( rLoc ),
68 aUpperName( rNam ),
69 aUpperLocal( rLoc ),
70 aDescription( rDesc ),
71 xFunction( rFunc ),
72 aObject( rO ),
73 nArgCount( nAC ),
74 nCallerPos( nCP ),
75 nCategory( nCat ),
76 sHelpId( sHelp ),
77 bCompInitialized( false )
79 if ( nArgCount )
81 pArgDescs = new ScAddInArgDesc[nArgCount];
82 for (long i=0; i<nArgCount; i++)
83 pArgDescs[i] = pAD[i];
85 else
86 pArgDescs = NULL;
88 aUpperName = ScGlobal::pCharClass->uppercase(aUpperName);
89 aUpperLocal = ScGlobal::pCharClass->uppercase(aUpperLocal);
92 ScUnoAddInFuncData::~ScUnoAddInFuncData()
94 delete[] pArgDescs;
97 const ::std::vector<ScUnoAddInFuncData::LocalizedName>& ScUnoAddInFuncData::GetCompNames() const
99 if ( !bCompInitialized )
101 // read sequence of compatibility names on demand
103 uno::Reference<sheet::XAddIn> xAddIn;
104 if ( aObject >>= xAddIn )
106 uno::Reference<sheet::XCompatibilityNames> xComp( xAddIn, uno::UNO_QUERY );
107 if ( xComp.is() && xFunction.is() )
109 OUString aMethodName = xFunction->getName();
110 uno::Sequence< sheet::LocalizedName> aCompNames( xComp->getCompatibilityNames( aMethodName ));
111 maCompNames.clear();
112 sal_Int32 nSeqLen = aCompNames.getLength();
113 if ( nSeqLen )
115 const sheet::LocalizedName* pArray = aCompNames.getArray();
116 for (sal_Int32 i=0; i<nSeqLen; i++)
118 maCompNames.push_back( LocalizedName(
119 LanguageTag::convertToBcp47( pArray[i].Locale, false),
120 pArray[i].Name));
126 bCompInitialized = true; // also if not successful
128 return maCompNames;
131 void ScUnoAddInFuncData::SetCompNames( const ::std::vector< ScUnoAddInFuncData::LocalizedName >& rNew )
133 OSL_ENSURE( !bCompInitialized, "SetCompNames after initializing" );
135 maCompNames = rNew;
137 bCompInitialized = true;
140 bool ScUnoAddInFuncData::GetExcelName( LanguageType eDestLang, OUString& rRetExcelName ) const
142 const ::std::vector<LocalizedName>& rCompNames = GetCompNames();
143 if ( !rCompNames.empty() )
145 LanguageTag aLanguageTag( eDestLang);
146 const OUString aSearch( aLanguageTag.getBcp47());
148 // First, check exact match without fallback overhead.
149 ::std::vector<LocalizedName>::const_iterator itNames( rCompNames.begin());
150 for ( ; itNames != rCompNames.end(); ++itNames)
152 if ((*itNames).maLocale == aSearch)
154 rRetExcelName = (*itNames).maName;
155 return true;
159 // Second, try match of fallback search with fallback locales,
160 // appending also 'en-US' and 'en' to search if not queried.
161 ::std::vector< OUString > aFallbackSearch( aLanguageTag.getFallbackStrings( true));
162 if (aSearch != "en-US")
164 aFallbackSearch.push_back( "en-US");
165 if (aSearch != "en")
167 aFallbackSearch.push_back( "en");
170 ::std::vector< OUString >::const_iterator itSearch( aFallbackSearch.begin());
171 for ( ; itSearch != aFallbackSearch.end(); ++itSearch)
173 itNames = rCompNames.begin();
174 for ( ; itNames != rCompNames.end(); ++itNames)
176 // We checked already the full tag, start with second.
177 ::std::vector< OUString > aFallbackLocales( LanguageTag( (*itNames).maLocale).getFallbackStrings( false));
178 for (::std::vector< OUString >::const_iterator itLocales( aFallbackLocales.begin());
179 itLocales != aFallbackLocales.end(); ++itLocales)
181 if (*itLocales == *itSearch)
183 rRetExcelName = (*itNames).maName;
184 return true;
190 // Third, last resort, use first (default) entry.
191 rRetExcelName = rCompNames[0].maName;
192 return true;
194 return false;
197 void ScUnoAddInFuncData::SetFunction( const uno::Reference< reflection::XIdlMethod>& rNewFunc, const uno::Any& rNewObj )
199 xFunction = rNewFunc;
200 aObject = rNewObj;
203 void ScUnoAddInFuncData::SetArguments( long nNewCount, const ScAddInArgDesc* pNewDescs )
205 delete[] pArgDescs;
207 nArgCount = nNewCount;
208 if ( nArgCount )
210 pArgDescs = new ScAddInArgDesc[nArgCount];
211 for (long i=0; i<nArgCount; i++)
212 pArgDescs[i] = pNewDescs[i];
214 else
215 pArgDescs = NULL;
218 void ScUnoAddInFuncData::SetCallerPos( long nNewPos )
220 nCallerPos = nNewPos;
223 ScUnoAddInCollection::ScUnoAddInCollection() :
224 nFuncCount( 0 ),
225 ppFuncData( NULL ),
226 pExactHashMap( NULL ),
227 pNameHashMap( NULL ),
228 pLocalHashMap( NULL ),
229 bInitialized( false )
233 ScUnoAddInCollection::~ScUnoAddInCollection()
235 Clear();
238 void ScUnoAddInCollection::Clear()
240 DELETEZ( pExactHashMap );
241 DELETEZ( pNameHashMap );
242 DELETEZ( pLocalHashMap );
243 if ( ppFuncData )
245 for ( long i=0; i<nFuncCount; i++ )
246 delete ppFuncData[i];
247 delete[] ppFuncData;
249 ppFuncData = NULL;
250 nFuncCount = 0;
252 bInitialized = false;
255 void ScUnoAddInCollection::Initialize()
257 OSL_ENSURE( !bInitialized, "Initialize twice?" );
259 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
260 uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
261 if ( xEnAc.is() )
263 uno::Reference<container::XEnumeration> xEnum =
264 xEnAc->createContentEnumeration( "com.sun.star.sheet.AddIn" );
265 if ( xEnum.is() )
267 // loop through all AddIns
268 while ( xEnum->hasMoreElements() )
270 uno::Any aAddInAny = xEnum->nextElement();
274 uno::Reference<uno::XInterface> xIntFac;
275 aAddInAny >>= xIntFac;
276 if ( xIntFac.is() )
278 // #i59984# try XSingleComponentFactory in addition to (old) XSingleServiceFactory,
279 // passing the context to the component
281 uno::Reference<uno::XInterface> xInterface;
282 uno::Reference<uno::XComponentContext> xCtx(
283 comphelper::getComponentContext(xManager));
284 uno::Reference<lang::XSingleComponentFactory> xCFac( xIntFac, uno::UNO_QUERY );
285 if (xCFac.is())
287 xInterface = xCFac->createInstanceWithContext(xCtx);
288 if (xInterface.is())
289 ReadFromAddIn( xInterface );
292 if (!xInterface.is())
294 uno::Reference<lang::XSingleServiceFactory> xFac( xIntFac, uno::UNO_QUERY );
295 if ( xFac.is() )
297 xInterface = xFac->createInstance();
298 if (xInterface.is())
299 ReadFromAddIn( xInterface );
303 } catch ( const uno::Exception& ) {
304 SAL_WARN ( "sc", "Failed to initialize create instance of sheet.AddIn" );
310 // ReadConfiguration is called after looking at the AddIn implementations.
311 // Duplicated are skipped (by using the service information, they don't have to be updated again
312 // when argument information is needed).
313 ReadConfiguration();
315 bInitialized = true; // with or without functions
318 static sal_uInt16 lcl_GetCategory( const OUString& rName )
320 static const sal_Char* aFuncNames[SC_FUNCGROUP_COUNT] =
322 // array index = ID - 1 (ID starts at 1)
323 // all upper case
324 "Database", // ID_FUNCTION_GRP_DATABASE
325 "Date&Time", // ID_FUNCTION_GRP_DATETIME
326 "Financial", // ID_FUNCTION_GRP_FINANZ
327 "Information", // ID_FUNCTION_GRP_INFO
328 "Logical", // ID_FUNCTION_GRP_LOGIC
329 "Mathematical", // ID_FUNCTION_GRP_MATH
330 "Matrix", // ID_FUNCTION_GRP_MATRIX
331 "Statistical", // ID_FUNCTION_GRP_STATISTIC
332 "Spreadsheet", // ID_FUNCTION_GRP_TABLE
333 "Text", // ID_FUNCTION_GRP_TEXT
334 "Add-In" // ID_FUNCTION_GRP_ADDINS
336 for (sal_uInt16 i=0; i<SC_FUNCGROUP_COUNT; i++)
337 if ( rName.equalsAscii( aFuncNames[i] ) )
338 return i+1; // IDs start at 1
340 return ID_FUNCTION_GRP_ADDINS; // if not found, use Add-In group
343 #define CFGPATH_ADDINS "Office.CalcAddIns/AddInInfo"
344 #define CFGSTR_ADDINFUNCTIONS "AddInFunctions"
346 #define CFG_FUNCPROP_DISPLAYNAME 0
347 #define CFG_FUNCPROP_DESCRIPTION 1
348 #define CFG_FUNCPROP_CATEGORY 2
349 #define CFG_FUNCPROP_COUNT 3
350 #define CFGSTR_DISPLAYNAME "DisplayName"
351 #define CFGSTR_DESCRIPTION "Description"
352 #define CFGSTR_CATEGORY "Category"
353 // CategoryDisplayName is ignored for now
355 #define CFGSTR_COMPATIBILITYNAME "CompatibilityName"
356 #define CFGSTR_PARAMETERS "Parameters"
358 void ScUnoAddInCollection::ReadConfiguration()
360 // called only from Initialize
362 ScAddInCfg& rAddInConfig = SC_MOD()->GetAddInCfg();
364 // additional, temporary config item for the compatibility names
365 ScLinkConfigItem aAllLocalesConfig( OUString(CFGPATH_ADDINS), CONFIG_MODE_ALL_LOCALES );
366 // CommitLink is not used (only reading values)
368 const OUString sSlash('/');
370 // get the list of add-ins (services)
371 OUString aEmptyString;
372 uno::Sequence<OUString> aServiceNames = rAddInConfig.GetNodeNames( aEmptyString );
374 sal_Int32 nServiceCount = aServiceNames.getLength();
375 for ( sal_Int32 nService = 0; nService < nServiceCount; nService++ )
377 OUString aServiceName = aServiceNames[nService];
378 ScUnoAddInHelpIdGenerator aHelpIdGenerator( aServiceName );
380 OUString aFunctionsPath = aServiceName;
381 aFunctionsPath += sSlash;
382 aFunctionsPath += OUString(CFGSTR_ADDINFUNCTIONS);
384 uno::Sequence<OUString> aFunctionNames = rAddInConfig.GetNodeNames( aFunctionsPath );
385 sal_Int32 nNewCount = aFunctionNames.getLength();
387 // allocate pointers
389 long nOld = nFuncCount;
390 nFuncCount = nNewCount+nOld;
391 if ( nOld )
393 ScUnoAddInFuncData** ppNew = new ScUnoAddInFuncData*[nFuncCount];
394 for (long i=0; i<nOld; i++)
395 ppNew[i] = ppFuncData[i];
396 delete[] ppFuncData;
397 ppFuncData = ppNew;
399 else
400 ppFuncData = new ScUnoAddInFuncData*[nFuncCount];
402 //! TODO: adjust bucket count?
403 if ( !pExactHashMap )
404 pExactHashMap = new ScAddInHashMap;
405 if ( !pNameHashMap )
406 pNameHashMap = new ScAddInHashMap;
407 if ( !pLocalHashMap )
408 pLocalHashMap = new ScAddInHashMap;
410 //! get the function information in a single call for all functions?
412 const OUString* pFuncNameArray = aFunctionNames.getConstArray();
413 for ( sal_Int32 nFuncPos = 0; nFuncPos < nNewCount; nFuncPos++ )
415 ppFuncData[nFuncPos+nOld] = NULL;
417 // stored function name: (service name).(function)
418 OUStringBuffer aFuncNameBuffer( aServiceName.getLength()+1+pFuncNameArray[nFuncPos].getLength());
419 aFuncNameBuffer.append(aServiceName);
420 aFuncNameBuffer.append('.');
421 aFuncNameBuffer.append(pFuncNameArray[nFuncPos]);
422 OUString aFuncName = aFuncNameBuffer.makeStringAndClear();
424 // skip the function if already known (read from old AddIn service)
426 if ( pExactHashMap->find( aFuncName ) == pExactHashMap->end() )
428 OUString aLocalName;
429 OUString aDescription;
430 sal_uInt16 nCategory = ID_FUNCTION_GRP_ADDINS;
432 // get direct information on the function
434 OUString aFuncPropPath = aFunctionsPath;
435 aFuncPropPath += sSlash;
436 aFuncPropPath += pFuncNameArray[nFuncPos];
437 aFuncPropPath += sSlash;
439 uno::Sequence<OUString> aFuncPropNames(CFG_FUNCPROP_COUNT);
440 OUString* pNameArray = aFuncPropNames.getArray();
441 pNameArray[CFG_FUNCPROP_DISPLAYNAME] = aFuncPropPath;
442 pNameArray[CFG_FUNCPROP_DISPLAYNAME] += OUString(CFGSTR_DISPLAYNAME);
443 pNameArray[CFG_FUNCPROP_DESCRIPTION] = aFuncPropPath;
444 pNameArray[CFG_FUNCPROP_DESCRIPTION] += OUString(CFGSTR_DESCRIPTION);
445 pNameArray[CFG_FUNCPROP_CATEGORY] = aFuncPropPath;
446 pNameArray[CFG_FUNCPROP_CATEGORY] += OUString(CFGSTR_CATEGORY);
448 uno::Sequence<uno::Any> aFuncProperties = rAddInConfig.GetProperties( aFuncPropNames );
449 if ( aFuncProperties.getLength() == CFG_FUNCPROP_COUNT )
451 aFuncProperties[CFG_FUNCPROP_DISPLAYNAME] >>= aLocalName;
452 aFuncProperties[CFG_FUNCPROP_DESCRIPTION] >>= aDescription;
454 OUString aCategoryName;
455 aFuncProperties[CFG_FUNCPROP_CATEGORY] >>= aCategoryName;
456 nCategory = lcl_GetCategory( aCategoryName );
459 // get compatibility names
461 ::std::vector<ScUnoAddInFuncData::LocalizedName> aCompNames;
463 OUString aCompPath = aFuncPropPath;
464 aCompPath += OUString(CFGSTR_COMPATIBILITYNAME);
465 uno::Sequence<OUString> aCompPropNames( &aCompPath, 1 );
467 uno::Sequence<uno::Any> aCompProperties = aAllLocalesConfig.GetProperties( aCompPropNames );
468 if ( aCompProperties.getLength() == 1 )
470 uno::Sequence<beans::PropertyValue> aLocalEntries;
471 if ( aCompProperties[0] >>= aLocalEntries )
473 sal_Int32 nLocaleCount = aLocalEntries.getLength();
474 const beans::PropertyValue* pConfigArray = aLocalEntries.getConstArray();
476 for ( sal_Int32 nLocale = 0; nLocale < nLocaleCount; nLocale++ )
478 // PropertyValue name is the locale ("convert" from
479 // string to string to canonicalize)
480 OUString aLocale( LanguageTag( pConfigArray[nLocale].Name, true).getBcp47( false));
481 // PropertyValue value is the localized value (string in this case)
482 OUString aName;
483 pConfigArray[nLocale].Value >>= aName;
484 aCompNames.push_back( ScUnoAddInFuncData::LocalizedName( aLocale, aName));
489 // get argument info
491 ScAddInArgDesc* pVisibleArgs = NULL;
492 long nVisibleCount = 0;
493 long nCallerPos = SC_CALLERPOS_NONE;
495 OUString aArgumentsPath = aFuncPropPath;
496 aArgumentsPath += OUString(CFGSTR_PARAMETERS);
498 uno::Sequence<OUString> aArgumentNames = rAddInConfig.GetNodeNames( aArgumentsPath );
499 sal_Int32 nArgumentCount = aArgumentNames.getLength();
500 if ( nArgumentCount )
502 // get DisplayName and Description for each argument
503 uno::Sequence<OUString> aArgPropNames( nArgumentCount * 2 );
504 OUString* pPropNameArray = aArgPropNames.getArray();
506 sal_Int32 nArgument;
507 sal_Int32 nIndex = 0;
508 const OUString* pArgNameArray = aArgumentNames.getConstArray();
509 for ( nArgument = 0; nArgument < nArgumentCount; nArgument++ )
511 OUString aOneArgPath = aArgumentsPath;
512 aOneArgPath += sSlash;
513 aOneArgPath += pArgNameArray[nArgument];
514 aOneArgPath += sSlash;
516 pPropNameArray[nIndex] = aOneArgPath;
517 pPropNameArray[nIndex++] += OUString(CFGSTR_DISPLAYNAME);
518 pPropNameArray[nIndex] = aOneArgPath;
519 pPropNameArray[nIndex++] += OUString(CFGSTR_DESCRIPTION);
522 uno::Sequence<uno::Any> aArgProperties = rAddInConfig.GetProperties( aArgPropNames );
523 if ( aArgProperties.getLength() == aArgPropNames.getLength() )
525 const uno::Any* pPropArray = aArgProperties.getConstArray();
526 OUString sDisplayName;
527 OUString sDescription;
529 ScAddInArgDesc aDesc;
530 aDesc.eType = SC_ADDINARG_NONE; // arg type is not in configuration
531 aDesc.bOptional = false;
533 nVisibleCount = nArgumentCount;
534 pVisibleArgs = new ScAddInArgDesc[nVisibleCount];
536 nIndex = 0;
537 for ( nArgument = 0; nArgument < nArgumentCount; nArgument++ )
539 pPropArray[nIndex++] >>= sDisplayName;
540 pPropArray[nIndex++] >>= sDescription;
542 aDesc.aInternalName = pArgNameArray[nArgument];
543 aDesc.aName = sDisplayName;
544 aDesc.aDescription = sDescription;
546 pVisibleArgs[nArgument] = aDesc;
551 OString sHelpId = aHelpIdGenerator.GetHelpId( pFuncNameArray[nFuncPos] );
553 uno::Reference<reflection::XIdlMethod> xFunc; // remains empty
554 uno::Any aObject; // also empty
556 // create and insert into the array
558 ScUnoAddInFuncData* pData = new ScUnoAddInFuncData(
559 aFuncName, aLocalName, aDescription,
560 nCategory, sHelpId,
561 xFunc, aObject,
562 nVisibleCount, pVisibleArgs, nCallerPos );
564 pData->SetCompNames( aCompNames );
566 ppFuncData[nFuncPos+nOld] = pData;
568 pExactHashMap->insert(
569 ScAddInHashMap::value_type(
570 pData->GetOriginalName(),
571 pData ) );
572 pNameHashMap->insert(
573 ScAddInHashMap::value_type(
574 pData->GetUpperName(),
575 pData ) );
576 pLocalHashMap->insert(
577 ScAddInHashMap::value_type(
578 pData->GetUpperLocal(),
579 pData ) );
581 delete[] pVisibleArgs;
587 void ScUnoAddInCollection::LoadComponent( const ScUnoAddInFuncData& rFuncData )
589 OUString aFullName = rFuncData.GetOriginalName();
590 sal_Int32 nPos = aFullName.lastIndexOf( (sal_Unicode) '.' );
591 if ( nPos > 0 )
593 OUString aServiceName = aFullName.copy( 0, nPos );
595 uno::Reference<lang::XMultiServiceFactory> xServiceFactory = comphelper::getProcessServiceFactory();
596 uno::Reference<uno::XInterface> xInterface( xServiceFactory->createInstance( aServiceName ) );
598 if (xInterface.is())
599 UpdateFromAddIn( xInterface, aServiceName );
603 bool ScUnoAddInCollection::GetExcelName( const OUString& rCalcName,
604 LanguageType eDestLang, OUString& rRetExcelName )
606 const ScUnoAddInFuncData* pFuncData = GetFuncData( rCalcName );
607 if ( pFuncData )
608 return pFuncData->GetExcelName( eDestLang, rRetExcelName);
609 return false;
612 bool ScUnoAddInCollection::GetCalcName( const OUString& rExcelName, OUString& rRetCalcName )
614 if (!bInitialized)
615 Initialize();
617 OUString aUpperCmp = ScGlobal::pCharClass->uppercase(rExcelName);
619 for (long i=0; i<nFuncCount; i++)
621 ScUnoAddInFuncData* pFuncData = ppFuncData[i];
622 if ( pFuncData )
624 const ::std::vector<ScUnoAddInFuncData::LocalizedName>& rNames = pFuncData->GetCompNames();
625 if ( !rNames.empty() )
627 ::std::vector<ScUnoAddInFuncData::LocalizedName>::const_iterator it( rNames.begin());
628 for ( ; it != rNames.end(); ++it)
630 if ( ScGlobal::pCharClass->uppercase( (*it).maName ) == aUpperCmp )
632 //! store upper case for comparing?
634 // use the first function that has this name for any language
635 rRetCalcName = pFuncData->GetOriginalName();
636 return true;
642 return false;
645 inline bool IsTypeName( const OUString& rName, const uno::Type& rType )
647 return rName == rType.getTypeName();
650 static bool lcl_ValidReturnType( const uno::Reference<reflection::XIdlClass>& xClass )
652 // this must match with ScUnoAddInCall::SetResult
654 if ( !xClass.is() ) return false;
656 switch (xClass->getTypeClass())
658 case uno::TypeClass_ANY: // variable type
659 case uno::TypeClass_ENUM: //! ???
660 case uno::TypeClass_BOOLEAN:
661 case uno::TypeClass_CHAR:
662 case uno::TypeClass_BYTE:
663 case uno::TypeClass_SHORT:
664 case uno::TypeClass_UNSIGNED_SHORT:
665 case uno::TypeClass_LONG:
666 case uno::TypeClass_UNSIGNED_LONG:
667 case uno::TypeClass_FLOAT:
668 case uno::TypeClass_DOUBLE:
669 case uno::TypeClass_STRING:
670 return true; // values or string
672 case uno::TypeClass_INTERFACE:
674 // return type XInterface may contain a XVolatileResult
675 //! XIdlClass needs getType() method!
677 OUString sName = xClass->getName();
678 return (
679 IsTypeName( sName, getCppuType((uno::Reference<sheet::XVolatileResult>*)0) ) ||
680 IsTypeName( sName, getCppuType((uno::Reference<uno::XInterface>*)0) ) );
683 default:
685 // nested sequences for arrays
686 //! XIdlClass needs getType() method!
688 OUString sName = xClass->getName();
689 return (
690 IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<sal_Int32> >*)0) ) ||
691 IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<double> >*)0) ) ||
692 IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<OUString> >*)0) ) ||
693 IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<uno::Any> >*)0) ) );
698 static ScAddInArgumentType lcl_GetArgType( const uno::Reference<reflection::XIdlClass>& xClass )
700 if (!xClass.is())
701 return SC_ADDINARG_NONE;
703 uno::TypeClass eType = xClass->getTypeClass();
705 if ( eType == uno::TypeClass_LONG ) //! other integer types?
706 return SC_ADDINARG_INTEGER;
708 if ( eType == uno::TypeClass_DOUBLE )
709 return SC_ADDINARG_DOUBLE;
711 if ( eType == uno::TypeClass_STRING )
712 return SC_ADDINARG_STRING;
714 //! XIdlClass needs getType() method!
715 OUString sName = xClass->getName();
717 if (IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<sal_Int32> >*)0) ))
718 return SC_ADDINARG_INTEGER_ARRAY;
720 if (IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<double> >*)0) ))
721 return SC_ADDINARG_DOUBLE_ARRAY;
723 if (IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<OUString> >*)0) ))
724 return SC_ADDINARG_STRING_ARRAY;
726 if (IsTypeName( sName, getCppuType((uno::Sequence< uno::Sequence<uno::Any> >*)0) ))
727 return SC_ADDINARG_MIXED_ARRAY;
729 if (IsTypeName( sName, getCppuType((uno::Any*)0) ))
730 return SC_ADDINARG_VALUE_OR_ARRAY;
732 if (IsTypeName( sName, getCppuType((uno::Reference<table::XCellRange>*)0) ))
733 return SC_ADDINARG_CELLRANGE;
735 if (IsTypeName( sName, getCppuType((uno::Reference<beans::XPropertySet>*)0) ))
736 return SC_ADDINARG_CALLER;
738 if (IsTypeName( sName, getCppuType((uno::Sequence<uno::Any>*)0) ))
739 return SC_ADDINARG_VARARGS;
741 return SC_ADDINARG_NONE;
744 void ScUnoAddInCollection::ReadFromAddIn( const uno::Reference<uno::XInterface>& xInterface )
746 uno::Reference<sheet::XAddIn> xAddIn( xInterface, uno::UNO_QUERY );
747 uno::Reference<lang::XServiceName> xName( xInterface, uno::UNO_QUERY );
748 if ( xAddIn.is() && xName.is() )
750 // fdo50118 when GetUseEnglishFunctionName() returns true, set the
751 // locale to en-US to get English function names
752 if ( SC_MOD()->GetFormulaOptions().GetUseEnglishFuncName() )
753 xAddIn->setLocale( lang::Locale( "en", "US", ""));
754 else
755 xAddIn->setLocale( Application::GetSettings().GetUILanguageTag().getLocale());
757 OUString aServiceName( xName->getServiceName() );
758 ScUnoAddInHelpIdGenerator aHelpIdGenerator( aServiceName );
760 //! pass XIntrospection to ReadFromAddIn
762 uno::Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext();
764 uno::Reference<beans::XIntrospection> xIntro = beans::Introspection::create( xContext );
765 uno::Any aObject;
766 aObject <<= xAddIn;
767 uno::Reference<beans::XIntrospectionAccess> xAcc = xIntro->inspect(aObject);
768 if (xAcc.is())
770 uno::Sequence< uno::Reference<reflection::XIdlMethod> > aMethods =
771 xAcc->getMethods( beans::MethodConcept::ALL );
772 long nNewCount = aMethods.getLength();
773 if ( nNewCount )
775 long nOld = nFuncCount;
776 nFuncCount = nNewCount+nOld;
777 if ( nOld )
779 ScUnoAddInFuncData** ppNew = new ScUnoAddInFuncData*[nFuncCount];
780 for (long i=0; i<nOld; i++)
781 ppNew[i] = ppFuncData[i];
782 delete[] ppFuncData;
783 ppFuncData = ppNew;
785 else
786 ppFuncData = new ScUnoAddInFuncData*[nFuncCount];
788 //! TODO: adjust bucket count?
789 if ( !pExactHashMap )
790 pExactHashMap = new ScAddInHashMap;
791 if ( !pNameHashMap )
792 pNameHashMap = new ScAddInHashMap;
793 if ( !pLocalHashMap )
794 pLocalHashMap = new ScAddInHashMap;
796 const uno::Reference<reflection::XIdlMethod>* pArray = aMethods.getConstArray();
797 for (long nFuncPos=0; nFuncPos<nNewCount; nFuncPos++)
799 ppFuncData[nFuncPos+nOld] = NULL;
801 uno::Reference<reflection::XIdlMethod> xFunc = pArray[nFuncPos];
802 if (xFunc.is())
804 // leave out internal functions
805 uno::Reference<reflection::XIdlClass> xClass =
806 xFunc->getDeclaringClass();
807 bool bSkip = true;
808 if ( xClass.is() )
810 //! XIdlClass needs getType() method!
811 OUString sName = xClass->getName();
812 bSkip = (
813 IsTypeName( sName,
814 getCppuType((uno::Reference<uno::XInterface>*)0) ) ||
815 IsTypeName( sName,
816 getCppuType((uno::Reference<lang::XServiceName>*)0) ) ||
817 IsTypeName( sName,
818 getCppuType((uno::Reference<lang::XServiceInfo>*)0) ) ||
819 IsTypeName( sName,
820 getCppuType((uno::Reference<sheet::XAddIn>*)0) ) );
822 if (!bSkip)
824 uno::Reference<reflection::XIdlClass> xReturn =
825 xFunc->getReturnType();
826 if ( !lcl_ValidReturnType( xReturn ) )
827 bSkip = true;
829 if (!bSkip)
831 OUString aFuncU = xFunc->getName();
833 // stored function name: (service name).(function)
834 OUStringBuffer aFuncNameBuffer( aServiceName.getLength()+1+aFuncU.getLength());
835 aFuncNameBuffer.append(aServiceName);
836 aFuncNameBuffer.append('.');
837 aFuncNameBuffer.append(aFuncU);
838 OUString aFuncName = aFuncNameBuffer.makeStringAndClear();
840 bool bValid = true;
841 long nVisibleCount = 0;
842 long nCallerPos = SC_CALLERPOS_NONE;
844 uno::Sequence<reflection::ParamInfo> aParams =
845 xFunc->getParameterInfos();
846 long nParamCount = aParams.getLength();
847 const reflection::ParamInfo* pParArr = aParams.getConstArray();
848 long nParamPos;
849 for (nParamPos=0; nParamPos<nParamCount; nParamPos++)
851 if ( pParArr[nParamPos].aMode != reflection::ParamMode_IN )
852 bValid = false;
853 uno::Reference<reflection::XIdlClass> xParClass =
854 pParArr[nParamPos].aType;
855 ScAddInArgumentType eArgType = lcl_GetArgType( xParClass );
856 if ( eArgType == SC_ADDINARG_NONE )
857 bValid = false;
858 else if ( eArgType == SC_ADDINARG_CALLER )
859 nCallerPos = nParamPos;
860 else
861 ++nVisibleCount;
863 if (bValid)
865 sal_uInt16 nCategory = lcl_GetCategory(
866 xAddIn->getProgrammaticCategoryName( aFuncU ) );
868 OString sHelpId = aHelpIdGenerator.GetHelpId( aFuncU );
870 OUString aLocalName;
873 aLocalName = xAddIn->
874 getDisplayFunctionName( aFuncU );
876 catch(uno::Exception&)
878 aLocalName = "###";
881 OUString aDescription;
884 aDescription = xAddIn->
885 getFunctionDescription( aFuncU );
887 catch(uno::Exception&)
889 aDescription = "###";
892 ScAddInArgDesc* pVisibleArgs = NULL;
893 if ( nVisibleCount > 0 )
895 ScAddInArgDesc aDesc;
896 pVisibleArgs = new ScAddInArgDesc[nVisibleCount];
897 long nDestPos = 0;
898 for (nParamPos=0; nParamPos<nParamCount; nParamPos++)
900 uno::Reference<reflection::XIdlClass> xParClass =
901 pParArr[nParamPos].aType;
902 ScAddInArgumentType eArgType = lcl_GetArgType( xParClass );
903 if ( eArgType != SC_ADDINARG_CALLER )
905 OUString aArgName;
908 aArgName = xAddIn->
909 getDisplayArgumentName( aFuncU, nParamPos );
911 catch(uno::Exception&)
913 aArgName = "###";
915 OUString aArgDesc;
918 aArgDesc = xAddIn->
919 getArgumentDescription( aFuncU, nParamPos );
921 catch(uno::Exception&)
923 aArgDesc = "###";
926 bool bOptional =
927 ( eArgType == SC_ADDINARG_VALUE_OR_ARRAY ||
928 eArgType == SC_ADDINARG_VARARGS );
930 aDesc.eType = eArgType;
931 aDesc.aName = aArgName;
932 aDesc.aDescription = aArgDesc;
933 aDesc.bOptional = bOptional;
934 //! initialize aInternalName only from config?
935 aDesc.aInternalName = pParArr[nParamPos].aName;
937 pVisibleArgs[nDestPos++] = aDesc;
940 OSL_ENSURE( nDestPos==nVisibleCount, "wrong count" );
943 ppFuncData[nFuncPos+nOld] = new ScUnoAddInFuncData(
944 aFuncName, aLocalName, aDescription,
945 nCategory, sHelpId,
946 xFunc, aObject,
947 nVisibleCount, pVisibleArgs, nCallerPos );
949 const ScUnoAddInFuncData* pData =
950 ppFuncData[nFuncPos+nOld];
951 pExactHashMap->insert(
952 ScAddInHashMap::value_type(
953 pData->GetOriginalName(),
954 pData ) );
955 pNameHashMap->insert(
956 ScAddInHashMap::value_type(
957 pData->GetUpperName(),
958 pData ) );
959 pLocalHashMap->insert(
960 ScAddInHashMap::value_type(
961 pData->GetUpperLocal(),
962 pData ) );
964 delete[] pVisibleArgs;
974 static void lcl_UpdateFunctionList( ScFunctionList& rFunctionList, const ScUnoAddInFuncData& rFuncData )
976 OUString aCompare = rFuncData.GetUpperLocal(); // as used in FillFunctionDescFromData
978 sal_uLong nCount = rFunctionList.GetCount();
979 for (sal_uLong nPos=0; nPos<nCount; nPos++)
981 const ScFuncDesc* pDesc = rFunctionList.GetFunction( nPos );
982 if ( pDesc && pDesc->pFuncName && *pDesc->pFuncName == aCompare )
984 ScUnoAddInCollection::FillFunctionDescFromData( rFuncData, *const_cast<ScFuncDesc*>(pDesc) );
985 break;
990 static const ScAddInArgDesc* lcl_FindArgDesc( const ScUnoAddInFuncData& rFuncData, const OUString& rArgIntName )
992 long nArgCount = rFuncData.GetArgumentCount();
993 const ScAddInArgDesc* pArguments = rFuncData.GetArguments();
994 for (long nPos=0; nPos<nArgCount; nPos++)
996 if ( pArguments[nPos].aInternalName == rArgIntName )
997 return &pArguments[nPos];
999 return NULL;
1002 void ScUnoAddInCollection::UpdateFromAddIn( const uno::Reference<uno::XInterface>& xInterface,
1003 const OUString& rServiceName )
1005 uno::Reference<lang::XLocalizable> xLoc( xInterface, uno::UNO_QUERY );
1006 if ( xLoc.is() ) // optional in new add-ins
1008 // fdo50118 when GetUseEnglishFunctionName() returns true, set the
1009 // locale to en-US to get English function names
1010 if ( SC_MOD()->GetFormulaOptions().GetUseEnglishFuncName() )
1011 xLoc->setLocale( lang::Locale( "en", "US", ""));
1012 else
1013 xLoc->setLocale( Application::GetSettings().GetUILanguageTag().getLocale());
1016 // if function list was already initialized, it must be updated
1018 ScFunctionList* pFunctionList = NULL;
1019 if ( ScGlobal::HasStarCalcFunctionList() )
1020 pFunctionList = ScGlobal::GetStarCalcFunctionList();
1022 // only get the function information from Introspection
1024 uno::Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext();
1026 uno::Reference<beans::XIntrospection> xIntro = beans::Introspection::create(xContext);
1027 uno::Any aObject;
1028 aObject <<= xInterface;
1029 uno::Reference<beans::XIntrospectionAccess> xAcc = xIntro->inspect(aObject);
1030 if (xAcc.is())
1032 uno::Sequence< uno::Reference<reflection::XIdlMethod> > aMethods =
1033 xAcc->getMethods( beans::MethodConcept::ALL );
1034 long nMethodCount = aMethods.getLength();
1035 const uno::Reference<reflection::XIdlMethod>* pArray = aMethods.getConstArray();
1036 for (long nFuncPos=0; nFuncPos<nMethodCount; nFuncPos++)
1038 uno::Reference<reflection::XIdlMethod> xFunc = pArray[nFuncPos];
1039 if (xFunc.is())
1041 OUString aFuncU = xFunc->getName();
1043 // stored function name: (service name).(function)
1044 OUStringBuffer aFuncNameBuffer( rServiceName.getLength()+1+aFuncU.getLength());
1045 aFuncNameBuffer.append(rServiceName);
1046 aFuncNameBuffer.append('.');
1047 aFuncNameBuffer.append(aFuncU);
1048 OUString aFuncName = aFuncNameBuffer.makeStringAndClear();
1050 // internal names are skipped because no FuncData exists
1051 ScUnoAddInFuncData* pOldData = const_cast<ScUnoAddInFuncData*>( GetFuncData( aFuncName ) );
1052 if ( pOldData )
1054 // Create new (complete) argument info.
1055 // As in ReadFromAddIn, the reflection information is authoritative.
1056 // Local names and descriptions from pOldData are looked up using the
1057 // internal argument name.
1059 bool bValid = true;
1060 long nVisibleCount = 0;
1061 long nCallerPos = SC_CALLERPOS_NONE;
1063 uno::Sequence<reflection::ParamInfo> aParams =
1064 xFunc->getParameterInfos();
1065 long nParamCount = aParams.getLength();
1066 const reflection::ParamInfo* pParArr = aParams.getConstArray();
1067 long nParamPos;
1068 for (nParamPos=0; nParamPos<nParamCount; nParamPos++)
1070 if ( pParArr[nParamPos].aMode != reflection::ParamMode_IN )
1071 bValid = false;
1072 uno::Reference<reflection::XIdlClass> xParClass =
1073 pParArr[nParamPos].aType;
1074 ScAddInArgumentType eArgType = lcl_GetArgType( xParClass );
1075 if ( eArgType == SC_ADDINARG_NONE )
1076 bValid = false;
1077 else if ( eArgType == SC_ADDINARG_CALLER )
1078 nCallerPos = nParamPos;
1079 else
1080 ++nVisibleCount;
1082 if (bValid)
1084 ScAddInArgDesc* pVisibleArgs = NULL;
1085 if ( nVisibleCount > 0 )
1087 ScAddInArgDesc aDesc;
1088 pVisibleArgs = new ScAddInArgDesc[nVisibleCount];
1089 long nDestPos = 0;
1090 for (nParamPos=0; nParamPos<nParamCount; nParamPos++)
1092 uno::Reference<reflection::XIdlClass> xParClass =
1093 pParArr[nParamPos].aType;
1094 ScAddInArgumentType eArgType = lcl_GetArgType( xParClass );
1095 if ( eArgType != SC_ADDINARG_CALLER )
1097 const ScAddInArgDesc* pOldArgDesc =
1098 lcl_FindArgDesc( *pOldData, pParArr[nParamPos].aName );
1099 if ( pOldArgDesc )
1101 aDesc.aName = pOldArgDesc->aName;
1102 aDesc.aDescription = pOldArgDesc->aDescription;
1104 else
1105 aDesc.aName = aDesc.aDescription = "###";
1107 bool bOptional =
1108 ( eArgType == SC_ADDINARG_VALUE_OR_ARRAY ||
1109 eArgType == SC_ADDINARG_VARARGS );
1111 aDesc.eType = eArgType;
1112 aDesc.bOptional = bOptional;
1113 //! initialize aInternalName only from config?
1114 aDesc.aInternalName = pParArr[nParamPos].aName;
1116 pVisibleArgs[nDestPos++] = aDesc;
1119 OSL_ENSURE( nDestPos==nVisibleCount, "wrong count" );
1122 pOldData->SetFunction( xFunc, aObject );
1123 pOldData->SetArguments( nVisibleCount, pVisibleArgs );
1124 pOldData->SetCallerPos( nCallerPos );
1126 if ( pFunctionList )
1127 lcl_UpdateFunctionList( *pFunctionList, *pOldData );
1129 delete[] pVisibleArgs;
1137 OUString ScUnoAddInCollection::FindFunction( const OUString& rUpperName, bool bLocalFirst )
1139 if (!bInitialized)
1140 Initialize();
1142 if (nFuncCount == 0)
1143 return EMPTY_OUSTRING;
1145 if ( bLocalFirst )
1147 // first scan all local names (used for entering formulas)
1149 ScAddInHashMap::const_iterator iLook( pLocalHashMap->find( rUpperName ) );
1150 if ( iLook != pLocalHashMap->end() )
1151 return iLook->second->GetOriginalName();
1153 else
1155 // first scan international names (used when calling a function)
1156 //! before that, check for exact match???
1158 ScAddInHashMap::const_iterator iLook( pNameHashMap->find( rUpperName ) );
1159 if ( iLook != pNameHashMap->end() )
1160 return iLook->second->GetOriginalName();
1162 // after that, scan all local names (to allow replacing old AddIns with Uno)
1164 iLook = pLocalHashMap->find( rUpperName );
1165 if ( iLook != pLocalHashMap->end() )
1166 return iLook->second->GetOriginalName();
1169 return EMPTY_OUSTRING;
1172 const ScUnoAddInFuncData* ScUnoAddInCollection::GetFuncData( const OUString& rName, bool bComplete )
1174 if (!bInitialized)
1175 Initialize();
1177 // rName must be the exact internal name
1179 ScAddInHashMap::const_iterator iLook( pExactHashMap->find( rName ) );
1180 if ( iLook != pExactHashMap->end() )
1182 const ScUnoAddInFuncData* pFuncData = iLook->second;
1184 if ( bComplete && !pFuncData->GetFunction().is() ) //! extra flag?
1185 LoadComponent( *pFuncData );
1187 return pFuncData;
1190 return NULL;
1193 const ScUnoAddInFuncData* ScUnoAddInCollection::GetFuncData( long nIndex )
1195 if (!bInitialized)
1196 Initialize();
1198 if (nIndex < nFuncCount)
1199 return ppFuncData[nIndex];
1200 return NULL;
1203 void ScUnoAddInCollection::LocalizeString( OUString& rName )
1205 if (!bInitialized)
1206 Initialize();
1208 // modify rName - input: exact name
1210 ScAddInHashMap::const_iterator iLook( pExactHashMap->find( rName ) );
1211 if ( iLook != pExactHashMap->end() )
1212 rName = iLook->second->GetUpperLocal(); //! upper?
1215 long ScUnoAddInCollection::GetFuncCount()
1217 if (!bInitialized)
1218 Initialize();
1220 return nFuncCount;
1223 bool ScUnoAddInCollection::FillFunctionDesc( long nFunc, ScFuncDesc& rDesc )
1225 if (!bInitialized)
1226 Initialize();
1228 if (nFunc >= nFuncCount || !ppFuncData[nFunc])
1229 return false;
1231 const ScUnoAddInFuncData& rFuncData = *ppFuncData[nFunc];
1233 return FillFunctionDescFromData( rFuncData, rDesc );
1236 bool ScUnoAddInCollection::FillFunctionDescFromData( const ScUnoAddInFuncData& rFuncData, ScFuncDesc& rDesc )
1238 rDesc.Clear();
1240 bool bIncomplete = !rFuncData.GetFunction().is(); //! extra flag?
1242 long nArgCount = rFuncData.GetArgumentCount();
1243 if ( nArgCount > USHRT_MAX )
1244 return false;
1246 if ( bIncomplete )
1247 nArgCount = 0; // if incomplete, fill without argument info (no wrong order)
1249 // nFIndex is set from outside
1251 rDesc.pFuncName = new OUString( rFuncData.GetUpperLocal() ); //! upper?
1252 rDesc.nCategory = rFuncData.GetCategory();
1253 rDesc.sHelpId = rFuncData.GetHelpId();
1255 OUString aDesc = rFuncData.GetDescription();
1256 if (aDesc.isEmpty())
1257 aDesc = rFuncData.GetLocalName(); // use name if no description is available
1258 rDesc.pFuncDesc = new OUString( aDesc );
1260 // AddInArgumentType_CALLER is already left out in FuncData
1262 rDesc.nArgCount = (sal_uInt16)nArgCount;
1263 if ( nArgCount )
1265 bool bMultiple = false;
1266 const ScAddInArgDesc* pArgs = rFuncData.GetArguments();
1268 rDesc.ppDefArgNames = new OUString*[nArgCount];
1269 rDesc.ppDefArgDescs = new OUString*[nArgCount];
1270 rDesc.pDefArgFlags = new ScFuncDesc::ParameterFlags[nArgCount];
1271 for ( long nArg=0; nArg<nArgCount; nArg++ )
1273 rDesc.ppDefArgNames[nArg] = new OUString( pArgs[nArg].aName );
1274 rDesc.ppDefArgDescs[nArg] = new OUString( pArgs[nArg].aDescription );
1275 rDesc.pDefArgFlags[nArg].bOptional = pArgs[nArg].bOptional;
1276 rDesc.pDefArgFlags[nArg].bSuppress = false;
1278 // no empty names...
1279 if ( rDesc.ppDefArgNames[nArg]->isEmpty() )
1281 OUString aDefName("arg");
1282 aDefName += OUString::number( nArg+1 );
1283 *rDesc.ppDefArgNames[nArg] = aDefName;
1286 // last argument repeated?
1287 if ( nArg+1 == nArgCount && ( pArgs[nArg].eType == SC_ADDINARG_VARARGS ) )
1288 bMultiple = true;
1291 if ( bMultiple )
1292 rDesc.nArgCount += VAR_ARGS - 1; // VAR_ARGS means just one repeated arg
1295 rDesc.bIncomplete = bIncomplete;
1297 return true;
1300 ScUnoAddInCall::ScUnoAddInCall( ScUnoAddInCollection& rColl, const OUString& rName,
1301 long nParamCount ) :
1302 bValidCount( false ),
1303 nErrCode( errNoCode ), // before function was called
1304 bHasString( true ),
1305 fValue( 0.0 ),
1306 xMatrix( NULL )
1308 pFuncData = rColl.GetFuncData( rName, true ); // need fully initialized data
1309 OSL_ENSURE( pFuncData, "Function Data missing" );
1310 if ( pFuncData )
1312 long nDescCount = pFuncData->GetArgumentCount();
1313 const ScAddInArgDesc* pArgs = pFuncData->GetArguments();
1315 // is aVarArg sequence needed?
1316 if ( nParamCount >= nDescCount && nDescCount > 0 &&
1317 pArgs[nDescCount-1].eType == SC_ADDINARG_VARARGS )
1319 long nVarCount = nParamCount - ( nDescCount - 1 ); // size of last argument
1320 aVarArg.realloc( nVarCount );
1321 bValidCount = true;
1323 else if ( nParamCount <= nDescCount )
1325 // all args behind nParamCount must be optional
1326 bValidCount = true;
1327 for (long i=nParamCount; i<nDescCount; i++)
1328 if ( !pArgs[i].bOptional )
1329 bValidCount = false;
1331 // else invalid (too many arguments)
1333 if ( bValidCount )
1334 aArgs.realloc( nDescCount ); // sequence must always match function signature
1338 ScUnoAddInCall::~ScUnoAddInCall()
1340 // pFuncData is deleted with ScUnoAddInCollection
1343 bool ScUnoAddInCall::ValidParamCount()
1345 return bValidCount;
1348 ScAddInArgumentType ScUnoAddInCall::GetArgType( long nPos )
1350 if ( pFuncData )
1352 long nCount = pFuncData->GetArgumentCount();
1353 const ScAddInArgDesc* pArgs = pFuncData->GetArguments();
1355 // if last arg is sequence, use "any" type
1356 if ( nCount > 0 && nPos >= nCount-1 && pArgs[nCount-1].eType == SC_ADDINARG_VARARGS )
1357 return SC_ADDINARG_VALUE_OR_ARRAY;
1359 if ( nPos < nCount )
1360 return pArgs[nPos].eType;
1362 return SC_ADDINARG_VALUE_OR_ARRAY; //! error code !!!!
1365 bool ScUnoAddInCall::NeedsCaller() const
1367 return pFuncData && pFuncData->GetCallerPos() != SC_CALLERPOS_NONE;
1370 void ScUnoAddInCall::SetCaller( const uno::Reference<uno::XInterface>& rInterface )
1372 xCaller = rInterface;
1375 void ScUnoAddInCall::SetCallerFromObjectShell( SfxObjectShell* pObjSh )
1377 if (pObjSh)
1379 uno::Reference<uno::XInterface> xInt( pObjSh->GetBaseModel(), uno::UNO_QUERY );
1380 SetCaller( xInt );
1384 void ScUnoAddInCall::SetParam( long nPos, const uno::Any& rValue )
1386 if ( pFuncData )
1388 long nCount = pFuncData->GetArgumentCount();
1389 const ScAddInArgDesc* pArgs = pFuncData->GetArguments();
1390 if ( nCount > 0 && nPos >= nCount-1 && pArgs[nCount-1].eType == SC_ADDINARG_VARARGS )
1392 long nVarPos = nPos-(nCount-1);
1393 if ( nVarPos < aVarArg.getLength() )
1394 aVarArg.getArray()[nVarPos] = rValue;
1395 else
1397 OSL_FAIL("wrong argument number");
1400 else if ( nPos < aArgs.getLength() )
1401 aArgs.getArray()[nPos] = rValue;
1402 else
1404 OSL_FAIL("wrong argument number");
1409 void ScUnoAddInCall::ExecuteCall()
1411 if ( !pFuncData )
1412 return;
1414 long nCount = pFuncData->GetArgumentCount();
1415 const ScAddInArgDesc* pArgs = pFuncData->GetArguments();
1416 if ( nCount > 0 && pArgs[nCount-1].eType == SC_ADDINARG_VARARGS )
1418 // insert aVarArg as last argument
1419 //! after inserting caller (to prevent copying twice)?
1421 OSL_ENSURE( aArgs.getLength() == nCount, "wrong argument count" );
1422 aArgs.getArray()[nCount-1] <<= aVarArg;
1425 if ( pFuncData->GetCallerPos() != SC_CALLERPOS_NONE )
1427 uno::Any aCallerAny;
1428 aCallerAny <<= xCaller;
1430 long nUserLen = aArgs.getLength();
1431 long nCallPos = pFuncData->GetCallerPos();
1432 if (nCallPos>nUserLen) // should not happen
1434 OSL_FAIL("wrong CallPos");
1435 nCallPos = nUserLen;
1438 long nDestLen = nUserLen + 1;
1439 uno::Sequence<uno::Any> aRealArgs( nDestLen );
1440 uno::Any* pDest = aRealArgs.getArray();
1442 const uno::Any* pSource = aArgs.getConstArray();
1443 long nSrcPos = 0;
1445 for ( long nDestPos = 0; nDestPos < nDestLen; nDestPos++ )
1447 if ( nDestPos == nCallPos )
1448 pDest[nDestPos] = aCallerAny;
1449 else
1450 pDest[nDestPos] = pSource[nSrcPos++];
1453 ExecuteCallWithArgs( aRealArgs );
1455 else
1456 ExecuteCallWithArgs( aArgs );
1459 void ScUnoAddInCall::ExecuteCallWithArgs(uno::Sequence<uno::Any>& rCallArgs)
1461 // rCallArgs may not match argument descriptions (because of caller)
1463 uno::Reference<reflection::XIdlMethod> xFunction;
1464 uno::Any aObject;
1465 if ( pFuncData )
1467 xFunction = pFuncData->GetFunction();
1468 aObject = pFuncData->GetObject();
1471 if ( xFunction.is() )
1473 uno::Any aAny;
1474 nErrCode = 0;
1478 aAny = xFunction->invoke( aObject, rCallArgs );
1480 catch(lang::IllegalArgumentException&)
1482 nErrCode = errIllegalArgument;
1485 catch(const reflection::InvocationTargetException& rWrapped)
1487 if ( rWrapped.TargetException.getValueType().equals(
1488 getCppuType( (lang::IllegalArgumentException*)0 ) ) )
1489 nErrCode = errIllegalArgument;
1490 else if ( rWrapped.TargetException.getValueType().equals(
1491 getCppuType( (sheet::NoConvergenceException*)0 ) ) )
1492 nErrCode = errNoConvergence;
1493 else
1494 nErrCode = errNoValue;
1497 catch(uno::Exception&)
1499 nErrCode = errNoValue;
1502 if (!nErrCode)
1503 SetResult( aAny ); // convert result to Calc types
1507 void ScUnoAddInCall::SetResult( const uno::Any& rNewRes )
1509 nErrCode = 0;
1510 xVarRes = NULL;
1512 // Reflection* pRefl = rNewRes.getReflection();
1514 uno::TypeClass eClass = rNewRes.getValueTypeClass();
1515 uno::Type aType = rNewRes.getValueType();
1516 switch (eClass)
1518 case uno::TypeClass_VOID:
1519 nErrCode = NOTAVAILABLE; // #NA
1520 break;
1522 case uno::TypeClass_ENUM:
1523 case uno::TypeClass_BOOLEAN:
1524 case uno::TypeClass_CHAR:
1525 case uno::TypeClass_BYTE:
1526 case uno::TypeClass_SHORT:
1527 case uno::TypeClass_UNSIGNED_SHORT:
1528 case uno::TypeClass_LONG:
1529 case uno::TypeClass_UNSIGNED_LONG:
1530 case uno::TypeClass_FLOAT:
1531 case uno::TypeClass_DOUBLE:
1533 uno::TypeClass eMyClass;
1534 ScApiTypeConversion::ConvertAnyToDouble( fValue, eMyClass, rNewRes);
1535 bHasString = false;
1537 break;
1539 case uno::TypeClass_STRING:
1541 rNewRes >>= aString;
1542 bHasString = true;
1544 break;
1546 case uno::TypeClass_INTERFACE:
1548 //! directly extract XVolatileResult from any?
1549 uno::Reference<uno::XInterface> xInterface;
1550 rNewRes >>= xInterface;
1551 if ( xInterface.is() )
1552 xVarRes = uno::Reference<sheet::XVolatileResult>( xInterface, uno::UNO_QUERY );
1554 if (!xVarRes.is())
1555 nErrCode = errNoValue; // unknown interface
1557 break;
1559 default:
1560 if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<sal_Int32> > *)0 ) ) )
1562 const uno::Sequence< uno::Sequence<sal_Int32> >* pRowSeq = NULL;
1564 //! use pointer from any!
1565 uno::Sequence< uno::Sequence<sal_Int32> > aSequence;
1566 if ( rNewRes >>= aSequence )
1567 pRowSeq = &aSequence;
1569 if ( pRowSeq )
1571 long nRowCount = pRowSeq->getLength();
1572 const uno::Sequence<sal_Int32>* pRowArr = pRowSeq->getConstArray();
1573 long nMaxColCount = 0;
1574 long nCol, nRow;
1575 for (nRow=0; nRow<nRowCount; nRow++)
1577 long nTmp = pRowArr[nRow].getLength();
1578 if ( nTmp > nMaxColCount )
1579 nMaxColCount = nTmp;
1581 if ( nMaxColCount && nRowCount )
1583 xMatrix = new ScMatrix(
1584 static_cast<SCSIZE>(nMaxColCount),
1585 static_cast<SCSIZE>(nRowCount), 0.0);
1586 for (nRow=0; nRow<nRowCount; nRow++)
1588 long nColCount = pRowArr[nRow].getLength();
1589 const sal_Int32* pColArr = pRowArr[nRow].getConstArray();
1590 for (nCol=0; nCol<nColCount; nCol++)
1591 xMatrix->PutDouble( pColArr[nCol],
1592 static_cast<SCSIZE>(nCol),
1593 static_cast<SCSIZE>(nRow) );
1594 for (nCol=nColCount; nCol<nMaxColCount; nCol++)
1595 xMatrix->PutDouble( 0.0,
1596 static_cast<SCSIZE>(nCol),
1597 static_cast<SCSIZE>(nRow) );
1602 else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<double> > *)0 ) ) )
1604 const uno::Sequence< uno::Sequence<double> >* pRowSeq = NULL;
1606 //! use pointer from any!
1607 uno::Sequence< uno::Sequence<double> > aSequence;
1608 if ( rNewRes >>= aSequence )
1609 pRowSeq = &aSequence;
1611 if ( pRowSeq )
1613 long nRowCount = pRowSeq->getLength();
1614 const uno::Sequence<double>* pRowArr = pRowSeq->getConstArray();
1615 long nMaxColCount = 0;
1616 long nCol, nRow;
1617 for (nRow=0; nRow<nRowCount; nRow++)
1619 long nTmp = pRowArr[nRow].getLength();
1620 if ( nTmp > nMaxColCount )
1621 nMaxColCount = nTmp;
1623 if ( nMaxColCount && nRowCount )
1625 xMatrix = new ScMatrix(
1626 static_cast<SCSIZE>(nMaxColCount),
1627 static_cast<SCSIZE>(nRowCount), 0.0);
1628 for (nRow=0; nRow<nRowCount; nRow++)
1630 long nColCount = pRowArr[nRow].getLength();
1631 const double* pColArr = pRowArr[nRow].getConstArray();
1632 for (nCol=0; nCol<nColCount; nCol++)
1633 xMatrix->PutDouble( pColArr[nCol],
1634 static_cast<SCSIZE>(nCol),
1635 static_cast<SCSIZE>(nRow) );
1636 for (nCol=nColCount; nCol<nMaxColCount; nCol++)
1637 xMatrix->PutDouble( 0.0,
1638 static_cast<SCSIZE>(nCol),
1639 static_cast<SCSIZE>(nRow) );
1644 else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<OUString> > *)0 ) ) )
1646 const uno::Sequence< uno::Sequence<OUString> >* pRowSeq = NULL;
1648 //! use pointer from any!
1649 uno::Sequence< uno::Sequence<OUString> > aSequence;
1650 if ( rNewRes >>= aSequence )
1651 pRowSeq = &aSequence;
1653 if ( pRowSeq )
1655 long nRowCount = pRowSeq->getLength();
1656 const uno::Sequence<OUString>* pRowArr = pRowSeq->getConstArray();
1657 long nMaxColCount = 0;
1658 long nCol, nRow;
1659 for (nRow=0; nRow<nRowCount; nRow++)
1661 long nTmp = pRowArr[nRow].getLength();
1662 if ( nTmp > nMaxColCount )
1663 nMaxColCount = nTmp;
1665 if ( nMaxColCount && nRowCount )
1667 xMatrix = new ScMatrix(
1668 static_cast<SCSIZE>(nMaxColCount),
1669 static_cast<SCSIZE>(nRowCount), 0.0);
1670 for (nRow=0; nRow<nRowCount; nRow++)
1672 long nColCount = pRowArr[nRow].getLength();
1673 const OUString* pColArr = pRowArr[nRow].getConstArray();
1674 for (nCol=0; nCol<nColCount; nCol++)
1676 xMatrix->PutString(
1677 svl::SharedString(pColArr[nCol]),
1678 static_cast<SCSIZE>(nCol), static_cast<SCSIZE>(nRow));
1680 for (nCol=nColCount; nCol<nMaxColCount; nCol++)
1682 xMatrix->PutString(
1683 svl::SharedString(EMPTY_OUSTRING),
1684 static_cast<SCSIZE>(nCol), static_cast<SCSIZE>(nRow));
1690 else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<uno::Any> > *)0 ) ) )
1692 xMatrix = ScSequenceToMatrix::CreateMixedMatrix( rNewRes );
1695 if (!xMatrix) // no array found
1696 nErrCode = errNoValue; //! code for error in return type???
1700 ScMatrixRef ScUnoAddInCall::GetMatrix() const
1702 return xMatrix;
1705 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */