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 <svl/zforlist.hxx>
21 : #include <rtl/math.hxx>
22 :
23 : #include <com/sun/star/uno/Any.hxx>
24 : #include <com/sun/star/uno/Sequence.hxx>
25 : #include <comphelper/string.hxx>
26 : #include "rangeseq.hxx"
27 : #include "document.hxx"
28 : #include "dociter.hxx"
29 : #include "scmatrix.hxx"
30 : #include "formulacell.hxx"
31 :
32 : using namespace com::sun::star;
33 :
34 8 : static bool lcl_HasErrors( ScDocument* pDoc, const ScRange& rRange )
35 : {
36 : // no need to look at empty cells - just use ScCellIterator
37 8 : ScCellIterator aIter( pDoc, rRange );
38 48 : for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
39 : {
40 40 : if (aIter.getType() != CELLTYPE_FORMULA)
41 40 : continue;
42 :
43 0 : ScFormulaCell* pCell = aIter.getFormulaCell();
44 0 : if (pCell->GetErrCode() != 0)
45 0 : return true;
46 : }
47 8 : return false; // no error found
48 : }
49 :
50 20 : static long lcl_DoubleToLong( double fVal )
51 : {
52 : double fInt = (fVal >= 0.0) ? ::rtl::math::approxFloor( fVal ) :
53 20 : ::rtl::math::approxCeil( fVal );
54 20 : if ( fInt >= LONG_MIN && fInt <= LONG_MAX )
55 20 : return (long)fInt;
56 : else
57 0 : return 0; // out of range
58 : }
59 :
60 4 : bool ScRangeToSequence::FillLongArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange )
61 : {
62 4 : SCTAB nTab = rRange.aStart.Tab();
63 4 : SCCOL nStartCol = rRange.aStart.Col();
64 4 : SCROW nStartRow = rRange.aStart.Row();
65 4 : long nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
66 4 : long nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
67 :
68 4 : uno::Sequence< uno::Sequence<sal_Int32> > aRowSeq( nRowCount );
69 4 : uno::Sequence<sal_Int32>* pRowAry = aRowSeq.getArray();
70 24 : for (long nRow = 0; nRow < nRowCount; nRow++)
71 : {
72 20 : uno::Sequence<sal_Int32> aColSeq( nColCount );
73 20 : sal_Int32* pColAry = aColSeq.getArray();
74 40 : for (long nCol = 0; nCol < nColCount; nCol++)
75 20 : pColAry[nCol] = lcl_DoubleToLong( pDoc->GetValue(
76 20 : ScAddress( (SCCOL)(nStartCol+nCol), (SCROW)(nStartRow+nRow), nTab ) ) );
77 :
78 20 : pRowAry[nRow] = aColSeq;
79 20 : }
80 :
81 4 : rAny <<= aRowSeq;
82 4 : return !lcl_HasErrors( pDoc, rRange );
83 : }
84 :
85 0 : bool ScRangeToSequence::FillLongArray( uno::Any& rAny, const ScMatrix* pMatrix )
86 : {
87 0 : if (!pMatrix)
88 0 : return false;
89 :
90 : SCSIZE nColCount;
91 : SCSIZE nRowCount;
92 0 : pMatrix->GetDimensions( nColCount, nRowCount );
93 :
94 0 : uno::Sequence< uno::Sequence<sal_Int32> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
95 0 : uno::Sequence<sal_Int32>* pRowAry = aRowSeq.getArray();
96 0 : for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
97 : {
98 0 : uno::Sequence<sal_Int32> aColSeq( static_cast<sal_Int32>(nColCount) );
99 0 : sal_Int32* pColAry = aColSeq.getArray();
100 0 : for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
101 0 : if ( pMatrix->IsString( nCol, nRow ) )
102 0 : pColAry[nCol] = 0;
103 : else
104 0 : pColAry[nCol] = lcl_DoubleToLong( pMatrix->GetDouble( nCol, nRow ) );
105 :
106 0 : pRowAry[nRow] = aColSeq;
107 0 : }
108 :
109 0 : rAny <<= aRowSeq;
110 0 : return true;
111 : }
112 :
113 4 : bool ScRangeToSequence::FillDoubleArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange )
114 : {
115 4 : SCTAB nTab = rRange.aStart.Tab();
116 4 : SCCOL nStartCol = rRange.aStart.Col();
117 4 : SCROW nStartRow = rRange.aStart.Row();
118 4 : long nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
119 4 : long nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
120 :
121 4 : uno::Sequence< uno::Sequence<double> > aRowSeq( nRowCount );
122 4 : uno::Sequence<double>* pRowAry = aRowSeq.getArray();
123 24 : for (long nRow = 0; nRow < nRowCount; nRow++)
124 : {
125 20 : uno::Sequence<double> aColSeq( nColCount );
126 20 : double* pColAry = aColSeq.getArray();
127 40 : for (long nCol = 0; nCol < nColCount; nCol++)
128 20 : pColAry[nCol] = pDoc->GetValue(
129 20 : ScAddress( (SCCOL)(nStartCol+nCol), (SCROW)(nStartRow+nRow), nTab ) );
130 :
131 20 : pRowAry[nRow] = aColSeq;
132 20 : }
133 :
134 4 : rAny <<= aRowSeq;
135 4 : return !lcl_HasErrors( pDoc, rRange );
136 : }
137 :
138 2 : bool ScRangeToSequence::FillDoubleArray( uno::Any& rAny, const ScMatrix* pMatrix )
139 : {
140 2 : if (!pMatrix)
141 0 : return false;
142 :
143 : SCSIZE nColCount;
144 : SCSIZE nRowCount;
145 2 : pMatrix->GetDimensions( nColCount, nRowCount );
146 :
147 2 : uno::Sequence< uno::Sequence<double> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
148 2 : uno::Sequence<double>* pRowAry = aRowSeq.getArray();
149 4 : for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
150 : {
151 2 : uno::Sequence<double> aColSeq( static_cast<sal_Int32>(nColCount) );
152 2 : double* pColAry = aColSeq.getArray();
153 8 : for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
154 6 : if ( pMatrix->IsString( nCol, nRow ) )
155 0 : pColAry[nCol] = 0.0;
156 : else
157 6 : pColAry[nCol] = pMatrix->GetDouble( nCol, nRow );
158 :
159 2 : pRowAry[nRow] = aColSeq;
160 2 : }
161 :
162 2 : rAny <<= aRowSeq;
163 2 : return true;
164 : }
165 :
166 0 : bool ScRangeToSequence::FillStringArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange )
167 : {
168 0 : SCTAB nTab = rRange.aStart.Tab();
169 0 : SCCOL nStartCol = rRange.aStart.Col();
170 0 : SCROW nStartRow = rRange.aStart.Row();
171 0 : long nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
172 0 : long nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
173 :
174 0 : bool bHasErrors = false;
175 :
176 0 : uno::Sequence< uno::Sequence<OUString> > aRowSeq( nRowCount );
177 0 : uno::Sequence<OUString>* pRowAry = aRowSeq.getArray();
178 0 : for (long nRow = 0; nRow < nRowCount; nRow++)
179 : {
180 0 : uno::Sequence<OUString> aColSeq( nColCount );
181 0 : OUString* pColAry = aColSeq.getArray();
182 0 : for (long nCol = 0; nCol < nColCount; nCol++)
183 : {
184 : sal_uInt16 nErrCode = pDoc->GetStringForFormula(
185 : ScAddress((SCCOL)(nStartCol+nCol), (SCROW)(nStartRow+nRow), nTab),
186 0 : pColAry[nCol] );
187 0 : if ( nErrCode != 0 )
188 0 : bHasErrors = true;
189 : }
190 0 : pRowAry[nRow] = aColSeq;
191 0 : }
192 :
193 0 : rAny <<= aRowSeq;
194 0 : return !bHasErrors;
195 : }
196 :
197 0 : bool ScRangeToSequence::FillStringArray( uno::Any& rAny, const ScMatrix* pMatrix,
198 : SvNumberFormatter* pFormatter )
199 : {
200 0 : if (!pMatrix)
201 0 : return false;
202 :
203 : SCSIZE nColCount;
204 : SCSIZE nRowCount;
205 0 : pMatrix->GetDimensions( nColCount, nRowCount );
206 :
207 0 : uno::Sequence< uno::Sequence<OUString> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
208 0 : uno::Sequence<OUString>* pRowAry = aRowSeq.getArray();
209 0 : for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
210 : {
211 0 : uno::Sequence<OUString> aColSeq( static_cast<sal_Int32>(nColCount) );
212 0 : OUString* pColAry = aColSeq.getArray();
213 0 : for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
214 : {
215 0 : OUString aStr;
216 0 : if ( pMatrix->IsString( nCol, nRow ) )
217 : {
218 0 : if ( !pMatrix->IsEmpty( nCol, nRow ) )
219 0 : aStr = pMatrix->GetString(nCol, nRow).getString();
220 : }
221 0 : else if ( pFormatter )
222 : {
223 0 : double fVal = pMatrix->GetDouble( nCol, nRow );
224 : Color* pColor;
225 0 : pFormatter->GetOutputString( fVal, 0, aStr, &pColor );
226 : }
227 0 : pColAry[nCol] = aStr;
228 0 : }
229 :
230 0 : pRowAry[nRow] = aColSeq;
231 0 : }
232 :
233 0 : rAny <<= aRowSeq;
234 0 : return true;
235 : }
236 :
237 38 : bool ScRangeToSequence::FillMixedArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange,
238 : bool bAllowNV )
239 : {
240 38 : SCTAB nTab = rRange.aStart.Tab();
241 38 : SCCOL nStartCol = rRange.aStart.Col();
242 38 : SCROW nStartRow = rRange.aStart.Row();
243 38 : long nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
244 38 : long nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
245 :
246 38 : bool bHasErrors = false;
247 :
248 38 : uno::Sequence< uno::Sequence<uno::Any> > aRowSeq( nRowCount );
249 38 : uno::Sequence<uno::Any>* pRowAry = aRowSeq.getArray();
250 134 : for (long nRow = 0; nRow < nRowCount; nRow++)
251 : {
252 96 : uno::Sequence<uno::Any> aColSeq( nColCount );
253 96 : uno::Any* pColAry = aColSeq.getArray();
254 504 : for (long nCol = 0; nCol < nColCount; nCol++)
255 : {
256 408 : uno::Any& rElement = pColAry[nCol];
257 :
258 408 : ScAddress aPos( (SCCOL)(nStartCol+nCol), (SCROW)(nStartRow+nRow), nTab );
259 408 : ScRefCellValue aCell;
260 408 : aCell.assign(*pDoc, aPos);
261 :
262 408 : if (aCell.isEmpty())
263 : {
264 0 : rElement <<= EMPTY_OUSTRING;
265 0 : continue;
266 : }
267 :
268 408 : if (aCell.meType == CELLTYPE_FORMULA && aCell.mpFormula->GetErrCode() != 0)
269 : {
270 : // if NV is allowed, leave empty for errors
271 0 : bHasErrors = true;
272 : }
273 408 : else if (aCell.hasNumeric())
274 248 : rElement <<= aCell.getValue();
275 : else
276 160 : rElement <<= aCell.getString(pDoc);
277 408 : }
278 96 : pRowAry[nRow] = aColSeq;
279 96 : }
280 :
281 38 : rAny <<= aRowSeq;
282 38 : return bAllowNV || !bHasErrors;
283 : }
284 :
285 4 : bool ScRangeToSequence::FillMixedArray( uno::Any& rAny, const ScMatrix* pMatrix, bool bDataTypes )
286 : {
287 4 : if (!pMatrix)
288 0 : return false;
289 :
290 : SCSIZE nColCount;
291 : SCSIZE nRowCount;
292 4 : pMatrix->GetDimensions( nColCount, nRowCount );
293 :
294 4 : uno::Sequence< uno::Sequence<uno::Any> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
295 4 : uno::Sequence<uno::Any>* pRowAry = aRowSeq.getArray();
296 12 : for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
297 : {
298 8 : uno::Sequence<uno::Any> aColSeq( static_cast<sal_Int32>(nColCount) );
299 8 : uno::Any* pColAry = aColSeq.getArray();
300 32 : for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
301 : {
302 24 : if ( pMatrix->IsString( nCol, nRow ) )
303 : {
304 0 : OUString aStr;
305 0 : if ( !pMatrix->IsEmpty( nCol, nRow ) )
306 0 : aStr = pMatrix->GetString(nCol, nRow).getString();
307 0 : pColAry[nCol] <<= aStr;
308 : }
309 : else
310 : {
311 24 : double fVal = pMatrix->GetDouble( nCol, nRow );
312 24 : if (bDataTypes && pMatrix->IsBoolean( nCol, nRow ))
313 0 : pColAry[nCol] <<= (fVal ? true : false);
314 : else
315 24 : pColAry[nCol] <<= fVal;
316 : }
317 : }
318 :
319 8 : pRowAry[nRow] = aColSeq;
320 8 : }
321 :
322 4 : rAny <<= aRowSeq;
323 4 : return true;
324 : }
325 :
326 124 : bool ScApiTypeConversion::ConvertAnyToDouble( double & o_fVal,
327 : com::sun::star::uno::TypeClass & o_eClass,
328 : const com::sun::star::uno::Any & rAny )
329 : {
330 124 : bool bRet = false;
331 124 : o_eClass = rAny.getValueTypeClass();
332 124 : switch (o_eClass)
333 : {
334 : //! extract integer values
335 : case uno::TypeClass_ENUM:
336 : case uno::TypeClass_BOOLEAN:
337 : case uno::TypeClass_CHAR:
338 : case uno::TypeClass_BYTE:
339 : case uno::TypeClass_SHORT:
340 : case uno::TypeClass_UNSIGNED_SHORT:
341 : case uno::TypeClass_LONG:
342 : case uno::TypeClass_UNSIGNED_LONG:
343 : case uno::TypeClass_FLOAT:
344 : case uno::TypeClass_DOUBLE:
345 124 : rAny >>= o_fVal;
346 124 : bRet = true;
347 124 : break;
348 : default:
349 : ; // nothing, avoid warning
350 : }
351 124 : if (!bRet)
352 0 : o_fVal = 0.0;
353 124 : return bRet;
354 : }
355 :
356 2 : ScMatrixRef ScSequenceToMatrix::CreateMixedMatrix( const com::sun::star::uno::Any & rAny )
357 : {
358 2 : ScMatrixRef xMatrix;
359 4 : uno::Sequence< uno::Sequence< uno::Any > > aSequence;
360 2 : if ( rAny >>= aSequence )
361 : {
362 2 : sal_Int32 nRowCount = aSequence.getLength();
363 2 : const uno::Sequence<uno::Any>* pRowArr = aSequence.getConstArray();
364 2 : sal_Int32 nMaxColCount = 0;
365 : sal_Int32 nCol, nRow;
366 6 : for (nRow=0; nRow<nRowCount; nRow++)
367 : {
368 4 : sal_Int32 nTmp = pRowArr[nRow].getLength();
369 4 : if ( nTmp > nMaxColCount )
370 2 : nMaxColCount = nTmp;
371 : }
372 2 : if ( nMaxColCount && nRowCount )
373 : {
374 2 : OUString aUStr;
375 2 : xMatrix = new ScMatrix(
376 : static_cast<SCSIZE>(nMaxColCount),
377 2 : static_cast<SCSIZE>(nRowCount), 0.0);
378 : SCSIZE nCols, nRows;
379 2 : xMatrix->GetDimensions( nCols, nRows);
380 2 : if (nCols != static_cast<SCSIZE>(nMaxColCount) || nRows != static_cast<SCSIZE>(nRowCount))
381 : {
382 : OSL_FAIL( "ScSequenceToMatrix::CreateMixedMatrix: matrix exceeded max size, returning NULL matrix");
383 0 : return NULL;
384 : }
385 6 : for (nRow=0; nRow<nRowCount; nRow++)
386 : {
387 4 : sal_Int32 nColCount = pRowArr[nRow].getLength();
388 4 : const uno::Any* pColArr = pRowArr[nRow].getConstArray();
389 16 : for (nCol=0; nCol<nColCount; nCol++)
390 : {
391 : double fVal;
392 : uno::TypeClass eClass;
393 12 : if (ScApiTypeConversion::ConvertAnyToDouble( fVal, eClass, pColArr[nCol]))
394 : {
395 12 : if (eClass == uno::TypeClass_BOOLEAN)
396 : xMatrix->PutBoolean( (fVal ? true : false),
397 : static_cast<SCSIZE>(nCol),
398 0 : static_cast<SCSIZE>(nRow) );
399 : else
400 : xMatrix->PutDouble( fVal,
401 : static_cast<SCSIZE>(nCol),
402 12 : static_cast<SCSIZE>(nRow) );
403 : }
404 : else
405 : {
406 : // Try string, else use empty as last resort.
407 :
408 0 : if ( pColArr[nCol] >>= aUStr )
409 : {
410 : xMatrix->PutString(
411 0 : svl::SharedString(aUStr), static_cast<SCSIZE>(nCol), static_cast<SCSIZE>(nRow));
412 : }
413 : else
414 : xMatrix->PutEmpty(
415 : static_cast<SCSIZE>(nCol),
416 0 : static_cast<SCSIZE>(nRow) );
417 : }
418 : }
419 4 : for (nCol=nColCount; nCol<nMaxColCount; nCol++)
420 : {
421 : xMatrix->PutEmpty(
422 : static_cast<SCSIZE>(nCol),
423 0 : static_cast<SCSIZE>(nRow) );
424 : }
425 2 : }
426 : }
427 : }
428 4 : return xMatrix;
429 : }
430 :
431 10 : bool ScByteSequenceToString::GetString( OUString& rString, const uno::Any& rAny,
432 : sal_uInt16 nEncoding )
433 : {
434 10 : uno::Sequence<sal_Int8> aSeq;
435 10 : if ( rAny >>= aSeq )
436 : {
437 20 : rString = OUString( (const sal_Char*)aSeq.getConstArray(),
438 10 : aSeq.getLength(), nEncoding );
439 10 : rString = comphelper::string::stripEnd(rString, 0);
440 10 : return true;
441 : }
442 0 : return false;
443 228 : }
444 :
445 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|