chart2/qa/extras/chart2export3.cxx | 22 ++++++++ chart2/qa/extras/data/odt/testEmptyCharts.odt |binary oox/source/export/chartexport.cxx | 66 ++++++++++++++++---------- 3 files changed, 63 insertions(+), 25 deletions(-)
New commits: commit bc1f96229eaf67321c384593a4e59e33b8e80a8f Author: Aron Budea <[email protected]> AuthorDate: Thu Oct 16 20:17:44 2025 +1030 Commit: Aron Budea <[email protected]> CommitDate: Fri Oct 17 15:09:53 2025 +0200 tdf#168885 oox: save more of empty charts Otherwise Word will complain. Affected types: area, bar, bubble, line, stock. Regression from 3b4c11350a631e27345e87ecfe258d12983cbfbc. Change-Id: I56d533d9c55bae45240a1b51733ff60f47b1b2e7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192483 Reviewed-by: Aron Budea <[email protected]> Tested-by: Jenkins Reviewed-by: Balazs Varga <[email protected]> diff --git a/chart2/qa/extras/chart2export3.cxx b/chart2/qa/extras/chart2export3.cxx index 0c8cc4d82c36..f8655e99a3fe 100644 --- a/chart2/qa/extras/chart2export3.cxx +++ b/chart2/qa/extras/chart2export3.cxx @@ -691,6 +691,28 @@ CPPUNIT_TEST_FIXTURE(Chart2ExportTest3, testBarChartSecondaryAxisXLSX) assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:plotArea/c:valAx[2]/c:axId", "val", YValueIdOf2Barchart); } +CPPUNIT_TEST_FIXTURE(Chart2ExportTest3, testEmptyCharts) +{ + loadFromFile(u"odt/testEmptyCharts.odt"); + save(u"Office Open XML Text"_ustr); + + // Make sure each chart exists in the respective XML + xmlDocUniquePtr pXmlDoc = parseExport(u"word/charts/chart1.xml"_ustr); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:plotArea/c:barChart"); + + pXmlDoc = parseExport(u"word/charts/chart2.xml"_ustr); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:plotArea/c:areaChart"); + + pXmlDoc = parseExport(u"word/charts/chart3.xml"_ustr); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:plotArea/c:bubbleChart"); + + pXmlDoc = parseExport(u"word/charts/chart4.xml"_ustr); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:plotArea/c:lineChart"); + + pXmlDoc = parseExport(u"word/charts/chart5.xml"_ustr); + assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:plotArea/c:stockChart"); +} + CPPUNIT_TEST_FIXTURE(Chart2ExportTest3, testTdf148142) { // The document contains a line chart with "Between tick marks" X axis position. diff --git a/chart2/qa/extras/data/odt/testEmptyCharts.odt b/chart2/qa/extras/data/odt/testEmptyCharts.odt new file mode 100644 index 000000000000..54bf12e85763 Binary files /dev/null and b/chart2/qa/extras/data/odt/testEmptyCharts.odt differ diff --git a/oox/source/export/chartexport.cxx b/oox/source/export/chartexport.cxx index 58b8e44d1442..9b747901129b 100644 --- a/oox/source/export/chartexport.cxx +++ b/oox/source/export/chartexport.cxx @@ -2914,12 +2914,14 @@ void ChartExport::exportDataTable( ) void ChartExport::exportAreaChart( const Reference< chart2::XChartType >& xChartType ) { FSHelperPtr pFS = GetFS(); - const std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType); + std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType); + if (aSplitDataSeries.empty()) + { + // Use a dummy data series to output needed basic chart-related XML even in case of empty charts + aSplitDataSeries.push_back({}); + } for (const auto& splitDataSeries : aSplitDataSeries) { - if (!splitDataSeries.hasElements()) - continue; - sal_Int32 nTypeId = XML_areaChart; if (mbIs3DChart) nTypeId = XML_area3DChart; @@ -2927,7 +2929,9 @@ void ChartExport::exportAreaChart( const Reference< chart2::XChartType >& xChart exportGrouping(); bool bPrimaryAxes = true; - exportSeries_chart(xChartType, splitDataSeries, bPrimaryAxes); + if (splitDataSeries.hasElements()) + exportSeries_chart(xChartType, splitDataSeries, bPrimaryAxes); + createAxes(bPrimaryAxes, false); //exportAxesId(bPrimaryAxes); @@ -2942,12 +2946,14 @@ void ChartExport::exportBarChart(const Reference< chart2::XChartType >& xChartTy nTypeId = XML_bar3DChart; FSHelperPtr pFS = GetFS(); - const std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType); + std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType); + if (aSplitDataSeries.empty()) + { + // Use a dummy data series to output needed basic chart-related XML even in case of empty charts + aSplitDataSeries.push_back({}); + } for (const auto& splitDataSeries : aSplitDataSeries) { - if (!splitDataSeries.hasElements()) - continue; - pFS->startElement(FSNS(XML_c, nTypeId)); // bar direction bool bVertical = false; @@ -2963,7 +2969,8 @@ void ChartExport::exportBarChart(const Reference< chart2::XChartType >& xChartTy exportVaryColors(xChartType); bool bPrimaryAxes = true; - exportSeries_chart(xChartType, splitDataSeries, bPrimaryAxes); + if (splitDataSeries.hasElements()) + exportSeries_chart(xChartType, splitDataSeries, bPrimaryAxes); Reference< XPropertySet > xTypeProp(xChartType, uno::UNO_QUERY); @@ -3038,18 +3045,21 @@ void ChartExport::exportBarChart(const Reference< chart2::XChartType >& xChartTy void ChartExport::exportBubbleChart( const Reference< chart2::XChartType >& xChartType ) { FSHelperPtr pFS = GetFS(); - const std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType); + std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType); + if (aSplitDataSeries.empty()) + { + // Use a dummy data series to output needed basic chart-related XML even in case of empty charts + aSplitDataSeries.push_back({}); + } for (const auto& splitDataSeries : aSplitDataSeries) { - if (!splitDataSeries.hasElements()) - continue; - pFS->startElement(FSNS(XML_c, XML_bubbleChart)); exportVaryColors(xChartType); bool bPrimaryAxes = true; - exportSeries_chart(xChartType, splitDataSeries, bPrimaryAxes); + if (splitDataSeries.hasElements()) + exportSeries_chart(xChartType, splitDataSeries, bPrimaryAxes); createAxes(bPrimaryAxes, false); @@ -3150,12 +3160,14 @@ void writeDataLabelsRange(const FSHelperPtr& pFS, const XmlFilterBase* pFB, Data void ChartExport::exportLineChart( const Reference< chart2::XChartType >& xChartType ) { FSHelperPtr pFS = GetFS(); - const std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType); + std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType); + if (aSplitDataSeries.empty()) + { + // Use a dummy data series to output needed basic chart-related XML even in case of empty charts + aSplitDataSeries.push_back({}); + } for (const auto& splitDataSeries : aSplitDataSeries) { - if (!splitDataSeries.hasElements()) - continue; - sal_Int32 nTypeId = XML_lineChart; if( mbIs3DChart ) nTypeId = XML_line3DChart; @@ -3166,7 +3178,8 @@ void ChartExport::exportLineChart( const Reference< chart2::XChartType >& xChart exportVaryColors(xChartType); // TODO: show marker symbol in series? bool bPrimaryAxes = true; - exportSeries_chart(xChartType, splitDataSeries, bPrimaryAxes); + if (splitDataSeries.hasElements()) + exportSeries_chart(xChartType, splitDataSeries, bPrimaryAxes); // show marker? sal_Int32 nSymbolType = css::chart::ChartSymbolType::NONE; @@ -3282,16 +3295,19 @@ void ChartExport::exportScatterChart( const Reference< chart2::XChartType >& xCh void ChartExport::exportStockChart( const Reference< chart2::XChartType >& xChartType ) { FSHelperPtr pFS = GetFS(); - const std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType); + std::vector<Sequence<Reference<chart2::XDataSeries> > > aSplitDataSeries = splitDataSeriesByAxis(xChartType); + if (aSplitDataSeries.empty()) + { + // Use a dummy data series to output needed basic chart-related XML even in case of empty charts + aSplitDataSeries.push_back({}); + } for (const auto& splitDataSeries : aSplitDataSeries) { - if (!splitDataSeries.hasElements()) - continue; - pFS->startElement(FSNS(XML_c, XML_stockChart)); bool bPrimaryAxes = true; - exportCandleStickSeries(splitDataSeries, bPrimaryAxes); + if (splitDataSeries.hasElements()) + exportCandleStickSeries(splitDataSeries, bPrimaryAxes); // export stock properties Reference< css::chart::XStatisticDisplay > xStockPropProvider(mxDiagram, uno::UNO_QUERY);
