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: */

Reply via email to