desktop/source/lib/init.cxx                  |   17 ++-
 include/LibreOfficeKit/LibreOfficeKit.h      |    3 
 include/LibreOfficeKit/LibreOfficeKit.hxx    |    4 
 sw/inc/unoprnms.hxx                          |    1 
 sw/source/core/unocore/unocontentcontrol.cxx |   13 +++
 sw/source/uibase/shells/textsh1.cxx          |  116 ++++++++++++++++++++++++---
 sw/source/uibase/uno/loktxdoc.cxx            |   82 +++++++++++++++----
 sw/source/uibase/wrtsh/wrtsh1.cxx            |   22 +++++
 8 files changed, 221 insertions(+), 37 deletions(-)

New commits:
commit 578fb7b8227a8e19c00dba4d217bc1e3f7ffb5e9
Author:     Attila Szűcs <attila.sz...@collabora.com>
AuthorDate: Thu Jul 11 11:24:28 2024 +0200
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Fri Jul 12 14:38:26 2024 +0200

    Sw: extract/transform document structure 2
    
    inserting a ContentControl, now generate a unique ID for it...
    search the lowest possible non used (non negative) number
    
    added a GetType() function for SwXContentControl that get it from
    SwContentControl, and used it for extract and transform.
    
    Added some support for all other types.. some are not really usable
    yet.
    
    Fixed a problem when setting checkbox check, did not changed its
    content.
    
    If content is set to “”. It now set as placeholder,
    and reset its content to the initial placeholder value, like:
    “Choose an item” or  “Click here to enter text”
    (work for checkbox, and picture CntentControl.)
    
    Change-Id: I0fc696f73734bdfb9ac5b8fdc6891168b8d4ed5a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170365
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>

diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 176ab50d601d..cb542191befa 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -2637,7 +2637,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);
+static char* lo_extractDocumentStructureRequest(LibreOfficeKit* pThis, const 
char* pFilePath,
+                                                const char* pFilter);
 
 LibLibreOffice_Impl::LibLibreOffice_Impl()
     : m_pOfficeClass( gOfficeClass.lock() )
@@ -3200,7 +3201,8 @@ static char* lo_extractRequest(LibreOfficeKit* /*pThis*/, 
const char* pFilePath)
     return strdup("{ }");
 }
 
-static char* lo_extractDocumentStructureRequest(LibreOfficeKit* /*pThis*/, 
const char* pFilePath)
+static char* lo_extractDocumentStructureRequest(LibreOfficeKit* /*pThis*/, 
const char* pFilePath,
+                                                const char* pFilter)
 {
     uno::Reference<frame::XDesktop2> xComponentLoader = 
frame::Desktop::create(xContext);
     uno::Reference< css::lang::XComponent > xComp;
@@ -3245,9 +3247,14 @@ static char* 
lo_extractDocumentStructureRequest(LibreOfficeKit* /*pThis*/, const
                 {
                     tools::JsonWriter aJson;
                     {
-                        pDoc->getCommandValues(aJson, 
".uno:ExtractDocumentStructure");
-                        //auto aNode = aJson.startNode("Controls");
-                        //extractLinks(xLTS->getLinks(), false, aJson);
+                        OString aCommand = 
".uno:ExtractDocumentStructure"_ostr;
+                        if (pFilter && pFilter[0])
+                        {
+                            aCommand
+                                = OString::Concat(aCommand) + "?filter="_ostr 
+ pFilter;
+                        }
+
+                        pDoc->getCommandValues(aJson, aCommand);
                     }
                     return convertOString(aJson.finishAndGetAsOString());
                 }
diff --git a/include/LibreOfficeKit/LibreOfficeKit.h 
b/include/LibreOfficeKit/LibreOfficeKit.h
index 89bc609ff446..87bf5e6e7a0b 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.h
+++ b/include/LibreOfficeKit/LibreOfficeKit.h
@@ -152,7 +152,8 @@ struct _LibreOfficeKitClass
 
     /** @see lok::Office::extractDocumentStructureRequest.
      */
-    char* (*extractDocumentStructureRequest) (LibreOfficeKit* pThis, const 
char* pFilePath);
+    char* (*extractDocumentStructureRequest)(LibreOfficeKit* pThis, const 
char* pFilePath,
+                                             const char* pFilter);
 };
 
 #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 f00a5e4ede66..115e73fdf58c 100644
--- a/include/LibreOfficeKit/LibreOfficeKit.hxx
+++ b/include/LibreOfficeKit/LibreOfficeKit.hxx
@@ -1268,9 +1268,9 @@ public:
         return mpThis->pClass->setForkedChild(mpThis, bIsChild);
     }
 
