1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26
27
28
29 #include <svl/zforlist.hxx>
30 #include <rtl/math.hxx>
31 #include <tools/debug.hxx>
32
33 #include <com/sun/star/uno/Any.hxx>
34 #include <com/sun/star/uno/Sequence.hxx>
35
36 #include "rangeseq.hxx"
37 #include "document.hxx"
38 #include "dociter.hxx"
39 #include "scmatrix.hxx"
40 #include "cell.hxx"
41
42 using namespace com::sun::star;
43
44 //------------------------------------------------------------------------
45
lcl_HasErrors(ScDocument * pDoc,const ScRange & rRange)46 bool lcl_HasErrors( ScDocument* pDoc, const ScRange& rRange )
47 {
48 // no need to look at empty cells - just use ScCellIterator
49 ScCellIterator aIter( pDoc, rRange );
50 ScBaseCell* pCell = aIter.GetFirst();
51 while (pCell)
52 {
53 if ( pCell->GetCellType() == CELLTYPE_FORMULA && static_cast<ScFormulaCell*>(pCell)->GetErrCode() != 0 )
54 return true;
55 pCell = aIter.GetNext();
56 }
57 return false; // no error found
58 }
59
lcl_DoubleToLong(double fVal)60 long lcl_DoubleToLong( double fVal )
61 {
62 double fInt = (fVal >= 0.0) ? ::rtl::math::approxFloor( fVal ) :
63 ::rtl::math::approxCeil( fVal );
64 if ( fInt >= LONG_MIN && fInt <= LONG_MAX )
65 return (long)fInt;
66 else
67 return 0; // out of range
68 }
69
FillLongArray(uno::Any & rAny,ScDocument * pDoc,const ScRange & rRange)70 sal_Bool ScRangeToSequence::FillLongArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange )
71 {
72 SCTAB nTab = rRange.aStart.Tab();
73 SCCOL nStartCol = rRange.aStart.Col();
74 SCROW nStartRow = rRange.aStart.Row();
75 long nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
76 long nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
77
78 uno::Sequence< uno::Sequence<sal_Int32> > aRowSeq( nRowCount );
79 uno::Sequence<sal_Int32>* pRowAry = aRowSeq.getArray();
80 for (long nRow = 0; nRow < nRowCount; nRow++)
81 {
82 uno::Sequence<sal_Int32> aColSeq( nColCount );
83 sal_Int32* pColAry = aColSeq.getArray();
84 for (long nCol = 0; nCol < nColCount; nCol++)
85 pColAry[nCol] = lcl_DoubleToLong( pDoc->GetValue(
86 ScAddress( (SCCOL)(nStartCol+nCol), (SCROW)(nStartRow+nRow), nTab ) ) );
87
88 pRowAry[nRow] = aColSeq;
89 }
90
91 rAny <<= aRowSeq;
92 return !lcl_HasErrors( pDoc, rRange );
93 }
94
95
FillLongArray(uno::Any & rAny,const ScMatrix * pMatrix)96 sal_Bool ScRangeToSequence::FillLongArray( uno::Any& rAny, const ScMatrix* pMatrix )
97 {
98 if (!pMatrix)
99 return sal_False;
100
101 SCSIZE nColCount;
102 SCSIZE nRowCount;
103 pMatrix->GetDimensions( nColCount, nRowCount );
104
105 uno::Sequence< uno::Sequence<sal_Int32> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
106 uno::Sequence<sal_Int32>* pRowAry = aRowSeq.getArray();
107 for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
108 {
109 uno::Sequence<sal_Int32> aColSeq( static_cast<sal_Int32>(nColCount) );
110 sal_Int32* pColAry = aColSeq.getArray();
111 for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
112 if ( pMatrix->IsString( nCol, nRow ) )
113 pColAry[nCol] = 0;
114 else
115 pColAry[nCol] = lcl_DoubleToLong( pMatrix->GetDouble( nCol, nRow ) );
116
117 pRowAry[nRow] = aColSeq;
118 }
119
120 rAny <<= aRowSeq;
121 return sal_True;
122 }
123
124 //------------------------------------------------------------------------
125
FillDoubleArray(uno::Any & rAny,ScDocument * pDoc,const ScRange & rRange)126 sal_Bool ScRangeToSequence::FillDoubleArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange )
127 {
128 SCTAB nTab = rRange.aStart.Tab();
129 SCCOL nStartCol = rRange.aStart.Col();
130 SCROW nStartRow = rRange.aStart.Row();
131 long nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
132 long nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
133
134 uno::Sequence< uno::Sequence<double> > aRowSeq( nRowCount );
135 uno::Sequence<double>* pRowAry = aRowSeq.getArray();
136 for (long nRow = 0; nRow < nRowCount; nRow++)
137 {
138 uno::Sequence<double> aColSeq( nColCount );
139 double* pColAry = aColSeq.getArray();
140 for (long nCol = 0; nCol < nColCount; nCol++)
141 pColAry[nCol] = pDoc->GetValue(
142 ScAddress( (SCCOL)(nStartCol+nCol), (SCROW)(nStartRow+nRow), nTab ) );
143
144 pRowAry[nRow] = aColSeq;
145 }
146
147 rAny <<= aRowSeq;
148 return !lcl_HasErrors( pDoc, rRange );
149 }
150
151
FillDoubleArray(uno::Any & rAny,const ScMatrix * pMatrix)152 sal_Bool ScRangeToSequence::FillDoubleArray( uno::Any& rAny, const ScMatrix* pMatrix )
153 {
154 if (!pMatrix)
155 return sal_False;
156
157 SCSIZE nColCount;
158 SCSIZE nRowCount;
159 pMatrix->GetDimensions( nColCount, nRowCount );
160
161 uno::Sequence< uno::Sequence<double> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
162 uno::Sequence<double>* pRowAry = aRowSeq.getArray();
163 for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
164 {
165 uno::Sequence<double> aColSeq( static_cast<sal_Int32>(nColCount) );
166 double* pColAry = aColSeq.getArray();
167 for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
168 if ( pMatrix->IsString( nCol, nRow ) )
169 pColAry[nCol] = 0.0;
170 else
171 pColAry[nCol] = pMatrix->GetDouble( nCol, nRow );
172
173 pRowAry[nRow] = aColSeq;
174 }
175
176 rAny <<= aRowSeq;
177 return sal_True;
178 }
179
180 //------------------------------------------------------------------------
181
FillStringArray(uno::Any & rAny,ScDocument * pDoc,const ScRange & rRange)182 sal_Bool ScRangeToSequence::FillStringArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange )
183 {
184 SCTAB nTab = rRange.aStart.Tab();
185 SCCOL nStartCol = rRange.aStart.Col();
186 SCROW nStartRow = rRange.aStart.Row();
187 long nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
188 long nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
189
190 bool bHasErrors = false;
191
192 uno::Sequence< uno::Sequence<rtl::OUString> > aRowSeq( nRowCount );
193 uno::Sequence<rtl::OUString>* pRowAry = aRowSeq.getArray();
194 for (long nRow = 0; nRow < nRowCount; nRow++)
195 {
196 uno::Sequence<rtl::OUString> aColSeq( nColCount );
197 rtl::OUString* pColAry = aColSeq.getArray();
198 for (long nCol = 0; nCol < nColCount; nCol++)
199 {
200 sal_uInt16 nErrCode = pDoc->GetStringForFormula(
201 ScAddress((SCCOL)(nStartCol+nCol), (SCROW)(nStartRow+nRow), nTab),
202 pColAry[nCol] );
203 if ( nErrCode != 0 )
204 bHasErrors = true;
205 }
206 pRowAry[nRow] = aColSeq;
207 }
208
209 rAny <<= aRowSeq;
210 return !bHasErrors;
211 }
212
213
FillStringArray(uno::Any & rAny,const ScMatrix * pMatrix,SvNumberFormatter * pFormatter)214 sal_Bool ScRangeToSequence::FillStringArray( uno::Any& rAny, const ScMatrix* pMatrix,
215 SvNumberFormatter* pFormatter )
216 {
217 if (!pMatrix)
218 return sal_False;
219
220 SCSIZE nColCount;
221 SCSIZE nRowCount;
222 pMatrix->GetDimensions( nColCount, nRowCount );
223
224 uno::Sequence< uno::Sequence<rtl::OUString> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
225 uno::Sequence<rtl::OUString>* pRowAry = aRowSeq.getArray();
226 for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
227 {
228 uno::Sequence<rtl::OUString> aColSeq( static_cast<sal_Int32>(nColCount) );
229 rtl::OUString* pColAry = aColSeq.getArray();
230 for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
231 {
232 String aStr;
233 if ( pMatrix->IsString( nCol, nRow ) )
234 {
235 if ( !pMatrix->IsEmpty( nCol, nRow ) )
236 aStr = pMatrix->GetString( nCol, nRow );
237 }
238 else if ( pFormatter )
239 {
240 double fVal = pMatrix->GetDouble( nCol, nRow );
241 Color* pColor;
242 pFormatter->GetOutputString( fVal, 0, aStr, &pColor );
243 }
244 pColAry[nCol] = rtl::OUString( aStr );
245 }
246
247 pRowAry[nRow] = aColSeq;
248 }
249
250 rAny <<= aRowSeq;
251 return sal_True;
252 }
253
254 //------------------------------------------------------------------------
255
lcl_GetValueFromCell(ScBaseCell & rCell)256 double lcl_GetValueFromCell( ScBaseCell& rCell )
257 {
258 //! ScBaseCell member function?
259
260 CellType eType = rCell.GetCellType();
261 if ( eType == CELLTYPE_VALUE )
262 return ((ScValueCell&)rCell).GetValue();
263 else if ( eType == CELLTYPE_FORMULA )
264 return ((ScFormulaCell&)rCell).GetValue(); // called only if result is value
265
266 DBG_ERROR( "GetValueFromCell: wrong type" );
267 return 0;
268 }
269
FillMixedArray(uno::Any & rAny,ScDocument * pDoc,const ScRange & rRange,sal_Bool bAllowNV)270 sal_Bool ScRangeToSequence::FillMixedArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange,
271 sal_Bool bAllowNV )
272 {
273 SCTAB nTab = rRange.aStart.Tab();
274 SCCOL nStartCol = rRange.aStart.Col();
275 SCROW nStartRow = rRange.aStart.Row();
276 long nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
277 long nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
278
279 String aDocStr;
280 sal_Bool bHasErrors = sal_False;
281
282 uno::Sequence< uno::Sequence<uno::Any> > aRowSeq( nRowCount );
283 uno::Sequence<uno::Any>* pRowAry = aRowSeq.getArray();
284 for (long nRow = 0; nRow < nRowCount; nRow++)
285 {
286 uno::Sequence<uno::Any> aColSeq( nColCount );
287 uno::Any* pColAry = aColSeq.getArray();
288 for (long nCol = 0; nCol < nColCount; nCol++)
289 {
290 uno::Any& rElement = pColAry[nCol];
291
292 ScAddress aPos( (SCCOL)(nStartCol+nCol), (SCROW)(nStartRow+nRow), nTab );
293 ScBaseCell* pCell = pDoc->GetCell( aPos );
294 if ( pCell )
295 {
296 if ( pCell->GetCellType() == CELLTYPE_FORMULA &&
297 ((ScFormulaCell*)pCell)->GetErrCode() != 0 )
298 {
299 // if NV is allowed, leave empty for errors
300 bHasErrors = sal_True;
301 }
302 else if ( pCell->HasValueData() )
303 rElement <<= (double) lcl_GetValueFromCell( *pCell );
304 else
305 rElement <<= rtl::OUString( pCell->GetStringData() );
306 }
307 else
308 rElement <<= rtl::OUString(); // empty: empty string
309 }
310 pRowAry[nRow] = aColSeq;
311 }
312
313 rAny <<= aRowSeq;
314 return bAllowNV || !bHasErrors;
315 }
316
317
FillMixedArray(uno::Any & rAny,const ScMatrix * pMatrix,bool bDataTypes)318 sal_Bool ScRangeToSequence::FillMixedArray( uno::Any& rAny, const ScMatrix* pMatrix, bool bDataTypes )
319 {
320 if (!pMatrix)
321 return sal_False;
322
323 SCSIZE nColCount;
324 SCSIZE nRowCount;
325 pMatrix->GetDimensions( nColCount, nRowCount );
326
327 uno::Sequence< uno::Sequence<uno::Any> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
328 uno::Sequence<uno::Any>* pRowAry = aRowSeq.getArray();
329 for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
330 {
331 uno::Sequence<uno::Any> aColSeq( static_cast<sal_Int32>(nColCount) );
332 uno::Any* pColAry = aColSeq.getArray();
333 for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
334 {
335 if ( pMatrix->IsString( nCol, nRow ) )
336 {
337 String aStr;
338 if ( !pMatrix->IsEmpty( nCol, nRow ) )
339 aStr = pMatrix->GetString( nCol, nRow );
340 pColAry[nCol] <<= rtl::OUString( aStr );
341 }
342 else
343 {
344 double fVal = pMatrix->GetDouble( nCol, nRow );
345 if (bDataTypes && pMatrix->IsBoolean( nCol, nRow ))
346 pColAry[nCol] <<= (fVal ? true : false);
347 else
348 pColAry[nCol] <<= fVal;
349 }
350 }
351
352 pRowAry[nRow] = aColSeq;
353 }
354
355 rAny <<= aRowSeq;
356 return sal_True;
357 }
358
359 //------------------------------------------------------------------------
360
361 // static
ConvertAnyToDouble(double & o_fVal,com::sun::star::uno::TypeClass & o_eClass,const com::sun::star::uno::Any & rAny)362 bool ScApiTypeConversion::ConvertAnyToDouble( double & o_fVal,
363 com::sun::star::uno::TypeClass & o_eClass,
364 const com::sun::star::uno::Any & rAny )
365 {
366 bool bRet = false;
367 o_eClass = rAny.getValueTypeClass();
368 switch (o_eClass)
369 {
370 //! extract integer values
371 case uno::TypeClass_ENUM:
372 case uno::TypeClass_BOOLEAN:
373 case uno::TypeClass_CHAR:
374 case uno::TypeClass_BYTE:
375 case uno::TypeClass_SHORT:
376 case uno::TypeClass_UNSIGNED_SHORT:
377 case uno::TypeClass_LONG:
378 case uno::TypeClass_UNSIGNED_LONG:
379 case uno::TypeClass_FLOAT:
380 case uno::TypeClass_DOUBLE:
381 rAny >>= o_fVal;
382 bRet = true;
383 break;
384 default:
385 ; // nothing, avoid warning
386 }
387 if (!bRet)
388 o_fVal = 0.0;
389 return bRet;
390 }
391
392 //------------------------------------------------------------------------
393
394 // static
CreateMixedMatrix(const com::sun::star::uno::Any & rAny)395 ScMatrixRef ScSequenceToMatrix::CreateMixedMatrix( const com::sun::star::uno::Any & rAny )
396 {
397 ScMatrixRef xMatrix;
398 uno::Sequence< uno::Sequence< uno::Any > > aSequence;
399 if ( rAny >>= aSequence )
400 {
401 sal_Int32 nRowCount = aSequence.getLength();
402 const uno::Sequence<uno::Any>* pRowArr = aSequence.getConstArray();
403 sal_Int32 nMaxColCount = 0;
404 sal_Int32 nCol, nRow;
405 for (nRow=0; nRow<nRowCount; nRow++)
406 {
407 sal_Int32 nTmp = pRowArr[nRow].getLength();
408 if ( nTmp > nMaxColCount )
409 nMaxColCount = nTmp;
410 }
411 if ( nMaxColCount && nRowCount )
412 {
413 rtl::OUString aUStr;
414 xMatrix = new ScMatrix(
415 static_cast<SCSIZE>(nMaxColCount),
416 static_cast<SCSIZE>(nRowCount) );
417 ScMatrix* pMatrix = xMatrix;
418 SCSIZE nCols, nRows;
419 pMatrix->GetDimensions( nCols, nRows);
420 if (nCols != static_cast<SCSIZE>(nMaxColCount) || nRows != static_cast<SCSIZE>(nRowCount))
421 {
422 DBG_ERRORFILE( "ScSequenceToMatrix::CreateMixedMatrix: matrix exceeded max size, returning NULL matrix");
423 return NULL;
424 }
425 for (nRow=0; nRow<nRowCount; nRow++)
426 {
427 sal_Int32 nColCount = pRowArr[nRow].getLength();
428 const uno::Any* pColArr = pRowArr[nRow].getConstArray();
429 for (nCol=0; nCol<nColCount; nCol++)
430 {
431 double fVal;
432 uno::TypeClass eClass;
433 if (ScApiTypeConversion::ConvertAnyToDouble( fVal, eClass, pColArr[nCol]))
434 {
435 if (eClass == uno::TypeClass_BOOLEAN)
436 pMatrix->PutBoolean( (fVal ? true : false),
437 static_cast<SCSIZE>(nCol),
438 static_cast<SCSIZE>(nRow) );
439 else
440 pMatrix->PutDouble( fVal,
441 static_cast<SCSIZE>(nCol),
442 static_cast<SCSIZE>(nRow) );
443 }
444 else
445 {
446 // Try string, else use empty as last resort.
447
448 //Reflection* pRefl = pColArr[nCol].getReflection();
449 //if ( pRefl->equals( *OUString_getReflection() ) )
450 if ( pColArr[nCol] >>= aUStr )
451 pMatrix->PutString( String( aUStr ),
452 static_cast<SCSIZE>(nCol),
453 static_cast<SCSIZE>(nRow) );
454 else
455 pMatrix->PutEmpty(
456 static_cast<SCSIZE>(nCol),
457 static_cast<SCSIZE>(nRow) );
458 }
459 }
460 for (nCol=nColCount; nCol<nMaxColCount; nCol++)
461 {
462 pMatrix->PutEmpty(
463 static_cast<SCSIZE>(nCol),
464 static_cast<SCSIZE>(nRow) );
465 }
466 }
467 }
468 }
469 return xMatrix;
470 }
471
472
473 //------------------------------------------------------------------------
474
GetString(String & rString,const uno::Any & rAny,sal_uInt16 nEncoding)475 sal_Bool ScByteSequenceToString::GetString( String& rString, const uno::Any& rAny,
476 sal_uInt16 nEncoding )
477 {
478 uno::Sequence<sal_Int8> aSeq;
479 if ( rAny >>= aSeq )
480 {
481 rString = String( (const sal_Char*)aSeq.getConstArray(),
482 (xub_StrLen)aSeq.getLength(), nEncoding );
483 rString.EraseTrailingChars( (sal_Unicode) 0 );
484 return sal_True;
485 }
486 return sal_False;
487 }
488
489 //------------------------------------------------------------------------
490
491