sc/inc/dpcache.hxx | 3 sc/inc/dpobject.hxx | 13 +-- sc/inc/dpsave.hxx | 7 + sc/inc/dpshttab.hxx | 2 sc/inc/dptabdat.hxx | 2 sc/source/core/data/dpcache.cxx | 137 +++++++++++++++++++++++++++++----- sc/source/core/data/dpobject.cxx | 64 ++++++++------- sc/source/core/data/dpsave.cxx | 57 ++++++++++++++ sc/source/core/data/dpshttab.cxx | 7 + sc/source/core/data/dptabdat.cxx | 4 sc/source/ui/inc/gridwin.hxx | 1 sc/source/ui/view/gridwin.cxx | 4 sc/source/ui/view/gridwin_dbgutil.cxx | 14 +++ 13 files changed, 263 insertions(+), 52 deletions(-)
New commits: commit 13d52f6af376cfe7f9bb44d52a831f43053002fe Author: Tomaž Vajngerl <[email protected]> AuthorDate: Tue Nov 11 23:00:21 2025 +0900 Commit: Tomaž Vajngerl <[email protected]> CommitDate: Fri Nov 14 10:09:06 2025 +0100 sc: add dumpAsXml for the pivot table This adds dumpAsXml for the pivot table, which is triggered with ctrl+shift+alt F5 when the cursor is inside a pivot table. This will write the pivot_table_dump.xml into the CWD. The output includes the layout and the cache, which is similar to the pivot table dump, that has written the content to the console output. Change-Id: Ib20089cb63846aafe691a53bdb4e53f16602d5a8 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/193832 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <[email protected]> diff --git a/sc/inc/dpcache.hxx b/sc/inc/dpcache.hxx index f74258599beb..6d9462f989be 100644 --- a/sc/inc/dpcache.hxx +++ b/sc/inc/dpcache.hxx @@ -37,6 +37,7 @@ struct ScQueryParam; class ScDPObject; class ScDocument; struct ScInterpreterContext; +namespace tools { class XmlWriter; } enum class SvNumFormatType : sal_Int16; @@ -203,6 +204,8 @@ public: ScDPCache(ScDocument& rDoc); ~ScDPCache(); + void dumpAsXml(tools::XmlWriter& rWriter) const; + #if DUMP_PIVOT_TABLE void Dump() const; #endif diff --git a/sc/inc/dpobject.hxx b/sc/inc/dpobject.hxx index fb137dab306a..1bad3dc00fd3 100644 --- a/sc/inc/dpobject.hxx +++ b/sc/inc/dpobject.hxx @@ -55,7 +55,11 @@ namespace com::sun::star { } } -namespace tools { class Rectangle; } +namespace tools +{ + class Rectangle; + class XmlWriter; +} class ScDPSaveData; class ScDPOutput; struct ScImportSourceDesc; @@ -281,6 +285,9 @@ public: return { false, css::uno::Any() }; } + void dumpAsXml(tools::XmlWriter& rWriter) const; + void dumpXmlFile() const; + #if DUMP_PIVOT_TABLE void Dump() const; void DumpCache() const; @@ -435,10 +442,6 @@ public: bool IntersectsTableByRows( SCCOL nCol, SCROW nRow1, SCROW nRow2, SCTAB nTab ) const; bool HasTable( const ScRange& rRange ) const; -#if DEBUG_PIVOT_TABLE - void DumpTables() const; -#endif - private: /** Only to be called from ScDPCache::RemoveReference(). */ void RemoveCache(const ScDPCache* pCache); diff --git a/sc/inc/dpsave.hxx b/sc/inc/dpsave.hxx index ad1e393dc879..3490bcaa98ee 100644 --- a/sc/inc/dpsave.hxx +++ b/sc/inc/dpsave.hxx @@ -46,6 +46,7 @@ class ScDPDimensionSaveData; class ScDPTableData; enum class ScGeneralFunction; namespace sc { class PivotTableFormats; } +namespace tools { class XmlWriter; } // classes to save Data Pilot settings @@ -86,6 +87,8 @@ public: void WriteToSource( const css::uno::Reference<css::uno::XInterface>& xMember, sal_Int32 nPosition ); + void dumpAsXml(tools::XmlWriter& rWriter) const; + #if DUMP_PIVOT_TABLE void Dump(int nIndent = 0) const; #endif @@ -226,6 +229,8 @@ public: void RemoveObsoleteMembers(const MemberSetType& rMembers); + void dumpAsXml(tools::XmlWriter& rWriter) const; + #if DUMP_PIVOT_TABLE void Dump(int nIndent = 0) const; #endif @@ -365,6 +370,8 @@ public: */ SC_DLLPUBLIC bool HasInvisibleMember(std::u16string_view rDimName) const; + void dumpAsXml(tools::XmlWriter& rWriter) const; + #if DUMP_PIVOT_TABLE void Dump() const; #endif diff --git a/sc/inc/dpshttab.hxx b/sc/inc/dpshttab.hxx index c9b45755fbc6..1b5347988bda 100644 --- a/sc/inc/dpshttab.hxx +++ b/sc/inc/dpshttab.hxx @@ -115,6 +115,8 @@ public: virtual const ScDPFilteredCache& GetCacheTable() const override; virtual void ReloadCacheTable() override; + virtual void dumpAsXml(tools::XmlWriter& rWriter) const override; + #if DUMP_PIVOT_TABLE virtual void Dump() const override; #endif diff --git a/sc/inc/dptabdat.hxx b/sc/inc/dptabdat.hxx index 74830406aa31..059eff3324e8 100644 --- a/sc/inc/dptabdat.hxx +++ b/sc/inc/dptabdat.hxx @@ -48,6 +48,7 @@ class ScDPDimension; class ScDPLevel; class ScDPInitState; class ScDocument; +namespace tools { class XmlWriter; } /** * Base class that abstracts different data source types of a datapilot @@ -132,6 +133,7 @@ public: virtual sal_Int32 GetSourceDim( sal_Int32 nDim ); virtual sal_Int32 Compare( sal_Int32 nDim, sal_Int32 nDataId1, sal_Int32 nDataId2); + virtual void dumpAsXml(tools::XmlWriter& rWriter) const; #if DUMP_PIVOT_TABLE virtual void Dump() const; #endif diff --git a/sc/source/core/data/dpcache.cxx b/sc/source/core/data/dpcache.cxx index a4d38a91d3ad..1a1afb4a856b 100644 --- a/sc/source/core/data/dpcache.cxx +++ b/sc/source/core/data/dpcache.cxx @@ -31,6 +31,7 @@ #include <dpnumgroupinfo.hxx> #include <columniterator.hxx> #include <cellvalue.hxx> +#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp> #include <comphelper/parallelsort.hxx> #include <rtl/math.hxx> @@ -40,13 +41,10 @@ #include <unotools/collatorwrapper.hxx> #include <svl/numformat.hxx> #include <svl/zforlist.hxx> +#include <tools/XmlWriter.hxx> #include <o3tl/safeint.hxx> #include <osl/diagnose.h> -#if DUMP_PIVOT_TABLE -#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp> -#endif - // TODO : Threaded pivot cache operation is disabled until we can figure out // ways to make the edit engine and number formatter codes thread-safe in a // proper fashion. @@ -1407,21 +1405,9 @@ sal_Int32 ScDPCache::GetGroupType(tools::Long nDim) const return 0; } -#if DUMP_PIVOT_TABLE - -namespace { -void dumpItems(const ScDPCache& rCache, tools::Long nDim, const ScDPCache::ScDPItemDataVec& rItems, size_t nOffset) +namespace { - for (size_t i = 0; i < rItems.size(); ++i) - std::cout << " " << (i+nOffset) << ": " << rCache.GetFormattedString(nDim, rItems[i], false) << std::endl; -} - -void dumpSourceData(const ScDPCache& rCache, tools::Long nDim, const ScDPCache::ScDPItemDataVec& rItems, const ScDPCache::IndexArrayType& rArray) -{ - for (const auto& rIndex : rArray) - std::cout << " '" << rCache.GetFormattedString(nDim, rItems[rIndex], false) << "'" << std::endl; -} const char* getGroupTypeName(sal_Int32 nType) { @@ -1438,13 +1424,126 @@ const char* getGroupTypeName(sal_Int32 nType) case sheet::DataPilotFieldGroupBy::HOURS: return pNames[5]; case sheet::DataPilotFieldGroupBy::MINUTES: return pNames[6]; case sheet::DataPilotFieldGroupBy::SECONDS: return pNames[7]; - default: - ; } return pNames[0]; } +void dumpItemsAsXml(tools::XmlWriter& rWriter, ScDPCache const& rCache, tools::Long nDim, const ScDPCache::ScDPItemDataVec& rItems, size_t nOffset) +{ + for (size_t i = 0; i < rItems.size(); ++i) + { + rWriter.startElement("item"); + rWriter.attribute("index", i + nOffset); + rWriter.attribute("value", rCache.GetFormattedString(nDim, rItems[i], false)); + rWriter.endElement(); + } +} + +void dumpSourceDataAsXml(tools::XmlWriter& rWriter, ScDPCache const& rCache, tools::Long nDim, const ScDPCache::ScDPItemDataVec& rItems, const ScDPCache::IndexArrayType& rArray) +{ + for (const auto& rIndex : rArray) + { + rWriter.startElement("source_data"); + rWriter.attribute("value", rCache.GetFormattedString(nDim, rItems[rIndex], false)); + rWriter.endElement(); + } +} + +} // end anonymous namespace + +void ScDPCache::dumpAsXml(tools::XmlWriter& rWriter) const +{ + rWriter.startElement("cache"); + + { + size_t index = 0; + for (const auto& rxField : maFields) + { + rWriter.startElement("source"); + const Field& rField = *rxField; + + rWriter.attribute("dimension", GetDimensionName(index)); + rWriter.attribute("id", index); + rWriter.attribute("item_count", rField.maItems.size()); + + dumpItemsAsXml(rWriter, *this, index, rField.maItems, 0); + + if (rField.mpGroup) + { + auto const& rGroup = rField.mpGroup; + rWriter.attribute("group_item_count", rGroup->maItems.size()); + rWriter.attribute("group_type", getGroupTypeName(rGroup->mnGroupType)); + + dumpItemsAsXml(rWriter, *this, index, rField.mpGroup->maItems, rField.maItems.size()); + } + + dumpSourceDataAsXml(rWriter, *this, index, rField.maItems, rField.maData); + + index++; + rWriter.endElement(); + } + } + + { + size_t index = maFields.size(); + for (const auto& rxGroupField : maGroupFields) + { + rWriter.startElement("group"); + const GroupItems& rGroupitems = *rxGroupField; + + rWriter.attribute("id", index); + rWriter.attribute("item_count", rGroupitems.maItems.size()); + rWriter.attribute("group_type", getGroupTypeName(rGroupitems.mnGroupType) ); + + dumpItemsAsXml(rWriter, *this, index, rGroupitems.maItems, 0); + + index++; + rWriter.endElement(); + } + } + + { + struct { SCROW start; SCROW end; bool empty; } aRange; + mdds::flat_segment_tree<SCROW, bool>::const_iterator it = maEmptyRows.begin(), itEnd = maEmptyRows.end(); + if (it != itEnd) + { + aRange.start = it->first; + aRange.empty = it->second; + + for (++it; it != itEnd; ++it) + { + aRange.end = it->first-1; + + rWriter.startElement("empty_row"); + rWriter.attribute("start", aRange.start); + rWriter.attribute("end", aRange.end); + rWriter.attribute("empty", (aRange.empty ? "yes" : "no")); + rWriter.endElement(); + aRange.start = it->first; + aRange.empty = it->second; + } + } + } + + rWriter.endElement(); +} + +#if DUMP_PIVOT_TABLE + +namespace { + +void dumpItems(const ScDPCache& rCache, tools::Long nDim, const ScDPCache::ScDPItemDataVec& rItems, size_t nOffset) +{ + for (size_t i = 0; i < rItems.size(); ++i) + std::cout << " " << (i+nOffset) << ": " << rCache.GetFormattedString(nDim, rItems[i], false) << std::endl; +} + +void dumpSourceData(const ScDPCache& rCache, tools::Long nDim, const ScDPCache::ScDPItemDataVec& rItems, const ScDPCache::IndexArrayType& rArray) +{ + for (const auto& rIndex : rArray) + std::cout << " '" << rCache.GetFormattedString(nDim, rItems[rIndex], false) << "'" << std::endl; +} } void ScDPCache::Dump() const diff --git a/sc/source/core/data/dpobject.cxx b/sc/source/core/data/dpobject.cxx index 3c1cfaa7250a..23f4603f07c2 100644 --- a/sc/source/core/data/dpobject.cxx +++ b/sc/source/core/data/dpobject.cxx @@ -76,10 +76,12 @@ #include <utility> #include <vcl/svapp.hxx> #include <vcl/weld.hxx> +#include <tools/XmlWriter.hxx> #include <vector> #include <memory> #include <algorithm> +#include <filesystem> using namespace com::sun::star; using ::com::sun::star::uno::Sequence; @@ -2900,6 +2902,40 @@ uno::Reference<sheet::XDimensionsSupplier> ScDPObject::CreateSource( const ScDPS return xRet; } +void ScDPObject::dumpAsXml(tools::XmlWriter& rWriter) const +{ + rWriter.startElement("pivot"); + rWriter.attribute("name", GetName()); + + if (mpSaveData) + mpSaveData->dumpAsXml(rWriter); + + if (mpTableData) + { + mpTableData->dumpAsXml(rWriter); + const ScDPCache &rCache = mpTableData->GetCacheTable().getCache(); + rCache.dumpAsXml(rWriter); + } + + rWriter.endElement(); +} + +void ScDPObject::dumpXmlFile() const +{ + auto aFilePath = std::filesystem::current_path() / "pivot_table_dump.xml"; + OUString aFilePathString(aFilePath.u16string()); + + SAL_WARN("sc", "Dumping Pivot Table to " << aFilePathString); + + SvFileStream aStream(aFilePathString, StreamMode::STD_READWRITE | StreamMode::TRUNC); + tools::XmlWriter aWriter(&aStream); + aWriter.startDocument(); + aWriter.startElement("pivotTable"); + dumpAsXml(aWriter); + aWriter.endElement(); + aWriter.endDocument(); +} + #if DUMP_PIVOT_TABLE void ScDPObject::Dump() const @@ -3851,34 +3887,6 @@ bool ScDPCollection::HasTable( const ScRange& rRange ) const return std::any_of(maTables.begin(), maTables.end(), FindIntersectingTable(rRange)); } -#if DEBUG_PIVOT_TABLE - -namespace { - -struct DumpTable -{ - void operator() (const std::unique_ptr<ScDPObject>& rObj) const - { - cout << "-- '" << rObj->GetName() << "'" << endl; - ScDPSaveData* pSaveData = rObj->GetSaveData(); - if (!pSaveData) - return; - - pSaveData->Dump(); - - cout << endl; // blank line - } -}; - -} - -void ScDPCollection::DumpTables() const -{ - std::for_each(maTables.begin(), maTables.end(), DumpTable()); -} - -#endif - void ScDPCollection::RemoveCache(const ScDPCache* pCache) { if (maSheetCaches.remove(pCache)) diff --git a/sc/source/core/data/dpsave.cxx b/sc/source/core/data/dpsave.cxx index fce29e78358a..90ede1217eb8 100644 --- a/sc/source/core/data/dpsave.cxx +++ b/sc/source/core/data/dpsave.cxx @@ -26,6 +26,7 @@ #include <generalfunction.hxx> #include <dptabdat.hxx> #include <pivot/PivotTableFormats.hxx> +#include <tools/XmlWriter.hxx> #include <sal/types.h> #include <sal/log.hxx> @@ -156,6 +157,22 @@ void ScDPSaveMember::WriteToSource( const uno::Reference<uno::XInterface>& xMemb ScUnoHelpFunctions::SetOptionalPropertyValue(xMembProp, SC_UNO_DP_POSITION, nPosition); } +void ScDPSaveMember::dumpAsXml(tools::XmlWriter& rWriter) const +{ + rWriter.startElement("member"); + rWriter.attribute("name", aName); + if (mpLayoutName) + rWriter.attribute("layout_name", *mpLayoutName); + else + rWriter.attribute("layout_name", "(none)"_ostr); + + if (nVisibleMode == SC_DPSAVEMODE_DONTKNOW) + rWriter.attribute("visibility", "(unknown)"_ostr); + else + rWriter.attribute("visibility", (nVisibleMode ? "visible"_ostr : "hidden"_ostr)); + rWriter.endElement(); +} + #if DUMP_PIVOT_TABLE void ScDPSaveMember::Dump(int nIndent) const @@ -644,6 +661,37 @@ void ScDPSaveDimension::RemoveObsoleteMembers(const MemberSetType& rMembers) maMemberList.swap(aNew); } +void ScDPSaveDimension::dumpAsXml(tools::XmlWriter& rWriter) const +{ + static constexpr auto sOrientNames = std::to_array<std::string_view>({ + "hidden", "column", "row", "page", "data" + }); + + rWriter.startElement("dimension"); + rWriter.attribute("name", aName); + if (nOrientation <= DataPilotFieldOrientation_DATA) + rWriter.attribute("orientation", OString(sOrientNames[sal_Int32(nOrientation)])); + else + rWriter.attribute("orientation", "invalid"_ostr); + + if (mpLayoutName) + rWriter.attribute("layout_name", *mpLayoutName); + + if (mpSubtotalName) + rWriter.attribute("subtotal_name", *mpSubtotalName); + else + rWriter.attribute("subtotal_name", "(none)"_ostr); + + rWriter.attribute("data_layout", (bIsDataLayout ? "yes"_ostr : "no"_ostr)); + rWriter.attribute("duplicate", (bDupFlag ? "yes"_ostr : "no"_ostr)); + + for (ScDPSaveMember* pMember : maMemberList) + { + pMember->dumpAsXml(rWriter); + } + rWriter.endElement(); +} + #if DUMP_PIVOT_TABLE void ScDPSaveDimension::Dump(int nIndent) const @@ -1333,6 +1381,15 @@ bool ScDPSaveData::HasInvisibleMember(std::u16string_view rDimName) const return pDim->HasInvisibleMember(); } +void ScDPSaveData::dumpAsXml(tools::XmlWriter& rWriter) const +{ + for (auto const& itDim: m_DimList) + { + const ScDPSaveDimension& rSaveDimension = *itDim; + rSaveDimension.dumpAsXml(rWriter); + } +} + #if DUMP_PIVOT_TABLE void ScDPSaveData::Dump() const diff --git a/sc/source/core/data/dpshttab.cxx b/sc/source/core/data/dpshttab.cxx index f8cfa6de61e9..f95a05fc4edf 100644 --- a/sc/source/core/data/dpshttab.cxx +++ b/sc/source/core/data/dpshttab.cxx @@ -32,6 +32,7 @@ #include <queryentry.hxx> #include <osl/diagnose.h> +#include <tools/XmlWriter.hxx> #include <vector> @@ -208,6 +209,12 @@ void ScSheetDPData::ReloadCacheTable() CreateCacheTable(); } +void ScSheetDPData::dumpAsXml(tools::XmlWriter& rWriter) const +{ + rWriter.startElement("sheet_data"); + rWriter.endElement(); +} + #if DUMP_PIVOT_TABLE void ScSheetDPData::Dump() const diff --git a/sc/source/core/data/dptabdat.cxx b/sc/source/core/data/dptabdat.cxx index d9706f961e2d..b0d2fab09871 100644 --- a/sc/source/core/data/dptabdat.cxx +++ b/sc/source/core/data/dptabdat.cxx @@ -282,6 +282,10 @@ sal_Int32 ScDPTableData::Compare( sal_Int32 nDim, sal_Int32 nDataId1, sal_Int32 return -1; } +void ScDPTableData::dumpAsXml(tools::XmlWriter& /*rWriter*/) const +{ +} + #if DUMP_PIVOT_TABLE void ScDPTableData::Dump() const { diff --git a/sc/source/ui/inc/gridwin.hxx b/sc/source/ui/inc/gridwin.hxx index 228d5088f527..fa2ba12282b9 100644 --- a/sc/source/ui/inc/gridwin.hxx +++ b/sc/source/ui/inc/gridwin.hxx @@ -531,6 +531,7 @@ private: #ifdef DBG_UTIL void dumpCellProperties(); + void dumpPivotTable(); void dumpColumnInformationPixel(); void dumpColumnInformationHmm(); void dumpGraphicInformation(); diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx index 4e6e191c52a9..cbf6a586a949 100644 --- a/sc/source/ui/view/gridwin.cxx +++ b/sc/source/ui/view/gridwin.cxx @@ -3744,6 +3744,10 @@ void ScGridWindow::KeyInput(const KeyEvent& rKEvt) } return; } + else if (rKeyCode.IsMod2() && rKeyCode.GetCode() == KEY_F5) + { + dumpPivotTable(); + } } #endif diff --git a/sc/source/ui/view/gridwin_dbgutil.cxx b/sc/source/ui/view/gridwin_dbgutil.cxx index aba730a9c8f4..f798bf3e017e 100644 --- a/sc/source/ui/view/gridwin_dbgutil.cxx +++ b/sc/source/ui/view/gridwin_dbgutil.cxx @@ -17,6 +17,8 @@ #include <patattr.hxx> #include <userdat.hxx> #include <dpobject.hxx> +#include <tools/XmlWriter.hxx> +#include <filesystem> namespace { @@ -63,6 +65,18 @@ void ScGridWindow::dumpColumnInformationHmm() } } +void ScGridWindow::dumpPivotTable() +{ + ScAddress aPosition = mrViewData.GetCurPos(); + ScDocument& rDocument = mrViewData.GetDocument(); + + const ScDPObject* pDPObject = rDocument.GetDPAtCursor(aPosition.Col(), aPosition.Row(), aPosition.Tab()); + if (!pDPObject) + return; + + pDPObject->dumpXmlFile(); +} + void ScGridWindow::dumpCellProperties() { ScDocument& rDoc = mrViewData.GetDocument();