-    char* extractDocumentStructureRequest(const char* pFilePath)
+    char* extractDocumentStructureRequest(const char* pFilePath, const char* 
pFilter)
     {
-        return mpThis->pClass->extractDocumentStructureRequest(mpThis, 
pFilePath);
+        return mpThis->pClass->extractDocumentStructureRequest(mpThis, 
pFilePath, pFilter);
     }
 };
 
diff --git a/sw/inc/unoprnms.hxx b/sw/inc/unoprnms.hxx
index fdbc3c8f36eb..bad3067047fc 100644
--- a/sw/inc/unoprnms.hxx
+++ b/sw/inc/unoprnms.hxx
@@ -934,6 +934,7 @@ inline constexpr OUString UNO_NAME_MULTILINE = 
u"MultiLine"_ustr;
 inline constexpr OUString UNO_NAME_DATE_STRING = u"DateString"_ustr;
 inline constexpr OUString UNO_NAME_PARA_ID = u"ParaId"_ustr;
 inline constexpr OUString UNO_NAME_PARA_ID_PARENT = u"ParaIdParent"_ustr;
+inline constexpr OUString UNO_NAME_CONTENT_CONTROL_TYPE = 
u"ContentControlType"_ustr;
 #endif
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/unocore/unocontentcontrol.cxx 
b/sw/source/core/unocore/unocontentcontrol.cxx
index 5d54d60e9b5d..03d370a0eedf 100644
--- a/sw/source/core/unocore/unocontentcontrol.cxx
+++ b/sw/source/core/unocore/unocontentcontrol.cxx
@@ -177,6 +177,7 @@ public:
     sal_uInt32 m_nTabIndex;
     OUString m_aLock;
     OUString m_aMultiLine;
+    SwContentControlType m_iType;
 
     Impl(SwXContentControl& rThis, SwDoc& rDoc, SwContentControl* 
pContentControl,
          css::uno::Reference<SwXText> xParentText, std::unique_ptr<const 
TextRangeList_t> pPortions)
@@ -196,6 +197,7 @@ public:
         , m_bDropDown(false)
         , m_nId(0)
         , m_nTabIndex(0)
