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