chart2/qa/extras/chart2export2.cxx             |   11 +++++
 chart2/qa/extras/data/xlsx/waterfall2.xlsx     |binary
 include/oox/export/chartexport.hxx             |    2 -
 oox/source/drawingml/chart/plotareacontext.cxx |    7 +++
 oox/source/drawingml/chart/titlecontext.cxx    |    6 ++-
 oox/source/export/chartexport.cxx              |   47 +++++++++++++------------
 6 files changed, 49 insertions(+), 24 deletions(-)

New commits:
commit 996bf7400802ca79f99d590dea2f5aa8762977b7
Author:     Kurt Nordback <[email protected]>
AuthorDate: Sat Jan 31 06:31:54 2026 -0700
Commit:     Tomaž Vajngerl <[email protected]>
CommitDate: Mon Mar 2 07:40:43 2026 +0100

    tdf#165742 Step 5.5: Fixes to chartex axis import/export
    
    Improvements and fixes for chartex axes, plus a rudimentary round-trip test.
    
    Change-Id: I1d34aae9a139ea970f3d06315d32aefffd03598a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198453
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <[email protected]>

diff --git a/chart2/qa/extras/chart2export2.cxx 
b/chart2/qa/extras/chart2export2.cxx
index 25a51dd7381e..32766ba9b161 100644
--- a/chart2/qa/extras/chart2export2.cxx
+++ b/chart2/qa/extras/chart2export2.cxx
@@ -276,6 +276,17 @@ CPPUNIT_TEST_FIXTURE(Chart2ExportTest2, testChartexPPTX)
                 "layoutId", u"funnel");
 }
 
+CPPUNIT_TEST_FIXTURE(Chart2ExportTest2, testChartexAxes)
+{
+    loadFromFile(u"xlsx/waterfall2.xlsx");
+    save(TestFilter::XLSX);
+    xmlDocUniquePtr pXmlDoc = parseExport(u"xl/charts/chartEx1.xml"_ustr);
+    CPPUNIT_ASSERT(pXmlDoc);
+
+    // Should be two axes
+    assertXPath(pXmlDoc, "/cx:chartSpace/cx:chart/cx:plotArea/cx:axis", 2);
+}
+
 CPPUNIT_TEST_FIXTURE(Chart2ExportTest2, testAxisTitleRotationXLSX)
 {
     loadFromFile(u"xlsx/axis_title_rotation.xlsx");
diff --git a/chart2/qa/extras/data/xlsx/waterfall2.xlsx 
b/chart2/qa/extras/data/xlsx/waterfall2.xlsx
new file mode 100644
index 000000000000..573b0b69da48
Binary files /dev/null and b/chart2/qa/extras/data/xlsx/waterfall2.xlsx differ
diff --git a/include/oox/export/chartexport.hxx 
b/include/oox/export/chartexport.hxx
index 385fda19f806..6fd71cf87da1 100644
--- a/include/oox/export/chartexport.hxx
+++ b/include/oox/export/chartexport.hxx
@@ -282,7 +282,7 @@ private:
         const css::uno::Reference< css::beans::XPropertySet >& xMinorGrid,
         sal_Int32 nAxisType,
         const AxisIdPair& rAxisIdPair);
-    void createAxes(bool bPrimaryAxes, bool bCheckCombinedAxes);
+    void createAxes(bool bPrimaryAxes, bool bCheckCombinedAxes, bool 
bIsChartex);
     void exportView3D();
     bool isDeep3dChart();
 