+        , m_iType(SwContentControlType::RICH_TEXT)
     {
         if (m_pContentControl)
         {
@@ -1328,6 +1330,17 @@ uno::Any SAL_CALL 
SwXContentControl::getPropertyValue(const OUString& rPropertyN
             aRet <<= m_pImpl->m_pContentControl->GetMultiLine();
         }
     }
+    else if (rPropertyName == UNO_NAME_CONTENT_CONTROL_TYPE)
+    {
+        if (m_pImpl->m_bIsDescriptor)
+        {
+            aRet <<= static_cast<sal_Int32>(m_pImpl->m_iType);
+        }
+        else
+        {
+            aRet <<= 
static_cast<sal_Int32>(m_pImpl->m_pContentControl->GetType());
+        }
+    }
     else
     {
         throw beans::UnknownPropertyException();
diff --git a/sw/source/uibase/shells/textsh1.cxx 
b/sw/source/uibase/shells/textsh1.cxx
index 03d45649ead4..d9e96e4bd638 100644
--- a/sw/source/uibase/shells/textsh1.cxx
+++ b/sw/source/uibase/shells/textsh1.cxx
@@ -127,6 +127,7 @@
 #include <flyfrm.hxx>
 #include <unoprnms.hxx>
 #include <boost/property_tree/json_parser.hpp>
+#include <formatcontentcontrol.hxx>
 
 using namespace ::com::sun::star;
 using namespace com::sun::star::beans;
@@ -2166,11 +2167,14 @@ void SwTextShell::Execute(SfxRequest &rReq)
             // get the loaded content controls
             uno::Reference<text::XContentControlsSupplier> xCCSupplier(
                 GetView().GetDocShell()->GetModel(), uno::UNO_QUERY);
+            if (!xCCSupplier.is())
+                break;
+
             uno::Reference<container::XIndexAccess> xContentControls
                 = xCCSupplier->getContentControls();
             int iCCcount = xContentControls->getCount();
 
-            enum class ContentDataType
+            enum class ContentFilterType
             {
                 ERROR = -1,
                 INDEX,
@@ -2192,18 +2196,18 @@ void SwTextShell::Execute(SfxRequest &rReq)
                         {
                             std::string aTextEnd = aItem2.first.substr(15);
                             std::string aValue = "";
-                            ContentDataType iKeyId = ContentDataType::ERROR;
+                            ContentFilterType iKeyId = 
ContentFilterType::ERROR;
                             // Find how the content control is identified: 
ByIndex, ByAlias...
                             for (size_t i = 0; i < aIdTexts.size(); i++)
                             {
                                 if (aTextEnd.starts_with(aIdTexts[i]))
                                 {
-                                    iKeyId = static_cast<ContentDataType>(i);
+                                    iKeyId = static_cast<ContentFilterType>(i);
                                     aValue = 
aTextEnd.substr(aIdTexts[i].length());
                                     break;
                                 }
                             }
-                            if (iKeyId != ContentDataType::ERROR)
+                            if (iKeyId != ContentFilterType::ERROR)
                             {
                                 // Check all the content controls, if they 
match
                                 for (int i = 0; i < iCCcount; ++i)
@@ -2213,17 +2217,19 @@ void SwTextShell::Execute(SfxRequest &rReq)
 
                                     uno::Reference<beans::XPropertySet> 
xContentControlProps(
                                         xContentControl, uno::UNO_QUERY);
+                                    if (!xContentControlProps.is())
+                                        continue;
 
                                     // Compare the loaded and the actual 
idetifier
                                     switch (iKeyId)
                                     {
-                                        case ContentDataType::INDEX:
+                                        case ContentFilterType::INDEX:
                                         {
                                             if (stoi(aValue) != i)
                                                 continue;
                                         }
                                         break;
-                                        case ContentDataType::ID:
+                                        case ContentFilterType::ID:
                                         {
                                             sal_Int32 iID = -1;
                                             
xContentControlProps->getPropertyValue(UNO_NAME_ID)
@@ -2232,7 +2238,7 @@ void SwTextShell::Execute(SfxRequest &rReq)
                                                 continue;
                                         }
                                         break;
-                                        case ContentDataType::ALIAS:
+                                        case ContentFilterType::ALIAS:
                                         {
                                             OUString aAlias;
                                             
xContentControlProps->getPropertyValue(UNO_NAME_ALIAS)
@@ -2242,7 +2248,7 @@ void SwTextShell::Execute(SfxRequest &rReq)
                                                 continue;
                                         }
                                         break;
-                                        case ContentDataType::TAG:
+                                        case ContentFilterType::TAG:
                                         {
                                             OUString aTag;
                                             
xContentControlProps->getPropertyValue(UNO_NAME_TAG)
@@ -2257,16 +2263,91 @@ void SwTextShell::Execute(SfxRequest &rReq)
                                     }
 
                                     // We have a match, this content control 
need to be transformed
-                                    // Set all the values (of the content 
control) what nes needed
+                                    // Set all the values (of the content 
control) what is needed
                                     for (const auto& aItem3 : aItem2.second)
                                     {
                                         if (aItem3.first == "content")
                                         {
+                                            std::string aContent
+                                                = 
aItem3.second.get_value<std::string>();
+
                                             uno::Reference<text::XText> 
xContentControlText(
                                                 xContentControl, 
uno::UNO_QUERY);
-                                            
xContentControlText->setString(OStringToOUString(
-                                                
aItem3.second.get_value<std::string>(),
-                                                RTL_TEXTENCODING_UTF8));
+                                            if (!xContentControlText.is())
+                                                continue;
+
+                                            xContentControlText->setString(
+                                                OStringToOUString(aContent, 
RTL_TEXTENCODING_UTF8));
+
+                                            sal_Int32 iType;
+                                            
xContentControlProps->getPropertyValue(
+                                                UNO_NAME_CONTENT_CONTROL_TYPE)
+                                                >>= iType;
+                                            SwContentControlType aType
+                                                = 
static_cast<SwContentControlType>(iType);
+
+                                            // if we set the content of a 
checkbox, then we
+                                            // also set the checked state 
based on the content
+                                            if (aType == 
SwContentControlType::CHECKBOX)
+                                            {
+                                                OUString aCheckedContent;
+                                                
xContentControlProps->getPropertyValue(
+                                                    UNO_NAME_CHECKED_STATE)
+                                                    >>= aCheckedContent;
+                                                bool bChecked = false;
+                                                if (aCheckedContent
+                                                    == OStringToOUString(
+                                                        
aItem3.second.get_value<std::string>(),
+                                                        RTL_TEXTENCODING_UTF8))
+                                                    bChecked = true;
+                                                
xContentControlProps->setPropertyValue(
+                                                    UNO_NAME_CHECKED, 
uno::Any(bChecked));
+                                            }
+                                            else if (aType == 
SwContentControlType::PLAIN_TEXT
+                                                     || aType == 
SwContentControlType::RICH_TEXT
+                                                     || aType == 
SwContentControlType::DATE
+                                                     || aType == 
SwContentControlType::COMBO_BOX
+                                                     || aType
+                                                            == 
SwContentControlType::DROP_DOWN_LIST)
+                                            {
+                                                // Set the placeholder
+                                                bool bPlaceHolder = aContent 
== "" ? true : false;
+                                                
xContentControlProps->setPropertyValue(
+                                                    
UNO_NAME_SHOWING_PLACE_HOLDER,
+                                                    uno::Any(bPlaceHolder));
+                                                if (bPlaceHolder)
+                                                {
+                                                    OUString aPlaceHolderText;
+                                                    switch (aType)
+                                                    {
+                                                        case 
SwContentControlType::PLAIN_TEXT:
+                                                        case 
SwContentControlType::RICH_TEXT:
+                                                        {
+                                                            aPlaceHolderText = 
SwResId(
+                                                                
STR_CONTENT_CONTROL_PLACEHOLDER);
+                                                        }
+                                                        break;
+                                                        case 
SwContentControlType::COMBO_BOX:
+                                                        case 
SwContentControlType::DROP_DOWN_LIST:
+                                                        {
+                                                            aPlaceHolderText = 
SwResId(
+                                                                
STR_DROPDOWN_CONTENT_CONTROL_PLACEHOLDER);
+                                                        }
+                                                        break;
+                                                        case 
SwContentControlType::DATE:
+                                                        {
+                                                            aPlaceHolderText = 
SwResId(
+                                                                
STR_DATE_CONTENT_CONTROL_PLACEHOLDER);
+                                                        }
+                                                        break;
+                                                        default: // do nothing 
for picture and checkbox
+                                                        break;
+                                                    }
+                                                    if 
(!aPlaceHolderText.isEmpty())
+                                                        
xContentControlText->setString(
+                                                            aPlaceHolderText);
+                                                }
+                                            }
                                         }
                                         else if (aItem3.first == "checked")
                                         {
@@ -2277,6 +2358,17 @@ void SwTextShell::Execute(SfxRequest &rReq)
                                             
xContentControlProps->setPropertyValue(
                                                 UNO_NAME_CHECKED,
                                                 uno::Any(bChecked));
+
+                                            OUString aCheckContent;
+                                            
xContentControlProps->getPropertyValue(
+                                                bChecked ? 
UNO_NAME_CHECKED_STATE
+                                                         : 
UNO_NAME_UNCHECKED_STATE)
+                                                >>= aCheckContent;
+                                            uno::Reference<text::XText> 
xContentControlText(
+                                                xContentControl, 
uno::UNO_QUERY);
+                                            if (!xContentControlText.is())
+                                                continue;
+                                            
xContentControlText->setString(aCheckContent);
                                         }
                                         else if (aItem3.first == "alias")
                                         {
diff --git a/sw/source/uibase/uno/loktxdoc.cxx 
b/sw/source/uibase/uno/loktxdoc.cxx
index 4f9fa3b64e86..4da4f2ad72ab 100644
--- a/sw/source/uibase/uno/loktxdoc.cxx
+++ b/sw/source/uibase/uno/loktxdoc.cxx
@@ -387,11 +387,20 @@ void GetField(tools::JsonWriter& rJsonWriter, SwDocShell* 
pDocShell,
 ///
 /// Parameters:
 ///
-/// todo later (filtering options)
+/// - filter: To filter what document structure types to extract
+///   now, only contentcontrol is supported.
 void GetDocStructure(tools::JsonWriter& rJsonWriter, SwDocShell* /*pDocShell*/,
-                     const std::map<OUString, OUString>& /*rArguments*/,
+                     const std::map<OUString, OUString>& rArguments,
                      uno::Reference<container::XIndexAccess>& xContentControls)
 {
+    auto it = rArguments.find(u"filter"_ustr);
+    if (it != rArguments.end())
+    {
+        // If filter is present but we are filtering not to contentcontrols
+        if (!it->second.equals(u"contentcontrol"_ustr))
+            return;
+    }
+
     int iCCcount = xContentControls->getCount();
 
     auto commentsNode = rJsonWriter.startNode("DocStructure");
@@ -419,6 +428,10 @@ void GetDocStructure(tools::JsonWriter& rJsonWriter, 
SwDocShell* /*pDocShell*/,
         xContentControlProps->getPropertyValue(UNO_NAME_ALIAS) >>= aAlias;
         rJsonWriter.put("alias", aAlias);
 
+        sal_Int32 iType(0);
+        xContentControlProps->getPropertyValue(UNO_NAME_CONTENT_CONTROL_TYPE) 
>>= iType;
+        SwContentControlType aType = static_cast<SwContentControlType>(iType);
+
         bool bShowingPlaceHolder;
         xContentControlProps->getPropertyValue(UNO_NAME_SHOWING_PLACE_HOLDER)
             >>= bShowingPlaceHolder;
@@ -429,23 +442,58 @@ void GetDocStructure(tools::JsonWriter& rJsonWriter, 
SwDocShell* /*pDocShell*/,
         }
         rJsonWriter.put("content", aContent);
 
-        bool bPlainText;
-        xContentControlProps->getPropertyValue(UNO_NAME_PLAIN_TEXT) >>= 
bPlainText;
-        bool bChBox;
-        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)
+        switch (aType)
         {
-            rJsonWriter.put("type", "checkbox");
-            bool bchecked = false;
-            xContentControlProps->getPropertyValue(UNO_NAME_CHECKED) >>= 
bchecked;
-            rJsonWriter.put(UNO_NAME_CHECKED, OUString::boolean(bchecked));
+            case SwContentControlType::RICH_TEXT:
+            {
+                rJsonWriter.put("type", "rich-text");
+            }
+            break;
+            case SwContentControlType::CHECKBOX:
+            {
+                rJsonWriter.put("type", "checkbox");
+                bool bchecked = false;
+                xContentControlProps->getPropertyValue(UNO_NAME_CHECKED) >>= 
bchecked;
+                rJsonWriter.put(UNO_NAME_CHECKED, OUString::boolean(bchecked));
+            }
+            break;
+            case SwContentControlType::DROP_DOWN_LIST:
+            {
+                rJsonWriter.put("type", "drop-down-list");
+                // we could list its elements if we want
+            }
+            break;
+            case SwContentControlType::PICTURE:
+            {
+                rJsonWriter.put("type", "picture");
+            }
+            break;
+            case SwContentControlType::DATE:
+            {
+                rJsonWriter.put("type", "date");
+                OUString aDateFormat;
+                xContentControlProps->getPropertyValue(UNO_NAME_DATE_FORMAT) 
>>= aDateFormat;
+                rJsonWriter.put(UNO_NAME_DATE_FORMAT, aDateFormat);
+                OUString aDateLanguage;
+                xContentControlProps->getPropertyValue(UNO_NAME_DATE_LANGUAGE) 
>>= aDateLanguage;
+                rJsonWriter.put(UNO_NAME_DATE_LANGUAGE, aDateLanguage);
+            }
+            break;
+            case SwContentControlType::PLAIN_TEXT:
+            {
+                rJsonWriter.put("type", "plain-text");
+            }
+            break;
+            case SwContentControlType::COMBO_BOX:
+            {
+                rJsonWriter.put("type", "combo-box");
+                // we could list its elements if we want
+            }
+            break;
+            default:
+                //it should never happen
+                rJsonWriter.put("type", "no type?");
         }
-        // TODO more types: picture, date, combobox, dropdown...
     }
 }
 
diff --git a/sw/source/uibase/wrtsh/wrtsh1.cxx 
b/sw/source/uibase/wrtsh/wrtsh1.cxx
index 07ebe418bef8..16c49cdd7d89 100644
--- a/sw/source/uibase/wrtsh/wrtsh1.cxx
+++ b/sw/source/uibase/wrtsh/wrtsh1.cxx
@@ -1064,6 +1064,28 @@ void 
SwWrtShell::InsertContentControl(SwContentControlType eType)
     }
 
     auto pContentControl = std::make_shared<SwContentControl>(nullptr);
+
+    // Search for a non used ID for the new ContentControl, to make it unique
+    SwContentControlManager& pManager = GetDoc()->GetContentControlManager();
+    size_t nCCCount = pManager.GetCount();
+    std::vector<bool> aIdMap(nCCCount);
+    aIdMap.resize(nCCCount, false);
+    size_t nIdToCheck;
+    for (nIdToCheck = 0; nIdToCheck < nCCCount; nIdToCheck++)
+    {
+        sal_Int32 nID
+            = 
pManager.UnsortedGet(nIdToCheck)->GetContentControl().GetContentControl()->GetId();
+        if (nID >= 0 && nID < static_cast<sal_Int32>(nCCCount))
+        {
+            aIdMap[nID] = true;
+        }
+    }
+    // Find the first ID that was not used
+    nIdToCheck = 0;
+    while (nIdToCheck < nCCCount && aIdMap[nIdToCheck])
+        nIdToCheck++;
+    pContentControl->SetId(nIdToCheck);
+
     OUString aPlaceholder;
     switch (eType)
     {

Reply via email to