sw/CppunitTest_sw_filter_md.mk |    1 
 sw/qa/filter/md/md.cxx         |   44 ++++++++++++++++++++++++++++++++++++++++-
 sw/source/filter/md/wrtmd.cxx  |   35 ++++++++++++++++++++++++++++++--
 sw/source/filter/md/wrtmd.hxx  |    3 ++
 4 files changed, 80 insertions(+), 3 deletions(-)

New commits:
commit 91a98bd1da8d14ad85c4911e28e8afcc0f052bbe
Author:     Miklos Vajna <[email protected]>
AuthorDate: Wed Sep 10 08:35:40 2025 +0200
Commit:     Caolán McNamara <[email protected]>
CommitDate: Wed Sep 10 10:23:31 2025 +0200

    sw markdown export: handle table cell adjustment
    
    The bugdoc has a table where all lines have the same amount of cells,
    and the "columns" are left, center and right aligned. All alignment is
    set to "left" on markdown export.
    
    The problem is that Writer has no way to represent cell-level horizontal
    alignment, but the HTML parser sets the cell alignment on the content of
    the cell.
    
    Fix the problem by doing the same on markdown export: take the first
    text node in the cell, and if that has a custom alignment, then work
    with that.
    
    Interestingly this cell-level horizontal alignment is not only missing
    from ODF, it's also missing from OOXML.
    
    Change-Id: Ibf0cfd1e947f342e8745e6198742882893f08fe3
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190731
    Reviewed-by: Caolán McNamara <[email protected]>
    Tested-by: Jenkins CollaboraOffice <[email protected]>

