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), \
