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>
22 #include <osl/diagnose.h>
24 #include <com/sun/star/uno/Any.hxx>
25 #include <com/sun/star/uno/Sequence.hxx>
26 #include <comphelper/string.hxx>
27 #include "rangeseq.hxx"
28 #include "document.hxx"
29 #include "dociter.hxx"
30 #include "scmatrix.hxx"
31 #include "formulacell.hxx"
33 using namespace com::sun::star
;
35 static bool lcl_HasErrors( ScDocument
* pDoc
, const ScRange
& rRange
)
37 // no need to look at empty cells - just use ScCellIterator
38 ScCellIterator
aIter( pDoc
, rRange
);
39 for (bool bHas
= aIter
.first(); bHas
; bHas
= aIter
.next())
41 if (aIter
.getType() != CELLTYPE_FORMULA
)
44 ScFormulaCell
* pCell
= aIter
.getFormulaCell();
45 if (pCell
->GetErrCode() != 0)
48 return false; // no error found
51 static long lcl_DoubleToLong( double fVal
)
53 double fInt
= (fVal
>= 0.0) ? ::rtl::math::approxFloor( fVal
) :
54 ::rtl::math::approxCeil( fVal
);
55 if ( fInt
>= LONG_MIN
&& fInt
<= LONG_MAX
)
58 return 0; // out of range
61 bool ScRangeToSequence::FillLongArray( uno::Any
& rAny
, ScDocument
* pDoc
, const ScRange
& rRange
)
63 SCTAB nTab
= rRange
.aStart
.Tab();
64 SCCOL nStartCol
= rRange
.aStart
.Col();
65 SCROW nStartRow
= rRange
.aStart
.Row();
66 long nColCount
= rRange
.aEnd
.Col() + 1 - rRange
.aStart
.Col();
67 long nRowCount
= rRange
.aEnd
.Row() + 1 - rRange
.aStart
.Row();
69 uno::Sequence
< uno::Sequence
<sal_Int32
> > aRowSeq( nRowCount
);
70 uno::Sequence
<sal_Int32
>* pRowAry
= aRowSeq
.getArray();
71 for (long nRow
= 0; nRow
< nRowCount
; nRow
++)
73 uno::Sequence
<sal_Int32
> aColSeq( nColCount
);
74 sal_Int32
* pColAry
= aColSeq
.getArray();
75 for (long nCol
= 0; nCol
< nColCount
; nCol
++)
76 pColAry
[nCol
] = lcl_DoubleToLong( pDoc
->GetValue(
77 ScAddress( (SCCOL
)(nStartCol
+nCol
), (SCROW
)(nStartRow
+nRow
), nTab
) ) );
79 pRowAry
[nRow
] = aColSeq
;
83 return !lcl_HasErrors( pDoc
, rRange
);
86 bool ScRangeToSequence::FillLongArray( uno::Any
& rAny
, const ScMatrix
* pMatrix
)
93 pMatrix
->GetDimensions( nColCount
, nRowCount
);
95 uno::Sequence
< uno::Sequence
<sal_Int32
> > aRowSeq( static_cast<sal_Int32
>(nRowCount
) );
96 uno::Sequence
<sal_Int32
>* pRowAry
= aRowSeq
.getArray();
97 for (SCSIZE nRow
= 0; nRow
< nRowCount
; nRow
++)
99 uno::Sequence
<sal_Int32
> aColSeq( static_cast<sal_Int32
>(nColCount
) );
100 sal_Int32
* pColAry
= aColSeq
.getArray();
101 for (SCSIZE nCol
= 0; nCol
< nColCount
; nCol
++)
102 if ( pMatrix
->IsString( nCol
, nRow
) )
105 pColAry
[nCol
] = lcl_DoubleToLong( pMatrix
->GetDouble( nCol
, nRow
) );
107 pRowAry
[nRow
] = aColSeq
;
114 bool ScRangeToSequence::FillDoubleArray( uno::Any
& rAny
, ScDocument
* pDoc
, const ScRange
& rRange
)
116 SCTAB nTab
= rRange
.aStart
.Tab();
117 SCCOL nStartCol
= rRange
.aStart
.Col();
118 SCROW nStartRow
= rRange
.aStart
.Row();
119 long nColCount
= rRange
.aEnd
.Col() + 1 - rRange
.aStart
.Col();
120 long nRowCount
= rRange
.aEnd
.Row() + 1 - rRange
.aStart
.Row();
122 uno::Sequence
< uno::Sequence
<double> > aRowSeq( nRowCount
);
123 uno::Sequence
<double>* pRowAry
= aRowSeq
.getArray();
124 for (long nRow
= 0; nRow
< nRowCount
; nRow
++)
126 uno::Sequence
<double> aColSeq( nColCount
);
127 double* pColAry
= aColSeq
.getArray();
128 for (long nCol
= 0; nCol
< nColCount
; nCol
++)
129 pColAry
[nCol
] = pDoc
->GetValue(
130 ScAddress( (SCCOL
)(nStartCol
+nCol
), (SCROW
)(nStartRow
+nRow
), nTab
) );
132 pRowAry
[nRow
] = aColSeq
;
136 return !lcl_HasErrors( pDoc
, rRange
);
139 bool ScRangeToSequence::FillDoubleArray( uno::Any
& rAny
, const ScMatrix
* pMatrix
)
146 pMatrix
->GetDimensions( nColCount
, nRowCount
);
148 uno::Sequence
< uno::Sequence
<double> > aRowSeq( static_cast<sal_Int32
>(nRowCount
) );
149 uno::Sequence
<double>* pRowAry
= aRowSeq
.getArray();
150 for (SCSIZE nRow
= 0; nRow
< nRowCount
; nRow
++)
152 uno::Sequence
<double> aColSeq( static_cast<sal_Int32
>(nColCount
) );
153 double* pColAry
= aColSeq
.getArray();
154 for (SCSIZE nCol
= 0; nCol
< nColCount
; nCol
++)
155 if ( pMatrix
->IsString( nCol
, nRow
) )
158 pColAry
[nCol
] = pMatrix
->GetDouble( nCol
, nRow
);
160 pRowAry
[nRow
] = aColSeq
;
167 bool ScRangeToSequence::FillStringArray( uno::Any
& rAny
, ScDocument
* pDoc
, const ScRange
& rRange
)
169 SCTAB nTab
= rRange
.aStart
.Tab();
170 SCCOL nStartCol
= rRange
.aStart
.Col();
171 SCROW nStartRow
= rRange
.aStart
.Row();
172 long nColCount
= rRange
.aEnd
.Col() + 1 - rRange
.aStart
.Col();
173 long nRowCount
= rRange
.aEnd
.Row() + 1 - rRange
.aStart
.Row();
175 bool bHasErrors
= false;
177 uno::Sequence
< uno::Sequence
<OUString
> > aRowSeq( nRowCount
);
178 uno::Sequence
<OUString
>* pRowAry
= aRowSeq
.getArray();
179 for (long nRow
= 0; nRow
< nRowCount
; nRow
++)
181 uno::Sequence
<OUString
> aColSeq( nColCount
);
182 OUString
* pColAry
= aColSeq
.getArray();
183 for (long nCol
= 0; nCol
< nColCount
; nCol
++)
185 sal_uInt16 nErrCode
= pDoc
->GetStringForFormula(
186 ScAddress((SCCOL
)(nStartCol
+nCol
), (SCROW
)(nStartRow
+nRow
), nTab
),
191 pRowAry
[nRow
] = aColSeq
;
198 bool ScRangeToSequence::FillStringArray( uno::Any
& rAny
, const ScMatrix
* pMatrix
,
199 SvNumberFormatter
* pFormatter
)
206 pMatrix
->GetDimensions( nColCount
, nRowCount
);
208 uno::Sequence
< uno::Sequence
<OUString
> > aRowSeq( static_cast<sal_Int32
>(nRowCount
) );
209 uno::Sequence
<OUString
>* pRowAry
= aRowSeq
.getArray();
210 for (SCSIZE nRow
= 0; nRow
< nRowCount
; nRow
++)
212 uno::Sequence
<OUString
> aColSeq( static_cast<sal_Int32
>(nColCount
) );
213 OUString
* pColAry
= aColSeq
.getArray();
214 for (SCSIZE nCol
= 0; nCol
< nColCount
; nCol
++)
217 if ( pMatrix
->IsString( nCol
, nRow
) )
219 if ( !pMatrix
->IsEmpty( nCol
, nRow
) )
220 aStr
= pMatrix
->GetString(nCol
, nRow
).getString();
222 else if ( pFormatter
)
224 double fVal
= pMatrix
->GetDouble( nCol
, nRow
);
226 pFormatter
->GetOutputString( fVal
, 0, aStr
, &pColor
);
228 pColAry
[nCol
] = aStr
;
231 pRowAry
[nRow
] = aColSeq
;
238 bool ScRangeToSequence::FillMixedArray( uno::Any
& rAny
, ScDocument
* pDoc
, const ScRange
& rRange
,
241 SCTAB nTab
= rRange
.aStart
.Tab();
242 SCCOL nStartCol
= rRange
.aStart
.Col();
243 SCROW nStartRow
= rRange
.aStart
.Row();
244 long nColCount
= rRange
.aEnd
.Col() + 1 - rRange
.aStart
.Col();
245 long nRowCount
= rRange
.aEnd
.Row() + 1 - rRange
.aStart
.Row();
247 bool bHasErrors
= false;
249 uno::Sequence
< uno::Sequence
<uno::Any
> > aRowSeq( nRowCount
);
250 uno::Sequence
<uno::Any
>* pRowAry
= aRowSeq
.getArray();
251 for (long nRow
= 0; nRow
< nRowCount
; nRow
++)
253 uno::Sequence
<uno::Any
> aColSeq( nColCount
);
254 uno::Any
* pColAry
= aColSeq
.getArray();
255 for (long nCol
= 0; nCol
< nColCount
; nCol
++)
257 uno::Any
& rElement
= pColAry
[nCol
];
259 ScAddress
aPos( (SCCOL
)(nStartCol
+nCol
), (SCROW
)(nStartRow
+nRow
), nTab
);
260 ScRefCellValue aCell
;
261 aCell
.assign(*pDoc
, aPos
);
265 rElement
<<= EMPTY_OUSTRING
;
269 if (aCell
.meType
== CELLTYPE_FORMULA
&& aCell
.mpFormula
->GetErrCode() != 0)
271 // if NV is allowed, leave empty for errors
274 else if (aCell
.hasNumeric())
275 rElement
<<= aCell
.getValue();
277 rElement
<<= aCell
.getString(pDoc
);
279 pRowAry
[nRow
] = 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
->IsString( 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
] = aColSeq
;
327 bool ScApiTypeConversion::ConvertAnyToDouble( double & o_fVal
,
328 com::sun::star::uno::TypeClass
& o_eClass
,
329 const com::sun::star::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 com::sun::star::uno::Any
& rAny
)
360 uno::Sequence
< uno::Sequence
< uno::Any
> > aSequence
;
361 if ( rAny
>>= aSequence
)
363 sal_Int32 nRowCount
= aSequence
.getLength();
364 const uno::Sequence
<uno::Any
>* pRowArr
= aSequence
.getConstArray();
365 sal_Int32 nMaxColCount
= 0;
366 sal_Int32 nCol
, nRow
;
367 for (nRow
=0; nRow
<nRowCount
; nRow
++)
369 sal_Int32 nTmp
= pRowArr
[nRow
].getLength();
370 if ( nTmp
> nMaxColCount
)
373 if ( nMaxColCount
&& nRowCount
)
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 (nRow
=0; nRow
<nRowCount
; nRow
++)
388 sal_Int32 nColCount
= pRowArr
[nRow
].getLength();
389 const uno::Any
* pColArr
= pRowArr
[nRow
].getConstArray();
390 for (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 (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
,
433 sal_uInt16 nEncoding
)
435 uno::Sequence
<sal_Int8
> aSeq
;
438 rString
= OUString( reinterpret_cast<const char*>(aSeq
.getConstArray()),
439 aSeq
.getLength(), nEncoding
);
440 rString
= comphelper::string::stripEnd(rString
, 0);
446 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */