sw/inc/formatcontentcontrol.hxx | 14 +++ sw/inc/textcontentcontrol.hxx | 2 sw/inc/txatbase.hxx | 10 ++ sw/inc/unomap.hxx | 4 - sw/inc/unoprnms.hxx | 1 sw/qa/core/unocore/unocore.cxx | 9 ++ sw/source/core/inc/unocontentcontrol.hxx | 21 +++++ sw/source/core/txtnode/attrcontentcontrol.cxx | 36 +++++++++ sw/source/core/txtnode/txatbase.cxx | 1 sw/source/core/unocore/unocontentcontrol.cxx | 95 ++++++++++++++++++++++++++ sw/source/core/unocore/unomap.cxx | 5 + sw/source/core/unocore/unomap1.cxx | 17 ++++ 12 files changed, 212 insertions(+), 3 deletions(-)
New commits: commit 5da08b21cd23f2e70f5003733b03a7aee7915225 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Fri Apr 1 10:58:01 2022 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Fri Apr 1 11:54:33 2022 +0200 sw content controls: add UNO API to insert this with custom props Add the ability to specify if the content control is a placeholder or not on the content control object itself before insertion. Change-Id: Ia06869c69a5b85cfc1d0a55739bbb23a53bef4d5 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/132404 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins diff --git a/sw/inc/formatcontentcontrol.hxx b/sw/inc/formatcontentcontrol.hxx index 0fa075bf7036..c1ac07279efe 100644 --- a/sw/inc/formatcontentcontrol.hxx +++ b/sw/inc/formatcontentcontrol.hxx @@ -61,6 +61,8 @@ public: void NotifyChangeTextNode(SwTextNode* pTextNode); static SwFormatContentControl* CreatePoolDefault(sal_uInt16 nWhich); SwContentControl* GetContentControl() { return m_pContentControl.get(); } + + void dumpAsXml(xmlTextWriterPtr pWriter) const override; }; /// Stores the properties of a content control. @@ -73,6 +75,9 @@ class SwContentControl : public sw::BroadcastingModify /// Can be nullptr if not in a document for undo purposes. SwTextNode* m_pTextNode; + /// Current content is placeholder text. + bool m_bShowingPlaceHolder = false; + public: SwTextContentControl* GetTextAttr() const; @@ -99,6 +104,15 @@ public: explicit SwContentControl(SwFormatContentControl* pFormat); virtual ~SwContentControl() override; + + void SetShowingPlaceHolder(bool bShowingPlaceHolder) + { + m_bShowingPlaceHolder = bShowingPlaceHolder; + } + + bool GetShowingPlaceHolder() const { return m_bShowingPlaceHolder; } + + virtual void dumpAsXml(xmlTextWriterPtr pWriter) const; }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/inc/textcontentcontrol.hxx b/sw/inc/textcontentcontrol.hxx index 3410a6a35506..1c445d812099 100644 --- a/sw/inc/textcontentcontrol.hxx +++ b/sw/inc/textcontentcontrol.hxx @@ -36,6 +36,8 @@ public: ~SwTextContentControl() override; void ChgTextNode(SwTextNode* pNode); + + void dumpAsXml(xmlTextWriterPtr pWriter) const override; }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/inc/txatbase.hxx b/sw/inc/txatbase.hxx index 110e12064c9c..183e254f8817 100644 --- a/sw/inc/txatbase.hxx +++ b/sw/inc/txatbase.hxx @@ -29,6 +29,7 @@ #include "fmtflcnt.hxx" #include "fmtftn.hxx" #include "formatlinebreak.hxx" +#include "formatcontentcontrol.hxx" #include "fchrfmt.hxx" #include "tox.hxx" #include "ndhints.hxx" @@ -39,7 +40,7 @@ class SfxItemPool; * A wrapper around SfxPoolItem to store the start position of (usually) a text portion, with an * optional end. */ -class SAL_DLLPUBLIC_RTTI SwTextAttr +class SW_DLLPUBLIC SwTextAttr { friend class SwpHints; private: @@ -121,6 +122,7 @@ public: inline const SwFormatField &GetFormatField() const; inline const SwFormatFootnote &GetFootnote() const; inline const SwFormatLineBreak& GetLineBreak() const; + inline const SwFormatContentControl& GetContentControl() const; inline const SwFormatFlyCnt &GetFlyCnt() const; inline const SwTOXMark &GetTOXMark() const; inline const SwFormatRefMark &GetRefMark() const; @@ -215,6 +217,12 @@ inline const SwFormatLineBreak& SwTextAttr::GetLineBreak() const return static_cast<const SwFormatLineBreak&>(*m_pAttr); } +inline const SwFormatContentControl& SwTextAttr::GetContentControl() const +{ + assert(m_pAttr && m_pAttr->Which() == RES_TXTATR_CONTENTCONTROL); + return static_cast<const SwFormatContentControl&>(*m_pAttr); +} + inline const SwFormatFlyCnt& SwTextAttr::GetFlyCnt() const { assert( m_pAttr && m_pAttr->Which() == RES_TXTATR_FLYCNT ); diff --git a/sw/inc/unomap.hxx b/sw/inc/unomap.hxx index a9a78d550285..bae3be46d40f 100644 --- a/sw/inc/unomap.hxx +++ b/sw/inc/unomap.hxx @@ -126,7 +126,8 @@ struct SfxItemPropertyMapEntry; #define PROPERTY_MAP_CELL_STYLE 101 #define PROPERTY_MAP_FIELDMARK 102 #define PROPERTY_MAP_LINEBREAK 103 -#define PROPERTY_MAP_END 104 +#define PROPERTY_MAP_CONTENTCONTROL 104 +#define PROPERTY_MAP_END 105 //S&E #define WID_WORDS 0 @@ -352,6 +353,7 @@ private: static const SfxItemPropertyMapEntry* GetRedlinePortionPropertyMap(); static SfxItemPropertyMapEntry* GetTextDefaultPropertyMap(); static const SfxItemPropertyMapEntry* GetLineBreakPropertyMap(); + static const SfxItemPropertyMapEntry* GetContentControlPropertyMap(); }; extern SwUnoPropertyMapProvider aSwMapProvider; diff --git a/sw/inc/unoprnms.hxx b/sw/inc/unoprnms.hxx index 579e1752508a..6a04072fdae5 100644 --- a/sw/inc/unoprnms.hxx +++ b/sw/inc/unoprnms.hxx @@ -870,6 +870,7 @@ #define UNO_NAME_ALLOW_OVERLAP "AllowOverlap" #define UNO_NAME_CLEAR "Clear" #define UNO_NAME_LINEBREAK "LineBreak" +#define UNO_NAME_SHOWING_PLACE_HOLDER "ShowingPlaceHolder" #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 3d5bb93f2600..b03c91b39425 100644 --- a/sw/qa/core/unocore/unocore.cxx +++ b/sw/qa/core/unocore/unocore.cxx @@ -325,6 +325,9 @@ CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlInsert) xCursor->gotoEnd(/*bExpand=*/true); uno::Reference<text::XTextContent> xContentControl( xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY); + // Set a custom property on the content control: + uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY); + xContentControlProps->setPropertyValue("ShowingPlaceHolder", uno::makeAny(true)); xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); // Then make sure that the text attribute is inserted: @@ -335,6 +338,12 @@ CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlInsert) // Without the accompanying fix in place, this test would have failed, as the // SwXContentControl::attach() implementation was missing. CPPUNIT_ASSERT(pAttr); + // Also verify that the custom property was set: + auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr); + auto& rFormatContentControl + = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr()); + SwContentControl* pContentControl = rFormatContentControl.GetContentControl(); + CPPUNIT_ASSERT(pContentControl->GetShowingPlaceHolder()); } CPPUNIT_TEST_FIXTURE(SwModelTestBase, testImageTooltip) diff --git a/sw/source/core/inc/unocontentcontrol.hxx b/sw/source/core/inc/unocontentcontrol.hxx index 7f90f2ec18e7..631ccdaf02d3 100644 --- a/sw/source/core/inc/unocontentcontrol.hxx +++ b/sw/source/core/inc/unocontentcontrol.hxx @@ -29,6 +29,7 @@ #include <com/sun/star/container/XEnumerationAccess.hpp> #include <com/sun/star/text/XTextContent.hpp> #include <com/sun/star/text/XTextField.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> #include <cppuhelper/implbase.hxx> @@ -47,7 +48,7 @@ class SwContentControl; class SwXContentControl : public cppu::WeakImplHelper<css::lang::XUnoTunnel, css::lang::XServiceInfo, css::container::XEnumerationAccess, css::text::XTextContent, - css::text::XText> + css::text::XText, css::beans::XPropertySet> { public: class Impl; @@ -134,6 +135,24 @@ public: sal_Bool bAbsorb) override; void SAL_CALL removeTextContent(const css::uno::Reference<css::text::XTextContent>& xContent) override; + + // XPropertySet + css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + void SAL_CALL setPropertyValue(const OUString& rPropertyName, + const css::uno::Any& rValue) override; + css::uno::Any SAL_CALL getPropertyValue(const OUString& rPropertyName) override; + void SAL_CALL addPropertyChangeListener( + const OUString& rPropertyName, + const css::uno::Reference<css::beans::XPropertyChangeListener>& xListener) override; + void SAL_CALL removePropertyChangeListener( + const OUString& rPropertyName, + const css::uno::Reference<css::beans::XPropertyChangeListener>& xListener) override; + void SAL_CALL addVetoableChangeListener( + const OUString& rPropertyName, + const css::uno::Reference<css::beans::XVetoableChangeListener>& xListener) override; + void SAL_CALL removeVetoableChangeListener( + const OUString& rPropertyName, + const css::uno::Reference<css::beans::XVetoableChangeListener>& xListener) override; }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/txtnode/attrcontentcontrol.cxx b/sw/source/core/txtnode/attrcontentcontrol.cxx index eb127f1a1ba6..01af0eaec704 100644 --- a/sw/source/core/txtnode/attrcontentcontrol.cxx +++ b/sw/source/core/txtnode/attrcontentcontrol.cxx @@ -19,6 +19,8 @@ #include <formatcontentcontrol.hxx> +#include <libxml/xmlwriter.h> + #include <sal/log.hxx> #include <ndtxt.hxx> @@ -139,6 +141,21 @@ void SwFormatContentControl::DoCopy(SwTextNode& rTargetTextNode) m_pContentControl->NotifyChangeTextNode(&rTargetTextNode); } +void SwFormatContentControl::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwFormatContentControl")); + (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this); + (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("m_pTextAttr"), "%p", m_pTextAttr); + SfxPoolItem::dumpAsXml(pWriter); + + if (m_pContentControl) + { + m_pContentControl->dumpAsXml(pWriter); + } + + (void)xmlTextWriterEndElement(pWriter); +} + SwContentControl::SwContentControl(SwFormatContentControl* pFormat) : sw::BroadcastingModify() , m_pFormat(pFormat) @@ -188,6 +205,16 @@ void SwContentControl::SwClientNotify(const SwModify&, const SfxHint& rHint) } } +void SwContentControl::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwContentControl")); + (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this); + (void)xmlTextWriterWriteFormatAttribute( + pWriter, BAD_CAST("showing-place-holder"), "%s", + BAD_CAST(OString::boolean(m_bShowingPlaceHolder).getStr())); + (void)xmlTextWriterEndElement(pWriter); +} + SwTextContentControl* SwTextContentControl::CreateTextContentControl(SwTextNode* pTargetTextNode, SwFormatContentControl& rAttr, sal_Int32 nStart, @@ -234,4 +261,13 @@ void SwTextContentControl::ChgTextNode(SwTextNode* pNode) } } +void SwTextContentControl::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwTextContentControl")); + (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this); + SwTextAttr::dumpAsXml(pWriter); + + (void)xmlTextWriterEndElement(pWriter); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/txtnode/txatbase.cxx b/sw/source/core/txtnode/txatbase.cxx index cd18549c58d8..a6fe1599519b 100644 --- a/sw/source/core/txtnode/txatbase.cxx +++ b/sw/source/core/txtnode/txatbase.cxx @@ -166,6 +166,7 @@ void SwTextAttr::dumpAsXml(xmlTextWriterPtr pWriter) const case RES_TXTATR_META: break; case RES_TXTATR_CONTENTCONTROL: + GetContentControl().dumpAsXml(pWriter); break; default: SAL_WARN("sw.core", "Unhandled TXTATR"); diff --git a/sw/source/core/unocore/unocontentcontrol.cxx b/sw/source/core/unocore/unocontentcontrol.cxx index 63d80cc831fc..2b431a20de96 100644 --- a/sw/source/core/unocore/unocontentcontrol.cxx +++ b/sw/source/core/unocore/unocontentcontrol.cxx @@ -35,6 +35,8 @@ #include <unotextrange.hxx> #include <doc.hxx> #include <unoport.hxx> +#include <unomap.hxx> +#include <unoprnms.hxx> using namespace com::sun::star; @@ -153,6 +155,7 @@ public: uno::Reference<text::XText> m_xParentText; rtl::Reference<SwXContentControlText> m_xText; SwContentControl* m_pContentControl; + bool m_bShowingPlaceHolder; Impl(SwXContentControl& rThis, SwDoc& rDoc, SwContentControl* pContentControl, const uno::Reference<text::XText>& xParentText, @@ -163,6 +166,7 @@ public: , m_xParentText(xParentText) , m_xText(new SwXContentControlText(rDoc, rThis)) , m_pContentControl(pContentControl) + , m_bShowingPlaceHolder(false) { if (m_pContentControl) { @@ -500,6 +504,9 @@ void SwXContentControl::AttachImpl(const uno::Reference<text::XTextRange>& xText : SetAttrMode::DONTEXPAND; auto pContentControl = std::make_shared<SwContentControl>(nullptr); + + pContentControl->SetShowingPlaceHolder(m_pImpl->m_bShowingPlaceHolder); + SwFormatContentControl aContentControl(pContentControl, nWhich); bool bSuccess = pDoc->getIDocumentContentOperations().InsertPoolItem(aPam, aContentControl, nInsertFlags); @@ -635,6 +642,94 @@ SwXContentControl::removeTextContent(const uno::Reference<text::XTextContent>& x return m_pImpl->m_xText->removeTextContent(xContent); } +// XPropertySet +uno::Reference<beans::XPropertySetInfo> SAL_CALL SwXContentControl::getPropertySetInfo() +{ + SolarMutexGuard aGuard; + + static uno::Reference<beans::XPropertySetInfo> xRet + = aSwMapProvider.GetPropertySet(PROPERTY_MAP_CONTENTCONTROL)->getPropertySetInfo(); + return xRet; +} + +void SAL_CALL SwXContentControl::setPropertyValue(const OUString& rPropertyName, + const css::uno::Any& rValue) +{ + SolarMutexGuard aGuard; + + if (rPropertyName == UNO_NAME_SHOWING_PLACE_HOLDER) + { + bool bValue; + if (rValue >>= bValue) + { + if (m_pImpl->m_bIsDescriptor) + { + m_pImpl->m_bShowingPlaceHolder = bValue; + } + else + { + m_pImpl->m_pContentControl->SetShowingPlaceHolder(bValue); + } + } + } + else + { + throw beans::UnknownPropertyException(); + } +} + +uno::Any SAL_CALL SwXContentControl::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + + uno::Any aRet; + if (rPropertyName == UNO_NAME_SHOWING_PLACE_HOLDER) + { + if (m_pImpl->m_bIsDescriptor) + { + aRet <<= m_pImpl->m_bShowingPlaceHolder; + } + else + { + m_pImpl->m_pContentControl->GetShowingPlaceHolder(); + } + } + else + { + throw beans::UnknownPropertyException(); + } + + return aRet; +} + +void SAL_CALL SwXContentControl::addPropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference<beans::XPropertyChangeListener>& /*xListener*/) +{ + SAL_WARN("sw.uno", "SwXContentControl::addPropertyChangeListener: not implemented"); +} + +void SAL_CALL SwXContentControl::removePropertyChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference<beans::XPropertyChangeListener>& /*xListener*/) +{ + SAL_WARN("sw.uno", "SwXContentControl::removePropertyChangeListener: not implemented"); +} + +void SAL_CALL SwXContentControl::addVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference<beans::XVetoableChangeListener>& /*xListener*/) +{ + SAL_WARN("sw.uno", "SwXContentControl::addVetoableChangeListener: not implemented"); +} + +void SAL_CALL SwXContentControl::removeVetoableChangeListener( + const OUString& /*rPropertyName*/, + const uno::Reference<beans::XVetoableChangeListener>& /*xListener*/) +{ + SAL_WARN("sw.uno", "SwXContentControl::removeVetoableChangeListener: not implemented"); +} + // XElementAccess uno::Type SAL_CALL SwXContentControl::getElementType() { diff --git a/sw/source/core/unocore/unomap.cxx b/sw/source/core/unocore/unomap.cxx index b8e6f166fc80..e07481448d40 100644 --- a/sw/source/core/unocore/unomap.cxx +++ b/sw/source/core/unocore/unomap.cxx @@ -1559,6 +1559,11 @@ const SfxItemPropertyMapEntry* SwUnoPropertyMapProvider::GetPropertyMapEntries(s m_aMapEntriesArr[nPropertyId] = GetLineBreakPropertyMap(); } break; + case PROPERTY_MAP_CONTENTCONTROL: + { + m_aMapEntriesArr[nPropertyId] = GetContentControlPropertyMap(); + } + break; default: OSL_FAIL( "unexpected property map ID" ); diff --git a/sw/source/core/unocore/unomap1.cxx b/sw/source/core/unocore/unomap1.cxx index cc27bdc8b549..0b138f1d772c 100644 --- a/sw/source/core/unocore/unomap1.cxx +++ b/sw/source/core/unocore/unomap1.cxx @@ -1017,6 +1017,17 @@ const SfxItemPropertyMapEntry* SwUnoPropertyMapProvider::GetLineBreakPropertyMap return aLineBreakMap_Impl; } +const SfxItemPropertyMapEntry* SwUnoPropertyMapProvider::GetContentControlPropertyMap() +{ + static SfxItemPropertyMapEntry const aContentControlMap_Impl[] = + { + { u"" UNO_NAME_SHOWING_PLACE_HOLDER, 0, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0 }, + { u"", 0, css::uno::Type(), 0, 0 } + }; + + return aContentControlMap_Impl; +} + const SfxItemPropertyMapEntry* SwUnoPropertyMapProvider::GetRedlinePropertyMap() { static SfxItemPropertyMapEntry const aRedlineMap_Impl[] = @@ -1676,6 +1687,12 @@ const SfxItemPropertySet* SwUnoPropertyMapProvider::GetPropertySet( sal_uInt16 m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_LINEBREAK; } break; + case PROPERTY_MAP_CONTENTCONTROL: + { + static SfxItemPropertySet aPROPERTY_MAP_CONTENTCONTROL(pEntries); + m_aPropertySetArr[nPropertyId] = &aPROPERTY_MAP_CONTENTCONTROL; + } + break; } } return m_aPropertySetArr[nPropertyId];