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 5d0022c28b149dcc1db22176e442d130ff8d0279
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Wed Sep 10 08:35:40 2025 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Wed Sep 10 17:39:51 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/+/190739
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/CppunitTest_sw_filter_md.mk b/sw/CppunitTest_sw_filter_md.mk
index 533e6b9d6529..c16777849709 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 2f62fa80703b..824b80d3874d 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 75400719e687..7430aa389447 100644
--- a/sw/source/filter/md/wrtmd.cxx
+++ b/sw/source/filter/md/wrtmd.cxx
@@ -678,7 +678,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"|");
         }
@@ -699,13 +712,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;
@@ -718,6 +748,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