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);

Reply via email to