sc/Library_sc.mk               |    1 
 sc/functions_setup.mk          |    1 
 sc/source/ui/view/viewfun5.cxx |  119 +++++++++++++++++++++++++++++++++++++++++
 sc/ucalc_setup.mk              |    1 
 4 files changed, 122 insertions(+)

New commits:
commit aeedb45f8f18290b7fee882874a4afb589f212e4
Author:     Ujjawal Kumar <[email protected]>
AuthorDate: Wed Jul 30 11:00:14 2025 +0530
Commit:     Thorsten Behrens <[email protected]>
CommitDate: Sun Aug 10 21:11:22 2025 +0200

    tdf#165590 Parse Markdown tables into Calc
    
    This commit adds a dialog box that prompts the user to choose between
    the default CSV importer and the Markdown importer when Markdown data
    is detected on the clipboard.
    
    Change-Id: I2ac162e13040b0414bf0cdc5d3eb7ac997db9503
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188528
    Tested-by: Jenkins
    Reviewed-by: Thorsten Behrens <[email protected]>

diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index 6fed08771625..c1bfa620e75d 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -55,6 +55,7 @@ $(eval $(call gb_Library_use_externals,sc,\
     icuuc \
     libxml2 \
     mdds_headers \
+    md4c \
 ))
 
 ifneq ($(SYSTEM_LIBORCUS),)
