sw/qa/uibase/shells/shells.cxx      |  115 ++++++++++++
 sw/source/uibase/shells/textsh1.cxx |  321 ++++++++++++++++++++++++++++++++++++
 sw/source/uibase/uno/loktxdoc.cxx   |  207 +++++++++++++++++++++++
 3 files changed, 642 insertions(+), 1 deletion(-)

New commits:
commit a2ed0b9bfae98c1ee06a325f52e93eda77fb37ce
Author:     Attila Szűcs <attila.sz...@collabora.com>
AuthorDate: Wed Oct 2 16:04:56 2024 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Fri Dec 20 15:07:41 2024 +0100

    SW: extract transform DocProperties
    
    Implemented Document Properties extraction, and transformation.
    
    For UserDefinedProperties Properties you can use add, and delete commands.
    If the property already exist, "add" will delete that,
    before adding the new UserDefinedProperty
    
    see the unittest for an example.
    
    Change-Id: I036b73bf1539bc25f454aea64c319241177e167a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/178918
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/qa/uibase/shells/shells.cxx b/sw/qa/uibase/shells/shells.cxx
index f48ab0a35337..218cf47ff11b 100644
--- a/sw/qa/uibase/shells/shells.cxx
+++ b/sw/qa/uibase/shells/shells.cxx
@@ -753,7 +753,7 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, 
testDocumentStructureExtractChart)
 
     //extract
     tools::JsonWriter aJsonWriter;
-    std::string_view aCommand(".uno:ExtractDocumentStructure");
+    std::string_view aCommand(".uno:ExtractDocumentStructure?filter=charts");
     getSwTextDoc()->getCommandValues(aJsonWriter, aCommand);
 
     OString aExpectedStr
@@ -772,6 +772,119 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, 
testDocumentStructureExtractChart)
     CPPUNIT_ASSERT_EQUAL(aExpectedStr, aJsonWriter.finishAndGetAsOString());
 }
 
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testDocumentStructureDocProperties)
+{
+    createSwDoc("docStructureChartExampleOriginal.odt");
+    OString aJson = R"json(
+{
+    "Transforms": {
+        "DocumentProperties": {
+            "Author":"Author TxT",
+            "Generator":"Generator TxT",
+            "CreationDate":"2024-01-21T14:45:00",
+            "Title":"Title TxT",
+            "Subject":"Subject TxT",
+            "Description":"Description TxT",
+            "Keywords": [ ],
+            "Language":"en-GB",
+            "ModifiedBy":"ModifiedBy TxT",
+            "ModificationDate":"2024-05-23T10:05:50.159530766",
+            "PrintedBy":"PrintedBy TxT",
+            "PrintDate":"0000-00-00T00:00:00",
+            "TemplateName":"TemplateName TxT",
+            "TemplateURL":"TemplateURL TxT",
+            "TemplateDate":"0000-00-00T00:00:00",
+            "AutoloadURL":"",
+            "AutoloadSecs": 0,
+            "DefaultTarget":"DefaultTarget TxT",
+            "DocumentStatistics": {
+                "PageCount": 300,
+                "TableCount": 60,
+                "ImageCount": 10,
+                "ObjectCount": 0,
+                "ParagraphCount": 2880,
+                "WordCount": 78680,
+                "CharacterCount": 485920,
+                "NonWhitespaceCharacterCount": 411520
+            },
+            "EditingCycles":12,
+            "EditingDuration":12345,
+            "Contributor":["Contributor1 TxT","Contributor2 TXT"],
+            "Coverage":"Coverage TxT",
+            "Identifier":"Identifier TxT",
+            "Publisher":["Publisher TxT","Publisher2 TXT"],
+            "Relation":["Relation TxT","Relation2 TXT"],
+            "Rights":"Rights TxT",
+            "Source":"Source TxT",
+            "Type":"Type TxT",
+            "UserDefinedProperties":{
+                "Add.NewPropName Str": {
+                    "type": "string",
+                    "value": "this is a string"
+                },
+                "Add.NewPropName Str": {
+                    "type": "boolean",
+                    "value": false
+                },
+                "Add.NewPropName Bool": {
+                    "type": "boolean",
+                    "value": true
+                },
+                "Add.NewPropName Numb": {
+                    "type": "long",
+                    "value": 1245
+                },
+                "Add.NewPropName float": {
+                    "type": "float",
+                    "value": 12.45
+                },
+                "Add.NewPropName Double": {
+                    "type": "double",
+                    "value": 124.578
+                },
+                "Delete": "NewPropName Double"
+            }
+        }
+    }
+}
+)json"_ostr;
+
+    uno::Sequence<css::beans::PropertyValue> aArgs = {
+        comphelper::makePropertyValue(u"DataJson"_ustr,
+                                      uno::Any(OStringToOUString(aJson, 
RTL_TEXTENCODING_UTF8))),
+    };
+    dispatchCommand(mxComponent, u".uno:TransformDocumentStructure"_ustr, 
aArgs);
+
+    tools::JsonWriter aJsonWriter;
+    std::string_view aCommand(".uno:ExtractDocumentStructure?filter=docprops");
+    auto pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+    pXTextDocument->getCommandValues(aJsonWriter, aCommand);
+
+    OString aExpectedStr
+        = "{ \"DocStructure\": { \"DocumentProperties\": { \"Author\": 
\"Author TxT\", "
+          "\"Generator\": \"Generator TxT\", \"CreationDate\": 
\"2024-01-21T14:45:00\", "
+          "\"Title\": \"Title TxT\", \"Subject\": \"Subject TxT\", 
\"Description\": "
+          "\"Description TxT\", \"Keywords\": [ ], \"Language\": \"en-GB\", "
+          "\"ModifiedBy\": \"ModifiedBy TxT\", \"ModificationDate\": "
+          "\"2024-05-23T10:05:50.159530766\", \"PrintedBy\": \"PrintedBy 
TxT\", \"PrintDate\": "
+          "\"0000-00-00T00:00:00\", \"TemplateName\": \"TemplateName TxT\", 
\"TemplateURL\": "
+          "\"TemplateURL TxT\", \"TemplateDate\": \"0000-00-00T00:00:00\", 
\"AutoloadURL\": \"\", "
+          "\"AutoloadSecs\": 0, \"DefaultTarget\": \"DefaultTarget TxT\", 
\"DocumentStatistics\": "
+          "{ \"PageCount\": 300, \"TableCount\": 60, \"ImageCount\": 10, 
\"ObjectCount\": 0, "
+          "\"ParagraphCount\": 2880, \"WordCount\": 78680, \"CharacterCount\": 
485920, "
+          "\"NonWhitespaceCharacterCount\": 411520}, \"EditingCycles\": 12, 
\"EditingDuration\": "
+          "12345, \"Contributor\": [ \"Contributor1 TxT\", \"Contributor2 
TXT\"], \"Coverage\": "
+          "\"Coverage TxT\", \"Identifier\": \"Identifier TxT\", 
\"Publisher\": [ "
+          "\"Publisher TxT\", \"Publisher2 TXT\"], \"Relation\": [ \"Relation 
TxT\", "
+          "\"Relation2 TXT\"], \"Rights\": \"Rights TxT\", \"Source\": 
\"Source TxT\", \"Type\": "
+          "\"Type TxT\", \"UserDefinedProperties\": { \"NewPropName Bool\": { 
\"type\": "
+          "\"boolean\", \"value\": true}, \"NewPropName Numb\": { \"type\": 
\"long\", "
+          "\"value\": 1245}, \"NewPropName Str\": { \"type\": \"boolean\", 
\"value\": false}, "
+          "\"NewPropName float\": { \"type\": \"float\", \"value\": 
12.45}}}}}"_ostr;
+
+    CPPUNIT_ASSERT_EQUAL(aExpectedStr, aJsonWriter.finishAndGetAsOString());
+}
+
 CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateRefmarks)
 {
     // Given a document with two refmarks, one is not interesting the other is 
a citation:
diff --git a/sw/source/uibase/shells/textsh1.cxx 
b/sw/source/uibase/shells/textsh1.cxx
index e7ad2b19f872..87865564da1b 100644
--- a/sw/source/uibase/shells/textsh1.cxx
+++ b/sw/source/uibase/shells/textsh1.cxx
@@ -28,6 +28,7 @@
 #include <hintids.hxx>
 #include <cmdid.h>
 #include <comphelper/lok.hxx>
+#include <comphelper/propertysequence.hxx>
 
 #include <i18nutil/unicode.hxx>
 #include <i18nlangtag/languagetag.hxx>
@@ -135,6 +136,7 @@
 #include <formatcontentcontrol.hxx>
 #include <rtl/uri.hxx>
 #include <unotxdoc.hxx>
+#include <sax/tools/converter.hxx>
 
 #include <com/sun/star/text/XTextEmbeddedObjectsSupplier.hpp>
 #include <com/sun/star/chart2/XInternalDataProvider.hpp>
@@ -151,6 +153,13 @@
 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
 #include <com/sun/star/util/XCloneable.hpp>
 
+#include <com/sun/star/util/SearchAlgorithms2.hpp>
+#include <com/sun/star/document/XDocumentProperties2.hpp>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+
+#include <com/sun/star/beans/XPropertyAccess.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
 using namespace ::com::sun::star;
 using namespace com::sun::star::beans;
 using namespace ::com::sun::star::container;
@@ -2466,6 +2475,318 @@ void SwTextShell::Execute(SfxRequest &rReq)
                     // Handle all transformations
                     for (const auto& aItem2 : aItem.second)
                     {
+                        if (aItem2.first == "DocumentProperties")
+                        {
+                            
uno::Reference<document::XDocumentPropertiesSupplier>
+                                
xDocumentPropsSupplier(GetView().GetDocShell()->GetModel(),
+                                                       uno::UNO_QUERY);
+                            if (!xDocumentPropsSupplier.is())
+                                continue;
+                            uno::Reference<document::XDocumentProperties2> 
xDocProps(
+                                
xDocumentPropsSupplier->getDocumentProperties(), uno::UNO_QUERY);
+                            if (!xDocProps.is())
+                                continue;
+
+                            for (const auto& aItem3 : aItem2.second)
+                            {
+                                if (aItem3.first == "Author")
+                                {
+                                    xDocProps->setAuthor(
+                                        
OStringToOUString(aItem3.second.get_value<std::string>(),
+                                                          
RTL_TEXTENCODING_UTF8));
+                                }
+                                else if (aItem3.first == "Generator")
+                                {
+                                    xDocProps->setGenerator(
+                                        
OStringToOUString(aItem3.second.get_value<std::string>(),
+                                                          
RTL_TEXTENCODING_UTF8));
+                                }
+                                else if (aItem3.first == "CreationDate")
+                                {
+                                    util::DateTime aDateTime;
+                                    sax::Converter::parseDateTime(
+                                        aDateTime,
+                                        
OStringToOUString(aItem3.second.get_value<std::string>(),
+                                                          
RTL_TEXTENCODING_UTF8));
+                                    xDocProps->setCreationDate(aDateTime);
+                                }
+                                else if (aItem3.first == "Title")
+                                {
+                                    xDocProps->setTitle(
+                                        
OStringToOUString(aItem3.second.get_value<std::string>(),
+                                                          
RTL_TEXTENCODING_UTF8));
+                                }
+                                else if (aItem3.first == "Subject")
+                                {
+                                    xDocProps->setSubject(
+                                        
OStringToOUString(aItem3.second.get_value<std::string>(),
+                                                          
RTL_TEXTENCODING_UTF8));
+                                }
+                                else if (aItem3.first == "Description")
+                                {
+                                    xDocProps->setDescription(
+                                        
OStringToOUString(aItem3.second.get_value<std::string>(),
+                                                          
RTL_TEXTENCODING_UTF8));
+                                }
+                                else if (aItem3.first == "Keywords")
+                                {
+                                    uno::Sequence<OUString> 
aStringSeq(aItem3.second.size());
+                                    auto aStringArray = aStringSeq.getArray();
+                                    int nId = 0;
+                                    for (const auto& aItem4 : aItem3.second)
+                                    {
+                                        aStringArray[nId++] = 
OStringToOUString(aItem4.second.get_value<std::string>(),
+                                                          
RTL_TEXTENCODING_UTF8);
+                                    }
+                                    xDocProps->setKeywords(aStringSeq);
+                                }
+                                else if (aItem3.first == "Language")
+                                {
+                                    OUString aLanguageStr
+                                        = 
OStringToOUString(aItem3.second.get_value<std::string>(),
+                                                            
RTL_TEXTENCODING_UTF8);
+                                    lang::Locale aLanguageLang
+                                        = 
LanguageTag::convertToLocale(aLanguageStr);
+                                    xDocProps->setLanguage(aLanguageLang);
+                                }
+                                else if (aItem3.first == "ModifiedBy")
+                                {
+                                    xDocProps->setModifiedBy(
+                                        
OStringToOUString(aItem3.second.get_value<std::string>(),
+                                                          
RTL_TEXTENCODING_UTF8));
+                                }
+                                else if (aItem3.first == "ModificationDate")
+                                {
+                                    util::DateTime aDateTime;
+                                    sax::Converter::parseDateTime(
+                                        aDateTime,
+                                        
OStringToOUString(aItem3.second.get_value<std::string>(),
+                                                          
RTL_TEXTENCODING_UTF8));
+                                    xDocProps->setModificationDate(aDateTime);
+                                }
+                                else if (aItem3.first == "PrintedBy")
+                                {
+                                    xDocProps->setPrintedBy(
+                                        
OStringToOUString(aItem3.second.get_value<std::string>(),
+                                                          
RTL_TEXTENCODING_UTF8));
+                                }
+                                else if (aItem3.first == "PrintDate")
+                                {
+                                    util::DateTime aDateTime;
+                                    sax::Converter::parseDateTime(
+                                        aDateTime,
+                                        
OStringToOUString(aItem3.second.get_value<std::string>(),
+                                                          
RTL_TEXTENCODING_UTF8));
+                                    xDocProps->setPrintDate(aDateTime);
+                                }
+                                else if (aItem3.first == "TemplateName")
+                                {
+                                    xDocProps->setTemplateName(
+                                        
OStringToOUString(aItem3.second.get_value<std::string>(),
+                                                          
RTL_TEXTENCODING_UTF8));
+                                }
+                                else if (aItem3.first == "TemplateURL")
+                                {
+                                    xDocProps->setTemplateURL(
+                                        
OStringToOUString(aItem3.second.get_value<std::string>(),
+                                                          
RTL_TEXTENCODING_UTF8));
+                                }
+                                else if (aItem3.first == "TemplateDate")
+                                {
+                                    util::DateTime aDateTime;
+                                    sax::Converter::parseDateTime(
+                                        aDateTime,
+                                        
OStringToOUString(aItem3.second.get_value<std::string>(),
+                                                          
RTL_TEXTENCODING_UTF8));
+                                    xDocProps->setTemplateDate(aDateTime);
+                                }
+                                else if (aItem3.first == "AutoloadURL")
+                                {
+                                    // Warning: wrong data here, can froze LO.
+                                    xDocProps->setAutoloadURL(
+                                        
OStringToOUString(aItem3.second.get_value<std::string>(),
+                                                          
RTL_TEXTENCODING_UTF8));
+                                }
+                                else if (aItem3.first == "AutoloadSecs")
+                                {
+                                    //sal_Int32
+                                    
xDocProps->setAutoloadSecs(aItem3.second.get_value<int>());
+                                }
+                                else if (aItem3.first == "DefaultTarget")
+                                {
+                                    xDocProps->setDefaultTarget(
+                                        
OStringToOUString(aItem3.second.get_value<std::string>(),
+                                                          
RTL_TEXTENCODING_UTF8));
+                                }
+                                else if (aItem3.first == "DocumentStatistics")
+                                {
+                                    uno::Sequence<beans::NamedValue> 
aNamedValueSeq(
+                                        aItem3.second.size());
+                                    auto aNamedValueArray = 
aNamedValueSeq.getArray();
+                                    int nId = 0;
+                                    for (const auto& aItem4 : aItem3.second)
+                                    {
+                                        OUString aName = 
OStringToOUString(aItem4.first,
+                                                                           
RTL_TEXTENCODING_UTF8);
+                                        sal_Int32 nValue = 
aItem4.second.get_value<int>();
+                                        aNamedValueArray[nId].Name = aName;
+                                        aNamedValueArray[nId].Value <<= nValue;
+                                        nId++;
+                                    }
+                                    
xDocProps->setDocumentStatistics(aNamedValueSeq);
+                                }
+                                else if (aItem3.first == "EditingCycles")
+                                {
+                                    //sal_Int16
+                                    
xDocProps->setEditingCycles(aItem3.second.get_value<int>());
+                                }
+                                else if (aItem3.first == "EditingDuration")
+                                {
+                                    //sal_Int32
+                                    
xDocProps->setEditingDuration(aItem3.second.get_value<int>());
+                                }
+                                else if (aItem3.first == "Contributor")
+                                {
+                                    uno::Sequence<OUString> 
aStringSeq(aItem3.second.size());
+                                    auto aStringArray = aStringSeq.getArray();
+                                    int nId = 0;
+                                    for (const auto& aItem4 : aItem3.second)
+                                    {
+                                        aStringArray[nId++] = 
OStringToOUString(
+                                            
aItem4.second.get_value<std::string>(),
+                                            RTL_TEXTENCODING_UTF8);
+                                    }
+                                    xDocProps->setContributor(aStringSeq);
+                                }
+                                else if (aItem3.first == "Coverage")
+                                {
+                                    xDocProps->setCoverage(
+                                        
OStringToOUString(aItem3.second.get_value<std::string>(),
+                                                          
RTL_TEXTENCODING_UTF8));
+                                }
+                                else if (aItem3.first == "Identifier")
+                                {
+                                    xDocProps->setIdentifier(
+                                        
OStringToOUString(aItem3.second.get_value<std::string>(),
+                                                          
RTL_TEXTENCODING_UTF8));
+                                }
+                                else if (aItem3.first == "Publisher")
+                                {
+                                    uno::Sequence<OUString> 
aStringSeq(aItem3.second.size());
+                                    auto aStringArray = aStringSeq.getArray();
+                                    int nId = 0;
+                                    for (const auto& aItem4 : aItem3.second)
+                                    {
+                                        aStringArray[nId++] = 
OStringToOUString(
+                                            
aItem4.second.get_value<std::string>(),
+                                            RTL_TEXTENCODING_UTF8);
+                                    }
+                                    xDocProps->setPublisher(aStringSeq);
+                                }
+                                else if (aItem3.first == "Relation")
+                                {
+                                    uno::Sequence<OUString> 
aStringSeq(aItem3.second.size());
+                                    auto aStringArray = aStringSeq.getArray();
+                                    int nId = 0;
+                                    for (const auto& aItem4 : aItem3.second)
+                                    {
+                                        aStringArray[nId++] = 
OStringToOUString(
+                                            
aItem4.second.get_value<std::string>(),
+                                            RTL_TEXTENCODING_UTF8);
+                                    }
+                                    xDocProps->setRelation(aStringSeq);
+                                }
+                                else if (aItem3.first == "Rights")
+                                {
+                                    xDocProps->setRights(
+                                        
OStringToOUString(aItem3.second.get_value<std::string>(),
+                                                          
RTL_TEXTENCODING_UTF8));
+                                }
+                                else if (aItem3.first == "Source")
+                                {
+                                    xDocProps->setSource(
+                                        
OStringToOUString(aItem3.second.get_value<std::string>(),
+                                                          
RTL_TEXTENCODING_UTF8));
+                                }
+                                else if (aItem3.first == "Type")
+                                {
+                                    xDocProps->setType(
+                                        
OStringToOUString(aItem3.second.get_value<std::string>(),
+                                                          
RTL_TEXTENCODING_UTF8));
+                                }
+                                else if (aItem3.first == 
"UserDefinedProperties")
+                                {
+                                    const 
uno::Reference<beans::XPropertyContainer> xUserProps
+                                        = 
xDocProps->getUserDefinedProperties();
+                                    if (!xUserProps.is())
+                                        continue;
+                                    uno::Reference<beans::XPropertyAccess> 
xUserPropsAccess(
+                                        xDocProps->getUserDefinedProperties(), 
uno::UNO_QUERY);
+                                    if (!xUserPropsAccess.is())
+                                        continue;
+
+                                    for (const auto& aItem4 : aItem3.second)
+                                    {
+                                        if (aItem4.first == "Delete")
+                                        {
+                                            std::string aPropName
+                                                = 
aItem4.second.get_value<std::string>();
+                                            try
+                                            {
+                                                
xUserProps->removeProperty(OStringToOUString(
+                                                    aPropName, 
RTL_TEXTENCODING_UTF8));
+                                            }
+                                            catch (...)
+                                            {
+                                                lcl_LogWarning("FillApi 
DocumentProperties "
+                                                               
"UserDefinedPropertieschart, failed "
+                                                               "to delete 
property: '"
+                                                               + aPropName + 
"'");
+                                            }
+                                        }
+                                        else if 
(aItem4.first.starts_with("Add."))
+                                        {
+                                            std::string aPropName = 
aItem4.first.substr(4);
+
+                                            comphelper::SequenceAsHashMap 
aUserDefinedProperties(
+                                                
xUserPropsAccess->getPropertyValues());
+                                            
comphelper::SequenceAsHashMap::iterator it
+                                                = 
aUserDefinedProperties.find(OStringToOUString(
+                                                    aPropName, 
RTL_TEXTENCODING_UTF8));
+                                            bool bToDelete = (it != 
aUserDefinedProperties.end());
+
+                                            try
+                                            {
+                                                std::stringstream aStreamPart;
+                                                aStreamPart << "{
\"" << aPropName << "\" : ";
+                                                
boost::property_tree::json_parser::write_json(
+                                                    aStreamPart, 
aItem4.second);
+                                                aStreamPart << "}";
+
+                                                OString 
aJSONPart(aStreamPart.str());
+                                                
std::vector<beans::PropertyValue> aPropVec
+                                                    = 
comphelper::JsonToPropertyValues(aJSONPart);
+
+                                                if (bToDelete)
+                                                    
xUserProps->removeProperty(aPropVec[0].Name);
+
+                                                xUserProps->addProperty(
+                                                    aPropVec[0].Name,
+                                                    
beans::PropertyAttribute::REMOVABLE,
+                                                    aPropVec[0].Value);
+                                            }
+                                            catch(...)
+                                            {
+                                                lcl_LogWarning("FillApi 
DocumentProperties "
+                                                               
"UserDefinedPropertieschart, failed "
+                                                               "to add 
property: '"
+                                                               + aPropName + 
"'");
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
                         if (aItem2.first.starts_with("Charts"))
                         {
                             std::string aTextEnd = aItem2.first.substr(6);
diff --git a/sw/source/uibase/uno/loktxdoc.cxx 
b/sw/source/uibase/uno/loktxdoc.cxx
index dc1c3ab74e57..20f7cd9367ba 100644
--- a/sw/source/uibase/uno/loktxdoc.cxx
+++ b/sw/source/uibase/uno/loktxdoc.cxx
@@ -52,6 +52,10 @@
 #include <com/sun/star/chart/XChartDataArray.hpp>
 #include <com/sun/star/chart2/XTitle.hpp>
 #include <com/sun/star/chart2/XTitled.hpp>
+#include <com/sun/star/document/XDocumentProperties2.hpp>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+
+#include <sax/tools/converter.hxx>
 
 using namespace ::com::sun::star;
 
@@ -627,6 +631,208 @@ void GetDocStructureCharts(tools::JsonWriter& 
rJsonWriter, SwDocShell* /*pDocShe
     }
 }
 
+void GetDocStructureDocProps(tools::JsonWriter& rJsonWriter, SwDocShell* 
pDocShell,
+                             const std::map<OUString, OUString>& rArguments)
+{
+    auto it = rArguments.find(u"filter"_ustr);
+    if (it != rArguments.end())
+    {
+        // If filter is present but we are filtering not to document properties
+        if (!it->second.equals(u"docprops"_ustr))
+            return;
+    }
+
+    uno::Reference<document::XDocumentPropertiesSupplier> 
xDocumentPropsSupplier(
+        pDocShell->GetModel(), uno::UNO_QUERY);
+    if (!xDocumentPropsSupplier.is())
+        return;
+
+    //uno::Reference<document::XDocumentProperties> xDocProps();
+    uno::Reference<document::XDocumentProperties2> xDocProps(
+        xDocumentPropsSupplier->getDocumentProperties(), uno::UNO_QUERY);
+    if (!xDocProps.is())
+        return;
+
+    auto aDocPropsNode = rJsonWriter.startNode("DocumentProperties");
+
+    // StringBuffer for converting DateTimes to String
+    OUStringBuffer aDateBuf(32);
+
+    //Properties from XDocumentProperties
+    OUString aAuthor = xDocProps->getAuthor();
+    rJsonWriter.put("Author", aAuthor);
+
+    OUString aGenerator = xDocProps->getGenerator();
+    rJsonWriter.put("Generator", aGenerator);
+
+    util::DateTime aCreationDate = xDocProps->getCreationDate();
+    sax::Converter::convertDateTime(aDateBuf, aCreationDate, nullptr, true);
+    rJsonWriter.put("CreationDate", aDateBuf.makeStringAndClear());
+
+    OUString aTitle = xDocProps->getTitle();
+    rJsonWriter.put("Title", aTitle);
+
+    OUString aSubject = xDocProps->getSubject();
+    rJsonWriter.put("Subject", aSubject);
+
+    OUString aDescription = xDocProps->getDescription();
+    rJsonWriter.put("Description", aDescription);
+
+    uno::Sequence<OUString> aKeywords = xDocProps->getKeywords();
+    {
+        auto aKeywordsNode = rJsonWriter.startArray("Keywords");
+        for (int i = 0; i < aKeywords.getLength(); i++)
+        {
+            rJsonWriter.putSimpleValue(aKeywords[i]);
+        }
+    }
+
+    lang::Locale aLanguage = xDocProps->getLanguage();
+    OUString aLanguageStr(LanguageTag::convertToBcp47(aLanguage, false));
+    rJsonWriter.put("Language", aLanguageStr);
+
+    OUString aModifiedBy = xDocProps->getModifiedBy();
+    rJsonWriter.put("ModifiedBy", aModifiedBy);
+
+    util::DateTime aModificationDate = xDocProps->getModificationDate();
+    sax::Converter::convertDateTime(aDateBuf, aModificationDate, nullptr, 
true);
+    rJsonWriter.put("ModificationDate", aDateBuf.makeStringAndClear());
+
+    OUString aPrintedBy = xDocProps->getPrintedBy();
+    rJsonWriter.put("PrintedBy", aPrintedBy);
+
+    util::DateTime aPrintDate = xDocProps->getPrintDate();
+    sax::Converter::convertDateTime(aDateBuf, aPrintDate, nullptr, true);
+    rJsonWriter.put("PrintDate", aDateBuf.makeStringAndClear());
+
+    OUString aTemplateName = xDocProps->getTemplateName();
+    rJsonWriter.put("TemplateName", aTemplateName);
+
+    OUString aTemplateURL = xDocProps->getTemplateURL();
+    rJsonWriter.put("TemplateURL", aTemplateURL);
+
+    util::DateTime aTemplateDate = xDocProps->getTemplateDate();
+    sax::Converter::convertDateTime(aDateBuf, aTemplateDate, nullptr, true);
+    rJsonWriter.put("TemplateDate", aDateBuf.makeStringAndClear());
+
+    OUString aAutoloadURL = xDocProps->getAutoloadURL();
+    rJsonWriter.put("AutoloadURL", aAutoloadURL);
+
+    sal_Int32 aAutoloadSecs = xDocProps->getAutoloadSecs();
+    rJsonWriter.put("AutoloadSecs", aAutoloadSecs);
+
+    OUString aDefaultTarget = xDocProps->getDefaultTarget();
+    rJsonWriter.put("DefaultTarget", aDefaultTarget);
+
+    uno::Sequence<beans::NamedValue> aDocumentStatistics = 
xDocProps->getDocumentStatistics();
+    {
+        auto aDocumentStatisticsNode = 
rJsonWriter.startNode("DocumentStatistics");
+        for (int i = 0; i < aDocumentStatistics.getLength(); i++)
+        {
+            // Todo check: do all stast are integer numbers?
+            sal_Int32 nValue = 0;
+            aDocumentStatistics[i].Value >>= nValue;
+            std::string aStr(OUStringToOString(aDocumentStatistics[i].Name, 
RTL_TEXTENCODING_UTF8));
+            rJsonWriter.put(aStr, nValue);
+        }
+    }
+
+    sal_Int16 aEditingCycles = xDocProps->getEditingCycles();
+    rJsonWriter.put("EditingCycles", aEditingCycles);
+
+    sal_Int32 aEditingDuration = xDocProps->getEditingDuration();
+    rJsonWriter.put("EditingDuration", aEditingDuration);
+
+    //Properties from XDocumentProperties2
+    uno::Sequence<OUString> aContributor = xDocProps->getContributor();
+    {
+        auto aContributorNode = rJsonWriter.startArray("Contributor");
+        for (int i = 0; i < aContributor.getLength(); i++)
+        {
+            rJsonWriter.putSimpleValue(aContributor[i]);
+        }
+    }
+
+    OUString aCoverage = xDocProps->getCoverage();
+    rJsonWriter.put("Coverage", aCoverage);
+
+    OUString aIdentifier = xDocProps->getIdentifier();
+    rJsonWriter.put("Identifier", aIdentifier);
+
+    uno::Sequence<OUString> aPublisher = xDocProps->getPublisher();
+    {
+        auto aPublisherNode = rJsonWriter.startArray("Publisher");
+        for (int i = 0; i < aPublisher.getLength(); i++)
+        {
+            rJsonWriter.putSimpleValue(aPublisher[i]);
+        }
+    }
+
+    uno::Sequence<OUString> aRelation = xDocProps->getRelation();
+    {
+        auto aRelationNode = rJsonWriter.startArray("Relation");
+        for (int i = 0; i < aRelation.getLength(); i++)
+        {
+            rJsonWriter.putSimpleValue(aRelation[i]);
+        }
+    }
+
+    OUString aRights = xDocProps->getRights();
+    rJsonWriter.put("Rights", aRights);
+
+    OUString aSource = xDocProps->getSource();
+    rJsonWriter.put("Source", aSource);
+
+    OUString aType = xDocProps->getType();
+    rJsonWriter.put("Type", aType);
+
+    // PropertySet -> JSON
+    css::uno::Reference<css::beans::XPropertyContainer> aUserDefinedProperties
+        = xDocProps->getUserDefinedProperties();
+    uno::Reference<beans::XPropertySet> 
aUserDefinedPropertySet(aUserDefinedProperties,
+                                                                
uno::UNO_QUERY);
+    if (aUserDefinedPropertySet.is())
+    {
+        auto aRelationNode = rJsonWriter.startNode("UserDefinedProperties");
+        const uno::Sequence<beans::Property> aProperties
+            = aUserDefinedPropertySet->getPropertySetInfo()->getProperties();
+        for (const beans::Property& rProperty : aProperties)
+        {
+            const OUString& rKey = rProperty.Name;
+            auto aNode = rJsonWriter.startNode(OUStringToOString(rKey, 
RTL_TEXTENCODING_UTF8));
+            uno::Any aValue = aUserDefinedPropertySet->getPropertyValue(rKey);
+
+            OUString aAnyType = aValue.getValueTypeName();
+            rJsonWriter.put("type", aAnyType);
+
+            if (aAnyType == "boolean")
+                rJsonWriter.put("value", aValue.get<bool>());
+            else if (aAnyType == "double")
+                rJsonWriter.put("value", aValue.get<double>());
+            else if (aAnyType == "float")
+                rJsonWriter.put("value", aValue.get<float>());
+            else if (aAnyType == "long")
+                rJsonWriter.put("value", aValue.get<sal_Int32>());
+            else if (aAnyType == "short")
+                rJsonWriter.put("value", aValue.get<sal_Int16>());
+            else if (aValue.has<OUString>())
+                rJsonWriter.put("value", aValue.get<OUString>());
+            else if (aValue.has<sal_uInt64>())
+                rJsonWriter.put("value", aValue.get<sal_Int64>());
+            else
+            {
+                // Todo: some more types should be supported..
+                // AddProperty allow these 13 types:
+                // "com.sun.star.util.Date", "DateTime", 
"DateTimeWithTimezone",
+                // "DateWithTimezone", "Duration", "Time"
+                // typelib_TypeClass_BOOLEAN, typelib_TypeClass_DOUBLE, 
typelib_TypeClass_FLOAT
+                // typelib_TypeClass_HYPER, typelib_TypeClass_LONG, 
typelib_TypeClass_SHORT,
+                // typelib_TypeClass_STRING
+            }
+        }
+    }
+}
+
 /// Implements getCommandValues(".uno:Sections").
 ///
 /// Parameters:
@@ -728,6 +934,7 @@ void SwXTextDocument::getCommandValues(tools::JsonWriter& 
rJsonWriter, std::stri
 
         uno::Reference<container::XIndexAccess> xContentControls = 
getContentControls();
         GetDocStructure(rJsonWriter, m_pDocShell, aMap, xContentControls);
+        GetDocStructureDocProps(rJsonWriter, m_pDocShell, aMap);
     }
 }
 

Reply via email to