xref: /trunk/main/sc/source/core/tool/rangeseq.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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