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 0 : static bool lcl_HasErrors( ScDocument* pDoc, const ScRange& rRange )
35 : {
36 : // no need to look at empty cells - just use ScCellIterator
37 0 : ScCellIterator aIter( pDoc, rRange );
38 0 : for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
39 : {
40 0 : if (aIter.getType() != CELLTYPE_FORMULA)
41 0 : continue;
42 :
43 0 : ScFormulaCell* pCell = aIter.getFormulaCell();
44 0 : if (pCell->GetErrCode() != 0)
45 0 : return true;
46 : }
47 0 : return false; // no error found
48 : }
49 :
50 0 : static long lcl_DoubleToLong( double fVal )
51 : {
52 : double fInt = (fVal >= 0.0) ? ::rtl::math::approxFloor( fVal ) :
53 0 : ::rtl::math::approxCeil( fVal );
54 0 : if ( fInt >= LONG_MIN && fInt <= LONG_MAX )
55 0 : return (long)fInt;
56 : else
57 0 : return 0; // out of range
58 : }
59 :
60 0 : bool ScRangeToSequence::FillLongArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange )
61 : {
62 0 : SCTAB nTab = rRange.aStart.Tab();
63 0 : SCCOL nStartCol = rRange.aStart.Col();
64 0 : SCROW nStartRow = rRange.aStart.Row();
65 0 : long nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
66 0 : long nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
67 :
68 0 : uno::Sequence< uno::Sequence<sal_Int32> > aRowSeq( nRowCount );
69 0 : uno::Sequence<sal_Int32>* pRowAry = aRowSeq.getArray();
70 0 : for (long nRow = 0; nRow < nRowCount; nRow++)
71 : {
72 0 : uno::Sequence<sal_Int32> aColSeq( nColCount );
73 0 : sal_Int32* pColAry = aColSeq.getArray();
74 0 : for (long nCol = 0; nCol < nColCount; nCol++)
75 0 : pColAry[nCol] = lcl_DoubleToLong( pDoc->GetValue(
76 0 : ScAddress( (SCCOL)(nStartCol+nCol), (SCROW)(nStartRow+nRow), nTab ) ) );
77 :
78 0 : pRowAry[nRow] = aColSeq;
79 0 : }
80 :
81 0 : rAny <<= aRowSeq;
82 0 : 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 0 : bool ScRangeToSequence::FillDoubleArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange )
114 : {
115 0 : SCTAB nTab = rRange.aStart.Tab();
116 0 : SCCOL nStartCol = rRange.aStart.Col();
117 0 : SCROW nStartRow = rRange.aStart.Row();
118 0 : long nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
119 0 : long nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
120 :
121 0 : uno::Sequence< uno::Sequence<double> > aRowSeq( nRowCount );
122 0 : uno::Sequence<double>* pRowAry = aRowSeq.getArray();
123 0 : for (long nRow = 0; nRow < nRowCount; nRow++)
124 : {
125 0 : uno::Sequence<double> aColSeq( nColCount );
126 0 : double* pColAry = aColSeq.getArray();
127 0 : for (long nCol = 0; nCol < nColCount; nCol++)
128 0 : pColAry[nCol] = pDoc->GetValue(
129 0 : ScAddress( (SCCOL)(nStartCol+nCol), (SCROW)(nStartRow+nRow), nTab ) );
130 :
131 0 : pRowAry[nRow] = aColSeq;
132 0 : }
133 :
134 0 : rAny <<= aRowSeq;
135 0 : return !lcl_HasErrors( pDoc, rRange );
136 : }
137 :
138 0 : bool ScRangeToSequence::FillDoubleArray( uno::Any& rAny, const ScMatrix* pMatrix )
139 : {
140 0 : if (!pMatrix)
141 0 : return false;
142 :
143 : SCSIZE nColCount;
144 : SCSIZE nRowCount;
145 0 : pMatrix->GetDimensions( nColCount, nRowCount );
146 :
147 0 : uno::Sequence< uno::Sequence<double> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
148 0 : uno::Sequence<double>* pRowAry = aRowSeq.getArray();
149 0 : for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
150 : {
151 0 : uno::Sequence<double> aColSeq( static_cast<sal_Int32>(nColCount) );
152 0 : double* pColAry = aColSeq.getArray();
153 0 : for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
154 0 : if ( pMatrix->IsString( nCol, nRow ) )
155 0 : pColAry[nCol] = 0.0;
156 : else
157 0 : pColAry[nCol] = pMatrix->GetDouble( nCol, nRow );
158 :
159 0 : pRowAry[nRow] = aColSeq;
160 0 : }
161 :
162 0 : rAny <<= aRowSeq;
163 0 : 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 0 : bool ScRangeToSequence::FillMixedArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange,
238 : bool bAllowNV )
239 : {
240 0 : SCTAB nTab = rRange.aStart.Tab();
241 0 : SCCOL nStartCol = rRange.aStart.Col();
242 0 : SCROW nStartRow = rRange.aStart.Row();
243 0 : long nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
244 0 : long nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
245 :
246 0 : bool bHasErrors = false;
247 :
248 0 : uno::Sequence< uno::Sequence<uno::Any> > aRowSeq( nRowCount );
249 0 : uno::Sequence<uno::Any>* pRowAry = aRowSeq.getArray();
250 0 : for (long nRow = 0; nRow < nRowCount; nRow++)
251 : {
252 0 : uno::Sequence<uno::Any> aColSeq( nColCount );
253 0 : uno::Any* pColAry = aColSeq.getArray();
254 0 : for (long nCol = 0; nCol < nColCount; nCol++)
255 : {
256 0 : uno::Any& rElement = pColAry[nCol];
257 :
258 0 : ScAddress aPos( (SCCOL)(nStartCol+nCol), (SCROW)(nStartRow+nRow), nTab );
259 0 : ScRefCellValue aCell;
260 0 : aCell.assign(*pDoc, aPos);
261 :
262 0 : if (aCell.isEmpty())
263 : {
264 0 : rElement <<= EMPTY_OUSTRING;
265 0 : continue;
266 : }
267 :
268 0 : 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 0 : else if (aCell.hasNumeric())
274 0 : rElement <<= aCell.getValue();
275 : else
276 0 : rElement <<= aCell.getString(pDoc);
277 0 : }
278 0 : pRowAry[nRow] = aColSeq;
279 0 : }
280 :
281 0 : rAny <<= aRowSeq;
282 0 : return bAllowNV || !bHasErrors;
283 : }
284 :
285 0 : bool ScRangeToSequence::FillMixedArray( uno::Any& rAny, const ScMatrix* pMatrix, bool bDataTypes )
286 : {
287 0 : if (!pMatrix)
288 0 : return false;
289 :
290 : SCSIZE nColCount;
291 : SCSIZE nRowCount;
292 0 : pMatrix->GetDimensions( nColCount, nRowCount );
293 :
294 0 : uno::Sequence< uno::Sequence<uno::Any> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
295 0 : uno::Sequence<uno::Any>* pRowAry = aRowSeq.getArray();
296 0 : for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
297 : {
298 0 : uno::Sequence<uno::Any> aColSeq( static_cast<sal_Int32>(nColCount) );
299 0 : uno::Any* pColAry = aColSeq.getArray();
300 0 : for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
301 : {
302 0 : 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 0 : double fVal = pMatrix->GetDouble( nCol, nRow );
312 0 : if (bDataTypes && pMatrix->IsBoolean( nCol, nRow ))
313 0 : pColAry[nCol] <<= (fVal ? true : false);
314 : else
315 0 : pColAry[nCol] <<= fVal;
316 : }
317 : }
318 :
319 0 : pRowAry[nRow] = aColSeq;
320 0 : }
321 :
322 0 : rAny <<= aRowSeq;
323 0 : return true;
324 : }
325 :
326 0 : bool ScApiTypeConversion::ConvertAnyToDouble( double & o_fVal,
327 : com::sun::star::uno::TypeClass & o_eClass,
328 : const com::sun::star::uno::Any & rAny )
329 : {
330 0 : bool bRet = false;
331 0 : o_eClass = rAny.getValueTypeClass();
332 0 : 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 0 : rAny >>= o_fVal;
346 0 : bRet = true;
347 0 : break;
348 : default:
349 : ; // nothing, avoid warning
350 : }
351 0 : if (!bRet)
352 0 : o_fVal = 0.0;
353 0 : return bRet;
354 : }
355 :
356 0 : ScMatrixRef ScSequenceToMatrix::CreateMixedMatrix( const com::sun::star::uno::Any & rAny )
357 : {
358 0 : ScMatrixRef xMatrix;
359 0 : uno::Sequence< uno::Sequence< uno::Any > > aSequence;
360 0 : if ( rAny >>= aSequence )
361 : {
362 0 : sal_Int32 nRowCount = aSequence.getLength();
363 0 : const uno::Sequence<uno::Any>* pRowArr = aSequence.getConstArray();
364 0 : sal_Int32 nMaxColCount = 0;
365 : sal_Int32 nCol, nRow;
366 0 : for (nRow=0; nRow<nRowCount; nRow++)
367 : {
368 0 : sal_Int32 nTmp = pRowArr[nRow].getLength();
369 0 : if ( nTmp > nMaxColCount )
370 0 : nMaxColCount = nTmp;
371 : }
372 0 : if ( nMaxColCount && nRowCount )
373 : {
374 0 : OUString aUStr;
375 0 : xMatrix = new ScMatrix(
376 : static_cast<SCSIZE>(nMaxColCount),
377 0 : static_cast<SCSIZE>(nRowCount), 0.0);
378 : SCSIZE nCols, nRows;
379 0 : xMatrix->GetDimensions( nCols, nRows);
380 0 : 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 0 : for (nRow=0; nRow<nRowCount; nRow++)
386 : {
387 0 : sal_Int32 nColCount = pRowArr[nRow].getLength();
388 0 : const uno::Any* pColArr = pRowArr[nRow].getConstArray();
389 0 : for (nCol=0; nCol<nColCount; nCol++)
390 : {
391 : double fVal;
392 : uno::TypeClass eClass;
393 0 : if (ScApiTypeConversion::ConvertAnyToDouble( fVal, eClass, pColArr[nCol]))
394 : {
395 0 : 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 0 : 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 0 : for (nCol=nColCount; nCol<nMaxColCount; nCol++)
420 : {
421 : xMatrix->PutEmpty(
422 : static_cast<SCSIZE>(nCol),
423 0 : static_cast<SCSIZE>(nRow) );
424 : }
425 0 : }
426 : }
427 : }
428 0 : return xMatrix;
429 : }
430 :
431 0 : bool ScByteSequenceToString::GetString( OUString& rString, const uno::Any& rAny,
432 : sal_uInt16 nEncoding )
433 : {
434 0 : uno::Sequence<sal_Int8> aSeq;
435 0 : if ( rAny >>= aSeq )
436 : {
437 0 : rString = OUString( (const sal_Char*)aSeq.getConstArray(),
438 0 : aSeq.getLength(), nEncoding );
439 0 : rString = comphelper::string::stripEnd(rString, 0);
440 0 : return true;
441 : }
442 0 : return false;
443 : }
444 :
445 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|