/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sc.hxx" #include #include #include #include #include #include "rangeseq.hxx" #include "document.hxx" #include "dociter.hxx" #include "scmatrix.hxx" #include "cell.hxx" using namespace com::sun::star; //------------------------------------------------------------------------ bool lcl_HasErrors( ScDocument* pDoc, const ScRange& rRange ) { // no need to look at empty cells - just use ScCellIterator ScCellIterator aIter( pDoc, rRange ); ScBaseCell* pCell = aIter.GetFirst(); while (pCell) { if ( pCell->GetCellType() == CELLTYPE_FORMULA && static_cast(pCell)->GetErrCode() != 0 ) return true; pCell = aIter.GetNext(); } return false; // no error found } long lcl_DoubleToLong( double fVal ) { double fInt = (fVal >= 0.0) ? ::rtl::math::approxFloor( fVal ) : ::rtl::math::approxCeil( fVal ); if ( fInt >= LONG_MIN && fInt <= LONG_MAX ) return (long)fInt; else return 0; // out of range } sal_Bool ScRangeToSequence::FillLongArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange ) { SCTAB nTab = rRange.aStart.Tab(); SCCOL nStartCol = rRange.aStart.Col(); SCROW nStartRow = rRange.aStart.Row(); long nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col(); long nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row(); uno::Sequence< uno::Sequence > aRowSeq( nRowCount ); uno::Sequence* pRowAry = aRowSeq.getArray(); for (long nRow = 0; nRow < nRowCount; nRow++) { uno::Sequence aColSeq( nColCount ); sal_Int32* pColAry = aColSeq.getArray(); for (long nCol = 0; nCol < nColCount; nCol++) pColAry[nCol] = lcl_DoubleToLong( pDoc->GetValue( ScAddress( (SCCOL)(nStartCol+nCol), (SCROW)(nStartRow+nRow), nTab ) ) ); pRowAry[nRow] = aColSeq; } rAny <<= aRowSeq; return !lcl_HasErrors( pDoc, rRange ); } sal_Bool ScRangeToSequence::FillLongArray( uno::Any& rAny, const ScMatrix* pMatrix ) { if (!pMatrix) return sal_False; SCSIZE nColCount; SCSIZE nRowCount; pMatrix->GetDimensions( nColCount, nRowCount ); uno::Sequence< uno::Sequence > aRowSeq( static_cast(nRowCount) ); uno::Sequence* pRowAry = aRowSeq.getArray(); for (SCSIZE nRow = 0; nRow < nRowCount; nRow++) { uno::Sequence aColSeq( static_cast(nColCount) ); sal_Int32* pColAry = aColSeq.getArray(); for (SCSIZE nCol = 0; nCol < nColCount; nCol++) if ( pMatrix->IsString( nCol, nRow ) ) pColAry[nCol] = 0; else pColAry[nCol] = lcl_DoubleToLong( pMatrix->GetDouble( nCol, nRow ) ); pRowAry[nRow] = aColSeq; } rAny <<= aRowSeq; return sal_True; } //------------------------------------------------------------------------ sal_Bool ScRangeToSequence::FillDoubleArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange ) { SCTAB nTab = rRange.aStart.Tab(); SCCOL nStartCol = rRange.aStart.Col(); SCROW nStartRow = rRange.aStart.Row(); long nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col(); long nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row(); uno::Sequence< uno::Sequence > aRowSeq( nRowCount ); uno::Sequence* pRowAry = aRowSeq.getArray(); for (long nRow = 0; nRow < nRowCount; nRow++) { uno::Sequence aColSeq( nColCount ); double* pColAry = aColSeq.getArray(); for (long nCol = 0; nCol < nColCount; nCol++) pColAry[nCol] = pDoc->GetValue( ScAddress( (SCCOL)(nStartCol+nCol), (SCROW)(nStartRow+nRow), nTab ) ); pRowAry[nRow] = aColSeq; } rAny <<= aRowSeq; return !lcl_HasErrors( pDoc, rRange ); } sal_Bool ScRangeToSequence::FillDoubleArray( uno::Any& rAny, const ScMatrix* pMatrix ) { if (!pMatrix) return sal_False; SCSIZE nColCount; SCSIZE nRowCount; pMatrix->GetDimensions( nColCount, nRowCount ); uno::Sequence< uno::Sequence > aRowSeq( static_cast(nRowCount) ); uno::Sequence* pRowAry = aRowSeq.getArray(); for (SCSIZE nRow = 0; nRow < nRowCount; nRow++) { uno::Sequence aColSeq( static_cast(nColCount) ); double* pColAry = aColSeq.getArray(); for (SCSIZE nCol = 0; nCol < nColCount; nCol++) if ( pMatrix->IsString( nCol, nRow ) ) pColAry[nCol] = 0.0; else pColAry[nCol] = pMatrix->GetDouble( nCol, nRow ); pRowAry[nRow] = aColSeq; } rAny <<= aRowSeq; return sal_True; } //------------------------------------------------------------------------ sal_Bool ScRangeToSequence::FillStringArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange ) { SCTAB nTab = rRange.aStart.Tab(); SCCOL nStartCol = rRange.aStart.Col(); SCROW nStartRow = rRange.aStart.Row(); long nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col(); long nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row(); bool bHasErrors = false; uno::Sequence< uno::Sequence > aRowSeq( nRowCount ); uno::Sequence* pRowAry = aRowSeq.getArray(); for (long nRow = 0; nRow < nRowCount; nRow++) { uno::Sequence aColSeq( nColCount ); rtl::OUString* pColAry = aColSeq.getArray(); for (long nCol = 0; nCol < nColCount; nCol++) { sal_uInt16 nErrCode = pDoc->GetStringForFormula( ScAddress((SCCOL)(nStartCol+nCol), (SCROW)(nStartRow+nRow), nTab), pColAry[nCol] ); if ( nErrCode != 0 ) bHasErrors = true; } pRowAry[nRow] = aColSeq; } rAny <<= aRowSeq; return !bHasErrors; } sal_Bool ScRangeToSequence::FillStringArray( uno::Any& rAny, const ScMatrix* pMatrix, SvNumberFormatter* pFormatter ) { if (!pMatrix) return sal_False; SCSIZE nColCount; SCSIZE nRowCount; pMatrix->GetDimensions( nColCount, nRowCount ); uno::Sequence< uno::Sequence > aRowSeq( static_cast(nRowCount) ); uno::Sequence* pRowAry = aRowSeq.getArray(); for (SCSIZE nRow = 0; nRow < nRowCount; nRow++) { uno::Sequence aColSeq( static_cast(nColCount) ); rtl::OUString* pColAry = aColSeq.getArray(); for (SCSIZE nCol = 0; nCol < nColCount; nCol++) { String aStr; if ( pMatrix->IsString( nCol, nRow ) ) { if ( !pMatrix->IsEmpty( nCol, nRow ) ) aStr = pMatrix->GetString( nCol, nRow ); } else if ( pFormatter ) { double fVal = pMatrix->GetDouble( nCol, nRow ); Color* pColor; pFormatter->GetOutputString( fVal, 0, aStr, &pColor ); } pColAry[nCol] = rtl::OUString( aStr ); } pRowAry[nRow] = aColSeq; } rAny <<= aRowSeq; return sal_True; } //------------------------------------------------------------------------ double lcl_GetValueFromCell( ScBaseCell& rCell ) { //! ScBaseCell member function? CellType eType = rCell.GetCellType(); if ( eType == CELLTYPE_VALUE ) return ((ScValueCell&)rCell).GetValue(); else if ( eType == CELLTYPE_FORMULA ) return ((ScFormulaCell&)rCell).GetValue(); // called only if result is value DBG_ERROR( "GetValueFromCell: wrong type" ); return 0; } sal_Bool ScRangeToSequence::FillMixedArray( uno::Any& rAny, ScDocument* pDoc, const ScRange& rRange, sal_Bool bAllowNV ) { SCTAB nTab = rRange.aStart.Tab(); SCCOL nStartCol = rRange.aStart.Col(); SCROW nStartRow = rRange.aStart.Row(); long nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col(); long nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row(); String aDocStr; sal_Bool bHasErrors = sal_False; uno::Sequence< uno::Sequence > aRowSeq( nRowCount ); uno::Sequence* pRowAry = aRowSeq.getArray(); for (long nRow = 0; nRow < nRowCount; nRow++) { uno::Sequence aColSeq( nColCount ); uno::Any* pColAry = aColSeq.getArray(); for (long nCol = 0; nCol < nColCount; nCol++) { uno::Any& rElement = pColAry[nCol]; ScAddress aPos( (SCCOL)(nStartCol+nCol), (SCROW)(nStartRow+nRow), nTab ); ScBaseCell* pCell = pDoc->GetCell( aPos ); if ( pCell ) { if ( pCell->GetCellType() == CELLTYPE_FORMULA && ((ScFormulaCell*)pCell)->GetErrCode() != 0 ) { // if NV is allowed, leave empty for errors bHasErrors = sal_True; } else if ( pCell->HasValueData() ) rElement <<= (double) lcl_GetValueFromCell( *pCell ); else rElement <<= rtl::OUString( pCell->GetStringData() ); } else rElement <<= rtl::OUString(); // empty: empty string } pRowAry[nRow] = aColSeq; } rAny <<= aRowSeq; return bAllowNV || !bHasErrors; } sal_Bool ScRangeToSequence::FillMixedArray( uno::Any& rAny, const ScMatrix* pMatrix, bool bDataTypes ) { if (!pMatrix) return sal_False; SCSIZE nColCount; SCSIZE nRowCount; pMatrix->GetDimensions( nColCount, nRowCount ); uno::Sequence< uno::Sequence > aRowSeq( static_cast(nRowCount) ); uno::Sequence* pRowAry = aRowSeq.getArray(); for (SCSIZE nRow = 0; nRow < nRowCount; nRow++) { uno::Sequence aColSeq( static_cast(nColCount) ); uno::Any* pColAry = aColSeq.getArray(); for (SCSIZE nCol = 0; nCol < nColCount; nCol++) { if ( pMatrix->IsString( nCol, nRow ) ) { String aStr; if ( !pMatrix->IsEmpty( nCol, nRow ) ) aStr = pMatrix->GetString( nCol, nRow ); pColAry[nCol] <<= rtl::OUString( aStr ); } else { double fVal = pMatrix->GetDouble( nCol, nRow ); if (bDataTypes && pMatrix->IsBoolean( nCol, nRow )) pColAry[nCol] <<= (fVal ? true : false); else pColAry[nCol] <<= fVal; } } pRowAry[nRow] = aColSeq; } rAny <<= aRowSeq; return sal_True; } //------------------------------------------------------------------------ // static bool ScApiTypeConversion::ConvertAnyToDouble( double & o_fVal, com::sun::star::uno::TypeClass & o_eClass, const com::sun::star::uno::Any & rAny ) { bool bRet = false; o_eClass = rAny.getValueTypeClass(); switch (o_eClass) { //! extract integer values case uno::TypeClass_ENUM: case uno::TypeClass_BOOLEAN: case uno::TypeClass_CHAR: case uno::TypeClass_BYTE: case uno::TypeClass_SHORT: case uno::TypeClass_UNSIGNED_SHORT: case uno::TypeClass_LONG: case uno::TypeClass_UNSIGNED_LONG: case uno::TypeClass_FLOAT: case uno::TypeClass_DOUBLE: rAny >>= o_fVal; bRet = true; break; default: ; // nothing, avoid warning } if (!bRet) o_fVal = 0.0; return bRet; } //------------------------------------------------------------------------ // static ScMatrixRef ScSequenceToMatrix::CreateMixedMatrix( const com::sun::star::uno::Any & rAny ) { ScMatrixRef xMatrix; uno::Sequence< uno::Sequence< uno::Any > > aSequence; if ( rAny >>= aSequence ) { sal_Int32 nRowCount = aSequence.getLength(); const uno::Sequence* pRowArr = aSequence.getConstArray(); sal_Int32 nMaxColCount = 0; sal_Int32 nCol, nRow; for (nRow=0; nRow nMaxColCount ) nMaxColCount = nTmp; } if ( nMaxColCount && nRowCount ) { rtl::OUString aUStr; xMatrix = new ScMatrix( static_cast(nMaxColCount), static_cast(nRowCount) ); ScMatrix* pMatrix = xMatrix; SCSIZE nCols, nRows; pMatrix->GetDimensions( nCols, nRows); if (nCols != static_cast(nMaxColCount) || nRows != static_cast(nRowCount)) { DBG_ERRORFILE( "ScSequenceToMatrix::CreateMixedMatrix: matrix exceeded max size, returning NULL matrix"); return NULL; } for (nRow=0; nRowPutBoolean( (fVal ? true : false), static_cast(nCol), static_cast(nRow) ); else pMatrix->PutDouble( fVal, static_cast(nCol), static_cast(nRow) ); } else { // Try string, else use empty as last resort. //Reflection* pRefl = pColArr[nCol].getReflection(); //if ( pRefl->equals( *OUString_getReflection() ) ) if ( pColArr[nCol] >>= aUStr ) pMatrix->PutString( String( aUStr ), static_cast(nCol), static_cast(nRow) ); else pMatrix->PutEmpty( static_cast(nCol), static_cast(nRow) ); } } for (nCol=nColCount; nColPutEmpty( static_cast(nCol), static_cast(nRow) ); } } } } return xMatrix; } //------------------------------------------------------------------------ sal_Bool ScByteSequenceToString::GetString( String& rString, const uno::Any& rAny, sal_uInt16 nEncoding ) { uno::Sequence aSeq; if ( rAny >>= aSeq ) { rString = String( (const sal_Char*)aSeq.getConstArray(), (xub_StrLen)aSeq.getLength(), nEncoding ); rString.EraseTrailingChars( (sal_Unicode) 0 ); return sal_True; } return sal_False; } //------------------------------------------------------------------------