2010-10-12 15:59:00 +02:00
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2012-11-30 12:23:25 +00:00
/*
* This file is part of the LibreOffice project .
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2.0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at http : //mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice :
*
* Licensed to the Apache Software Foundation ( ASF ) under one or more
* contributor license agreements . See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership . The ASF licenses this file to you under the Apache
* License , Version 2.0 ( the " License " ) ; you may not use this file
* except in compliance with the License . You may obtain a copy of
* the License at http : //www.apache.org/licenses/LICENSE-2.0 .
*/
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-10-06 10:15:43 +01:00
void lclConvertBooleanToDouble ( uno : : Any & rAny )
{
2014-04-23 11:08:48 +02:00
bool bValue ( false ) ;
2010-10-06 10:15:43 +01:00
if ( rAny > > = bValue )
{
if ( bValue )
rAny < < = double ( 1.0 ) ;
else
rAny < < = double ( 0.0 ) ;
}
}
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 >
2014-02-25 21:31:58 +01:00
ScVbaWSFunction : : getIntrospection ( void ) throw ( uno : : RuntimeException , std : : exception )
2007-04-25 15:14:30 +00:00
{
return uno : : Reference < beans : : XIntrospectionAccess > ( ) ;
}
uno : : Any SAL_CALL
2014-02-25 21:31:58 +01:00
ScVbaWSFunction : : invoke ( const 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 , std : : exception )
2007-04-25 15:14:30 +00:00
{
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 )
{
2010-10-06 10:15:43 +01:00
switch ( pArray - > getValueType ( ) . getTypeClass ( ) )
{
case uno : : TypeClass_BOOLEAN :
lclConvertBooleanToDouble ( * pArray ) ;
break ;
case uno : : TypeClass_INTERFACE :
{
uno : : Reference < excel : : XRange > myRange ( * pArray , uno : : UNO_QUERY ) ;
if ( myRange . is ( ) )
* pArray = myRange - > getCellRange ( ) ;
}
break ;
case uno : : TypeClass_SEQUENCE :
{
// the sheet.FunctionAccess service doesn't deal with Sequences, only Sequences of Sequence
uno : : Type aType = pArray - > getValueType ( ) ;
if ( aType . equals ( getCppuType ( ( uno : : Sequence < sal_Int16 > * ) 0 ) ) )
{
uno : : Sequence < uno : : Sequence < sal_Int16 > > aTmp ( 1 ) ;
( * pArray ) > > = aTmp [ 0 ] ;
( * pArray ) < < = aTmp ;
}
else if ( aType . equals ( getCppuType ( ( uno : : Sequence < sal_Int32 > * ) 0 ) ) )
{
uno : : Sequence < uno : : Sequence < sal_Int32 > > aTmp ( 1 ) ;
( * pArray ) > > = aTmp [ 0 ] ;
( * pArray ) < < = aTmp ;
}
else if ( aType . equals ( getCppuType ( ( uno : : Sequence < double > * ) 0 ) ) )
{
uno : : Sequence < uno : : Sequence < double > > aTmp ( 1 ) ;
( * pArray ) > > = aTmp [ 0 ] ;
( * pArray ) < < = aTmp ;
}
2013-04-07 12:06:47 +02:00
else if ( aType . equals ( getCppuType ( ( uno : : Sequence < OUString > * ) 0 ) ) )
2010-10-06 10:15:43 +01:00
{
2013-04-07 12:06:47 +02:00
uno : : Sequence < uno : : Sequence < OUString > > aTmp ( 1 ) ;
2010-10-06 10:15:43 +01:00
( * pArray ) > > = aTmp [ 0 ] ;
( * pArray ) < < = aTmp ;
}
else if ( aType . equals ( getCppuType ( ( uno : : Sequence < uno : : Any > * ) 0 ) ) )
{
uno : : Sequence < uno : : Sequence < uno : : Any > > aTmp ( 1 ) ;
( * pArray ) > > = aTmp [ 0 ] ;
( * pArray ) < < = aTmp ;
}
}
break ;
default :
break ;
}
2013-04-07 12:06:47 +02:00
OSL_TRACE ( " Param[%d] is %s " , ( int ) ( pArray - aParamTemp . getConstArray ( ) ) , OUStringToOString ( comphelper : : anyToString ( * pArray ) , RTL_TEXTENCODING_UTF8 ) . getStr ( ) ) ;
2010-06-15 20:02:53 +02:00
}
}
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 (
2013-04-07 12:06:47 +02:00
OUString ( " com.sun.star.sheet.FunctionAccess " ) , mxContext ) ,
2010-06-15 20:02:53 +02:00
uno : : UNO_QUERY_THROW ) ;
uno : : Reference < beans : : XPropertySet > xPropSet ( xFunctionAccess , uno : : UNO_QUERY_THROW ) ;
2013-06-29 21:24:12 +02:00
xPropSet - > setPropertyValue ( " IsArrayFunction " , uno : : Any ( bAsArray ) ) ;
2010-06-15 20:02:53 +02:00
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 ) | |
2012-06-09 12:43:30 +02:00
( eOpCode = = ocAnd ) | | ( eOpCode = = ocOr ) | | ( eOpCode = = ocXor ) | | ( eOpCode = = ocNot ) | | ( eOpCode = = ocTrue ) | | ( eOpCode = = ocFalse ) )
2010-06-15 20:02:53 +02:00
{
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.
2013-08-29 20:44:22 +01:00
OUString aUpper ( FunctionName . toAsciiUpperCase ( ) ) ;
2009-02-13 13:03:24 +00:00
ScCompiler aCompiler ( NULL , ScAddress ( ) ) ;
2013-08-29 20:44:22 +01:00
OpCode eOp = aCompiler . GetEnglishOpCode ( aUpper ) ;
2009-02-13 13:03:24 +00:00
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
2014-02-25 21:31:58 +01:00
ScVbaWSFunction : : setValue ( const OUString & /*PropertyName*/ , const uno : : Any & /*Value*/ ) throw ( beans : : UnknownPropertyException , script : : CannotConvertException , reflection : : InvocationTargetException , uno : : RuntimeException , std : : exception )
2007-04-25 15:14:30 +00:00
{
throw beans : : UnknownPropertyException ( ) ;
}
uno : : Any SAL_CALL
2014-02-25 21:31:58 +01:00
ScVbaWSFunction : : getValue ( const OUString & /*PropertyName*/ ) throw ( beans : : UnknownPropertyException , uno : : RuntimeException , std : : exception )
2007-04-25 15:14:30 +00:00
{
throw beans : : UnknownPropertyException ( ) ;
}
sal_Bool SAL_CALL
2014-02-25 21:31:58 +01:00
ScVbaWSFunction : : hasMethod ( const OUString & Name ) throw ( uno : : RuntimeException , std : : exception )
2007-04-25 15:14:30 +00:00
{
2014-04-23 11:08:48 +02:00
bool bIsFound = false ;
2007-04-25 15:14:30 +00:00
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 ) )
2014-04-23 11:08:48 +02:00
bIsFound = true ;
2007-04-25 15:14:30 +00:00
}
catch ( uno : : Exception & /*e*/ )
{
// failed to find name
}
return bIsFound ;
}
sal_Bool SAL_CALL
2014-02-25 21:31:58 +01:00
ScVbaWSFunction : : hasProperty ( const OUString & /*Name*/ ) throw ( uno : : RuntimeException , std : : exception )
2007-04-25 15:14:30 +00:00
{
2011-03-10 16:55:21 -05:00
return false ;
2007-04-25 15:14:30 +00:00
}
2013-04-07 12:06:47 +02:00
OUString SAL_CALL
2014-02-25 21:31:58 +01:00
ScVbaWSFunction : : getExactName ( const OUString & aApproximateName ) throw ( css : : uno : : RuntimeException , std : : exception )
2007-04-25 15:14:30 +00:00
{
2013-04-07 12:06:47 +02:00
OUString sName = aApproximateName . toAsciiUpperCase ( ) ;
2007-04-25 15:14:30 +00:00
if ( ! hasMethod ( sName ) )
2013-04-07 12:06:47 +02:00
return OUString ( ) ;
2007-04-25 15:14:30 +00:00
return sName ;
}
2007-12-07 10:07:56 +00:00
2013-04-07 12:06:47 +02:00
OUString
2007-12-07 10:07:56 +00:00
ScVbaWSFunction : : getServiceImplName ( )
{
2013-04-07 12:06:47 +02:00
return OUString ( " ScVbaWSFunction " ) ;
2007-12-07 10:07:56 +00:00
}
2013-04-07 12:06:47 +02:00
uno : : Sequence < OUString >
2007-12-07 10:07:56 +00:00
ScVbaWSFunction : : getServiceNames ( )
{
2013-04-07 12:06:47 +02:00
static uno : : Sequence < OUString > aServiceNames ;
2007-12-07 10:07:56 +00:00
if ( aServiceNames . getLength ( ) = = 0 )
{
aServiceNames . realloc ( 1 ) ;
2013-11-04 11:22:26 +02:00
aServiceNames [ 0 ] = " ooo.vba.excel.WorksheetFunction " ;
2007-12-07 10:07:56 +00:00
}
return aServiceNames ;
}
2010-10-12 15:59:00 +02:00
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */