xref: /trunk/main/sc/source/core/tool/rangeseq.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 
32 
33 #include <svl/zforlist.hxx>
34 #include <rtl/math.hxx>
35 #include <tools/debug.hxx>
36 
37 #include <com/sun/star/uno/Any.hxx>
38 #include <com/sun/star/uno/Sequence.hxx>
39 
40 #include "rangeseq.hxx"
41 #include "document.hxx"
42 #include "dociter.hxx"
43 #include "scmatrix.hxx"
44 #include "cell.hxx"
45 
46 using namespace com::sun::star;
47 
48 //------------------------------------------------------------------------
49 
50 bool lcl_HasErrors( ScDocument* pDoc, const ScRange& rRange )
51 {
52     // no need to look at empty cells - just use ScCellIterator
53     ScCellIterator aIter( pDoc, rRange );
54     ScBaseCell* pCell = aIter.GetFirst();
55     while (pCell)
56     {
57         if ( pCell->GetCellType() == CELLTYPE_FORMULA && static_cast<ScFormulaCell*>(pCell)->GetErrCode() != 0 )
58             return true;
59         pCell = aIter.GetNext();
60     }
61     return false;   // no error found
62 }
63 
64 long lcl_DoubleToLong( double fVal )
65 {
66 	double fInt = (fVal >= 0.0) ? ::rtl::math::approxFloor( fVal ) :
67 								  ::rtl::math::approxCeil( fVal );
68 	if ( fInt >= LONG_MIN && fInt <= LONG_MAX )
69 		return (long)fInt;
70 	else
71 		return 0;		// out of range
72 }
73 
74 sal_Bool ScRangeToSequence::FillLongArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange )
75 {
76 	SCTAB nTab = rRange.aStart.Tab();
77 	SCCOL nStartCol = rRange.aStart.Col();
78 	SCROW nStartRow = rRange.aStart.Row();
79 	long nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
80 	long nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
81 
82 	uno::Sequence< uno::Sequence<sal_Int32> > aRowSeq( nRowCount );
83 	uno::Sequence<sal_Int32>* pRowAry = aRowSeq.getArray();
84 	for (long nRow = 0; nRow < nRowCount; nRow++)
85 	{
86 		uno::Sequence<sal_Int32> aColSeq( nColCount );
87 		sal_Int32* pColAry = aColSeq.getArray();
88 		for (long nCol = 0; nCol < nColCount; nCol++)
89 			pColAry[nCol] = lcl_DoubleToLong( pDoc->GetValue(
90 				ScAddress( (SCCOL)(nStartCol+nCol), (SCROW)(nStartRow+nRow), nTab ) ) );
91 
92 		pRowAry[nRow] = aColSeq;
93 	}
94 
95 	rAny <<= aRowSeq;
96     return !lcl_HasErrors( pDoc, rRange );
97 }
98 
99 
100 sal_Bool ScRangeToSequence::FillLongArray( uno::Any& rAny, const ScMatrix* pMatrix )
101 {
102 	if (!pMatrix)
103 		return sal_False;
104 
105 	SCSIZE nColCount;
106 	SCSIZE nRowCount;
107 	pMatrix->GetDimensions( nColCount, nRowCount );
108 
109 	uno::Sequence< uno::Sequence<sal_Int32> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
110 	uno::Sequence<sal_Int32>* pRowAry = aRowSeq.getArray();
111 	for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
112 	{
113 		uno::Sequence<sal_Int32> aColSeq( static_cast<sal_Int32>(nColCount) );
114 		sal_Int32* pColAry = aColSeq.getArray();
115 		for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
116 			if ( pMatrix->IsString( nCol, nRow ) )
117 				pColAry[nCol] = 0;
118 			else
119 				pColAry[nCol] = lcl_DoubleToLong( pMatrix->GetDouble( nCol, nRow ) );
120 
121 		pRowAry[nRow] = aColSeq;
122 	}
123 
124 	rAny <<= aRowSeq;
125 	return sal_True;
126 }
127 
128 //------------------------------------------------------------------------
129 
130 sal_Bool ScRangeToSequence::FillDoubleArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange )
131 {
132 	SCTAB nTab = rRange.aStart.Tab();
133 	SCCOL nStartCol = rRange.aStart.Col();
134 	SCROW nStartRow = rRange.aStart.Row();
135 	long nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
136 	long nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
137 
138 	uno::Sequence< uno::Sequence<double> > aRowSeq( nRowCount );
139 	uno::Sequence<double>* pRowAry = aRowSeq.getArray();
140 	for (long nRow = 0; nRow < nRowCount; nRow++)
141 	{
142 		uno::Sequence<double> aColSeq( nColCount );
143 		double* pColAry = aColSeq.getArray();
144 		for (long nCol = 0; nCol < nColCount; nCol++)
145 			pColAry[nCol] = pDoc->GetValue(
146 				ScAddress( (SCCOL)(nStartCol+nCol), (SCROW)(nStartRow+nRow), nTab ) );
147 
148 		pRowAry[nRow] = aColSeq;
149 	}
150 
151 	rAny <<= aRowSeq;
152     return !lcl_HasErrors( pDoc, rRange );
153 }
154 
155 
156 sal_Bool ScRangeToSequence::FillDoubleArray( uno::Any& rAny, const ScMatrix* pMatrix )
157 {
158 	if (!pMatrix)
159 		return sal_False;
160 
161 	SCSIZE nColCount;
162 	SCSIZE nRowCount;
163 	pMatrix->GetDimensions( nColCount, nRowCount );
164 
165 	uno::Sequence< uno::Sequence<double> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
166 	uno::Sequence<double>* pRowAry = aRowSeq.getArray();
167 	for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
168 	{
169 		uno::Sequence<double> aColSeq( static_cast<sal_Int32>(nColCount) );
170 		double* pColAry = aColSeq.getArray();
171 		for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
172 			if ( pMatrix->IsString( nCol, nRow ) )
173 				pColAry[nCol] = 0.0;
174 			else
175 				pColAry[nCol] = pMatrix->GetDouble( nCol, nRow );
176 
177 		pRowAry[nRow] = aColSeq;
178 	}
179 
180 	rAny <<= aRowSeq;
181 	return sal_True;
182 }
183 
184 //------------------------------------------------------------------------
185 
186 sal_Bool ScRangeToSequence::FillStringArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange )
187 {
188 	SCTAB nTab = rRange.aStart.Tab();
189 	SCCOL nStartCol = rRange.aStart.Col();
190 	SCROW nStartRow = rRange.aStart.Row();
191 	long nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
192 	long nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
193 
194     bool bHasErrors = false;
195 
196 	uno::Sequence< uno::Sequence<rtl::OUString> > aRowSeq( nRowCount );
197 	uno::Sequence<rtl::OUString>* pRowAry = aRowSeq.getArray();
198 	for (long nRow = 0; nRow < nRowCount; nRow++)
199 	{
200 		uno::Sequence<rtl::OUString> aColSeq( nColCount );
201 		rtl::OUString* pColAry = aColSeq.getArray();
202 		for (long nCol = 0; nCol < nColCount; nCol++)
203 		{
204             sal_uInt16 nErrCode = pDoc->GetStringForFormula(
205                         ScAddress((SCCOL)(nStartCol+nCol), (SCROW)(nStartRow+nRow), nTab),
206                         pColAry[nCol] );
207             if ( nErrCode != 0 )
208                 bHasErrors = true;
209 		}
210 		pRowAry[nRow] = aColSeq;
211 	}
212 
213 	rAny <<= aRowSeq;
214     return !bHasErrors;
215 }
216 
217 
218 sal_Bool ScRangeToSequence::FillStringArray( uno::Any& rAny, const ScMatrix* pMatrix,
219 											SvNumberFormatter* pFormatter )
220 {
221 	if (!pMatrix)
222 		return sal_False;
223 
224 	SCSIZE nColCount;
225 	SCSIZE nRowCount;
226 	pMatrix->GetDimensions( nColCount, nRowCount );
227 
228 	uno::Sequence< uno::Sequence<rtl::OUString> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
229 	uno::Sequence<rtl::OUString>* pRowAry = aRowSeq.getArray();
230 	for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
231 	{
232 		uno::Sequence<rtl::OUString> aColSeq( static_cast<sal_Int32>(nColCount) );
233 		rtl::OUString* pColAry = aColSeq.getArray();
234 		for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
235 		{
236 			String aStr;
237 			if ( pMatrix->IsString( nCol, nRow ) )
238 			{
239 				if ( !pMatrix->IsEmpty( nCol, nRow ) )
240 					aStr = pMatrix->GetString( nCol, nRow );
241 			}
242 			else if ( pFormatter )
243 			{
244 				double fVal = pMatrix->GetDouble( nCol, nRow );
245 				Color* pColor;
246 				pFormatter->GetOutputString( fVal, 0, aStr, &pColor );
247 			}
248 			pColAry[nCol] = rtl::OUString( aStr );
249 		}
250 
251 		pRowAry[nRow] = aColSeq;
252 	}
253 
254 	rAny <<= aRowSeq;
255 	return sal_True;
256 }
257 
258 //------------------------------------------------------------------------
259 
260 double lcl_GetValueFromCell( ScBaseCell& rCell )
261 {
262 	//!	ScBaseCell member function?
263 
264 	CellType eType = rCell.GetCellType();
265 	if ( eType == CELLTYPE_VALUE )
266 		return ((ScValueCell&)rCell).GetValue();
267 	else if ( eType == CELLTYPE_FORMULA )
268 		return ((ScFormulaCell&)rCell).GetValue();		// called only if result is value
269 
270 	DBG_ERROR( "GetValueFromCell: wrong type" );
271 	return 0;
272 }
273 
274 sal_Bool ScRangeToSequence::FillMixedArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange,
275 										sal_Bool bAllowNV )
276 {
277 	SCTAB nTab = rRange.aStart.Tab();
278 	SCCOL nStartCol = rRange.aStart.Col();
279 	SCROW nStartRow = rRange.aStart.Row();
280 	long nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col();
281 	long nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row();
282 
283 	String aDocStr;
284 	sal_Bool bHasErrors = sal_False;
285 
286 	uno::Sequence< uno::Sequence<uno::Any> > aRowSeq( nRowCount );
287 	uno::Sequence<uno::Any>* pRowAry = aRowSeq.getArray();
288 	for (long nRow = 0; nRow < nRowCount; nRow++)
289 	{
290 		uno::Sequence<uno::Any> aColSeq( nColCount );
291 		uno::Any* pColAry = aColSeq.getArray();
292 		for (long nCol = 0; nCol < nColCount; nCol++)
293 		{
294 			uno::Any& rElement = pColAry[nCol];
295 
296 			ScAddress aPos( (SCCOL)(nStartCol+nCol), (SCROW)(nStartRow+nRow), nTab );
297 			ScBaseCell* pCell = pDoc->GetCell( aPos );
298 			if ( pCell )
299 			{
300 				if ( pCell->GetCellType() == CELLTYPE_FORMULA &&
301 						((ScFormulaCell*)pCell)->GetErrCode() != 0 )
302 				{
303 					// if NV is allowed, leave empty for errors
304 					bHasErrors = sal_True;
305 				}
306 				else if ( pCell->HasValueData() )
307 					rElement <<= (double) lcl_GetValueFromCell( *pCell );
308 				else
309 					rElement <<= rtl::OUString( pCell->GetStringData() );
310 			}
311 			else
312 				rElement <<= rtl::OUString();		// empty: empty string
313 		}
314 		pRowAry[nRow] = aColSeq;
315 	}
316 
317 	rAny <<= aRowSeq;
318 	return bAllowNV || !bHasErrors;
319 }
320 
321 
322 sal_Bool ScRangeToSequence::FillMixedArray( uno::Any& rAny, const ScMatrix* pMatrix, bool bDataTypes )
323 {
324 	if (!pMatrix)
325 		return sal_False;
326 
327 	SCSIZE nColCount;
328 	SCSIZE nRowCount;
329 	pMatrix->GetDimensions( nColCount, nRowCount );
330 
331 	uno::Sequence< uno::Sequence<uno::Any> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
332 	uno::Sequence<uno::Any>* pRowAry = aRowSeq.getArray();
333 	for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
334 	{
335 		uno::Sequence<uno::Any> aColSeq( static_cast<sal_Int32>(nColCount) );
336 		uno::Any* pColAry = aColSeq.getArray();
337 		for (SCSIZE nCol = 0; nCol < nColCount; nCol++)
338 		{
339 			if ( pMatrix->IsString( nCol, nRow ) )
340 			{
341 				String aStr;
342 				if ( !pMatrix->IsEmpty( nCol, nRow ) )
343 					aStr = pMatrix->GetString( nCol, nRow );
344 				pColAry[nCol] <<= rtl::OUString( aStr );
345 			}
346 			else
347             {
348                 double fVal = pMatrix->GetDouble( nCol, nRow );
349                 if (bDataTypes && pMatrix->IsBoolean( nCol, nRow ))
350                     pColAry[nCol] <<= (fVal ? true : false);
351                 else
352                     pColAry[nCol] <<= fVal;
353             }
354 		}
355 
356 		pRowAry[nRow] = aColSeq;
357 	}
358 
359 	rAny <<= aRowSeq;
360 	return sal_True;
361 }
362 
363 //------------------------------------------------------------------------
364 
365 // static
366 bool ScApiTypeConversion::ConvertAnyToDouble( double & o_fVal,
367         com::sun::star::uno::TypeClass & o_eClass,
368         const com::sun::star::uno::Any & rAny )
369 {
370     bool bRet = false;
371     o_eClass = rAny.getValueTypeClass();
372     switch (o_eClass)
373     {
374         //! extract integer values
375         case uno::TypeClass_ENUM:
376         case uno::TypeClass_BOOLEAN:
377         case uno::TypeClass_CHAR:
378         case uno::TypeClass_BYTE:
379         case uno::TypeClass_SHORT:
380         case uno::TypeClass_UNSIGNED_SHORT:
381         case uno::TypeClass_LONG:
382         case uno::TypeClass_UNSIGNED_LONG:
383         case uno::TypeClass_FLOAT:
384         case uno::TypeClass_DOUBLE:
385             rAny >>= o_fVal;
386             bRet = true;
387             break;
388         default:
389             ;   // nothing, avoid warning
390     }
391     if (!bRet)
392         o_fVal = 0.0;
393     return bRet;
394 }
395 
396 //------------------------------------------------------------------------
397 
398 // static
399 ScMatrixRef ScSequenceToMatrix::CreateMixedMatrix( const com::sun::star::uno::Any & rAny )
400 {
401     ScMatrixRef xMatrix;
402     uno::Sequence< uno::Sequence< uno::Any > > aSequence;
403     if ( rAny >>= aSequence )
404     {
405         sal_Int32 nRowCount = aSequence.getLength();
406         const uno::Sequence<uno::Any>* pRowArr = aSequence.getConstArray();
407         sal_Int32 nMaxColCount = 0;
408         sal_Int32 nCol, nRow;
409         for (nRow=0; nRow<nRowCount; nRow++)
410         {
411             sal_Int32 nTmp = pRowArr[nRow].getLength();
412             if ( nTmp > nMaxColCount )
413                 nMaxColCount = nTmp;
414         }
415         if ( nMaxColCount && nRowCount )
416         {
417             rtl::OUString aUStr;
418             xMatrix = new ScMatrix(
419                     static_cast<SCSIZE>(nMaxColCount),
420                     static_cast<SCSIZE>(nRowCount) );
421             ScMatrix* pMatrix = xMatrix;
422             SCSIZE nCols, nRows;
423             pMatrix->GetDimensions( nCols, nRows);
424             if (nCols != static_cast<SCSIZE>(nMaxColCount) || nRows != static_cast<SCSIZE>(nRowCount))
425             {
426                 DBG_ERRORFILE( "ScSequenceToMatrix::CreateMixedMatrix: matrix exceeded max size, returning NULL matrix");
427                 return NULL;
428             }
429             for (nRow=0; nRow<nRowCount; nRow++)
430             {
431                 sal_Int32 nColCount = pRowArr[nRow].getLength();
432                 const uno::Any* pColArr = pRowArr[nRow].getConstArray();
433                 for (nCol=0; nCol<nColCount; nCol++)
434                 {
435                     double fVal;
436                     uno::TypeClass eClass;
437                     if (ScApiTypeConversion::ConvertAnyToDouble( fVal, eClass, pColArr[nCol]))
438                     {
439                         if (eClass == uno::TypeClass_BOOLEAN)
440                             pMatrix->PutBoolean( (fVal ? true : false),
441                                     static_cast<SCSIZE>(nCol),
442                                     static_cast<SCSIZE>(nRow) );
443                         else
444                             pMatrix->PutDouble( fVal,
445                                     static_cast<SCSIZE>(nCol),
446                                     static_cast<SCSIZE>(nRow) );
447                     }
448                     else
449                     {
450                         // Try string, else use empty as last resort.
451 
452                         //Reflection* pRefl = pColArr[nCol].getReflection();
453                         //if ( pRefl->equals( *OUString_getReflection() ) )
454                         if ( pColArr[nCol] >>= aUStr )
455                             pMatrix->PutString( String( aUStr ),
456                                     static_cast<SCSIZE>(nCol),
457                                     static_cast<SCSIZE>(nRow) );
458                         else
459                             pMatrix->PutEmpty(
460                                     static_cast<SCSIZE>(nCol),
461                                     static_cast<SCSIZE>(nRow) );
462                     }
463                 }
464                 for (nCol=nColCount; nCol<nMaxColCount; nCol++)
465                 {
466                     pMatrix->PutEmpty(
467                             static_cast<SCSIZE>(nCol),
468                             static_cast<SCSIZE>(nRow) );
469                 }
470             }
471         }
472     }
473     return xMatrix;
474 }
475 
476 
477 //------------------------------------------------------------------------
478 
479 sal_Bool ScByteSequenceToString::GetString( String& rString, const uno::Any& rAny,
480 										sal_uInt16 nEncoding )
481 {
482 	uno::Sequence<sal_Int8> aSeq;
483 	if ( rAny >>= aSeq )
484 	{
485 		rString = String( (const sal_Char*)aSeq.getConstArray(),
486 							(xub_StrLen)aSeq.getLength(), nEncoding );
487 		rString.EraseTrailingChars( (sal_Unicode) 0 );
488 		return sal_True;
489 	}
490 	return sal_False;
491 }
492 
493 //------------------------------------------------------------------------
494 
495