sc/inc/column.hxx | 7 sc/inc/columnspanset.hxx | 29 ++ sc/inc/document.hxx | 3 sc/inc/formulacell.hxx | 1 sc/inc/formulagroup.hxx | 2 sc/inc/formularesult.hxx | 2 sc/inc/table.hxx | 4 sc/source/core/data/column.cxx | 100 +++++++++ sc/source/core/data/column2.cxx | 3 sc/source/core/data/columnspanset.cxx | 84 ++++++- sc/source/core/data/documen6.cxx | 4 sc/source/core/data/document.cxx | 17 + sc/source/core/data/formulacell.cxx | 9 sc/source/core/data/listenercontext.cxx | 4 sc/source/core/data/table3.cxx | 31 ++ sc/source/core/opencl/formulagroupcl.cxx | 7 sc/source/core/tool/formulagroup.cxx | 5 sc/source/core/tool/formularesult.cxx | 12 + sc/source/core/tool/interpr1.cxx | 338 ++++++++++++++++++++++++++++++- sc/source/core/tool/interpr5.cxx | 12 + sc/source/core/tool/token.cxx | 2 21 files changed, 649 insertions(+), 27 deletions(-)
New commits: commit 12a426b0261c44c4625f627ea21bd308266acae5 Author: Michael Meeks <michael.me...@suse.com> Date: Tue Jul 2 18:22:26 2013 +0100 fix naming snafu. diff --git a/sc/source/core/opencl/formulagroupcl.cxx b/sc/source/core/opencl/formulagroupcl.cxx index 9530276..ca064fe 100644 --- a/sc/source/core/opencl/formulagroupcl.cxx +++ b/sc/source/core/opencl/formulagroupcl.cxx @@ -57,7 +57,7 @@ public: const ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode); }; -ScMatrixRef FormulaGroupInterpreterSoftware::inverseMatrix(const ScMatrix& rMat) +ScMatrixRef FormulaGroupInterpreterOpenCL::inverseMatrix(const ScMatrix& rMat) { return ScMatrixRef(); } commit 97b026d934cdad9121c980cae87ea50bae9e4aad Author: Kohei Yoshida <kohei.yosh...@gmail.com> Date: Tue Jul 2 12:26:16 2013 -0400 Add a way to inverse matrix using openCL. It's an no-op for now. Change-Id: I4659d57505c3dccf872e124b8b569e680b307b71 diff --git a/sc/inc/formulagroup.hxx b/sc/inc/formulagroup.hxx index e5839e4..1c573c4 100644 --- a/sc/inc/formulagroup.hxx +++ b/sc/inc/formulagroup.hxx @@ -43,6 +43,7 @@ class SC_DLLPUBLIC FormulaGroupInterpreter public: static FormulaGroupInterpreter *getStatic(); + virtual ScMatrixRef inverseMatrix(const ScMatrix& rMat) = 0; virtual bool interpret(ScDocument& rDoc, const ScAddress& rTopPos, const ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode) = 0; }; @@ -54,6 +55,7 @@ public: FormulaGroupInterpreter() {} virtual ~FormulaGroupInterpreterSoftware() {} + virtual ScMatrixRef inverseMatrix(const ScMatrix& rMat); virtual bool interpret(ScDocument& rDoc, const ScAddress& rTopPos, const ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode); }; diff --git a/sc/source/core/opencl/formulagroupcl.cxx b/sc/source/core/opencl/formulagroupcl.cxx index 41e439c..9530276 100644 --- a/sc/source/core/opencl/formulagroupcl.cxx +++ b/sc/source/core/opencl/formulagroupcl.cxx @@ -51,10 +51,17 @@ public: { OclCalc::ReleaseOpenclRunEnv(); } + + virtual ScMatrixRef inverseMatrix(const ScMatrix& rMat); virtual bool interpret(ScDocument& rDoc, const ScAddress& rTopPos, const ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode); }; +ScMatrixRef FormulaGroupInterpreterSoftware::inverseMatrix(const ScMatrix& rMat) +{ + return ScMatrixRef(); +} + bool FormulaGroupInterpreterOpenCL::interpret(ScDocument& rDoc, const ScAddress& rTopPos, const ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode) { diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx index 4a04f79..4754bd0 100644 --- a/sc/source/core/tool/formulagroup.cxx +++ b/sc/source/core/tool/formulagroup.cxx @@ -20,6 +20,11 @@ namespace sc { +ScMatrixRef FormulaGroupInterpreterSoftware::inverseMatrix(const ScMatrix& /*rMat*/) +{ + return ScMatrixRef(); +} + bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddress& rTopPos, const ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode) diff --git a/sc/source/core/tool/interpr5.cxx b/sc/source/core/tool/interpr5.cxx index 26c2378..d48cfe7 100644 --- a/sc/source/core/tool/interpr5.cxx +++ b/sc/source/core/tool/interpr5.cxx @@ -35,6 +35,7 @@ #include "scmatrix.hxx" #include "globstr.hrc" #include "cellkeytranslator.hxx" +#include "formulagroup.hxx" #include <vector> @@ -850,6 +851,17 @@ void ScInterpreter::ScMatInv() } SCSIZE nC, nR; pMat->GetDimensions(nC, nR); + + if (ScInterpreter::GetGlobalConfig().mbOpenCLEnabled) + { + ScMatrixRef xResMat = sc::FormulaGroupInterpreter::getStatic()->inverseMatrix(*pMat); + if (xResMat) + { + PushMatrix(xResMat); + return; + } + } + if ( nC != nR || nC == 0 || (sal_uLong) nC * nC > ScMatrix::GetElementsMax() ) PushIllegalArgument(); else commit 946e1cb115a2a46fa10f528f83ca7a214fc31544 Author: Kohei Yoshida <kohei.yosh...@gmail.com> Date: Tue Jul 2 12:00:02 2013 -0400 Enable group calculation on COUNT and COUNT2. Change-Id: I7a1cb5aa485bd54e1f6e41262435129b6ac6b98b diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx index e25ef60..3ce8fda 100644 --- a/sc/source/core/tool/token.cxx +++ b/sc/source/core/tool/token.cxx @@ -1319,6 +1319,8 @@ void ScTokenArray::CheckToken( const FormulaToken& r ) case ocSum: case ocSumProduct: case ocMatInv: + case ocCount: + case ocCount2: // Don't change the state. break; default: commit b8904b25d622bcf5c2b1435a993e507d1c7f7555 Author: Kohei Yoshida <kohei.yosh...@gmail.com> Date: Tue Jul 2 09:24:09 2013 -0400 Try not to iterate beyond the end of the formula block. Or else a crash would ensue... Change-Id: Ib08163ba91e4bac023ae778c704a0c052fa48ebb diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx index abe2806..4becbb7 100644 --- a/sc/source/core/data/column2.cxx +++ b/sc/source/core/data/column2.cxx @@ -2258,8 +2258,9 @@ const double* ScColumn::FetchDoubleArray( sc::FormulaGroupContext& rCxt, SCROW n return &rArray[0]; } + // Requested length goes beyond a single block. Fill the array + // with the content of this formula block first. itEnd = sc::formula_block::end(*aPos.first->data); - std::advance(itEnd, nLenRequested); for (; it != itEnd; ++it) { ScFormulaCell& rCell = **it; commit cd2594c7504318a88719c710f7e627b9dd72fa16 Author: Kohei Yoshida <kohei.yosh...@gmail.com> Date: Tue Jul 2 01:12:27 2013 -0400 COUNT should skip formula cells with error. Change-Id: I829eaf309056403f77949526877888315a2ad720 diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx index a63025c..52a1474 100644 --- a/sc/inc/formulacell.hxx +++ b/sc/inc/formulacell.hxx @@ -202,6 +202,7 @@ public: // display as empty string if formula::svEmptyCell result bool IsEmptyDisplayedAsString(); bool IsValue(); // also true if formula::svEmptyCell + bool IsValueNoError(); bool IsHybridValueCell(); // for cells after import to deal with inherited number formats double GetValue(); double GetValueAlways(); // ignore errors diff --git a/sc/inc/formularesult.hxx b/sc/inc/formularesult.hxx index 6736a10..f1f7b5d 100644 --- a/sc/inc/formularesult.hxx +++ b/sc/inc/formularesult.hxx @@ -128,6 +128,8 @@ public: details instead. */ bool IsValue() const; + bool IsValueNoError() const; + /** Determines whether or not the result is a string containing more than one paragraph */ bool IsMultiline() const; diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index 64aae03..61f57ab 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -511,7 +511,7 @@ public: for (; it != itEnd; ++it) { ScFormulaCell& rCell = const_cast<ScFormulaCell&>(**it); - if (rCell.IsValue()) + if (rCell.IsValueNoError()) ++mnCount; } } diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx index 1e86cfc..a129726 100644 --- a/sc/source/core/data/formulacell.cxx +++ b/sc/source/core/data/formulacell.cxx @@ -1711,6 +1711,15 @@ bool ScFormulaCell::IsValue() return aResult.IsValue(); } +bool ScFormulaCell::IsValueNoError() +{ + MaybeInterpret(); + if (pCode->GetCodeError()) + return false; + + return aResult.IsValueNoError(); +} + bool ScFormulaCell::IsHybridValueCell() { return aResult.GetType() == formula::svHybridValueCell; diff --git a/sc/source/core/tool/formularesult.cxx b/sc/source/core/tool/formularesult.cxx index a20963b..72944a0 100644 --- a/sc/source/core/tool/formularesult.cxx +++ b/sc/source/core/tool/formularesult.cxx @@ -265,6 +265,18 @@ bool ScFormulaResult::IsValue() const return isValue(GetCellResultType()); } +bool ScFormulaResult::IsValueNoError() const +{ + switch (GetCellResultType()) + { + case formula::svDouble: + case formula::svEmptyCell: + case formula::svHybridValueCell: + return true; + } + return false; +} + bool ScFormulaResult::IsMultiline() const { if (meMultiline == MULTILINE_UNKNOWN) commit 9d207f6fc479bf96db9fcde214f15f2ffb045001 Author: Kohei Yoshida <kohei.yosh...@gmail.com> Date: Tue Jul 2 00:51:10 2013 -0400 Re-implement SUM function to make use of new cell storage. And fix a bug in my new COUNT function, where I forgot to tally numeric formula cells. Change-Id: I52d26be3e48f646f656821066e23594d52f78c6d diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index 7ce53ad..359b8ac 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 8d3f625..64aae03 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 643a0aa..93bcfef 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(); commit 3b10c65d9e9a3ffd1bbe176c39d45bbb76b1fc05 Author: Kohei Yoshida <kohei.yosh...@gmail.com> Date: Mon Jul 1 23:30:00 2013 -0400 Unused variable. Change-Id: I1df58281896687e61d40675206d0fc3854d93866 diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index 2a59e7e..8d3f625 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -474,7 +474,7 @@ class NumericCellCounter 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; commit cfb2ce587b097b407eb15699cff7ce9fb6844123 Author: Kohei Yoshida <kohei.yosh...@gmail.com> Date: Mon Jul 1 23:08:14 2013 -0400 Re-implement the COUNT function for efficiency. By taking advantage of the block structure of the new cell storage. Change-Id: Ib953c14d364ccdff7df5caf70d57cec86189e3be diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx index 6cc3c4b..7ce53ad 100644 --- a/sc/inc/column.hxx +++ b/sc/inc/column.hxx @@ -44,6 +44,7 @@ namespace sc { class CopyToClipContext; class CopyToDocContext; class MixDocContext; + class ColumnSpanSet; struct ColumnBlockPosition; class SingleColumnSpanSet; } @@ -116,7 +117,6 @@ class ScColumn friend class ScDocument; // for FillInfo friend class ScTable; -friend class ScDocumentIterator; friend class ScValueIterator; friend class ScHorizontalValueIterator; friend class ScDBQueryDataIterator; @@ -127,6 +127,7 @@ friend class ScHorizontalAttrIterator; friend class ScColumnTextWidthIterator; friend class ScDocumentImport; friend class sc::SingleColumnSpanSet; +friend class sc::ColumnSpanSet; ScColumn(const ScColumn&); // disabled ScColumn& operator= (const ScColumn&); // disabled @@ -242,6 +243,7 @@ public: void SwapCol(ScColumn& rCol); void MoveTo(SCROW nStartRow, SCROW nEndRow, ScColumn& rCol); + void MarkSubTotalCells( sc::ColumnSpanSet& rSet, SCROW nRow1, SCROW nRow2, bool bVal ) const; bool HasEditCells(SCROW nStartRow, SCROW nEndRow, SCROW& rFirst); @@ -407,6 +409,8 @@ public: void ClearSelectionItems( const sal_uInt16* pWhich, const ScMarkData& rMark ); void ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark ); + size_t CountNumericCells( sc::ColumnBlockConstPosition& rPos, SCROW nRow1, SCROW nRow2 ) const; + long GetNeededSize( SCROW nRow, OutputDevice* pDev, double nPPTX, double nPPTY, const Fraction& rZoomX, const Fraction& rZoomY, diff --git a/sc/inc/columnspanset.hxx b/sc/inc/columnspanset.hxx index 55c3f57..98533e2 100644 --- a/sc/inc/columnspanset.hxx +++ b/sc/inc/columnspanset.hxx @@ -16,8 +16,10 @@ #include <mdds/flat_segment_tree.hpp> #include <boost/noncopyable.hpp> +class ScDocument; class ScColumn; class ScMarkData; +class ScRange; namespace sc { @@ -30,12 +32,22 @@ struct ColumnBlockConstPosition; class ColumnSpanSet : boost::noncopyable { typedef mdds::flat_segment_tree<SCROW, bool> ColumnSpansType; - typedef std::vector<ColumnSpansType*> TableType; + + struct ColumnType + { + ColumnSpansType maSpans; + ColumnSpansType::const_iterator miPos; + + ColumnType(SCROW nStart, SCROW nEnd, bool bInit); + }; + + typedef std::vector<ColumnType*> TableType; typedef std::vector<TableType*> DocType; DocType maDoc; + bool mbInit; - ColumnSpansType& getColumnSpans(SCTAB nTab, SCCOL nCol); + ColumnType& getColumn(SCTAB nTab, SCCOL nCol); public: class Action @@ -46,12 +58,23 @@ public: virtual void execute(const ScAddress& rPos, SCROW nLength, bool bVal) = 0; }; + class ColumnAction + { + public: + virtual ~ColumnAction() = 0; + virtual void startColumn(ScColumn* pCol) = 0; + virtual void execute(SCROW nRow1, SCROW nRow2, bool bVal) = 0; + }; + + ColumnSpanSet(bool bInit); ~ColumnSpanSet(); void set(SCTAB nTab, SCCOL nCol, SCROW nRow, bool bVal); void set(SCTAB nTab, SCCOL nCol, SCROW nRow1, SCROW nRow2, bool bVal); + void set(const ScRange& rRange, bool bVal); - void executeFromTop(Action& ac) const; + void executeAction(Action& ac) const; + void executeColumnAction(ScDocument& rDoc, ColumnAction& ac) const; }; /** diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx index 806fb77..4d41565 100644 --- a/sc/inc/document.hxx +++ b/sc/inc/document.hxx @@ -53,6 +53,7 @@ namespace sc { class StartListeningContext; class EndListeningContext; class CopyFromClipContext; + class ColumnSpanSet; struct ColumnBlockPosition; } class SvxFontItem; @@ -228,6 +229,7 @@ friend class ScFormulaCell; friend class ScTable; friend struct ScRefCellValue; friend class ScDocumentImport; +friend class sc::ColumnSpanSet; typedef ::std::vector<ScTable*> TableContainer; private: @@ -1960,6 +1962,7 @@ public: void AddSubTotalCell(ScFormulaCell* pCell); void RemoveSubTotalCell(ScFormulaCell* pCell); void SetSubTotalCellsDirty(const ScRange& rDirtyRange); + void MarkSubTotalCells( sc::ColumnSpanSet& rSet, const ScRange& rRange, bool bVal ) const; sal_uInt16 GetTextWidth( const ScAddress& rPos ) const; diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx index 03060bb..a8d5128 100644 --- a/sc/inc/table.hxx +++ b/sc/inc/table.hxx @@ -57,6 +57,7 @@ namespace sc { class CopyToClipContext; class CopyToDocContext; class MixDocContext; + class ColumnSpanSet; struct ColumnBlockPosition; } @@ -203,6 +204,7 @@ friend class ScDocAttrIterator; friend class ScAttrRectIterator; friend class ScColumnTextWidthIterator; friend class ScDocumentImport; +friend class sc::ColumnSpanSet; public: ScTable( ScDocument* pDoc, SCTAB nNewTab, const OUString& rNewName, @@ -231,6 +233,8 @@ public: void RemoveSubTotals( ScSubTotalParam& rParam ); bool DoSubTotals( ScSubTotalParam& rParam ); + void MarkSubTotalCells( sc::ColumnSpanSet& rSet, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, bool bVal ) const; + const ScSheetEvents* GetSheetEvents() const { return pSheetEvents; } void SetSheetEvents( const ScSheetEvents* pNew ); diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx index aa82f4d1..2a59e7e 100644 --- a/sc/source/core/data/column.cxx +++ b/sc/source/core/data/column.cxx @@ -466,6 +466,33 @@ void ScColumn::ChangeSelectionIndent( bool bIncrement, const ScMarkData& rMark ) } } +namespace { + +class NumericCellCounter +{ + size_t mnCount; +public: + NumericCellCounter() : mnCount(0) {} + + void operator() (const sc::CellStoreType::value_type& rNode, size_t nOffset, size_t nDataSize) + { + if (rNode.type != sc::element_type_numeric) + return; + + mnCount += nDataSize; + } + + size_t getCount() const { return mnCount; } +}; + +} + +size_t ScColumn::CountNumericCells( sc::ColumnBlockConstPosition& rPos, SCROW nRow1, SCROW nRow2 ) const +{ + NumericCellCounter aFunc; + rPos.miCellPos = sc::ParseBlock(rPos.miCellPos, maCells, aFunc, nRow1, nRow2); + return aFunc.getCount(); +} void ScColumn::ClearSelectionItems( const sal_uInt16* pWhich,const ScMarkData& rMark ) { @@ -2155,6 +2182,33 @@ void ScColumn::MoveTo(SCROW nStartRow, SCROW nEndRow, ScColumn& rCol) namespace { +class SubTotalCellPicker +{ + sc::ColumnSpanSet& mrSet; + SCTAB mnTab; + SCCOL mnCol; + bool mbVal; +public: + SubTotalCellPicker(sc::ColumnSpanSet& rSet, SCTAB nTab, SCCOL nCol, bool bVal) : + mrSet(rSet), mnTab(nTab), mnCol(nCol), mbVal(bVal) {} + + void operator() (size_t nRow, const ScFormulaCell* pCell) + { + if (pCell->IsSubTotal()) + mrSet.set(mnTab, mnCol, nRow, mbVal); + } +}; + +} + +void ScColumn::MarkSubTotalCells( sc::ColumnSpanSet& rSet, SCROW nRow1, SCROW nRow2, bool bVal ) const +{ + SubTotalCellPicker aFunc(rSet, nTab, nCol, bVal); + sc::ParseFormula(maCells.begin(), maCells, nRow1, nRow2, aFunc); +} + +namespace { + class UpdateRefOnCopy { protected: diff --git a/sc/source/core/data/columnspanset.cxx b/sc/source/core/data/columnspanset.cxx index 8bfb7fc..f8c7813 100644 --- a/sc/source/core/data/columnspanset.cxx +++ b/sc/source/core/data/columnspanset.cxx @@ -10,6 +10,8 @@ #include "columnspanset.hxx" #include "stlalgorithm.hxx" #include "column.hxx" +#include "table.hxx" +#include "document.hxx" #include "mtvfunctions.hxx" #include "markdata.hxx" #include "rangelst.hxx" @@ -18,9 +20,16 @@ namespace sc { +ColumnSpanSet::ColumnType::ColumnType(SCROW nStart, SCROW nEnd, bool bInit) : + maSpans(nStart, nEnd+1, bInit), miPos(maSpans.begin()) {} + ColumnSpanSet::Action::~Action() {} void ColumnSpanSet::Action::startColumn(SCTAB /*nTab*/, SCCOL /*nCol*/) {} +ColumnSpanSet::ColumnAction::~ColumnAction() {} + +ColumnSpanSet::ColumnSpanSet(bool bInit) : mbInit(bInit) {} + ColumnSpanSet::~ColumnSpanSet() { DocType::iterator itTab = maDoc.begin(), itTabEnd = maDoc.end(); @@ -30,12 +39,12 @@ ColumnSpanSet::~ColumnSpanSet() if (!pTab) continue; - std::for_each(pTab->begin(), pTab->end(), ScDeleteObjectByPtr<ColumnSpansType>()); + std::for_each(pTab->begin(), pTab->end(), ScDeleteObjectByPtr<ColumnType>()); delete pTab; } } -ColumnSpanSet::ColumnSpansType& ColumnSpanSet::getColumnSpans(SCTAB nTab, SCCOL nCol) +ColumnSpanSet::ColumnType& ColumnSpanSet::getColumn(SCTAB nTab, SCCOL nCol) { if (static_cast<size_t>(nTab) >= maDoc.size()) maDoc.resize(nTab+1, NULL); @@ -48,7 +57,7 @@ ColumnSpanSet::ColumnSpansType& ColumnSpanSet::getColumnSpans(SCTAB nTab, SCCOL rTab.resize(nCol+1, NULL); if (!rTab[nCol]) - rTab[nCol] = new ColumnSpansType(0, MAXROW+1, false); + rTab[nCol] = new ColumnType(0, MAXROW, mbInit); return *rTab[nCol]; } @@ -58,8 +67,8 @@ void ColumnSpanSet::set(SCTAB nTab, SCCOL nCol, SCROW nRow, bool bVal) if (!ValidTab(nTab) || !ValidCol(nCol) || !ValidRow(nRow)) return; - ColumnSpansType& rCol = getColumnSpans(nTab, nCol); - rCol.insert_back(nRow, nRow+1, bVal); + ColumnType& rCol = getColumn(nTab, nCol); + rCol.miPos = rCol.maSpans.insert(rCol.miPos, nRow, nRow+1, bVal).first; } void ColumnSpanSet::set(SCTAB nTab, SCCOL nCol, SCROW nRow1, SCROW nRow2, bool bVal) @@ -67,11 +76,23 @@ void ColumnSpanSet::set(SCTAB nTab, SCCOL nCol, SCROW nRow1, SCROW nRow2, bool b if (!ValidTab(nTab) || !ValidCol(nCol) || !ValidRow(nRow1) || !ValidRow(nRow2)) return; - ColumnSpansType& rCol = getColumnSpans(nTab, nCol); - rCol.insert_back(nRow1, nRow2+1, bVal); + ColumnType& rCol = getColumn(nTab, nCol); + rCol.miPos = rCol.maSpans.insert(rCol.miPos, nRow1, nRow2+1, bVal).first; } -void ColumnSpanSet::executeFromTop(Action& ac) const +void ColumnSpanSet::set(const ScRange& rRange, bool bVal) +{ + for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab) + { + for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol) + { + ColumnType& rCol = getColumn(nTab, nCol); + rCol.miPos = rCol.maSpans.insert(rCol.miPos, rRange.aStart.Row(), rRange.aEnd.Row()+1, bVal).first; + } + } +} + +void ColumnSpanSet::executeAction(Action& ac) const { for (size_t nTab = 0; nTab < maDoc.size(); ++nTab) { @@ -85,8 +106,8 @@ void ColumnSpanSet::executeFromTop(Action& ac) const continue; ac.startColumn(nTab, nCol); - ColumnSpansType& rCol = *rTab[nCol]; - ColumnSpansType::const_iterator it = rCol.begin(), itEnd = rCol.end(); + ColumnType& rCol = *rTab[nCol]; + ColumnSpansType::const_iterator it = rCol.maSpans.begin(), itEnd = rCol.maSpans.end(); SCROW nRow1, nRow2; nRow1 = it->first; bool bVal = it->second; @@ -102,6 +123,49 @@ void ColumnSpanSet::executeFromTop(Action& ac) const } } +void ColumnSpanSet::executeColumnAction(ScDocument& rDoc, ColumnAction& ac) const +{ + for (size_t nTab = 0; nTab < maDoc.size(); ++nTab) + { + if (!maDoc[nTab]) + continue; + + const TableType& rTab = *maDoc[nTab]; + for (size_t nCol = 0; nCol < rTab.size(); ++nCol) + { + if (!rTab[nCol]) + continue; + + ScTable* pTab = rDoc.FetchTable(nTab); + if (!pTab) + continue; + + if (!ValidCol(nCol)) + { + // End the loop. + nCol = rTab.size(); + continue; + } + + ScColumn& rColumn = pTab->aCol[nCol]; + ac.startColumn(&rColumn); + ColumnType& rCol = *rTab[nCol]; + ColumnSpansType::const_iterator it = rCol.maSpans.begin(), itEnd = rCol.maSpans.end(); + SCROW nRow1, nRow2; + nRow1 = it->first; + bool bVal = it->second; + for (++it; it != itEnd; ++it) + { + nRow2 = it->first-1; + ac.execute(nRow1, nRow2, bVal); + + nRow1 = nRow2+1; // for the next iteration. + bVal = it->second; + } + } + } +} + namespace { class Scanner diff --git a/sc/source/core/data/documen6.cxx b/sc/source/core/data/documen6.cxx index a165f97..b9b8d5f 100644 --- a/sc/source/core/data/documen6.cxx +++ b/sc/source/core/data/documen6.cxx @@ -194,7 +194,7 @@ sal_uInt8 ScDocument::GetRangeScriptType( sal_uInt8 ScDocument::GetRangeScriptType( const ScRangeList& rRanges ) { - sc::ColumnSpanSet aSet; + sc::ColumnSpanSet aSet(false); for (size_t i = 0, n = rRanges.size(); i < n; ++i) { const ScRange& rRange = *rRanges[i]; @@ -206,7 +206,7 @@ sal_uInt8 ScDocument::GetRangeScriptType( const ScRangeList& rRanges ) } ScriptTypeAggregator aAction(*this); - aSet.executeFromTop(aAction); + aSet.executeAction(aAction); return aAction.getScriptType(); } diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx index 9d3c72f..2920d99 100644 --- a/sc/source/core/data/document.cxx +++ b/sc/source/core/data/document.cxx @@ -3538,8 +3538,7 @@ void ScDocument::AddTableOpFormulaCell( ScFormulaCell* pCell ) void ScDocument::CalcAll() { ClearLookupCaches(); // Ensure we don't deliver zombie data. - bool bOldAutoCalc = GetAutoCalc(); - SetAutoCalc( true ); + sc::AutoCalcSwitch aSwitch(*this, true); TableContainer::iterator it = maTabs.begin(); for (; it != maTabs.end(); ++it) if (*it) @@ -3548,7 +3547,6 @@ void ScDocument::CalcAll() if (*it) (*it)->CalcAll(); ClearFormulaTree(); - SetAutoCalc( bOldAutoCalc ); } @@ -5925,6 +5923,19 @@ void ScDocument::SetSubTotalCellsDirty(const ScRange& rDirtyRange) maSubTotalCells.swap(aNewSet); // update the list. } +void ScDocument::MarkSubTotalCells( sc::ColumnSpanSet& rSet, const ScRange& rRange, bool bVal ) const +{ + for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab) + { + const ScTable* pTab = FetchTable(nTab); + if (!pTab) + continue; + + pTab->MarkSubTotalCells( + rSet, rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row(), bVal); + } +} + sal_uInt16 ScDocument::GetTextWidth( const ScAddress& rPos ) const { SCTAB nTab = rPos.Tab(); diff --git a/sc/source/core/data/listenercontext.cxx b/sc/source/core/data/listenercontext.cxx index 6f67920..dc92346 100644 --- a/sc/source/core/data/listenercontext.cxx +++ b/sc/source/core/data/listenercontext.cxx @@ -53,7 +53,7 @@ ColumnBlockPosition* StartListeningContext::getBlockPosition(SCTAB nTab, SCCOL n } EndListeningContext::EndListeningContext(ScDocument& rDoc) : - mrDoc(rDoc), mpPosSet(new ColumnBlockPositionSet(rDoc)) {} + mrDoc(rDoc), maSet(false), mpPosSet(new ColumnBlockPositionSet(rDoc)) {} ScDocument& EndListeningContext::getDoc() { @@ -73,7 +73,7 @@ void EndListeningContext::addEmptyBroadcasterPosition(SCTAB nTab, SCCOL nCol, SC void EndListeningContext::purgeEmptyBroadcasters() { PurgeAction aAction(mrDoc); - maSet.executeFromTop(aAction); + maSet.executeAction(aAction); } } diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx index eff2cd6..9971816 100644 --- a/sc/source/core/data/table3.cxx +++ b/sc/source/core/data/table3.cxx @@ -55,6 +55,7 @@ #include "cellvalue.hxx" #include "tokenarray.hxx" #include "mtvcellfunc.hxx" +#include "columnspanset.hxx" #include <vector> #include <boost/unordered_set.hpp> @@ -1159,6 +1160,36 @@ bool ScTable::DoSubTotals( ScSubTotalParam& rParam ) return bSpaceLeft; } +void ScTable::MarkSubTotalCells( + sc::ColumnSpanSet& rSet, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, bool bVal ) const +{ + if (!ValidCol(nCol1) || !ValidCol(nCol2)) + return; + + // Pick up all subtotal formula cells. + for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) + aCol[nCol].MarkSubTotalCells(rSet, nRow1, nRow2, bVal); + + // Pick up all filtered rows. + ScFlatBoolRowSegments::RangeData aFilteredSpan; + SCROW nRow = nRow1; + while (nRow <= nRow2) + { + if (!mpFilteredRows->getRangeData(nRow, aFilteredSpan)) + // Failed for whatever reason. + return; + + if (aFilteredSpan.mbValue) + { + // Filtered span found. + for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) + rSet.set(nTab, nCol, nRow, aFilteredSpan.mnRow2, bVal); + } + + nRow = aFilteredSpan.mnRow2 + 1; + } +} + namespace { class QueryEvaluator diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx index a88b542..643a0aa 100644 --- a/sc/source/core/tool/interpr1.cxx +++ b/sc/source/core/tool/interpr1.cxx @@ -58,6 +58,8 @@ #include "queryparam.hxx" #include "queryentry.hxx" #include "tokenarray.hxx" +#include "columnspanset.hxx" +#include "column.hxx" #include <comphelper/processfactory.hxx> #include <comphelper/string.hxx> @@ -4274,11 +4276,188 @@ 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() { - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCount" ); - PushDouble( IterateParameters( ifCOUNT ) ); + short nParamCount = GetByte(); + double fVal = 0.0; + sal_uLong nCount = 0; + ScAddress aAdr; + ScRange aRange; + size_t nRefInList = 0; + if (nGlobalError) + nGlobalError = 0; + + while (nParamCount-- > 0) + { + switch (GetStackType()) + { + case svString: + { + String aStr( PopString() ); + sal_uInt32 nFIndex = 0; // damit default Land/Spr. + if (pFormatter->IsNumberFormat(aStr, nFIndex, fVal)) + nCount++; + } + break; + case svDouble : + nCount++; + nFuncFmtType = NUMBERFORMAT_NUMBER; + break; + case svExternalSingleRef: + { + ScExternalRefCache::TokenRef pToken; + ScExternalRefCache::CellFormat aFmt; + PopExternalSingleRef(pToken, &aFmt); + if (nGlobalError) + { + nGlobalError = 0; + break; + } + + if (!pToken) + break; + + StackVar eType = pToken->GetType(); + if (eType == formula::svDouble) + { + nCount++; + if (aFmt.mbIsSet) + { + nFuncFmtType = aFmt.mnType; + nFuncFmtIndex = aFmt.mnIndex; + } + + if (nGlobalError) + { + nGlobalError = 0; + nCount--; + } + } + } + break; + case svSingleRef : + { + PopSingleRef( aAdr ); + if (nGlobalError) + { + nGlobalError = 0; + break; + } + if (glSubTotal && pDok->RowFiltered( aAdr.Row(), aAdr.Tab())) + { + break; + } + ScRefCellValue aCell; + aCell.assign(*pDok, aAdr); + if (!aCell.isEmpty()) + { + if (aCell.hasNumeric()) + { + nCount++; + CurFmtToFuncFmt(); + if (nGlobalError) + { + nGlobalError = 0; + nCount--; + } + } + } + } + break; + case svDoubleRef : + case svRefList : + { + PopDoubleRef( aRange, nParamCount, nRefInList); + if (nGlobalError) + { + nGlobalError = 0; + break; + } + + sc::ColumnSpanSet aSet(false); + aSet.set(aRange, true); + if (glSubTotal) + // Skip all filtered rows and subtotal formula cells. + pDok->MarkSubTotalCells(aSet, aRange, false); + + FuncCount aAction; + aSet.executeColumnAction(*pDok, aAction); + nCount = aAction.getCount(); + + // 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; + + double fMem = 0.0, fRes = 0.0; + bool bNull = true; + IterateMatrix(pMat, ifCOUNT, false, nCount, nFuncFmtType, fRes, fMem, bNull); + } + break; + case svMatrix : + { + ScMatrixRef pMat = PopMatrix(); + double fMem = 0.0, fRes = 0.0; + bool bNull = true; + IterateMatrix(pMat, ifCOUNT, false, nCount, nFuncFmtType, fRes, fMem, bNull); + } + break; + case svError: + { + PopError(); + nGlobalError = 0; + } + break; + default : + while (nParamCount-- > 0) + PopError(); + SetError(errIllegalParameter); + } + } + + nFuncFmtType = NUMBERFORMAT_NUMBER; + + PushDouble(nCount); } _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits