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