blob: bce3197f5174da26e4669829d69cf55cedac0315 [file] [log] [blame]
/**************************************************************
*
* 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 <svl/zforlist.hxx>
#include <rtl/math.hxx>
#include <tools/debug.hxx>
#include <com/sun/star/uno/Any.hxx>
#include <com/sun/star/uno/Sequence.hxx>
#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<ScFormulaCell*>(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<sal_Int32> > aRowSeq( nRowCount );
uno::Sequence<sal_Int32>* pRowAry = aRowSeq.getArray();
for (long nRow = 0; nRow < nRowCount; nRow++)
{
uno::Sequence<sal_Int32> 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<sal_Int32> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
uno::Sequence<sal_Int32>* pRowAry = aRowSeq.getArray();
for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
{
uno::Sequence<sal_Int32> aColSeq( static_cast<sal_Int32>(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<double> > aRowSeq( nRowCount );
uno::Sequence<double>* pRowAry = aRowSeq.getArray();
for (long nRow = 0; nRow < nRowCount; nRow++)
{
uno::Sequence<double> 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<double> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
uno::Sequence<double>* pRowAry = aRowSeq.getArray();
for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
{
uno::Sequence<double> aColSeq( static_cast<sal_Int32>(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<rtl::OUString> > aRowSeq( nRowCount );
uno::Sequence<rtl::OUString>* pRowAry = aRowSeq.getArray();
for (long nRow = 0; nRow < nRowCount; nRow++)
{
uno::Sequence<rtl::OUString> 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<rtl::OUString> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
uno::Sequence<rtl::OUString>* pRowAry = aRowSeq.getArray();
for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
{
uno::Sequence<rtl::OUString> aColSeq( static_cast<sal_Int32>(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<uno::Any> > aRowSeq( nRowCount );
uno::Sequence<uno::Any>* pRowAry = aRowSeq.getArray();
for (long nRow = 0; nRow < nRowCount; nRow++)
{
uno::Sequence<uno::Any> 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<uno::Any> > aRowSeq( static_cast<sal_Int32>(nRowCount) );
uno::Sequence<uno::Any>* pRowAry = aRowSeq.getArray();
for (SCSIZE nRow = 0; nRow < nRowCount; nRow++)
{
uno::Sequence<uno::Any> aColSeq( static_cast<sal_Int32>(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<uno::Any>* pRowArr = aSequence.getConstArray();
sal_Int32 nMaxColCount = 0;
sal_Int32 nCol, nRow;
for (nRow=0; nRow<nRowCount; nRow++)
{
sal_Int32 nTmp = pRowArr[nRow].getLength();
if ( nTmp > nMaxColCount )
nMaxColCount = nTmp;
}
if ( nMaxColCount && nRowCount )
{
rtl::OUString aUStr;
xMatrix = new ScMatrix(
static_cast<SCSIZE>(nMaxColCount),
static_cast<SCSIZE>(nRowCount) );
ScMatrix* pMatrix = xMatrix;
SCSIZE nCols, nRows;
pMatrix->GetDimensions( nCols, nRows);
if (nCols != static_cast<SCSIZE>(nMaxColCount) || nRows != static_cast<SCSIZE>(nRowCount))
{
DBG_ERRORFILE( "ScSequenceToMatrix::CreateMixedMatrix: matrix exceeded max size, returning NULL matrix");
return NULL;
}
for (nRow=0; nRow<nRowCount; nRow++)
{
sal_Int32 nColCount = pRowArr[nRow].getLength();
const uno::Any* pColArr = pRowArr[nRow].getConstArray();
for (nCol=0; nCol<nColCount; nCol++)
{
double fVal;
uno::TypeClass eClass;
if (ScApiTypeConversion::ConvertAnyToDouble( fVal, eClass, pColArr[nCol]))
{
if (eClass == uno::TypeClass_BOOLEAN)
pMatrix->PutBoolean( (fVal ? true : false),
static_cast<SCSIZE>(nCol),
static_cast<SCSIZE>(nRow) );
else
pMatrix->PutDouble( fVal,
static_cast<SCSIZE>(nCol),
static_cast<SCSIZE>(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<SCSIZE>(nCol),
static_cast<SCSIZE>(nRow) );
else
pMatrix->PutEmpty(
static_cast<SCSIZE>(nCol),
static_cast<SCSIZE>(nRow) );
}
}
for (nCol=nColCount; nCol<nMaxColCount; nCol++)
{
pMatrix->PutEmpty(
static_cast<SCSIZE>(nCol),
static_cast<SCSIZE>(nRow) );
}
}
}
}
return xMatrix;
}
//------------------------------------------------------------------------
sal_Bool ScByteSequenceToString::GetString( String& rString, const uno::Any& rAny,
sal_uInt16 nEncoding )
{
uno::Sequence<sal_Int8> 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;
}
//------------------------------------------------------------------------