2007-04-25 15:14:30 +00:00
/*************************************************************************
*
2008-04-11 00:24:23 +00:00
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER .
2007-04-25 15:14:30 +00:00
*
2010-02-12 15:01:35 +01:00
* Copyright 2000 , 2010 Oracle and / or its affiliates .
2007-04-25 15:14:30 +00:00
*
2008-04-11 00:24:23 +00:00
* OpenOffice . org - a multi - platform office productivity suite
2007-04-25 15:14:30 +00:00
*
2008-04-11 00:24:23 +00:00
* This file is part of OpenOffice . org .
2007-04-25 15:14:30 +00:00
*
2008-04-11 00:24:23 +00:00
* OpenOffice . org is free software : you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License version 3
* only , as published by the Free Software Foundation .
2007-04-25 15:14:30 +00:00
*
2008-04-11 00:24:23 +00:00
* OpenOffice . org is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Lesser General Public License version 3 for more details
* ( a copy is included in the LICENSE file that accompanied this code ) .
2007-04-25 15:14:30 +00:00
*
2008-04-11 00:24:23 +00:00
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice . org . If not , see
* < http : //www.openoffice.org/license.html>
* for a copy of the LGPLv3 License .
2007-04-25 15:14:30 +00:00
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <com/sun/star/beans/XPropertySet.hpp>
# include <com/sun/star/table/XCell.hpp>
# include <com/sun/star/table/XColumnRowRange.hpp>
# include <com/sun/star/beans/XIntrospection.hpp>
# include <com/sun/star/beans/XIntrospectionAccess.hpp>
# include <com/sun/star/sheet/XFunctionAccess.hpp>
# include <com/sun/star/sheet/XCellRangesQuery.hpp>
2010-06-15 20:02:53 +02:00
# include <com/sun/star/sheet/XCellRangeAddressable.hpp>
2007-04-25 15:14:30 +00:00
# include <com/sun/star/sheet/CellFlags.hpp>
# include <com/sun/star/reflection/XIdlMethod.hpp>
# include <com/sun/star/beans/MethodConcept.hpp>
# include <comphelper/processfactory.hxx>
# include <cppuhelper/queryinterface.hxx>
# include <comphelper/anytostring.hxx>
# include "vbawsfunction.hxx"
2009-02-13 13:03:24 +00:00
# include "compiler.hxx"
2007-04-25 15:14:30 +00:00
using namespace com : : sun : : star ;
2009-02-13 13:03:24 +00:00
using namespace ooo : : vba ;
2007-04-25 15:14:30 +00:00
2010-06-15 20:02:53 +02:00
namespace {
void lclConvertDoubleToBoolean ( uno : : Any & rAny )
2007-04-25 15:14:30 +00:00
{
2010-06-15 20:02:53 +02:00
if ( rAny . has < double > ( ) )
{
double fValue = rAny . get < double > ( ) ;
if ( fValue = = 0.0 )
rAny < < = false ;
else if ( fValue = = 1.0 )
rAny < < = true ;
// do nothing for other values or types
}
2007-04-25 15:14:30 +00:00
}
2010-06-15 20:02:53 +02:00
} // namespace
ScVbaWSFunction : : ScVbaWSFunction ( const uno : : Reference < XHelperInterface > & xParent , const css : : uno : : Reference < css : : uno : : XComponentContext > & xContext ) :
ScVbaWSFunction_BASE ( xParent , xContext )
{
}
2007-04-25 15:14:30 +00:00
uno : : Reference < beans : : XIntrospectionAccess >
ScVbaWSFunction : : getIntrospection ( void ) throw ( uno : : RuntimeException )
{
return uno : : Reference < beans : : XIntrospectionAccess > ( ) ;
}
uno : : Any SAL_CALL
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 )
{
2010-06-15 20:02:53 +02:00
// create copy of parameters, replace Excel range objects with UNO range objects
uno : : Sequence < uno : : Any > aParamTemp ( Params ) ;
if ( aParamTemp . hasElements ( ) )
{
uno : : Any * pArray = aParamTemp . getArray ( ) ;
uno : : Any * pArrayEnd = pArray + aParamTemp . getLength ( ) ;
for ( ; pArray < pArrayEnd ; + + pArray )
{
uno : : Reference < excel : : XRange > myRange ( * pArray , uno : : UNO_QUERY ) ;
if ( myRange . is ( ) )
* pArray = myRange - > getCellRange ( ) ;
OSL_TRACE ( " Param[%d] is %s " , ( int ) ( pArray - aParamTemp . getConstArray ( ) ) , rtl : : OUStringToOString ( comphelper : : anyToString ( * pArray ) , RTL_TEXTENCODING_UTF8 ) . getStr ( ) ) ;
}
}
uno : : Any aRet ;
bool bAsArray = true ;
// special handing for some functions that don't work correctly in FunctionAccess
ScCompiler aCompiler ( 0 , ScAddress ( ) ) ;
OpCode eOpCode = aCompiler . GetEnglishOpCode ( FunctionName . toAsciiUpperCase ( ) ) ;
switch ( eOpCode )
2007-04-25 15:14:30 +00:00
{
2010-06-15 20:02:53 +02:00
// ISLOGICAL does not work in array formula mode
case ocIsLogical :
2007-04-25 15:14:30 +00:00
{
2010-06-15 20:02:53 +02:00
if ( aParamTemp . getLength ( ) ! = 1 )
throw lang : : IllegalArgumentException ( ) ;
const uno : : Any & rParam = aParamTemp [ 0 ] ;
if ( rParam . has < bool > ( ) )
{
aRet < < = true ;
}
else if ( rParam . has < uno : : Reference < table : : XCellRange > > ( ) ) try
{
uno : : Reference < sheet : : XCellRangeAddressable > xRangeAddr ( rParam , uno : : UNO_QUERY_THROW ) ;
table : : CellRangeAddress aRangeAddr = xRangeAddr - > getRangeAddress ( ) ;
bAsArray = ( aRangeAddr . StartColumn ! = aRangeAddr . EndColumn ) | | ( aRangeAddr . StartRow ! = aRangeAddr . EndRow ) ;
}
catch ( uno : : Exception & )
{
}
2007-04-25 15:14:30 +00:00
}
2010-06-15 20:02:53 +02:00
break ;
default : ;
2007-04-25 15:14:30 +00:00
}
2010-06-15 20:02:53 +02:00
if ( ! aRet . hasValue ( ) )
{
uno : : Reference < lang : : XMultiComponentFactory > xSMgr ( mxContext - > getServiceManager ( ) , uno : : UNO_QUERY_THROW ) ;
uno : : Reference < sheet : : XFunctionAccess > xFunctionAccess ( xSMgr - > createInstanceWithContext (
: : rtl : : OUString ( RTL_CONSTASCII_USTRINGPARAM ( " com.sun.star.sheet.FunctionAccess " ) ) , mxContext ) ,
uno : : UNO_QUERY_THROW ) ;
uno : : Reference < beans : : XPropertySet > xPropSet ( xFunctionAccess , uno : : UNO_QUERY_THROW ) ;
xPropSet - > setPropertyValue ( : : rtl : : OUString ( RTL_CONSTASCII_USTRINGPARAM ( " IsArrayFunction " ) ) , uno : : Any ( bAsArray ) ) ;
aRet = xFunctionAccess - > callFunction ( FunctionName , aParamTemp ) ;
}
2009-02-13 13:03:24 +00:00
2010-06-15 20:02:53 +02:00
/* Convert return value from double to to Boolean for some functions that
return Booleans . */
typedef uno : : Sequence < uno : : Sequence < uno : : Any > > AnySeqSeq ;
if ( ( eOpCode = = ocIsEmpty ) | | ( eOpCode = = ocIsString ) | | ( eOpCode = = ocIsNonString ) | | ( eOpCode = = ocIsLogical ) | |
( eOpCode = = ocIsRef ) | | ( eOpCode = = ocIsValue ) | | ( eOpCode = = ocIsFormula ) | | ( eOpCode = = ocIsNA ) | |
( eOpCode = = ocIsErr ) | | ( eOpCode = = ocIsError ) | | ( eOpCode = = ocIsEven ) | | ( eOpCode = = ocIsOdd ) | |
( eOpCode = = ocAnd ) | | ( eOpCode = = ocOr ) | | ( eOpCode = = ocNot ) | | ( eOpCode = = ocTrue ) | | ( eOpCode = = ocFalse ) )
{
if ( aRet . has < AnySeqSeq > ( ) )
{
AnySeqSeq aAnySeqSeq = aRet . get < AnySeqSeq > ( ) ;
for ( sal_Int32 nRow = 0 ; nRow < aAnySeqSeq . getLength ( ) ; + + nRow )
for ( sal_Int32 nCol = 0 ; nCol < aAnySeqSeq [ nRow ] . getLength ( ) ; + + nCol )
lclConvertDoubleToBoolean ( aAnySeqSeq [ nRow ] [ nCol ] ) ;
aRet < < = aAnySeqSeq ;
}
else
{
lclConvertDoubleToBoolean ( aRet ) ;
}
}
/* Hack/workaround (?): shorten single-row matrix to simple array, shorten
1 x1 matrix to single value . */
if ( aRet . has < AnySeqSeq > ( ) )
{
AnySeqSeq aAnySeqSeq = aRet . get < AnySeqSeq > ( ) ;
if ( aAnySeqSeq . getLength ( ) = = 1 )
{
if ( aAnySeqSeq [ 0 ] . getLength ( ) = = 1 )
aRet = aAnySeqSeq [ 0 ] [ 0 ] ;
else
aRet < < = aAnySeqSeq [ 0 ] ;
}
}
#if 0
2009-02-13 13:03:24 +00:00
// 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?
// To fix this issue in safe, current solution is to convert this array to a double value just for MATCH function.
String aUpper ( FunctionName ) ;
ScCompiler aCompiler ( NULL , ScAddress ( ) ) ;
OpCode eOp = aCompiler . GetEnglishOpCode ( aUpper . ToUpperAscii ( ) ) ;
if ( eOp = = ocMatch )
{
double fVal = 0.0 ;
if ( aRet > > = fVal )
return aRet ;
uno : : Sequence < uno : : Sequence < uno : : Any > > aSequence ;
if ( ! ( ( aRet > > = aSequence ) & & ( aSequence . getLength ( ) > 0 ) & &
( aSequence [ 0 ] . getLength ( ) > 0 ) & & ( aSequence [ 0 ] [ 0 ] > > = fVal ) ) )
throw uno : : RuntimeException ( ) ;
aRet < < = fVal ;
}
2010-06-15 20:02:53 +02:00
# endif
2009-02-13 13:03:24 +00:00
return aRet ;
2007-04-25 15:14:30 +00:00
}
void SAL_CALL
ScVbaWSFunction : : setValue ( const rtl : : OUString & /*PropertyName*/ , const uno : : Any & /*Value*/ ) throw ( beans : : UnknownPropertyException , script : : CannotConvertException , reflection : : InvocationTargetException , uno : : RuntimeException )
{
throw beans : : UnknownPropertyException ( ) ;
}
uno : : Any SAL_CALL
ScVbaWSFunction : : getValue ( const rtl : : OUString & /*PropertyName*/ ) throw ( beans : : UnknownPropertyException , uno : : RuntimeException )
{
throw beans : : UnknownPropertyException ( ) ;
}
sal_Bool SAL_CALL
ScVbaWSFunction : : hasMethod ( const rtl : : OUString & Name ) throw ( uno : : RuntimeException )
{
sal_Bool bIsFound = sal_False ;
try
{
2010-06-15 20:02:53 +02:00
// the function name contained in the com.sun.star.sheet.FunctionDescription service is alwayse localized.
2009-02-13 13:03:24 +00:00
// but the function name used in WorksheetFunction is a programmatic name (seems English).
// So m_xNameAccess->hasByName( Name ) may fail to find name when a function name has a localized name.
ScCompiler aCompiler ( NULL , ScAddress ( ) ) ;
if ( aCompiler . IsEnglishSymbol ( Name ) )
2007-04-25 15:14:30 +00:00
bIsFound = sal_True ;
}
catch ( uno : : Exception & /*e*/ )
{
// failed to find name
}
return bIsFound ;
}
sal_Bool SAL_CALL
ScVbaWSFunction : : hasProperty ( const rtl : : OUString & /*Name*/ ) throw ( uno : : RuntimeException )
{
return sal_False ;
}
: : rtl : : OUString SAL_CALL
ScVbaWSFunction : : getExactName ( const : : rtl : : OUString & aApproximateName ) throw ( css : : uno : : RuntimeException )
{
rtl : : OUString sName = aApproximateName . toAsciiUpperCase ( ) ;
if ( ! hasMethod ( sName ) )
return rtl : : OUString ( ) ;
return sName ;
}
2007-12-07 10:07:56 +00:00
rtl : : OUString &
ScVbaWSFunction : : getServiceImplName ( )
{
static rtl : : OUString sImplName ( RTL_CONSTASCII_USTRINGPARAM ( " ScVbaWSFunction " ) ) ;
return sImplName ;
}
uno : : Sequence < rtl : : OUString >
ScVbaWSFunction : : getServiceNames ( )
{
static uno : : Sequence < rtl : : OUString > aServiceNames ;
if ( aServiceNames . getLength ( ) = = 0 )
{
aServiceNames . realloc ( 1 ) ;
2009-02-13 13:03:24 +00:00
aServiceNames [ 0 ] = rtl : : OUString ( RTL_CONSTASCII_USTRINGPARAM ( " ooo.vba.excel.WorksheetFunction " ) ) ;
2007-12-07 10:07:56 +00:00
}
return aServiceNames ;
}