desktop/qa/desktop_lib/test_desktop_lib.cxx |   16 ++
 desktop/source/lib/init.cxx                 |  175 ++++++++++++++++++++++++++++
 include/LibreOfficeKit/LibreOfficeKit.h     |   10 +
 include/LibreOfficeKit/LibreOfficeKit.hxx   |   10 +
 4 files changed, 208 insertions(+), 3 deletions(-)

New commits:
commit ac1de680ae7f7d3ac71b73d3ebf2311a7f9e5451
Author:     Tor Lillqvist <t...@collabora.com>
AuthorDate: Tue Feb 21 13:19:42 2023 +0200
Commit:     Tor Lillqvist <t...@collabora.com>
CommitDate: Fri Feb 24 07:52:53 2023 +0000

    Extend LOKit API with functionality to extract a request and paint 
thumbnails
    
    Original author was Mert Tümer.
    
    Change-Id: I181a9955bcce1d5ee4c81e2a52445ef318dc4823
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/147432
    Tested-by: Tor Lillqvist <t...@collabora.com>
    Reviewed-by: Tor Lillqvist <t...@collabora.com>

diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx 
b/desktop/qa/desktop_lib/test_desktop_lib.cxx
index 3908829f1918..4348da15a68b 100644
--- a/desktop/qa/desktop_lib/test_desktop_lib.cxx
+++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx
@@ -3554,6 +3554,15 @@ void DesktopLOKTest::testABI()
     CPPUNIT_ASSERT_EQUAL(classOffset(9), offsetof(struct _LibreOfficeKitClass, 
getVersionInfo));
     CPPUNIT_ASSERT_EQUAL(classOffset(10), offsetof(struct 
_LibreOfficeKitClass, runMacro));
     CPPUNIT_ASSERT_EQUAL(classOffset(11), offsetof(struct 
_LibreOfficeKitClass, signDocument));
+    CPPUNIT_ASSERT_EQUAL(classOffset(12), offsetof(struct 
_LibreOfficeKitClass, runLoop));
+    CPPUNIT_ASSERT_EQUAL(classOffset(13), offsetof(struct 
_LibreOfficeKitClass, sendDialogEvent));
+    CPPUNIT_ASSERT_EQUAL(classOffset(14), offsetof(struct 
_LibreOfficeKitClass, setOption));
+    CPPUNIT_ASSERT_EQUAL(classOffset(15), offsetof(struct 
_LibreOfficeKitClass, dumpState));
+    CPPUNIT_ASSERT_EQUAL(classOffset(16), offsetof(struct 
_LibreOfficeKitClass, extractRequest));
+
+    // 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(17), sizeof(struct _LibreOfficeKitClass));
 
     CPPUNIT_ASSERT_EQUAL(documentClassOffset(0), offsetof(struct 
_LibreOfficeKitDocumentClass, destroy));
     CPPUNIT_ASSERT_EQUAL(documentClassOffset(1), offsetof(struct 
_LibreOfficeKitDocumentClass, saveAs));
@@ -3631,10 +3640,11 @@ void DesktopLOKTest::testABI()
     CPPUNIT_ASSERT_EQUAL(documentClassOffset(67), offsetof(struct 
_LibreOfficeKitDocumentClass, getEditMode));
     CPPUNIT_ASSERT_EQUAL(documentClassOffset(68),
                          offsetof(struct _LibreOfficeKitDocumentClass, 
setViewTimezone));
+    CPPUNIT_ASSERT_EQUAL(documentClassOffset(69), offsetof(struct 
_LibreOfficeKitDocumentClass, paintThumbnail));
+
 
-    // Extending is fine, update this, and add new assert for the offsetof the
-    // new method
-    CPPUNIT_ASSERT_EQUAL(documentClassOffset(69), sizeof(struct 
_LibreOfficeKitDocumentClass));
+    // As above
+    CPPUNIT_ASSERT_EQUAL(documentClassOffset(70), sizeof(struct 
_LibreOfficeKitDocumentClass));
 }
 
 CPPUNIT_TEST_SUITE_REGISTRATION(DesktopLOKTest);
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index d0e899b124f4..399a42159cc3 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -63,6 +63,7 @@
 #include <cppuhelper/bootstrap.hxx>
 #include <comphelper/base64.hxx>
 #include <comphelper/dispatchcommand.hxx>
