desktop/qa/desktop_lib/test_desktop_lib.cxx | 3 - desktop/source/lib/init.cxx | 62 ++++++++++++++++++++++ include/LibreOfficeKit/LibreOfficeKit.h | 4 + include/LibreOfficeKit/LibreOfficeKit.hxx | 5 + sw/source/uibase/uno/loktxdoc.cxx | 77 ++++++++++++++++++++++++++++ 5 files changed, 150 insertions(+), 1 deletion(-)
New commits: commit f8e7da23b64580d4bc45abb159651c63b578be8d Author: Attila Szűcs <attila.sz...@collabora.com> AuthorDate: Mon Jun 24 12:45:57 2024 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Fri Jul 12 10:45:49 2024 +0200 SW: exctract document structure It extract form controls, and write its data to JSON. It is a basic 1. version, for now it only recognize: -PlainText (and write its text) -CheckBox (and write its state) but it writes some common data for any type of controls: ID, alias, Tag, TabIndex, and its index. Change-Id: I9ff74cd013c6f1118942207059181678713504af Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170381 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx index 85cd7e47e4f2..c5d981ca6c58 100644 --- a/desktop/qa/desktop_lib/test_desktop_lib.cxx +++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx @@ -3590,10 +3590,11 @@ void DesktopLOKTest::testABI() CPPUNIT_ASSERT_EQUAL(classOffset(19), offsetof(struct _LibreOfficeKitClass, stopURP)); CPPUNIT_ASSERT_EQUAL(classOffset(20), offsetof(struct _LibreOfficeKitClass, joinThreads)); CPPUNIT_ASSERT_EQUAL(classOffset(21), offsetof(struct _LibreOfficeKitClass, setForkedChild)); + CPPUNIT_ASSERT_EQUAL(classOffset(22), offsetof(struct _LibreOfficeKitClass, extractDocumentStructureRequest)); // When extending LibreOfficeKit with a new function pointer, add new assert for the offsetof the // new function pointer and bump this assert for the size of the class. - CPPUNIT_ASSERT_EQUAL(classOffset(22), sizeof(struct _LibreOfficeKitClass)); + CPPUNIT_ASSERT_EQUAL(classOffset(23), sizeof(struct _LibreOfficeKitClass)); CPPUNIT_ASSERT_EQUAL(documentClassOffset(0), offsetof(struct _LibreOfficeKitDocumentClass, destroy)); CPPUNIT_ASSERT_EQUAL(documentClassOffset(1), offsetof(struct _LibreOfficeKitDocumentClass, saveAs)); diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index 365947a43b9f..5a85758039ff 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -2588,6 +2588,8 @@ static void lo_setOption(LibreOfficeKit* pThis, const char* pOption, const char* static void lo_dumpState(LibreOfficeKit* pThis, const char* pOptions, char** pState); +static char* lo_extractDocumentStructureRequest(LibreOfficeKit* pThis, const char* pFilePath); + LibLibreOffice_Impl::LibLibreOffice_Impl() : m_pOfficeClass( gOfficeClass.lock() ) , maThread(nullptr) @@ -2621,6 +2623,7 @@ LibLibreOffice_Impl::LibLibreOffice_Impl() m_pOfficeClass->stopURP = lo_stopURP; m_pOfficeClass->joinThreads = lo_joinThreads; m_pOfficeClass->setForkedChild = lo_setForkedChild; + m_pOfficeClass->extractDocumentStructureRequest = lo_extractDocumentStructureRequest; gOfficeClass = m_pOfficeClass; } @@ -3144,6 +3147,65 @@ static char* lo_extractRequest(LibreOfficeKit* /*pThis*/, const char* pFilePath) return strdup("{ }"); } +static char* lo_extractDocumentStructureRequest(LibreOfficeKit* /*pThis*/, const char* pFilePath) +{ + uno::Reference<frame::XDesktop2> xComponentLoader = frame::Desktop::create(xContext); + uno::Reference< css::lang::XComponent > xComp; + OUString aURL(getAbsoluteURL(pFilePath)); + if (!aURL.isEmpty()) + { + if (xComponentLoader.is()) + { + try + { + uno::Sequence<css::beans::PropertyValue> aFilterOptions(comphelper::InitPropertySequence( + { + {u"Hidden"_ustr, css::uno::Any(true)}, + {u"ReadOnly"_ustr, css::uno::Any(true)} + })); + xComp = xComponentLoader->loadComponentFromURL( aURL, u"_blank"_ustr, 0, aFilterOptions ); + } + catch ( const lang::IllegalArgumentException& ex ) + { + SAL_WARN("lok", "lo_extractDocumentStructureRequest: IllegalArgumentException: " << ex.Message); + } + catch (...) + { + SAL_WARN("lok", "lo_extractDocumentStructureRequest: Exception on loadComponentFromURL, url= " << aURL); + } + + if (xComp.is()) + { + ITiledRenderable* pDoc = dynamic_cast<ITiledRenderable*>(xComp.get()); + + auto pBaseModel = dynamic_cast<SfxBaseModel*>(xComp.get()); + if (!pBaseModel) + return nullptr; + + SfxObjectShell* pObjectShell = pBaseModel->GetObjectShell(); + if (!pObjectShell) + return nullptr; + + //if it is a writer document.. + uno::Reference<lang::XServiceInfo> xDocument(xComp, uno::UNO_QUERY_THROW); + if (xDocument->supportsService(u"com.sun.star.text.TextDocument"_ustr) || xDocument->supportsService(u"com.sun.star.text.WebDocument"_ustr)) + { + tools::JsonWriter aJson; + { + pDoc->getCommandValues(aJson, ".uno:ExtractDocumentStructure"); + //auto aNode = aJson.startNode("Controls"); + //extractLinks(xLTS->getLinks(), false, aJson); + } + return convertOString(aJson.finishAndGetAsOString()); + } + + xComp->dispose(); + } + } + } + return strdup("{ }"); +} + static void lo_trimMemory(LibreOfficeKit* /* pThis */, int nTarget) { vcl::lok::trimMemory(nTarget); diff --git a/include/LibreOfficeKit/LibreOfficeKit.h b/include/LibreOfficeKit/LibreOfficeKit.h index 7589da304594..168e1203123e 100644 --- a/include/LibreOfficeKit/LibreOfficeKit.h +++ b/include/LibreOfficeKit/LibreOfficeKit.h @@ -146,6 +146,10 @@ struct _LibreOfficeKitClass /// @see lok::Office::setForkedChild void (*setForkedChild)(LibreOfficeKit* pThis, bool bIsChild); + + /** @see lok::Office::extractDocumentStructureRequest. + */ + char* (*extractDocumentStructureRequest) (LibreOfficeKit* pThis, const char* pFilePath); }; #define LIBREOFFICEKIT_DOCUMENT_HAS(pDoc,member) LIBREOFFICEKIT_HAS_MEMBER(LibreOfficeKitDocumentClass,member,(pDoc)->pClass->nSize) diff --git a/include/LibreOfficeKit/LibreOfficeKit.hxx b/include/LibreOfficeKit/LibreOfficeKit.hxx index 3678dd29a9ec..9ce39d9e7d34 100644 --- a/include/LibreOfficeKit/LibreOfficeKit.hxx +++ b/include/LibreOfficeKit/LibreOfficeKit.hxx @@ -1258,6 +1258,11 @@ public: { return mpThis->pClass->setForkedChild(mpThis, bIsChild); } + + char* extractDocumentStructureRequest(const char* pFilePath) + { + return mpThis->pClass->extractDocumentStructureRequest(mpThis, pFilePath); + } }; /// Factory method to create a lok::Office instance. diff --git a/sw/source/uibase/uno/loktxdoc.cxx b/sw/source/uibase/uno/loktxdoc.cxx index ff9819e97529..f2ae84f339d3 100644 --- a/sw/source/uibase/uno/loktxdoc.cxx +++ b/sw/source/uibase/uno/loktxdoc.cxx @@ -39,6 +39,11 @@ #include <txtrfmrk.hxx> #include <ndtxt.hxx> +#include <unoport.hxx> +#include <unoprnms.hxx> +#include <unocontentcontrol.hxx> +#include <com/sun/star/text/XTextContent.hpp> + using namespace ::com::sun::star; namespace @@ -378,6 +383,72 @@ void GetField(tools::JsonWriter& rJsonWriter, SwDocShell* pDocShell, rJsonWriter.put("name", rRefmark.GetRefName()); } +/// Implements getCommandValues(".uno:ExtractDocumentStructures"). +/// +/// Parameters: +/// +/// todo later (filtering options) +void GetDocStructure(tools::JsonWriter& rJsonWriter, SwDocShell* /*pDocShell*/, + const std::map<OUString, OUString>& /*rArguments*/, + uno::Reference<container::XIndexAccess>& xContentControls) +{ + int iCCcount = xContentControls->getCount(); + + auto commentsNode = rJsonWriter.startNode("DocStructure"); + for (int i = 0; i < iCCcount; ++i) + { + OString aNodeName("ContentControls.ByIndex."_ostr + OString::number(i)); + auto ContentControlNode = rJsonWriter.startNode(aNodeName); + + uno::Reference<text::XTextContent> xContentControl; + + xContentControls->getByIndex(i) >>= xContentControl; + + uno::Reference<text::XText> xContentControlText(xContentControl, uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY); + + sal_Int32 iID = -1; + xContentControlProps->getPropertyValue(UNO_NAME_ID) >>= iID; + rJsonWriter.put("id", iID); + + OUString aTag; + xContentControlProps->getPropertyValue(UNO_NAME_TAG) >>= aTag; + rJsonWriter.put("tag", aTag); + + OUString aAlias; + xContentControlProps->getPropertyValue(UNO_NAME_ALIAS) >>= aAlias; + rJsonWriter.put("alias", aAlias); + + bool bShowingPlaceHolder = false; + xContentControlProps->getPropertyValue(UNO_NAME_SHOWING_PLACE_HOLDER) + >>= bShowingPlaceHolder; + OUString aContent; + if (!bShowingPlaceHolder) + { + aContent = xContentControlText->getString(); + } + rJsonWriter.put("content", aContent); + + bool bPlainText = false; + xContentControlProps->getPropertyValue(UNO_NAME_PLAIN_TEXT) >>= bPlainText; + bool bChBox = false; + xContentControlProps->getPropertyValue(UNO_NAME_CHECKBOX) >>= bChBox; + // "type" value derives from the UNO bool property name. + if (bPlainText) + { + rJsonWriter.put("type", "plain-text"); + } + else if (bChBox) + { + rJsonWriter.put("type", "checkbox"); + bool bchecked = false; + xContentControlProps->getPropertyValue(UNO_NAME_CHECKED) >>= bchecked; + rJsonWriter.put(UNO_NAME_CHECKED, OUString::boolean(bchecked)); + } + // TODO more types: picture, date, combobox, dropdown... + } +} + /// Implements getCommandValues(".uno:Sections"). /// /// Parameters: @@ -432,6 +503,7 @@ void SwXTextDocument::getCommandValues(tools::JsonWriter& rJsonWriter, std::stri static constexpr OStringLiteral aSections(".uno:Sections"); static constexpr OStringLiteral aBookmark(".uno:Bookmark"); static constexpr OStringLiteral aField(".uno:Field"); + static constexpr OStringLiteral aExtractDocStructure(".uno:ExtractDocumentStructure"); INetURLObject aParser(OUString::fromUtf8(rCommand)); OUString aArguments = aParser.GetParam(); @@ -485,6 +557,11 @@ void SwXTextDocument::getCommandValues(tools::JsonWriter& rJsonWriter, std::stri { GetField(rJsonWriter, m_pDocShell, aMap); } + else if (o3tl::starts_with(rCommand, aExtractDocStructure)) + { + uno::Reference<container::XIndexAccess> xContentControls = getContentControls(); + GetDocStructure(rJsonWriter, m_pDocShell, aMap, xContentControls); + } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */