1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
)
46 ScFormulaCell
* pCell
= aIter
.getFormulaCell();
47 if (pCell
->GetErrCode() != FormulaError::NONE
)
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
);
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
);
85 return !lcl_HasErrors( rDoc
, rRange
);
88 bool ScRangeToSequence::FillLongArray( uno::Any
& rAny
, const ScMatrix
* pMatrix
)
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
) )
107 pColAry
[nCol
] = lcl_DoubleToLong( pMatrix
->GetDouble( nCol
, nRow
) );
109 pRowAry
[nRow
] = std::move(aColSeq
);
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
);
138 return !lcl_HasErrors( rDoc
, rRange
);
141 bool ScRangeToSequence::FillDoubleArray( uno::Any
& rAny
, const ScMatrix
* pMatrix
)
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
) )
160 pColAry
[nCol
] = pMatrix
->GetDouble( nCol
, nRow
);
162 pRowAry
[nRow
] = std::move(aColSeq
);
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
),
190 if ( nErrCode
!= FormulaError::NONE
)
193 pRowAry
[nRow
] = std::move(aColSeq
);
200 bool ScRangeToSequence::FillStringArray(uno::Any
& rAny
, const ScMatrix
* pMatrix
, ScInterpreterContext
& rContext
)
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
++)
218 if ( pMatrix
->IsStringOrEmpty( nCol
, nRow
) )
220 if ( !pMatrix
->IsEmpty( nCol
, nRow
) )
221 aStr
= pMatrix
->GetString(nCol
, nRow
).getString();
225 double fVal
= pMatrix
->GetDouble( nCol
, nRow
);
227 rContext
.NFGetOutputString( fVal
, 0, aStr
, &pColor
);
229 pColAry
[nCol
] = aStr
;
232 pRowAry
[nRow
] = std::move(aColSeq
);
239 bool ScRangeToSequence::FillMixedArray( uno::Any
& rAny
, ScDocument
& rDoc
, const ScRange
& rRange
,
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
);
265 rElement
<<= OUString();
269 if (aCell
.getType() == CELLTYPE_FORMULA
&& aCell
.getFormula()->GetErrCode() != FormulaError::NONE
)
271 // if NV is allowed, leave empty for errors
274 else if (aCell
.hasNumeric())
275 rElement
<<= aCell
.getValue();
277 rElement
<<= aCell
.getString(&rDoc
);
279 pRowAry
[nRow
] = std::move(aColSeq
);
283 return bAllowNV
|| !bHasErrors
;
286 bool ScRangeToSequence::FillMixedArray( uno::Any
& rAny
, const ScMatrix
* pMatrix
, bool bDataTypes
)
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
) )
306 if ( !pMatrix
->IsEmpty( nCol
, nRow
) )
307 aStr
= pMatrix
->GetString(nCol
, nRow
).getString();
308 pColAry
[nCol
] <<= aStr
;
312 double fVal
= pMatrix
->GetDouble( nCol
, nRow
);
313 if (bDataTypes
&& pMatrix
->IsBoolean( nCol
, nRow
))
314 pColAry
[nCol
] <<= fVal
!= 0.0;
316 pColAry
[nCol
] <<= fVal
;
320 pRowAry
[nRow
] = std::move(aColSeq
);
327 bool ScApiTypeConversion::ConvertAnyToDouble( double & o_fVal
,
328 css::uno::TypeClass
& o_eClass
,
329 const css::uno::Any
& rAny
)
332 o_eClass
= rAny
.getValueTypeClass();
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
:
350 ; // nothing, avoid warning
357 ScMatrixRef
ScSequenceToMatrix::CreateMixedMatrix( const css::uno::Any
& rAny
)
360 uno::Sequence
< uno::Sequence
< uno::Any
> > aSequence
;
361 if ( rAny
>>= aSequence
)
363 sal_Int32 nRowCount
= aSequence
.getLength();
364 sal_Int32 nMaxColCount
= 0;
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();
376 xMatrix
= new ScMatrix(
377 static_cast<SCSIZE
>(nMaxColCount
),
378 static_cast<SCSIZE
>(nRowCount
), 0.0);
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");
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
++)
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
) );
401 xMatrix
->PutDouble( fVal
,
402 static_cast<SCSIZE
>(nCol
),
403 static_cast<SCSIZE
>(nRow
) );
407 // Try string, else use empty as last resort.
409 if ( pColArr
[nCol
] >>= aUStr
)
412 svl::SharedString(aUStr
), static_cast<SCSIZE
>(nCol
), static_cast<SCSIZE
>(nRow
));
416 static_cast<SCSIZE
>(nCol
),
417 static_cast<SCSIZE
>(nRow
) );
420 for (sal_Int32 nCol
=nColCount
; nCol
<nMaxColCount
; nCol
++)
423 static_cast<SCSIZE
>(nCol
),
424 static_cast<SCSIZE
>(nRow
) );
432 bool ScByteSequenceToString::GetString( OUString
& rString
, const uno::Any
& rAny
)
434 bool bResult
= false;
435 if (rAny
>>= rString
)
439 else if (uno::Sequence
<sal_Int8
> aSeq
; rAny
>>= aSeq
)
441 rString
= OUString( reinterpret_cast<const char*>(aSeq
.getConstArray()),
442 aSeq
.getLength(), osl_getThreadTextEncoding() );
446 rString
= comphelper::string::stripEnd(rString
, 0);
450 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */