| /************************************************************** |
| * |
| * 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 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the 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( sal_True ); |
| if ( !rCache.GetDocument() ) |
| rCache.SetDocument( CreateDocument() ); |
| } |
| } |
| |
| ScTempDocSource::~ScTempDocSource() |
| { |
| if ( pTempDoc ) |
| delete pTempDoc; |
| else |
| rCache.SetInUse( sal_False ); |
| } |
| |
| ScDocument* ScTempDocSource::GetDocument() |
| { |
| if ( pTempDoc ) |
| return pTempDoc; |
| else |
| return rCache.GetDocument(); |
| } |
| |
| //------------------------------------------------------------------------ |
| |
| ScTempDocCache::ScTempDocCache() : |
| pDoc( NULL ), |
| bInUse( sal_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? |
| |
| sal_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); |
| sal_uInt16 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, sal_False ); |
| |
| delete pClipDoc; |
| return sal_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 |
| |
| sal_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 |
| |
| sal_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 sal_True; |
| } |
| |
| // 2. old add in functions |
| |
| sal_uInt16 nIndex; |
| if ( ScGlobal::GetFuncCollection()->SearchFunc( aUpper, nIndex ) ) |
| { |
| rArray.AddExternal( aUpper.GetBuffer() ); |
| return sal_True; |
| } |
| |
| // 3. new (uno) add in functions |
| |
| String aIntName(ScGlobal::GetAddInCollection()->FindFunction( aUpper, sal_False )); |
| if (aIntName.Len()) |
| { |
| rArray.AddExternal( aIntName.GetBuffer() ); // international name |
| return sal_True; |
| } |
| |
| return sal_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, sal_Bool& rArgErr, sal_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 |
| // |
| |
| sal_Bool bArgErr = sal_False; |
| sal_Bool bOverflow = sal_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 = sal_True; |
| else |
| { |
| // copy data |
| if ( !lcl_CopyData( pSrcDoc, aSrcRange, pDoc, ScAddress( 0, (SCROW)nDocRow, 0 ) ) ) |
| bOverflow = sal_True; |
| } |
| |
| nDocRow += nRowCount; |
| if ( !bOverflow ) |
| lcl_AddRef( aTokenArr, nStartRow, nColCount, nRowCount ); |
| } |
| else |
| bArgErr = sal_True; |
| } |
| else |
| bArgErr = sal_True; |
| } |
| else |
| bArgErr = sal_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, (sal_uInt8)(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; |
| sal_uInt16 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 = sal_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; |
| } |
| |
| |