Update git submodules
[LibreOffice.git] / sc / source / core / tool / rangeseq.cxx
blob63731b3236c96023ceafc0335a4195433ec288be
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <svl/numformat.hxx>
21 #include <rtl/math.hxx>
22 #include <o3tl/float_int_conversion.hxx>
23 #include <osl/diagnose.h>
24 #include <osl/thread.h>
26 #include <com/sun/star/uno/Any.hxx>
27 #include <com/sun/star/uno/Sequence.hxx>
28 #include <comphelper/string.hxx>
29 #include <rangeseq.hxx>
30 #include <document.hxx>
31 #include <dociter.hxx>
32 #include <scmatrix.hxx>
33 #include <formulacell.hxx>
35 using namespace com::sun::star;
37 static bool lcl_HasErrors( ScDocument& rDoc, const ScRange& rRange )
39 // no need to look at empty cells - just use ScCellIterator
40 ScCellIterator aIter( rDoc, rRange );
41 for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
43 if (aIter.getType() != CELLTYPE_FORMULA)
44 continue;
46 ScFormulaCell* pCell = aIter.getFormulaCell();
47 if (pCell->GetErrCode() != FormulaError::NONE)
48 return true;
50 return false; // no error found
53 static tools::Long lcl_DoubleToLong( double fVal )
55 double fInt = (fVal >= 0.0) ? ::rtl::math::approxFloor( fVal ) :
56 ::rtl::math::approxCeil( fVal );
57 if ( o3tl::convertsToAtLeast(fInt, LONG_MIN) && o3tl::convertsToAtMost(fInt, LONG_MAX) )
58 return static_cast<tools::Long>(fInt);
59 else
60 return 0; // out of range
63 bool ScRangeToSequence::FillLongArray( uno::Any& rAny, ScDocument& rDoc, const ScRange& rRange )
65 SCTAB nTab = rRange.aStart.Tab();
66 SCCOL nStartCol = rRange.aStart.Col();
67 SCROW nStartRow = rRange.aStart.Row();
68 sal_Int32 nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
69 sal_Int32 nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
71 uno::Sequence< uno::Sequence<sal_Int32> > aRowSeq( nRowCount );
72 uno::Sequence<sal_Int32>* pRowAry = aRowSeq.getArray();
73 for (sal_Int32 nRow = 0; nRow < nRowCount; nRow++)
75 uno::Sequence<sal_Int32> aColSeq( nColCount );
76 sal_Int32* pColAry = aColSeq.getArray();
77 for (sal_Int32 nCol = 0; nCol < nColCount; nCol++)
78 pColAry[nCol] = lcl_DoubleToLong( rDoc.GetValue(
79 ScAddress( static_cast<SCCOL>(nStartCol+nCol), static_cast<SCROW>(nStartRow+nRow), nTab ) ) );
81 pRowAry[nRow] = std::move(aColSeq);
84 rAny <<= aRowSeq;
85 return !lcl_HasErrors( rDoc, rRange );
88 bool ScRangeToSequence::FillLongArray( uno::Any& rAny, const ScMatrix* pMatrix )
90 if (!pMatrix)
91 return false;
93 SCSIZE nColCount;
94 SCSIZE nRowCount;
95 pMatrix->GetDimensions( nColCount, nRowCount );
97 uno::Sequence< uno::Sequence<sal_Int32> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
98 uno::Sequence<sal_Int32>* pRowAry = aRowSeq.getArray();
99 for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
101 uno::Sequence<sal_Int32> aColSeq( static_cast<sal_Int32>(nColCount) );
102 sal_Int32* pColAry = aColSeq.getArray();
103 for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
104 if ( pMatrix->IsStringOrEmpty( nCol, nRow ) )
105 pColAry[nCol] = 0;
106 else
107 pColAry[nCol] = lcl_DoubleToLong( pMatrix->GetDouble( nCol, nRow ) );
109 pRowAry[nRow] = std::move(aColSeq);
112 rAny <<= aRowSeq;
113 return true;
116 bool ScRangeToSequence::FillDoubleArray( uno::Any& rAny, ScDocument& rDoc, const ScRange& rRange )
118 SCTAB nTab = rRange.aStart.Tab();
119 SCCOL nStartCol = rRange.aStart.Col();
120 SCROW nStartRow = rRange.aStart.Row();
121 sal_Int32 nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
122 sal_Int32 nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
124 uno::Sequence< uno::Sequence<double> > aRowSeq( nRowCount );
125 uno::Sequence<double>* pRowAry = aRowSeq.getArray();
126 for (sal_Int32 nRow = 0; nRow < nRowCount; nRow++)
128 uno::Sequence<double> aColSeq( nColCount );
129 double* pColAry = aColSeq.getArray();
130 for (sal_Int32 nCol = 0; nCol < nColCount; nCol++)
131 pColAry[nCol] = rDoc.GetValue(
132 ScAddress( static_cast<SCCOL>(nStartCol+nCol), static_cast<SCROW>(nStartRow+nRow), nTab ) );
134 pRowAry[nRow] = std::move(aColSeq);
137 rAny <<= aRowSeq;
138 return !lcl_HasErrors( rDoc, rRange );
141 bool ScRangeToSequence::FillDoubleArray( uno::Any& rAny, const ScMatrix* pMatrix )
143 if (!pMatrix)
144 return false;
146 SCSIZE nColCount;
147 SCSIZE nRowCount;
148 pMatrix->GetDimensions( nColCount, nRowCount );
150 uno::Sequence< uno::Sequence<double> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
151 uno::Sequence<double>* pRowAry = aRowSeq.getArray();
152 for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
154 uno::Sequence<double> aColSeq( static_cast<sal_Int32>(nColCount) );
155 double* pColAry = aColSeq.getArray();
156 for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
157 if ( pMatrix->IsStringOrEmpty( nCol, nRow ) )
158 pColAry[nCol] = 0.0;
159 else
160 pColAry[nCol] = pMatrix->GetDouble( nCol, nRow );
162 pRowAry[nRow] = std::move(aColSeq);
165 rAny <<= aRowSeq;
166 return true;
169 bool ScRangeToSequence::FillStringArray( uno::Any& rAny, ScDocument& rDoc, const ScRange& rRange )
171 SCTAB nTab = rRange.aStart.Tab();
172 SCCOL nStartCol = rRange.aStart.Col();
173 SCROW nStartRow = rRange.aStart.Row();
174 sal_Int32 nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
175 sal_Int32 nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
177 bool bHasErrors = false;
179 uno::Sequence< uno::Sequence<OUString> > aRowSeq( nRowCount );
180 uno::Sequence<OUString>* pRowAry = aRowSeq.getArray();
181 for (sal_Int32 nRow = 0; nRow < nRowCount; nRow++)
183 uno::Sequence<OUString> aColSeq( nColCount );
184 OUString* pColAry = aColSeq.getArray();
185 for (sal_Int32 nCol = 0; nCol < nColCount; nCol++)
187 FormulaError nErrCode = rDoc.GetStringForFormula(
188 ScAddress(static_cast<SCCOL>(nStartCol+nCol), static_cast<SCROW>(nStartRow+nRow), nTab),
189 pColAry[nCol] );
190 if ( nErrCode != FormulaError::NONE )
191 bHasErrors = true;
193 pRowAry[nRow] = std::move(aColSeq);
196 rAny <<= aRowSeq;
197 return !bHasErrors;
200 bool ScRangeToSequence::FillStringArray(uno::Any& rAny, const ScMatrix* pMatrix, ScInterpreterContext& rContext)
202 if (!pMatrix)
203 return false;
205 SCSIZE nColCount;
206 SCSIZE nRowCount;
207 pMatrix->GetDimensions( nColCount, nRowCount );
209 uno::Sequence< uno::Sequence<OUString> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
210 uno::Sequence<OUString>* pRowAry = aRowSeq.getArray();
211 for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
213 uno::Sequence<OUString> aColSeq( static_cast<sal_Int32>(nColCount) );
214 OUString* pColAry = aColSeq.getArray();
215 for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
217 OUString aStr;
218 if ( pMatrix->IsStringOrEmpty( nCol, nRow ) )
220 if ( !pMatrix->IsEmpty( nCol, nRow ) )
221 aStr = pMatrix->GetString(nCol, nRow).getString();
223 else
225 double fVal = pMatrix->GetDouble( nCol, nRow );
226 const Color* pColor;
227 rContext.NFGetOutputString( fVal, 0, aStr, &pColor );
229 pColAry[nCol] = aStr;
232 pRowAry[nRow] = std::move(aColSeq);
235 rAny <<= aRowSeq;
236 return true;
239 bool ScRangeToSequence::FillMixedArray( uno::Any& rAny, ScDocument& rDoc, const ScRange& rRange,
240 bool bAllowNV )
242 SCTAB nTab = rRange.aStart.Tab();
243 SCCOL nStartCol = rRange.aStart.Col();
244 SCROW nStartRow = rRange.aStart.Row();
245 sal_Int32 nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
246 sal_Int32 nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
248 bool bHasErrors = false;
250 uno::Sequence< uno::Sequence<uno::Any> > aRowSeq( nRowCount );
251 uno::Sequence<uno::Any>* pRowAry = aRowSeq.getArray();
252 for (sal_Int32 nRow = 0; nRow < nRowCount; nRow++)
254 uno::Sequence<uno::Any> aColSeq( nColCount );
255 uno::Any* pColAry = aColSeq.getArray();
256 for (sal_Int32 nCol = 0; nCol < nColCount; nCol++)
258 uno::Any& rElement = pColAry[nCol];
260 ScAddress aPos( static_cast<SCCOL>(nStartCol+nCol), static_cast<SCROW>(nStartRow+nRow), nTab );
261 ScRefCellValue aCell(rDoc, aPos);
263 if (aCell.isEmpty())
265 rElement <<= OUString();
266 continue;
269 if (aCell.getType() == CELLTYPE_FORMULA && aCell.getFormula()->GetErrCode() != FormulaError::NONE)
271 // if NV is allowed, leave empty for errors
272 bHasErrors = true;
274 else if (aCell.hasNumeric())
275 rElement <<= aCell.getValue();
276 else
277 rElement <<= aCell.getString(&rDoc);
279 pRowAry[nRow] = std::move(aColSeq);
282 rAny <<= aRowSeq;
283 return bAllowNV || !bHasErrors;
286 bool ScRangeToSequence::FillMixedArray( uno::Any& rAny, const ScMatrix* pMatrix, bool bDataTypes )
288 if (!pMatrix)
289 return false;
291 SCSIZE nColCount;
292 SCSIZE nRowCount;
293 pMatrix->GetDimensions( nColCount, nRowCount );
295 uno::Sequence< uno::Sequence<uno::Any> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
296 uno::Sequence<uno::Any>* pRowAry = aRowSeq.getArray();
297 for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
299 uno::Sequence<uno::Any> aColSeq( static_cast<sal_Int32>(nColCount) );
300 uno::Any* pColAry = aColSeq.getArray();
301 for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
303 if ( pMatrix->IsStringOrEmpty( nCol, nRow ) )
305 OUString aStr;
306 if ( !pMatrix->IsEmpty( nCol, nRow ) )
307 aStr = pMatrix->GetString(nCol, nRow).getString();
308 pColAry[nCol] <<= aStr;
310 else
312 double fVal = pMatrix->GetDouble( nCol, nRow );
313 if (bDataTypes && pMatrix->IsBoolean( nCol, nRow ))
314 pColAry[nCol] <<= fVal != 0.0;
315 else
316 pColAry[nCol] <<= fVal;
320 pRowAry[nRow] = std::move(aColSeq);
323 rAny <<= aRowSeq;
324 return true;
327 bool ScApiTypeConversion::ConvertAnyToDouble( double & o_fVal,
328 css::uno::TypeClass & o_eClass,
329 const css::uno::Any & rAny )
331 bool bRet = false;
332 o_eClass = rAny.getValueTypeClass();
333 switch (o_eClass)
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 rAny >>= o_fVal;
347 bRet = true;
348 break;
349 default:
350 ; // nothing, avoid warning
352 if (!bRet)
353 o_fVal = 0.0;
354 return bRet;
357 ScMatrixRef ScSequenceToMatrix::CreateMixedMatrix( const css::uno::Any & rAny )
359 ScMatrixRef xMatrix;
360 uno::Sequence< uno::Sequence< uno::Any > > aSequence;
361 if ( rAny >>= aSequence )
363 sal_Int32 nRowCount = aSequence.getLength();
364 sal_Int32 nMaxColCount = 0;
365 if (nRowCount)
367 auto pRow = std::max_element(std::cbegin(aSequence), std::cend(aSequence),
368 [](const uno::Sequence<uno::Any>& a, const uno::Sequence<uno::Any>& b) {
369 return a.getLength() < b.getLength(); });
370 nMaxColCount = pRow->getLength();
372 if ( nMaxColCount && nRowCount )
374 const uno::Sequence<uno::Any>* pRowArr = aSequence.getConstArray();
375 OUString aUStr;
376 xMatrix = new ScMatrix(
377 static_cast<SCSIZE>(nMaxColCount),
378 static_cast<SCSIZE>(nRowCount), 0.0);
379 SCSIZE nCols, nRows;
380 xMatrix->GetDimensions( nCols, nRows);
381 if (nCols != static_cast<SCSIZE>(nMaxColCount) || nRows != static_cast<SCSIZE>(nRowCount))
383 OSL_FAIL( "ScSequenceToMatrix::CreateMixedMatrix: matrix exceeded max size, returning NULL matrix");
384 return nullptr;
386 for (sal_Int32 nRow=0; nRow<nRowCount; nRow++)
388 sal_Int32 nColCount = pRowArr[nRow].getLength();
389 const uno::Any* pColArr = pRowArr[nRow].getConstArray();
390 for (sal_Int32 nCol=0; nCol<nColCount; nCol++)
392 double fVal;
393 uno::TypeClass eClass;
394 if (ScApiTypeConversion::ConvertAnyToDouble( fVal, eClass, pColArr[nCol]))
396 if (eClass == uno::TypeClass_BOOLEAN)
397 xMatrix->PutBoolean( fVal != 0.0,
398 static_cast<SCSIZE>(nCol),
399 static_cast<SCSIZE>(nRow) );
400 else
401 xMatrix->PutDouble( fVal,
402 static_cast<SCSIZE>(nCol),
403 static_cast<SCSIZE>(nRow) );
405 else
407 // Try string, else use empty as last resort.
409 if ( pColArr[nCol] >>= aUStr )
411 xMatrix->PutString(
412 svl::SharedString(aUStr), static_cast<SCSIZE>(nCol), static_cast<SCSIZE>(nRow));
414 else
415 xMatrix->PutEmpty(
416 static_cast<SCSIZE>(nCol),
417 static_cast<SCSIZE>(nRow) );
420 for (sal_Int32 nCol=nColCount; nCol<nMaxColCount; nCol++)
422 xMatrix->PutEmpty(
423 static_cast<SCSIZE>(nCol),
424 static_cast<SCSIZE>(nRow) );
429 return xMatrix;
432 bool ScByteSequenceToString::GetString( OUString& rString, const uno::Any& rAny )
434 bool bResult = false;
435 if (rAny >>= rString)
437 bResult = true;
439 else if (uno::Sequence<sal_Int8> aSeq; rAny >>= aSeq)
441 rString = OUString( reinterpret_cast<const char*>(aSeq.getConstArray()),
442 aSeq.getLength(), osl_getThreadTextEncoding() );
443 bResult = true;
445 if (bResult)
446 rString = comphelper::string::stripEnd(rString, 0);
447 return bResult;
450 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */