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