summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2022-11-30 13:58:39 +0100
committerMiklos Vajna <vmiklos@collabora.com>2022-11-30 16:51:00 +0100
commitafb362c60a18243621834dcf2b30672be6eed76f (patch)
tree1aab9ef6ab0153ceef05dab58a22c69e85866ba6
parent12d8dc31b003f6a4d466d3547ab342b85ac84bf0 (diff)
sfx2: extend .uno:SetDocumentProperties to update custom doc props
Scripting clients (like the LOK API) had a way to get all custom properties where the name matches a certain prefix, but setting such properties was not possible. .uno:SetDocumentProperties can already show a dialog to edit properties interactively and had a parameter to set some properties in a non-interactive way, but there doesn't seem to be a way to influence custom properties there without using the internal API. Fix the problem by adding a new UpdatedProperties parameter that allows removing all old custom properties matching the prefix and adding new ones with a single UNO command dispatch. This is meant to be the write side of the reading commit 5e8f6dcb8ce00d2d5e35b3cf5654187b3068276c (sw lok, .uno:SetDocumentProperties: expose value of custom document properties, 2022-11-29). Change-Id: Ib7450d4d21285d9a73758e1c172543521fc07cef Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143491 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
-rw-r--r--comphelper/source/misc/sequenceashashmap.cxx8
-rw-r--r--sfx2/qa/cppunit/doc.cxx60
-rw-r--r--sfx2/sdi/sfx.sdi2
-rw-r--r--sfx2/source/doc/objserv.cxx57
4 files changed, 126 insertions, 1 deletions
diff --git a/comphelper/source/misc/sequenceashashmap.cxx b/comphelper/source/misc/sequenceashashmap.cxx
index b18202aab5f5..3bbce289ffe0 100644
--- a/comphelper/source/misc/sequenceashashmap.cxx
+++ b/comphelper/source/misc/sequenceashashmap.cxx
@@ -367,6 +367,14 @@ std::vector<css::beans::PropertyValue> JsonToPropertyValues(const OString& rJson
aValue.Value <<= aSeq;
}
}
+ else if (rType == "[]com.sun.star.beans.PropertyValue")
+ {
+ aNodeValue = rPair.second.get_child("value", aNodeNull);
+ std::stringstream s;
+ boost::property_tree::write_json(s, aNodeValue);
+ std::vector<beans::PropertyValue> aPropertyValues = JsonToPropertyValues(s.str().c_str());
+ aValue.Value <<= comphelper::containerToSequence(aPropertyValues);
+ }
else if (rType == "[][]com.sun.star.beans.PropertyValue")
{
aNodeValue = rPair.second.get_child("value", aNodeNull);
diff --git a/sfx2/qa/cppunit/doc.cxx b/sfx2/qa/cppunit/doc.cxx
index 9ef48043b582..d7538925113e 100644
--- a/sfx2/qa/cppunit/doc.cxx
+++ b/sfx2/qa/cppunit/doc.cxx
@@ -11,11 +11,16 @@
#include <com/sun/star/view/XSelectionSupplier.hpp>
#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/XPropertyAccess.hpp>
#include <comphelper/propertyvalue.hxx>
#include <sfx2/objsh.hxx>
#include <sfx2/sfxbasemodel.hxx>
#include <osl/file.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/sequence.hxx>
using namespace com::sun::star;
@@ -84,6 +89,61 @@ CPPUNIT_TEST_FIXTURE(Test, testTempFilePath)
// "test%25C3%25Bf" instead of a directory named "test%C3%Bf".
pBaseModel->storeToURL(aPdfTarget, aPdfArgs);
}
+
+CPPUNIT_TEST_FIXTURE(Test, testSetDocumentPropertiesUpdate)
+{
+ // Given a document with 3 custom props, 2 Zotero ones and an other:
+ mxComponent = loadFromDesktop("private:factory/swriter");
+ auto pBaseModel = dynamic_cast<SfxBaseModel*>(mxComponent.get());
+ CPPUNIT_ASSERT(pBaseModel);
+ uno::Reference<document::XDocumentProperties> xDP = pBaseModel->getDocumentProperties();
+ uno::Reference<beans::XPropertyContainer> xUDP = xDP->getUserDefinedProperties();
+ xUDP->addProperty("ZOTERO_PREF_1", beans::PropertyAttribute::REMOVABLE,
+ uno::Any(OUString("foo")));
+ xUDP->addProperty("ZOTERO_PREF_2", beans::PropertyAttribute::REMOVABLE,
+ uno::Any(OUString("bar")));
+ xUDP->addProperty("OTHER", beans::PropertyAttribute::REMOVABLE, uno::Any(OUString("baz")));
+
+ // When updating the Zotero ones (1 update, 1 removal):
+ std::vector<beans::PropertyValue> aArgsVec = comphelper::JsonToPropertyValues(R"json(
+{
+ "UpdatedProperties": {
+ "type": "[]com.sun.star.beans.PropertyValue",
+ "value": {
+ "NamePrefix": {
+ "type": "string",
+ "value": "ZOTERO_PREF_"
+ },
+ "UserDefinedProperties": {
+ "type": "[]com.sun.star.beans.PropertyValue",
+ "value": {
+ "ZOTERO_PREF_1": {
+ "type": "string",
+ "value": "test"
+ }
+ }
+ }
+ }
+ }
+}
+)json");
+ uno::Sequence<beans::PropertyValue> aArgs = comphelper::containerToSequence(aArgsVec);
+ dispatchCommand(mxComponent, ".uno:SetDocumentProperties", aArgs);
+
+ // Then make sure that OTHER is still there and that ZOTERO_PREF_1 + ZOTERO_PREF_2 gets updated
+ // to the new value of a single ZOTERO_PREF_1:
+ uno::Reference<beans::XPropertyAccess> xUDPAccess(xUDP, uno::UNO_QUERY);
+ comphelper::SequenceAsHashMap aMap(xUDPAccess->getPropertyValues());
+ auto it = aMap.find("ZOTERO_PREF_1");
+ CPPUNIT_ASSERT(it != aMap.end());
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: test
+ // - Actual : foo
+ // i.e. ZOTERO_PREF_1 was not updated.
+ CPPUNIT_ASSERT_EQUAL(OUString("test"), it->second.get<OUString>());
+ CPPUNIT_ASSERT(bool(aMap.find("ZOTERO_PREF_2") == aMap.end()));
+ CPPUNIT_ASSERT(aMap.find("OTHER") != aMap.end());
+}
}
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sfx2/sdi/sfx.sdi b/sfx2/sdi/sfx.sdi
index 5da078252261..d98e8e0b93bc 100644
--- a/sfx2/sdi/sfx.sdi
+++ b/sfx2/sdi/sfx.sdi
@@ -3308,7 +3308,7 @@ SfxBoolItem PrintPreview SID_PRINTPREVIEW
SfxVoidItem SetDocumentProperties SID_DOCINFO
-(SfxDocumentInfoItem Properties SID_DOCINFO)
+(SfxDocumentInfoItem Properties SID_DOCINFO, SfxUnoAnyItem UpdatedProperties FN_PARAM_1)
[
AutoUpdate = FALSE,
FastCall = FALSE,
diff --git a/sfx2/source/doc/objserv.cxx b/sfx2/source/doc/objserv.cxx
index ed8c0bf81a5a..bb2a01b77620 100644
--- a/sfx2/source/doc/objserv.cxx
+++ b/sfx2/source/doc/objserv.cxx
@@ -24,6 +24,7 @@
#include <com/sun/star/util/CloseVetoException.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
#include <com/sun/star/document/XCmisDocument.hpp>
#include <com/sun/star/drawing/LineStyle.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
@@ -467,6 +468,56 @@ static void sendErrorToLOK(ErrCode error)
SfxViewShell::Current()->libreOfficeKitViewCallback(LOK_CALLBACK_ERROR, aStream.str().c_str());
}
+namespace
+{
+void SetDocProperties(const uno::Reference<document::XDocumentProperties>& xDP,
+ const uno::Sequence<beans::PropertyValue>& rUpdatedProperties)
+{
+ comphelper::SequenceAsHashMap aMap(rUpdatedProperties);
+ OUString aNamePrefix;
+ auto it = aMap.find("NamePrefix");
+ if (it != aMap.end())
+ {
+ it->second >>= aNamePrefix;
+ }
+
+ uno::Sequence<beans::PropertyValue> aUserDefinedProperties;
+ it = aMap.find("UserDefinedProperties");
+ if (it != aMap.end())
+ {
+ it->second >>= aUserDefinedProperties;
+ }
+
+ uno::Reference<beans::XPropertyContainer> xUDP = xDP->getUserDefinedProperties();
+ if (!aNamePrefix.isEmpty())
+ {
+ uno::Reference<beans::XPropertySet> xSet(xUDP, UNO_QUERY);
+ uno::Reference<beans::XPropertySetInfo> xSetInfo = xSet->getPropertySetInfo();
+ const uno::Sequence<beans::Property> aProperties = xSetInfo->getProperties();
+ for (const auto& rProperty : aProperties)
+ {
+ if (!rProperty.Name.startsWith(aNamePrefix))
+ {
+ continue;
+ }
+
+ if (!(rProperty.Attributes & beans::PropertyAttribute::REMOVABLE))
+ {
+ continue;
+ }
+
+ xUDP->removeProperty(rProperty.Name);
+ }
+ }
+
+ for (const auto& rUserDefinedProperty : aUserDefinedProperties)
+ {
+ xUDP->addProperty(rUserDefinedProperty.Name, beans::PropertyAttribute::REMOVABLE,
+ rUserDefinedProperty.Value);
+ }
+}
+}
+
void SfxObjectShell::ExecFile_Impl(SfxRequest &rReq)
{
weld::Window* pDialogParent = rReq.GetFrameWeld();
@@ -571,6 +622,12 @@ void SfxObjectShell::ExecFile_Impl(SfxRequest &rReq)
SetUseUserData( pDocInfItem->IsUseUserData() );
SetUseThumbnailSave( pDocInfItem->IsUseThumbnailSave() );
}
+ else if (const SfxUnoAnyItem* pItem = rReq.GetArg<SfxUnoAnyItem>(FN_PARAM_1))
+ {
+ uno::Sequence<beans::PropertyValue> aUpdatedProperties;
+ pItem->GetValue() >>= aUpdatedProperties;
+ SetDocProperties(getDocProperties(), aUpdatedProperties);
+ }
else
{
// no argument containing DocInfo; check optional arguments