diff --git a/oox/source/drawingml/chart/plotareacontext.cxx 
b/oox/source/drawingml/chart/plotareacontext.cxx
index c3c3fc6af82f..95b20c8f77d9 100644
--- a/oox/source/drawingml/chart/plotareacontext.cxx
+++ b/oox/source/drawingml/chart/plotareacontext.cxx
@@ -175,6 +175,13 @@ ContextHandlerRef PlotAreaContext::onCreateContext( 
sal_Int32 nElement, [[maybe_
                     if (rAttribs.hasAttribute(XML_id)) {
                         sal_Int32 nId = rAttribs.getInteger(XML_id, -1);
                         // TODO: also handle attribute "hidden"
+
+                        // Add the id to the axis id list in the (fictitious)
+                        // type group
+                        std::shared_ptr<TypeGroupModel> aTGM =
+                            
mrModel.maTypeGroups.get(mrModel.maTypeGroups.size() - 1);
+                        aTGM->maAxisIds.push_back(nId);
+
                         return new CxAxisContext(*this, 
mrModel.maAxes.create(nElement, false), nId);
                     } else {
                         return nullptr;
diff --git a/oox/source/drawingml/chart/titlecontext.cxx 
b/oox/source/drawingml/chart/titlecontext.cxx
index 1470aa1b44e7..d9375536f5df 100644
--- a/oox/source/drawingml/chart/titlecontext.cxx
+++ b/oox/source/drawingml/chart/titlecontext.cxx
@@ -46,7 +46,9 @@ TextContext::~TextContext()
 ContextHandlerRef TextContext::onCreateContext( sal_Int32 nElement, const 
AttributeList& )
 {
     // this context handler is used for <c:tx> and embedded <c:v> elements
-    if( isCurrentElement( C_TOKEN( tx ) ) || isCurrentElement(CX_TOKEN(tx)) ) 
switch( nElement )
+    if( isCurrentElement( C_TOKEN( tx ) ) ||
+            isCurrentElement(CX_TOKEN(tx)) ||
+            isCurrentElement(CX_TOKEN(txData)) ) switch( nElement )
     {
         case C_TOKEN( rich ):
         case CX_TOKEN( rich ):
@@ -71,7 +73,7 @@ ContextHandlerRef TextContext::onCreateContext( sal_Int32 
nElement, const Attrib
 
 void TextContext::onCharacters( const OUString& rChars )
 {
-    if( isCurrentElement( C_TOKEN( v ) ) )
+    if( isCurrentElement( C_TOKEN( v ) ) ||  isCurrentElement( CX_TOKEN( v ) ))
     {
         // Static text is stored as a single string formula token for Excel 
document.
         mrModel.mxDataSeq.create().maFormula =  "\"" + rChars + "\"";
diff --git a/oox/source/export/chartexport.cxx 
b/oox/source/export/chartexport.cxx
index 7fb109ccdd7a..bf9486950c3d 100644
--- a/oox/source/export/chartexport.cxx
+++ b/oox/source/export/chartexport.cxx
@@ -2560,7 +2560,7 @@ void ChartExport::exportPlotArea(const Reference< 
css::chart::XChartDocument >&
         pFS->singleElement(FSNS(XML_c, XML_barDir), XML_val, "col");
         pFS->singleElement(FSNS(XML_c, XML_grouping), XML_val, "clustered");
         pFS->singleElement(FSNS(XML_c, XML_varyColors), XML_val, "0");
-        createAxes(true, false);
+        createAxes(true, false, false);
         pFS->endElement(FSNS(XML_c, XML_barChart));
     }
 
@@ -3112,7 +3112,7 @@ void ChartExport::exportAreaChart( const Reference< 
chart2::XChartType >& xChart
         if (splitDataSeries.hasElements())
             exportSeries_chart(xChartType, splitDataSeries, bPrimaryAxes);
 
-        createAxes(bPrimaryAxes, false);
+        createAxes(bPrimaryAxes, false, false);
         //exportAxesId(bPrimaryAxes);
 
         pFS->endElement(FSNS(XML_c, nTypeId));
@@ -3216,7 +3216,7 @@ void ChartExport::exportBarChart(const Reference< 
chart2::XChartType >& xChartTy
             }
         }
 
-        createAxes(bPrimaryAxes, false);
+        createAxes(bPrimaryAxes, false, false);
 
         pFS->endElement(FSNS(XML_c, nTypeId));
     }
@@ -3241,7 +3241,7 @@ void ChartExport::exportBubbleChart( const Reference< 
chart2::XChartType >& xCha
         if (splitDataSeries.hasElements())
             exportSeries_chart(xChartType, splitDataSeries, bPrimaryAxes);
 
-        createAxes(bPrimaryAxes, false);
+        createAxes(bPrimaryAxes, false, false);
 
         pFS->endElement(FSNS(XML_c, XML_bubbleChart));
     }
@@ -3259,6 +3259,8 @@ void ChartExport::exportChartex( const Reference< 
chart2::XChartType >& xChartTy
         if (!splitDataSeries.hasElements())
             continue;
 
+        createAxes(true, false, true);
+
         //exportVaryColors(xChartType);
 
         exportSeries_chartex(xChartType, splitDataSeries, sTypeName);
@@ -3396,7 +3398,7 @@ void ChartExport::exportLineChart( const Reference< 
chart2::XChartType >& xChart
             pFS->singleElement(FSNS(XML_c, XML_marker), XML_val, marker);
         }
 
-        createAxes(bPrimaryAxes, true);
+        createAxes(bPrimaryAxes, true, false);
 
         pFS->endElement( FSNS( XML_c, nTypeId ) );
     }
@@ -3441,7 +3443,7 @@ void ChartExport::exportRadarChart( const Reference< 
chart2::XChartType >& xChar
     exportVaryColors(xChartType);
     bool bPrimaryAxes = true;
     exportAllSeries(xChartType, bPrimaryAxes);
-    createAxes(bPrimaryAxes, false);
+    createAxes(bPrimaryAxes, false, false);
 
     pFS->endElement( FSNS( XML_c, XML_radarChart ) );
 }
@@ -3471,7 +3473,7 @@ void ChartExport::exportScatterChartSeries( const 
Reference< chart2::XChartType
     bool bPrimaryAxes = true;
     if (pSeries)
         exportSeries_chart(xChartType, *pSeries, bPrimaryAxes);
-    createAxes(bPrimaryAxes, false);
+    createAxes(bPrimaryAxes, false, false);
     //exportAxesId(bPrimaryAxes);
 
     pFS->endElement( FSNS( XML_c, XML_scatterChart ) );
@@ -3520,7 +3522,7 @@ void ChartExport::exportStockChart( const Reference< 
chart2::XChartType >& xChar
             exportUpDownBars(xChartType);
         }
 
-        createAxes(bPrimaryAxes, false);
+        createAxes(bPrimaryAxes, false, false);
 
         pFS->endElement(FSNS(XML_c, XML_stockChart));
     }
@@ -3595,7 +3597,7 @@ void ChartExport::exportSurfaceChart( const Reference< 
chart2::XChartType >& xCh
     exportVaryColors(xChartType);
     bool bPrimaryAxes = true;
     exportAllSeries(xChartType, bPrimaryAxes);
-    createAxes(bPrimaryAxes, false);
+    createAxes(bPrimaryAxes, false, false);
 
     pFS->endElement( FSNS( XML_c, nTypeId ) );
 }
@@ -5584,7 +5586,7 @@ void ChartExport::exportDataPoints(
 }
 
 // Generalized axis output
-void ChartExport::createAxes(bool bPrimaryAxes, bool bCheckCombinedAxes)
+void ChartExport::createAxes(bool bPrimaryAxes, bool bCheckCombinedAxes, bool 
bIsChartex)
 {
     sal_Int32 nAxisIdx, nAxisIdy;
     bool bPrimaryAxisExists = false;
@@ -5610,19 +5612,22 @@ void ChartExport::createAxes(bool bPrimaryAxes, bool 
bCheckCombinedAxes)
         maAxes.emplace_back( eXAxis, nAxisIdx, nAxisIdy );
         maAxes.emplace_back( eYAxis, nAxisIdy, nAxisIdx );
     }
-    // Export IDs
-    FSHelperPtr pFS = GetFS();
-    pFS->singleElement(FSNS(XML_c, XML_axId), XML_val, 
OString::number(nAxisIdx));
-    pFS->singleElement(FSNS(XML_c, XML_axId), XML_val, 
OString::number(nAxisIdy));
-    if (mbHasZAxis)
-    {
-        sal_Int32 nAxisIdz = 0;
-        if( isDeep3dChart() )
+
+    if (!bIsChartex) {
+        // Export IDs
+        FSHelperPtr pFS = GetFS();
+        pFS->singleElement(FSNS(XML_c, XML_axId), XML_val, 
OString::number(nAxisIdx));
+        pFS->singleElement(FSNS(XML_c, XML_axId), XML_val, 
OString::number(nAxisIdy));
+        if (mbHasZAxis)
         {
-            nAxisIdz = lcl_generateRandomValue();
-            maAxes.emplace_back( AXIS_PRIMARY_Z, nAxisIdz, nAxisIdy );
+            sal_Int32 nAxisIdz = 0;
+            if( isDeep3dChart() )
+            {
+                nAxisIdz = lcl_generateRandomValue();
+                maAxes.emplace_back( AXIS_PRIMARY_Z, nAxisIdz, nAxisIdy );
+            }
+            pFS->singleElement(FSNS(XML_c, XML_axId), XML_val, 
OString::number(nAxisIdz));
         }
-        pFS->singleElement(FSNS(XML_c, XML_axId), XML_val, 
OString::number(nAxisIdz));
     }
 }
 

Reply via email to