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