Calc/Add-In/CompleteAddIn
Contents
An other C++ add-in example
In this article under construction, a complete and simple add-in in C++ is presented.
Introduction
We start from an example of SDK slightly modified : <OpenOffice.org1.1_SDK>/examples/DevelopersGuide/Components/CppComponent
This example contains two files but I only use one file (and one service).
IDL File
Here is the corresponding IDL file :
// IDL #include <com/sun/star/uno/XInterface.idl> #include <com/sun/star/lang/XInitialization.idl> #include <com/sun/star/lang/XServiceName.idl> #include <com/sun/star/lang/XLocalizable.idl> #include <com/sun/star/sheet/XAddIn.idl> module my_module { interface XSomething : com::sun::star::uno::XInterface { // our four methods string methodOne( [in] string val ); string methodTwo( [in] string val ); long methodThree( [in] sequence< sequence< long > > aValList ); sequence< sequence< long > > methodFour( [in] sequence< sequence< long > > aValList ); }; service MyService2 { interface XSomething; interface com::sun::star::lang::XInitialization; interface com::sun::star::lang::XServiceName; interface com::sun::star::sheet::XAddIn; }; };
Four method named methodOne, methodTwo, methodThree and methodFour will be implemented.
Implementing in C++ the corresponding four Methods
We first give the C++ code of the four method presented in IDL file.
The two first Methods
The two first methods are similar :
OUString MyService2Impl::methodOne( OUString const & str ) throw (RuntimeException) { return OUString( RTL_CONSTASCII_USTRINGPARAM( "called methodOne() of MyService2 implementation: ") ) + m_arg + str; } OUString MyService2Impl::methodTwo( OUString const & str )throw (RuntimeException) { return OUString( RTL_CONSTASCII_USTRINGPARAM( "called methodTwo() of MyService2 implementation: ") ) + m_arg + str; }
They only take a string (from a OOoCalc Cell) and add a message and put all the message+string in the result cell.
The third Method
The third method is more complicated : it returns a value calculed from a cell range (the sum).
sal_Int32 MyService2Impl::methodThree(const Sequence< Sequence< sal_Int32 > > &aValList ) throw (RuntimeException) { sal_Int32 n1, n2; sal_Int32 nE1 = aValList.getLength(); sal_Int32 nE2; sal_Int32 temp=0; for( n1 = 0 ; n1 < nE1 ; n1++ ) { const Sequence< sal_Int32 > rList = aValList[ n1 ]; nE2 = rList.getLength(); const sal_Int32* pList = rList.getConstArray(); for( n2 = 0 ; n2 < nE2 ; n2++ ) { temp += pList[ n2 ]; } } return temp; }
The fourth Method
The goal of the fourth method is to show how we can implement a matrix function : starting from a cell range and obtaining a celle range.
//It's a matrix operation should be called like : {=METHODFOUR(A1:B4)} Sequence< Sequence< sal_Int32 > > MyService2Impl::methodFour(const Sequence< Sequence< sal_Int32 > > &aValList ) throw (RuntimeException) { sal_Int32 n1, n2; sal_Int32 nE1 = aValList.getLength(); sal_Int32 nE2; Sequence< Sequence< sal_Int32 > > temp = aValList; for( n1 = 0 ; n1 < nE1 ; n1++ ) { Sequence< sal_Int32 > rList = temp[ n1 ]; nE2 = rList.getLength(); for( n2 = 0 ; n2 < nE2 ; n2++ ) { rList[ n2 ] += 4; } temp[n1]=rList; } return temp; }
What is done by this example is not great : only add four to every cells of the cell range.
The code is not complete with this four method. If you want to create a component you have to add code, if you want to make a scriptable component you still add more code and if you want to create an AddIn you have to add more.
The XAddIn Interface
Every add-in have to implement the XAddIn interface. As usual it is described by an IDL file :
// IDL module com { module sun { module star { module sheet { interface XAddIn: com::sun::star::lang::XLocalizable { string getProgrammaticFuntionName( [in] string aDisplayName ); string getDisplayFunctionName( [in] string aProgrammaticName ); string getFunctionDescription( [in] string aProgrammaticName ); string getDisplayArgumentName( [in] string aProgrammaticFunctionName, [in] long nArgument ); string getArgumentDescription( [in] string aProgrammaticFunctionName, [in] long nArgument ); string getProgrammaticCategoryName( [in] string aProgrammaticFunctionName ); string getDisplayCategoryName( [in] string aProgrammaticFunctionName ); }; }; }; }; };
The corresponding C++ code is given now without explanation (for the moment)
// XAddIn OUString SAL_CALL MyService2Impl::getProgrammaticFuntionName( const OUString& aDisplayName ) throw( uno::RuntimeException ) { // not used by calc // (but should be implemented for other uses of the AddIn service) return OUString(); } OUString SAL_CALL MyService2Impl::getDisplayFunctionName( const OUString& aProgrammaticName ) throw( uno::RuntimeException ) { // a nested if implementation would be better OUString aProgName, aRet; aProgName = aProgrammaticName; if (aProgName.equalsAscii("methodOne")) aRet = OUString::createFromAscii("method1"); if (aProgName.equalsAscii("methodTwo")) aRet = OUString::createFromAscii("method2"); if (aProgName.equalsAscii("methodThree")) aRet = OUString::createFromAscii("method3"); if (aProgName.equalsAscii("methodFour")) aRet = OUString::createFromAscii("method4"); return aRet; } OUString SAL_CALL MyService2Impl::getFunctionDescription( const OUString& aProgrammaticName ) throw( uno::RuntimeException ) { // a nested if implementation would be better OUString aRet; if (aProgrammaticName.equalsAscii("methodOne")) aRet = OUString::createFromAscii("methodOne() : 1st try"); if (aProgrammaticName.equalsAscii("methodTwo")) aRet = OUString::createFromAscii("methodTwo() : 1st try"); if (aProgrammaticName.equalsAscii("methodThree")) aRet = OUString::createFromAscii("methodThree() : 1st try"); return aRet; } OUString SAL_CALL MyService2Impl::getDisplayArgumentName( const OUString& aProgrammaticName, sal_Int32 nArgument ) throw( uno::RuntimeException ) { OUString aRet; if (aProgrammaticName.equalsAscii("methodOne")||aProgrammaticName.equalsAscii("methodTwo")) aRet = OUString::createFromAscii("a string"); if (aProgrammaticName.equalsAscii("methodThree")||aProgrammaticName.equalsAscii("methodFour")) aRet = OUString::createFromAscii("a Cell Range"); return aRet; } OUString SAL_CALL MyService2Impl::getArgumentDescription( const OUString& aProgrammaticName, sal_Int32 nArgument ) throw( uno::RuntimeException ) { OUString aRet; if (aProgrammaticName.equalsAscii("methodOne")||aProgrammaticName.equalsAscii("methodTwo")) aRet = OUString::createFromAscii("method1/2:a string or a cell with a string is required"); if (aProgrammaticName.equalsAscii("methodThree")||aProgrammaticName.equalsAscii("methodFour")) aRet = OUString::createFromAscii("method3/4:a cell range is required"); return aRet; } OUString SAL_CALL MyService2Impl::getProgrammaticCategoryName(const OUString& aProgrammaticName ) throw( uno::RuntimeException ) { OUString aRet( RTL_CONSTASCII_USTRINGPARAM("Add-In")); return aRet; } OUString SAL_CALL MyService2Impl::getDisplayCategoryName(const OUString& aProgrammaticName ) throw( uno::RuntimeException ) { return getProgrammaticCategoryName( aProgrammaticName ); }
The XServiceName Interface
Again the corresponding IDL file indicates what we have to do :
// IDL module com { module sun { module star { module lang { interface XServiceName: com::sun::star::uno::XInterface { string getServiceName(); }; }; }; }; };
This interface is simple : one method :
// XServiceName OUString SAL_CALL MyService2Impl::getServiceName() throw( uno::RuntimeException ) { // name of specific AddIn service return OUString::createFromAscii( "my_module.MyService2" ); }
The XServiceInfo Interface
This Interface may be avoided. You have to implement it only if you want that your add-in is also scriptable : you can call it from OOoBasic for instance.
// XServiceInfo implementation OUString MyService2Impl::getImplementationName() throw (RuntimeException) { // unique implementation name return OUString( RTL_CONSTASCII_USTRINGPARAM("my_module.my_sc_impl.MyService2") ); } sal_Bool MyService2Impl::supportsService( OUString const & serviceName ) throw (RuntimeException) { // this object only supports one service, so the test is simple if (serviceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("my_module.MyService2") )) return true; if (serviceName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("com.sun.star.sheet.AddIn") )) return true; else return false; } Sequence< OUString > MyService2Impl::getSupportedServiceNames() throw (RuntimeException) { return getSupportedServiceNames_MyService2Impl(); } Reference< XInterface > SAL_CALL create_MyService2Impl(Reference< XComponentContext > const & xContext) SAL_THROW( () ) { return static_cast< lang::XTypeProvider * >( new MyService2Impl() ); }
See also
This article is under construction and if you want to go further, for the moment have a look to the following references :
- Add-in : adding OooCalc functions (Chapter 14 from UNO/C++ document) http://perso.wanadoo.fr/moutou/MyUNODoc_HTML/UNOCppAPI14.html
- Add-In in C++ http://www.oooforum.org/forum/viewtopic.phtml?t=29552
- How to add-in in OpenOffice.org Calc http://sc.openoffice.org/addin_howto.html
- service AddIn http://api.openoffice.org/docs/common/ref/com/sun/star/sheet/AddIn.html</nowiki></pre>
- QuantLibAddin can be found here : http://quantlib.org/quantlibaddin/
- Constructing Components http://perso.wanadoo.fr/moutou/MyUNODoc_HTML/UNOCppAPI13.html
- All my UNO/C++ document is available here http://perso.wanadoo.fr/moutou/MyUNODoc_HTML/UNOCppAPI.html
- UNO tutorial