sc/inc/dbdata.hxx | 13 + sc/source/core/data/table3.cxx | 6 sc/source/core/tool/dbdata.cxx | 261 ++++++++++++++++++++++++++-- sc/source/filter/excel/xedbdata.cxx | 35 +++ sc/source/filter/oox/tablecolumnsbuffer.cxx | 4 sc/source/ui/view/cellsh2.cxx | 9 sc/source/ui/view/gridwin.cxx | 2 sc/source/ui/view/tableshell.cxx | 5 8 files changed, 304 insertions(+), 31 deletions(-)
New commits: commit 917801869c1f9efb9c8d947f55444584b3e7873f Author: Balazs Varga <[email protected]> AuthorDate: Thu Oct 30 17:49:09 2025 +0100 Commit: Andras Timar <[email protected]> CommitDate: Mon Nov 17 19:03:41 2025 +0100 Disable original SubTotal functionality if table style is applied on the Dbrange (same as MSO). Change-Id: I9ad8d3f31ea8e417e7c40e930659c0bdbc55d9f7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/193226 Tested-by: Balazs Varga <[email protected]> Reviewed-by: Balazs Varga <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/193683 Tested-by: Andras Timar <[email protected]> Reviewed-by: Andras Timar <[email protected]> diff --git a/sc/source/ui/view/cellsh2.cxx b/sc/source/ui/view/cellsh2.cxx index 96edd44d5114..9ca07df51670 100644 --- a/sc/source/ui/view/cellsh2.cxx +++ b/sc/source/ui/view/cellsh2.cxx @@ -1193,6 +1193,15 @@ void ScCellShell::GetDBState( SfxItemSet& rSet ) rSet.DisableItem(nWhich); } } + else if (nWhich == SCITEM_SUBTDATA) + { + // Disable if table style is applied (same as MSO) + ScDBData* pDBData = pTabViewShell->GetDBData(false, SC_DB_OLD); + if (pDBData && pDBData->GetTableStyleInfo()) + { + rSet.DisableItem(nWhich); + } + } } } break; commit e725c5b9327424fb927ed251d54b6913ae9d8568 Author: Balazs Varga <[email protected]> AuthorDate: Thu Oct 30 14:14:41 2025 +0100 Commit: Andras Timar <[email protected]> CommitDate: Mon Nov 17 19:03:27 2025 +0100 Table Style improvements: ooxml export of Total Row attributes. XML_totalsRowLabel, XML_totalsRowFunction, XML_totalsRowFormula and XML_totalsRowShown. cherry-pick from: dbe65f04327924e0d3c7bcefab5bbfba07687033 Change-Id: I2b7c356cf71abe940ddbe6672c8fdb52d2513f79 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/193206 Reviewed-by: Balazs Varga <[email protected]> Tested-by: Balazs Varga <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/193682 Tested-by: Andras Timar <[email protected]> Reviewed-by: Andras Timar <[email protected]> diff --git a/sc/inc/dbdata.hxx b/sc/inc/dbdata.hxx index 0676e6d8dde5..65ed43be7a5b 100644 --- a/sc/inc/dbdata.hxx +++ b/sc/inc/dbdata.hxx @@ -36,6 +36,7 @@ class ScDocument; struct ScSortParam; struct ScQueryParam; struct ScSubTotalParam; +class ScTokenArray; class SC_DLLPUBLIC ScDatabaseSettingItem final : public SfxPoolItem { @@ -276,10 +277,17 @@ public: SC_DLLPUBLIC void GetSubTotalParam(ScSubTotalParam& rSubTotalParam) const; SC_DLLPUBLIC void SetSubTotalParam(const ScSubTotalParam& rSubTotalParam); - SC_DLLPUBLIC void ImportSubTotalParam(ScSubTotalParam& rSubTotalParam, + + // Total row param handling for Table Styles + SC_DLLPUBLIC void ImportTotalRowParam(ScSubTotalParam& rSubTotalParam, const std::vector<TableColumnAttributes>& rAttributesVector, formula::FormulaGrammar::Grammar eGrammar) const; - SC_DLLPUBLIC void CreateSubTotalParam(ScSubTotalParam& rSubTotalParam) const; + SC_DLLPUBLIC void CreateTotalRowParam(ScSubTotalParam& rSubTotalParam) const; + + SC_DLLPUBLIC std::vector<TableColumnAttributes> + GetTotalRowAttributes(formula::FormulaGrammar::Grammar eGrammar) const; + + OUString GetSimpleSubTotalFunction(const ScTokenArray* pTokens, SCCOL nCol, SCROW nHeaderRow) const; void GetImportParam(ScImportParam& rImportParam) const; void SetImportParam(const ScImportParam& rImportParam); @@ -315,6 +323,7 @@ public: SC_DLLPUBLIC const ScTableStyleParam* GetTableStyleInfo() const; static ScSubTotalFunc GetSubTotalFuncFromString(std::u16string_view sFunction); + static OUString GetStringFromSubTotalFunc(ScSubTotalFunc eFunc); private: diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx index be8931c3ab1e..c976be11bd33 100644 --- a/sc/source/core/data/table3.cxx +++ b/sc/source/core/data/table3.cxx @@ -2305,9 +2305,9 @@ bool ScTable::DoSubTotals( ScSubTotalParam& rParam ) bool ScTable::DoSimpleSubTotals( ScSubTotalParam& rParam ) { RowEntry aRowEntry; - aRowEntry.nGroupNo = 0; - aRowEntry.nSubStartRow = rParam.nRow1 + static_cast<SCROW>(rParam.bHasHeader); // Header - aRowEntry.nFuncStart = rParam.nRow1 + static_cast<SCROW>(rParam.bHasHeader); // Header + aRowEntry.nGroupNo = 0; // only one group can have + //aRowEntry.nSubStartRow = rParam.nRow1 + static_cast<SCROW>(rParam.bHasHeader); // Header + //aRowEntry.nFuncStart = rParam.nRow1 + static_cast<SCROW>(rParam.bHasHeader); // Header aRowEntry.nDestRow = rParam.nRow2 + 1; aRowEntry.nFuncEnd = rParam.nRow2; diff --git a/sc/source/core/tool/dbdata.cxx b/sc/source/core/tool/dbdata.cxx index 14d7226ef7c6..e620443fa771 100644 --- a/sc/source/core/tool/dbdata.cxx +++ b/sc/source/core/tool/dbdata.cxx @@ -26,6 +26,7 @@ #include <dbdata.hxx> #include <compiler.hxx> +#include <tokenarray.hxx> #include <globalnames.hxx> #include <refupdat.hxx> #include <document.hxx> @@ -695,7 +696,7 @@ void ScDBData::SetSubTotalParam(const ScSubTotalParam& rSubTotalParam) mpSubTotal.reset(new ScSubTotalParam(rSubTotalParam)); } -void ScDBData::ImportSubTotalParam(ScSubTotalParam& rSubTotalParam, +void ScDBData::ImportTotalRowParam(ScSubTotalParam& rSubTotalParam, const std::vector<TableColumnAttributes>& rAttributesVector, formula::FormulaGrammar::Grammar eGrammar) const { @@ -772,7 +773,7 @@ void ScDBData::ImportSubTotalParam(ScSubTotalParam& rSubTotalParam, } } -void ScDBData::CreateSubTotalParam(ScSubTotalParam& rSubTotalParam) const +void ScDBData::CreateTotalRowParam(ScSubTotalParam& rSubTotalParam) const { rSubTotalParam.bDoSort = false; rSubTotalParam.bGroupedBy = false; @@ -815,6 +816,209 @@ void ScDBData::CreateSubTotalParam(ScSubTotalParam& rSubTotalParam) const } } +std::vector<TableColumnAttributes> ScDBData::GetTotalRowAttributes(formula::FormulaGrammar::Grammar eGrammar) const +{ + ScSubTotalParam rParam; + GetSubTotalParam(rParam); + + const SCCOL nEntryCount = rParam.nCol2 - rParam.nCol1 + 1; // col count + std::vector<TableColumnAttributes> aAttributesVector(nEntryCount); + if (nEntryCount > 0) + { + if (HasTotals()) + { + if (!mpContainer) + assert(!"ScDBData::GetTotalRowAttributes - how did we end up here without container?"); + else + { + ScDocument& rDoc = mpContainer->GetDocument(); + ScHorizontalCellIterator aIter(rDoc, nTable, rParam.nCol1, rParam.nRow2, + rParam.nCol2, + rParam.nRow2); // Total row only + ScRefCellValue* pCell; + SCCOL nCol = rParam.nCol1 - 1; + SCROW nRow; + while ((pCell = aIter.GetNext(nCol, nRow)) != nullptr) + { + TableColumnAttributes aNameAttr; + if (pCell->getType() != CELLTYPE_FORMULA) + { + OUString aStr = pCell->getString(&rDoc); + if (!aStr.isEmpty()) + aNameAttr.maTotalsRowLabel = aStr; + } + else + { + if (ScFormulaCell* pFC = pCell->getFormula()) + { + bool bSubTotal = pFC->IsSubTotal(); + ScTokenArray* pTokens = pFC->GetCode(); + if (bSubTotal && pTokens) + { + OUString aFunctype = GetSimpleSubTotalFunction(pTokens, nCol, rParam.nRow1); + if (aFunctype != u"custom") + aNameAttr.maTotalsFunction = aFunctype; + else + bSubTotal = false; // fallback to custom + } + + if (!bSubTotal && pTokens) + { + ScAddress aPos(nCol, rParam.nRow2, nTable); + ScCompiler aComp(rDoc, aPos, *pTokens, eGrammar); + OUStringBuffer aBuf; + aComp.CreateStringFromTokenArray(aBuf); + OUString aFormula = aBuf.makeStringAndClear(); + aNameAttr.maTotalsFunction = "custom"; + aNameAttr.maCustomFunction = aFormula; + } + } + } + SCCOL nPos = nCol - rParam.nCol1; + if (nPos < nEntryCount) + aAttributesVector[nPos] = std::move(aNameAttr); + else + SAL_WARN("sc.core", "ScDBData::GetTotalRowAttributes - invalid attributes/columns"); + } + } + } + else + { + const auto& group = rParam.aGroups[0]; + if (group.nSubLabels > 0) + { + for (SCCOL nResult = 0; nResult < group.nSubLabels; ++nResult) + { + SCCOL nPos = group.collabels(nResult) - rParam.nCol1; + if (nPos < nEntryCount) + aAttributesVector[nPos].maTotalsRowLabel = group.label(nResult); + else + SAL_WARN("sc.core", "ScDBData::GetTotalRowAttributes - invalid attributes/columns"); + } + } + + // insert the formulas + if (group.nCustFuncs > 0) + { + for (SCCOL nResult = 0; nResult < group.nCustFuncs; ++nResult) + { + if (ScTokenArray* pTokens = group.custToken(nResult)) + { + SCCOL nCol = group.colcust(nResult); + bool bSubTotal = pTokens->HasOpCode(ocSubTotal); + if (bSubTotal) + { + OUString aFunctype = GetSimpleSubTotalFunction(pTokens, nCol, rParam.nRow1); + if (aFunctype != u"custom") + { + SCCOL nPos = nCol - rParam.nCol1; + if (nPos < nEntryCount) + aAttributesVector[nPos].maTotalsFunction = aFunctype; + else + SAL_WARN("sc.core", "ScDBData::GetTotalRowAttributes - invalid " + "attributes/columns"); + } + else + bSubTotal = false; // fallback to custom + } + + if (!bSubTotal) + { + if (!mpContainer) + assert(!"ScDBData::GetTotalRowAttributes - how did we end up here without container?"); + else + { + ScDocument& rDoc = mpContainer->GetDocument(); + ScAddress aPos(nCol, rParam.nRow2 + 1, nTable); + ScCompiler aComp(rDoc, aPos, *pTokens, eGrammar); + OUStringBuffer aBuf; + aComp.CreateStringFromTokenArray(aBuf); + OUString aFormula = aBuf.makeStringAndClear(); + + SCCOL nPos = nCol - rParam.nCol1; + if (nPos < nEntryCount) + { + aAttributesVector[nPos].maTotalsFunction = "custom"; + aAttributesVector[nPos].maCustomFunction = aFormula; + } + else + SAL_WARN("sc.core", "ScDBData::GetTotalRowAttributes - invalid " + "attributes/columns"); + } + } + } + } + } + } + } + return aAttributesVector; +} + +OUString ScDBData::GetSimpleSubTotalFunction(const ScTokenArray* pTokens, SCCOL nCol, SCROW nHeaderRow) const +{ + std::vector<std::pair<OpCode, formula::StackVar>> expected + = { { ocSubTotal, formula::svByte }, { ocOpen, formula::svSep }, + { ocPush, formula::svDouble }, { ocSep, formula::svSep }, + { ocTableRef, formula::svIndex }, { ocTableRefOpen, formula::svSep }, + { ocPush, formula::svSingleRef }, { ocTableRefClose, formula::svSep }, + { ocClose, formula::svSep } }; + + size_t nIdx = 0; + ScSubTotalFunc eSubType = SUBTOTAL_FUNC_NONE; + formula::FormulaTokenArrayPlainIterator aIterResult(*pTokens); + for (formula::FormulaToken* t = aIterResult.NextNoSpaces(); t; t = aIterResult.NextNoSpaces()) + { + // check for subtotal opcode + OpCode eOpCode = t->GetOpCode(); + formula::StackVar eType = t->GetType(); + + if (nIdx < expected.size() && eOpCode == expected[nIdx].first + && eType == expected[nIdx].second) + { + if (nIdx == 2) // { ocPush, formula::svDouble } + { + sal_Int32 nFunc = static_cast<sal_Int32>(t->GetDouble()); + if (nFunc > 100.) + nFunc -= 100; + + if (nFunc < 1 || nFunc > 11) + { + return u"custom"_ustr; + } + else + eSubType = static_cast<ScSubTotalFunc>(nFunc); + } + else if (nIdx == 4) // { ocTableRef, formula::svIndex } + { + sal_uInt16 nDbIndex = t->GetIndex(); + if (GetIndex() != nDbIndex) + { + return u"custom"_ustr; + } + } + else if (nIdx == 6) // { ocPush, formula::svSingleRef } + { + const ScSingleRefData* pRef = t->GetSingleRef(); + if (!(pRef && pRef->Col() == nCol && pRef->Row() == nHeaderRow)) + { + return u"custom"_ustr; + } + } + else + { /*Nothing to do*/ + } + + ++nIdx; + } + else + { + return u"custom"_ustr; + } + } + + return GetStringFromSubTotalFunc(eSubType); +} + void ScDBData::GetImportParam(ScImportParam& rImportParam) const { rImportParam = *mpImportParam; @@ -1347,29 +1551,58 @@ ScSubTotalFunc ScDBData::GetSubTotalFuncFromString(std::u16string_view sFunction { if (sFunction == u"sum") return SUBTOTAL_FUNC_SUM; - if (sFunction == u"countNums") + else if (sFunction == u"countNums") return SUBTOTAL_FUNC_CNT; - if (sFunction == u"count") + else if (sFunction == u"count") return SUBTOTAL_FUNC_CNT2; - /*if (sFunction) + /*else if (sFunction) return SUBTOTAL_FUNC_PROD;*/ - if (sFunction == u"average") + else if (sFunction == u"average") return SUBTOTAL_FUNC_AVE; - /*if (sFunction) + /*else if (sFunction) return SUBTOTAL_FUNC_MED;*/ - if (sFunction == u"max") + else if (sFunction == u"max") return SUBTOTAL_FUNC_MAX; - if (sFunction == u"min") + else if (sFunction == u"min") return SUBTOTAL_FUNC_MIN; - if (sFunction == u"stdDev") + else if (sFunction == u"stdDev") return SUBTOTAL_FUNC_STD; - /*if (sFunction) + /*else if (sFunction) return SUBTOTAL_FUNC_STDP;*/ - if (sFunction == u"var") + else if (sFunction == u"var") return SUBTOTAL_FUNC_VAR; - /*if (sFunction) + /*else if (sFunction) return SUBTOTAL_FUNC_VARP;*/ - return SUBTOTAL_FUNC_NONE; + else + return SUBTOTAL_FUNC_NONE; +} + +OUString ScDBData::GetStringFromSubTotalFunc(ScSubTotalFunc eFunc) +{ + if (eFunc == SUBTOTAL_FUNC_SUM) + return u"sum"_ustr; + else if (eFunc == SUBTOTAL_FUNC_CNT) + return u"countNums"_ustr; + else if (eFunc == SUBTOTAL_FUNC_CNT2) + return u"count"_ustr; + else if (eFunc == SUBTOTAL_FUNC_PROD) + return u"custom"_ustr; // ooxml not support in Total row + else if (eFunc == SUBTOTAL_FUNC_AVE) + return u"average"_ustr; + else if (eFunc == SUBTOTAL_FUNC_MED) + return u"custom"_ustr; // ooxml not support in Total row + else if (eFunc == SUBTOTAL_FUNC_MAX) + return u"max"_ustr; + else if (eFunc == SUBTOTAL_FUNC_MIN) + return u"min"_ustr; + else if (eFunc == SUBTOTAL_FUNC_STD) + return u"stdDev"_ustr; + else if (eFunc == SUBTOTAL_FUNC_STDP) + return u"custom"_ustr; // ooxml not support in Total row + else if (eFunc == SUBTOTAL_FUNC_VAR) + return u"var"_ustr; + else + return u"none"_ustr; } namespace { diff --git a/sc/source/filter/excel/xedbdata.cxx b/sc/source/filter/excel/xedbdata.cxx index 1283082fe13c..2440213419b4 100644 --- a/sc/source/filter/excel/xedbdata.cxx +++ b/sc/source/filter/excel/xedbdata.cxx @@ -189,6 +189,18 @@ void XclExpTables::SaveTableXml( XclExpXmlStream& rStrm, const Entry& rEntry ) if (hasTableTypeAttr) tableType = rData.GetTableType(); + const std::vector<TableColumnAttributes> aTotalValues + = rData.GetTotalRowAttributes(formula::FormulaGrammar::GRAM_OOXML); + + // if the Total row have ever been showed it will be true + bool hasAnySetValue = std::any_of(aTotalValues.begin(), aTotalValues.end(), + [](const TableColumnAttributes& attr) + { + return attr.maTotalsRowLabel.has_value() + || attr.maTotalsFunction.has_value() + || attr.maCustomFunction.has_value(); + }); + pTableStrm->startElement( XML_table, XML_xmlns, rStrm.getNamespaceURL(OOX_NS(xls)).toUtf8(), XML_id, OString::number( rEntry.mnTableId), @@ -198,7 +210,7 @@ void XclExpTables::SaveTableXml( XclExpXmlStream& rStrm, const Entry& rEntry ) XML_tableType, tableType, XML_headerRowCount, ToPsz10(rData.HasHeader()), XML_totalsRowCount, ToPsz10(rData.HasTotals()), - XML_totalsRowShown, ToPsz10(rData.HasTotals()) // we don't support that but if there are totals they are shown + XML_totalsRowShown, ToPsz10(hasAnySetValue) // OOXTODO: XML_comment, ..., // OOXTODO: XML_connectionId, ..., // OOXTODO: XML_dataCellStyle, ..., @@ -233,6 +245,10 @@ void XclExpTables::SaveTableXml( XclExpXmlStream& rStrm, const Entry& rEntry ) const std::vector< TableColumnModel >& rTableColumnModel = rData.GetTableColumnModel(); if (!rColNames.empty()) { + // rColNames and aTotalValues size should always be equal + assert((rColNames.size() == aTotalValues.size()) && + "XclExpTables::SaveTableXml - mismatch between column names and total values"); + pTableStrm->startElement(XML_tableColumns, XML_count, OString::number(aRange.aEnd.Col() - aRange.aStart.Col() + 1)); @@ -242,8 +258,6 @@ void XclExpTables::SaveTableXml( XclExpXmlStream& rStrm, const Entry& rEntry ) // which case we'd need start/endElement XML_tableColumn for such // column. - // OOXTODO: write <totalsRowFormula> once we support it. - std::optional<OUString> uniqueName = std::nullopt; // uniqueName should only be used when this table's tableType is queryTable or xml. @@ -259,9 +273,9 @@ void XclExpTables::SaveTableXml( XclExpXmlStream& rStrm, const Entry& rEntry ) pTableStrm->startElement( XML_tableColumn, XML_id, OString::number(i+1), XML_uniqueName, uniqueName, - XML_name, rColNames[i].toUtf8() - // XML_totalsRowLabel, (i < rColAttributes.size() ? rColAttributes[i].maTotalsRowLabel : std::nullopt), - // XML_totalsRowFunction, (i < rColAttributes.size() ? rColAttributes[i].maTotalsFunction : std::nullopt) + XML_name, rColNames[i].toUtf8(), + XML_totalsRowLabel, (i < aTotalValues.size() ? aTotalValues[i].maTotalsRowLabel : std::nullopt), + XML_totalsRowFunction, (i < aTotalValues.size() ? aTotalValues[i].maTotalsFunction : std::nullopt) // OOXTODO: XML_dataCellStyle, ..., // OOXTODO: XML_dataDxfId, ..., // OOXTODO: XML_headerRowCellStyle, ..., @@ -288,6 +302,15 @@ void XclExpTables::SaveTableXml( XclExpXmlStream& rStrm, const Entry& rEntry ) pTableStrm->singleElement(XML_xmlColumnPr, pXmlColumnPrAttrList); } + if (i < aTotalValues.size() && aTotalValues[i].maTotalsFunction.has_value() + && aTotalValues[i].maTotalsFunction.value() == u"custom") + { + // write custom functions + pTableStrm->startElement(XML_totalsRowFormula); + pTableStrm->writeEscaped(aTotalValues[i].maCustomFunction.value()); + pTableStrm->endElement(XML_totalsRowFormula); + } + // put </tableColumn> pTableStrm->endElement(XML_tableColumn); } diff --git a/sc/source/filter/oox/tablecolumnsbuffer.cxx b/sc/source/filter/oox/tablecolumnsbuffer.cxx index 0d0b6e0a75be..aba02524ceaf 100644 --- a/sc/source/filter/oox/tablecolumnsbuffer.cxx +++ b/sc/source/filter/oox/tablecolumnsbuffer.cxx @@ -161,12 +161,12 @@ bool TableColumns::finalizeImport( ScDBData* pDBData ) pDBData->SetTableColumnNames( std::move(aNames) ); // Import subtotal parameters for columns - if (hasAnySetValue && !pDBData->HasTotals()) + if (hasAnySetValue) { ScSubTotalParam aSubTotalParam; pDBData->GetSubTotalParam(aSubTotalParam); aSubTotalParam.bHasHeader = pDBData->HasHeader(); - pDBData->ImportSubTotalParam(aSubTotalParam, aAttributes, + pDBData->ImportTotalRowParam(aSubTotalParam, aAttributes, formula::FormulaGrammar::GRAM_OOXML); pDBData->SetSubTotalParam(aSubTotalParam); } diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx index e71c3e4b3f83..acd21fb6d928 100644 --- a/sc/source/ui/view/gridwin.cxx +++ b/sc/source/ui/view/gridwin.cxx @@ -2502,7 +2502,7 @@ void ScGridWindow::MouseButtonUp( const MouseEvent& rMEvt ) pDBData->GetSubTotalParam(aSubTotalParam); aSubTotalParam.bHasHeader = aNewDBData.HasHeader(); // store current subtotal settings - pDBData->CreateSubTotalParam(aSubTotalParam); + pDBData->CreateTotalRowParam(aSubTotalParam); aNewDBData.SetSubTotalParam(aSubTotalParam); // add/replace total row aSubTotalParam.bRemoveOnly = false; diff --git a/sc/source/ui/view/tableshell.cxx b/sc/source/ui/view/tableshell.cxx index bb35a0d98ba7..6436073b9b10 100644 --- a/sc/source/ui/view/tableshell.cxx +++ b/sc/source/ui/view/tableshell.cxx @@ -102,10 +102,9 @@ void ScTableShell::ExecuteDatabaseSettings(SfxRequest& rReq) if (!aNewDBData.HasTotals()) { - // store current subtotal settings - pDBData->CreateSubTotalParam(aSubTotalParam); + // store current subtotal settings before removing total row + pDBData->CreateTotalRowParam(aSubTotalParam); aNewDBData.SetSubTotalParam(aSubTotalParam); - // remove total row aSubTotalParam.bRemoveOnly = true; aSubTotalParam.bReplace = true; aFunc.DoTableSubTotals(aNewDBData.GetTab(), aNewDBData, aSubTotalParam,
