chart2/qa/extras/chart2export3.cxx | 22 ++++++++ chart2/qa/extras/data/odt/testEmptyCharts.odt |binary oox/source/export/chartexport.cxx | 65 ++++++++++++++++---------- 3 files changed, 62 insertions(+), 25 deletions(-)
New commits: commit 30ca1deeebbdb3cf69816fe65401d91e36596717 Author: Aron Budea <[email protected]> AuthorDate: Thu Oct 16 20:17:44 2025 +1030 Commit: Xisco Fauli <[email protected]> CommitDate: Tue Oct 21 14:12: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]> Signed-off-by: Xisco Fauli <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192782 diff --git a/chart2/qa/extras/chart2export3.cxx b/chart2/qa/extras/chart2export3.cxx index fd96286e7c86..d5e69f6120a5 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 aa0b03a31a1c..aba13dd9bb6c 100644 --- a/oox/source/export/chartexport.cxx +++ b/oox/source/export/chartexport.cxx @@ -2637,12 +2637,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; @@ -2650,7 +2652,8 @@ void ChartExport::exportAreaChart( const Reference< chart2::XChartType >& xChart exportGrouping(); bool bPrimaryAxes = true; - exportSeries(xChartType, splitDataSeries, bPrimaryAxes, false); + if (splitDataSeries.hasElements()) + exportSeries(xChartType, splitDataSeries, bPrimaryAxes, false); createAxes(bPrimaryAxes, false); pFS->endElement(FSNS(XML_c, nTypeId)); @@ -2664,12 +2667,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; @@ -2685,7 +2690,8 @@ void ChartExport::exportBarChart(const Reference< chart2::XChartType >& xChartTy exportVaryColors(xChartType); bool bPrimaryAxes = true; - exportSeries(xChartType, splitDataSeries, bPrimaryAxes, false); + if (splitDataSeries.hasElements()) + exportSeries(xChartType, splitDataSeries, bPrimaryAxes, false); Reference< XPropertySet > xTypeProp(xChartType, uno::UNO_QUERY); @@ -2760,18 +2766,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(xChartType, splitDataSeries, bPrimaryAxes, false); + if (splitDataSeries.hasElements()) + exportSeries(xChartType, splitDataSeries, bPrimaryAxes, false); createAxes(bPrimaryAxes, false); @@ -2877,12 +2886,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; @@ -2893,7 +2904,8 @@ void ChartExport::exportLineChart( const Reference< chart2::XChartType >& xChart exportVaryColors(xChartType); // TODO: show marker symbol in series? bool bPrimaryAxes = true; - exportSeries(xChartType, splitDataSeries, bPrimaryAxes, false); + if (splitDataSeries.hasElements()) + exportSeries(xChartType, splitDataSeries, bPrimaryAxes, false); // show marker? sal_Int32 nSymbolType = css::chart::ChartSymbolType::NONE; @@ -3008,16 +3020,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);
