summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Luth <justin.luth@collabora.com>2022-11-30 13:09:07 -0500
committerMiklos Vajna <vmiklos@collabora.com>2022-12-20 14:45:38 +0000
commitc4620dec0818802e9b56e223cb78eabca632abba (patch)
tree75d775eba95e203d8c3516bbcaf8f8aeb65be95b
parent77449c9877bff4979e4d9ff0fe489f61e340c975 (diff)
tdf#151548 sw content controls: preserve lock
DOCX SdtControls can be locked in two ways: -Content Control cannot be deleted (sdtLocked) -Contents cannot be edited (contentLocked) or both (sdtContentLocked) make CppunitTest_writerfilter_dmapper CPPUNIT_TEST_NAME=testSdtRunRichText make CppunitTest_sw_ooxmlexport4 CPPUNIT_TEST_NAME=testSimpleSdts make CppunitTest_sw_ooxmlexport17 CPPUNIT_TEST_NAME=testDateContentControlExport make CppunitTest_sw_core_unocore CPPUNIT_TEST_NAME=testContentControlDate make CppunitTest_sw_macros_test CPPUNIT_TEST_NAME=testVba make CppunitTest_xmloff_text CPPUNIT_TEST_NAME=testAliasContentControlExport make CppunitTest_xmloff_text CPPUNIT_TEST_NAME=testAliasContentControlImport Change-Id: I5a82d9f6b5103a4902f59af66cd8a99addd4e690 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143542 Tested-by: Jenkins Reviewed-by: Justin Luth <jluth@mail.com> Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/144553 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
-rw-r--r--include/xmloff/xmltoken.hxx1
-rw-r--r--offapi/com/sun/star/text/ContentControl.idl6
-rw-r--r--schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng5
-rw-r--r--sw/inc/formatcontentcontrol.hxx12
-rw-r--r--sw/inc/unoprnms.hxx1
-rw-r--r--sw/qa/core/data/docm/testModernVBA.docmbin32539 -> 32970 bytes
-rw-r--r--sw/qa/core/unocore/unocore.cxx2
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport17.cxx3
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport4.cxx1
-rw-r--r--sw/source/core/txtnode/attrcontentcontrol.cxx38
-rw-r--r--sw/source/core/unocore/unocontentcontrol.cxx28
-rw-r--r--sw/source/core/unocore/unomap1.cxx1
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.cxx16
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.hxx1
-rw-r--r--sw/source/ui/vba/vbacontentcontrol.cxx42
-rw-r--r--writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx4
-rw-r--r--writerfilter/qa/cppunittests/dmapper/data/sdt-run-rich-text.docxbin4376 -> 5381 bytes
-rw-r--r--writerfilter/source/dmapper/DomainMapper.cxx12
-rw-r--r--writerfilter/source/dmapper/DomainMapper_Impl.cxx5
-rw-r--r--writerfilter/source/dmapper/SdtHelper.cxx5
-rw-r--r--writerfilter/source/dmapper/SdtHelper.hxx6
-rw-r--r--xmloff/qa/unit/data/content-control-alias.fodt2
-rw-r--r--xmloff/qa/unit/text.cxx5
-rw-r--r--xmloff/source/core/xmltoken.cxx1
-rw-r--r--xmloff/source/text/txtparae.cxx7
-rw-r--r--xmloff/source/text/xmlcontentcontrolcontext.cxx10
-rw-r--r--xmloff/source/text/xmlcontentcontrolcontext.hxx1
-rw-r--r--xmloff/source/token/tokens.txt1
28 files changed, 205 insertions, 11 deletions
diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx
index e5c38a25bcfd..fb3685a64c59 100644
--- a/include/xmloff/xmltoken.hxx
+++ b/include/xmloff/xmltoken.hxx
@@ -1218,6 +1218,7 @@ namespace xmloff::token {
XML_LIST_STYLE,
XML_LIST_STYLE_NAME,
XML_LN,
+ XML_LOCK,
XML_LOCKED,
XML_LOG,
XML_LOGARITHMIC,
diff --git a/offapi/com/sun/star/text/ContentControl.idl b/offapi/com/sun/star/text/ContentControl.idl
index 6abcc79fd204..59894741de2b 100644
--- a/offapi/com/sun/star/text/ContentControl.idl
+++ b/offapi/com/sun/star/text/ContentControl.idl
@@ -127,6 +127,12 @@ service ContentControl
@since LibreOffice 7.5
*/
[optional, property] long Id;
+
+ /** Describes whether the control itself and/or its data can be modified or deleted by the user.
+
+ @since LibreOffice 7.6
+ */
+ [optional, property] string Lock;
};
diff --git a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
index 5359dec15298..0acadbb8e71c 100644
--- a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
+++ b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
@@ -2944,6 +2944,11 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.
<rng:ref name="string"/>
</rng:attribute>
</rng:optional>
+ <rng:optional>
+ <rng:attribute name="loext:lock">
+ <rng:ref name="string"/>
+ </rng:attribute>
+ </rng:optional>
<rng:zeroOrMore>
<rng:element name="loext:list-item">
<rng:attribute name="loext:display-text">
diff --git a/sw/inc/formatcontentcontrol.hxx b/sw/inc/formatcontentcontrol.hxx
index b8b2db8882a9..c0b200683277 100644
--- a/sw/inc/formatcontentcontrol.hxx
+++ b/sw/inc/formatcontentcontrol.hxx
@@ -178,6 +178,9 @@ class SW_DLLPUBLIC SwContentControl : public sw::BroadcastingModify
/// The id: just remembered.
sal_Int32 m_nId = 0;
+ /// The control and content locks: mostly just remembered.
+ OUString m_aLock;
+
/// Stores a list item index, in case the doc model is not yet updated.
// i.e. temporarily store the selected item until the text is inserted by GotoContentControl.
std::optional<size_t> m_oSelectedListItem;
@@ -361,8 +364,17 @@ public:
sal_Int32 GetId() const { return m_nId; }
+ // At the design level, define how the control should be locked. No effect at implementation lvl
+ void SetLock(bool bLockContent, bool bLockControl);
+ void SetLock(const OUString& rLock) { m_aLock = rLock; }
+
+ // At the design level, get how the control is locked. Does not reflect actual implementation.
+ std::optional<bool> GetLock(bool bControl) const;
+ const OUString& GetLock() const { return m_aLock; }
+
void SetReadWrite(bool bReadWrite) { m_bReadWrite = bReadWrite; }
+ // At the implementation level, define whether the user can directly modify the contents.
bool GetReadWrite() const { return m_bReadWrite; }
SwContentControlType GetType() const;
diff --git a/sw/inc/unoprnms.hxx b/sw/inc/unoprnms.hxx
index 2dffbeb739af..a850b76994f4 100644
--- a/sw/inc/unoprnms.hxx
+++ b/sw/inc/unoprnms.hxx
@@ -891,6 +891,7 @@
#define UNO_NAME_ALIAS "Alias"
#define UNO_NAME_TAG "Tag"
#define UNO_NAME_ID "Id"
+#define UNO_NAME_LOCK "Lock"
#define UNO_NAME_DATE_STRING "DateString"
#endif
diff --git a/sw/qa/core/data/docm/testModernVBA.docm b/sw/qa/core/data/docm/testModernVBA.docm
index 49e53b615622..c08d738c8adb 100644
--- a/sw/qa/core/data/docm/testModernVBA.docm
+++ b/sw/qa/core/data/docm/testModernVBA.docm
Binary files differ
diff --git a/sw/qa/core/unocore/unocore.cxx b/sw/qa/core/unocore/unocore.cxx
index 20d93d688f96..be5d74678e2e 100644
--- a/sw/qa/core/unocore/unocore.cxx
+++ b/sw/qa/core/unocore/unocore.cxx
@@ -574,6 +574,7 @@ CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlDate)
xContentControlProps->setPropertyValue("Color", uno::Any(OUString("008000")));
xContentControlProps->setPropertyValue("Alias", uno::Any(OUString("myalias")));
xContentControlProps->setPropertyValue("Tag", uno::Any(OUString("mytag")));
+ xContentControlProps->setPropertyValue("Lock", uno::Any(OUString("sdtContentLocked")));
xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
// Then make sure that the specified properties are set:
@@ -599,6 +600,7 @@ CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlDate)
CPPUNIT_ASSERT_EQUAL(OUString("008000"), pContentControl->GetColor());
CPPUNIT_ASSERT_EQUAL(OUString("myalias"), pContentControl->GetAlias());
CPPUNIT_ASSERT_EQUAL(OUString("mytag"), pContentControl->GetTag());
+ CPPUNIT_ASSERT_EQUAL(OUString("sdtContentLocked"), pContentControl->GetLock());
}
CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlPlainText)
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
index 8ccd9f1f6540..63fda18c23f3 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx
@@ -300,6 +300,8 @@ CPPUNIT_TEST_FIXTURE(Test, testDateContentControlExport)
xContentControlProps->setPropertyValue("Color", uno::Any(OUString("008000")));
xContentControlProps->setPropertyValue("Alias", uno::Any(OUString("myalias")));
xContentControlProps->setPropertyValue("Tag", uno::Any(OUString("mytag")));
+ xContentControlProps->setPropertyValue("Lock", uno::Any(OUString("sdtLocked")));
+
xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
// When exporting to DOCX:
@@ -323,6 +325,7 @@ CPPUNIT_TEST_FIXTURE(Test, testDateContentControlExport)
assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w15:color", "val", "008000");
assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:alias", "val", "myalias");
assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:tag", "val", "mytag");
+ assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:lock", "val", "sdtLocked");
}
DECLARE_OOXMLEXPORT_TEST(testTdf137466, "tdf137466.docx")
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx
index e0b9db36e980..a32da9cb88ae 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport4.cxx
@@ -1022,6 +1022,7 @@ CPPUNIT_TEST_FIXTURE(Test, testSimpleSdts)
assertXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:sdt/w:sdtPr/w:text", 1);
assertXPath(pXmlDoc, "//*/w:sdt/w:sdtPr/w:id", 5);
+ assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:lock", 1);
assertXPath(pXmlDoc, "/w:document/w:body/w:sdt[1]/w:sdtPr/w:picture", 1);
assertXPath(pXmlDoc, "/w:document/w:body/w:sdt[2]/w:sdtPr/w:group", 1);
assertXPath(pXmlDoc, "/w:document/w:body/w:p[4]/w:sdt/w:sdtPr/w:citation", 1);
diff --git a/sw/source/core/txtnode/attrcontentcontrol.cxx b/sw/source/core/txtnode/attrcontentcontrol.cxx
index 8542423e8696..19fd922a439b 100644
--- a/sw/source/core/txtnode/attrcontentcontrol.cxx
+++ b/sw/source/core/txtnode/attrcontentcontrol.cxx
@@ -439,6 +439,42 @@ bool SwContentControl::ShouldOpenPopup(const vcl::KeyCode& rKeyCode)
return false;
}
+// NOTE: call SetReadWrite separately to implement true (un)locking.
+// This is mostly a theoretical function; the lock state is mainly kept for round-tripping purposes.
+// It is implemented here primarily for pointless VBA control, but with the intention that it
+// could be made functionally useful as well for checkboxes/dropdowns/pictures.
+// Returns whether the content (bControl=false) cannot be modified,
+// or if the control cannot be deleted.
+std::optional<bool> SwContentControl::GetLock(bool bControl) const
+{
+ std::optional<bool> oLock;
+ if (m_aLock.isEmpty())
+ return oLock;
+ else if (m_aLock.equalsIgnoreAsciiCase("sdtContentLocked"))
+ oLock = true;
+ else if (m_aLock.equalsIgnoreAsciiCase("unlocked"))
+ oLock = false;
+ else if (m_aLock.equalsIgnoreAsciiCase("sdtLocked"))
+ oLock = bControl;
+ else if (m_aLock.equalsIgnoreAsciiCase("contentLocked"))
+ oLock = !bControl;
+
+ assert(oLock && "invalid or unknown lock state");
+ return oLock;
+}
+
+void SwContentControl::SetLock(bool bLockContent, bool bLockControl)
+{
+ if (!bLockContent && !bLockControl)
+ m_aLock = "unlocked";
+ else if (bLockContent && bLockControl)
+ m_aLock = "sdtContentLocked";
+ else if (bLockContent)
+ m_aLock = "contentLocked";
+ else
+ m_aLock = "sdtLocked";
+}
+
SwContentControlType SwContentControl::GetType() const
{
if (m_bCheckbox)
@@ -520,6 +556,8 @@ void SwContentControl::dumpAsXml(xmlTextWriterPtr pWriter) const
(void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("tag"), BAD_CAST(m_aTag.toUtf8().getStr()));
(void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("id"),
BAD_CAST(OString::number(m_nId).getStr()));
+ (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("lock"),
+ BAD_CAST(m_aLock.toUtf8().getStr()));
if (!m_aListItems.empty())
{
diff --git a/sw/source/core/unocore/unocontentcontrol.cxx b/sw/source/core/unocore/unocontentcontrol.cxx
index 61c7ac66c9fd..01b1771e6edf 100644
--- a/sw/source/core/unocore/unocontentcontrol.cxx
+++ b/sw/source/core/unocore/unocontentcontrol.cxx
@@ -178,6 +178,7 @@ public:
OUString m_aAlias;
OUString m_aTag;
sal_Int32 m_nId;
+ OUString m_aLock;
Impl(SwXContentControl& rThis, SwDoc& rDoc, SwContentControl* pContentControl,
const uno::Reference<text::XText>& xParentText,
@@ -556,6 +557,7 @@ void SwXContentControl::AttachImpl(const uno::Reference<text::XTextRange>& xText
pContentControl->SetAlias(m_pImpl->m_aAlias);
pContentControl->SetTag(m_pImpl->m_aTag);
pContentControl->SetId(m_pImpl->m_nId);
+ pContentControl->SetLock(m_pImpl->m_aLock);
SwFormatContentControl aContentControl(pContentControl, nWhich);
bool bSuccess
@@ -1046,6 +1048,21 @@ void SAL_CALL SwXContentControl::setPropertyValue(const OUString& rPropertyName,
}
}
}
+ else if (rPropertyName == UNO_NAME_LOCK)
+ {
+ OUString aValue;
+ if (rValue >>= aValue)
+ {
+ if (m_pImpl->m_bIsDescriptor)
+ {
+ m_pImpl->m_aLock = aValue;
+ }
+ else
+ {
+ m_pImpl->m_pContentControl->SetLock(aValue);
+ }
+ }
+ }
else
{
throw beans::UnknownPropertyException();
@@ -1308,6 +1325,17 @@ uno::Any SAL_CALL SwXContentControl::getPropertyValue(const OUString& rPropertyN
aRet <<= m_pImpl->m_pContentControl->GetId();
}
}
+ else if (rPropertyName == UNO_NAME_LOCK)
+ {
+ if (m_pImpl->m_bIsDescriptor)
+ {
+ aRet <<= m_pImpl->m_aLock;
+ }
+ else
+ {
+ aRet <<= m_pImpl->m_pContentControl->GetLock();
+ }
+ }
else
{
throw beans::UnknownPropertyException();
diff --git a/sw/source/core/unocore/unomap1.cxx b/sw/source/core/unocore/unomap1.cxx
index 5d4d0c0b1a77..0ae874b3b9e1 100644
--- a/sw/source/core/unocore/unomap1.cxx
+++ b/sw/source/core/unocore/unomap1.cxx
@@ -1048,6 +1048,7 @@ const SfxItemPropertyMapEntry* SwUnoPropertyMapProvider::GetContentControlProper
{ u"" UNO_NAME_ALIAS, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 },
{ u"" UNO_NAME_TAG, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 },
{ u"" UNO_NAME_ID, 0, cppu::UnoType<sal_Int32>::get(), PROPERTY_NONE, 0 },
+ { u"" UNO_NAME_LOCK, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 },
{ u"" UNO_NAME_DATE_STRING, 0, cppu::UnoType<OUString>::get(), PropertyAttribute::READONLY, 0 },
{ u"", 0, css::uno::Type(), 0, 0 }
};
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index bd9bba939aa7..f2aaefa22440 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -617,6 +617,8 @@ void SdtBlockHelper::DeleteAndResetTheLists()
m_aAlias.clear();
if (!m_aTag.isEmpty())
m_aTag.clear();
+ if (!m_aLock.isEmpty())
+ m_aLock.clear();
if (!m_aPlaceHolderDocPart.isEmpty())
m_aPlaceHolderDocPart.clear();
if (!m_aColor.isEmpty())
@@ -723,6 +725,9 @@ void SdtBlockHelper::WriteExtraParams(::sax_fastparser::FSHelperPtr& pSerializer
if (!m_aTag.isEmpty())
pSerializer->singleElementNS(XML_w, XML_tag, FSNS(XML_w, XML_val), m_aTag);
+
+ if (!m_aLock.isEmpty())
+ pSerializer->singleElementNS(XML_w, XML_lock, FSNS(XML_w, XML_val), m_aLock);
}
void SdtBlockHelper::EndSdtBlock(::sax_fastparser::FSHelperPtr& pSerializer)
@@ -832,6 +837,11 @@ void SdtBlockHelper::GetSdtParamsFromGrabBag(const uno::Sequence<beans::Property
if (!(aPropertyValue.Value >>= m_aTag))
SAL_WARN("sw.ww8", "DocxAttributeOutput::GrabBag: unexpected sdt tag value");
}
+ else if (aPropertyValue.Name == "ooxml:CT_SdtPr_lock" && m_aLock.isEmpty())
+ {
+ if (!(aPropertyValue.Value >>= m_aLock))
+ SAL_WARN("sw.ww8", "DocxAttributeOutput::GrabBag: unexpected sdt lock value");
+ }
else if (aPropertyValue.Name == "ooxml:CT_SdtPr_id")
m_bHasId = true;
else if (aPropertyValue.Name == "ooxml:CT_SdtPr_citation")
@@ -2391,6 +2401,12 @@ void DocxAttributeOutput::WriteContentControlStart()
OString::number(m_pContentControl->GetId()));
}
+ if (!m_pContentControl->GetLock().isEmpty())
+ {
+ m_pSerializer->singleElementNS(XML_w, XML_lock, FSNS(XML_w, XML_val),
+ m_pContentControl->GetLock());
+ }
+
if (m_pContentControl->GetShowingPlaceHolder())
{
m_pSerializer->singleElementNS(XML_w, XML_showingPlcHdr);
diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx
index 07bffdb061ae..f61b4576a941 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -143,6 +143,7 @@ public:
OUString m_aPlaceHolderDocPart;
OUString m_aAlias;
OUString m_aTag;
+ OUString m_aLock;
sal_Int32 m_nSdtPrToken;
void DeleteAndResetTheLists();
diff --git a/sw/source/ui/vba/vbacontentcontrol.cxx b/sw/source/ui/vba/vbacontentcontrol.cxx
index 7ecd5ccc0365..03569406cb53 100644
--- a/sw/source/ui/vba/vbacontentcontrol.cxx
+++ b/sw/source/ui/vba/vbacontentcontrol.cxx
@@ -97,6 +97,13 @@ sal_Bool SwVbaContentControl::getChecked()
void SwVbaContentControl::setChecked(sal_Bool bSet)
{
+ // Word 2010: if locked, then the checked status is changed, but not the underlying text.
+ // Do we really want to do that? That is pretty bizarre behaviour...
+ // For now, just implement what seems to be a more logical response.
+ // TODO: test with modern versions.
+ if (getLockContents())
+ return;
+
std::shared_ptr<SwContentControl> pCC = m_rCC.GetContentControl().GetContentControl();
if (pCC->GetCheckbox() && pCC->GetChecked() != static_cast<bool>(bSet))
{
@@ -489,21 +496,27 @@ sal_Int32 SwVbaContentControl::getLevel()
sal_Bool SwVbaContentControl::getLockContentControl()
{
- SAL_INFO("sw.vba", "SwVbaContentControl::getLockContentControl stub");
- // returns whether the user can delete a content control from the active document.
- return true;
+ const std::shared_ptr<SwContentControl>& pCC = m_rCC.GetContentControl().GetContentControl();
+ std::optional<bool> oLock = pCC->GetLock(/*bControl=*/true);
+ return oLock && *oLock;
}
-void SwVbaContentControl::setLockContentControl(sal_Bool /*bSet*/)
+void SwVbaContentControl::setLockContentControl(sal_Bool bSet)
{
- SAL_INFO("sw.vba", "SwVbaContentControl::setLockContentControl stub");
+ std::shared_ptr<SwContentControl> pCC = m_rCC.GetContentControl().GetContentControl();
+ std::optional<bool> oLock = pCC->GetLock(/*bControl=*/false);
+ pCC->SetLock(/*bContents=*/oLock && *oLock, /*bControl=*/bSet);
}
sal_Bool SwVbaContentControl::getLockContents()
{
- // Pseudo-implementation - the need for locking in a form would be very rare.
- // LO uses this for internal purposes. Only expose it to VBA when safe.
const std::shared_ptr<SwContentControl>& pCC = m_rCC.GetContentControl().GetContentControl();
+ // If the theoretical design model says it is locked, then report as locked.
+ std::optional<bool> oLock = pCC->GetLock(/*bControl=*/false);
+ if (oLock && *oLock)
+ return true;
+
+ // Now check the real implementation.
// Checkbox/DropDown/Picture are normally locked - but not in this sense. Report as unlocked.
if (pCC->GetType() == SwContentControlType::CHECKBOX
|| pCC->GetType() == SwContentControlType::DROP_DOWN_LIST
@@ -518,6 +531,10 @@ sal_Bool SwVbaContentControl::getLockContents()
void SwVbaContentControl::setLockContents(sal_Bool bSet)
{
std::shared_ptr<SwContentControl> pCC = m_rCC.GetContentControl().GetContentControl();
+ // Set the lock both theoretically and actually.
+ std::optional<bool> oLock = pCC->GetLock(/*bControl=*/true);
+ pCC->SetLock(/*bContents=*/bSet, /*bControl=*/oLock && *oLock);
+
// Checkbox/DropDown/Picture are normally locked in LO implementation - don't unlock them.
if (pCC->GetType() == SwContentControlType::CHECKBOX
|| pCC->GetType() == SwContentControlType::DROP_DOWN_LIST
@@ -688,17 +705,24 @@ void SwVbaContentControl::Copy()
void SwVbaContentControl::Cut()
{
+ if (getLockContentControl())
+ return;
+
SAL_INFO("sw.vba",
"SwVbaContentControl::Cut[" << getID() << "], but missing sending to clipboard");
- m_rCC.Delete(/*bSaveContents=*/false);
+ m_rCC.Delete(/*bSaveContents=*/getLockContents());
}
void SwVbaContentControl::Delete(const uno::Any& DeleteContents)
{
+ if (getLockContentControl())
+ return;
+
bool bDeleteContents = false;
DeleteContents >>= bDeleteContents;
- m_rCC.Delete(!bDeleteContents);
+
+ m_rCC.Delete(/*bSaveContents=*/!bDeleteContents || getLockContents());
}
void SwVbaContentControl::SetCheckedSymbol(sal_Int32 Character, const uno::Any& Font)
diff --git a/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx b/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx
index 5b62fdf55122..f773991f7e02 100644
--- a/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx
+++ b/writerfilter/qa/cppunittests/dmapper/SdtHelper.cxx
@@ -95,6 +95,10 @@ CPPUNIT_TEST_FIXTURE(Test, testSdtRunRichText)
xContentControlProps->getPropertyValue("Tag") >>= aTag;
// This was empty.
CPPUNIT_ASSERT_EQUAL(OUString("mytag"), aTag);
+ OUString aLock;
+ xContentControlProps->getPropertyValue("Lock") >>= aLock;
+ // This was empty.
+ CPPUNIT_ASSERT_EQUAL(OUString("contentLocked"), aLock);
}
CPPUNIT_TEST_FIXTURE(Test, testSdtRunPlainText)
diff --git a/writerfilter/qa/cppunittests/dmapper/data/sdt-run-rich-text.docx b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-rich-text.docx
index b7f291f776bf..aabc745bcf0e 100644
--- a/writerfilter/qa/cppunittests/dmapper/data/sdt-run-rich-text.docx
+++ b/writerfilter/qa/cppunittests/dmapper/data/sdt-run-rich-text.docx
Binary files differ
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx
index 4395b65fc9c8..2dd9b0583445 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -2812,6 +2812,7 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
case NS_ooxml::LN_CT_SdtPlaceholder_docPart:
case NS_ooxml::LN_CT_SdtPr_color:
case NS_ooxml::LN_CT_SdtPr_tag:
+ case NS_ooxml::LN_CT_SdtPr_lock:
{
if (!m_pImpl->GetSdtStarts().empty())
{
@@ -2843,6 +2844,12 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
break;
}
+ if (nSprmId == NS_ooxml::LN_CT_SdtPr_lock)
+ {
+ m_pImpl->m_pSdtHelper->SetLock(sStringValue);
+ break;
+ }
+
if (nSprmId == NS_ooxml::LN_CT_SdtPr_checkbox)
{
m_pImpl->m_pSdtHelper->setControlType(SdtControlType::checkBox);
@@ -2890,6 +2897,7 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
case NS_ooxml::LN_CT_SdtPr_id: sName = "ooxml:CT_SdtPr_id"; break;
case NS_ooxml::LN_CT_SdtPr_alias: sName = "ooxml:CT_SdtPr_alias"; break;
case NS_ooxml::LN_CT_SdtPr_tag: sName = "ooxml:CT_SdtPr_tag"; break;
+ case NS_ooxml::LN_CT_SdtPr_lock: sName = "ooxml:CT_SdtPr_lock"; break;
case NS_ooxml::LN_CT_SdtPlaceholder_docPart: sName = "ooxml:CT_SdtPlaceholder_docPart"; break;
case NS_ooxml::LN_CT_SdtPr_color: sName = "ooxml:CT_SdtPr_color"; break;
default: assert(false);
@@ -2910,8 +2918,10 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
if (pProperties)
pProperties->resolve(*this);
- if (nSprmId == NS_ooxml::LN_CT_SdtPr_alias || nSprmId == NS_ooxml::LN_CT_SdtPr_tag)
+ if (nSprmId == NS_ooxml::LN_CT_SdtPr_alias || nSprmId == NS_ooxml::LN_CT_SdtPr_tag
+ || nSprmId == NS_ooxml::LN_CT_SdtPr_lock)
{
+ // Grabbag string values
beans::PropertyValue aValue;
aValue.Name = sName;
aValue.Value <<= sStringValue;
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index a3fba36fc39c..71f73d3fedea 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -948,6 +948,11 @@ void DomainMapper_Impl::PopSdt()
xContentControlProps->setPropertyValue("Id", uno::Any(m_pSdtHelper->GetId()));
}
+ if (!m_pSdtHelper->GetLock().isEmpty())
+ {
+ xContentControlProps->setPropertyValue("Lock", uno::Any(m_pSdtHelper->GetLock()));
+ }
+
if (m_pSdtHelper->getControlType() == SdtControlType::checkBox)
{
xContentControlProps->setPropertyValue("Checkbox", uno::makeAny(true));
diff --git a/writerfilter/source/dmapper/SdtHelper.cxx b/writerfilter/source/dmapper/SdtHelper.cxx
index 3e8811c69e92..9a72ef5e1f3a 100644
--- a/writerfilter/source/dmapper/SdtHelper.cxx
+++ b/writerfilter/source/dmapper/SdtHelper.cxx
@@ -460,6 +460,7 @@ void SdtHelper::clear()
m_aAlias.clear();
m_aTag.clear();
m_nId = 0;
+ m_aLock.clear();
}
void SdtHelper::SetPlaceholderDocPart(const OUString& rPlaceholderDocPart)
@@ -485,6 +486,10 @@ void SdtHelper::SetId(sal_Int32 nId) { m_nId = nId; }
sal_Int32 SdtHelper::GetId() const { return m_nId; }
+void SdtHelper::SetLock(const OUString& rLock) { m_aLock = rLock; }
+
+const OUString& SdtHelper::GetLock() const { return m_aLock; }
+
} // namespace writerfilter::dmapper
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/dmapper/SdtHelper.hxx b/writerfilter/source/dmapper/SdtHelper.hxx
index 201441547208..9504be5ddd57 100644
--- a/writerfilter/source/dmapper/SdtHelper.hxx
+++ b/writerfilter/source/dmapper/SdtHelper.hxx
@@ -134,6 +134,9 @@ class SdtHelper final : public virtual SvRefBase
/// <w:sdtPr>'s <w:id w:val="...">.
sal_Int32 m_nId = 0;
+ /// <w:sdtPr>'s <w:lock w:val="...">.
+ OUString m_aLock;
+
public:
explicit SdtHelper(DomainMapper_Impl& rDM_Impl,
css::uno::Reference<css::uno::XComponentContext> const& xContext);
@@ -222,6 +225,9 @@ public:
void SetId(sal_Int32 nId);
sal_Int32 GetId() const;
+ void SetLock(const OUString& rLock);
+ const OUString& GetLock() const;
+
std::optional<OUString> getValueFromDataBinding();
};
diff --git a/xmloff/qa/unit/data/content-control-alias.fodt b/xmloff/qa/unit/data/content-control-alias.fodt
index 8307f682e474..8f541bef42cc 100644
--- a/xmloff/qa/unit/data/content-control-alias.fodt
+++ b/xmloff/qa/unit/data/content-control-alias.fodt
@@ -2,7 +2,7 @@
<office:document xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text">
<office:body>
<office:text>
- <text:p><loext:content-control loext:alias="my alias" loext:tag="my tag">test</loext:content-control></text:p>
+ <text:p><loext:content-control loext:alias="my alias" loext:tag="my tag" loext:lock="sdtContentLocked">test</loext:content-control></text:p>
</office:text>
</office:body>
</office:document>
diff --git a/xmloff/qa/unit/text.cxx b/xmloff/qa/unit/text.cxx
index e2c18f4878da..a57bbc55d4dc 100644
--- a/xmloff/qa/unit/text.cxx
+++ b/xmloff/qa/unit/text.cxx
@@ -849,6 +849,7 @@ CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testAliasContentControlExport)
uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
xContentControlProps->setPropertyValue("Alias", uno::Any(OUString("my alias")));
xContentControlProps->setPropertyValue("Tag", uno::Any(OUString("my tag")));
+ xContentControlProps->setPropertyValue("Lock", uno::Any(OUString("unlocked")));
xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
// When exporting to ODT:
@@ -870,6 +871,7 @@ CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testAliasContentControlExport)
// i.e. alias was lost on export.
assertXPath(pXmlDoc, "//loext:content-control", "alias", "my alias");
assertXPath(pXmlDoc, "//loext:content-control", "tag", "my tag");
+ assertXPath(pXmlDoc, "//loext:content-control", "lock", "unlocked");
}
CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testComboBoxContentControlImport)
@@ -935,6 +937,9 @@ CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testAliasContentControlImport)
OUString aTag;
xContentControlProps->getPropertyValue("Tag") >>= aTag;
CPPUNIT_ASSERT_EQUAL(OUString("my tag"), aTag);
+ OUString aLock;
+ xContentControlProps->getPropertyValue("Lock") >>= aLock;
+ CPPUNIT_ASSERT_EQUAL(OUString("sdtContentLocked"), aLock);
}
CPPUNIT_TEST_FIXTURE(XmloffStyleTest, testDropdownContentControlAutostyleExport)
diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx
index 468c727e3d52..f605ab33ac26 100644
--- a/xmloff/source/core/xmltoken.cxx
+++ b/xmloff/source/core/xmltoken.cxx
@@ -1231,6 +1231,7 @@ namespace xmloff::token {
TOKEN( "list-style", XML_LIST_STYLE ),
TOKEN( "list-style-name", XML_LIST_STYLE_NAME ),
TOKEN( "ln", XML_LN ),
+ TOKEN( "lock", XML_LOCK ),
TOKEN( "locked", XML_LOCKED ),
TOKEN( "log", XML_LOG ),
TOKEN( "logarithmic", XML_LOGARITHMIC ),
diff --git a/xmloff/source/text/txtparae.cxx b/xmloff/source/text/txtparae.cxx
index e1ae73aae8cd..e46cbfc68649 100644
--- a/xmloff/source/text/txtparae.cxx
+++ b/xmloff/source/text/txtparae.cxx
@@ -3988,6 +3988,13 @@ void XMLTextParagraphExport::ExportContentControl(
{
GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_TAG, aTag);
}
+
+ OUString aLock;
+ xPropertySet->getPropertyValue("Lock") >>= aLock;
+ if (!aLock.isEmpty())
+ {
+ GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, XML_LOCK, aLock);
+ }
}
SvXMLElementExport aElem(GetExport(), bExport, XML_NAMESPACE_LO_EXT, XML_CONTENT_CONTROL, false,
diff --git a/xmloff/source/text/xmlcontentcontrolcontext.cxx b/xmloff/source/text/xmlcontentcontrolcontext.cxx
index 0a7574625ab9..d08d3f02cf32 100644
--- a/xmloff/source/text/xmlcontentcontrolcontext.cxx
+++ b/xmloff/source/text/xmlcontentcontrolcontext.cxx
@@ -151,6 +151,11 @@ void XMLContentControlContext::startFastElement(
m_aTag = rIter.toString();
break;
}
+ case XML_ELEMENT(LO_EXT, XML_LOCK):
+ {
+ m_aLock = rIter.toString();
+ break;
+ }
default:
XMLOFF_WARN_UNKNOWN("xmloff", rIter);
}
@@ -261,6 +266,11 @@ void XMLContentControlContext::endFastElement(sal_Int32)
{
xPropertySet->setPropertyValue("Tag", uno::Any(m_aTag));
}
+
+ if (!m_aLock.isEmpty())
+ {
+ xPropertySet->setPropertyValue("Lock", uno::Any(m_aLock));
+ }
}
css::uno::Reference<css::xml::sax::XFastContextHandler>
diff --git a/xmloff/source/text/xmlcontentcontrolcontext.hxx b/xmloff/source/text/xmlcontentcontrolcontext.hxx
index 936fc03c781b..f0b1eea0b010 100644
--- a/xmloff/source/text/xmlcontentcontrolcontext.hxx
+++ b/xmloff/source/text/xmlcontentcontrolcontext.hxx
@@ -53,6 +53,7 @@ class XMLContentControlContext : public SvXMLImportContext
bool m_bDropDown = false;
OUString m_aAlias;
OUString m_aTag;
+ OUString m_aLock;
public:
XMLContentControlContext(SvXMLImport& rImport, sal_Int32 nElement, XMLHints_Impl& rHints,
diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt
index d3f9c6f45d81..aed630735aaf 100644
--- a/xmloff/source/token/tokens.txt
+++ b/xmloff/source/token/tokens.txt
@@ -1131,6 +1131,7 @@ list-name
list-style
list-style-name
ln
+lock
locked
log
logarithmic