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 f059851ccef11d835bd09678414ebcf56c73f7d6
Author:     Aron Budea <[email protected]>
AuthorDate: Thu Oct 16 20:17:44 2025 +1030
Commit:     Andras Timar <[email protected]>
CommitDate: Fri Oct 17 16:50:32 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]>
    (cherry picked from commit bc1f96229eaf67321c384593a4e59e33b8e80a8f)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192576
    Reviewed-by: Andras Timar <[email protected]>
    Tested-by: Jenkins CollaboraOffice <[email protected]>

diff --git a/chart2/qa/extras/chart2export3.cxx 
b/chart2/qa/extras/chart2export3.cxx
index 1b17d0ba1e6c..ebd1d914c93a 100644
--- a/chart2/qa/extras/chart2export3.cxx
+++ b/chart2/qa/extras/chart2export3.cxx
@@ -686,6 +686,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 ee6150d47f2a..11aa39786daf 100644
--- a/oox/source/export/chartexport.cxx
+++ b/oox/source/export/chartexport.cxx
@@ -2843,12 +2843,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;
@@ -2856,7 +2858,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);
 
@@ -2871,12 +2875,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;
@@ -2892,7 +2898,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);
 
@@ -2967,18 +2974,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);
 
@@ -3079,12 +3089,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;
@@ -3095,7 +3107,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;
@@ -3211,16 +3224,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