+#include <comphelper/propertysequence.hxx>
 #include <comphelper/lok.hxx>
 #include <comphelper/processfactory.hxx>
 #include <comphelper/string.hxx>
@@ -175,6 +176,7 @@
 // Needed for getUndoManager()
 #include <com/sun/star/document/XUndoManager.hpp>
 #include <com/sun/star/document/XUndoManagerSupplier.hpp>
+#include <com/sun/star/document/XLinkTargetSupplier.hpp>
 #include <editeng/sizeitem.hxx>
 #include <svx/rulritem.hxx>
 #include <svx/pageitem.hxx>
@@ -395,6 +397,97 @@ std::vector<beans::PropertyValue> 
desktop::jsonToPropertyValuesVector(const char
     return aArguments;
 }
 
+static bool extractLinks(const uno::Reference< container::XNameAccess >& 
xLinks, bool subcontent, OUStringBuffer& jsonText)
+{
+    const uno::Sequence< OUString > aNames( xLinks->getElementNames() );
+
+    const sal_uLong nLinks = aNames.getLength();
+    const OUString* pNames = aNames.getConstArray();
+    const OUString aProp_LinkDisplayName( "LinkDisplayName" );
+    const OUString aProp_LinkTarget( "com.sun.star.document.LinkTarget" );
+    bool bIsTarget = false;
+    for( sal_uLong i = 0; i < nLinks; i++ )
+    {
+        uno::Any aAny;
+        OUString aLink( *pNames++ );
+
+        bool bError = false;
+        try
+        {
+            aAny = xLinks->getByName( aLink );
+        }
+        catch(const uno::Exception&)
+        {
+            // if the name of the target was invalid (like empty headings)
+            // no object can be provided
+            bError = true;
+        }
+        if(bError)
+            continue;
+
+        uno::Reference< beans::XPropertySet > xTarget;
+        if( aAny >>= xTarget )
+        {
+            try
+            {
+                // get name to display
+                aAny = xTarget->getPropertyValue( aProp_LinkDisplayName );
+                OUString aDisplayName;
+                aAny >>= aDisplayName;
+                OUString aStrDisplayname ( aDisplayName );
+
+                if (subcontent)
+                {
+                    jsonText.append("\"");
+                    jsonText.append(aStrDisplayname);
+                    jsonText.append("\": \"");
+                    jsonText.append(aLink);
+                    jsonText.append("\"");
+                    if (i < nLinks-1)
+                    {
+                        jsonText.append(", ");
+                    }
+                }
+                else
+                {
+                    uno::Reference< lang::XServiceInfo > xSI( xTarget, 
uno::UNO_QUERY );
+                    bIsTarget = xSI->supportsService( aProp_LinkTarget );
+                    if (i != 0)
+                    {
+                        if (!bIsTarget)
+                            jsonText.append("}");
+                        if (i < nLinks)
+                        {
+                            jsonText.append(", ");
+                        }
+                    }
+                    jsonText.append("\"");
+                    jsonText.append(aStrDisplayname);
+                    jsonText.append("\": ");
+
+                    if (bIsTarget)
+                    {
+                        jsonText.append("true");
+                        continue;
+                    }
+                    jsonText.append("{");
+                }
+
+                uno::Reference< document::XLinkTargetSupplier > xLTS( xTarget, 
uno::UNO_QUERY );
+                if( xLTS.is() )
+                {
+                    extractLinks(xLTS->getLinks(), true, jsonText);
+                }
+            }
+            catch(...)
+            {
+                SAL_WARN("lok", "extractLinks: Exception");
+            }
+        }
+    }
+    return bIsTarget;
+}
+
 static void unoAnyToJson(tools::JsonWriter& rJson, const char * pNodeName, 
const uno::Any& anyItem)
 {
     auto aNode = rJson.startNode(pNodeName);
@@ -1018,6 +1111,7 @@ static void doc_paintTile(LibreOfficeKitDocument* pThis,
                           const int nCanvasWidth, const int nCanvasHeight,
                           const int nTilePosX, const int nTilePosY,
                           const int nTileWidth, const int nTileHeight);
+static void doc_paintThumbnail(LibreOfficeKitDocument* pThis, unsigned char* 
pBuffer, int x, int y);
 #ifdef IOS
 static void doc_paintTileToCGContext(LibreOfficeKitDocument* pThis,
                                      void* rCGContext,
@@ -1291,6 +1385,7 @@ LibLODocument_Impl::LibLODocument_Impl(uno::Reference 
<css::lang::XComponent> xC
         m_pDocumentClass->setPartMode = doc_setPartMode;
         m_pDocumentClass->getEditMode = doc_getEditMode;
         m_pDocumentClass->paintTile = doc_paintTile;
+        m_pDocumentClass->paintThumbnail = doc_paintThumbnail;
 #ifdef IOS
         m_pDocumentClass->paintTileToCGContext = doc_paintTileToCGContext;
 #endif
@@ -2424,6 +2519,9 @@ static bool lo_signDocument(LibreOfficeKit* pThis,
                                    const unsigned char* pPrivateKeyBinary,
                                    const int nPrivateKeyBinarySize);
 
+static char* lo_extractRequest(LibreOfficeKit* pThis,
+                                   const char* pFilePath);
+
 static void lo_runLoop(LibreOfficeKit* pThis,
                        LibreOfficeKitPollCallback pPollCallback,
                        LibreOfficeKitWakeCallback pWakeCallback,
@@ -2464,6 +2562,7 @@ LibLibreOffice_Impl::LibLibreOffice_Impl()
         m_pOfficeClass->sendDialogEvent = lo_sendDialogEvent;
         m_pOfficeClass->setOption = lo_setOption;
         m_pOfficeClass->dumpState = lo_dumpState;
+        m_pOfficeClass->extractRequest = lo_extractRequest;
 
         gOfficeClass = m_pOfficeClass;
     }
@@ -2979,6 +3078,69 @@ static bool lo_signDocument(LibreOfficeKit* /*pThis*/,
     return true;
 }
 
+
+static char* lo_extractRequest(LibreOfficeKit* /*pThis*/, const char* 
pFilePath)
+{
+    uno::Reference<frame::XDesktop2> xComponentLoader = 
frame::Desktop::create(xContext);
+    uno::Reference< css::lang::XComponent > xComp;
+    OUString aURL(getAbsoluteURL(pFilePath));
+    OUString result;
+    if (!aURL.isEmpty())
+    {
+        if (xComponentLoader.is())
+        {
+            try
+            {
+                uno::Sequence<css::beans::PropertyValue> 
aFilterOptions(comphelper::InitPropertySequence(
+                {
+                    {"Hidden", css::uno::Any(true)},
+                    {"ReadOnly", css::uno::Any(true)}
+                }));
+                xComp = xComponentLoader->loadComponentFromURL( aURL, 
"_blank", 0, aFilterOptions );
+            }
+            catch ( const lang::IllegalArgumentException& ex )
+            {
+                SAL_WARN("lok", "lo_extractRequest: IllegalArgumentException: 
" << ex.Message);
+                result = "{ }";
+                return convertOUString(result);
+            }
+            catch (...)
+            {
+                SAL_WARN("lok", "lo_extractRequest: Exception on 
loadComponentFromURL, url= " << aURL);
+                result = "{ }";
+                return convertOUString(result);
+            }
+
+            if (xComp.is())
+            {
+                uno::Reference< document::XLinkTargetSupplier > xLTS( xComp, 
uno::UNO_QUERY );
+
+                if( xLTS.is() )
+                {
+                    OUStringBuffer jsonText;
+                    jsonText.append("{ \"Targets\": { ");
+                    bool lastParentheses = extractLinks(xLTS->getLinks(), 
false, jsonText);
+                    jsonText.append("} }");
+                    if (!lastParentheses)
+                        jsonText.append(" }");
+
+                    OUString res(jsonText.makeStringAndClear());
+                    return convertOUString(res);
+                }
+                xComp->dispose();
+            }
+            else
+            {
+                result = "{ }";
+                return convertOUString(result);
+            }
+
+        }
+    }
+    result = "{ }";
+    return convertOUString(result);
+}
+
 static void lo_registerCallback (LibreOfficeKit* pThis,
                                  LibreOfficeKitCallback pCallback,
                                  void* pData)
@@ -3845,6 +4007,19 @@ static void 
doc_paintTileToCGContext(LibreOfficeKitDocument* pThis,
 
 #endif
 
+static void doc_paintThumbnail(LibreOfficeKitDocument* pThis, unsigned char* 
pBuffer, int x, int y)
+{
+    constexpr float zoom = 0.5f;
+    constexpr int pixelWidth = 120;
+    constexpr int pixelHeight = 120;
+    constexpr int pixelWidthTwips = pixelWidth * 15 / zoom;
+    constexpr int pixelHeightTwips = pixelHeight * 15 / zoom;
+    constexpr int offsetXTwips = 15 * 15; // start 15 px/twips before the 
target to get a clearer thumbnail
+    constexpr int offsetYTwips = 15 * 15;
+
+    doc_paintTile(pThis, pBuffer, pixelWidth, pixelHeight, x-offsetXTwips, 
y-offsetYTwips, pixelWidthTwips, pixelHeightTwips);
+}
+
 static void doc_paintPartTile(LibreOfficeKitDocument* pThis,
                               unsigned char* pBuffer,
                               const int nPart,
diff --git a/include/LibreOfficeKit/LibreOfficeKit.h 
b/include/LibreOfficeKit/LibreOfficeKit.h
index 74c2100ab18c..4de2380998b4 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.h
+++ b/include/LibreOfficeKit/LibreOfficeKit.h
@@ -122,6 +122,11 @@ struct _LibreOfficeKitClass
     /// @see lok::Document::dumpState
     /// @since LibreOffice 7.5
     void (*dumpState) (LibreOfficeKit* pThis, const char* pOptions, char** 
pState);
+
+    /** @see lok::Office::extractRequest.
+     */
+    char* (*extractRequest) (LibreOfficeKit* pThis,
+                           const char* pFilePath);
 };
 
 #define LIBREOFFICEKIT_DOCUMENT_HAS(pDoc,member) 
LIBREOFFICEKIT_HAS_MEMBER(LibreOfficeKitDocumentClass,member,(pDoc)->pClass->nSize)
@@ -496,6 +501,11 @@ struct _LibreOfficeKitDocumentClass
     /// @see lok::Document::setViewTimezone().
     void (*setViewTimezone) (LibreOfficeKitDocument* pThis, int nId, const 
char* timezone);
 
+    void (*paintThumbnail) (LibreOfficeKitDocument* pThis,
+                            unsigned char* pBuffer,
+                            int x,
+                            int y);
+
 #endif // defined LOK_USE_UNSTABLE_API || defined LIBO_INTERNAL_ONLY
 };
 
diff --git a/include/LibreOfficeKit/LibreOfficeKit.hxx 
b/include/LibreOfficeKit/LibreOfficeKit.hxx
index 2ac398edd497..17fc518fbe13 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.hxx
+++ b/include/LibreOfficeKit/LibreOfficeKit.hxx
@@ -886,6 +886,11 @@ public:
         mpDoc->pClass->setViewTimezone(mpDoc, nId, timezone);
     }
 
+    void paintThumbnail(unsigned char* pBuffer, int x, int y)
+    {
+        return mpDoc->pClass->paintThumbnail(mpDoc, pBuffer, x, y);
+    }
+
 #endif // defined LOK_USE_UNSTABLE_API || defined LIBO_INTERNAL_ONLY
 };
 
@@ -1141,6 +1146,11 @@ public:
     {
         mpThis->pClass->dumpState(mpThis, pOption, pState);
     }
+
+    char* extractRequest(const char* pFilePath)
+    {
+        return mpThis->pClass->extractRequest(mpThis, pFilePath);
+    }
 };
 
 /// Factory method to create a lok::Office instance.

Reply via email to