summaryrefslogtreecommitdiff
path: root/sc/source/ui/unoobj/funcuno.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/ui/unoobj/funcuno.cxx')
-rw-r--r--sc/source/ui/unoobj/funcuno.cxx745
1 files changed, 745 insertions, 0 deletions
diff --git a/sc/source/ui/unoobj/funcuno.cxx b/sc/source/ui/unoobj/funcuno.cxx
new file mode 100644
index 000000000000..7012b477050c
--- /dev/null
+++ b/sc/source/ui/unoobj/funcuno.cxx
@@ -0,0 +1,745 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * 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.
+ *
+ * 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).
+ *
+ * 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.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+#include <tools/debug.hxx>
+#include <sfx2/app.hxx>
+#include <svl/itemprop.hxx>
+
+#include "scitems.hxx"
+#include "funcuno.hxx"
+#include "miscuno.hxx"
+#include "cellsuno.hxx"
+#include "unoguard.hxx"
+#include "scdll.hxx"
+#include "document.hxx"
+#include "compiler.hxx"
+#include "formula/errorcodes.hxx"
+#include "callform.hxx"
+#include "addincol.hxx"
+#include "rangeseq.hxx"
+#include "cell.hxx"
+#include "docoptio.hxx"
+#include "optuno.hxx"
+#include <docuno.hxx>
+// for lcl_CopyData:
+#include "markdata.hxx"
+#include "patattr.hxx"
+#include "docpool.hxx"
+#include "attrib.hxx"
+#include "clipparam.hxx"
+#include "dociter.hxx"
+
+using namespace com::sun::star;
+
+//------------------------------------------------------------------------
+
+// registered as implementation for service FunctionAccess,
+// also supports service SpreadsheetDocumentSettings (to set null date etc.)
+
+#define SCFUNCTIONACCESS_SERVICE "com.sun.star.sheet.FunctionAccess"
+#define SCDOCSETTINGS_SERVICE "com.sun.star.sheet.SpreadsheetDocumentSettings"
+
+//------------------------------------------------------------------------
+
+// helper to use cached document if not in use, temporary document otherwise
+
+class ScTempDocSource
+{
+private:
+ ScTempDocCache& rCache;
+ ScDocument* pTempDoc;
+
+ static ScDocument* CreateDocument(); // create and initialize doc
+
+public:
+ ScTempDocSource( ScTempDocCache& rDocCache );
+ ~ScTempDocSource();
+
+ ScDocument* GetDocument();
+};
+
+//------------------------------------------------------------------------
+
+// static
+ScDocument* ScTempDocSource::CreateDocument()
+{
+ ScDocument* pDoc = new ScDocument; // SCDOCMODE_DOCUMENT
+ pDoc->MakeTable( 0 );
+ return pDoc;
+}
+
+ScTempDocSource::ScTempDocSource( ScTempDocCache& rDocCache ) :
+ rCache( rDocCache ),
+ pTempDoc( NULL )
+{
+ if ( rCache.IsInUse() )
+ pTempDoc = CreateDocument();
+ else
+ {
+ rCache.SetInUse( TRUE );
+ if ( !rCache.GetDocument() )
+ rCache.SetDocument( CreateDocument() );
+ }
+}
+
+ScTempDocSource::~ScTempDocSource()
+{
+ if ( pTempDoc )
+ delete pTempDoc;
+ else
+ rCache.SetInUse( FALSE );
+}
+
+ScDocument* ScTempDocSource::GetDocument()
+{
+ if ( pTempDoc )
+ return pTempDoc;
+ else
+ return rCache.GetDocument();
+}
+
+//------------------------------------------------------------------------
+
+ScTempDocCache::ScTempDocCache() :
+ pDoc( NULL ),
+ bInUse( FALSE )
+{
+}
+
+ScTempDocCache::~ScTempDocCache()
+{
+ DBG_ASSERT( !bInUse, "ScTempDocCache dtor: bInUse" );
+ delete pDoc;
+}
+
+void ScTempDocCache::SetDocument( ScDocument* pNew )
+{
+ DBG_ASSERT( !pDoc, "ScTempDocCache::SetDocument: already set" );
+ pDoc = pNew;
+}
+
+void ScTempDocCache::Clear()
+{
+ DBG_ASSERT( !bInUse, "ScTempDocCache::Clear: bInUse" );
+ delete pDoc;
+ pDoc = NULL;
+}
+
+//------------------------------------------------------------------------
+
+// copy results from one document into another
+//! merge this with ScAreaLink::Refresh
+//! copy directly without a clipboard document?
+
+BOOL lcl_CopyData( ScDocument* pSrcDoc, const ScRange& rSrcRange,
+ ScDocument* pDestDoc, const ScAddress& rDestPos )
+{
+ SCTAB nSrcTab = rSrcRange.aStart.Tab();
+ SCTAB nDestTab = rDestPos.Tab();
+
+ ScRange aNewRange( rDestPos, ScAddress(
+ rSrcRange.aEnd.Col() - rSrcRange.aStart.Col() + rDestPos.Col(),
+ rSrcRange.aEnd.Row() - rSrcRange.aStart.Row() + rDestPos.Row(),
+ nDestTab ) );
+
+ ScDocument* pClipDoc = new ScDocument( SCDOCMODE_CLIP );
+ ScMarkData aSourceMark;
+ aSourceMark.SelectOneTable( nSrcTab ); // for CopyToClip
+ aSourceMark.SetMarkArea( rSrcRange );
+ ScClipParam aClipParam(rSrcRange, false);
+ pSrcDoc->CopyToClip(aClipParam, pClipDoc, &aSourceMark, false);
+
+ if ( pClipDoc->HasAttrib( 0,0,nSrcTab, MAXCOL,MAXROW,nSrcTab,
+ HASATTR_MERGED | HASATTR_OVERLAPPED ) )
+ {
+ ScPatternAttr aPattern( pSrcDoc->GetPool() );
+ aPattern.GetItemSet().Put( ScMergeAttr() ); // Defaults
+ aPattern.GetItemSet().Put( ScMergeFlagAttr() );
+ pClipDoc->ApplyPatternAreaTab( 0,0, MAXCOL,MAXROW, nSrcTab, aPattern );
+ }
+
+ // If the range contains formula cells with default number format,
+ // apply a number format for the formula result
+ ScCellIterator aIter( pClipDoc, rSrcRange );
+ ScBaseCell* pCell = aIter.GetFirst();
+ while (pCell)
+ {
+ if (pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ ScAddress aCellPos = aIter.GetPos();
+ sal_uInt32 nFormat = pClipDoc->GetNumberFormat(aCellPos);
+ if ( (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
+ {
+ ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
+ USHORT nErrCode = pFCell->GetErrCode();
+ if ( nErrCode == 0 && pFCell->IsValue() )
+ {
+ sal_uInt32 nNewFormat = pFCell->GetStandardFormat( *pClipDoc->GetFormatTable(), nFormat );
+ if ( nNewFormat != nFormat )
+ pClipDoc->ApplyAttr( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(),
+ SfxUInt32Item( ATTR_VALUE_FORMAT, nNewFormat ) );
+ }
+ }
+ }
+ pCell = aIter.GetNext();
+ }
+
+ ScMarkData aDestMark;
+ aDestMark.SelectOneTable( nDestTab );
+ aDestMark.SetMarkArea( aNewRange );
+ pDestDoc->CopyFromClip( aNewRange, aDestMark, IDF_ALL & ~IDF_FORMULA, NULL, pClipDoc, FALSE );
+
+ delete pClipDoc;
+ return TRUE;
+}
+
+//------------------------------------------------------------------------
+
+ScFunctionAccess::ScFunctionAccess() :
+ pOptions( NULL ),
+ aPropertyMap( ScDocOptionsHelper::GetPropertyMap() ),
+ mbArray( true ), // default according to behaviour of older Office versions
+ mbValid( true )
+{
+ StartListening( *SFX_APP() ); // for SFX_HINT_DEINITIALIZING
+}
+
+ScFunctionAccess::~ScFunctionAccess()
+{
+ delete pOptions;
+}
+
+void ScFunctionAccess::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.ISA(SfxSimpleHint) &&
+ ((SfxSimpleHint&)rHint).GetId() == SFX_HINT_DEINITIALIZING )
+ {
+ // document must not be used anymore
+ aDocCache.Clear();
+ mbValid = false;
+ }
+}
+
+// stuff for exService_...
+
+uno::Reference<uno::XInterface> SAL_CALL ScFunctionAccess_CreateInstance(
+ const uno::Reference<lang::XMultiServiceFactory>& )
+{
+ ScUnoGuard aGuard;
+ ScDLL::Init();
+ static uno::Reference< uno::XInterface > xInst((::cppu::OWeakObject*) new ScFunctionAccess);
+ return xInst;
+}
+
+rtl::OUString ScFunctionAccess::getImplementationName_Static()
+{
+ return rtl::OUString::createFromAscii( "stardiv.StarCalc.ScFunctionAccess" );
+}
+
+uno::Sequence<rtl::OUString> ScFunctionAccess::getSupportedServiceNames_Static()
+{
+ uno::Sequence<rtl::OUString> aRet(1);
+ rtl::OUString* pArray = aRet.getArray();
+ pArray[0] = rtl::OUString::createFromAscii( SCFUNCTIONACCESS_SERVICE );
+ return aRet;
+}
+
+// XServiceInfo
+
+rtl::OUString SAL_CALL ScFunctionAccess::getImplementationName() throw(uno::RuntimeException)
+{
+ return rtl::OUString::createFromAscii( "ScFunctionAccess" );
+}
+
+sal_Bool SAL_CALL ScFunctionAccess::supportsService( const rtl::OUString& rServiceName )
+ throw(uno::RuntimeException)
+{
+ String aServiceStr(rServiceName);
+ return aServiceStr.EqualsAscii( SCFUNCTIONACCESS_SERVICE ) ||
+ aServiceStr.EqualsAscii( SCDOCSETTINGS_SERVICE );
+}
+
+uno::Sequence<rtl::OUString> SAL_CALL ScFunctionAccess::getSupportedServiceNames()
+ throw(uno::RuntimeException)
+{
+ uno::Sequence<rtl::OUString> aRet(2);
+ rtl::OUString* pArray = aRet.getArray();
+ pArray[0] = rtl::OUString::createFromAscii( SCFUNCTIONACCESS_SERVICE );
+ pArray[1] = rtl::OUString::createFromAscii( SCDOCSETTINGS_SERVICE );
+ return aRet;
+}
+
+// XPropertySet (document settings)
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScFunctionAccess::getPropertySetInfo()
+ throw(uno::RuntimeException)
+{
+ ScUnoGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( &aPropertyMap ));
+ return aRef;
+}
+
+void SAL_CALL ScFunctionAccess::setPropertyValue(
+ const rtl::OUString& aPropertyName, const uno::Any& aValue )
+ throw(beans::UnknownPropertyException, beans::PropertyVetoException,
+ lang::IllegalArgumentException, lang::WrappedTargetException,
+ uno::RuntimeException)
+{
+ ScUnoGuard aGuard;
+
+ if( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsArrayFunction" ) ) )
+ {
+ if( !(aValue >>= mbArray) )
+ throw lang::IllegalArgumentException();
+ }
+ else
+ {
+ if ( !pOptions )
+ pOptions = new ScDocOptions();
+
+ // options aren't initialized from configuration - always get the same default behaviour
+
+ BOOL bDone = ScDocOptionsHelper::setPropertyValue( *pOptions, aPropertyMap, aPropertyName, aValue );
+ if (!bDone)
+ throw beans::UnknownPropertyException();
+ }
+}
+
+uno::Any SAL_CALL ScFunctionAccess::getPropertyValue( const rtl::OUString& aPropertyName )
+ throw(beans::UnknownPropertyException, lang::WrappedTargetException,
+ uno::RuntimeException)
+{
+ ScUnoGuard aGuard;
+
+ if( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "IsArrayFunction" ) ) )
+ return uno::Any( mbArray );
+
+ if ( !pOptions )
+ pOptions = new ScDocOptions();
+
+ // options aren't initialized from configuration - always get the same default behaviour
+
+ return ScDocOptionsHelper::getPropertyValue( *pOptions, aPropertyMap, aPropertyName );
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFunctionAccess )
+
+// XFunctionAccess
+
+BOOL lcl_AddFunctionToken( ScTokenArray& rArray, const rtl::OUString& rName,const ScCompiler& rCompiler )
+{
+ // function names are always case-insensitive
+ String aUpper( ScGlobal::pCharClass->upper( rName ) );
+
+ // same options as in ScCompiler::IsOpCode:
+ // 1. built-in function name
+
+ OpCode eOp = rCompiler.GetEnglishOpCode( aUpper );
+ if ( eOp != ocNone )
+ {
+ rArray.AddOpCode( eOp );
+ return TRUE;
+ }
+
+ // 2. old add in functions
+
+ USHORT nIndex;
+ if ( ScGlobal::GetFuncCollection()->SearchFunc( aUpper, nIndex ) )
+ {
+ rArray.AddExternal( aUpper.GetBuffer() );
+ return TRUE;
+ }
+
+ // 3. new (uno) add in functions
+
+ String aIntName(ScGlobal::GetAddInCollection()->FindFunction( aUpper, FALSE ));
+ if (aIntName.Len())
+ {
+ rArray.AddExternal( aIntName.GetBuffer() ); // international name
+ return TRUE;
+ }
+
+ return FALSE; // no valid function name
+}
+
+void lcl_AddRef( ScTokenArray& rArray, long nStartRow, long nColCount, long nRowCount )
+{
+ ScComplexRefData aRef;
+ aRef.InitFlags();
+ aRef.Ref1.nTab = 0;
+ aRef.Ref2.nTab = 0;
+ aRef.Ref1.nCol = 0;
+ aRef.Ref1.nRow = (SCROW) nStartRow;
+ aRef.Ref2.nCol = (SCCOL) (nColCount - 1);
+ aRef.Ref2.nRow = (SCROW) (nStartRow + nRowCount - 1);
+ rArray.AddDoubleReference(aRef);
+}
+
+class SimpleVisitor
+{
+protected:
+ bool mbArgError;
+ ScDocument* mpDoc;
+public:
+ SimpleVisitor( ScDocument* pDoc ) : mbArgError( false ), mpDoc( pDoc ) {}
+ // could possibly just get away with JUST the following overload
+ // 1) virtual void visitElem( long& nCol, long& nRow, const double& elem )
+ // 2) virtual void visitElem( long& nCol, long& nRow, const rtl::OUString& elem )
+ // 3) virtual void visitElem( long& nCol, long& nRow, const uno::Any& elem )
+ // the other types methods are here just to reflect the orig code and for
+ // completeness.
+
+ void visitElem( long nCol, long nRow, const sal_Int16& elem )
+ {
+ mpDoc->SetValue( (SCCOL) nCol, (SCROW) nRow, 0, elem );
+ }
+ void visitElem( long nCol, long nRow, const sal_Int32& elem )
+ {
+ mpDoc->SetValue( (SCCOL) nCol, (SCROW) nRow, 0, elem );
+ }
+ void visitElem( long nCol, long nRow, const double& elem )
+ {
+ mpDoc->SetValue( (SCCOL) nCol, (SCROW) nRow, 0, elem );
+ }
+ void visitElem( long nCol, long nRow, const rtl::OUString& elem )
+ {
+ if ( elem.getLength() )
+ mpDoc->PutCell( (SCCOL) nCol, (SCROW) nRow, 0,
+ new ScStringCell( elem ) );
+ }
+ void visitElem( long nCol, long nRow, const uno::Any& rElement )
+ {
+ uno::TypeClass eElemClass = rElement.getValueTypeClass();
+ if ( eElemClass == uno::TypeClass_VOID )
+ {
+ // leave empty
+ }
+ else if ( eElemClass == uno::TypeClass_BYTE ||
+ eElemClass == uno::TypeClass_SHORT ||
+ eElemClass == uno::TypeClass_UNSIGNED_SHORT ||
+ eElemClass == uno::TypeClass_LONG ||
+ eElemClass == uno::TypeClass_UNSIGNED_LONG ||
+ eElemClass == uno::TypeClass_FLOAT ||
+ eElemClass == uno::TypeClass_DOUBLE )
+ {
+ // #87871# accept integer types because Basic passes a floating point
+ // variable as byte, short or long if it's an integer number.
+ double fVal(0.0);
+ rElement >>= fVal;
+ visitElem( nCol, nRow, fVal );
+ }
+ else if ( eElemClass == uno::TypeClass_STRING )
+ {
+ rtl::OUString aUStr;
+ rElement >>= aUStr;
+ visitElem( nCol, nRow, aUStr );
+ }
+ else
+ mbArgError = true;
+ }
+ bool hasArgError() { return mbArgError; }
+};
+
+template< class seq >
+class SequencesContainer
+{
+ uno::Sequence< uno::Sequence< seq > > maSeq;
+
+ long& mrDocRow;
+ bool mbOverflow;
+ bool mbArgError;
+ ScDocument* mpDoc;
+ ScTokenArray& mrTokenArr;
+
+public:
+ SequencesContainer( const uno::Any& rArg, ScTokenArray& rTokenArr, long& rDocRow, ScDocument* pDoc ) :
+ mrDocRow( rDocRow ), mbOverflow(false), mbArgError(false), mpDoc( pDoc ), mrTokenArr( rTokenArr )
+ {
+ rArg >>= maSeq;
+ }
+
+ void process()
+ {
+ SimpleVisitor aVisitor(mpDoc);
+ long nStartRow = mrDocRow;
+ long nRowCount = maSeq.getLength();
+ long nMaxColCount = 0;
+ const uno::Sequence< seq >* pRowArr = maSeq.getConstArray();
+ for ( long nRow=0; nRow<nRowCount; nRow++ )
+ {
+ long nColCount = pRowArr[nRow].getLength();
+ if ( nColCount > nMaxColCount )
+ nMaxColCount = nColCount;
+ const seq* pColArr = pRowArr[nRow].getConstArray();
+ for (long nCol=0; nCol<nColCount; nCol++)
+ if ( nCol <= MAXCOL && mrDocRow <= MAXROW )
+ aVisitor.visitElem( nCol, mrDocRow, pColArr[ nCol ] );
+ else
+ mbOverflow=true;
+ mrDocRow++;
+ }
+ mbArgError = aVisitor.hasArgError();
+ if ( nRowCount && nMaxColCount && !mbOverflow )
+ lcl_AddRef( mrTokenArr, nStartRow, nMaxColCount, nRowCount );
+ }
+ bool getOverflow() { return mbOverflow; }
+ bool getArgError() { return mbArgError; }
+};
+
+template <class T>
+class ArrayOfArrayProc
+{
+public:
+static void processSequences( ScDocument* pDoc, const uno::Any& rArg, ScTokenArray& rTokenArr,
+ long& rDocRow, BOOL& rArgErr, BOOL& rOverflow )
+{
+ SequencesContainer< T > aContainer( rArg, rTokenArr, rDocRow, pDoc );
+ aContainer.process();
+ rArgErr = aContainer.getArgError();
+ rOverflow = aContainer.getOverflow();
+}
+};
+
+uno::Any SAL_CALL ScFunctionAccess::callFunction( const rtl::OUString& aName,
+ const uno::Sequence<uno::Any>& aArguments )
+ throw(container::NoSuchElementException, lang::IllegalArgumentException,
+ uno::RuntimeException)
+{
+ ScUnoGuard aGuard;
+
+ if (!mbValid)
+ throw uno::RuntimeException();
+
+ // use cached document if not in use, temporary document otherwise
+ // (deleted in ScTempDocSource dtor)
+ ScTempDocSource aSource( aDocCache );
+ ScDocument* pDoc = aSource.GetDocument();
+ const static SCTAB nTempSheet = 1;
+ // Create an extra tab to contain the Function Cell
+ // this will allow full rows to be used.
+ if ( !pDoc->HasTable( nTempSheet ) )
+ pDoc->MakeTable( nTempSheet );
+
+ /// TODO: check
+ ScAddress aAdr;
+ ScCompiler aCompiler(pDoc,aAdr);
+ aCompiler.SetGrammar(pDoc->GetGrammar());
+ //if (!ScCompiler::IsInitialized())
+ // ScCompiler::InitSymbolsEnglish();
+
+ //
+ // find function
+ //
+
+ ScTokenArray aTokenArr;
+ if ( !lcl_AddFunctionToken( aTokenArr, aName,aCompiler ) )
+ {
+ // function not found
+ throw container::NoSuchElementException();
+ }
+
+ //
+ // set options (null date, etc.)
+ //
+
+ if ( pOptions )
+ pDoc->SetDocOptions( *pOptions );
+
+ //
+ // add arguments to token array
+ //
+
+ BOOL bArgErr = FALSE;
+ BOOL bOverflow = FALSE;
+ long nDocRow = 0;
+ long nArgCount = aArguments.getLength();
+ const uno::Any* pArgArr = aArguments.getConstArray();
+
+ aTokenArr.AddOpCode(ocOpen);
+ for (long nPos=0; nPos<nArgCount; nPos++)
+ {
+ if ( nPos > 0 )
+ aTokenArr.AddOpCode(ocSep);
+
+ const uno::Any& rArg = pArgArr[nPos];
+
+ uno::TypeClass eClass = rArg.getValueTypeClass();
+ uno::Type aType = rArg.getValueType();
+ if ( eClass == uno::TypeClass_BYTE ||
+ eClass == uno::TypeClass_BOOLEAN ||
+ eClass == uno::TypeClass_SHORT ||
+ eClass == uno::TypeClass_UNSIGNED_SHORT ||
+ eClass == uno::TypeClass_LONG ||
+ eClass == uno::TypeClass_UNSIGNED_LONG ||
+ eClass == uno::TypeClass_FLOAT ||
+ eClass == uno::TypeClass_DOUBLE )
+ {
+ // #87871# accept integer types because Basic passes a floating point
+ // variable as byte, short or long if it's an integer number.
+ double fVal = 0;
+ rArg >>= fVal;
+ aTokenArr.AddDouble( fVal );
+ }
+ else if ( eClass == uno::TypeClass_STRING )
+ {
+ rtl::OUString aUStr;
+ rArg >>= aUStr;
+ String aStr( aUStr );
+ aTokenArr.AddString( aStr.GetBuffer() );
+ }
+ else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<sal_Int16> > *)0 ) ) )
+ {
+ ArrayOfArrayProc<sal_Int16>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
+ }
+ else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<sal_Int32> > *)0 ) ) )
+ {
+ ArrayOfArrayProc<sal_Int32>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
+ }
+ else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<double> > *)0 ) ) )
+ {
+ ArrayOfArrayProc<double>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
+ }
+ else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<rtl::OUString> > *)0 ) ) )
+ {
+ ArrayOfArrayProc<rtl::OUString>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
+ }
+ else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<uno::Any> > *)0 ) ) )
+ {
+ ArrayOfArrayProc<uno::Any>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
+ }
+ else if ( aType.equals( getCppuType( (uno::Reference<table::XCellRange>*)0 ) ) )
+ {
+ // currently, only our own cell ranges are supported
+
+ uno::Reference<table::XCellRange> xRange(rArg, uno::UNO_QUERY);
+ ScCellRangesBase* pImpl = ScCellRangesBase::getImplementation( xRange );
+ if ( pImpl )
+ {
+ ScDocument* pSrcDoc = pImpl->GetDocument();
+ const ScRangeList& rRanges = pImpl->GetRangeList();
+ if ( pSrcDoc && rRanges.Count() == 1 )
+ {
+ ScRange aSrcRange = *rRanges.GetObject(0);
+
+ long nStartRow = nDocRow;
+ long nColCount = aSrcRange.aEnd.Col() - aSrcRange.aStart.Col() + 1;
+ long nRowCount = aSrcRange.aEnd.Row() - aSrcRange.aStart.Row() + 1;
+
+ if ( nStartRow + nRowCount > MAXROWCOUNT )
+ bOverflow = TRUE;
+ else
+ {
+ // copy data
+ if ( !lcl_CopyData( pSrcDoc, aSrcRange, pDoc, ScAddress( 0, (SCROW)nDocRow, 0 ) ) )
+ bOverflow = TRUE;
+ }
+
+ nDocRow += nRowCount;
+ if ( !bOverflow )
+ lcl_AddRef( aTokenArr, nStartRow, nColCount, nRowCount );
+ }
+ else
+ bArgErr = TRUE;
+ }
+ else
+ bArgErr = TRUE;
+ }
+ else
+ bArgErr = TRUE; // invalid type
+ }
+ aTokenArr.AddOpCode(ocClose);
+ aTokenArr.AddOpCode(ocStop);
+
+ //
+ // execute formula
+ //
+
+ uno::Any aRet;
+ if ( !bArgErr && !bOverflow && nDocRow <= MAXROWCOUNT )
+ {
+ ScAddress aFormulaPos( 0, 0, nTempSheet );
+ // GRAM_PODF_A1 doesn't really matter for the token array but fits with
+ // other API compatibility grammars.
+ ScFormulaCell* pFormula = new ScFormulaCell( pDoc, aFormulaPos,
+ &aTokenArr, formula::FormulaGrammar::GRAM_PODF_A1, (BYTE)(mbArray ? MM_FORMULA : MM_NONE) );
+ pDoc->PutCell( aFormulaPos, pFormula ); //! necessary?
+
+ // call GetMatrix before GetErrCode because GetMatrix always recalculates
+ // if there is no matrix result
+
+ const ScMatrix* pMat = mbArray ? pFormula->GetMatrix() : 0;
+ USHORT nErrCode = pFormula->GetErrCode();
+ if ( nErrCode == 0 )
+ {
+ if ( pMat )
+ {
+ // array result
+ ScRangeToSequence::FillMixedArray( aRet, pMat );
+ }
+ else if ( pFormula->IsValue() )
+ {
+ // numeric value
+ aRet <<= (double) pFormula->GetValue();
+ }
+ else
+ {
+ // string result
+ String aStrVal;
+ pFormula->GetString( aStrVal );
+ aRet <<= rtl::OUString( aStrVal );
+ }
+ }
+ else if ( nErrCode == NOTAVAILABLE )
+ {
+ // #N/A: leave result empty, no exception
+ }
+ else
+ {
+ // any other error: IllegalArgumentException
+ bArgErr = TRUE;
+ }
+
+ pDoc->DeleteAreaTab( 0, 0, MAXCOL, MAXROW, 0, IDF_ALL );
+ pDoc->DeleteAreaTab( 0, 0, 0, 0, nTempSheet, IDF_ALL );
+ }
+
+ if (bOverflow)
+ throw uno::RuntimeException();
+
+ if (bArgErr)
+ throw lang::IllegalArgumentException();
+
+ return aRet;
+}
+
+