LibreOffice Module sc (master)  1
rangeseq.cxx
Go to the documentation of this file.
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/numformat.hxx>
21 #include <svl/zforlist.hxx>
22 #include <rtl/math.hxx>
24 #include <osl/diagnose.h>
25 
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>
34 
35 using namespace com::sun::star;
36 
37 static bool lcl_HasErrors( ScDocument& rDoc, const ScRange& rRange )
38 {
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())
42  {
43  if (aIter.getType() != CELLTYPE_FORMULA)
44  continue;
45 
46  ScFormulaCell* pCell = aIter.getFormulaCell();
47  if (pCell->GetErrCode() != FormulaError::NONE)
48  return true;
49  }
50  return false; // no error found
51 }
52 
53 static tools::Long lcl_DoubleToLong( double fVal )
54 {
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
61 }
62 
63 bool ScRangeToSequence::FillLongArray( uno::Any& rAny, ScDocument& rDoc, const ScRange& rRange )
64 {
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();
70 
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++)
74  {
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 ) ) );
80 
81  pRowAry[nRow] = aColSeq;
82  }
83 
84  rAny <<= aRowSeq;
85  return !lcl_HasErrors( rDoc, rRange );
86 }
87 
88 bool ScRangeToSequence::FillLongArray( uno::Any& rAny, const ScMatrix* pMatrix )
89 {
90  if (!pMatrix)
91  return false;
92 
93  SCSIZE nColCount;
94  SCSIZE nRowCount;
95  pMatrix->GetDimensions( nColCount, nRowCount );
96 
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++)
100  {
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 ) );
108 
109  pRowAry[nRow] = aColSeq;
110  }
111 
112  rAny <<= aRowSeq;
113  return true;
114 }
115 
116 bool ScRangeToSequence::FillDoubleArray( uno::Any& rAny, ScDocument& rDoc, const ScRange& rRange )
117 {
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();
123 
124  uno::Sequence< uno::Sequence<double> > aRowSeq( nRowCount );
125  uno::Sequence<double>* pRowAry = aRowSeq.getArray();
126  for (sal_Int32 nRow = 0; nRow < nRowCount; nRow++)
127  {
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 ) );
133 
134  pRowAry[nRow] = aColSeq;
135  }
136 
137  rAny <<= aRowSeq;
138  return !lcl_HasErrors( rDoc, rRange );
139 }
140 
141 bool ScRangeToSequence::FillDoubleArray( uno::Any& rAny, const ScMatrix* pMatrix )
142 {
143  if (!pMatrix)
144  return false;
145 
146  SCSIZE nColCount;
147  SCSIZE nRowCount;
148  pMatrix->GetDimensions( nColCount, nRowCount );
149 
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++)
153  {
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 );
161 
162  pRowAry[nRow] = aColSeq;
163  }
164 
165  rAny <<= aRowSeq;
166  return true;
167 }
168 
169 bool ScRangeToSequence::FillStringArray( uno::Any& rAny, ScDocument& rDoc, const ScRange& rRange )
170 {
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();
176 
177  bool bHasErrors = false;
178 
179  uno::Sequence< uno::Sequence<OUString> > aRowSeq( nRowCount );
180  uno::Sequence<OUString>* pRowAry = aRowSeq.getArray();
181  for (sal_Int32 nRow = 0; nRow < nRowCount; nRow++)
182  {
183  uno::Sequence<OUString> aColSeq( nColCount );
184  OUString* pColAry = aColSeq.getArray();
185  for (sal_Int32 nCol = 0; nCol < nColCount; nCol++)
186  {
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;
192  }
193  pRowAry[nRow] = aColSeq;
194  }
195 
196  rAny <<= aRowSeq;
197  return !bHasErrors;
198 }
199 
200 bool ScRangeToSequence::FillStringArray( uno::Any& rAny, const ScMatrix* pMatrix,
201  SvNumberFormatter* pFormatter )
202 {
203  if (!pMatrix)
204  return false;
205 
206  SCSIZE nColCount;
207  SCSIZE nRowCount;
208  pMatrix->GetDimensions( nColCount, nRowCount );
209 
210  uno::Sequence< uno::Sequence<OUString> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
211  uno::Sequence<OUString>* pRowAry = aRowSeq.getArray();
212  for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
213  {
214  uno::Sequence<OUString> aColSeq( static_cast<sal_Int32>(nColCount) );
215  OUString* pColAry = aColSeq.getArray();
216  for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
217  {
218  OUString aStr;
219  if ( pMatrix->IsStringOrEmpty( nCol, nRow ) )
220  {
221  if ( !pMatrix->IsEmpty( nCol, nRow ) )
222  aStr = pMatrix->GetString(nCol, nRow).getString();
223  }
224  else if ( pFormatter )
225  {
226  double fVal = pMatrix->GetDouble( nCol, nRow );
227  const Color* pColor;
228  pFormatter->GetOutputString( fVal, 0, aStr, &pColor );
229  }
230  pColAry[nCol] = aStr;
231  }
232 
233  pRowAry[nRow] = aColSeq;
234  }
235 
236  rAny <<= aRowSeq;
237  return true;
238 }
239 
240 bool ScRangeToSequence::FillMixedArray( uno::Any& rAny, ScDocument& rDoc, const ScRange& rRange,
241  bool bAllowNV )
242 {
243  SCTAB nTab = rRange.aStart.Tab();
244  SCCOL nStartCol = rRange.aStart.Col();
245  SCROW nStartRow = rRange.aStart.Row();
246  sal_Int32 nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
247  sal_Int32 nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
248 
249  bool bHasErrors = false;
250 
251  uno::Sequence< uno::Sequence<uno::Any> > aRowSeq( nRowCount );
252  uno::Sequence<uno::Any>* pRowAry = aRowSeq.getArray();
253  for (sal_Int32 nRow = 0; nRow < nRowCount; nRow++)
254  {
255  uno::Sequence<uno::Any> aColSeq( nColCount );
256  uno::Any* pColAry = aColSeq.getArray();
257  for (sal_Int32 nCol = 0; nCol < nColCount; nCol++)
258  {
259  uno::Any& rElement = pColAry[nCol];
260 
261  ScAddress aPos( static_cast<SCCOL>(nStartCol+nCol), static_cast<SCROW>(nStartRow+nRow), nTab );
262  ScRefCellValue aCell(rDoc, aPos);
263 
264  if (aCell.isEmpty())
265  {
266  rElement <<= OUString();
267  continue;
268  }
269 
270  if (aCell.meType == CELLTYPE_FORMULA && aCell.mpFormula->GetErrCode() != FormulaError::NONE)
271  {
272  // if NV is allowed, leave empty for errors
273  bHasErrors = true;
274  }
275  else if (aCell.hasNumeric())
276  rElement <<= aCell.getValue();
277  else
278  rElement <<= aCell.getString(&rDoc);
279  }
280  pRowAry[nRow] = aColSeq;
281  }
282 
283  rAny <<= aRowSeq;
284  return bAllowNV || !bHasErrors;
285 }
286 
287 bool ScRangeToSequence::FillMixedArray( uno::Any& rAny, const ScMatrix* pMatrix, bool bDataTypes )
288 {
289  if (!pMatrix)
290  return false;
291 
292  SCSIZE nColCount;
293  SCSIZE nRowCount;
294  pMatrix->GetDimensions( nColCount, nRowCount );
295 
296  uno::Sequence< uno::Sequence<uno::Any> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
297  uno::Sequence<uno::Any>* pRowAry = aRowSeq.getArray();
298  for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
299  {
300  uno::Sequence<uno::Any> aColSeq( static_cast<sal_Int32>(nColCount) );
301  uno::Any* pColAry = aColSeq.getArray();
302  for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
303  {
304  if ( pMatrix->IsStringOrEmpty( nCol, nRow ) )
305  {
306  OUString aStr;
307  if ( !pMatrix->IsEmpty( nCol, nRow ) )
308  aStr = pMatrix->GetString(nCol, nRow).getString();
309  pColAry[nCol] <<= aStr;
310  }
311  else
312  {
313  double fVal = pMatrix->GetDouble( nCol, nRow );
314  if (bDataTypes && pMatrix->IsBoolean( nCol, nRow ))
315  pColAry[nCol] <<= fVal != 0.0;
316  else
317  pColAry[nCol] <<= fVal;
318  }
319  }
320 
321  pRowAry[nRow] = aColSeq;
322  }
323 
324  rAny <<= aRowSeq;
325  return true;
326 }
327 
329  css::uno::TypeClass & o_eClass,
330  const css::uno::Any & rAny )
331 {
332  bool bRet = false;
333  o_eClass = rAny.getValueTypeClass();
334  switch (o_eClass)
335  {
336  //TODO: extract integer values
337  case uno::TypeClass_ENUM:
338  case uno::TypeClass_BOOLEAN:
339  case uno::TypeClass_CHAR:
340  case uno::TypeClass_BYTE:
341  case uno::TypeClass_SHORT:
342  case uno::TypeClass_UNSIGNED_SHORT:
343  case uno::TypeClass_LONG:
344  case uno::TypeClass_UNSIGNED_LONG:
345  case uno::TypeClass_FLOAT:
346  case uno::TypeClass_DOUBLE:
347  rAny >>= o_fVal;
348  bRet = true;
349  break;
350  default:
351  ; // nothing, avoid warning
352  }
353  if (!bRet)
354  o_fVal = 0.0;
355  return bRet;
356 }
357 
359 {
360  ScMatrixRef xMatrix;
361  uno::Sequence< uno::Sequence< uno::Any > > aSequence;
362  if ( rAny >>= aSequence )
363  {
364  sal_Int32 nRowCount = aSequence.getLength();
365  sal_Int32 nMaxColCount = 0;
366  if (nRowCount)
367  {
368  auto pRow = std::max_element(std::cbegin(aSequence), std::cend(aSequence),
369  [](const uno::Sequence<uno::Any>& a, const uno::Sequence<uno::Any>& b) {
370  return a.getLength() < b.getLength(); });
371  nMaxColCount = pRow->getLength();
372  }
373  if ( nMaxColCount && nRowCount )
374  {
375  const uno::Sequence<uno::Any>* pRowArr = aSequence.getConstArray();
376  OUString aUStr;
377  xMatrix = new ScMatrix(
378  static_cast<SCSIZE>(nMaxColCount),
379  static_cast<SCSIZE>(nRowCount), 0.0);
380  SCSIZE nCols, nRows;
381  xMatrix->GetDimensions( nCols, nRows);
382  if (nCols != static_cast<SCSIZE>(nMaxColCount) || nRows != static_cast<SCSIZE>(nRowCount))
383  {
384  OSL_FAIL( "ScSequenceToMatrix::CreateMixedMatrix: matrix exceeded max size, returning NULL matrix");
385  return nullptr;
386  }
387  for (sal_Int32 nRow=0; nRow<nRowCount; nRow++)
388  {
389  sal_Int32 nColCount = pRowArr[nRow].getLength();
390  const uno::Any* pColArr = pRowArr[nRow].getConstArray();
391  for (sal_Int32 nCol=0; nCol<nColCount; nCol++)
392  {
393  double fVal;
394  uno::TypeClass eClass;
395  if (ScApiTypeConversion::ConvertAnyToDouble( fVal, eClass, pColArr[nCol]))
396  {
397  if (eClass == uno::TypeClass_BOOLEAN)
398  xMatrix->PutBoolean( fVal != 0.0,
399  static_cast<SCSIZE>(nCol),
400  static_cast<SCSIZE>(nRow) );
401  else
402  xMatrix->PutDouble( fVal,
403  static_cast<SCSIZE>(nCol),
404  static_cast<SCSIZE>(nRow) );
405  }
406  else
407  {
408  // Try string, else use empty as last resort.
409 
410  if ( pColArr[nCol] >>= aUStr )
411  {
412  xMatrix->PutString(
413  svl::SharedString(aUStr), static_cast<SCSIZE>(nCol), static_cast<SCSIZE>(nRow));
414  }
415  else
416  xMatrix->PutEmpty(
417  static_cast<SCSIZE>(nCol),
418  static_cast<SCSIZE>(nRow) );
419  }
420  }
421  for (sal_Int32 nCol=nColCount; nCol<nMaxColCount; nCol++)
422  {
423  xMatrix->PutEmpty(
424  static_cast<SCSIZE>(nCol),
425  static_cast<SCSIZE>(nRow) );
426  }
427  }
428  }
429  }
430  return xMatrix;
431 }
432 
433 bool ScByteSequenceToString::GetString( OUString& rString, const uno::Any& rAny,
434  sal_uInt16 nEncoding )
435 {
436  uno::Sequence<sal_Int8> aSeq;
437  if ( rAny >>= aSeq )
438  {
439  rString = OUString( reinterpret_cast<const char*>(aSeq.getConstArray()),
440  aSeq.getLength(), nEncoding );
441  rString = comphelper::string::stripEnd(rString, 0);
442  return true;
443  }
444  return false;
445 }
446 
447 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Matrix data type that can store values of mixed types.
Definition: scmatrix.hxx:112
constexpr std::enable_if_t< std::is_floating_point_v< F > &&std::is_integral_v< I >, bool > convertsToAtLeast(F value, I min)
OString stripEnd(std::string_view rIn, char c)
static bool FillLongArray(css::uno::Any &rAny, ScDocument &rDoc, const ScRange &rRange)
OUString getString() const
ScAddress aStart
Definition: address.hxx:499
static bool lcl_HasErrors(ScDocument &rDoc, const ScRange &rRange)
Definition: rangeseq.cxx:37
SCROW Row() const
Definition: address.hxx:261
long Long
static bool ConvertAnyToDouble(double &o_fVal, css::uno::TypeClass &o_eClass, const css::uno::Any &rAny)
Convert a uno::Any to double if possible, including integer types.
Definition: rangeseq.cxx:328
ScAddress aEnd
Definition: address.hxx:500
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:103
ScFormulaCell * getFormulaCell()
Definition: dociter.hxx:238
double GetDouble(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3010
CellType getType() const
Definition: dociter.hxx:235
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
Definition: address.hxx:44
FormulaError GetErrCode()
::boost::intrusive_ptr< ScMatrix > ScMatrixRef
Definition: types.hxx:25
Walk through all cells in an area.
Definition: dociter.hxx:207
SCTAB Tab() const
Definition: address.hxx:270
bool IsStringOrEmpty(SCSIZE nIndex) const
Definition: scmatrix.cxx:3045
static bool FillMixedArray(css::uno::Any &rAny, ScDocument &rDoc, const ScRange &rRange, bool bAllowNV=false)
static bool FillDoubleArray(css::uno::Any &rAny, ScDocument &rDoc, const ScRange &rRange)
SC_DLLPUBLIC double GetValue(const ScAddress &rPos) const
Definition: document.cxx:3644
constexpr std::enable_if_t< std::is_floating_point_v< F > &&std::is_integral_v< I >, bool > convertsToAtMost(F value, I max)
static bool FillStringArray(css::uno::Any &rAny, ScDocument &rDoc, const ScRange &rRange)
svl::SharedString GetString(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3025
uno_Any a
void GetDimensions(SCSIZE &rC, SCSIZE &rR) const
Definition: scmatrix.cxx:2930
sal_Int16 SCCOL
Definition: types.hxx:21
bool IsBoolean(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3090
static tools::Long lcl_DoubleToLong(double fVal)
Definition: rangeseq.cxx:53
const long LONG_MAX
FormulaError
SCCOL Col() const
Definition: address.hxx:266
static bool GetString(OUString &rString, const css::uno::Any &rAny, sal_uInt16 nEncoding)
Definition: rangeseq.cxx:433
sal_Int32 SCROW
Definition: types.hxx:17
bool IsEmpty(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3055
static ScMatrixRef CreateMixedMatrix(const css::uno::Any &rAny)
Convert a sequence of mixed elements to ScMatrix.
Definition: rangeseq.cxx:358
Sequence< sal_Int8 > aSeq
FormulaError GetStringForFormula(const ScAddress &rPos, OUString &rString)
Definition: document.cxx:3572
aStr
void GetOutputString(const double &fOutNumber, sal_uInt32 nFIndex, OUString &sOutString, const Color **ppColor, bool bUseStarFormat=false)
sal_Int16 SCTAB
Definition: types.hxx:22