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); } }