diff --git a/sw/CppunitTest_sw_filter_md.mk b/sw/CppunitTest_sw_filter_md.mk
index 4fc01af86145..66ff788c18e7 100644
--- a/sw/CppunitTest_sw_filter_md.mk
+++ b/sw/CppunitTest_sw_filter_md.mk
@@ -18,6 +18,7 @@ $(eval $(call 
gb_CppunitTest_add_exception_objects,sw_filter_md, \
 $(eval $(call gb_CppunitTest_use_libraries,sw_filter_md, \
     cppu \
     cppuhelper \
+    editeng \
     sal \
     subsequenttest \
     sw \
diff --git a/sw/qa/filter/md/md.cxx b/sw/qa/filter/md/md.cxx
index aea24eec80e2..4de7d058ded0 100644
--- a/sw/qa/filter/md/md.cxx
+++ b/sw/qa/filter/md/md.cxx
@@ -355,7 +355,7 @@ CPPUNIT_TEST_FIXTURE(Test, testExportingTable)
         SAL_NEWLINE_STRING
         "| A1 | B1 | C1 |" SAL_NEWLINE_STRING
         // Delimiter row consists of cells whose only content are hyphens (-).
-        "|-|-|-|" SAL_NEWLINE_STRING
+        "| - | - | - |" SAL_NEWLINE_STRING
         "| A2 | B2 | C2 |" SAL_NEWLINE_STRING
         "| A3 | B3 | C3 |" SAL_NEWLINE_STRING
         SAL_NEWLINE_STRING
@@ -463,6 +463,48 @@ CPPUNIT_TEST_FIXTURE(Test, testCodeBlockMdExport)
     CPPUNIT_ASSERT_EQUAL(aExpected, aActual);
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testTableColumnAdjustMdExport)
+{
+    // Given a document that has a table with custom adjustments:
+    createSwDoc();
+    SwDocShell* pDocShell = getSwDocShell();
+    SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+    pWrtShell->Insert(u"before"_ustr);
+    SwInsertTableOptions aInsertTableOptions(SwInsertTableFlags::DefaultBorder,
+                                             /*nRowsToRepeat=*/0);
+    pWrtShell->InsertTable(aInsertTableOptions, /*nRows=*/1, /*nCols=*/3);
+    pWrtShell->Insert(u"after"_ustr);
+    pWrtShell->SttPara();
+    pWrtShell->MoveTable(GotoPrevTable, fnTableStart);
+    pWrtShell->Insert(u"A1"_ustr);
+    pWrtShell->GoNextCell();
+    pWrtShell->Insert(u"B1"_ustr);
+    pWrtShell->SetAttrItem(SvxAdjustItem(SvxAdjust::Center, 
RES_PARATR_ADJUST));
+    pWrtShell->GoNextCell();
+    pWrtShell->Insert(u"C1"_ustr);
+    pWrtShell->SetAttrItem(SvxAdjustItem(SvxAdjust::Right, RES_PARATR_ADJUST));
+
+    // When saving that to markdown:
+    save(mpFilter);
+
+    // Then make sure the table content is not lost:
+    std::string aActual = TempFileToString();
+    std::string aExpected(
+        // clang-format off
+        "before" SAL_NEWLINE_STRING
+        SAL_NEWLINE_STRING
+        "| A1 | B1 | C1 |" SAL_NEWLINE_STRING
+        "| - | :-: | -: |" SAL_NEWLINE_STRING
+        SAL_NEWLINE_STRING
+        "after" SAL_NEWLINE_STRING
+        // clang-format on
+    );
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Actual  : | - | - | - |
+    // i.e. the delimiter row's cell adjustments were lost.
+    CPPUNIT_ASSERT_EQUAL(aExpected, aActual);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/sw/source/filter/md/wrtmd.cxx b/sw/source/filter/md/wrtmd.cxx
index 6e55f4792a28..48134875b499 100644
--- a/sw/source/filter/md/wrtmd.cxx
+++ b/sw/source/filter/md/wrtmd.cxx
@@ -659,7 +659,20 @@ void OutMarkdown_SwTextNode(SwMDWriter& rWrt, const 
SwTextNode& rNode, bool bFir
             rWrt.Strm().WriteUnicodeOrByteText(u"" SAL_NEWLINE_STRING);
             for (size_t nBox = 0; nBox < oCellInfo->nFirstRowBoxCount; ++nBox)
             {
-                rWrt.Strm().WriteUnicodeOrByteText(u"|-");
+                std::u16string aDelimiter(u"| - ");
+                // Decorate with leading or trailing colon if the adjustment 
is not the default.
+                switch (oCellInfo->aFirstRowBoxAdjustments[nBox])
+                {
+                    case SvxAdjust::Center:
+                        aDelimiter = u"| :-: ";
+                        break;
+                    case SvxAdjust::Right:
+                        aDelimiter = u"| -: ";
+                        break;
+                    default:
+                        break;
+                }
+                rWrt.Strm().WriteUnicodeOrByteText(aDelimiter);
             }
             rWrt.Strm().WriteUnicodeOrByteText(u"|");
         }
@@ -680,13 +693,30 @@ void OutMarkdown_SwTableNode(SwMDWriter& rWrt, const 
SwTableNode& rTableNode)
     for (size_t nLine = 0; nLine < rTable.GetTabLines().size(); ++nLine)
     {
         const SwTableLine* pLine = rTable.GetTabLines()[nLine];
+        std::vector<SvxAdjust> aBoxAdjustments;
         for (size_t nBox = 0; nBox < pLine->GetTabBoxes().size(); ++nBox)
         {
             const SwTableBox* pBox = pLine->GetTabBoxes()[nBox];
             const SwStartNode* pStart = pBox->GetSttNd();
-            SwMDCellInfo& rStartInfo = 
aTableInfo.aCellInfos[pStart->GetIndex() + 1];
+            SwNodeOffset nCellStartIndex = pStart->GetIndex() + 1;
+            SwMDCellInfo& rStartInfo = aTableInfo.aCellInfos[nCellStartIndex];
             const SwEndNode* pEnd = pStart->EndOfSectionNode();
             rStartInfo.bCellStart = true;
+
+            if (nLine == 0)
+            {
+                // First row, save the alignment of the first text node, if 
the cell has one.
+                SwTextNode* pCellStartNode
+                    = rWrt.m_pDoc->GetNodes()[nCellStartIndex]->GetTextNode();
+                SvxAdjust eAdjust{};
+                if (pCellStartNode)
+                {
+                    const SwAttrSet& rCellStartSet = 
pCellStartNode->GetSwAttrSet();
+                    eAdjust = rCellStartSet.Get(RES_PARATR_ADJUST).GetAdjust();
+                }
+                aBoxAdjustments.push_back(eAdjust);
+            }
+
             if (nBox == 0)
             {
                 rStartInfo.bRowStart = true;
@@ -699,6 +729,7 @@ void OutMarkdown_SwTableNode(SwMDWriter& rWrt, const 
SwTableNode& rTableNode)
                 {
                     rEndInfo.bFirstRowEnd = true;
                     rEndInfo.nFirstRowBoxCount = pLine->GetTabBoxes().size();
+                    rEndInfo.aFirstRowBoxAdjustments = aBoxAdjustments;
                 }
             }
         }
diff --git a/sw/source/filter/md/wrtmd.hxx b/sw/source/filter/md/wrtmd.hxx
index 10960de60461..d3f6d15db58f 100644
--- a/sw/source/filter/md/wrtmd.hxx
+++ b/sw/source/filter/md/wrtmd.hxx
@@ -36,7 +36,10 @@ struct SwMDCellInfo
     bool bRowStart = false;
     bool bRowEnd = false;
     bool bFirstRowEnd = false;
+
+    // These are only set in the bFirstRowEnd == true case.
     size_t nFirstRowBoxCount = 0;
+    std::vector<SvxAdjust> aFirstRowBoxAdjustments;
 };
 
 /// Tracks information about one SwTableNode, the instance is alive while the 
write of the table is

Reply via email to