sw/inc/formatcontentcontrol.hxx | 28 ++++++ sw/inc/unoprnms.hxx | 4 sw/qa/core/unocore/unocore.cxx | 38 ++++++++ sw/source/core/txtnode/attrcontentcontrol.cxx | 8 + sw/source/core/unocore/unocontentcontrol.cxx | 114 ++++++++++++++++++++++++++ sw/source/core/unocore/unomap1.cxx | 4 6 files changed, 196 insertions(+)
New commits: commit cd2272874d1b1911dec6c6e7bf3d67861be4a015 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Mon Apr 25 08:47:32 2022 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Mon Apr 25 12:36:00 2022 +0200 sw content controls, checkbox: add document model & UNO API Add 4 new properties: if this is a checkbox, and is so: - if it's checked - unicode value for the checked state - unicode value for the unchecked state This should be enough for the UI to be able to update checkmark state on click. Change-Id: I723532fd2d3377cf09a1127c69c55f9539649088 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133363 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins diff --git a/sw/inc/formatcontentcontrol.hxx b/sw/inc/formatcontentcontrol.hxx index bb92454ffd09..368720a0cb76 100644 --- a/sw/inc/formatcontentcontrol.hxx +++ b/sw/inc/formatcontentcontrol.hxx @@ -80,6 +80,18 @@ class SAL_DLLPUBLIC_RTTI SwContentControl : public sw::BroadcastingModify /// Current content is placeholder text. bool m_bShowingPlaceHolder = false; + /// Display the content control as a checkbox. + bool m_bCheckbox = false; + + /// If m_bCheckbox is true, is the checkbox checked? + bool m_bChecked = false; + + /// If m_bCheckbox is true, the value of a checked checkbox. + OUString m_aCheckedState; + + /// If m_bCheckbox is true, the value of an unchecked checkbox. + OUString m_aUncheckedState; + public: SwTextContentControl* GetTextAttr() const; @@ -114,6 +126,22 @@ public: bool GetShowingPlaceHolder() const { return m_bShowingPlaceHolder; } + void SetCheckbox(bool bCheckbox) { m_bCheckbox = bCheckbox; } + + bool GetCheckbox() const { return m_bCheckbox; } + + void SetChecked(bool bChecked) { m_bChecked = bChecked; } + + bool GetChecked() const { return m_bChecked; } + + void SetCheckedState(const OUString& rCheckedState) { m_aCheckedState = rCheckedState; } + + OUString GetCheckedState() const { return m_aCheckedState; } + + void SetUncheckedState(const OUString& rUncheckedState) { m_aUncheckedState = rUncheckedState; } + + OUString GetUncheckedState() const { return m_aUncheckedState; } + virtual void dumpAsXml(xmlTextWriterPtr pWriter) const; }; diff --git a/sw/inc/unoprnms.hxx b/sw/inc/unoprnms.hxx index 3e6516b3551c..bfc3a28aeecc 100644 --- a/sw/inc/unoprnms.hxx +++ b/sw/inc/unoprnms.hxx @@ -872,6 +872,10 @@ #define UNO_NAME_LINEBREAK "LineBreak" #define UNO_NAME_CONTENT_CONTROL "ContentControl" #define UNO_NAME_SHOWING_PLACE_HOLDER "ShowingPlaceHolder" +#define UNO_NAME_CHECKBOX "Checkbox" +#define UNO_NAME_CHECKED "Checked" +#define UNO_NAME_CHECKED_STATE "CheckedState" +#define UNO_NAME_UNCHECKED_STATE "UncheckedState" #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/qa/core/unocore/unocore.cxx b/sw/qa/core/unocore/unocore.cxx index 19ad5d5fd48b..0f1b6a5e7623 100644 --- a/sw/qa/core/unocore/unocore.cxx +++ b/sw/qa/core/unocore/unocore.cxx @@ -418,6 +418,44 @@ CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlTextPortionEnum) assertXPath(pXmlDoc, "//SwParaPortion/SwLineLayout/SwLinePortion", "portion", "test"); } +CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlCheckbox) +{ + // Given an empty document: + SwDoc* pDoc = createSwDoc(); + + // When inserting a checkbox content control: + uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XText> xText = xTextDocument->getText(); + uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor(); + xText->insertString(xCursor, "test", /*bAbsorb=*/false); + xCursor->gotoStart(/*bExpand=*/false); + xCursor->gotoEnd(/*bExpand=*/true); + uno::Reference<text::XTextContent> xContentControl( + xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY); + // Without the accompanying fix in place, this test would have failed with: + // An uncaught exception of type com.sun.star.beans.UnknownPropertyException + xContentControlProps->setPropertyValue("Checkbox", uno::makeAny(true)); + xContentControlProps->setPropertyValue("Checked", uno::makeAny(true)); + xContentControlProps->setPropertyValue("CheckedState", uno::makeAny(OUString(u"☒"))); + xContentControlProps->setPropertyValue("UncheckedState", uno::makeAny(OUString(u"☐"))); + xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); + + // Then make sure that the specified properties are set: + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + SwTextNode* pTextNode = pWrtShell->GetCursor()->GetNode().GetTextNode(); + SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_CONTENTCONTROL); + auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr); + auto& rFormatContentControl + = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr()); + SwContentControl* pContentControl = rFormatContentControl.GetContentControl(); + CPPUNIT_ASSERT(pContentControl->GetCheckbox()); + CPPUNIT_ASSERT(pContentControl->GetChecked()); + CPPUNIT_ASSERT_EQUAL(OUString(u"☒"), pContentControl->GetCheckedState()); + CPPUNIT_ASSERT_EQUAL(OUString(u"☐"), pContentControl->GetUncheckedState()); +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/txtnode/attrcontentcontrol.cxx b/sw/source/core/txtnode/attrcontentcontrol.cxx index 066ddd0494be..e469bab96e1d 100644 --- a/sw/source/core/txtnode/attrcontentcontrol.cxx +++ b/sw/source/core/txtnode/attrcontentcontrol.cxx @@ -212,6 +212,14 @@ void SwContentControl::dumpAsXml(xmlTextWriterPtr pWriter) const (void)xmlTextWriterWriteFormatAttribute( pWriter, BAD_CAST("showing-place-holder"), "%s", BAD_CAST(OString::boolean(m_bShowingPlaceHolder).getStr())); + (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("checkbox"), "%s", + BAD_CAST(OString::boolean(m_bCheckbox).getStr())); + (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("checked"), "%s", + BAD_CAST(OString::boolean(m_bChecked).getStr())); + (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("checked-state"), "%s", + BAD_CAST(m_aCheckedState.toUtf8().getStr())); + (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("unchecked-state"), "%s", + BAD_CAST(m_aUncheckedState.toUtf8().getStr())); (void)xmlTextWriterEndElement(pWriter); } diff --git a/sw/source/core/unocore/unocontentcontrol.cxx b/sw/source/core/unocore/unocontentcontrol.cxx index 93b7c976ae0d..81ccc9fd088c 100644 --- a/sw/source/core/unocore/unocontentcontrol.cxx +++ b/sw/source/core/unocore/unocontentcontrol.cxx @@ -156,6 +156,10 @@ public: rtl::Reference<SwXContentControlText> m_xText; SwContentControl* m_pContentControl; bool m_bShowingPlaceHolder; + bool m_bCheckbox; + bool m_bChecked; + OUString m_aCheckedState; + OUString m_aUncheckedState; Impl(SwXContentControl& rThis, SwDoc& rDoc, SwContentControl* pContentControl, const uno::Reference<text::XText>& xParentText, @@ -167,6 +171,8 @@ public: , m_xText(new SwXContentControlText(rDoc, rThis)) , m_pContentControl(pContentControl) , m_bShowingPlaceHolder(false) + , m_bCheckbox(false) + , m_bChecked(false) { if (m_pContentControl) { @@ -506,6 +512,10 @@ void SwXContentControl::AttachImpl(const uno::Reference<text::XTextRange>& xText auto pContentControl = std::make_shared<SwContentControl>(nullptr); pContentControl->SetShowingPlaceHolder(m_pImpl->m_bShowingPlaceHolder); + pContentControl->SetCheckbox(m_pImpl->m_bCheckbox); + pContentControl->SetChecked(m_pImpl->m_bChecked); + pContentControl->SetCheckedState(m_pImpl->m_aCheckedState); + pContentControl->SetUncheckedState(m_pImpl->m_aUncheckedState); SwFormatContentControl aContentControl(pContentControl, nWhich); bool bSuccess @@ -672,6 +682,66 @@ void SAL_CALL SwXContentControl::setPropertyValue(const OUString& rPropertyName, } } } + else if (rPropertyName == UNO_NAME_CHECKBOX) + { + bool bValue; + if (rValue >>= bValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_bCheckbox = bValue; + } + else + { + m_pImpl->m_pContentControl->SetCheckbox(bValue); + } + } + } + else if (rPropertyName == UNO_NAME_CHECKED) + { + bool bValue; + if (rValue >>= bValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_bChecked = bValue; + } + else + { + m_pImpl->m_pContentControl->SetChecked(bValue); + } + } + } + else if (rPropertyName == UNO_NAME_CHECKED_STATE) + { + OUString aValue; + if (rValue >>= aValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_aCheckedState = aValue; + } + else + { + m_pImpl->m_pContentControl->SetCheckedState(aValue); + } + } + } + else if (rPropertyName == UNO_NAME_UNCHECKED_STATE) + { + OUString aValue; + if (rValue >>= aValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_aUncheckedState = aValue; + } + else + { + m_pImpl->m_pContentControl->SetUncheckedState(aValue); + } + } + } else { throw beans::UnknownPropertyException(); @@ -694,6 +764,50 @@ uno::Any SAL_CALL SwXContentControl::getPropertyValue(const OUString& rPropertyN aRet <<= m_pImpl->m_pContentControl->GetShowingPlaceHolder(); } } + else if (rPropertyName == UNO_NAME_CHECKBOX) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_bCheckbox; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetCheckbox(); + } + } + else if (rPropertyName == UNO_NAME_CHECKED) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_bChecked; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetChecked(); + } + } + else if (rPropertyName == UNO_NAME_CHECKED_STATE) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_aCheckedState; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetCheckedState(); + } + } + else if (rPropertyName == UNO_NAME_UNCHECKED_STATE) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_aUncheckedState; + } + else + { + aRet <<= m_pImpl->m_pContentControl->GetUncheckedState(); + } + } else { throw beans::UnknownPropertyException(); diff --git a/sw/source/core/unocore/unomap1.cxx b/sw/source/core/unocore/unomap1.cxx index acf803d34253..3da6c8097051 100644 --- a/sw/source/core/unocore/unomap1.cxx +++ b/sw/source/core/unocore/unomap1.cxx @@ -1023,6 +1023,10 @@ const SfxItemPropertyMapEntry* SwUnoPropertyMapProvider::GetContentControlProper static SfxItemPropertyMapEntry const aContentControlMap_Impl[] = { { u"" UNO_NAME_SHOWING_PLACE_HOLDER, 0, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + { u"" UNO_NAME_CHECKBOX, 0, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + { u"" UNO_NAME_CHECKED, 0, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + { u"" UNO_NAME_CHECKED_STATE, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, + { u"" UNO_NAME_UNCHECKED_STATE, 0, cppu::UnoType<OUString>::get(), PROPERTY_NONE, 0 }, { u"", 0, css::uno::Type(), 0, 0 } };