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/zforlist.hxx>
21 #include <rtl/math.hxx>
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"
32 using namespace com::sun::star
;
34 static bool lcl_HasErrors( ScDocument
* pDoc
, const ScRange
& rRange
)
36 // no need to look at empty cells - just use ScCellIterator
37 ScCellIterator
aIter( pDoc
, rRange
);
38 for (bool bHas
= aIter
.first(); bHas
; bHas
= aIter
.next())
40 if (aIter
.getType() != CELLTYPE_FORMULA
)
43 ScFormulaCell
* pCell
= aIter
.getFormulaCell();
44 if (pCell
->GetErrCode() != 0)
47 return false; // no error found
50 static long lcl_DoubleToLong( double fVal
)
52 double fInt
= (fVal
>= 0.0) ? ::rtl::math::approxFloor( fVal
) :
53 ::rtl::math::approxCeil( fVal
);
54 if ( fInt
>= LONG_MIN
&& fInt
<= LONG_MAX
)
57 return 0; // out of range
60 sal_Bool
ScRangeToSequence::FillLongArray( uno::Any
& rAny
, ScDocument
* pDoc
, const ScRange
& rRange
)
62 SCTAB nTab
= rRange
.aStart
.Tab();
63 SCCOL nStartCol
= rRange
.aStart
.Col();
64 SCROW nStartRow
= rRange
.aStart
.Row();
65 long nColCount
= rRange
.aEnd
.Col() + 1 - rRange
.aStart
.Col();
66 long nRowCount
= rRange
.aEnd
.Row() + 1 - rRange
.aStart
.Row();
68 uno::Sequence
< uno::Sequence
<sal_Int32
> > aRowSeq( nRowCount
);
69 uno::Sequence
<sal_Int32
>* pRowAry
= aRowSeq
.getArray();
70 for (long nRow
= 0; nRow
< nRowCount
; nRow
++)
72 uno::Sequence
<sal_Int32
> aColSeq( nColCount
);
73 sal_Int32
* pColAry
= aColSeq
.getArray();
74 for (long nCol
= 0; nCol
< nColCount
; nCol
++)
75 pColAry
[nCol
] = lcl_DoubleToLong( pDoc
->GetValue(
76 ScAddress( (SCCOL
)(nStartCol
+nCol
), (SCROW
)(nStartRow
+nRow
), nTab
) ) );
78 pRowAry
[nRow
] = aColSeq
;
82 return !lcl_HasErrors( pDoc
, rRange
);
85 sal_Bool
ScRangeToSequence::FillLongArray( uno::Any
& rAny
, const ScMatrix
* pMatrix
)
92 pMatrix
->GetDimensions( nColCount
, nRowCount
);
94 uno::Sequence
< uno::Sequence
<sal_Int32
> > aRowSeq( static_cast<sal_Int32
>(nRowCount
) );
95 uno::Sequence
<sal_Int32
>* pRowAry
= aRowSeq
.getArray();
96 for (SCSIZE nRow
= 0; nRow
< nRowCount
; nRow
++)
98 uno::Sequence
<sal_Int32
> aColSeq( static_cast<sal_Int32
>(nColCount
) );
99 sal_Int32
* pColAry
= aColSeq
.getArray();
100 for (SCSIZE nCol
= 0; nCol
< nColCount
; nCol
++)
101 if ( pMatrix
->IsString( nCol
, nRow
) )
104 pColAry
[nCol
] = lcl_DoubleToLong( pMatrix
->GetDouble( nCol
, nRow
) );
106 pRowAry
[nRow
] = aColSeq
;
113 sal_Bool
ScRangeToSequence::FillDoubleArray( uno::Any
& rAny
, ScDocument
* pDoc
, const ScRange
& rRange
)
115 SCTAB nTab
= rRange
.aStart
.Tab();
116 SCCOL nStartCol
= rRange
.aStart
.Col();
117 SCROW nStartRow
= rRange
.aStart
.Row();
118 long nColCount
= rRange
.aEnd
.Col() + 1 - rRange
.aStart
.Col();
119 long nRowCount
= rRange
.aEnd
.Row() + 1 - rRange
.aStart
.Row();
121 uno::Sequence
< uno::Sequence
<double> > aRowSeq( nRowCount
);
122 uno::Sequence
<double>* pRowAry
= aRowSeq
.getArray();
123 for (long nRow
= 0; nRow
< nRowCount
; nRow
++)
125 uno::Sequence
<double> aColSeq( nColCount
);
126 double* pColAry
= aColSeq
.getArray();
127 for (long nCol
= 0; nCol
< nColCount
; nCol
++)
128 pColAry
[nCol
] = pDoc
->GetValue(
129 ScAddress( (SCCOL
)(nStartCol
+nCol
), (SCROW
)(nStartRow
+nRow
), nTab
) );
131 pRowAry
[nRow
] = aColSeq
;
135 return !lcl_HasErrors( pDoc
, rRange
);
138 sal_Bool
ScRangeToSequence::FillDoubleArray( uno::Any
& rAny
, const ScMatrix
* pMatrix
)
145 pMatrix
->GetDimensions( nColCount
, nRowCount
);
147 uno::Sequence
< uno::Sequence
<double> > aRowSeq( static_cast<sal_Int32
>(nRowCount
) );
148 uno::Sequence
<double>* pRowAry
= aRowSeq
.getArray();
149 for (SCSIZE nRow
= 0; nRow
< nRowCount
; nRow
++)
151 uno::Sequence
<double> aColSeq( static_cast<sal_Int32
>(nColCount
) );
152 double* pColAry
= aColSeq
.getArray();
153 for (SCSIZE nCol
= 0; nCol
< nColCount
; nCol
++)
154 if ( pMatrix
->IsString( nCol
, nRow
) )
157 pColAry
[nCol
] = pMatrix
->GetDouble( nCol
, nRow
);
159 pRowAry
[nRow
] = aColSeq
;
166 sal_Bool
ScRangeToSequence::FillStringArray( uno::Any
& rAny
, ScDocument
* pDoc
, const ScRange
& rRange
)
168 SCTAB nTab
= rRange
.aStart
.Tab();
169 SCCOL nStartCol
= rRange
.aStart
.Col();
170 SCROW nStartRow
= rRange
.aStart
.Row();
171 long nColCount
= rRange
.aEnd
.Col() + 1 - rRange
.aStart
.Col();
172 long nRowCount
= rRange
.aEnd
.Row() + 1 - rRange
.aStart
.Row();
174 bool bHasErrors
= false;
176 uno::Sequence
< uno::Sequence
<OUString
> > aRowSeq( nRowCount
);
177 uno::Sequence
<OUString
>* pRowAry
= aRowSeq
.getArray();
178 for (long nRow
= 0; nRow
< nRowCount
; nRow
++)
180 uno::Sequence
<OUString
> aColSeq( nColCount
);
181 OUString
* pColAry
= aColSeq
.getArray();
182 for (long nCol
= 0; nCol
< nColCount
; nCol
++)
184 sal_uInt16 nErrCode
= pDoc
->GetStringForFormula(
185 ScAddress((SCCOL
)(nStartCol
+nCol
), (SCROW
)(nStartRow
+nRow
), nTab
),
190 pRowAry
[nRow
] = aColSeq
;
197 sal_Bool
ScRangeToSequence::FillStringArray( uno::Any
& rAny
, const ScMatrix
* pMatrix
,
198 SvNumberFormatter
* pFormatter
)
205 pMatrix
->GetDimensions( nColCount
, nRowCount
);
207 uno::Sequence
< uno::Sequence
<OUString
> > aRowSeq( static_cast<sal_Int32
>(nRowCount
) );
208 uno::Sequence
<OUString
>* pRowAry
= aRowSeq
.getArray();
209 for (SCSIZE nRow
= 0; nRow
< nRowCount
; nRow
++)
211 uno::Sequence
<OUString
> aColSeq( static_cast<sal_Int32
>(nColCount
) );
212 OUString
* pColAry
= aColSeq
.getArray();
213 for (SCSIZE nCol
= 0; nCol
< nColCount
; nCol
++)
216 if ( pMatrix
->IsString( nCol
, nRow
) )
218 if ( !pMatrix
->IsEmpty( nCol
, nRow
) )
219 aStr
= pMatrix
->GetString(nCol
, nRow
).getString();
221 else if ( pFormatter
)
223 double fVal
= pMatrix
->GetDouble( nCol
, nRow
);
225 pFormatter
->GetOutputString( fVal
, 0, aStr
, &pColor
);
227 pColAry
[nCol
] = aStr
;
230 pRowAry
[nRow
] = aColSeq
;
237 sal_Bool
ScRangeToSequence::FillMixedArray( uno::Any
& rAny
, ScDocument
* pDoc
, const ScRange
& rRange
,
240 SCTAB nTab
= rRange
.aStart
.Tab();
241 SCCOL nStartCol
= rRange
.aStart
.Col();
242 SCROW nStartRow
= rRange
.aStart
.Row();
243 long nColCount
= rRange
.aEnd
.Col() + 1 - rRange
.aStart
.Col();
244 long nRowCount
= rRange
.aEnd
.Row() + 1 - rRange
.aStart
.Row();
246 sal_Bool bHasErrors
= false;
248 uno::Sequence
< uno::Sequence
<uno::Any
> > aRowSeq( nRowCount
);
249 uno::Sequence
<uno::Any
>* pRowAry
= aRowSeq
.getArray();
250 for (long nRow
= 0; nRow
< nRowCount
; nRow
++)
252 uno::Sequence
<uno::Any
> aColSeq( nColCount
);
253 uno::Any
* pColAry
= aColSeq
.getArray();
254 for (long nCol
= 0; nCol
< nColCount
; nCol
++)
256 uno::Any
& rElement
= pColAry
[nCol
];
258 ScAddress
aPos( (SCCOL
)(nStartCol
+nCol
), (SCROW
)(nStartRow
+nRow
), nTab
);
259 ScRefCellValue aCell
;
260 aCell
.assign(*pDoc
, aPos
);
264 rElement
<<= EMPTY_OUSTRING
;
268 if (aCell
.meType
== CELLTYPE_FORMULA
&& aCell
.mpFormula
->GetErrCode() != 0)
270 // if NV is allowed, leave empty for errors
273 else if (aCell
.hasNumeric())
274 rElement
<<= aCell
.getValue();
276 rElement
<<= aCell
.getString(pDoc
);
278 pRowAry
[nRow
] = aColSeq
;
282 return bAllowNV
|| !bHasErrors
;
285 sal_Bool
ScRangeToSequence::FillMixedArray( uno::Any
& rAny
, const ScMatrix
* pMatrix
, bool bDataTypes
)
292 pMatrix
->GetDimensions( nColCount
, nRowCount
);
294 uno::Sequence
< uno::Sequence
<uno::Any
> > aRowSeq( static_cast<sal_Int32
>(nRowCount
) );
295 uno::Sequence
<uno::Any
>* pRowAry
= aRowSeq
.getArray();
296 for (SCSIZE nRow
= 0; nRow
< nRowCount
; nRow
++)
298 uno::Sequence
<uno::Any
> aColSeq( static_cast<sal_Int32
>(nColCount
) );
299 uno::Any
* pColAry
= aColSeq
.getArray();
300 for (SCSIZE nCol
= 0; nCol
< nColCount
; nCol
++)
302 if ( pMatrix
->IsString( nCol
, nRow
) )
305 if ( !pMatrix
->IsEmpty( nCol
, nRow
) )
306 aStr
= pMatrix
->GetString(nCol
, nRow
).getString();
307 pColAry
[nCol
] <<= aStr
;
311 double fVal
= pMatrix
->GetDouble( nCol
, nRow
);
312 if (bDataTypes
&& pMatrix
->IsBoolean( nCol
, nRow
))
313 pColAry
[nCol
] <<= (fVal
? true : false);
315 pColAry
[nCol
] <<= fVal
;
319 pRowAry
[nRow
] = aColSeq
;
326 bool ScApiTypeConversion::ConvertAnyToDouble( double & o_fVal
,
327 com::sun::star::uno::TypeClass
& o_eClass
,
328 const com::sun::star::uno::Any
& rAny
)
331 o_eClass
= rAny
.getValueTypeClass();
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
:
349 ; // nothing, avoid warning
356 ScMatrixRef
ScSequenceToMatrix::CreateMixedMatrix( const com::sun::star::uno::Any
& rAny
)
359 uno::Sequence
< uno::Sequence
< uno::Any
> > aSequence
;
360 if ( rAny
>>= aSequence
)
362 sal_Int32 nRowCount
= aSequence
.getLength();
363 const uno::Sequence
<uno::Any
>* pRowArr
= aSequence
.getConstArray();
364 sal_Int32 nMaxColCount
= 0;
365 sal_Int32 nCol
, nRow
;
366 for (nRow
=0; nRow
<nRowCount
; nRow
++)
368 sal_Int32 nTmp
= pRowArr
[nRow
].getLength();
369 if ( nTmp
> nMaxColCount
)
372 if ( nMaxColCount
&& nRowCount
)
375 xMatrix
= new ScMatrix(
376 static_cast<SCSIZE
>(nMaxColCount
),
377 static_cast<SCSIZE
>(nRowCount
), 0.0);
379 xMatrix
->GetDimensions( nCols
, nRows
);
380 if (nCols
!= static_cast<SCSIZE
>(nMaxColCount
) || nRows
!= static_cast<SCSIZE
>(nRowCount
))
382 OSL_FAIL( "ScSequenceToMatrix::CreateMixedMatrix: matrix exceeded max size, returning NULL matrix");
385 for (nRow
=0; nRow
<nRowCount
; nRow
++)
387 sal_Int32 nColCount
= pRowArr
[nRow
].getLength();
388 const uno::Any
* pColArr
= pRowArr
[nRow
].getConstArray();
389 for (nCol
=0; nCol
<nColCount
; nCol
++)
392 uno::TypeClass eClass
;
393 if (ScApiTypeConversion::ConvertAnyToDouble( fVal
, eClass
, pColArr
[nCol
]))
395 if (eClass
== uno::TypeClass_BOOLEAN
)
396 xMatrix
->PutBoolean( (fVal
? true : false),
397 static_cast<SCSIZE
>(nCol
),
398 static_cast<SCSIZE
>(nRow
) );
400 xMatrix
->PutDouble( fVal
,
401 static_cast<SCSIZE
>(nCol
),
402 static_cast<SCSIZE
>(nRow
) );
406 // Try string, else use empty as last resort.
408 if ( pColArr
[nCol
] >>= aUStr
)
411 svl::SharedString(aUStr
), static_cast<SCSIZE
>(nCol
), static_cast<SCSIZE
>(nRow
));
415 static_cast<SCSIZE
>(nCol
),
416 static_cast<SCSIZE
>(nRow
) );
419 for (nCol
=nColCount
; nCol
<nMaxColCount
; nCol
++)
422 static_cast<SCSIZE
>(nCol
),
423 static_cast<SCSIZE
>(nRow
) );
431 sal_Bool
ScByteSequenceToString::GetString( OUString
& rString
, const uno::Any
& rAny
,
432 sal_uInt16 nEncoding
)
434 uno::Sequence
<sal_Int8
> aSeq
;
437 rString
= OUString( (const sal_Char
*)aSeq
.getConstArray(),
438 aSeq
.getLength(), nEncoding
);
439 rString
= comphelper::string::stripEnd(rString
, 0);
445 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */