/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 . */ #include #include #include #include #include #include #include #include #include #include #include #include using namespace com::sun::star; static bool lcl_HasErrors( ScDocument& rDoc, const ScRange& rRange ) { // no need to look at empty cells - just use ScCellIterator ScCellIterator aIter( rDoc, rRange ); for (bool bHas = aIter.first(); bHas; bHas = aIter.next()) { if (aIter.getType() != CELLTYPE_FORMULA) continue; ScFormulaCell* pCell = aIter.getFormulaCell(); if (pCell->GetErrCode() != FormulaError::NONE) return true; } return false; // no error found } static tools::Long lcl_DoubleToLong( double fVal ) { double fInt = (fVal >= 0.0) ? ::rtl::math::approxFloor( fVal ) : ::rtl::math::approxCeil( fVal ); if ( o3tl::convertsToAtLeast(fInt, LONG_MIN) && o3tl::convertsToAtMost(fInt, LONG_MAX) ) return static_cast(fInt); else return 0; // out of range } bool ScRangeToSequence::FillLongArray( uno::Any& rAny, ScDocument& rDoc, const ScRange& rRange ) { SCTAB nTab = rRange.aStart.Tab(); SCCOL nStartCol = rRange.aStart.Col(); SCROW nStartRow = rRange.aStart.Row(); sal_Int32 nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col(); sal_Int32 nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row(); uno::Sequence< uno::Sequence > aRowSeq( nRowCount ); uno::Sequence* pRowAry = aRowSeq.getArray(); for (sal_Int32 nRow = 0; nRow < nRowCount; nRow++) { uno::Sequence aColSeq( nColCount ); sal_Int32* pColAry = aColSeq.getArray(); for (sal_Int32 nCol = 0; nCol < nColCount; nCol++) pColAry[nCol] = lcl_DoubleToLong( rDoc.GetValue( ScAddress( static_cast(nStartCol+nCol), static_cast(nStartRow+nRow), nTab ) ) ); pRowAry[nRow] = aColSeq; } rAny <<= aRowSeq; return !lcl_HasErrors( rDoc, rRange ); } bool ScRangeToSequence::FillLongArray( uno::Any& rAny, const ScMatrix* pMatrix ) { if (!pMatrix) return 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->IsStringOrEmpty( nCol, nRow ) ) pColAry[nCol] = 0; else pColAry[nCol] = lcl_DoubleToLong( pMatrix->GetDouble( nCol, nRow ) ); pRowAry[nRow] = aColSeq; } rAny <<= aRowSeq; return true; } bool ScRangeToSequence::FillDoubleArray( uno::Any& rAny, ScDocument& rDoc, const ScRange& rRange ) { SCTAB nTab = rRange.aStart.Tab(); SCCOL nStartCol = rRange.aStart.Col(); SCROW nStartRow = rRange.aStart.Row(); sal_Int32 nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col(); sal_Int32 nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row(); uno::Sequence< uno::Sequence > aRowSeq( nRowCount ); uno::Sequence* pRowAry = aRowSeq.getArray(); for (sal_Int32 nRow = 0; nRow < nRowCount; nRow++) { uno::Sequence aColSeq( nColCount ); double* pColAry = aColSeq.getArray(); for (sal_Int32 nCol = 0; nCol < nColCount; nCol++) pColAry[nCol] = rDoc.GetValue( ScAddress( static_cast(nStartCol+nCol), static_cast(nStartRow+nRow), nTab ) ); pRowAry[nRow] = aColSeq; } rAny <<= aRowSeq; return !lcl_HasErrors( rDoc, rRange ); } bool ScRangeToSequence::FillDoubleArray( uno::Any& rAny, const ScMatrix* pMatrix ) { if (!pMatrix) return 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->IsStringOrEmpty( nCol, nRow ) ) pColAry[nCol] = 0.0; else pColAry[nCol] = pMatrix->GetDouble( nCol, nRow ); pRowAry[nRow] = aColSeq; } rAny <<= aRowSeq; return true; } bool ScRangeToSequence::FillStringArray( uno::Any& rAny, ScDocument& rDoc, const ScRange& rRange ) { SCTAB nTab = rRange.aStart.Tab(); SCCOL nStartCol = rRange.aStart.Col(); SCROW nStartRow = rRange.aStart.Row(); sal_Int32 nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col(); sal_Int32 nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row(); bool bHasErrors = false; uno::Sequence< uno::Sequence > aRowSeq( nRowCount ); uno::Sequence* pRowAry = aRowSeq.getArray(); for (sal_Int32 nRow = 0; nRow < nRowCount; nRow++) { uno::Sequence aColSeq( nColCount ); OUString* pColAry = aColSeq.getArray(); for (sal_Int32 nCol = 0; nCol < nColCount; nCol++) { FormulaError nErrCode = rDoc.GetStringForFormula( ScAddress(static_cast(nStartCol+nCol), static_cast(nStartRow+nRow), nTab), pColAry[nCol] ); if ( nErrCode != FormulaError::NONE ) bHasErrors = true; } pRowAry[nRow] = aColSeq; } rAny <<= aRowSeq; return !bHasErrors; } bool ScRangeToSequence::FillStringArray( uno::Any& rAny, const ScMatrix* pMatrix, SvNumberFormatter* pFormatter ) { if (!pMatrix) return 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) ); OUString* pColAry = aColSeq.getArray(); for (SCSIZE nCol = 0; nCol < nColCount; nCol++) { OUString aStr; if ( pMatrix->IsStringOrEmpty( nCol, nRow ) ) { if ( !pMatrix->IsEmpty( nCol, nRow ) ) aStr = pMatrix->GetString(nCol, nRow).getString(); } else if ( pFormatter ) { double fVal = pMatrix->GetDouble( nCol, nRow ); const Color* pColor; pFormatter->GetOutputString( fVal, 0, aStr, &pColor ); } pColAry[nCol] = aStr; } pRowAry[nRow] = aColSeq; } rAny <<= aRowSeq; return true; } bool ScRangeToSequence::FillMixedArray( uno::Any& rAny, ScDocument& rDoc, const ScRange& rRange, bool bAllowNV ) { SCTAB nTab = rRange.aStart.Tab(); SCCOL nStartCol = rRange.aStart.Col(); SCROW nStartRow = rRange.aStart.Row(); sal_Int32 nColCount = rRange.aEnd.Col() + 1 - rRange.aStart.Col(); sal_Int32 nRowCount = rRange.aEnd.Row() + 1 - rRange.aStart.Row(); bool bHasErrors = false; uno::Sequence< uno::Sequence > aRowSeq( nRowCount ); uno::Sequence* pRowAry = aRowSeq.getArray(); for (sal_Int32 nRow = 0; nRow < nRowCount; nRow++) { uno::Sequence aColSeq( nColCount ); uno::Any* pColAry = aColSeq.getArray(); for (sal_Int32 nCol = 0; nCol < nColCount; nCol++) { uno::Any& rElement = pColAry[nCol]; ScAddress aPos( static_cast(nStartCol+nCol), static_cast(nStartRow+nRow), nTab ); ScRefCellValue aCell(rDoc, aPos); if (aCell.isEmpty()) { rElement <<= EMPTY_OUSTRING; continue; } if (aCell.meType == CELLTYPE_FORMULA && aCell.mpFormula->GetErrCode() != FormulaError::NONE) { // if NV is allowed, leave empty for errors bHasErrors = true; } else if (aCell.hasNumeric()) rElement <<= aCell.getValue(); else rElement <<= aCell.getString(&rDoc); } pRowAry[nRow] = aColSeq; } rAny <<= aRowSeq; return bAllowNV || !bHasErrors; } bool ScRangeToSequence::FillMixedArray( uno::Any& rAny, const ScMatrix* pMatrix, bool bDataTypes ) { if (!pMatrix) return 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->IsStringOrEmpty( nCol, nRow ) ) { OUString aStr; if ( !pMatrix->IsEmpty( nCol, nRow ) ) aStr = pMatrix->GetString(nCol, nRow).getString(); pColAry[nCol] <<= aStr; } else { double fVal = pMatrix->GetDouble( nCol, nRow ); if (bDataTypes && pMatrix->IsBoolean( nCol, nRow )) pColAry[nCol] <<= fVal != 0.0; else pColAry[nCol] <<= fVal; } } pRowAry[nRow] = aColSeq; } rAny <<= aRowSeq; return true; } bool ScApiTypeConversion::ConvertAnyToDouble( double & o_fVal, css::uno::TypeClass & o_eClass, const css::uno::Any & rAny ) { bool bRet = false; o_eClass = rAny.getValueTypeClass(); switch (o_eClass) { //TODO: 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; } ScMatrixRef ScSequenceToMatrix::CreateMixedMatrix( const css::uno::Any & rAny ) { ScMatrixRef xMatrix; uno::Sequence< uno::Sequence< uno::Any > > aSequence; if ( rAny >>= aSequence ) { sal_Int32 nRowCount = aSequence.getLength(); sal_Int32 nMaxColCount = 0; if (nRowCount) { auto pRow = std::max_element(aSequence.begin(), aSequence.end(), [](const uno::Sequence& a, const uno::Sequence& b) { return a.getLength() < b.getLength(); }); nMaxColCount = pRow->getLength(); } if ( nMaxColCount && nRowCount ) { const uno::Sequence* pRowArr = aSequence.getConstArray(); OUString aUStr; xMatrix = new ScMatrix( static_cast(nMaxColCount), static_cast(nRowCount), 0.0); SCSIZE nCols, nRows; xMatrix->GetDimensions( nCols, nRows); if (nCols != static_cast(nMaxColCount) || nRows != static_cast(nRowCount)) { OSL_FAIL( "ScSequenceToMatrix::CreateMixedMatrix: matrix exceeded max size, returning NULL matrix"); return nullptr; } for (sal_Int32 nRow=0; nRowPutBoolean( fVal != 0.0, static_cast(nCol), static_cast(nRow) ); else xMatrix->PutDouble( fVal, static_cast(nCol), static_cast(nRow) ); } else { // Try string, else use empty as last resort. if ( pColArr[nCol] >>= aUStr ) { xMatrix->PutString( svl::SharedString(aUStr), static_cast(nCol), static_cast(nRow)); } else xMatrix->PutEmpty( static_cast(nCol), static_cast(nRow) ); } } for (sal_Int32 nCol=nColCount; nColPutEmpty( static_cast(nCol), static_cast(nRow) ); } } } } return xMatrix; } bool ScByteSequenceToString::GetString( OUString& rString, const uno::Any& rAny, sal_uInt16 nEncoding ) { uno::Sequence aSeq; if ( rAny >>= aSeq ) { rString = OUString( reinterpret_cast(aSeq.getConstArray()), aSeq.getLength(), nEncoding ); rString = comphelper::string::stripEnd(rString, 0); return true; } return false; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */