diff options
-rw-r--r-- | sc/inc/column.hxx | 1 | ||||
-rw-r--r-- | sc/source/core/data/column.cxx | 56 | ||||
-rw-r--r-- | sc/source/core/tool/interpr1.cxx | 219 |
3 files changed, 236 insertions, 40 deletions
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index 7ce53ade706c..359b8ac6f322 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -409,6 +409,7 @@ public: void ClearSelectionItems( const sal_uInt16* pWhich, const ScMarkData& rMark ); void ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark ); + double SumNumericCells( sc::ColumnBlockConstPosition& rPos, SCROW nRow1, SCROW nRow2 ) const; size_t CountNumericCells( sc::ColumnBlockConstPosition& rPos, SCROW nRow1, SCROW nRow2 ) const; long GetNeededSize( diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index 8d3f62508bc3..64aae039a853 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -468,18 +468,57 @@ void ScColumn::ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark ) namespace { +class NumericCellAccumulator +{ + double mfSum; +public: + NumericCellAccumulator() : mfSum(0.0) {} + + void operator() (size_t, double fVal) + { + mfSum += fVal; + } + + void operator() (size_t, const ScFormulaCell* pCell) + { + ScFormulaCell& rCell = const_cast<ScFormulaCell&>(*pCell); + if (rCell.IsValue()) + mfSum += rCell.GetValue(); + } + + double getSum() const { return mfSum; } +}; + class NumericCellCounter { size_t mnCount; public: NumericCellCounter() : mnCount(0) {} - void operator() (const sc::CellStoreType::value_type& rNode, size_t /*nOffset*/, size_t nDataSize) + void operator() (const sc::CellStoreType::value_type& rNode, size_t nOffset, size_t nDataSize) { - if (rNode.type != sc::element_type_numeric) - return; - - mnCount += nDataSize; + switch (rNode.type) + { + case sc::element_type_numeric: + mnCount += nDataSize; + break; + case sc::element_type_formula: + { + sc::formula_block::const_iterator it = sc::formula_block::begin(*rNode.data); + std::advance(it, nOffset); + sc::formula_block::const_iterator itEnd = it; + std::advance(itEnd, nDataSize); + for (; it != itEnd; ++it) + { + ScFormulaCell& rCell = const_cast<ScFormulaCell&>(**it); + if (rCell.IsValue()) + ++mnCount; + } + } + break; + default: + ; + } } size_t getCount() const { return mnCount; } @@ -487,6 +526,13 @@ public: } +double ScColumn::SumNumericCells( sc::ColumnBlockConstPosition& rPos, SCROW nRow1, SCROW nRow2 ) const +{ + NumericCellAccumulator aFunc; + rPos.miCellPos = sc::ParseFormulaNumeric(rPos.miCellPos, maCells, nRow1, nRow2, aFunc); + return aFunc.getSum(); +} + size_t ScColumn::CountNumericCells( sc::ColumnBlockConstPosition& rPos, SCROW nRow1, SCROW nRow2 ) const { NumericCellCounter aFunc; diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx index 643a0aa3d321..93bcfef1440a 100644 --- a/sc/source/core/tool/interpr1.cxx +++ b/sc/source/core/tool/interpr1.cxx @@ -3854,6 +3854,64 @@ void ScInterpreter::ScMax( bool bTextAsZero ) namespace { +class FuncCount : public sc::ColumnSpanSet::ColumnAction +{ + sc::ColumnBlockConstPosition maPos; + ScColumn* mpCol; + size_t mnCount; + sal_uInt32 mnNumFmt; + +public: + FuncCount() : mnCount(0), mnNumFmt(0) {} + + virtual void startColumn(ScColumn* pCol) + { + mpCol = pCol; + mpCol->InitBlockPosition(maPos); + } + + virtual void execute(SCROW nRow1, SCROW nRow2, bool bVal) + { + if (!bVal) + return; + + mnCount += mpCol->CountNumericCells(maPos, nRow1, nRow2); + mnNumFmt = mpCol->GetNumberFormat(nRow2); + }; + + size_t getCount() const { return mnCount; } + sal_uInt32 getNumberFormat() const { return mnNumFmt; } +}; + +class FuncSum : public sc::ColumnSpanSet::ColumnAction +{ + sc::ColumnBlockConstPosition maPos; + ScColumn* mpCol; + double mfSum; + sal_uInt32 mnNumFmt; + +public: + FuncSum() : mfSum(0.0), mnNumFmt(0) {} + + virtual void startColumn(ScColumn* pCol) + { + mpCol = pCol; + mpCol->InitBlockPosition(maPos); + } + + virtual void execute(SCROW nRow1, SCROW nRow2, bool bVal) + { + if (!bVal) + return; + + mfSum += mpCol->SumNumericCells(maPos, nRow1, nRow2); + mnNumFmt = mpCol->GetNumberFormat(nRow2); + }; + + double getSum() const { return mfSum; } + sal_uInt32 getNumberFormat() const { return mnNumFmt; } +}; + void IterateMatrix( const ScMatrixRef& pMat, ScIterFunc eFunc, bool bTextAsZero, sal_uLong& rCount, short& rFuncFmtType, double& fRes, double& fMem, bool& bNull) @@ -4258,8 +4316,132 @@ void ScInterpreter::ScSumSQ() void ScInterpreter::ScSum() { - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSum" ); - PushDouble( IterateParameters( ifSUM ) ); + short nParamCount = GetByte(); + double fRes = 0.0; + double fVal = 0.0; + ScAddress aAdr; + ScRange aRange; + size_t nRefInList = 0; + while (nParamCount-- > 0) + { + switch (GetStackType()) + { + case svString: + { + while (nParamCount-- > 0) + Pop(); + SetError( errNoValue ); + } + break; + case svDouble : + fVal = GetDouble(); + fRes += fVal; + nFuncFmtType = NUMBERFORMAT_NUMBER; + break; + case svExternalSingleRef: + { + ScExternalRefCache::TokenRef pToken; + ScExternalRefCache::CellFormat aFmt; + PopExternalSingleRef(pToken, &aFmt); + + if (!pToken) + break; + + StackVar eType = pToken->GetType(); + if (eType == formula::svDouble) + { + fVal = pToken->GetDouble(); + if (aFmt.mbIsSet) + { + nFuncFmtType = aFmt.mnType; + nFuncFmtIndex = aFmt.mnIndex; + } + + fRes += fVal; + } + } + break; + case svSingleRef : + { + PopSingleRef( aAdr ); + + if (glSubTotal && pDok->RowFiltered( aAdr.Row(), aAdr.Tab())) + { + break; + } + ScRefCellValue aCell; + aCell.assign(*pDok, aAdr); + if (!aCell.isEmpty()) + { + if (aCell.hasNumeric()) + { + fVal = GetCellValue(aAdr, aCell); + CurFmtToFuncFmt(); + fRes += fVal; + } + } + } + break; + case svDoubleRef : + case svRefList : + { + PopDoubleRef( aRange, nParamCount, nRefInList); + + sc::ColumnSpanSet aSet(false); + aSet.set(aRange, true); + if (glSubTotal) + // Skip all filtered rows and subtotal formula cells. + pDok->MarkSubTotalCells(aSet, aRange, false); + + FuncSum aAction; + aSet.executeColumnAction(*pDok, aAction); + fRes = aAction.getSum(); + + // Get the number format of the last iterated cell. + nFuncFmtIndex = aAction.getNumberFormat(); + nFuncFmtType = pDok->GetFormatTable()->GetType(nFuncFmtIndex); + } + break; + case svExternalDoubleRef: + { + ScMatrixRef pMat; + PopExternalDoubleRef(pMat); + if (nGlobalError) + break; + + sal_uLong nCount = 0; + double fMem = 0.0; + bool bNull = true; + IterateMatrix(pMat, ifSUM, false, nCount, nFuncFmtType, fRes, fMem, bNull); + fRes += fMem; + } + break; + case svMatrix : + { + ScMatrixRef pMat = PopMatrix(); + sal_uLong nCount = 0; + double fMem = 0.0; + bool bNull = true; + IterateMatrix(pMat, ifSUM, false, nCount, nFuncFmtType, fRes, fMem, bNull); + fRes += fMem; + } + break; + case svError: + { + PopError(); + } + break; + default : + while (nParamCount-- > 0) + PopError(); + SetError(errIllegalParameter); + } + } + + if (nFuncFmtType == NUMBERFORMAT_LOGICAL) + nFuncFmtType = NUMBERFORMAT_NUMBER; + + PushDouble(fRes); } @@ -4276,39 +4458,6 @@ void ScInterpreter::ScAverage( bool bTextAsZero ) PushDouble( IterateParameters( ifAVERAGE, bTextAsZero ) ); } -namespace { - -class FuncCount : public sc::ColumnSpanSet::ColumnAction -{ - sc::ColumnBlockConstPosition maPos; - ScColumn* mpCol; - size_t mnCount; - sal_uInt32 mnNumFmt; - -public: - FuncCount() : mnCount(0), mnNumFmt(0) {} - - virtual void startColumn(ScColumn* pCol) - { - mpCol = pCol; - mpCol->InitBlockPosition(maPos); - } - - virtual void execute(SCROW nRow1, SCROW nRow2, bool bVal) - { - if (!bVal) - return; - - mnCount += mpCol->CountNumericCells(maPos, nRow1, nRow2); - mnNumFmt = mpCol->GetNumberFormat(nRow2); - }; - - size_t getCount() const { return mnCount; } - sal_uInt32 getNumberFormat() const { return mnNumFmt; } -}; - -} - void ScInterpreter::ScCount() { short nParamCount = GetByte(); |