diff --git a/sc/functions_setup.mk b/sc/functions_setup.mk
index 1c82249ab5fd..2a0c78c8fca9 100644
--- a/sc/functions_setup.mk
+++ b/sc/functions_setup.mk
@@ -21,6 +21,7 @@ $(eval $(call 
gb_CppunitTest_add_exception_objects,sc_$(1)_functions_test, \
 $(eval $(call gb_CppunitTest_use_externals,sc_$(1)_functions_test, \
        boost_headers \
        mdds_headers \
+        md4c \
 ))
 
 $(eval $(call gb_CppunitTest_use_libraries,sc_$(1)_functions_test, \
diff --git a/sc/source/ui/view/viewfun5.cxx b/sc/source/ui/view/viewfun5.cxx
index 9599833e00e0..968df102dac6 100644
--- a/sc/source/ui/view/viewfun5.cxx
+++ b/sc/source/ui/view/viewfun5.cxx
@@ -26,12 +26,17 @@
 #include <svx/unomodel.hxx>
 #include <unotools/streamwrap.hxx>
 
+#include <svtools/svtresid.hxx>
+#include <svtools/strings.hrc>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
 #include <svx/svditer.hxx>
 #include <svx/svdobj.hxx>
 #include <svx/svdogrp.hxx>
 #include <svx/svdouno.hxx>
 #include <svx/svdoole2.hxx>
 #include <svx/svdpage.hxx>
+#include <svx/GenericDropDownFieldDialog.hxx>
 #include <sfx2/dispatch.hxx>
 #include <sfx2/docfile.hxx>
 #include <comphelper/classids.hxx>
@@ -45,12 +50,14 @@
 #include <osl/thread.h>
 #include <o3tl/unit_conversion.hxx>
 #include <o3tl/string_view.hxx>
+#include <md4c.h>
 
 #include <comphelper/automationinvokedzone.hxx>
 #include <comphelper/lok.hxx>
 #include <comphelper/processfactory.hxx>
 #include <comphelper/storagehelper.hxx>
 #include <comphelper/string.hxx>
+#include <comphelper/markdown.hxx>
 
 #include <viewfunc.hxx>
 #include <docsh.hxx>
@@ -657,6 +664,89 @@ bool ScViewFunc::PasteDataFormatSource( 
SotClipboardFormatId nFormatId,
     return bRet;
 }
 
+static bool lcl_convert_markdown_to_csv(OUString& rData)
+{
+
+    auto enter_block_callbck = [](MD_BLOCKTYPE, void*, void*) -> int {
+        return 0;
+    };
+
+    auto leave_block_callbck = [](MD_BLOCKTYPE type, void*, void* userdata) -> 
int {
+
+        OUString& rStr = *static_cast<OUString*>(userdata);
+        switch(type)
+        {
+            case MD_BLOCK_DOC:
+            case MD_BLOCK_QUOTE:
+            case MD_BLOCK_UL:
+            case MD_BLOCK_OL:
+            case MD_BLOCK_LI:
+            case MD_BLOCK_HR:
+            case MD_BLOCK_H:
+            case MD_BLOCK_CODE:
+            case MD_BLOCK_HTML:
+            case MD_BLOCK_P:
+            case MD_BLOCK_TABLE:
+            case MD_BLOCK_THEAD:
+            case MD_BLOCK_TBODY:
+                break;
+            case MD_BLOCK_TR:
+            {
+                rStr += u"
"_ustr;
+                break;
+            }
+            case MD_BLOCK_TH:
+            case MD_BLOCK_TD:
+            {
+                rStr += u","_ustr;
+                break;
+            }
+        }
+
+        return 0;
+    };
+
+    auto enter_span_callbck = [](MD_SPANTYPE, void*, void*) -> int {
+        return 0;
+    };
+
+    auto leave_span_callbck = [](MD_SPANTYPE, void*, void*) -> int {
+        return 0;
+    };
+
+    auto text_callbck = [](MD_TEXTTYPE, const MD_CHAR* text, MD_SIZE size, 
void* userdata) -> int {
+
+        OUString& rStr = *static_cast<OUString*>(userdata);
+
+        OUString aText = OStringToOUString({text, size}, 
RTL_TEXTENCODING_UTF8);
+        rStr += aText;
+
+        return 0;
+    };
+
+    MD_PARSER parser = {0,
+                        MD_FLAG_TABLES,
+                        enter_block_callbck,
+                        leave_block_callbck,
+                        enter_span_callbck,
+                        leave_span_callbck,
+                        text_callbck,
+                        nullptr,
+                        nullptr};
+
+
+    OUString aConvertedData;
+    OString rawData = OUStringToOString(rData, RTL_TEXTENCODING_UTF8);
+
+    int ret = md_parse(rawData.getStr(), rawData.getLength(), &parser, 
static_cast<void*>(&aConvertedData));
+
+    if(ret != 0)
+        return false;
+
+    rData = aConvertedData;
+    return true;
+}
+
 bool ScViewFunc::PasteDataFormatFormattedText( SotClipboardFormatId nFormatId,
                     const uno::Reference<datatransfer::XTransferable>& 
rxTransferable,
                     SCCOL nPosX, SCROW nPosY, bool bAllowDialogs,
@@ -734,6 +824,35 @@ bool ScViewFunc::PasteDataFormatFormattedText( 
SotClipboardFormatId nFormatId,
         {
             vcl::Window* pParent = GetActiveWin();
 
+            OUString aSelection;
+            std::vector<OUString> aFormats;
+            aFormats.push_back(SvtResId(STR_FORMAT_STRING));
+
+            if(comphelper::IsMarkdownData(*pStrBuffer)) //markdown
+            {
+                aFormats.push_back(SvtResId(STR_FORMAT_ID_MARKDOWN));
+            }
+
+            if(aFormats.size() > 1)
+            {
+                GenericDropDownFieldDialog aDialog(pParent->GetFrameWeld(),
+                                                   
SvxResId(RID_SVXSTR_PASTE_AS_DIALOG_TITLE),
+                                                   aFormats);
+                short nRet = aDialog.run();
+                if( nRet == RET_OK)
+                {
+                    aSelection = aDialog.GetSelectedItem();
+                }
+                else if(nRet == RET_CANCEL)
+                    return false;
+            }
+
+            if(aSelection == SvtResId(STR_FORMAT_ID_MARKDOWN))
+            {
+                if(!lcl_convert_markdown_to_csv(*pStrBuffer))
+                    return false;
+            }
+
             auto pStrm = std::make_shared<ScImportStringStream>(*pStrBuffer);
 
             ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
diff --git a/sc/ucalc_setup.mk b/sc/ucalc_setup.mk
index af400da43014..4a4918d0dcf6 100644
--- a/sc/ucalc_setup.mk
+++ b/sc/ucalc_setup.mk
@@ -36,6 +36,7 @@ $(eval $(call gb_CppunitTest_use_externals,sc_ucalc$(1),\
        mdds_headers \
        orcus \
        orcus-parser \
+    md4c \
 ))
 
 $(eval $(call gb_CppunitTest_use_libraries,sc_ucalc$(1), \

Reply via email to