Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <cppuhelper/supportsservice.hxx>
21 : #include <sfx2/app.hxx>
22 : #include <svl/itemprop.hxx>
23 : #include <svl/sharedstringpool.hxx>
24 :
25 : #include "scitems.hxx"
26 : #include "funcuno.hxx"
27 : #include "miscuno.hxx"
28 : #include "cellsuno.hxx"
29 : #include "scdll.hxx"
30 : #include "document.hxx"
31 : #include "compiler.hxx"
32 : #include <formula/errorcodes.hxx>
33 : #include "callform.hxx"
34 : #include "addincol.hxx"
35 : #include "rangeseq.hxx"
36 : #include "formulacell.hxx"
37 : #include "docoptio.hxx"
38 : #include "optuno.hxx"
39 : #include <docuno.hxx>
40 : #include "markdata.hxx"
41 : #include "patattr.hxx"
42 : #include "docpool.hxx"
43 : #include "attrib.hxx"
44 : #include "clipparam.hxx"
45 : #include "dociter.hxx"
46 : #include "stringutil.hxx"
47 : #include "tokenarray.hxx"
48 :
49 : using namespace com::sun::star;
50 :
51 : // registered as implementation for service FunctionAccess,
52 : // also supports service SpreadsheetDocumentSettings (to set null date etc.)
53 :
54 : #define SCFUNCTIONACCESS_SERVICE "com.sun.star.sheet.FunctionAccess"
55 : #define SCDOCSETTINGS_SERVICE "com.sun.star.sheet.SpreadsheetDocumentSettings"
56 :
57 : // helper to use cached document if not in use, temporary document otherwise
58 :
59 : class ScTempDocSource
60 : {
61 : private:
62 : ScTempDocCache& rCache;
63 : ScDocument* pTempDoc;
64 :
65 : static ScDocument* CreateDocument(); // create and initialize doc
66 :
67 : public:
68 : ScTempDocSource( ScTempDocCache& rDocCache );
69 : ~ScTempDocSource();
70 :
71 : ScDocument* GetDocument();
72 : };
73 :
74 0 : ScDocument* ScTempDocSource::CreateDocument()
75 : {
76 0 : ScDocument* pDoc = new ScDocument; // SCDOCMODE_DOCUMENT
77 0 : pDoc->MakeTable( 0 );
78 0 : return pDoc;
79 : }
80 :
81 0 : ScTempDocSource::ScTempDocSource( ScTempDocCache& rDocCache ) :
82 : rCache( rDocCache ),
83 0 : pTempDoc( NULL )
84 : {
85 0 : if ( rCache.IsInUse() )
86 0 : pTempDoc = CreateDocument();
87 : else
88 : {
89 0 : rCache.SetInUse( true );
90 0 : if ( !rCache.GetDocument() )
91 0 : rCache.SetDocument( CreateDocument() );
92 : }
93 0 : }
94 :
95 0 : ScTempDocSource::~ScTempDocSource()
96 : {
97 0 : if ( pTempDoc )
98 0 : delete pTempDoc;
99 : else
100 0 : rCache.SetInUse( false );
101 0 : }
102 :
103 0 : ScDocument* ScTempDocSource::GetDocument()
104 : {
105 0 : if ( pTempDoc )
106 0 : return pTempDoc;
107 : else
108 0 : return rCache.GetDocument();
109 : }
110 :
111 0 : ScTempDocCache::ScTempDocCache() :
112 : pDoc( NULL ),
113 0 : bInUse( false )
114 : {
115 0 : }
116 :
117 0 : ScTempDocCache::~ScTempDocCache()
118 : {
119 : OSL_ENSURE( !bInUse, "ScTempDocCache dtor: bInUse" );
120 0 : delete pDoc;
121 0 : }
122 :
123 0 : void ScTempDocCache::SetDocument( ScDocument* pNew )
124 : {
125 : OSL_ENSURE( !pDoc, "ScTempDocCache::SetDocument: already set" );
126 0 : pDoc = pNew;
127 0 : }
128 :
129 0 : void ScTempDocCache::Clear()
130 : {
131 : OSL_ENSURE( !bInUse, "ScTempDocCache::Clear: bInUse" );
132 0 : delete pDoc;
133 0 : pDoc = NULL;
134 0 : }
135 :
136 : // copy results from one document into another
137 : //! merge this with ScAreaLink::Refresh
138 : //! copy directly without a clipboard document?
139 :
140 0 : static bool lcl_CopyData( ScDocument* pSrcDoc, const ScRange& rSrcRange,
141 : ScDocument* pDestDoc, const ScAddress& rDestPos )
142 : {
143 0 : SCTAB nSrcTab = rSrcRange.aStart.Tab();
144 0 : SCTAB nDestTab = rDestPos.Tab();
145 :
146 : ScRange aNewRange( rDestPos, ScAddress(
147 0 : rSrcRange.aEnd.Col() - rSrcRange.aStart.Col() + rDestPos.Col(),
148 0 : rSrcRange.aEnd.Row() - rSrcRange.aStart.Row() + rDestPos.Row(),
149 0 : nDestTab ) );
150 :
151 0 : ScDocument* pClipDoc = new ScDocument( SCDOCMODE_CLIP );
152 0 : ScMarkData aSourceMark;
153 0 : aSourceMark.SelectOneTable( nSrcTab ); // for CopyToClip
154 0 : aSourceMark.SetMarkArea( rSrcRange );
155 0 : ScClipParam aClipParam(rSrcRange, false);
156 0 : pSrcDoc->CopyToClip(aClipParam, pClipDoc, &aSourceMark, false);
157 :
158 0 : if ( pClipDoc->HasAttrib( 0,0,nSrcTab, MAXCOL,MAXROW,nSrcTab,
159 0 : HASATTR_MERGED | HASATTR_OVERLAPPED ) )
160 : {
161 0 : ScPatternAttr aPattern( pSrcDoc->GetPool() );
162 0 : aPattern.GetItemSet().Put( ScMergeAttr() ); // Defaults
163 0 : aPattern.GetItemSet().Put( ScMergeFlagAttr() );
164 0 : pClipDoc->ApplyPatternAreaTab( 0,0, MAXCOL,MAXROW, nSrcTab, aPattern );
165 : }
166 :
167 0 : ScMarkData aDestMark;
168 0 : aDestMark.SelectOneTable( nDestTab );
169 0 : aDestMark.SetMarkArea( aNewRange );
170 0 : pDestDoc->CopyFromClip( aNewRange, aDestMark, IDF_ALL & ~IDF_FORMULA, NULL, pClipDoc, false );
171 :
172 0 : delete pClipDoc;
173 0 : return true;
174 : }
175 :
176 0 : ScFunctionAccess::ScFunctionAccess() :
177 : pOptions( NULL ),
178 : aPropertyMap( ScDocOptionsHelper::GetPropertyMap() ),
179 : mbArray( true ), // default according to behaviour of older Office versions
180 0 : mbValid( true )
181 : {
182 0 : StartListening( *SfxGetpApp() ); // for SFX_HINT_DEINITIALIZING
183 0 : }
184 :
185 0 : ScFunctionAccess::~ScFunctionAccess()
186 : {
187 0 : delete pOptions;
188 0 : }
189 :
190 0 : void ScFunctionAccess::Notify( SfxBroadcaster&, const SfxHint& rHint )
191 : {
192 0 : const SfxSimpleHint* pSimpleHint = dynamic_cast<const SfxSimpleHint*>(&rHint);
193 0 : if ( pSimpleHint && pSimpleHint->GetId() == SFX_HINT_DEINITIALIZING )
194 : {
195 : // document must not be used anymore
196 0 : aDocCache.Clear();
197 0 : mbValid = false;
198 : }
199 0 : }
200 :
201 : // stuff for exService_...
202 :
203 0 : uno::Reference<uno::XInterface> SAL_CALL ScFunctionAccess_CreateInstance(
204 : const uno::Reference<lang::XMultiServiceFactory>& )
205 : {
206 0 : SolarMutexGuard aGuard;
207 0 : ScDLL::Init();
208 0 : static uno::Reference< uno::XInterface > xInst((::cppu::OWeakObject*) new ScFunctionAccess);
209 0 : return xInst;
210 : }
211 :
212 300 : OUString ScFunctionAccess::getImplementationName_Static()
213 : {
214 300 : return OUString( "stardiv.StarCalc.ScFunctionAccess" );
215 : }
216 :
217 0 : uno::Sequence<OUString> ScFunctionAccess::getSupportedServiceNames_Static()
218 : {
219 0 : uno::Sequence<OUString> aRet(1);
220 0 : OUString* pArray = aRet.getArray();
221 0 : pArray[0] = OUString( SCFUNCTIONACCESS_SERVICE );
222 0 : return aRet;
223 : }
224 :
225 : // XServiceInfo
226 0 : OUString SAL_CALL ScFunctionAccess::getImplementationName() throw(uno::RuntimeException, std::exception)
227 : {
228 0 : return OUString( "ScFunctionAccess");
229 : }
230 :
231 0 : sal_Bool SAL_CALL ScFunctionAccess::supportsService( const OUString& rServiceName )
232 : throw(uno::RuntimeException, std::exception)
233 : {
234 0 : return cppu::supportsService(this, rServiceName);
235 : }
236 :
237 0 : uno::Sequence<OUString> SAL_CALL ScFunctionAccess::getSupportedServiceNames()
238 : throw(uno::RuntimeException, std::exception)
239 : {
240 0 : uno::Sequence<OUString> aRet(2);
241 0 : OUString* pArray = aRet.getArray();
242 0 : pArray[0] = OUString( SCFUNCTIONACCESS_SERVICE );
243 0 : pArray[1] = OUString( SCDOCSETTINGS_SERVICE );
244 0 : return aRet;
245 : }
246 :
247 : // XPropertySet (document settings)
248 :
249 0 : uno::Reference<beans::XPropertySetInfo> SAL_CALL ScFunctionAccess::getPropertySetInfo()
250 : throw(uno::RuntimeException, std::exception)
251 : {
252 0 : SolarMutexGuard aGuard;
253 : static uno::Reference<beans::XPropertySetInfo> aRef(
254 0 : new SfxItemPropertySetInfo( aPropertyMap ));
255 0 : return aRef;
256 : }
257 :
258 0 : void SAL_CALL ScFunctionAccess::setPropertyValue(
259 : const OUString& aPropertyName, const uno::Any& aValue )
260 : throw(beans::UnknownPropertyException, beans::PropertyVetoException,
261 : lang::IllegalArgumentException, lang::WrappedTargetException,
262 : uno::RuntimeException, std::exception)
263 : {
264 0 : SolarMutexGuard aGuard;
265 :
266 0 : if ( aPropertyName == "IsArrayFunction" )
267 : {
268 0 : if( !(aValue >>= mbArray) )
269 0 : throw lang::IllegalArgumentException();
270 : }
271 : else
272 : {
273 0 : if ( !pOptions )
274 0 : pOptions = new ScDocOptions();
275 :
276 : // options aren't initialized from configuration - always get the same default behaviour
277 :
278 0 : bool bDone = ScDocOptionsHelper::setPropertyValue( *pOptions, aPropertyMap, aPropertyName, aValue );
279 0 : if (!bDone)
280 0 : throw beans::UnknownPropertyException();
281 0 : }
282 0 : }
283 :
284 0 : uno::Any SAL_CALL ScFunctionAccess::getPropertyValue( const OUString& aPropertyName )
285 : throw(beans::UnknownPropertyException, lang::WrappedTargetException,
286 : uno::RuntimeException, std::exception)
287 : {
288 0 : SolarMutexGuard aGuard;
289 :
290 0 : if ( aPropertyName == "IsArrayFunction" )
291 0 : return uno::Any( mbArray );
292 :
293 0 : if ( !pOptions )
294 0 : pOptions = new ScDocOptions();
295 :
296 : // options aren't initialized from configuration - always get the same default behaviour
297 :
298 0 : return ScDocOptionsHelper::getPropertyValue( *pOptions, aPropertyMap, aPropertyName );
299 : }
300 :
301 0 : SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFunctionAccess )
302 :
303 : // XFunctionAccess
304 :
305 0 : static bool lcl_AddFunctionToken( ScTokenArray& rArray, const OUString& rName,const ScCompiler& rCompiler )
306 : {
307 : // function names are always case-insensitive
308 0 : OUString aUpper = ScGlobal::pCharClass->uppercase(rName);
309 :
310 : // same options as in ScCompiler::IsOpCode:
311 : // 1. built-in function name
312 :
313 0 : OpCode eOp = rCompiler.GetEnglishOpCode( aUpper );
314 0 : if ( eOp != ocNone )
315 : {
316 0 : rArray.AddOpCode( eOp );
317 0 : return true;
318 : }
319 :
320 : // 2. old add in functions
321 :
322 0 : if (ScGlobal::GetFuncCollection()->findByName(aUpper))
323 : {
324 0 : rArray.AddExternal(aUpper.getStr());
325 0 : return true;
326 : }
327 :
328 : // 3. new (uno) add in functions
329 :
330 : OUString aIntName =
331 0 : ScGlobal::GetAddInCollection()->FindFunction(aUpper, false);
332 0 : if (!aIntName.isEmpty())
333 : {
334 0 : rArray.AddExternal(aIntName.getStr()); // international name
335 0 : return true;
336 : }
337 :
338 0 : return false; // no valid function name
339 : }
340 :
341 0 : static void lcl_AddRef( ScTokenArray& rArray, long nStartRow, long nColCount, long nRowCount )
342 : {
343 : ScComplexRefData aRef;
344 0 : aRef.InitRange(ScRange(0,nStartRow,0,nColCount-1,nStartRow+nRowCount-1,0));
345 0 : rArray.AddDoubleReference(aRef);
346 0 : }
347 :
348 : class SimpleVisitor
349 : {
350 : protected:
351 : bool mbArgError;
352 : ScDocument* mpDoc;
353 : public:
354 0 : SimpleVisitor( ScDocument* pDoc ) : mbArgError( false ), mpDoc( pDoc ) {}
355 : // could possibly just get away with JUST the following overload
356 : // 1) virtual void visitElem( long& nCol, long& nRow, const double& elem )
357 : // 2) virtual void visitElem( long& nCol, long& nRow, const OUString& elem )
358 : // 3) virtual void visitElem( long& nCol, long& nRow, const uno::Any& elem )
359 : // the other types methods are here just to reflect the orig code and for
360 : // completeness.
361 :
362 0 : void visitElem( long nCol, long nRow, const sal_Int16& elem )
363 : {
364 0 : mpDoc->SetValue( (SCCOL) nCol, (SCROW) nRow, 0, elem );
365 0 : }
366 0 : void visitElem( long nCol, long nRow, const sal_Int32& elem )
367 : {
368 0 : mpDoc->SetValue( (SCCOL) nCol, (SCROW) nRow, 0, elem );
369 0 : }
370 0 : void visitElem( long nCol, long nRow, const double& elem )
371 : {
372 0 : mpDoc->SetValue( (SCCOL) nCol, (SCROW) nRow, 0, elem );
373 0 : }
374 0 : void visitElem( long nCol, long nRow, const OUString& elem )
375 : {
376 0 : if (!elem.isEmpty())
377 : {
378 0 : ScSetStringParam aParam;
379 0 : aParam.setTextInput();
380 0 : mpDoc->SetString(ScAddress(nCol,nRow,0), elem, &aParam);
381 : }
382 0 : }
383 0 : void visitElem( long nCol, long nRow, const uno::Any& rElement )
384 : {
385 0 : uno::TypeClass eElemClass = rElement.getValueTypeClass();
386 0 : if ( eElemClass == uno::TypeClass_VOID )
387 : {
388 : // leave empty
389 : }
390 0 : else if ( eElemClass == uno::TypeClass_BYTE ||
391 0 : eElemClass == uno::TypeClass_SHORT ||
392 0 : eElemClass == uno::TypeClass_UNSIGNED_SHORT ||
393 0 : eElemClass == uno::TypeClass_LONG ||
394 0 : eElemClass == uno::TypeClass_UNSIGNED_LONG ||
395 0 : eElemClass == uno::TypeClass_FLOAT ||
396 : eElemClass == uno::TypeClass_DOUBLE )
397 : {
398 : // accept integer types because Basic passes a floating point
399 : // variable as byte, short or long if it's an integer number.
400 0 : double fVal(0.0);
401 0 : rElement >>= fVal;
402 0 : visitElem( nCol, nRow, fVal );
403 : }
404 0 : else if ( eElemClass == uno::TypeClass_STRING )
405 : {
406 0 : OUString aUStr;
407 0 : rElement >>= aUStr;
408 0 : visitElem( nCol, nRow, aUStr );
409 : }
410 : else
411 0 : mbArgError = true;
412 0 : }
413 0 : bool hasArgError() const { return mbArgError; }
414 : };
415 :
416 : template< class seq >
417 0 : class SequencesContainer
418 : {
419 : uno::Sequence< uno::Sequence< seq > > maSeq;
420 :
421 : long& mrDocRow;
422 : bool mbOverflow;
423 : bool mbArgError;
424 : ScDocument* mpDoc;
425 : ScTokenArray& mrTokenArr;
426 :
427 : public:
428 0 : SequencesContainer( const uno::Any& rArg, ScTokenArray& rTokenArr, long& rDocRow, ScDocument* pDoc ) :
429 0 : mrDocRow( rDocRow ), mbOverflow(false), mbArgError(false), mpDoc( pDoc ), mrTokenArr( rTokenArr )
430 : {
431 0 : rArg >>= maSeq;
432 0 : }
433 :
434 0 : void process()
435 : {
436 0 : SimpleVisitor aVisitor(mpDoc);
437 0 : long nStartRow = mrDocRow;
438 0 : long nRowCount = maSeq.getLength();
439 0 : long nMaxColCount = 0;
440 0 : const uno::Sequence< seq >* pRowArr = maSeq.getConstArray();
441 0 : for ( long nRow=0; nRow<nRowCount; nRow++ )
442 : {
443 0 : long nColCount = pRowArr[nRow].getLength();
444 0 : if ( nColCount > nMaxColCount )
445 0 : nMaxColCount = nColCount;
446 0 : const seq* pColArr = pRowArr[nRow].getConstArray();
447 0 : for (long nCol=0; nCol<nColCount; nCol++)
448 0 : if ( nCol <= MAXCOL && mrDocRow <= MAXROW )
449 0 : aVisitor.visitElem( nCol, mrDocRow, pColArr[ nCol ] );
450 : else
451 0 : mbOverflow=true;
452 0 : mrDocRow++;
453 : }
454 0 : mbArgError = aVisitor.hasArgError();
455 0 : if ( nRowCount && nMaxColCount && !mbOverflow )
456 0 : lcl_AddRef( mrTokenArr, nStartRow, nMaxColCount, nRowCount );
457 0 : }
458 0 : bool getOverflow() const { return mbOverflow; }
459 0 : bool getArgError() const { return mbArgError; }
460 : };
461 :
462 : template <class T>
463 : class ArrayOfArrayProc
464 : {
465 : public:
466 0 : static void processSequences( ScDocument* pDoc, const uno::Any& rArg, ScTokenArray& rTokenArr,
467 : long& rDocRow, bool& rArgErr, bool& rOverflow )
468 : {
469 0 : SequencesContainer< T > aContainer( rArg, rTokenArr, rDocRow, pDoc );
470 0 : aContainer.process();
471 0 : rArgErr = aContainer.getArgError();
472 0 : rOverflow = aContainer.getOverflow();
473 0 : }
474 : };
475 :
476 0 : uno::Any SAL_CALL ScFunctionAccess::callFunction( const OUString& aName,
477 : const uno::Sequence<uno::Any>& aArguments )
478 : throw (container::NoSuchElementException, lang::IllegalArgumentException,
479 : uno::RuntimeException, std::exception)
480 : {
481 0 : SolarMutexGuard aGuard;
482 :
483 0 : if (!mbValid)
484 0 : throw uno::RuntimeException();
485 :
486 : // use cached document if not in use, temporary document otherwise
487 : // (deleted in ScTempDocSource dtor)
488 0 : ScTempDocSource aSource( aDocCache );
489 0 : ScDocument* pDoc = aSource.GetDocument();
490 : const static SCTAB nTempSheet = 1;
491 : // Create an extra tab to contain the Function Cell
492 : // this will allow full rows to be used.
493 0 : if ( !pDoc->HasTable( nTempSheet ) )
494 0 : pDoc->MakeTable( nTempSheet );
495 :
496 : /// TODO: check
497 0 : ScAddress aAdr;
498 0 : ScCompiler aCompiler(pDoc,aAdr);
499 0 : aCompiler.SetGrammar(pDoc->GetGrammar());
500 :
501 : // find function
502 :
503 0 : ScTokenArray aTokenArr;
504 0 : if ( !lcl_AddFunctionToken( aTokenArr, aName,aCompiler ) )
505 : {
506 : // function not found
507 0 : throw container::NoSuchElementException();
508 : }
509 :
510 : // set options (null date, etc.)
511 :
512 0 : if ( pOptions )
513 0 : pDoc->SetDocOptions( *pOptions );
514 :
515 : // add arguments to token array
516 :
517 0 : bool bArgErr = false;
518 0 : bool bOverflow = false;
519 0 : long nDocRow = 0;
520 0 : long nArgCount = aArguments.getLength();
521 0 : const uno::Any* pArgArr = aArguments.getConstArray();
522 :
523 0 : svl::SharedStringPool& rSPool = pDoc->GetSharedStringPool();
524 0 : aTokenArr.AddOpCode(ocOpen);
525 0 : for (long nPos=0; nPos<nArgCount; nPos++)
526 : {
527 0 : if ( nPos > 0 )
528 0 : aTokenArr.AddOpCode(ocSep);
529 :
530 0 : const uno::Any& rArg = pArgArr[nPos];
531 :
532 0 : uno::TypeClass eClass = rArg.getValueTypeClass();
533 0 : uno::Type aType = rArg.getValueType();
534 0 : if ( eClass == uno::TypeClass_BYTE ||
535 0 : eClass == uno::TypeClass_BOOLEAN ||
536 0 : eClass == uno::TypeClass_SHORT ||
537 0 : eClass == uno::TypeClass_UNSIGNED_SHORT ||
538 0 : eClass == uno::TypeClass_LONG ||
539 0 : eClass == uno::TypeClass_UNSIGNED_LONG ||
540 0 : eClass == uno::TypeClass_FLOAT ||
541 : eClass == uno::TypeClass_DOUBLE )
542 : {
543 : // accept integer types because Basic passes a floating point
544 : // variable as byte, short or long if it's an integer number.
545 0 : double fVal = 0;
546 0 : rArg >>= fVal;
547 0 : aTokenArr.AddDouble( fVal );
548 : }
549 0 : else if ( eClass == uno::TypeClass_STRING )
550 : {
551 0 : OUString aUStr;
552 0 : rArg >>= aUStr;
553 0 : aTokenArr.AddString(rSPool.intern(aUStr));
554 : }
555 0 : else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<sal_Int16> > *)0 ) ) )
556 : {
557 0 : ArrayOfArrayProc<sal_Int16>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
558 : }
559 0 : else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<sal_Int32> > *)0 ) ) )
560 : {
561 0 : ArrayOfArrayProc<sal_Int32>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
562 : }
563 0 : else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<double> > *)0 ) ) )
564 : {
565 0 : ArrayOfArrayProc<double>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
566 : }
567 0 : else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<OUString> > *)0 ) ) )
568 : {
569 0 : ArrayOfArrayProc<OUString>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
570 : }
571 0 : else if ( aType.equals( getCppuType( (uno::Sequence< uno::Sequence<uno::Any> > *)0 ) ) )
572 : {
573 0 : ArrayOfArrayProc<uno::Any>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
574 : }
575 0 : else if ( aType.equals( cppu::UnoType<table::XCellRange>::get()) )
576 : {
577 : // currently, only our own cell ranges are supported
578 :
579 0 : uno::Reference<table::XCellRange> xRange(rArg, uno::UNO_QUERY);
580 0 : ScCellRangesBase* pImpl = ScCellRangesBase::getImplementation( xRange );
581 0 : if ( pImpl )
582 : {
583 0 : ScDocument* pSrcDoc = pImpl->GetDocument();
584 0 : const ScRangeList& rRanges = pImpl->GetRangeList();
585 0 : if ( pSrcDoc && rRanges.size() == 1 )
586 : {
587 0 : ScRange aSrcRange = *rRanges[ 0 ];
588 :
589 0 : long nStartRow = nDocRow;
590 0 : long nColCount = aSrcRange.aEnd.Col() - aSrcRange.aStart.Col() + 1;
591 0 : long nRowCount = aSrcRange.aEnd.Row() - aSrcRange.aStart.Row() + 1;
592 :
593 0 : if ( nStartRow + nRowCount > MAXROWCOUNT )
594 0 : bOverflow = true;
595 : else
596 : {
597 : // copy data
598 0 : if ( !lcl_CopyData( pSrcDoc, aSrcRange, pDoc, ScAddress( 0, (SCROW)nDocRow, 0 ) ) )
599 0 : bOverflow = true;
600 : }
601 :
602 0 : nDocRow += nRowCount;
603 0 : if ( !bOverflow )
604 0 : lcl_AddRef( aTokenArr, nStartRow, nColCount, nRowCount );
605 : }
606 : else
607 0 : bArgErr = true;
608 : }
609 : else
610 0 : bArgErr = true;
611 : }
612 : else
613 0 : bArgErr = true; // invalid type
614 0 : }
615 0 : aTokenArr.AddOpCode(ocClose);
616 0 : aTokenArr.AddOpCode(ocStop);
617 :
618 : // execute formula
619 :
620 0 : uno::Any aRet;
621 0 : if ( !bArgErr && !bOverflow && nDocRow <= MAXROWCOUNT )
622 : {
623 0 : ScAddress aFormulaPos( 0, 0, nTempSheet );
624 : // GRAM_PODF_A1 doesn't really matter for the token array but fits with
625 : // other API compatibility grammars.
626 : ScFormulaCell* pFormula = new ScFormulaCell(
627 : pDoc, aFormulaPos, aTokenArr, formula::FormulaGrammar::GRAM_PODF_A1,
628 0 : (sal_uInt8)(mbArray ? MM_FORMULA : MM_NONE) );
629 0 : pFormula = pDoc->SetFormulaCell(aFormulaPos, pFormula);
630 :
631 : // call GetMatrix before GetErrCode because GetMatrix always recalculates
632 : // if there is no matrix result
633 :
634 0 : const ScMatrix* pMat = (mbArray && pFormula) ? pFormula->GetMatrix() : 0;
635 0 : sal_uInt16 nErrCode = pFormula ? pFormula->GetErrCode() : errIllegalArgument;
636 0 : if ( nErrCode == 0 )
637 : {
638 0 : if ( pMat )
639 : {
640 : // array result
641 0 : ScRangeToSequence::FillMixedArray( aRet, pMat );
642 : }
643 0 : else if ( pFormula->IsValue() )
644 : {
645 : // numeric value
646 0 : aRet <<= (double) pFormula->GetValue();
647 : }
648 : else
649 : {
650 : // string result
651 0 : OUString aStrVal = pFormula->GetString().getString();
652 0 : aRet <<= aStrVal;
653 : }
654 : }
655 0 : else if ( nErrCode == NOTAVAILABLE )
656 : {
657 : // #N/A: leave result empty, no exception
658 : }
659 : else
660 : {
661 : // any other error: IllegalArgumentException
662 0 : bArgErr = true;
663 : }
664 :
665 0 : pDoc->DeleteAreaTab( 0, 0, MAXCOL, MAXROW, 0, IDF_ALL );
666 0 : pDoc->DeleteAreaTab( 0, 0, 0, 0, nTempSheet, IDF_ALL );
667 : }
668 :
669 0 : if (bOverflow)
670 0 : throw uno::RuntimeException();
671 :
672 0 : if (bArgErr)
673 0 : throw lang::IllegalArgumentException();
674 :
675 0 : return aRet;
676 228 : }
677 :
678 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|