fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / core / tool / addincol.cxx
blobfd8571a600e491f8cb5289f7e107672018309ec7
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 <vcl/settings.hxx>
24 #include <sfx2/objsh.hxx>
25 #include <unotools/charclass.hxx>
27 #include <com/sun/star/container/XContentEnumerationAccess.hpp>
28 #include <com/sun/star/lang/XServiceName.hpp>
29 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
30 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
31 #include <com/sun/star/reflection/XIdlClass.hpp>
32 #include <com/sun/star/beans/XIntrospectionAccess.hpp>
33 #include <com/sun/star/beans/theIntrospection.hpp>
34 #include <com/sun/star/beans/MethodConcept.hpp>
35 #include <com/sun/star/beans/XPropertySet.hpp>
36 #include <com/sun/star/table/XCellRange.hpp>
37 #include <com/sun/star/lang/Locale.hpp>
38 #include <com/sun/star/sheet/XCompatibilityNames.hpp>
39 #include <com/sun/star/sheet/NoConvergenceException.hpp>
41 #include "addincol.hxx"
42 #include "addinhelpid.hxx"
43 #include "compiler.hxx"
44 #include "scmatrix.hxx"
45 #include "addinlis.hxx"
46 #include <formula/errorcodes.hxx>
47 #include "scfuncs.hrc"
48 #include "optutil.hxx"
49 #include "addincfg.hxx"
50 #include "scmod.hxx"
51 #include "rangeseq.hxx"
52 #include "funcdesc.hxx"
53 #include <svl/sharedstring.hxx>
54 #include "formulaopt.hxx"
55 #include <boost/scoped_array.hpp>
57 using namespace com::sun::star;
59 #define SC_CALLERPOS_NONE (-1)
61 ScUnoAddInFuncData::ScUnoAddInFuncData( const OUString& rNam, const OUString& rLoc,
62 const OUString& rDesc,
63 sal_uInt16 nCat, const OString& sHelp,
64 const uno::Reference<reflection::XIdlMethod>& rFunc,
65 const uno::Any& rO,
66 long nAC, const ScAddInArgDesc* pAD,
67 long nCP ) :
68 aOriginalName( rNam ),
69 aLocalName( rLoc ),
70 aUpperName( rNam ),
71 aUpperLocal( rLoc ),
72 aDescription( rDesc ),
73 xFunction( rFunc ),
74 aObject( rO ),
75 nArgCount( nAC ),
76 nCallerPos( nCP ),
77 nCategory( nCat ),
78 sHelpId( sHelp ),
79 bCompInitialized( false )
81 if ( nArgCount )
83 pArgDescs = new ScAddInArgDesc[nArgCount];
84 for (long i=0; i<nArgCount; i++)
85 pArgDescs[i] = pAD[i];
87 else
88 pArgDescs = NULL;
90 aUpperName = ScGlobal::pCharClass->uppercase(aUpperName);
91 aUpperLocal = ScGlobal::pCharClass->uppercase(aUpperLocal);
94 ScUnoAddInFuncData::~ScUnoAddInFuncData()
96 delete[] pArgDescs;
99 const ::std::vector<ScUnoAddInFuncData::LocalizedName>& ScUnoAddInFuncData::GetCompNames() const
101 if ( !bCompInitialized )
103 // read sequence of compatibility names on demand
105 uno::Reference<sheet::XAddIn> xAddIn;
106 if ( aObject >>= xAddIn )
108 uno::Reference<sheet::XCompatibilityNames> xComp( xAddIn, uno::UNO_QUERY );
109 if ( xComp.is() && xFunction.is() )
111 OUString aMethodName = xFunction->getName();
112 uno::Sequence< sheet::LocalizedName> aCompNames( xComp->getCompatibilityNames( aMethodName ));
113 maCompNames.clear();
114 sal_Int32 nSeqLen = aCompNames.getLength();
115 if ( nSeqLen )
117 const sheet::LocalizedName* pArray = aCompNames.getArray();
118 for (sal_Int32 i=0; i<nSeqLen; i++)
120 maCompNames.push_back( LocalizedName(
121 LanguageTag::convertToBcp47( pArray[i].Locale, false),
122 pArray[i].Name));
128 bCompInitialized = true; // also if not successful
130 return maCompNames;
133 void ScUnoAddInFuncData::SetCompNames( const ::std::vector< ScUnoAddInFuncData::LocalizedName >& rNew )
135 OSL_ENSURE( !bCompInitialized, "SetCompNames after initializing" );
137 maCompNames = rNew;
139 bCompInitialized = true;
142 bool ScUnoAddInFuncData::GetExcelName( LanguageType eDestLang, OUString& rRetExcelName ) const
144 const ::std::vector<LocalizedName>& rCompNames = GetCompNames();
145 if ( !rCompNames.empty() )
147 LanguageTag aLanguageTag( eDestLang);
148 const OUString aSearch( aLanguageTag.getBcp47());
150 // First, check exact match without fallback overhead.
151 ::std::vector<LocalizedName>::const_iterator itNames( rCompNames.begin());
152 for ( ; itNames != rCompNames.end(); ++itNames)
154 if ((*itNames).maLocale == aSearch)
156 rRetExcelName = (*itNames).maName;
157 return true;
161 // Second, try match of fallback search with fallback locales,
162 // appending also 'en-US' and 'en' to search if not queried.
163 ::std::vector< OUString > aFallbackSearch( aLanguageTag.getFallbackStrings( true));
164 if (aSearch != "en-US")
166 aFallbackSearch.push_back( "en-US");
167 if (aSearch != "en")
169 aFallbackSearch.push_back( "en");
172 ::std::vector< OUString >::const_iterator itSearch( aFallbackSearch.begin());
173 for ( ; itSearch != aFallbackSearch.end(); ++itSearch)
175 itNames = rCompNames.begin();
176 for ( ; itNames != rCompNames.end(); ++itNames)
178 // We checked already the full tag, start with second.
179 ::std::vector< OUString > aFallbackLocales( LanguageTag( (*itNames).maLocale).getFallbackStrings( false));
180 for (::std::vector< OUString >::const_iterator itLocales( aFallbackLocales.begin());
181 itLocales != aFallbackLocales.end(); ++itLocales)
183 if (*itLocales == *itSearch)
185 rRetExcelName = (*itNames).maName;
186 return true;
192 // Third, last resort, use first (default) entry.
193 rRetExcelName = rCompNames[0].maName;
194 return true;
196 return false;
199 void ScUnoAddInFuncData::SetFunction( const uno::Reference< reflection::XIdlMethod>& rNewFunc, const uno::Any& rNewObj )
201 xFunction = rNewFunc;
202 aObject = rNewObj;
205 void ScUnoAddInFuncData::SetArguments( long nNewCount, const ScAddInArgDesc* pNewDescs )
207 delete[] pArgDescs;
209 nArgCount = nNewCount;
210 if ( nArgCount )
212 pArgDescs = new ScAddInArgDesc[nArgCount];
213 for (long i=0; i<nArgCount; i++)
214 pArgDescs[i] = pNewDescs[i];
216 else
217 pArgDescs = NULL;
220 void ScUnoAddInFuncData::SetCallerPos( long nNewPos )
222 nCallerPos = nNewPos;
225 ScUnoAddInCollection::ScUnoAddInCollection() :
226 nFuncCount( 0 ),
227 ppFuncData( NULL ),
228 pExactHashMap( NULL ),
229 pNameHashMap( NULL ),
230 pLocalHashMap( NULL ),
231 bInitialized( false )
235 ScUnoAddInCollection::~ScUnoAddInCollection()
237 Clear();
240 void ScUnoAddInCollection::Clear()
242 DELETEZ( pExactHashMap );
243 DELETEZ( pNameHashMap );
244 DELETEZ( pLocalHashMap );
245 if ( ppFuncData )
247 for ( long i=0; i<nFuncCount; i++ )
248 delete ppFuncData[i];
249 delete[] ppFuncData;
251 ppFuncData = NULL;
252 nFuncCount = 0;
254 bInitialized = false;
257 void ScUnoAddInCollection::Initialize()
259 OSL_ENSURE( !bInitialized, "Initialize twice?" );
261 uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
262 uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
263 if ( xEnAc.is() )
265 uno::Reference<container::XEnumeration> xEnum =
266 xEnAc->createContentEnumeration( "com.sun.star.sheet.AddIn" );
267 if ( xEnum.is() )
269 // loop through all AddIns
270 while ( xEnum->hasMoreElements() )
272 uno::Any aAddInAny = xEnum->nextElement();
276 uno::Reference<uno::XInterface> xIntFac;
277 aAddInAny >>= xIntFac;
278 if ( xIntFac.is() )
280 // #i59984# try XSingleComponentFactory in addition to (old) XSingleServiceFactory,
281 // passing the context to the component
283 uno::Reference<uno::XInterface> xInterface;
284 uno::Reference<uno::XComponentContext> xCtx(
285 comphelper::getComponentContext(xManager));
286 uno::Reference<lang::XSingleComponentFactory> xCFac( xIntFac, uno::UNO_QUERY );
287 if (xCFac.is())
289 xInterface = xCFac->createInstanceWithContext(xCtx);
290 if (xInterface.is())
291 ReadFromAddIn( xInterface );
294 if (!xInterface.is())
296 uno::Reference<lang::XSingleServiceFactory> xFac( xIntFac, uno::UNO_QUERY );
297 if ( xFac.is() )
299 xInterface = xFac->createInstance();
300 if (xInterface.is())
301 ReadFromAddIn( xInterface );
305 } catch ( const uno::Exception& ) {
306 SAL_WARN ( "sc", "Failed to initialize create instance of sheet.AddIn" );
312 // ReadConfiguration is called after looking at the AddIn implementations.
313 // Duplicated are skipped (by using the service information, they don't have to be updated again
314 // when argument information is needed).
315 ReadConfiguration();
317 bInitialized = true; // with or without functions
320 static sal_uInt16 lcl_GetCategory( const OUString& rName )
322 static const sal_Char* aFuncNames[SC_FUNCGROUP_COUNT] =
324 // array index = ID - 1 (ID starts at 1)
325 // all upper case
326 "Database", // ID_FUNCTION_GRP_DATABASE
327 "Date&Time", // ID_FUNCTION_GRP_DATETIME
328 "Financial", // ID_FUNCTION_GRP_FINANZ
329 "Information", // ID_FUNCTION_GRP_INFO
330 "Logical", // ID_FUNCTION_GRP_LOGIC
331 "Mathematical", // ID_FUNCTION_GRP_MATH
332 "Matrix", // ID_FUNCTION_GRP_MATRIX
333 "Statistical", // ID_FUNCTION_GRP_STATISTIC
334 "Spreadsheet", // ID_FUNCTION_GRP_TABLE
335 "Text", // ID_FUNCTION_GRP_TEXT
336 "Add-In" // ID_FUNCTION_GRP_ADDINS
338 for (sal_uInt16 i=0; i<SC_FUNCGROUP_COUNT; i++)
339 if ( rName.equalsAscii( aFuncNames[i] ) )
340 return i+1; // IDs start at 1
342 return ID_FUNCTION_GRP_ADDINS; // if not found, use Add-In group
345 #define CFGPATH_ADDINS "Office.CalcAddIns/AddInInfo"
346 #define CFGSTR_ADDINFUNCTIONS "AddInFunctions"
348 #define CFG_FUNCPROP_DISPLAYNAME 0
349 #define CFG_FUNCPROP_DESCRIPTION 1
350 #define CFG_FUNCPROP_CATEGORY 2
351 #define CFG_FUNCPROP_COUNT 3
352 #define CFGSTR_DISPLAYNAME "DisplayName"
353 #define CFGSTR_DESCRIPTION "Description"
354 #define CFGSTR_CATEGORY "Category"
355 // CategoryDisplayName is ignored for now
357 #define CFGSTR_COMPATIBILITYNAME "CompatibilityName"
358 #define CFGSTR_PARAMETERS "Parameters"
360 void ScUnoAddInCollection::ReadConfiguration()
362 // called only from Initialize
364 ScAddInCfg& rAddInConfig = SC_MOD()->GetAddInCfg();
366 // additional, temporary config item for the compatibility names
367 ScLinkConfigItem aAllLocalesConfig( OUString(CFGPATH_ADDINS), ConfigItemMode::AllLocales );
368 // CommitLink is not used (only reading values)
370 const OUString sSlash('/');
372 // get the list of add-ins (services)
373 OUString aEmptyString;
374 uno::Sequence<OUString> aServiceNames = rAddInConfig.GetNodeNames( aEmptyString );
376 sal_Int32 nServiceCount = aServiceNames.getLength();
377 for ( sal_Int32 nService = 0; nService < nServiceCount; nService++ )
379 OUString aServiceName = aServiceNames[nService];
380 ScUnoAddInHelpIdGenerator aHelpIdGenerator( aServiceName );
382 OUString aFunctionsPath = aServiceName;
383 aFunctionsPath += sSlash;
384 aFunctionsPath += OUString(CFGSTR_ADDINFUNCTIONS);
386 uno::Sequence<OUString> aFunctionNames = rAddInConfig.GetNodeNames( aFunctionsPath );
387 sal_Int32 nNewCount = aFunctionNames.getLength();
389 // allocate pointers
391 long nOld = nFuncCount;
392 nFuncCount = nNewCount+nOld;
393 if ( nOld )
395 ScUnoAddInFuncData** ppNew = new ScUnoAddInFuncData*[nFuncCount];
396 for (long i=0; i<nOld; i++)
397 ppNew[i] = ppFuncData[i];
398 delete[] ppFuncData;
399 ppFuncData = ppNew;
401 else
402 ppFuncData = new ScUnoAddInFuncData*[nFuncCount];
404 //TODO: adjust bucket count?
405 if ( !pExactHashMap )
406 pExactHashMap = new ScAddInHashMap;
407 if ( !pNameHashMap )
408 pNameHashMap = new ScAddInHashMap;
409 if ( !pLocalHashMap )
410 pLocalHashMap = new ScAddInHashMap;
412 //TODO: get the function information in a single call for all functions?
414 const OUString* pFuncNameArray = aFunctionNames.getConstArray();
415 for ( sal_Int32 nFuncPos = 0; nFuncPos < nNewCount; nFuncPos++ )
417 ppFuncData[nFuncPos+nOld] = NULL;
419 // stored function name: (service name).(function)
420 OUStringBuffer aFuncNameBuffer( aServiceName.getLength()+1+pFuncNameArray[nFuncPos].getLength());
421 aFuncNameBuffer.append(aServiceName);
422 aFuncNameBuffer.append('.');
423 aFuncNameBuffer.append(pFuncNameArray[nFuncPos]);
424 OUString aFuncName = aFuncNameBuffer.makeStringAndClear();
426 // skip the function if already known (read from old AddIn service)
428 if ( pExactHashMap->find( aFuncName ) == pExactHashMap->end() )
430 OUString aLocalName;
431 OUString aDescription;
432 sal_uInt16 nCategory = ID_FUNCTION_GRP_ADDINS;
434 // get direct information on the function
436 OUString aFuncPropPath = aFunctionsPath;
437 aFuncPropPath += sSlash;
438 aFuncPropPath += pFuncNameArray[nFuncPos];
439 aFuncPropPath += sSlash;
441 uno::Sequence<OUString> aFuncPropNames(CFG_FUNCPROP_COUNT);
442 OUString* pNameArray = aFuncPropNames.getArray();
443 pNameArray[CFG_FUNCPROP_DISPLAYNAME] = aFuncPropPath;
444 pNameArray[CFG_FUNCPROP_DISPLAYNAME] += OUString(CFGSTR_DISPLAYNAME);
445 pNameArray[CFG_FUNCPROP_DESCRIPTION] = aFuncPropPath;
446 pNameArray[CFG_FUNCPROP_DESCRIPTION] += OUString(CFGSTR_DESCRIPTION);
447 pNameArray[CFG_FUNCPROP_CATEGORY] = aFuncPropPath;
448 pNameArray[CFG_FUNCPROP_CATEGORY] += OUString(CFGSTR_CATEGORY);
450 uno::Sequence<uno::Any> aFuncProperties = rAddInConfig.GetProperties( aFuncPropNames );
451 if ( aFuncProperties.getLength() == CFG_FUNCPROP_COUNT )
453 aFuncProperties[CFG_FUNCPROP_DISPLAYNAME] >>= aLocalName;
454 aFuncProperties[CFG_FUNCPROP_DESCRIPTION] >>= aDescription;
456 OUString aCategoryName;
457 aFuncProperties[CFG_FUNCPROP_CATEGORY] >>= aCategoryName;
458 nCategory = lcl_GetCategory( aCategoryName );
461 // get compatibility names
463 ::std::vector<ScUnoAddInFuncData::LocalizedName> aCompNames;
465 OUString aCompPath = aFuncPropPath;
466 aCompPath += OUString(CFGSTR_COMPATIBILITYNAME);
467 uno::Sequence<OUString> aCompPropNames( &aCompPath, 1 );
469 uno::Sequence<uno::Any> aCompProperties = aAllLocalesConfig.GetProperties( aCompPropNames );
470 if ( aCompProperties.getLength() == 1 )
472 uno::Sequence<beans::PropertyValue> aLocalEntries;
473 if ( aCompProperties[0] >>= aLocalEntries )
475 sal_Int32 nLocaleCount = aLocalEntries.getLength();
476 const beans::PropertyValue* pConfigArray = aLocalEntries.getConstArray();
478 for ( sal_Int32 nLocale = 0; nLocale < nLocaleCount; nLocale++ )
480 // PropertyValue name is the locale ("convert" from
481 // string to string to canonicalize)
482 OUString aLocale( LanguageTag( pConfigArray[nLocale].Name, true).getBcp47( false));
483 // PropertyValue value is the localized value (string in this case)
484 OUString aName;
485 pConfigArray[nLocale].Value >>= aName;
486 aCompNames.push_back( ScUnoAddInFuncData::LocalizedName( aLocale, aName));
491 // get argument info
493 boost::scoped_array<ScAddInArgDesc> pVisibleArgs;
494 long nVisibleCount = 0;
495 long nCallerPos = SC_CALLERPOS_NONE;
497 OUString aArgumentsPath = aFuncPropPath;
498 aArgumentsPath += OUString(CFGSTR_PARAMETERS);
500 uno::Sequence<OUString> aArgumentNames = rAddInConfig.GetNodeNames( aArgumentsPath );
501 sal_Int32 nArgumentCount = aArgumentNames.getLength();
502 if ( nArgumentCount )
504 // get DisplayName and Description for each argument
505 uno::Sequence<OUString> aArgPropNames( nArgumentCount * 2 );
506 OUString* pPropNameArray = aArgPropNames.getArray();
508 sal_Int32 nArgument;
509 sal_Int32 nIndex = 0;
510 const OUString* pArgNameArray = aArgumentNames.getConstArray();
511 for ( nArgument = 0; nArgument < nArgumentCount; nArgument++ )
513 OUString aOneArgPath = aArgumentsPath;
514 aOneArgPath += sSlash;
515 aOneArgPath += pArgNameArray[nArgument];
516 aOneArgPath += sSlash;
518 pPropNameArray[nIndex] = aOneArgPath;
519 pPropNameArray[nIndex++] += OUString(CFGSTR_DISPLAYNAME);
520 pPropNameArray[nIndex] = aOneArgPath;
521 pPropNameArray[nIndex++] += OUString(CFGSTR_DESCRIPTION);
524 uno::Sequence<uno::Any> aArgProperties = rAddInConfig.GetProperties( aArgPropNames );
525 if ( aArgProperties.getLength() == aArgPropNames.getLength() )
527 const uno::Any* pPropArray = aArgProperties.getConstArray();
528 OUString sDisplayName;
529 OUString sDescription;
531 ScAddInArgDesc aDesc;
532 aDesc.eType = SC_ADDINARG_NONE; // arg type is not in configuration
533 aDesc.bOptional = false;
535 nVisibleCount = nArgumentCount;
536 pVisibleArgs.reset(new ScAddInArgDesc[nVisibleCount]);
538 nIndex = 0;
539 for ( nArgument = 0; nArgument < nArgumentCount; nArgument++ )
541 pPropArray[nIndex++] >>= sDisplayName;
542 pPropArray[nIndex++] >>= sDescription;
544 aDesc.aInternalName = pArgNameArray[nArgument];
545 aDesc.aName = sDisplayName;
546 aDesc.aDescription = sDescription;
548 pVisibleArgs[nArgument] = aDesc;
553 OString sHelpId = aHelpIdGenerator.GetHelpId( pFuncNameArray[nFuncPos] );
555 uno::Reference<reflection::XIdlMethod> xFunc; // remains empty
556 uno::Any aObject; // also empty
558 // create and insert into the array
560 ScUnoAddInFuncData* pData = new ScUnoAddInFuncData(
561 aFuncName, aLocalName, aDescription,
562 nCategory, sHelpId,
563 xFunc, aObject,
564 nVisibleCount, pVisibleArgs.get(), nCallerPos );
566 pData->SetCompNames( aCompNames );
568 ppFuncData[nFuncPos+nOld] = pData;
570 pExactHashMap->insert(
571 ScAddInHashMap::value_type(
572 pData->GetOriginalName(),
573 pData ) );
574 pNameHashMap->insert(
575 ScAddInHashMap::value_type(
576 pData->GetUpperName(),
577 pData ) );
578 pLocalHashMap->insert(
579 ScAddInHashMap::value_type(
580 pData->GetUpperLocal(),
581 pData ) );
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 );
597 uno::Reference<lang::XMultiServiceFactory> xServiceFactory = comphelper::getProcessServiceFactory();
598 uno::Reference<uno::XInterface> xInterface( xServiceFactory->createInstance( aServiceName ) );
600 if (xInterface.is())
601 UpdateFromAddIn( xInterface, aServiceName );
603 catch (const uno::Exception &)
605 SAL_WARN ("sc", "Failed to create addin component '"
606 << aServiceName << "'");
611 bool ScUnoAddInCollection::GetExcelName( const OUString& rCalcName,
612 LanguageType eDestLang, OUString& rRetExcelName )
614 const ScUnoAddInFuncData* pFuncData = GetFuncData( rCalcName );
615 if ( pFuncData )
616 return pFuncData->GetExcelName( eDestLang, rRetExcelName);
617 return false;
620 bool ScUnoAddInCollection::GetCalcName( const OUString& rExcelName, OUString& rRetCalcName )
622 if (!bInitialized)
623 Initialize();
625 OUString aUpperCmp = ScGlobal::pCharClass->uppercase(rExcelName);
627 for (long i=0; i<nFuncCount; i++)
629 ScUnoAddInFuncData* pFuncData = ppFuncData[i];
630 if ( pFuncData )
632 const ::std::vector<ScUnoAddInFuncData::LocalizedName>& rNames = pFuncData->GetCompNames();
633 if ( !rNames.empty() )
635 ::std::vector<ScUnoAddInFuncData::LocalizedName>::const_iterator it( rNames.begin());
636 for ( ; it != rNames.end(); ++it)
638 if ( ScGlobal::pCharClass->uppercase( (*it).maName ) == aUpperCmp )
640 //TODO: store upper case for comparing?
642 // use the first function that has this name for any language
643 rRetCalcName = pFuncData->GetOriginalName();
644 return true;
650 return false;
653 inline bool IsTypeName( const OUString& rName, const uno::Type& rType )
655 return rName == rType.getTypeName();
658 static bool lcl_ValidReturnType( const uno::Reference<reflection::XIdlClass>& xClass )
660 // this must match with ScUnoAddInCall::SetResult
662 if ( !xClass.is() ) return false;
664 switch (xClass->getTypeClass())
666 case uno::TypeClass_ANY: // variable type
667 case uno::TypeClass_ENUM: //TODO: ???
668 case uno::TypeClass_BOOLEAN:
669 case uno::TypeClass_CHAR:
670 case uno::TypeClass_BYTE:
671 case uno::TypeClass_SHORT:
672 case uno::TypeClass_UNSIGNED_SHORT:
673 case uno::TypeClass_LONG:
674 case uno::TypeClass_UNSIGNED_LONG:
675 case uno::TypeClass_FLOAT:
676 case uno::TypeClass_DOUBLE:
677 case uno::TypeClass_STRING:
678 return true; // values or string
680 case uno::TypeClass_INTERFACE:
682 // return type XInterface may contain a XVolatileResult
683 //TODO: XIdlClass needs getType() method!
685 OUString sName = xClass->getName();
686 return (
687 IsTypeName( sName, cppu::UnoType<sheet::XVolatileResult>::get()) ||
688 IsTypeName( sName, cppu::UnoType<uno::XInterface>::get()) );
691 default:
693 // nested sequences for arrays
694 //TODO: XIdlClass needs getType() method!
696 OUString sName = xClass->getName();
697 return (
698 IsTypeName( sName, cppu::UnoType<uno::Sequence< uno::Sequence<sal_Int32> >>::get() ) ||
699 IsTypeName( sName, cppu::UnoType<uno::Sequence< uno::Sequence<double> >>::get() ) ||
700 IsTypeName( sName, cppu::UnoType<uno::Sequence< uno::Sequence<OUString> >>::get() ) ||
701 IsTypeName( sName, cppu::UnoType<uno::Sequence< uno::Sequence<uno::Any> >>::get() ) );
706 static ScAddInArgumentType lcl_GetArgType( const uno::Reference<reflection::XIdlClass>& xClass )
708 if (!xClass.is())
709 return SC_ADDINARG_NONE;
711 uno::TypeClass eType = xClass->getTypeClass();
713 if ( eType == uno::TypeClass_LONG ) //TODO: other integer types?
714 return SC_ADDINARG_INTEGER;
716 if ( eType == uno::TypeClass_DOUBLE )
717 return SC_ADDINARG_DOUBLE;
719 if ( eType == uno::TypeClass_STRING )
720 return SC_ADDINARG_STRING;
722 //TODO: XIdlClass needs getType() method!
723 OUString sName = xClass->getName();
725 if (IsTypeName( sName, cppu::UnoType<uno::Sequence< uno::Sequence<sal_Int32> >>::get() ))
726 return SC_ADDINARG_INTEGER_ARRAY;
728 if (IsTypeName( sName, cppu::UnoType<uno::Sequence< uno::Sequence<double> >>::get() ))
729 return SC_ADDINARG_DOUBLE_ARRAY;
731 if (IsTypeName( sName, cppu::UnoType<uno::Sequence< uno::Sequence<OUString> >>::get() ))
732 return SC_ADDINARG_STRING_ARRAY;
734 if (IsTypeName( sName, cppu::UnoType<uno::Sequence< uno::Sequence<uno::Any> >>::get() ))
735 return SC_ADDINARG_MIXED_ARRAY;
737 if (IsTypeName( sName, cppu::UnoType<uno::Any>::get()))
738 return SC_ADDINARG_VALUE_OR_ARRAY;
740 if (IsTypeName( sName, cppu::UnoType<table::XCellRange>::get()))
741 return SC_ADDINARG_CELLRANGE;
743 if (IsTypeName( sName, cppu::UnoType<beans::XPropertySet>::get()))
744 return SC_ADDINARG_CALLER;
746 if (IsTypeName( sName, cppu::UnoType<uno::Sequence<uno::Any>>::get() ))
747 return SC_ADDINARG_VARARGS;
749 return SC_ADDINARG_NONE;
752 void ScUnoAddInCollection::ReadFromAddIn( const uno::Reference<uno::XInterface>& xInterface )
754 uno::Reference<sheet::XAddIn> xAddIn( xInterface, uno::UNO_QUERY );
755 uno::Reference<lang::XServiceName> xName( xInterface, uno::UNO_QUERY );
756 if ( xAddIn.is() && xName.is() )
758 // fdo50118 when GetUseEnglishFunctionName() returns true, set the
759 // locale to en-US to get English function names
760 if ( SC_MOD()->GetFormulaOptions().GetUseEnglishFuncName() )
761 xAddIn->setLocale( lang::Locale( "en", "US", ""));
762 else
763 xAddIn->setLocale( Application::GetSettings().GetUILanguageTag().getLocale());
765 OUString aServiceName( xName->getServiceName() );
766 ScUnoAddInHelpIdGenerator aHelpIdGenerator( aServiceName );
768 //TODO: pass XIntrospection to ReadFromAddIn
770 uno::Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext();
772 uno::Reference<beans::XIntrospection> xIntro = beans::theIntrospection::get( xContext );
773 uno::Any aObject;
774 aObject <<= xAddIn;
775 uno::Reference<beans::XIntrospectionAccess> xAcc = xIntro->inspect(aObject);
776 if (xAcc.is())
778 uno::Sequence< uno::Reference<reflection::XIdlMethod> > aMethods =
779 xAcc->getMethods( beans::MethodConcept::ALL );
780 long nNewCount = aMethods.getLength();
781 if ( nNewCount )
783 long nOld = nFuncCount;
784 nFuncCount = nNewCount+nOld;
785 if ( nOld )
787 ScUnoAddInFuncData** ppNew = new ScUnoAddInFuncData*[nFuncCount];
788 for (long i=0; i<nOld; i++)
789 ppNew[i] = ppFuncData[i];
790 delete[] ppFuncData;
791 ppFuncData = ppNew;
793 else
794 ppFuncData = new ScUnoAddInFuncData*[nFuncCount];
796 //TODO: adjust bucket count?
797 if ( !pExactHashMap )
798 pExactHashMap = new ScAddInHashMap;
799 if ( !pNameHashMap )
800 pNameHashMap = new ScAddInHashMap;
801 if ( !pLocalHashMap )
802 pLocalHashMap = new ScAddInHashMap;
804 const uno::Reference<reflection::XIdlMethod>* pArray = aMethods.getConstArray();
805 for (long nFuncPos=0; nFuncPos<nNewCount; nFuncPos++)
807 ppFuncData[nFuncPos+nOld] = NULL;
809 uno::Reference<reflection::XIdlMethod> xFunc = pArray[nFuncPos];
810 if (xFunc.is())
812 // leave out internal functions
813 uno::Reference<reflection::XIdlClass> xClass =
814 xFunc->getDeclaringClass();
815 bool bSkip = true;
816 if ( xClass.is() )
818 //TODO: XIdlClass needs getType() method!
819 OUString sName = xClass->getName();
820 bSkip = (
821 IsTypeName( sName,
822 cppu::UnoType<uno::XInterface>::get()) ||
823 IsTypeName( sName,
824 cppu::UnoType<lang::XServiceName>::get()) ||
825 IsTypeName( sName,
826 cppu::UnoType<lang::XServiceInfo>::get()) ||
827 IsTypeName( sName,
828 cppu::UnoType<sheet::XAddIn>::get()) );
830 if (!bSkip)
832 uno::Reference<reflection::XIdlClass> xReturn =
833 xFunc->getReturnType();
834 if ( !lcl_ValidReturnType( xReturn ) )
835 bSkip = true;
837 if (!bSkip)
839 OUString aFuncU = xFunc->getName();
841 // stored function name: (service name).(function)
842 OUStringBuffer aFuncNameBuffer( aServiceName.getLength()+1+aFuncU.getLength());
843 aFuncNameBuffer.append(aServiceName);
844 aFuncNameBuffer.append('.');
845 aFuncNameBuffer.append(aFuncU);
846 OUString aFuncName = aFuncNameBuffer.makeStringAndClear();
848 bool bValid = true;
849 long nVisibleCount = 0;
850 long nCallerPos = SC_CALLERPOS_NONE;
852 uno::Sequence<reflection::ParamInfo> aParams =
853 xFunc->getParameterInfos();
854 long nParamCount = aParams.getLength();
855 const reflection::ParamInfo* pParArr = aParams.getConstArray();
856 long nParamPos;
857 for (nParamPos=0; nParamPos<nParamCount; nParamPos++)
859 if ( pParArr[nParamPos].aMode != reflection::ParamMode_IN )
860 bValid = false;
861 uno::Reference<reflection::XIdlClass> xParClass =
862 pParArr[nParamPos].aType;
863 ScAddInArgumentType eArgType = lcl_GetArgType( xParClass );
864 if ( eArgType == SC_ADDINARG_NONE )
865 bValid = false;
866 else if ( eArgType == SC_ADDINARG_CALLER )
867 nCallerPos = nParamPos;
868 else
869 ++nVisibleCount;
871 if (bValid)
873 sal_uInt16 nCategory = lcl_GetCategory(
874 xAddIn->getProgrammaticCategoryName( aFuncU ) );
876 OString sHelpId = aHelpIdGenerator.GetHelpId( aFuncU );
878 OUString aLocalName;
881 aLocalName = xAddIn->
882 getDisplayFunctionName( aFuncU );
884 catch(uno::Exception&)
886 aLocalName = "###";
889 OUString aDescription;
892 aDescription = xAddIn->
893 getFunctionDescription( aFuncU );
895 catch(uno::Exception&)
897 aDescription = "###";
900 boost::scoped_array<ScAddInArgDesc> pVisibleArgs;
901 if ( nVisibleCount > 0 )
903 ScAddInArgDesc aDesc;
904 pVisibleArgs.reset(new ScAddInArgDesc[nVisibleCount]);
905 long nDestPos = 0;
906 for (nParamPos=0; nParamPos<nParamCount; nParamPos++)
908 uno::Reference<reflection::XIdlClass> xParClass =
909 pParArr[nParamPos].aType;
910 ScAddInArgumentType eArgType = lcl_GetArgType( xParClass );
911 if ( eArgType != SC_ADDINARG_CALLER )
913 OUString aArgName;
916 aArgName = xAddIn->
917 getDisplayArgumentName( aFuncU, nParamPos );
919 catch(uno::Exception&)
921 aArgName = "###";
923 OUString aArgDesc;
926 aArgDesc = xAddIn->
927 getArgumentDescription( aFuncU, nParamPos );
929 catch(uno::Exception&)
931 aArgDesc = "###";
934 bool bOptional =
935 ( eArgType == SC_ADDINARG_VALUE_OR_ARRAY ||
936 eArgType == SC_ADDINARG_VARARGS );
938 aDesc.eType = eArgType;
939 aDesc.aName = aArgName;
940 aDesc.aDescription = aArgDesc;
941 aDesc.bOptional = bOptional;
942 //TODO: initialize aInternalName only from config?
943 aDesc.aInternalName = pParArr[nParamPos].aName;
945 pVisibleArgs[nDestPos++] = aDesc;
948 OSL_ENSURE( nDestPos==nVisibleCount, "wrong count" );
951 ppFuncData[nFuncPos+nOld] = new ScUnoAddInFuncData(
952 aFuncName, aLocalName, aDescription,
953 nCategory, sHelpId,
954 xFunc, aObject,
955 nVisibleCount, pVisibleArgs.get(), nCallerPos );
957 const ScUnoAddInFuncData* pData =
958 ppFuncData[nFuncPos+nOld];
959 pExactHashMap->insert(
960 ScAddInHashMap::value_type(
961 pData->GetOriginalName(),
962 pData ) );
963 pNameHashMap->insert(
964 ScAddInHashMap::value_type(
965 pData->GetUpperName(),
966 pData ) );
967 pLocalHashMap->insert(
968 ScAddInHashMap::value_type(
969 pData->GetUpperLocal(),
970 pData ) );
980 static void lcl_UpdateFunctionList( ScFunctionList& rFunctionList, const ScUnoAddInFuncData& rFuncData )
982 OUString aCompare = rFuncData.GetUpperLocal(); // as used in FillFunctionDescFromData
984 sal_uLong nCount = rFunctionList.GetCount();
985 for (sal_uLong nPos=0; nPos<nCount; nPos++)
987 const ScFuncDesc* pDesc = rFunctionList.GetFunction( nPos );
988 if ( pDesc && pDesc->pFuncName && *pDesc->pFuncName == aCompare )
990 ScUnoAddInCollection::FillFunctionDescFromData( rFuncData, *const_cast<ScFuncDesc*>(pDesc) );
991 break;
996 static const ScAddInArgDesc* lcl_FindArgDesc( const ScUnoAddInFuncData& rFuncData, const OUString& rArgIntName )
998 long nArgCount = rFuncData.GetArgumentCount();
999 const ScAddInArgDesc* pArguments = rFuncData.GetArguments();
1000 for (long nPos=0; nPos<nArgCount; nPos++)
1002 if ( pArguments[nPos].aInternalName == rArgIntName )
1003 return &pArguments[nPos];
1005 return NULL;
1008 void ScUnoAddInCollection::UpdateFromAddIn( const uno::Reference<uno::XInterface>& xInterface,
1009 const OUString& rServiceName )
1011 uno::Reference<lang::XLocalizable> xLoc( xInterface, uno::UNO_QUERY );
1012 if ( xLoc.is() ) // optional in new add-ins
1014 // fdo50118 when GetUseEnglishFunctionName() returns true, set the
1015 // locale to en-US to get English function names
1016 if ( SC_MOD()->GetFormulaOptions().GetUseEnglishFuncName() )
1017 xLoc->setLocale( lang::Locale( "en", "US", ""));
1018 else
1019 xLoc->setLocale( Application::GetSettings().GetUILanguageTag().getLocale());
1022 // if function list was already initialized, it must be updated
1024 ScFunctionList* pFunctionList = NULL;
1025 if ( ScGlobal::HasStarCalcFunctionList() )
1026 pFunctionList = ScGlobal::GetStarCalcFunctionList();
1028 // only get the function information from Introspection
1030 uno::Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext();
1032 uno::Reference<beans::XIntrospection> xIntro = beans::theIntrospection::get(xContext);
1033 uno::Any aObject;
1034 aObject <<= xInterface;
1035 uno::Reference<beans::XIntrospectionAccess> xAcc = xIntro->inspect(aObject);
1036 if (xAcc.is())
1038 uno::Sequence< uno::Reference<reflection::XIdlMethod> > aMethods =
1039 xAcc->getMethods( beans::MethodConcept::ALL );
1040 long nMethodCount = aMethods.getLength();
1041 const uno::Reference<reflection::XIdlMethod>* pArray = aMethods.getConstArray();
1042 for (long nFuncPos=0; nFuncPos<nMethodCount; nFuncPos++)
1044 uno::Reference<reflection::XIdlMethod> xFunc = pArray[nFuncPos];
1045 if (xFunc.is())
1047 OUString aFuncU = xFunc->getName();
1049 // stored function name: (service name).(function)
1050 OUStringBuffer aFuncNameBuffer( rServiceName.getLength()+1+aFuncU.getLength());
1051 aFuncNameBuffer.append(rServiceName);
1052 aFuncNameBuffer.append('.');
1053 aFuncNameBuffer.append(aFuncU);
1054 OUString aFuncName = aFuncNameBuffer.makeStringAndClear();
1056 // internal names are skipped because no FuncData exists
1057 ScUnoAddInFuncData* pOldData = const_cast<ScUnoAddInFuncData*>( GetFuncData( aFuncName ) );
1058 if ( pOldData )
1060 // Create new (complete) argument info.
1061 // As in ReadFromAddIn, the reflection information is authoritative.
1062 // Local names and descriptions from pOldData are looked up using the
1063 // internal argument name.
1065 bool bValid = true;
1066 long nVisibleCount = 0;
1067 long nCallerPos = SC_CALLERPOS_NONE;
1069 uno::Sequence<reflection::ParamInfo> aParams =
1070 xFunc->getParameterInfos();
1071 long nParamCount = aParams.getLength();
1072 const reflection::ParamInfo* pParArr = aParams.getConstArray();
1073 long nParamPos;
1074 for (nParamPos=0; nParamPos<nParamCount; nParamPos++)
1076 if ( pParArr[nParamPos].aMode != reflection::ParamMode_IN )
1077 bValid = false;
1078 uno::Reference<reflection::XIdlClass> xParClass =
1079 pParArr[nParamPos].aType;
1080 ScAddInArgumentType eArgType = lcl_GetArgType( xParClass );
1081 if ( eArgType == SC_ADDINARG_NONE )
1082 bValid = false;
1083 else if ( eArgType == SC_ADDINARG_CALLER )
1084 nCallerPos = nParamPos;
1085 else
1086 ++nVisibleCount;
1088 if (bValid)
1090 boost::scoped_array<ScAddInArgDesc> pVisibleArgs;
1091 if ( nVisibleCount > 0 )
1093 ScAddInArgDesc aDesc;
1094 pVisibleArgs.reset(new ScAddInArgDesc[nVisibleCount]);
1095 long nDestPos = 0;
1096 for (nParamPos=0; nParamPos<nParamCount; nParamPos++)
1098 uno::Reference<reflection::XIdlClass> xParClass =
1099 pParArr[nParamPos].aType;
1100 ScAddInArgumentType eArgType = lcl_GetArgType( xParClass );
1101 if ( eArgType != SC_ADDINARG_CALLER )
1103 const ScAddInArgDesc* pOldArgDesc =
1104 lcl_FindArgDesc( *pOldData, pParArr[nParamPos].aName );
1105 if ( pOldArgDesc )
1107 aDesc.aName = pOldArgDesc->aName;
1108 aDesc.aDescription = pOldArgDesc->aDescription;
1110 else
1111 aDesc.aName = aDesc.aDescription = "###";
1113 bool bOptional =
1114 ( eArgType == SC_ADDINARG_VALUE_OR_ARRAY ||
1115 eArgType == SC_ADDINARG_VARARGS );
1117 aDesc.eType = eArgType;
1118 aDesc.bOptional = bOptional;
1119 //TODO: initialize aInternalName only from config?
1120 aDesc.aInternalName = pParArr[nParamPos].aName;
1122 pVisibleArgs[nDestPos++] = aDesc;
1125 OSL_ENSURE( nDestPos==nVisibleCount, "wrong count" );
1128 pOldData->SetFunction( xFunc, aObject );
1129 pOldData->SetArguments( nVisibleCount, pVisibleArgs.get() );
1130 pOldData->SetCallerPos( nCallerPos );
1132 if ( pFunctionList )
1133 lcl_UpdateFunctionList( *pFunctionList, *pOldData );
1141 OUString ScUnoAddInCollection::FindFunction( const OUString& rUpperName, bool bLocalFirst )
1143 if (!bInitialized)
1144 Initialize();
1146 if (nFuncCount == 0)
1147 return EMPTY_OUSTRING;
1149 if ( bLocalFirst )
1151 // first scan all local names (used for entering formulas)
1153 ScAddInHashMap::const_iterator iLook( pLocalHashMap->find( rUpperName ) );
1154 if ( iLook != pLocalHashMap->end() )
1155 return iLook->second->GetOriginalName();
1157 else
1159 // first scan international names (used when calling a function)
1160 //TODO: before that, check for exact match???
1162 ScAddInHashMap::const_iterator iLook( pNameHashMap->find( rUpperName ) );
1163 if ( iLook != pNameHashMap->end() )
1164 return iLook->second->GetOriginalName();
1166 // after that, scan all local names (to allow replacing old AddIns with Uno)
1168 iLook = pLocalHashMap->find( rUpperName );
1169 if ( iLook != pLocalHashMap->end() )
1170 return iLook->second->GetOriginalName();
1173 return EMPTY_OUSTRING;
1176 const ScUnoAddInFuncData* ScUnoAddInCollection::GetFuncData( const OUString& rName, bool bComplete )
1178 if (!bInitialized)
1179 Initialize();
1181 // rName must be the exact internal name
1183 ScAddInHashMap::const_iterator iLook( pExactHashMap->find( rName ) );
1184 if ( iLook != pExactHashMap->end() )
1186 const ScUnoAddInFuncData* pFuncData = iLook->second;
1188 if ( bComplete && !pFuncData->GetFunction().is() ) //TODO: extra flag?
1189 LoadComponent( *pFuncData );
1191 return pFuncData;
1194 return NULL;
1197 const ScUnoAddInFuncData* ScUnoAddInCollection::GetFuncData( long nIndex )
1199 if (!bInitialized)
1200 Initialize();
1202 if (nIndex < nFuncCount)
1203 return ppFuncData[nIndex];
1204 return NULL;
1207 void ScUnoAddInCollection::LocalizeString( OUString& rName )
1209 if (!bInitialized)
1210 Initialize();
1212 // modify rName - input: exact name
1214 ScAddInHashMap::const_iterator iLook( pExactHashMap->find( rName ) );
1215 if ( iLook != pExactHashMap->end() )
1216 rName = iLook->second->GetUpperLocal(); //TODO: upper?
1219 long ScUnoAddInCollection::GetFuncCount()
1221 if (!bInitialized)
1222 Initialize();
1224 return nFuncCount;
1227 bool ScUnoAddInCollection::FillFunctionDesc( long nFunc, ScFuncDesc& rDesc )
1229 if (!bInitialized)
1230 Initialize();
1232 if (nFunc >= nFuncCount || !ppFuncData[nFunc])
1233 return false;
1235 const ScUnoAddInFuncData& rFuncData = *ppFuncData[nFunc];
1237 return FillFunctionDescFromData( rFuncData, rDesc );
1240 bool ScUnoAddInCollection::FillFunctionDescFromData( const ScUnoAddInFuncData& rFuncData, ScFuncDesc& rDesc )
1242 rDesc.Clear();
1244 bool bIncomplete = !rFuncData.GetFunction().is(); //TODO: extra flag?
1246 long nArgCount = rFuncData.GetArgumentCount();
1247 if ( nArgCount > USHRT_MAX )
1248 return false;
1250 if ( bIncomplete )
1251 nArgCount = 0; // if incomplete, fill without argument info (no wrong order)
1253 // nFIndex is set from outside
1255 rDesc.pFuncName = new OUString( rFuncData.GetUpperLocal() ); //TODO: upper?
1256 rDesc.nCategory = rFuncData.GetCategory();
1257 rDesc.sHelpId = rFuncData.GetHelpId();
1259 OUString aDesc = rFuncData.GetDescription();
1260 if (aDesc.isEmpty())
1261 aDesc = rFuncData.GetLocalName(); // use name if no description is available
1262 rDesc.pFuncDesc = new OUString( aDesc );
1264 // AddInArgumentType_CALLER is already left out in FuncData
1266 rDesc.nArgCount = (sal_uInt16)nArgCount;
1267 if ( nArgCount )
1269 bool bMultiple = false;
1270 const ScAddInArgDesc* pArgs = rFuncData.GetArguments();
1272 rDesc.maDefArgNames.clear();
1273 rDesc.maDefArgNames.resize(nArgCount);
1274 rDesc.maDefArgDescs.clear();
1275 rDesc.maDefArgDescs.resize(nArgCount);
1276 rDesc.pDefArgFlags = new ScFuncDesc::ParameterFlags[nArgCount];
1277 for ( long nArg=0; nArg<nArgCount; nArg++ )
1279 rDesc.maDefArgNames[nArg] = pArgs[nArg].aName;
1280 rDesc.maDefArgDescs[nArg] = pArgs[nArg].aDescription;
1281 rDesc.pDefArgFlags[nArg].bOptional = pArgs[nArg].bOptional;
1282 rDesc.pDefArgFlags[nArg].bSuppress = false;
1284 // no empty names...
1285 if ( rDesc.maDefArgNames[nArg].isEmpty() )
1287 OUString aDefName("arg");
1288 aDefName += OUString::number( nArg+1 );
1289 rDesc.maDefArgNames[nArg] = aDefName;
1292 // last argument repeated?
1293 if ( nArg+1 == nArgCount && ( pArgs[nArg].eType == SC_ADDINARG_VARARGS ) )
1294 bMultiple = true;
1297 if ( bMultiple )
1298 rDesc.nArgCount += VAR_ARGS - 1; // VAR_ARGS means just one repeated arg
1301 rDesc.bIncomplete = bIncomplete;
1303 return true;
1306 ScUnoAddInCall::ScUnoAddInCall( ScUnoAddInCollection& rColl, const OUString& rName,
1307 long nParamCount ) :
1308 bValidCount( false ),
1309 nErrCode( errNoCode ), // before function was called
1310 bHasString( true ),
1311 fValue( 0.0 ),
1312 xMatrix( NULL )
1314 pFuncData = rColl.GetFuncData( rName, true ); // need fully initialized data
1315 OSL_ENSURE( pFuncData, "Function Data missing" );
1316 if ( pFuncData )
1318 long nDescCount = pFuncData->GetArgumentCount();
1319 const ScAddInArgDesc* pArgs = pFuncData->GetArguments();
1321 // is aVarArg sequence needed?
1322 if ( nParamCount >= nDescCount && nDescCount > 0 &&
1323 pArgs[nDescCount-1].eType == SC_ADDINARG_VARARGS )
1325 long nVarCount = nParamCount - ( nDescCount - 1 ); // size of last argument
1326 aVarArg.realloc( nVarCount );
1327 bValidCount = true;
1329 else if ( nParamCount <= nDescCount )
1331 // all args behind nParamCount must be optional
1332 bValidCount = true;
1333 for (long i=nParamCount; i<nDescCount; i++)
1334 if ( !pArgs[i].bOptional )
1335 bValidCount = false;
1337 // else invalid (too many arguments)
1339 if ( bValidCount )
1340 aArgs.realloc( nDescCount ); // sequence must always match function signature
1344 ScUnoAddInCall::~ScUnoAddInCall()
1346 // pFuncData is deleted with ScUnoAddInCollection
1349 ScAddInArgumentType ScUnoAddInCall::GetArgType( long nPos )
1351 if ( pFuncData )
1353 long nCount = pFuncData->GetArgumentCount();
1354 const ScAddInArgDesc* pArgs = pFuncData->GetArguments();
1356 // if last arg is sequence, use "any" type
1357 if ( nCount > 0 && nPos >= nCount-1 && pArgs[nCount-1].eType == SC_ADDINARG_VARARGS )
1358 return SC_ADDINARG_VALUE_OR_ARRAY;
1360 if ( nPos < nCount )
1361 return pArgs[nPos].eType;
1363 return SC_ADDINARG_VALUE_OR_ARRAY; //TODO: error code !!!!
1366 bool ScUnoAddInCall::NeedsCaller() const
1368 return pFuncData && pFuncData->GetCallerPos() != SC_CALLERPOS_NONE;
1371 void ScUnoAddInCall::SetCaller( const uno::Reference<uno::XInterface>& rInterface )
1373 xCaller = rInterface;
1376 void ScUnoAddInCall::SetCallerFromObjectShell( SfxObjectShell* pObjSh )
1378 if (pObjSh)
1380 uno::Reference<uno::XInterface> xInt( pObjSh->GetBaseModel(), uno::UNO_QUERY );
1381 SetCaller( xInt );
1385 void ScUnoAddInCall::SetParam( long nPos, const uno::Any& rValue )
1387 if ( pFuncData )
1389 long nCount = pFuncData->GetArgumentCount();
1390 const ScAddInArgDesc* pArgs = pFuncData->GetArguments();
1391 if ( nCount > 0 && nPos >= nCount-1 && pArgs[nCount-1].eType == SC_ADDINARG_VARARGS )
1393 long nVarPos = nPos-(nCount-1);
1394 if ( nVarPos < aVarArg.getLength() )
1395 aVarArg.getArray()[nVarPos] = rValue;
1396 else
1398 OSL_FAIL("wrong argument number");
1401 else if ( nPos < aArgs.getLength() )
1402 aArgs.getArray()[nPos] = rValue;
1403 else
1405 OSL_FAIL("wrong argument number");
1410 void ScUnoAddInCall::ExecuteCall()
1412 if ( !pFuncData )
1413 return;
1415 long nCount = pFuncData->GetArgumentCount();
1416 const ScAddInArgDesc* pArgs = pFuncData->GetArguments();
1417 if ( nCount > 0 && pArgs[nCount-1].eType == SC_ADDINARG_VARARGS )
1419 // insert aVarArg as last argument
1420 //TODO: after inserting caller (to prevent copying twice)?
1422 OSL_ENSURE( aArgs.getLength() == nCount, "wrong argument count" );
1423 aArgs.getArray()[nCount-1] <<= aVarArg;
1426 if ( pFuncData->GetCallerPos() != SC_CALLERPOS_NONE )
1428 uno::Any aCallerAny;
1429 aCallerAny <<= xCaller;
1431 long nUserLen = aArgs.getLength();
1432 long nCallPos = pFuncData->GetCallerPos();
1433 if (nCallPos>nUserLen) // should not happen
1435 OSL_FAIL("wrong CallPos");
1436 nCallPos = nUserLen;
1439 long nDestLen = nUserLen + 1;
1440 uno::Sequence<uno::Any> aRealArgs( nDestLen );
1441 uno::Any* pDest = aRealArgs.getArray();
1443 const uno::Any* pSource = aArgs.getConstArray();
1444 long nSrcPos = 0;
1446 for ( long nDestPos = 0; nDestPos < nDestLen; nDestPos++ )
1448 if ( nDestPos == nCallPos )
1449 pDest[nDestPos] = aCallerAny;
1450 else
1451 pDest[nDestPos] = pSource[nSrcPos++];
1454 ExecuteCallWithArgs( aRealArgs );
1456 else
1457 ExecuteCallWithArgs( aArgs );
1460 void ScUnoAddInCall::ExecuteCallWithArgs(uno::Sequence<uno::Any>& rCallArgs)
1462 // rCallArgs may not match argument descriptions (because of caller)
1464 uno::Reference<reflection::XIdlMethod> xFunction;
1465 uno::Any aObject;
1466 if ( pFuncData )
1468 xFunction = pFuncData->GetFunction();
1469 aObject = pFuncData->GetObject();
1472 if ( xFunction.is() )
1474 uno::Any aAny;
1475 nErrCode = 0;
1479 aAny = xFunction->invoke( aObject, rCallArgs );
1481 catch(lang::IllegalArgumentException&)
1483 nErrCode = errIllegalArgument;
1486 catch(const reflection::InvocationTargetException& rWrapped)
1488 if ( rWrapped.TargetException.getValueType().equals(
1489 cppu::UnoType<lang::IllegalArgumentException>::get()) )
1490 nErrCode = errIllegalArgument;
1491 else if ( rWrapped.TargetException.getValueType().equals(
1492 cppu::UnoType<sheet::NoConvergenceException>::get()) )
1493 nErrCode = errNoConvergence;
1494 else
1495 nErrCode = errNoValue;
1498 catch(uno::Exception&)
1500 nErrCode = errNoValue;
1503 if (!nErrCode)
1504 SetResult( aAny ); // convert result to Calc types
1508 void ScUnoAddInCall::SetResult( const uno::Any& rNewRes )
1510 nErrCode = 0;
1511 xVarRes = NULL;
1513 // Reflection* pRefl = rNewRes.getReflection();
1515 uno::TypeClass eClass = rNewRes.getValueTypeClass();
1516 uno::Type aType = rNewRes.getValueType();
1517 switch (eClass)
1519 case uno::TypeClass_VOID:
1520 nErrCode = NOTAVAILABLE; // #NA
1521 break;
1523 case uno::TypeClass_ENUM:
1524 case uno::TypeClass_BOOLEAN:
1525 case uno::TypeClass_CHAR:
1526 case uno::TypeClass_BYTE:
1527 case uno::TypeClass_SHORT:
1528 case uno::TypeClass_UNSIGNED_SHORT:
1529 case uno::TypeClass_LONG:
1530 case uno::TypeClass_UNSIGNED_LONG:
1531 case uno::TypeClass_FLOAT:
1532 case uno::TypeClass_DOUBLE:
1534 uno::TypeClass eMyClass;
1535 ScApiTypeConversion::ConvertAnyToDouble( fValue, eMyClass, rNewRes);
1536 bHasString = false;
1538 break;
1540 case uno::TypeClass_STRING:
1542 rNewRes >>= aString;
1543 bHasString = true;
1545 break;
1547 case uno::TypeClass_INTERFACE:
1549 //TODO: directly extract XVolatileResult from any?
1550 uno::Reference<uno::XInterface> xInterface;
1551 rNewRes >>= xInterface;
1552 if ( xInterface.is() )
1553 xVarRes = uno::Reference<sheet::XVolatileResult>( xInterface, uno::UNO_QUERY );
1555 if (!xVarRes.is())
1556 nErrCode = errNoValue; // unknown interface
1558 break;
1560 default:
1561 if ( aType.equals( cppu::UnoType<uno::Sequence< uno::Sequence<sal_Int32> >>::get() ) )
1563 const uno::Sequence< uno::Sequence<sal_Int32> >* pRowSeq = NULL;
1565 //TODO: use pointer from any!
1566 uno::Sequence< uno::Sequence<sal_Int32> > aSequence;
1567 if ( rNewRes >>= aSequence )
1568 pRowSeq = &aSequence;
1570 if ( pRowSeq )
1572 long nRowCount = pRowSeq->getLength();
1573 const uno::Sequence<sal_Int32>* pRowArr = pRowSeq->getConstArray();
1574 long nMaxColCount = 0;
1575 long nCol, nRow;
1576 for (nRow=0; nRow<nRowCount; nRow++)
1578 long nTmp = pRowArr[nRow].getLength();
1579 if ( nTmp > nMaxColCount )
1580 nMaxColCount = nTmp;
1582 if ( nMaxColCount && nRowCount )
1584 xMatrix = new ScMatrix(
1585 static_cast<SCSIZE>(nMaxColCount),
1586 static_cast<SCSIZE>(nRowCount), 0.0);
1587 for (nRow=0; nRow<nRowCount; nRow++)
1589 long nColCount = pRowArr[nRow].getLength();
1590 const sal_Int32* pColArr = pRowArr[nRow].getConstArray();
1591 for (nCol=0; nCol<nColCount; nCol++)
1592 xMatrix->PutDouble( pColArr[nCol],
1593 static_cast<SCSIZE>(nCol),
1594 static_cast<SCSIZE>(nRow) );
1595 for (nCol=nColCount; nCol<nMaxColCount; nCol++)
1596 xMatrix->PutDouble( 0.0,
1597 static_cast<SCSIZE>(nCol),
1598 static_cast<SCSIZE>(nRow) );
1603 else if ( aType.equals( cppu::UnoType<uno::Sequence< uno::Sequence<double> >>::get() ) )
1605 const uno::Sequence< uno::Sequence<double> >* pRowSeq = NULL;
1607 //TODO: use pointer from any!
1608 uno::Sequence< uno::Sequence<double> > aSequence;
1609 if ( rNewRes >>= aSequence )
1610 pRowSeq = &aSequence;
1612 if ( pRowSeq )
1614 long nRowCount = pRowSeq->getLength();
1615 const uno::Sequence<double>* pRowArr = pRowSeq->getConstArray();
1616 long nMaxColCount = 0;
1617 long nCol, nRow;
1618 for (nRow=0; nRow<nRowCount; nRow++)
1620 long nTmp = pRowArr[nRow].getLength();
1621 if ( nTmp > nMaxColCount )
1622 nMaxColCount = nTmp;
1624 if ( nMaxColCount && nRowCount )
1626 xMatrix = new ScMatrix(
1627 static_cast<SCSIZE>(nMaxColCount),
1628 static_cast<SCSIZE>(nRowCount), 0.0);
1629 for (nRow=0; nRow<nRowCount; nRow++)
1631 long nColCount = pRowArr[nRow].getLength();
1632 const double* pColArr = pRowArr[nRow].getConstArray();
1633 for (nCol=0; nCol<nColCount; nCol++)
1634 xMatrix->PutDouble( pColArr[nCol],
1635 static_cast<SCSIZE>(nCol),
1636 static_cast<SCSIZE>(nRow) );
1637 for (nCol=nColCount; nCol<nMaxColCount; nCol++)
1638 xMatrix->PutDouble( 0.0,
1639 static_cast<SCSIZE>(nCol),
1640 static_cast<SCSIZE>(nRow) );
1645 else if ( aType.equals( cppu::UnoType<uno::Sequence< uno::Sequence<OUString> >>::get() ) )
1647 const uno::Sequence< uno::Sequence<OUString> >* pRowSeq = NULL;
1649 //TODO: use pointer from any!
1650 uno::Sequence< uno::Sequence<OUString> > aSequence;
1651 if ( rNewRes >>= aSequence )
1652 pRowSeq = &aSequence;
1654 if ( pRowSeq )
1656 long nRowCount = pRowSeq->getLength();
1657 const uno::Sequence<OUString>* pRowArr = pRowSeq->getConstArray();
1658 long nMaxColCount = 0;
1659 long nCol, nRow;
1660 for (nRow=0; nRow<nRowCount; nRow++)
1662 long nTmp = pRowArr[nRow].getLength();
1663 if ( nTmp > nMaxColCount )
1664 nMaxColCount = nTmp;
1666 if ( nMaxColCount && nRowCount )
1668 xMatrix = new ScMatrix(
1669 static_cast<SCSIZE>(nMaxColCount),
1670 static_cast<SCSIZE>(nRowCount), 0.0);
1671 for (nRow=0; nRow<nRowCount; nRow++)
1673 long nColCount = pRowArr[nRow].getLength();
1674 const OUString* pColArr = pRowArr[nRow].getConstArray();
1675 for (nCol=0; nCol<nColCount; nCol++)
1677 xMatrix->PutString(
1678 svl::SharedString(pColArr[nCol]),
1679 static_cast<SCSIZE>(nCol), static_cast<SCSIZE>(nRow));
1681 for (nCol=nColCount; nCol<nMaxColCount; nCol++)
1683 xMatrix->PutString(
1684 svl::SharedString(EMPTY_OUSTRING),
1685 static_cast<SCSIZE>(nCol), static_cast<SCSIZE>(nRow));
1691 else if ( aType.equals( cppu::UnoType<uno::Sequence< uno::Sequence<uno::Any> >>::get() ) )
1693 xMatrix = ScSequenceToMatrix::CreateMixedMatrix( rNewRes );
1696 if (!xMatrix) // no array found
1697 nErrCode = errNoValue; //TODO: code for error in return type???
1701 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */