Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : : #include <com/sun/star/beans/XPropertySet.hpp>
29 : : #include <com/sun/star/table/XCell.hpp>
30 : : #include <com/sun/star/table/XColumnRowRange.hpp>
31 : : #include <com/sun/star/beans/XIntrospection.hpp>
32 : : #include <com/sun/star/beans/XIntrospectionAccess.hpp>
33 : : #include <com/sun/star/sheet/XFunctionAccess.hpp>
34 : : #include <com/sun/star/sheet/XCellRangesQuery.hpp>
35 : : #include <com/sun/star/sheet/XCellRangeAddressable.hpp>
36 : : #include <com/sun/star/sheet/CellFlags.hpp>
37 : : #include <com/sun/star/reflection/XIdlMethod.hpp>
38 : : #include <com/sun/star/beans/MethodConcept.hpp>
39 : : #include <comphelper/processfactory.hxx>
40 : : #include <cppuhelper/queryinterface.hxx>
41 : : #include <comphelper/anytostring.hxx>
42 : :
43 : : #include "vbawsfunction.hxx"
44 : : #include "compiler.hxx"
45 : :
46 : : using namespace com::sun::star;
47 : : using namespace ooo::vba;
48 : :
49 : : namespace {
50 : :
51 : 0 : void lclConvertDoubleToBoolean( uno::Any& rAny )
52 : : {
53 [ # # ]: 0 : if( rAny.has< double >() )
54 : : {
55 : 0 : double fValue = rAny.get< double >();
56 [ # # ]: 0 : if( fValue == 0.0 )
57 [ # # ]: 0 : rAny <<= false;
58 [ # # ]: 0 : else if( fValue == 1.0 )
59 [ # # ]: 0 : rAny <<= true;
60 : : // do nothing for other values or types
61 : : }
62 : 0 : }
63 : :
64 : 0 : void lclConvertBooleanToDouble( uno::Any& rAny )
65 : : {
66 : 0 : sal_Bool bValue( false );
67 [ # # ]: 0 : if ( rAny >>= bValue )
68 : : {
69 [ # # ]: 0 : if ( bValue )
70 [ # # ]: 0 : rAny <<= double( 1.0 );
71 : : else
72 [ # # ]: 0 : rAny <<= double( 0.0 );
73 : : }
74 : 0 : }
75 : :
76 : : } // namespace
77 : :
78 : 0 : ScVbaWSFunction::ScVbaWSFunction( const uno::Reference< XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext ) :
79 : 0 : ScVbaWSFunction_BASE( xParent, xContext )
80 : : {
81 : 0 : }
82 : :
83 : : uno::Reference< beans::XIntrospectionAccess >
84 : 0 : ScVbaWSFunction::getIntrospection(void) throw(uno::RuntimeException)
85 : : {
86 : 0 : return uno::Reference<beans::XIntrospectionAccess>();
87 : : }
88 : :
89 : : uno::Any SAL_CALL
90 : 0 : ScVbaWSFunction::invoke(const rtl::OUString& FunctionName, const uno::Sequence< uno::Any >& Params, uno::Sequence< sal_Int16 >& /*OutParamIndex*/, uno::Sequence< uno::Any >& /*OutParam*/) throw(lang::IllegalArgumentException, script::CannotConvertException, reflection::InvocationTargetException, uno::RuntimeException)
91 : : {
92 : : // create copy of parameters, replace Excel range objects with UNO range objects
93 [ # # ]: 0 : uno::Sequence< uno::Any > aParamTemp( Params );
94 [ # # ]: 0 : if( aParamTemp.hasElements() )
95 : : {
96 [ # # ]: 0 : uno::Any* pArray = aParamTemp.getArray();
97 : 0 : uno::Any* pArrayEnd = pArray + aParamTemp.getLength();
98 [ # # ]: 0 : for( ; pArray < pArrayEnd; ++pArray )
99 : : {
100 [ # # # # ]: 0 : switch( pArray->getValueType().getTypeClass() )
101 : : {
102 : : case uno::TypeClass_BOOLEAN:
103 [ # # ]: 0 : lclConvertBooleanToDouble( *pArray );
104 : 0 : break;
105 : : case uno::TypeClass_INTERFACE:
106 : : {
107 [ # # ]: 0 : uno::Reference< excel::XRange > myRange( *pArray, uno::UNO_QUERY );
108 [ # # ]: 0 : if( myRange.is() )
109 [ # # ][ # # ]: 0 : *pArray = myRange->getCellRange();
110 : : }
111 : 0 : break;
112 : : case uno::TypeClass_SEQUENCE:
113 : : {
114 : : // the sheet.FunctionAccess service doesn't deal with Sequences, only Sequences of Sequence
115 : 0 : uno::Type aType = pArray->getValueType();
116 [ # # ][ # # ]: 0 : if ( aType.equals( getCppuType( (uno::Sequence<sal_Int16>*)0 ) ) )
117 : : {
118 [ # # ]: 0 : uno::Sequence< uno::Sequence< sal_Int16 > > aTmp(1);
119 [ # # ][ # # ]: 0 : (*pArray) >>= aTmp[ 0 ];
120 [ # # ][ # # ]: 0 : (*pArray) <<= aTmp;
121 : : }
122 [ # # ][ # # ]: 0 : else if ( aType.equals( getCppuType( (uno::Sequence<sal_Int32>*)0 ) ) )
123 : : {
124 [ # # ]: 0 : uno::Sequence< uno::Sequence< sal_Int32 > > aTmp(1);
125 [ # # ][ # # ]: 0 : (*pArray) >>= aTmp[ 0 ];
126 [ # # ][ # # ]: 0 : (*pArray) <<= aTmp;
127 : : }
128 [ # # ][ # # ]: 0 : else if ( aType.equals( getCppuType( (uno::Sequence<double>*)0 ) ) )
129 : : {
130 [ # # ]: 0 : uno::Sequence< uno::Sequence< double > > aTmp(1);
131 [ # # ][ # # ]: 0 : (*pArray) >>= aTmp[ 0 ];
132 [ # # ][ # # ]: 0 : (*pArray) <<= aTmp;
133 : : }
134 [ # # ][ # # ]: 0 : else if ( aType.equals( getCppuType( (uno::Sequence<rtl::OUString>*)0 ) ) )
135 : : {
136 [ # # ]: 0 : uno::Sequence< uno::Sequence< rtl::OUString > > aTmp(1);
137 [ # # ][ # # ]: 0 : (*pArray) >>= aTmp[ 0 ];
138 [ # # ][ # # ]: 0 : (*pArray) <<= aTmp;
139 : : }
140 [ # # ][ # # ]: 0 : else if ( aType.equals( getCppuType( (uno::Sequence<uno::Any>*)0 ) ) )
141 : : {
142 [ # # ]: 0 : uno::Sequence< uno::Sequence<uno::Any > > aTmp(1);
143 [ # # ][ # # ]: 0 : (*pArray) >>= aTmp[ 0 ];
144 [ # # ][ # # ]: 0 : (*pArray) <<= aTmp;
145 : 0 : }
146 : : }
147 : 0 : break;
148 : : default:
149 : 0 : break;
150 : : }
151 : : OSL_TRACE("Param[%d] is %s", (int)(pArray - aParamTemp.getConstArray()), rtl::OUStringToOString( comphelper::anyToString( *pArray ), RTL_TEXTENCODING_UTF8 ).getStr() );
152 : : }
153 : : }
154 : :
155 : 0 : uno::Any aRet;
156 : 0 : bool bAsArray = true;
157 : :
158 : : // special handing for some functions that don't work correctly in FunctionAccess
159 [ # # ]: 0 : ScCompiler aCompiler( 0, ScAddress() );
160 [ # # ][ # # ]: 0 : OpCode eOpCode = aCompiler.GetEnglishOpCode( FunctionName.toAsciiUpperCase() );
[ # # ]
161 [ # # ]: 0 : switch( eOpCode )
162 : : {
163 : : // ISLOGICAL does not work in array formula mode
164 : : case ocIsLogical:
165 : : {
166 [ # # ]: 0 : if( aParamTemp.getLength() != 1 )
167 [ # # ]: 0 : throw lang::IllegalArgumentException();
168 [ # # ]: 0 : const uno::Any& rParam = aParamTemp[ 0 ];
169 [ # # ][ # # ]: 0 : if( rParam.has< bool >() )
170 : : {
171 [ # # ]: 0 : aRet <<= true;
172 : : }
173 [ # # ][ # # ]: 0 : else if( rParam.has< uno::Reference< table::XCellRange > >() ) try
174 : : {
175 [ # # ]: 0 : uno::Reference< sheet::XCellRangeAddressable > xRangeAddr( rParam, uno::UNO_QUERY_THROW );
176 [ # # ][ # # ]: 0 : table::CellRangeAddress aRangeAddr = xRangeAddr->getRangeAddress();
177 [ # # ][ # # ]: 0 : bAsArray = (aRangeAddr.StartColumn != aRangeAddr.EndColumn) || (aRangeAddr.StartRow != aRangeAddr.EndRow);
[ # # ]
178 : : }
179 [ # # ]: 0 : catch( uno::Exception& )
180 : : {
181 : : }
182 : : }
183 : 0 : break;
184 : : default:;
185 : : }
186 : :
187 [ # # ]: 0 : if( !aRet.hasValue() )
188 : : {
189 [ # # ][ # # ]: 0 : uno::Reference< lang::XMultiComponentFactory > xSMgr( mxContext->getServiceManager(), uno::UNO_QUERY_THROW );
[ # # ]
190 [ # # ]: 0 : uno::Reference< sheet::XFunctionAccess > xFunctionAccess( xSMgr->createInstanceWithContext(
191 : 0 : ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sheet.FunctionAccess" ) ), mxContext ),
192 [ # # ][ # # ]: 0 : uno::UNO_QUERY_THROW );
[ # # ]
193 [ # # ]: 0 : uno::Reference< beans::XPropertySet > xPropSet( xFunctionAccess, uno::UNO_QUERY_THROW );
194 [ # # ][ # # ]: 0 : xPropSet->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IsArrayFunction" ) ), uno::Any( bAsArray ) );
[ # # ][ # # ]
195 [ # # ][ # # ]: 0 : aRet = xFunctionAccess->callFunction( FunctionName, aParamTemp );
196 : : }
197 : :
198 : : /* Convert return value from double to to Boolean for some functions that
199 : : return Booleans. */
200 : : typedef uno::Sequence< uno::Sequence< uno::Any > > AnySeqSeq;
201 [ # # ][ # # ]: 0 : if( (eOpCode == ocIsEmpty) || (eOpCode == ocIsString) || (eOpCode == ocIsNonString) || (eOpCode == ocIsLogical) ||
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
202 : : (eOpCode == ocIsRef) || (eOpCode == ocIsValue) || (eOpCode == ocIsFormula) || (eOpCode == ocIsNA) ||
203 : : (eOpCode == ocIsErr) || (eOpCode == ocIsError) || (eOpCode == ocIsEven) || (eOpCode == ocIsOdd) ||
204 : : (eOpCode == ocAnd) || (eOpCode == ocOr) || (eOpCode == ocXor) || (eOpCode == ocNot) || (eOpCode == ocTrue) || (eOpCode == ocFalse) )
205 : : {
206 [ # # ][ # # ]: 0 : if( aRet.has< AnySeqSeq >() )
207 : : {
208 [ # # ]: 0 : AnySeqSeq aAnySeqSeq = aRet.get< AnySeqSeq >();
209 [ # # ]: 0 : for( sal_Int32 nRow = 0; nRow < aAnySeqSeq.getLength(); ++nRow )
210 [ # # ][ # # ]: 0 : for( sal_Int32 nCol = 0; nCol < aAnySeqSeq[ nRow ].getLength(); ++nCol )
211 [ # # ][ # # ]: 0 : lclConvertDoubleToBoolean( aAnySeqSeq[ nRow ][ nCol ] );
[ # # ]
212 [ # # ][ # # ]: 0 : aRet <<= aAnySeqSeq;
213 : : }
214 : : else
215 : : {
216 [ # # ]: 0 : lclConvertDoubleToBoolean( aRet );
217 : : }
218 : : }
219 : :
220 : : /* Hack/workaround (?): shorten single-row matrix to simple array, shorten
221 : : 1x1 matrix to single value. */
222 [ # # ][ # # ]: 0 : if( aRet.has< AnySeqSeq >() )
223 : : {
224 [ # # ]: 0 : AnySeqSeq aAnySeqSeq = aRet.get< AnySeqSeq >();
225 [ # # ]: 0 : if( aAnySeqSeq.getLength() == 1 )
226 : : {
227 [ # # ][ # # ]: 0 : if( aAnySeqSeq[ 0 ].getLength() == 1 )
228 [ # # ][ # # ]: 0 : aRet = aAnySeqSeq[ 0 ][ 0 ];
229 : : else
230 [ # # ][ # # ]: 0 : aRet <<= aAnySeqSeq[ 0 ];
231 [ # # ]: 0 : }
232 : : }
233 : :
234 : : #if 0
235 : : // MATCH function should alwayse return a double value, but currently if the first argument is XCellRange, MATCH function returns an array instead of a double value. Don't know why?
236 : : // To fix this issue in safe, current solution is to convert this array to a double value just for MATCH function.
237 : : String aUpper( FunctionName );
238 : : ScCompiler aCompiler( NULL, ScAddress() );
239 : : OpCode eOp = aCompiler.GetEnglishOpCode( aUpper.ToUpperAscii() );
240 : : if( eOp == ocMatch )
241 : : {
242 : : double fVal = 0.0;
243 : : if( aRet >>= fVal )
244 : : return aRet;
245 : : uno::Sequence< uno::Sequence< uno::Any > > aSequence;
246 : : if( !( ( aRet >>= aSequence ) && ( aSequence.getLength() > 0 ) &&
247 : : ( aSequence[0].getLength() > 0 ) && ( aSequence[0][0] >>= fVal ) ) )
248 : : throw uno::RuntimeException();
249 : : aRet <<= fVal;
250 : : }
251 : : #endif
252 : :
253 [ # # ][ # # ]: 0 : return aRet;
254 : : }
255 : :
256 : : void SAL_CALL
257 : 0 : ScVbaWSFunction::setValue(const rtl::OUString& /*PropertyName*/, const uno::Any& /*Value*/) throw(beans::UnknownPropertyException, script::CannotConvertException, reflection::InvocationTargetException, uno::RuntimeException)
258 : : {
259 [ # # ]: 0 : throw beans::UnknownPropertyException();
260 : : }
261 : :
262 : : uno::Any SAL_CALL
263 : 0 : ScVbaWSFunction::getValue(const rtl::OUString& /*PropertyName*/) throw(beans::UnknownPropertyException, uno::RuntimeException)
264 : : {
265 [ # # ]: 0 : throw beans::UnknownPropertyException();
266 : : }
267 : :
268 : : sal_Bool SAL_CALL
269 : 0 : ScVbaWSFunction::hasMethod(const rtl::OUString& Name) throw(uno::RuntimeException)
270 : : {
271 : 0 : sal_Bool bIsFound = false;
272 : : try
273 : : {
274 : : // the function name contained in the com.sun.star.sheet.FunctionDescription service is alwayse localized.
275 : : // but the function name used in WorksheetFunction is a programmatic name (seems English).
276 : : // So m_xNameAccess->hasByName( Name ) may fail to find name when a function name has a localized name.
277 [ # # ]: 0 : ScCompiler aCompiler( NULL, ScAddress() );
278 [ # # ][ # # ]: 0 : if( aCompiler.IsEnglishSymbol( Name ) )
[ # # ][ # # ]
279 [ # # ][ # # ]: 0 : bIsFound = sal_True;
280 : : }
281 : 0 : catch( uno::Exception& /*e*/ )
282 : : {
283 : : // failed to find name
284 : : }
285 : 0 : return bIsFound;
286 : : }
287 : :
288 : : sal_Bool SAL_CALL
289 : 0 : ScVbaWSFunction::hasProperty(const rtl::OUString& /*Name*/) throw(uno::RuntimeException)
290 : : {
291 : 0 : return false;
292 : : }
293 : :
294 : : ::rtl::OUString SAL_CALL
295 : 0 : ScVbaWSFunction::getExactName( const ::rtl::OUString& aApproximateName ) throw (css::uno::RuntimeException)
296 : : {
297 : 0 : rtl::OUString sName = aApproximateName.toAsciiUpperCase();
298 [ # # ][ # # ]: 0 : if ( !hasMethod( sName ) )
299 : 0 : return rtl::OUString();
300 : 0 : return sName;
301 : : }
302 : :
303 : : rtl::OUString
304 : 0 : ScVbaWSFunction::getServiceImplName()
305 : : {
306 : 0 : return rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ScVbaWSFunction"));
307 : : }
308 : :
309 : : uno::Sequence< rtl::OUString >
310 : 0 : ScVbaWSFunction::getServiceNames()
311 : : {
312 [ # # ][ # # ]: 0 : static uno::Sequence< rtl::OUString > aServiceNames;
[ # # ][ # # ]
313 [ # # ]: 0 : if ( aServiceNames.getLength() == 0 )
314 : : {
315 : 0 : aServiceNames.realloc( 1 );
316 [ # # ]: 0 : aServiceNames[ 0 ] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ooo.vba.excel.WorksheetFunction" ) );
317 : : }
318 : 0 : return aServiceNames;
319 : : }
320 : :
321 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|