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