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