LibreOffice Module sc (master)  1
addincol.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
22 #include <vcl/svapp.hxx>
23 #include <vcl/settings.hxx>
24 #include <sfx2/objsh.hxx>
25 #include <unotools/charclass.hxx>
26 #include <sal/log.hxx>
27 #include <osl/diagnose.h>
28 
29 #include <com/sun/star/container/XContentEnumerationAccess.hpp>
30 #include <com/sun/star/frame/XModel.hpp>
31 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
32 #include <com/sun/star/lang/XServiceName.hpp>
33 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
34 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
35 #include <com/sun/star/reflection/XIdlClass.hpp>
36 #include <com/sun/star/beans/XIntrospectionAccess.hpp>
37 #include <com/sun/star/beans/theIntrospection.hpp>
38 #include <com/sun/star/beans/MethodConcept.hpp>
39 #include <com/sun/star/beans/XPropertySet.hpp>
40 #include <com/sun/star/beans/PropertyValue.hpp>
41 #include <com/sun/star/table/XCellRange.hpp>
42 #include <com/sun/star/lang/Locale.hpp>
43 #include <com/sun/star/sheet/XCompatibilityNames.hpp>
44 #include <com/sun/star/sheet/NoConvergenceException.hpp>
45 #include <com/sun/star/sheet/XAddIn.hpp>
46 #include <com/sun/star/sheet/XVolatileResult.hpp>
47 
48 #include <addincol.hxx>
49 #include <addinhelpid.hxx>
50 #include <compiler.hxx>
51 #include <scmatrix.hxx>
52 #include <addinlis.hxx>
53 #include <formula/errorcodes.hxx>
54 #include <formula/funcvarargs.h>
55 #include <sc.hrc>
56 #include <optutil.hxx>
57 #include <addincfg.hxx>
58 #include <scmod.hxx>
59 #include <rangeseq.hxx>
60 #include <funcdesc.hxx>
61 #include <svl/sharedstring.hxx>
62 #include <formulaopt.hxx>
63 #include <memory>
64 
65 using namespace com::sun::star;
66 
67 #define SC_CALLERPOS_NONE (-1)
68 
69 ScUnoAddInFuncData::ScUnoAddInFuncData( const OUString& rNam, const OUString& rLoc,
70  const OUString& rDesc,
71  sal_uInt16 nCat, const OString& sHelp,
72  const uno::Reference<reflection::XIdlMethod>& rFunc,
73  const uno::Any& rO,
74  long nAC, const ScAddInArgDesc* pAD,
75  long nCP ) :
76  aOriginalName( rNam ),
77  aLocalName( rLoc ),
78  aUpperName( rNam ),
79  aUpperLocal( rLoc ),
80  aDescription( rDesc ),
81  xFunction( rFunc ),
82  aObject( rO ),
83  nArgCount( nAC ),
84  nCallerPos( nCP ),
85  nCategory( nCat ),
86  sHelpId( sHelp ),
87  bCompInitialized( false )
88 {
89  if ( nArgCount )
90  {
91  pArgDescs.reset( new ScAddInArgDesc[nArgCount] );
92  for (long i=0; i<nArgCount; i++)
93  pArgDescs[i] = pAD[i];
94  }
95 
98 }
99 
101 {
102 }
103 
104 const ::std::vector<ScUnoAddInFuncData::LocalizedName>& ScUnoAddInFuncData::GetCompNames() const
105 {
106  if ( !bCompInitialized )
107  {
108  // read sequence of compatibility names on demand
109 
110  uno::Reference<sheet::XAddIn> xAddIn;
111  if ( aObject >>= xAddIn )
112  {
113  uno::Reference<sheet::XCompatibilityNames> xComp( xAddIn, uno::UNO_QUERY );
114  if ( xComp.is() && xFunction.is() )
115  {
116  OUString aMethodName = xFunction->getName();
117  const uno::Sequence< sheet::LocalizedName> aCompNames( xComp->getCompatibilityNames( aMethodName ));
118  maCompNames.clear();
119  for (const sheet::LocalizedName& rCompName : aCompNames)
120  {
121  maCompNames.emplace_back(
122  LanguageTag::convertToBcp47( rCompName.Locale, false),
123  rCompName.Name);
124  }
125  }
126  }
127 
128  bCompInitialized = true; // also if not successful
129  }
130  return maCompNames;
131 }
132 
133 void ScUnoAddInFuncData::SetCompNames( const ::std::vector< ScUnoAddInFuncData::LocalizedName >& rNew )
134 {
135  OSL_ENSURE( !bCompInitialized, "SetCompNames after initializing" );
136 
137  maCompNames = rNew;
138 
139  bCompInitialized = true;
140 }
141 
142 bool ScUnoAddInFuncData::GetExcelName( LanguageType eDestLang, OUString& rRetExcelName ) const
143 {
144  const ::std::vector<LocalizedName>& rCompNames = GetCompNames();
145  if ( !rCompNames.empty() )
146  {
147  LanguageTag aLanguageTag( eDestLang);
148  const OUString& aSearch( aLanguageTag.getBcp47());
149 
150  // First, check exact match without fallback overhead.
151  ::std::vector<LocalizedName>::const_iterator itNames = std::find_if(rCompNames.begin(), rCompNames.end(),
152  [&aSearch](const LocalizedName& rName) { return rName.maLocale == aSearch; });
153  if (itNames != rCompNames.end())
154  {
155  rRetExcelName = (*itNames).maName;
156  return true;
157  }
158 
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")
163  {
164  aFallbackSearch.emplace_back("en-US");
165  if (aSearch != "en")
166  {
167  aFallbackSearch.emplace_back("en");
168  }
169  }
170  for (const auto& rSearch : aFallbackSearch)
171  {
172  for (const auto& rCompName : rCompNames)
173  {
174  // We checked already the full tag, start with second.
175  ::std::vector< OUString > aFallbackLocales( LanguageTag( rCompName.maLocale).getFallbackStrings( false));
176  if (std::find(aFallbackLocales.begin(), aFallbackLocales.end(), rSearch) != aFallbackLocales.end())
177  {
178  rRetExcelName = rCompName.maName;
179  return true;
180  }
181  }
182  }
183 
184  // Third, last resort, use first (default) entry.
185  rRetExcelName = rCompNames[0].maName;
186  return true;
187  }
188  return false;
189 }
190 
191 void ScUnoAddInFuncData::SetFunction( const uno::Reference< reflection::XIdlMethod>& rNewFunc, const uno::Any& rNewObj )
192 {
193  xFunction = rNewFunc;
194  aObject = rNewObj;
195 }
196 
197 void ScUnoAddInFuncData::SetArguments( long nNewCount, const ScAddInArgDesc* pNewDescs )
198 {
199  nArgCount = nNewCount;
200  if ( nArgCount )
201  {
202  pArgDescs.reset( new ScAddInArgDesc[nArgCount] );
203  for (long i=0; i<nArgCount; i++)
204  pArgDescs[i] = pNewDescs[i];
205  }
206  else
207  pArgDescs.reset();
208 }
209 
211 {
212  nCallerPos = nNewPos;
213 }
214 
216  nFuncCount( 0 ),
217  bInitialized( false )
218 {
219 }
220 
222 {
223 }
224 
226 {
227  pExactHashMap.reset();
228  pNameHashMap.reset();
229  pLocalHashMap.reset();
230  ppFuncData.reset();
231  nFuncCount = 0;
232 
233  bInitialized = false;
234 }
235 
237 {
238  OSL_ENSURE( !bInitialized, "Initialize twice?" );
239 
240  uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
241  uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
242  if ( xEnAc.is() )
243  {
244  uno::Reference<container::XEnumeration> xEnum =
245  xEnAc->createContentEnumeration( "com.sun.star.sheet.AddIn" );
246  if ( xEnum.is() )
247  {
248  // loop through all AddIns
249  while ( xEnum->hasMoreElements() )
250  {
251  uno::Any aAddInAny = xEnum->nextElement();
252 
253  try
254  {
255  uno::Reference<uno::XInterface> xIntFac;
256  aAddInAny >>= xIntFac;
257  if ( xIntFac.is() )
258  {
259  // #i59984# try XSingleComponentFactory in addition to (old) XSingleServiceFactory,
260  // passing the context to the component
261 
262  uno::Reference<uno::XInterface> xInterface;
263  uno::Reference<uno::XComponentContext> xCtx(
265  uno::Reference<lang::XSingleComponentFactory> xCFac( xIntFac, uno::UNO_QUERY );
266  if (xCFac.is())
267  {
268  xInterface = xCFac->createInstanceWithContext(xCtx);
269  if (xInterface.is())
270  ReadFromAddIn( xInterface );
271  }
272 
273  if (!xInterface.is())
274  {
275  uno::Reference<lang::XSingleServiceFactory> xFac( xIntFac, uno::UNO_QUERY );
276  if ( xFac.is() )
277  {
278  xInterface = xFac->createInstance();
279  if (xInterface.is())
280  ReadFromAddIn( xInterface );
281  }
282  }
283  }
284  } catch ( const uno::Exception& ) {
285  SAL_WARN ( "sc", "Failed to initialize create instance of sheet.AddIn" );
286  }
287  }
288  }
289  }
290 
291  // ReadConfiguration is called after looking at the AddIn implementations.
292  // Duplicated are skipped (by using the service information, they don't have to be updated again
293  // when argument information is needed).
295 
296  bInitialized = true; // with or without functions
297 }
298 
299 static sal_uInt16 lcl_GetCategory( const OUString& rName )
300 {
301  static const char* aFuncNames[SC_FUNCGROUP_COUNT] =
302  {
303  // array index = ID - 1 (ID starts at 1)
304  // all upper case
305  "Database", // ID_FUNCTION_GRP_DATABASE
306  "Date&Time", // ID_FUNCTION_GRP_DATETIME
307  "Financial", // ID_FUNCTION_GRP_FINANCIAL
308  "Information", // ID_FUNCTION_GRP_INFO
309  "Logical", // ID_FUNCTION_GRP_LOGIC
310  "Mathematical", // ID_FUNCTION_GRP_MATH
311  "Matrix", // ID_FUNCTION_GRP_MATRIX
312  "Statistical", // ID_FUNCTION_GRP_STATISTIC
313  "Spreadsheet", // ID_FUNCTION_GRP_TABLE
314  "Text", // ID_FUNCTION_GRP_TEXT
315  "Add-In" // ID_FUNCTION_GRP_ADDINS
316  };
317  for (sal_uInt16 i=0; i<SC_FUNCGROUP_COUNT; i++)
318  if ( rName.equalsAscii( aFuncNames[i] ) )
319  return i+1; // IDs start at 1
320 
321  return ID_FUNCTION_GRP_ADDINS; // if not found, use Add-In group
322 }
323 
324 #define CFGPATH_ADDINS "Office.CalcAddIns/AddInInfo"
325 #define CFGSTR_ADDINFUNCTIONS "AddInFunctions"
326 
327 #define CFG_FUNCPROP_DISPLAYNAME 0
328 #define CFG_FUNCPROP_DESCRIPTION 1
329 #define CFG_FUNCPROP_CATEGORY 2
330 #define CFG_FUNCPROP_COUNT 3
331 #define CFGSTR_DISPLAYNAME "DisplayName"
332 #define CFGSTR_DESCRIPTION "Description"
333 #define CFGSTR_CATEGORY "Category"
334 // CategoryDisplayName is ignored for now
335 
336 #define CFGSTR_COMPATIBILITYNAME "CompatibilityName"
337 #define CFGSTR_PARAMETERS "Parameters"
338 
340 {
341  // called only from Initialize
342 
343  ScAddInCfg& rAddInConfig = SC_MOD()->GetAddInCfg();
344 
345  // additional, temporary config item for the compatibility names
346  ScLinkConfigItem aAllLocalesConfig( CFGPATH_ADDINS, ConfigItemMode::AllLocales );
347  // CommitLink is not used (only reading values)
348 
349  const OUString sSlash('/');
350 
351  // get the list of add-ins (services)
352  const uno::Sequence<OUString> aServiceNames = rAddInConfig.GetNodeNames( "" );
353 
354  for ( const OUString& aServiceName : aServiceNames )
355  {
356  ScUnoAddInHelpIdGenerator aHelpIdGenerator( aServiceName );
357 
358  OUString aFunctionsPath(aServiceName + sSlash + CFGSTR_ADDINFUNCTIONS);
359 
360  uno::Sequence<OUString> aFunctionNames = rAddInConfig.GetNodeNames( aFunctionsPath );
361  sal_Int32 nNewCount = aFunctionNames.getLength();
362 
363  // allocate pointers
364 
365  long nOld = nFuncCount;
366  nFuncCount = nNewCount+nOld;
367  if ( nOld )
368  {
369  std::unique_ptr<std::unique_ptr<ScUnoAddInFuncData>[]> ppNew(new std::unique_ptr<ScUnoAddInFuncData>[nFuncCount]);
370  for (long i=0; i<nOld; i++)
371  ppNew[i] = std::move(ppFuncData[i]);
372  ppFuncData = std::move(ppNew);
373  }
374  else
375  ppFuncData.reset( new std::unique_ptr<ScUnoAddInFuncData>[nFuncCount] );
376 
377  //TODO: adjust bucket count?
378  if ( !pExactHashMap )
379  pExactHashMap.reset( new ScAddInHashMap );
380  if ( !pNameHashMap )
381  pNameHashMap.reset( new ScAddInHashMap );
382  if ( !pLocalHashMap )
383  pLocalHashMap.reset( new ScAddInHashMap );
384 
385  //TODO: get the function information in a single call for all functions?
386 
387  const OUString* pFuncNameArray = aFunctionNames.getConstArray();
388  for ( sal_Int32 nFuncPos = 0; nFuncPos < nNewCount; nFuncPos++ )
389  {
390  ppFuncData[nFuncPos+nOld] = nullptr;
391 
392  // stored function name: (service name).(function)
393  OUString aFuncName = aServiceName + "." + pFuncNameArray[nFuncPos];
394 
395  // skip the function if already known (read from old AddIn service)
396 
397  if ( pExactHashMap->find( aFuncName ) == pExactHashMap->end() )
398  {
399  OUString aLocalName;
400  OUString aDescription;
401  sal_uInt16 nCategory = ID_FUNCTION_GRP_ADDINS;
402 
403  // get direct information on the function
404 
405  OUString aFuncPropPath = aFunctionsPath + sSlash + pFuncNameArray[nFuncPos] + sSlash;
406 
407  uno::Sequence<OUString> aFuncPropNames{
408  (aFuncPropPath + CFGSTR_DISPLAYNAME), // CFG_FUNCPROP_DISPLAYNAME
409  (aFuncPropPath + CFGSTR_DESCRIPTION), // CFG_FUNCPROP_DESCRIPTION
410  (aFuncPropPath + CFGSTR_CATEGORY)}; // CFG_FUNCPROP_CATEGORY
411 
412  uno::Sequence<uno::Any> aFuncProperties = rAddInConfig.GetProperties( aFuncPropNames );
413  if ( aFuncProperties.getLength() == CFG_FUNCPROP_COUNT )
414  {
415  aFuncProperties[CFG_FUNCPROP_DISPLAYNAME] >>= aLocalName;
416  aFuncProperties[CFG_FUNCPROP_DESCRIPTION] >>= aDescription;
417 
418  OUString aCategoryName;
419  aFuncProperties[CFG_FUNCPROP_CATEGORY] >>= aCategoryName;
420  nCategory = lcl_GetCategory( aCategoryName );
421  }
422 
423  // get compatibility names
424 
425  ::std::vector<ScUnoAddInFuncData::LocalizedName> aCompNames;
426 
427  OUString aCompPath(aFuncPropPath + CFGSTR_COMPATIBILITYNAME);
428  uno::Sequence<OUString> aCompPropNames( &aCompPath, 1 );
429 
430  uno::Sequence<uno::Any> aCompProperties = aAllLocalesConfig.GetProperties( aCompPropNames );
431  if ( aCompProperties.getLength() == 1 )
432  {
433  uno::Sequence<beans::PropertyValue> aLocalEntries;
434  if ( aCompProperties[0] >>= aLocalEntries )
435  {
436  for ( const beans::PropertyValue& rConfig : std::as_const(aLocalEntries) )
437  {
438  // PropertyValue name is the locale ("convert" from
439  // string to canonicalize)
440  OUString aLocale( LanguageTag( rConfig.Name, true).getBcp47( false));
441  // PropertyValue value is the localized value (string in this case)
442  OUString aName;
443  rConfig.Value >>= aName;
444  aCompNames.emplace_back( aLocale, aName);
445  }
446  }
447  }
448 
449  // get argument info
450 
451  std::unique_ptr<ScAddInArgDesc[]> pVisibleArgs;
452  long nVisibleCount = 0;
453 
454  OUString aArgumentsPath(aFuncPropPath + CFGSTR_PARAMETERS);
455 
456  const uno::Sequence<OUString> aArgumentNames = rAddInConfig.GetNodeNames( aArgumentsPath );
457  sal_Int32 nArgumentCount = aArgumentNames.getLength();
458  if ( nArgumentCount )
459  {
460  // get DisplayName and Description for each argument
461  uno::Sequence<OUString> aArgPropNames( nArgumentCount * 2 );
462  OUString* pPropNameArray = aArgPropNames.getArray();
463 
464  sal_Int32 nIndex = 0;
465  for ( const OUString& rArgName : aArgumentNames )
466  {
467  OUString aOneArgPath = aArgumentsPath + sSlash + rArgName + sSlash;
468 
469  pPropNameArray[nIndex++] = aOneArgPath
471  pPropNameArray[nIndex++] = aOneArgPath
473  }
474 
475  uno::Sequence<uno::Any> aArgProperties = rAddInConfig.GetProperties( aArgPropNames );
476  if ( aArgProperties.getLength() == aArgPropNames.getLength() )
477  {
478  const OUString* pArgNameArray = aArgumentNames.getConstArray();
479  const uno::Any* pPropArray = aArgProperties.getConstArray();
480  OUString sDisplayName;
481  OUString sDescription;
482 
483  ScAddInArgDesc aDesc;
484  aDesc.eType = SC_ADDINARG_NONE; // arg type is not in configuration
485  aDesc.bOptional = false;
486 
487  nVisibleCount = nArgumentCount;
488  pVisibleArgs.reset(new ScAddInArgDesc[nVisibleCount]);
489 
490  nIndex = 0;
491  for ( sal_Int32 nArgument = 0; nArgument < nArgumentCount; nArgument++ )
492  {
493  pPropArray[nIndex++] >>= sDisplayName;
494  pPropArray[nIndex++] >>= sDescription;
495 
496  aDesc.aInternalName = pArgNameArray[nArgument];
497  aDesc.aName = sDisplayName;
498  aDesc.aDescription = sDescription;
499 
500  pVisibleArgs[nArgument] = aDesc;
501  }
502  }
503  }
504 
505  OString sHelpId = aHelpIdGenerator.GetHelpId( pFuncNameArray[nFuncPos] );
506 
507  uno::Reference<reflection::XIdlMethod> xFunc; // remains empty
508  uno::Any aObject; // also empty
509 
510  // create and insert into the array
511 
513  aFuncName, aLocalName, aDescription,
514  nCategory, sHelpId,
515  xFunc, aObject,
516  nVisibleCount, pVisibleArgs.get(), SC_CALLERPOS_NONE );
517 
518  pData->SetCompNames( aCompNames );
519 
520  ppFuncData[nFuncPos+nOld].reset(pData);
521 
522  pExactHashMap->emplace(
523  pData->GetOriginalName(),
524  pData );
525  pNameHashMap->emplace(
526  pData->GetUpperName(),
527  pData );
528  pLocalHashMap->emplace(
529  pData->GetUpperLocal(),
530  pData );
531  }
532  }
533  }
534 }
535 
537 {
538  const OUString& aFullName = rFuncData.GetOriginalName();
539  sal_Int32 nPos = aFullName.lastIndexOf( '.' );
540  if ( nPos <= 0 )
541  return;
542 
543  OUString aServiceName = aFullName.copy( 0, nPos );
544 
545  try
546  {
547  uno::Reference<lang::XMultiServiceFactory> xServiceFactory = comphelper::getProcessServiceFactory();
548  uno::Reference<uno::XInterface> xInterface( xServiceFactory->createInstance( aServiceName ) );
549 
550  if (xInterface.is())
551  UpdateFromAddIn( xInterface, aServiceName );
552  }
553  catch (const uno::Exception &)
554  {
555  SAL_WARN ("sc", "Failed to create addin component '"
556  << aServiceName << "'");
557  }
558 }
559 
560 bool ScUnoAddInCollection::GetExcelName( const OUString& rCalcName,
561  LanguageType eDestLang, OUString& rRetExcelName )
562 {
563  const ScUnoAddInFuncData* pFuncData = GetFuncData( rCalcName );
564  if ( pFuncData )
565  return pFuncData->GetExcelName( eDestLang, rRetExcelName);
566  return false;
567 }
568 
569 bool ScUnoAddInCollection::GetCalcName( const OUString& rExcelName, OUString& rRetCalcName )
570 {
571  if (!bInitialized)
572  Initialize();
573 
574  OUString aUpperCmp = ScGlobal::getCharClassPtr()->uppercase(rExcelName);
575 
576  for (long i=0; i<nFuncCount; i++)
577  {
578  ScUnoAddInFuncData* pFuncData = ppFuncData[i].get();
579  if ( pFuncData )
580  {
581  const ::std::vector<ScUnoAddInFuncData::LocalizedName>& rNames = pFuncData->GetCompNames();
582  auto bFound = std::any_of(rNames.begin(), rNames.end(),
583  [&aUpperCmp](const ScUnoAddInFuncData::LocalizedName& rName) {
584  return ScGlobal::getCharClassPtr()->uppercase( rName.maName ) == aUpperCmp; });
585  if (bFound)
586  {
587  //TODO: store upper case for comparing?
588 
589  // use the first function that has this name for any language
590  rRetCalcName = pFuncData->GetOriginalName();
591  return true;
592  }
593  }
594  }
595  return false;
596 }
597 
598 static bool IsTypeName( const OUString& rName, const uno::Type& rType )
599 {
600  return rName == rType.getTypeName();
601 }
602 
603 static bool lcl_ValidReturnType( const uno::Reference<reflection::XIdlClass>& xClass )
604 {
605  // this must match with ScUnoAddInCall::SetResult
606 
607  if ( !xClass.is() ) return false;
608 
609  switch (xClass->getTypeClass())
610  {
611  case uno::TypeClass_ANY: // variable type
612  case uno::TypeClass_ENUM: //TODO: ???
613  case uno::TypeClass_BOOLEAN:
614  case uno::TypeClass_CHAR:
615  case uno::TypeClass_BYTE:
616  case uno::TypeClass_SHORT:
617  case uno::TypeClass_UNSIGNED_SHORT:
618  case uno::TypeClass_LONG:
619  case uno::TypeClass_UNSIGNED_LONG:
620  case uno::TypeClass_FLOAT:
621  case uno::TypeClass_DOUBLE:
622  case uno::TypeClass_STRING:
623  return true; // values or string
624 
625  case uno::TypeClass_INTERFACE:
626  {
627  // return type XInterface may contain a XVolatileResult
628  //TODO: XIdlClass needs getType() method!
629 
630  OUString sName = xClass->getName();
631  return (
634  }
635 
636  default:
637  {
638  // nested sequences for arrays
639  //TODO: XIdlClass needs getType() method!
640 
641  OUString sName = xClass->getName();
642  return (
643  IsTypeName( sName, cppu::UnoType<uno::Sequence< uno::Sequence<sal_Int32> >>::get() ) ||
644  IsTypeName( sName, cppu::UnoType<uno::Sequence< uno::Sequence<double> >>::get() ) ||
645  IsTypeName( sName, cppu::UnoType<uno::Sequence< uno::Sequence<OUString> >>::get() ) ||
646  IsTypeName( sName, cppu::UnoType<uno::Sequence< uno::Sequence<uno::Any> >>::get() ) );
647  }
648  }
649 }
650 
651 static ScAddInArgumentType lcl_GetArgType( const uno::Reference<reflection::XIdlClass>& xClass )
652 {
653  if (!xClass.is())
654  return SC_ADDINARG_NONE;
655 
656  uno::TypeClass eType = xClass->getTypeClass();
657 
658  if ( eType == uno::TypeClass_LONG ) //TODO: other integer types?
659  return SC_ADDINARG_INTEGER;
660 
661  if ( eType == uno::TypeClass_DOUBLE )
662  return SC_ADDINARG_DOUBLE;
663 
664  if ( eType == uno::TypeClass_STRING )
665  return SC_ADDINARG_STRING;
666 
667  //TODO: XIdlClass needs getType() method!
668  OUString sName = xClass->getName();
669 
670  if (IsTypeName( sName, cppu::UnoType<uno::Sequence< uno::Sequence<sal_Int32> >>::get() ))
672 
673  if (IsTypeName( sName, cppu::UnoType<uno::Sequence< uno::Sequence<double> >>::get() ))
675 
676  if (IsTypeName( sName, cppu::UnoType<uno::Sequence< uno::Sequence<OUString> >>::get() ))
678 
679  if (IsTypeName( sName, cppu::UnoType<uno::Sequence< uno::Sequence<uno::Any> >>::get() ))
681 
684 
686  return SC_ADDINARG_CELLRANGE;
687 
689  return SC_ADDINARG_CALLER;
690 
691  if (IsTypeName( sName, cppu::UnoType<uno::Sequence<uno::Any>>::get() ))
692  return SC_ADDINARG_VARARGS;
693 
694  return SC_ADDINARG_NONE;
695 }
696 
697 void ScUnoAddInCollection::ReadFromAddIn( const uno::Reference<uno::XInterface>& xInterface )
698 {
699  uno::Reference<sheet::XAddIn> xAddIn( xInterface, uno::UNO_QUERY );
700  uno::Reference<lang::XServiceName> xName( xInterface, uno::UNO_QUERY );
701  if ( !(xAddIn.is() && xName.is()) )
702  return;
703 
704  // fdo50118 when GetUseEnglishFunctionName() returns true, set the
705  // locale to en-US to get English function names
706  if ( SC_MOD()->GetFormulaOptions().GetUseEnglishFuncName() )
707  xAddIn->setLocale( lang::Locale( "en", "US", ""));
708  else
709  xAddIn->setLocale( Application::GetSettings().GetUILanguageTag().getLocale());
710 
711  OUString aServiceName( xName->getServiceName() );
712  ScUnoAddInHelpIdGenerator aHelpIdGenerator( aServiceName );
713 
714  //TODO: pass XIntrospection to ReadFromAddIn
715 
716  uno::Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext();
717 
718  uno::Reference<beans::XIntrospection> xIntro = beans::theIntrospection::get( xContext );
719  uno::Any aObject;
720  aObject <<= xAddIn;
721  uno::Reference<beans::XIntrospectionAccess> xAcc = xIntro->inspect(aObject);
722  if (!xAcc.is())
723  return;
724 
725  uno::Sequence< uno::Reference<reflection::XIdlMethod> > aMethods =
726  xAcc->getMethods( beans::MethodConcept::ALL );
727  long nNewCount = aMethods.getLength();
728  if ( !nNewCount )
729  return;
730 
731  long nOld = nFuncCount;
732  nFuncCount = nNewCount+nOld;
733  if ( nOld )
734  {
735  std::unique_ptr<std::unique_ptr<ScUnoAddInFuncData>[]> ppNew(new std::unique_ptr<ScUnoAddInFuncData>[nFuncCount]);
736  for (long i=0; i<nOld; i++)
737  ppNew[i] = std::move(ppFuncData[i]);
738  ppFuncData = std::move(ppNew);
739  }
740  else
741  ppFuncData.reset(new std::unique_ptr<ScUnoAddInFuncData>[nFuncCount]);
742 
743  //TODO: adjust bucket count?
744  if ( !pExactHashMap )
745  pExactHashMap.reset( new ScAddInHashMap );
746  if ( !pNameHashMap )
747  pNameHashMap.reset( new ScAddInHashMap );
748  if ( !pLocalHashMap )
749  pLocalHashMap.reset( new ScAddInHashMap );
750 
751  const uno::Reference<reflection::XIdlMethod>* pArray = aMethods.getConstArray();
752  for (long nFuncPos=0; nFuncPos<nNewCount; nFuncPos++)
753  {
754  ppFuncData[nFuncPos+nOld] = nullptr;
755 
756  uno::Reference<reflection::XIdlMethod> xFunc = pArray[nFuncPos];
757  if (xFunc.is())
758  {
759  // leave out internal functions
760  uno::Reference<reflection::XIdlClass> xClass =
761  xFunc->getDeclaringClass();
762  bool bSkip = true;
763  if ( xClass.is() )
764  {
765  //TODO: XIdlClass needs getType() method!
766  OUString sName = xClass->getName();
767  bSkip = (
768  IsTypeName( sName,
770  IsTypeName( sName,
772  IsTypeName( sName,
774  IsTypeName( sName,
776  }
777  if (!bSkip)
778  {
779  uno::Reference<reflection::XIdlClass> xReturn =
780  xFunc->getReturnType();
781  if ( !lcl_ValidReturnType( xReturn ) )
782  bSkip = true;
783  }
784  if (!bSkip)
785  {
786  OUString aFuncU = xFunc->getName();
787 
788  // stored function name: (service name).(function)
789  OUString aFuncName = aServiceName + "." + aFuncU;
790 
791  bool bValid = true;
792  long nVisibleCount = 0;
793  long nCallerPos = SC_CALLERPOS_NONE;
794 
795  uno::Sequence<reflection::ParamInfo> aParams =
796  xFunc->getParameterInfos();
797  long nParamCount = aParams.getLength();
798  const reflection::ParamInfo* pParArr = aParams.getConstArray();
799  long nParamPos;
800  for (nParamPos=0; nParamPos<nParamCount; nParamPos++)
801  {
802  if ( pParArr[nParamPos].aMode != reflection::ParamMode_IN )
803  bValid = false;
804  uno::Reference<reflection::XIdlClass> xParClass =
805  pParArr[nParamPos].aType;
806  ScAddInArgumentType eArgType = lcl_GetArgType( xParClass );
807  if ( eArgType == SC_ADDINARG_NONE )
808  bValid = false;
809  else if ( eArgType == SC_ADDINARG_CALLER )
810  nCallerPos = nParamPos;
811  else
812  ++nVisibleCount;
813  }
814  if (bValid)
815  {
816  sal_uInt16 nCategory = lcl_GetCategory(
817  xAddIn->getProgrammaticCategoryName( aFuncU ) );
818 
819  OString sHelpId = aHelpIdGenerator.GetHelpId( aFuncU );
820 
821  OUString aLocalName;
822  try
823  {
824  aLocalName = xAddIn->
825  getDisplayFunctionName( aFuncU );
826  }
827  catch(uno::Exception&)
828  {
829  aLocalName = "###";
830  }
831 
832  OUString aDescription;
833  try
834  {
835  aDescription = xAddIn->
836  getFunctionDescription( aFuncU );
837  }
838  catch(uno::Exception&)
839  {
840  aDescription = "###";
841  }
842 
843  std::unique_ptr<ScAddInArgDesc[]> pVisibleArgs;
844  if ( nVisibleCount > 0 )
845  {
846  ScAddInArgDesc aDesc;
847  pVisibleArgs.reset(new ScAddInArgDesc[nVisibleCount]);
848  long nDestPos = 0;
849  for (nParamPos=0; nParamPos<nParamCount; nParamPos++)
850  {
851  uno::Reference<reflection::XIdlClass> xParClass =
852  pParArr[nParamPos].aType;
853  ScAddInArgumentType eArgType = lcl_GetArgType( xParClass );
854  if ( eArgType != SC_ADDINARG_CALLER )
855  {
856  OUString aArgName;
857  try
858  {
859  aArgName = xAddIn->
860  getDisplayArgumentName( aFuncU, nParamPos );
861  }
862  catch(uno::Exception&)
863  {
864  aArgName = "###";
865  }
866  OUString aArgDesc;
867  try
868  {
869  aArgDesc = xAddIn->
870  getArgumentDescription( aFuncU, nParamPos );
871  }
872  catch(uno::Exception&)
873  {
874  aArgDesc = "###";
875  }
876 
877  bool bOptional =
878  ( eArgType == SC_ADDINARG_VALUE_OR_ARRAY ||
879  eArgType == SC_ADDINARG_VARARGS );
880 
881  aDesc.eType = eArgType;
882  aDesc.aName = aArgName;
883  aDesc.aDescription = aArgDesc;
884  aDesc.bOptional = bOptional;
885  //TODO: initialize aInternalName only from config?
886  aDesc.aInternalName = pParArr[nParamPos].aName;
887 
888  pVisibleArgs[nDestPos++] = aDesc;
889  }
890  }
891  OSL_ENSURE( nDestPos==nVisibleCount, "wrong count" );
892  }
893 
894  ppFuncData[nFuncPos+nOld].reset( new ScUnoAddInFuncData(
895  aFuncName, aLocalName, aDescription,
896  nCategory, sHelpId,
897  xFunc, aObject,
898  nVisibleCount, pVisibleArgs.get(), nCallerPos ) );
899 
900  const ScUnoAddInFuncData* pData =
901  ppFuncData[nFuncPos+nOld].get();
902  pExactHashMap->emplace(
903  pData->GetOriginalName(),
904  pData );
905  pNameHashMap->emplace(
906  pData->GetUpperName(),
907  pData );
908  pLocalHashMap->emplace(
909  pData->GetUpperLocal(),
910  pData );
911  }
912  }
913  }
914  }
915 }
916 
917 static void lcl_UpdateFunctionList( const ScFunctionList& rFunctionList, const ScUnoAddInFuncData& rFuncData )
918 {
919  const OUString& aCompare = rFuncData.GetUpperLocal(); // as used in FillFunctionDescFromData
920 
921  sal_uLong nCount = rFunctionList.GetCount();
922  for (sal_uLong nPos=0; nPos<nCount; nPos++)
923  {
924  const ScFuncDesc* pDesc = rFunctionList.GetFunction( nPos );
925  if ( pDesc && pDesc->mxFuncName && *pDesc->mxFuncName == aCompare )
926  {
927  ScUnoAddInCollection::FillFunctionDescFromData( rFuncData, *const_cast<ScFuncDesc*>(pDesc) );
928  break;
929  }
930  }
931 }
932 
933 static const ScAddInArgDesc* lcl_FindArgDesc( const ScUnoAddInFuncData& rFuncData, const OUString& rArgIntName )
934 {
935  long nArgCount = rFuncData.GetArgumentCount();
936  const ScAddInArgDesc* pArguments = rFuncData.GetArguments();
937  for (long nPos=0; nPos<nArgCount; nPos++)
938  {
939  if ( pArguments[nPos].aInternalName == rArgIntName )
940  return &pArguments[nPos];
941  }
942  return nullptr;
943 }
944 
945 void ScUnoAddInCollection::UpdateFromAddIn( const uno::Reference<uno::XInterface>& xInterface,
946  const OUString& rServiceName )
947 {
948  uno::Reference<lang::XLocalizable> xLoc( xInterface, uno::UNO_QUERY );
949  if ( xLoc.is() ) // optional in new add-ins
950  {
951  // fdo50118 when GetUseEnglishFunctionName() returns true, set the
952  // locale to en-US to get English function names
953  if ( SC_MOD()->GetFormulaOptions().GetUseEnglishFuncName() )
954  xLoc->setLocale( lang::Locale( "en", "US", ""));
955  else
956  xLoc->setLocale( Application::GetSettings().GetUILanguageTag().getLocale());
957  }
958 
959  // if function list was already initialized, it must be updated
960 
961  ScFunctionList* pFunctionList = nullptr;
963  pFunctionList = ScGlobal::GetStarCalcFunctionList();
964 
965  // only get the function information from Introspection
966 
967  uno::Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext();
968 
969  uno::Reference<beans::XIntrospection> xIntro = beans::theIntrospection::get(xContext);
970  uno::Any aObject;
971  aObject <<= xInterface;
972  uno::Reference<beans::XIntrospectionAccess> xAcc = xIntro->inspect(aObject);
973  if (!xAcc.is())
974  return;
975 
976  const uno::Sequence< uno::Reference<reflection::XIdlMethod> > aMethods =
977  xAcc->getMethods( beans::MethodConcept::ALL );
978  for (const uno::Reference<reflection::XIdlMethod>& xFunc : aMethods)
979  {
980  if (xFunc.is())
981  {
982  OUString aFuncU = xFunc->getName();
983 
984  // stored function name: (service name).(function)
985  OUString aFuncName = rServiceName + "." + aFuncU;
986 
987  // internal names are skipped because no FuncData exists
988  ScUnoAddInFuncData* pOldData = const_cast<ScUnoAddInFuncData*>( GetFuncData( aFuncName ) );
989  if ( pOldData )
990  {
991  // Create new (complete) argument info.
992  // As in ReadFromAddIn, the reflection information is authoritative.
993  // Local names and descriptions from pOldData are looked up using the
994  // internal argument name.
995 
996  bool bValid = true;
997  long nVisibleCount = 0;
998  long nCallerPos = SC_CALLERPOS_NONE;
999 
1000  const uno::Sequence<reflection::ParamInfo> aParams =
1001  xFunc->getParameterInfos();
1002  long nParamCount = aParams.getLength();
1003  const reflection::ParamInfo* pParArr = aParams.getConstArray();
1004  for (long nParamPos=0; nParamPos<nParamCount; nParamPos++)
1005  {
1006  if ( pParArr[nParamPos].aMode != reflection::ParamMode_IN )
1007  bValid = false;
1008  uno::Reference<reflection::XIdlClass> xParClass =
1009  pParArr[nParamPos].aType;
1010  ScAddInArgumentType eArgType = lcl_GetArgType( xParClass );
1011  if ( eArgType == SC_ADDINARG_NONE )
1012  bValid = false;
1013  else if ( eArgType == SC_ADDINARG_CALLER )
1014  nCallerPos = nParamPos;
1015  else
1016  ++nVisibleCount;
1017  }
1018  if (bValid)
1019  {
1020  std::unique_ptr<ScAddInArgDesc[]> pVisibleArgs;
1021  if ( nVisibleCount > 0 )
1022  {
1023  ScAddInArgDesc aDesc;
1024  pVisibleArgs.reset(new ScAddInArgDesc[nVisibleCount]);
1025  long nDestPos = 0;
1026  for (const auto& rParam : aParams)
1027  {
1028  uno::Reference<reflection::XIdlClass> xParClass =
1029  rParam.aType;
1030  ScAddInArgumentType eArgType = lcl_GetArgType( xParClass );
1031  if ( eArgType != SC_ADDINARG_CALLER )
1032  {
1033  const ScAddInArgDesc* pOldArgDesc =
1034  lcl_FindArgDesc( *pOldData, rParam.aName );
1035  if ( pOldArgDesc )
1036  {
1037  aDesc.aName = pOldArgDesc->aName;
1038  aDesc.aDescription = pOldArgDesc->aDescription;
1039  }
1040  else
1041  aDesc.aName = aDesc.aDescription = "###";
1042 
1043  bool bOptional =
1044  ( eArgType == SC_ADDINARG_VALUE_OR_ARRAY ||
1045  eArgType == SC_ADDINARG_VARARGS );
1046 
1047  aDesc.eType = eArgType;
1048  aDesc.bOptional = bOptional;
1049  //TODO: initialize aInternalName only from config?
1050  aDesc.aInternalName = rParam.aName;
1051 
1052  pVisibleArgs[nDestPos++] = aDesc;
1053  }
1054  }
1055  OSL_ENSURE( nDestPos==nVisibleCount, "wrong count" );
1056  }
1057 
1058  pOldData->SetFunction( xFunc, aObject );
1059  pOldData->SetArguments( nVisibleCount, pVisibleArgs.get() );
1060  pOldData->SetCallerPos( nCallerPos );
1061 
1062  if ( pFunctionList )
1063  lcl_UpdateFunctionList( *pFunctionList, *pOldData );
1064  }
1065  }
1066  }
1067  }
1068 }
1069 
1070 const OUString & ScUnoAddInCollection::FindFunction( const OUString& rUpperName, bool bLocalFirst )
1071 {
1072  if (!bInitialized)
1073  Initialize();
1074 
1075  if (nFuncCount == 0)
1076  return EMPTY_OUSTRING;
1077 
1078  if ( bLocalFirst )
1079  {
1080  // first scan all local names (used for entering formulas)
1081 
1082  ScAddInHashMap::const_iterator iLook( pLocalHashMap->find( rUpperName ) );
1083  if ( iLook != pLocalHashMap->end() )
1084  return iLook->second->GetOriginalName();
1085  }
1086  else
1087  {
1088  // first scan international names (used when calling a function)
1089  //TODO: before that, check for exact match???
1090 
1091  ScAddInHashMap::const_iterator iLook( pNameHashMap->find( rUpperName ) );
1092  if ( iLook != pNameHashMap->end() )
1093  return iLook->second->GetOriginalName();
1094 
1095  // after that, scan all local names (to allow replacing old AddIns with Uno)
1096 
1097  iLook = pLocalHashMap->find( rUpperName );
1098  if ( iLook != pLocalHashMap->end() )
1099  return iLook->second->GetOriginalName();
1100  }
1101 
1102  return EMPTY_OUSTRING;
1103 }
1104 
1105 const ScUnoAddInFuncData* ScUnoAddInCollection::GetFuncData( const OUString& rName, bool bComplete )
1106 {
1107  if (!bInitialized)
1108  Initialize();
1109 
1110  // rName must be the exact internal name
1111 
1112  ScAddInHashMap::const_iterator iLook( pExactHashMap->find( rName ) );
1113  if ( iLook != pExactHashMap->end() )
1114  {
1115  const ScUnoAddInFuncData* pFuncData = iLook->second;
1116 
1117  if ( bComplete && !pFuncData->GetFunction().is() ) //TODO: extra flag?
1118  LoadComponent( *pFuncData );
1119 
1120  return pFuncData;
1121  }
1122 
1123  return nullptr;
1124 }
1125 
1127 {
1128  if (!bInitialized)
1129  Initialize();
1130 
1131  if (nIndex < nFuncCount)
1132  return ppFuncData[nIndex].get();
1133  return nullptr;
1134 }
1135 
1137 {
1138  if (!bInitialized)
1139  Initialize();
1140 
1141  // modify rName - input: exact name
1142 
1143  ScAddInHashMap::const_iterator iLook( pExactHashMap->find( rName ) );
1144  if ( iLook != pExactHashMap->end() )
1145  rName = iLook->second->GetUpperLocal(); //TODO: upper?
1146 }
1147 
1149 {
1150  if (!bInitialized)
1151  Initialize();
1152 
1153  return nFuncCount;
1154 }
1155 
1157 {
1158  if (!bInitialized)
1159  Initialize();
1160 
1161  if (nFunc >= nFuncCount || !ppFuncData[nFunc])
1162  return false;
1163 
1164  const ScUnoAddInFuncData& rFuncData = *ppFuncData[nFunc];
1165 
1166  return FillFunctionDescFromData( rFuncData, rDesc );
1167 }
1168 
1170 {
1171  rDesc.Clear();
1172 
1173  bool bIncomplete = !rFuncData.GetFunction().is(); //TODO: extra flag?
1174 
1175  long nArgCount = rFuncData.GetArgumentCount();
1176  if ( nArgCount > SAL_MAX_UINT16 )
1177  return false;
1178 
1179  if ( bIncomplete )
1180  nArgCount = 0; // if incomplete, fill without argument info (no wrong order)
1181 
1182  // nFIndex is set from outside
1183 
1184  rDesc.mxFuncName = rFuncData.GetUpperLocal(); //TODO: upper?
1185  rDesc.nCategory = rFuncData.GetCategory();
1186  rDesc.sHelpId = rFuncData.GetHelpId();
1187 
1188  OUString aDesc = rFuncData.GetDescription();
1189  if (aDesc.isEmpty())
1190  aDesc = rFuncData.GetLocalName(); // use name if no description is available
1191  rDesc.mxFuncDesc = aDesc ;
1192 
1193  // AddInArgumentType_CALLER is already left out in FuncData
1194 
1195  rDesc.nArgCount = static_cast<sal_uInt16>(nArgCount);
1196  if ( nArgCount )
1197  {
1198  bool bMultiple = false;
1199  const ScAddInArgDesc* pArgs = rFuncData.GetArguments();
1200 
1201  rDesc.maDefArgNames.clear();
1202  rDesc.maDefArgNames.resize(nArgCount);
1203  rDesc.maDefArgDescs.clear();
1204  rDesc.maDefArgDescs.resize(nArgCount);
1205  rDesc.pDefArgFlags = new ScFuncDesc::ParameterFlags[nArgCount];
1206  for ( long nArg=0; nArg<nArgCount; nArg++ )
1207  {
1208  rDesc.maDefArgNames[nArg] = pArgs[nArg].aName;
1209  rDesc.maDefArgDescs[nArg] = pArgs[nArg].aDescription;
1210  rDesc.pDefArgFlags[nArg].bOptional = pArgs[nArg].bOptional;
1211 
1212  // no empty names...
1213  if ( rDesc.maDefArgNames[nArg].isEmpty() )
1214  {
1215  OUString aDefName = "arg" + OUString::number( nArg+1 );
1216  rDesc.maDefArgNames[nArg] = aDefName;
1217  }
1218 
1219  // last argument repeated?
1220  if ( nArg+1 == nArgCount && ( pArgs[nArg].eType == SC_ADDINARG_VARARGS ) )
1221  bMultiple = true;
1222  }
1223 
1224  if ( bMultiple )
1225  rDesc.nArgCount += VAR_ARGS - 1; // VAR_ARGS means just one repeated arg
1226  }
1227 
1228  rDesc.bIncomplete = bIncomplete;
1229 
1230  return true;
1231 }
1232 
1234  long nParamCount ) :
1235  bValidCount( false ),
1236  nErrCode( FormulaError::NoCode ), // before function was called
1237  bHasString( true ),
1238  fValue( 0.0 ),
1239  xMatrix( nullptr )
1240 {
1241  pFuncData = rColl.GetFuncData( rName, true ); // need fully initialized data
1242  OSL_ENSURE( pFuncData, "Function Data missing" );
1243  if ( !pFuncData )
1244  return;
1245 
1246  long nDescCount = pFuncData->GetArgumentCount();
1247  const ScAddInArgDesc* pArgs = pFuncData->GetArguments();
1248 
1249  // is aVarArg sequence needed?
1250  if ( nParamCount >= nDescCount && nDescCount > 0 &&
1251  pArgs[nDescCount-1].eType == SC_ADDINARG_VARARGS )
1252  {
1253  long nVarCount = nParamCount - ( nDescCount - 1 ); // size of last argument
1254  aVarArg.realloc( nVarCount );
1255  bValidCount = true;
1256  }
1257  else if ( nParamCount <= nDescCount )
1258  {
1259  // all args behind nParamCount must be optional
1260  bValidCount = true;
1261  for (long i=nParamCount; i<nDescCount; i++)
1262  if ( !pArgs[i].bOptional )
1263  bValidCount = false;
1264  }
1265  // else invalid (too many arguments)
1266 
1267  if ( bValidCount )
1268  aArgs.realloc( nDescCount ); // sequence must always match function signature
1269 }
1270 
1272 {
1273  // pFuncData is deleted with ScUnoAddInCollection
1274 }
1275 
1277 {
1278  if ( pFuncData )
1279  {
1280  long nCount = pFuncData->GetArgumentCount();
1281  const ScAddInArgDesc* pArgs = pFuncData->GetArguments();
1282 
1283  // if last arg is sequence, use "any" type
1284  if ( nCount > 0 && nPos >= nCount-1 && pArgs[nCount-1].eType == SC_ADDINARG_VARARGS )
1286 
1287  if ( nPos < nCount )
1288  return pArgs[nPos].eType;
1289  }
1290  return SC_ADDINARG_VALUE_OR_ARRAY; //TODO: error code !!!!
1291 }
1292 
1294 {
1296 }
1297 
1298 void ScUnoAddInCall::SetCaller( const uno::Reference<uno::XInterface>& rInterface )
1299 {
1300  xCaller = rInterface;
1301 }
1302 
1304 {
1305  if (pObjSh)
1306  {
1307  uno::Reference<uno::XInterface> xInt( pObjSh->GetBaseModel(), uno::UNO_QUERY );
1308  SetCaller( xInt );
1309  }
1310 }
1311 
1312 void ScUnoAddInCall::SetParam( long nPos, const uno::Any& rValue )
1313 {
1314  if ( !pFuncData )
1315  return;
1316 
1317  long nCount = pFuncData->GetArgumentCount();
1318  const ScAddInArgDesc* pArgs = pFuncData->GetArguments();
1319  if ( nCount > 0 && nPos >= nCount-1 && pArgs[nCount-1].eType == SC_ADDINARG_VARARGS )
1320  {
1321  long nVarPos = nPos-(nCount-1);
1322  if ( nVarPos < aVarArg.getLength() )
1323  aVarArg.getArray()[nVarPos] = rValue;
1324  else
1325  {
1326  OSL_FAIL("wrong argument number");
1327  }
1328  }
1329  else if ( nPos < aArgs.getLength() )
1330  aArgs.getArray()[nPos] = rValue;
1331  else
1332  {
1333  OSL_FAIL("wrong argument number");
1334  }
1335 }
1336 
1338 {
1339  if ( !pFuncData )
1340  return;
1341 
1342  long nCount = pFuncData->GetArgumentCount();
1343  const ScAddInArgDesc* pArgs = pFuncData->GetArguments();
1344  if ( nCount > 0 && pArgs[nCount-1].eType == SC_ADDINARG_VARARGS )
1345  {
1346  // insert aVarArg as last argument
1347  //TODO: after inserting caller (to prevent copying twice)?
1348 
1349  OSL_ENSURE( aArgs.getLength() == nCount, "wrong argument count" );
1350  aArgs.getArray()[nCount-1] <<= aVarArg;
1351  }
1352 
1354  {
1355  uno::Any aCallerAny;
1356  aCallerAny <<= xCaller;
1357 
1358  long nUserLen = aArgs.getLength();
1359  long nCallPos = pFuncData->GetCallerPos();
1360  if (nCallPos>nUserLen) // should not happen
1361  {
1362  OSL_FAIL("wrong CallPos");
1363  nCallPos = nUserLen;
1364  }
1365 
1366  long nDestLen = nUserLen + 1;
1367  uno::Sequence<uno::Any> aRealArgs( nDestLen );
1368  uno::Any* pDest = aRealArgs.getArray();
1369 
1370  pDest = std::copy_n(aArgs.begin(), nCallPos, pDest);
1371  *pDest = aCallerAny;
1372  std::copy(std::next(aArgs.begin(), nCallPos), aArgs.end(), std::next(pDest));
1373 
1374  ExecuteCallWithArgs( aRealArgs );
1375  }
1376  else
1378 }
1379 
1380 void ScUnoAddInCall::ExecuteCallWithArgs(uno::Sequence<uno::Any>& rCallArgs)
1381 {
1382  // rCallArgs may not match argument descriptions (because of caller)
1383 
1384  uno::Reference<reflection::XIdlMethod> xFunction;
1385  uno::Any aObject;
1386  if ( pFuncData )
1387  {
1388  xFunction = pFuncData->GetFunction();
1389  aObject = pFuncData->GetObject();
1390  }
1391 
1392  if ( !xFunction.is() )
1393  return;
1394 
1395  uno::Any aAny;
1396  nErrCode = FormulaError::NONE;
1397 
1398  try
1399  {
1400  aAny = xFunction->invoke( aObject, rCallArgs );
1401  }
1402  catch(lang::IllegalArgumentException&)
1403  {
1404  nErrCode = FormulaError::IllegalArgument;
1405  }
1406  catch(const reflection::InvocationTargetException& rWrapped)
1407  {
1408  if ( rWrapped.TargetException.getValueType().equals(
1410  nErrCode = FormulaError::IllegalArgument;
1411  else if ( rWrapped.TargetException.getValueType().equals(
1413  nErrCode = FormulaError::NoConvergence;
1414  else
1415  nErrCode = FormulaError::NoValue;
1416  }
1417  catch(uno::Exception&)
1418  {
1419  nErrCode = FormulaError::NoValue;
1420  }
1421 
1422  if (nErrCode == FormulaError::NONE)
1423  SetResult( aAny ); // convert result to Calc types
1424 }
1425 
1426 template <typename T>
1427 static long lcl_GetMaxColCount(const uno::Sequence< uno::Sequence<T> >* pRowSeq)
1428 {
1429  if (!pRowSeq->hasElements())
1430  return 0;
1431 
1432  auto pRow = std::max_element(pRowSeq->begin(), pRowSeq->end(),
1433  [](const uno::Sequence<T>& a, const uno::Sequence<T>& b) {
1434  return a.getLength() < b.getLength(); });
1435  return pRow->getLength();
1436 }
1437 
1438 void ScUnoAddInCall::SetResult( const uno::Any& rNewRes )
1439 {
1440  nErrCode = FormulaError::NONE;
1441  xVarRes = nullptr;
1442 
1443  // Reflection* pRefl = rNewRes.getReflection();
1444 
1445  uno::TypeClass eClass = rNewRes.getValueTypeClass();
1446  const uno::Type& aType = rNewRes.getValueType();
1447  switch (eClass)
1448  {
1449  case uno::TypeClass_VOID:
1450  nErrCode = FormulaError::NotAvailable; // #NA
1451  break;
1452 
1453  case uno::TypeClass_ENUM:
1454  case uno::TypeClass_BOOLEAN:
1455  case uno::TypeClass_CHAR:
1456  case uno::TypeClass_BYTE:
1457  case uno::TypeClass_SHORT:
1458  case uno::TypeClass_UNSIGNED_SHORT:
1459  case uno::TypeClass_LONG:
1460  case uno::TypeClass_UNSIGNED_LONG:
1461  case uno::TypeClass_FLOAT:
1462  case uno::TypeClass_DOUBLE:
1463  {
1464  uno::TypeClass eMyClass;
1465  ScApiTypeConversion::ConvertAnyToDouble( fValue, eMyClass, rNewRes);
1466  bHasString = false;
1467  }
1468  break;
1469 
1470  case uno::TypeClass_STRING:
1471  {
1472  rNewRes >>= aString;
1473  bHasString = true;
1474  }
1475  break;
1476 
1477  case uno::TypeClass_INTERFACE:
1478  {
1479  //TODO: directly extract XVolatileResult from any?
1480  uno::Reference<uno::XInterface> xInterface;
1481  rNewRes >>= xInterface;
1482  if ( xInterface.is() )
1483  xVarRes.set( xInterface, uno::UNO_QUERY );
1484 
1485  if (!xVarRes.is())
1486  nErrCode = FormulaError::NoValue; // unknown interface
1487  }
1488  break;
1489 
1490  default:
1491  if ( aType.equals( cppu::UnoType<uno::Sequence< uno::Sequence<sal_Int32> >>::get() ) )
1492  {
1493  const uno::Sequence< uno::Sequence<sal_Int32> >* pRowSeq = nullptr;
1494 
1495  //TODO: use pointer from any!
1496  uno::Sequence< uno::Sequence<sal_Int32> > aSequence;
1497  if ( rNewRes >>= aSequence )
1498  pRowSeq = &aSequence;
1499 
1500  if ( pRowSeq )
1501  {
1502  long nRowCount = pRowSeq->getLength();
1503  long nMaxColCount = lcl_GetMaxColCount(pRowSeq);
1504  if ( nMaxColCount && nRowCount )
1505  {
1506  const uno::Sequence<sal_Int32>* pRowArr = pRowSeq->getConstArray();
1507  xMatrix = new ScMatrix(
1508  static_cast<SCSIZE>(nMaxColCount),
1509  static_cast<SCSIZE>(nRowCount), 0.0);
1510  for (long nRow=0; nRow<nRowCount; nRow++)
1511  {
1512  long nColCount = pRowArr[nRow].getLength();
1513  const sal_Int32* pColArr = pRowArr[nRow].getConstArray();
1514  for (long nCol=0; nCol<nColCount; nCol++)
1515  xMatrix->PutDouble( pColArr[nCol],
1516  static_cast<SCSIZE>(nCol),
1517  static_cast<SCSIZE>(nRow) );
1518  for (long nCol=nColCount; nCol<nMaxColCount; nCol++)
1519  xMatrix->PutDouble( 0.0,
1520  static_cast<SCSIZE>(nCol),
1521  static_cast<SCSIZE>(nRow) );
1522  }
1523  }
1524  }
1525  }
1526  else if ( aType.equals( cppu::UnoType<uno::Sequence< uno::Sequence<double> >>::get() ) )
1527  {
1528  const uno::Sequence< uno::Sequence<double> >* pRowSeq = nullptr;
1529 
1530  //TODO: use pointer from any!
1531  uno::Sequence< uno::Sequence<double> > aSequence;
1532  if ( rNewRes >>= aSequence )
1533  pRowSeq = &aSequence;
1534 
1535  if ( pRowSeq )
1536  {
1537  long nRowCount = pRowSeq->getLength();
1538  long nMaxColCount = lcl_GetMaxColCount(pRowSeq);
1539  if ( nMaxColCount && nRowCount )
1540  {
1541  const uno::Sequence<double>* pRowArr = pRowSeq->getConstArray();
1542  xMatrix = new ScMatrix(
1543  static_cast<SCSIZE>(nMaxColCount),
1544  static_cast<SCSIZE>(nRowCount), 0.0);
1545  for (long nRow=0; nRow<nRowCount; nRow++)
1546  {
1547  long nColCount = pRowArr[nRow].getLength();
1548  const double* pColArr = pRowArr[nRow].getConstArray();
1549  for (long nCol=0; nCol<nColCount; nCol++)
1550  xMatrix->PutDouble( pColArr[nCol],
1551  static_cast<SCSIZE>(nCol),
1552  static_cast<SCSIZE>(nRow) );
1553  for (long nCol=nColCount; nCol<nMaxColCount; nCol++)
1554  xMatrix->PutDouble( 0.0,
1555  static_cast<SCSIZE>(nCol),
1556  static_cast<SCSIZE>(nRow) );
1557  }
1558  }
1559  }
1560  }
1561  else if ( aType.equals( cppu::UnoType<uno::Sequence< uno::Sequence<OUString> >>::get() ) )
1562  {
1563  const uno::Sequence< uno::Sequence<OUString> >* pRowSeq = nullptr;
1564 
1565  //TODO: use pointer from any!
1566  uno::Sequence< uno::Sequence<OUString> > aSequence;
1567  if ( rNewRes >>= aSequence )
1568  pRowSeq = &aSequence;
1569 
1570  if ( pRowSeq )
1571  {
1572  long nRowCount = pRowSeq->getLength();
1573  long nMaxColCount = lcl_GetMaxColCount(pRowSeq);
1574  if ( nMaxColCount && nRowCount )
1575  {
1576  const uno::Sequence<OUString>* pRowArr = pRowSeq->getConstArray();
1577  xMatrix = new ScMatrix(
1578  static_cast<SCSIZE>(nMaxColCount),
1579  static_cast<SCSIZE>(nRowCount), 0.0);
1580  for (long nRow=0; nRow<nRowCount; nRow++)
1581  {
1582  long nColCount = pRowArr[nRow].getLength();
1583  const OUString* pColArr = pRowArr[nRow].getConstArray();
1584  for (long nCol=0; nCol<nColCount; nCol++)
1585  {
1586  xMatrix->PutString(
1587  svl::SharedString(pColArr[nCol]),
1588  static_cast<SCSIZE>(nCol), static_cast<SCSIZE>(nRow));
1589  }
1590  for (long nCol=nColCount; nCol<nMaxColCount; nCol++)
1591  {
1592  xMatrix->PutString(
1594  static_cast<SCSIZE>(nCol), static_cast<SCSIZE>(nRow));
1595  }
1596  }
1597  }
1598  }
1599  }
1600  else if ( aType.equals( cppu::UnoType<uno::Sequence< uno::Sequence<uno::Any> >>::get() ) )
1601  {
1603  }
1604 
1605  if (!xMatrix) // no array found
1606  nErrCode = FormulaError::NoValue; //TODO: code for error in return type???
1607  }
1608 }
1609 
1610 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Matrix data type that can store values of mixed types.
Definition: scmatrix.hxx:113
static bool IsTypeName(const OUString &rName, const uno::Type &rType)
Definition: addincol.cxx:598
const int nColCount
#define ID_FUNCTION_GRP_ADDINS
Definition: scfuncs.hxx:32
List of spreadsheet functions.
Definition: funcdesc.hxx:242
OUString aName
Definition: addincol.hxx:66
sal_Int32 nIndex
bool NeedsCaller() const
Definition: addincol.cxx:1293
const ::std::vector< LocalizedName > & GetCompNames() const
Definition: addincol.cxx:104
#define EMPTY_OUSTRING
Definition: global.hxx:214
bool bOptional
Parameter is optional.
Definition: funcdesc.hxx:212
std::unique_ptr< ContentProperties > pData
ScMatrixRef xMatrix
Definition: addincol.hxx:196
const ScUnoAddInFuncData * GetFuncData(const OUString &rName, bool bComplete=false)
Only if bComplete is set, the function reference and argument types are initialized (component may ha...
Definition: addincol.cxx:1105
sal_uInt16 char char * pDesc
Definition: callform.cxx:58
static OUString convertToBcp47(LanguageType nLangID)
sal_uIntPtr sal_uLong
Stores whether a parameter is optional or suppressed.
Definition: funcdesc.hxx:210
static const AllSettings & GetSettings()
static const ScAddInArgDesc * lcl_FindArgDesc(const ScUnoAddInFuncData &rFuncData, const OUString &rArgIntName)
Definition: addincol.cxx:933
const OUString & GetLocalName() const
Definition: addincol.hxx:111
const OUString & getBcp47(bool bResolveSystem=true) const
static bool ConvertAnyToDouble(double &o_fVal, css::uno::TypeClass &o_eClass, const css::uno::Any &rAny)
Convert a uno::Any to double if possible, including integer types.
Definition: rangeseq.cxx:327
OUString aDescription
Definition: addincol.hxx:67
void LoadComponent(const ScUnoAddInFuncData &rFuncData)
Definition: addincol.cxx:536
Sequence< OUString > aServiceNames
static long lcl_GetMaxColCount(const uno::Sequence< uno::Sequence< T > > *pRowSeq)
Definition: addincol.cxx:1427
std::unordered_map< OUString, const ScUnoAddInFuncData * > ScAddInHashMap
Definition: addincol.hxx:43
const OUString & GetUpperName() const
Definition: addincol.hxx:112
OUString aUpperName
for entering formulas
Definition: addincol.hxx:86
long GetArgumentCount() const
Definition: addincol.hxx:117
const OUString & GetDescription() const
Definition: addincol.hxx:120
void SetParam(long nPos, const css::uno::Any &rValue)
Definition: addincol.cxx:1312
const css::uno::Any & GetObject() const
Definition: addincol.hxx:116
#define CFG_FUNCPROP_COUNT
Definition: addincol.cxx:330
OString GetHelpId(const OUString &rFuncName) const
#define SC_FUNCGROUP_COUNT
Definition: funcdesc.hxx:302
bool FillFunctionDesc(long nFunc, ScFuncDesc &rDesc)
Definition: addincol.cxx:1156
css::uno::Reference< css::sheet::XVolatileResult > xVarRes
Definition: addincol.hxx:197
void SetFunction(const css::uno::Reference< css::reflection::XIdlMethod > &rNewFunc, const css::uno::Any &rNewObj)
Definition: addincol.cxx:191
std::unique_ptr< ScAddInHashMap > pExactHashMap
exact internal name
Definition: addincol.hxx:139
bool GetExcelName(const OUString &rCalcName, LanguageType eDestLang, OUString &rRetExcelName)
leave rRetExcelName unchanged, if no matching name is found
Definition: addincol.cxx:560
char sal_uInt16 & nParamCount
Definition: callform.cxx:54
void SetCaller(const css::uno::Reference< css::uno::XInterface > &rInterface)
Definition: addincol.cxx:1298
#define SAL_MAX_UINT16
ScAddInArgumentType eType
Definition: addincol.hxx:68
#define CFG_FUNCPROP_DISPLAYNAME
Definition: addincol.cxx:327
int nCount
Generates help IDs for standard Calc AddIns.
Definition: addinhelpid.hxx:29
ParameterFlags * pDefArgFlags
Flags for each parameter.
Definition: funcdesc.hxx:221
void ExecuteCall()
Definition: addincol.cxx:1337
#define CFGSTR_DISPLAYNAME
Definition: addincol.cxx:331
css::uno::Reference< css::frame::XModel > GetBaseModel() const
const char * sName
const OUString & GetUpperLocal() const
Definition: addincol.hxx:113
css::uno::Reference< css::uno::XInterface > xCaller
Definition: addincol.hxx:189
css::uno::Sequence< css::uno::Any > GetProperties(const css::uno::Sequence< OUString > &rNames)
Definition: addincfg.hxx:36
DocumentType eType
#define CFGSTR_ADDINFUNCTIONS
Definition: addincol.cxx:325
XPropertySet.
Definition: addincol.hxx:59
void SetArguments(long nNewCount, const ScAddInArgDesc *pNewDescs)
Definition: addincol.cxx:197
sal_uInt16 nCategory
Function category.
Definition: funcdesc.hxx:223
OUString aUpperLocal
for entering formulas
Definition: addincol.hxx:87
int i
uno_Any a
ScAddInArgumentType GetArgType(long nPos)
Definition: addincol.cxx:1276
static bool lcl_ValidReturnType(const uno::Reference< reflection::XIdlClass > &xClass)
Definition: addincol.cxx:603
std::unique_ptr< ScAddInHashMap > pLocalHashMap
localized name upper
Definition: addincol.hxx:141
#define VAR_ARGS
std::vector< OUString > maDefArgDescs
Description(s) of parameter(s)
Definition: funcdesc.hxx:220
#define CFGSTR_CATEGORY
Definition: addincol.cxx:333
#define SC_MOD()
Definition: scmod.hxx:253
mutable::std::vector< LocalizedName > maCompNames
Definition: addincol.hxx:97
const OUString & FindFunction(const OUString &rUpperName, bool bLocalFirst)
User entered name. rUpperName MUST already be upper case!
Definition: addincol.cxx:1070
static bool FillFunctionDescFromData(const ScUnoAddInFuncData &rFuncData, ScFuncDesc &rDesc)
Definition: addincol.cxx:1169
void LocalizeString(OUString &rName)
modify rName - input: exact name
Definition: addincol.cxx:1136
OUString uppercase(const OUString &rStr, sal_Int32 nPos, sal_Int32 nCount) const
std::unique_ptr< ScAddInHashMap > pNameHashMap
internal name upper
Definition: addincol.hxx:140
void SetCallerPos(long nNewPos)
Definition: addincol.cxx:210
std::optional< OUString > mxFuncDesc
Description of function.
Definition: funcdesc.hxx:218
sal_uInt16 GetCategory() const
Definition: addincol.hxx:121
void ReadFromAddIn(const css::uno::Reference< css::uno::XInterface > &xInterface)
Definition: addincol.cxx:697
::std::vector< OUString > getFallbackStrings(bool bIncludeFullBcp47) const
Reference< XComponentContext > getComponentContext(Reference< XMultiServiceFactory > const &factory)
const OUString & GetOriginalName() const
Definition: addincol.hxx:110
const ScFuncDesc * GetFunction(sal_uInt32 nIndex) const
Definition: funcdesc.cxx:1015
OUString aInternalName
used to match configuration and reflection information
Definition: addincol.hxx:65
#define CFG_FUNCPROP_DESCRIPTION
Definition: addincol.cxx:328
const ScAddInArgDesc * GetArguments() const
Definition: addincol.hxx:118
FormulaError
static ScFunctionList * GetStarCalcFunctionList()
Definition: global.cxx:619
void UpdateFromAddIn(const css::uno::Reference< css::uno::XInterface > &xInterface, const OUString &rServiceName)
Definition: addincol.cxx:945
std::unique_ptr< ScAddInArgDesc[]> pArgDescs
Definition: addincol.hxx:93
#define CFGSTR_COMPATIBILITYNAME
Definition: addincol.cxx:336
ScUnoAddInCall(ScUnoAddInCollection &rColl, const OUString &rName, long nParamCount)
Definition: addincol.cxx:1233
static ScAddInArgumentType lcl_GetArgType(const uno::Reference< reflection::XIdlClass > &xClass)
Definition: addincol.cxx:651
const LanguageTag & getLocale()
long GetCallerPos() const
Definition: addincol.hxx:119
static bool HasStarCalcFunctionList()
Definition: global.cxx:614
const css::uno::Reference< css::reflection::XIdlMethod > & GetFunction() const
Definition: addincol.hxx:114
css::uno::Sequence< css::uno::Any > aVarArg
Definition: addincol.hxx:188
FormulaError nErrCode
Definition: addincol.hxx:192
Reference< XMultiServiceFactory > getProcessServiceFactory()
std::optional< OUString > mxFuncName
Function name.
Definition: funcdesc.hxx:217
#define CFGSTR_DESCRIPTION
Definition: addincol.cxx:332
void Clear()
Clears the object.
Definition: funcdesc.cxx:118
css::uno::Sequence< css::uno::Any > aArgs
Definition: addincol.hxx:187
void SetCallerFromObjectShell(const SfxObjectShell *pSh)
Definition: addincol.cxx:1303
#define CFGSTR_PARAMETERS
Definition: addincol.cxx:337
static ScMatrixRef CreateMixedMatrix(const css::uno::Any &rAny)
Convert a sequence of mixed elements to ScMatrix.
Definition: rangeseq.cxx:357
OUString aName
ScUnoAddInFuncData(const OUString &rNam, const OUString &rLoc, const OUString &rDesc, sal_uInt16 nCat, const OString &, const css::uno::Reference< css::reflection::XIdlMethod > &rFunc, const css::uno::Any &rO, long nAC, const ScAddInArgDesc *pAD, long nCP)
Definition: addincol.cxx:69
const ScUnoAddInFuncData * pFuncData
Definition: addincol.hxx:186
std::unique_ptr< std::unique_ptr< ScUnoAddInFuncData >[]> ppFuncData
Definition: addincol.hxx:138
css::uno::Reference< css::reflection::XIdlMethod > xFunction
Definition: addincol.hxx:89
static SC_DLLPUBLIC const CharClass * getCharClassPtr()
Definition: global.cxx:1018
Reference< XComponentContext > getProcessComponentContext()
XCellRange.
Definition: addincol.hxx:58
OUString aString
Definition: addincol.hxx:195
#define CFGPATH_ADDINS
Definition: addincol.cxx:324
sal_uInt32 GetCount() const
Definition: funcdesc.hxx:248
#define CFG_FUNCPROP_CATEGORY
Definition: addincol.cxx:329
void SetCompNames(const ::std::vector< LocalizedName > &rNew)
Definition: addincol.cxx:133
void SetResult(const css::uno::Any &rNewRes)
Definition: addincol.cxx:1438
OString sHelpId
HelpId of function.
Definition: funcdesc.hxx:227
css::uno::Sequence< OUString > GetNodeNames(const OUString &rNode)
#define SAL_WARN(area, stream)
static sal_uInt16 lcl_GetCategory(const OUString &rName)
Definition: addincol.cxx:299
const OString & GetHelpId() const
Definition: addincol.hxx:122
std::vector< OUString > maDefArgNames
Parameter name(s)
Definition: funcdesc.hxx:219
static void lcl_UpdateFunctionList(const ScFunctionList &rFunctionList, const ScUnoAddInFuncData &rFuncData)
Definition: addincol.cxx:917
ScAddInArgumentType
Definition: addincol.hxx:47
bool GetExcelName(LanguageType eDestLang, OUString &rRetExcelName) const
Definition: addincol.cxx:142
#define SC_CALLERPOS_NONE
Definition: addincol.cxx:67
void ExecuteCallWithArgs(css::uno::Sequence< css::uno::Any > &rCallArgs)
Definition: addincol.cxx:1380
bool GetCalcName(const OUString &rExcelName, OUString &rRetCalcName)
leave rRetCalcName unchanged, if no matching name is found
Definition: addincol.cxx:569
bool bIncomplete
Incomplete argument info (set for add-in info from configuration)
Definition: funcdesc.hxx:228
css::uno::Sequence< css::uno::Any > GetProperties(const css::uno::Sequence< OUString > &rNames)
Definition: optutil.hxx:52
css::uno::Any aObject
Definition: addincol.hxx:90
Stores and generates human readable descriptions for spreadsheet-functions, e.g. functions used in fo...
Definition: funcdesc.hxx:41
sal_uInt16 nArgCount
All parameter count, suppressed and unsuppressed.
Definition: funcdesc.hxx:224
sal_uInt16 nPos
OUString sDisplayName