summaryrefslogtreecommitdiff
path: root/sw
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2022-11-08 16:45:00 +0100
committerMiklos Vajna <vmiklos@collabora.com>2022-11-09 13:09:01 +0100
commit6b419811d46966e556e05024d240d050947ebb81 (patch)
treea3b5078e257847f3954124242475448eba0c7bb1 /sw
parente33d8fd1ff466876e5e95c8495c73a08c454d8c9 (diff)
sw: introduce an UNO manager for content controls
This builds on top of commit ad950f10dc382ea169f94a0c301ca8c424e7103e (sw: introduce a manager for content controls, 2022-11-08) and exposes it on the UNO API: - add a new css.text.ContentControls service, backed by SwContentControlManager - add a new css.text.XContentControlsSupplier interface, implemented by SwXTextDocument - implement XIndexAccess in ContentControls This allows UNO (and later VBA) clients to have random access to the content controls in a document, which is much easier than the relatively complex traversal of the whole doc model. (cherry picked from commit a8448ded5555947925b0e9ddb4aeea7043f03933) Change-Id: I26240c9ddbd06f4f57f5f65460ef75a2ace94825 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/142477 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com> Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Diffstat (limited to 'sw')
-rw-r--r--sw/inc/textcontentcontrol.hxx3
-rw-r--r--sw/inc/unotxdoc.hxx6
-rw-r--r--sw/qa/core/unocore/unocore.cxx50
-rw-r--r--sw/source/core/inc/unocontentcontrol.hxx24
-rw-r--r--sw/source/core/txtnode/attrcontentcontrol.cxx19
-rw-r--r--sw/source/core/unocore/unocontentcontrol.cxx70
-rw-r--r--sw/source/uibase/uno/unotxdoc.cxx20
7 files changed, 192 insertions, 0 deletions
diff --git a/sw/inc/textcontentcontrol.hxx b/sw/inc/textcontentcontrol.hxx
index dc7d210f79a6..78a4d5120b1b 100644
--- a/sw/inc/textcontentcontrol.hxx
+++ b/sw/inc/textcontentcontrol.hxx
@@ -56,6 +56,9 @@ public:
SwContentControlManager();
void Insert(SwTextContentControl* pTextContentControl);
void Erase(SwTextContentControl* pTextContentControl);
+ size_t GetCount() const { return m_aContentControls.size(); }
+ bool IsEmpty() const { return m_aContentControls.empty(); }
+ SwTextContentControl* Get(size_t nIndex);
void dumpAsXml(xmlTextWriterPtr pWriter) const;
};
diff --git a/sw/inc/unotxdoc.hxx b/sw/inc/unotxdoc.hxx
index dc022d34ccc7..4e4d3f160eec 100644
--- a/sw/inc/unotxdoc.hxx
+++ b/sw/inc/unotxdoc.hxx
@@ -29,6 +29,7 @@
#include <com/sun/star/text/XNumberingRulesSupplier.hpp>
#include <com/sun/star/text/XFootnotesSupplier.hpp>
#include <com/sun/star/text/XEndnotesSupplier.hpp>
+#include <com/sun/star/text/XContentControlsSupplier.hpp>
#include <com/sun/star/text/XTextSectionsSupplier.hpp>
#include <com/sun/star/text/XLineNumberingProperties.hpp>
#include <com/sun/star/text/XChapterNumberingSupplier.hpp>
@@ -99,6 +100,7 @@ typedef cppu::ImplInheritanceHelper
css::text::XNumberingRulesSupplier,
css::text::XFootnotesSupplier,
css::text::XEndnotesSupplier,
+ css::text::XContentControlsSupplier,
css::util::XReplaceable,
css::text::XPagePrintable,
css::text::XReferenceMarksSupplier,
@@ -156,6 +158,7 @@ private:
css::uno::Reference< css::beans::XPropertySet > mxXFootnoteSettings;
css::uno::Reference< css::container::XIndexAccess > mxXEndnotes;
css::uno::Reference< css::beans::XPropertySet > mxXEndnoteSettings;
+ css::uno::Reference< css::container::XIndexAccess > mxXContentControls;
css::uno::Reference< css::container::XNameAccess > mxXReferenceMarks;
css::uno::Reference< css::container::XEnumerationAccess > mxXTextFieldTypes;
css::uno::Reference< css::container::XNameAccess > mxXTextFieldMasters;
@@ -265,6 +268,9 @@ public:
virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL getEndnotes() override;
virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL getEndnoteSettings() override;
+ // XContentControlsSupplier
+ css::uno::Reference<css::container::XIndexAccess> SAL_CALL getContentControls() override;
+
//XReplaceable
virtual css::uno::Reference< css::util::XReplaceDescriptor > SAL_CALL createReplaceDescriptor() override;
virtual sal_Int32 SAL_CALL replaceAll(const css::uno::Reference< css::util::XSearchDescriptor > & xDesc) override;
diff --git a/sw/qa/core/unocore/unocore.cxx b/sw/qa/core/unocore/unocore.cxx
index 18286efe9ed9..20d93d688f96 100644
--- a/sw/qa/core/unocore/unocore.cxx
+++ b/sw/qa/core/unocore/unocore.cxx
@@ -706,6 +706,56 @@ CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlComboBox)
CPPUNIT_ASSERT(pContentControl->GetComboBox());
}
+CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControls)
+{
+ // Given an empty document:
+ createSwDoc();
+ auto pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ uno::Reference<container::XIndexAccess> xContentControls = pXTextDocument->getContentControls();
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), xContentControls->getCount());
+
+ // When inserting content controls:
+ 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();
+ // First tag1.
+ xText->insertString(xCursor, "test1", /*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);
+ xContentControlProps->setPropertyValue("Tag", uno::Any(OUString("tag1")));
+ xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
+ }
+ xCursor->gotoStart(/*bExpand=*/false);
+ // Then tag2 before tag1.
+ xText->insertString(xCursor, "test2", /*bAbsorb=*/false);
+ xCursor->gotoStart(/*bExpand=*/false);
+ xCursor->goRight(5, /*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);
+ xContentControlProps->setPropertyValue("Tag", uno::Any(OUString("tag2")));
+ xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
+ }
+
+ // Then make sure that XContentControls contains the items in a correct order:
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2), xContentControls->getCount());
+ uno::Reference<beans::XPropertySet> xContentControl;
+ xContentControls->getByIndex(0) >>= xContentControl;
+ OUString aTag;
+ xContentControl->getPropertyValue("Tag") >>= aTag;
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: tag2
+ // - Actual : tag1
+ // i.e. the order of the items was sorted by insert time, not by their doc model position.
+ CPPUNIT_ASSERT_EQUAL(OUString("tag2"), aTag);
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/inc/unocontentcontrol.hxx b/sw/source/core/inc/unocontentcontrol.hxx
index 631ccdaf02d3..90d408a7964d 100644
--- a/sw/source/core/inc/unocontentcontrol.hxx
+++ b/sw/source/core/inc/unocontentcontrol.hxx
@@ -34,11 +34,13 @@
#include <cppuhelper/implbase.hxx>
#include <unobaseclass.hxx>
+#include <unocoll.hxx>
typedef std::deque<css::uno::Reference<css::text::XTextRange>> TextRangeList_t;
class SwPaM;
class SwTextNode;
+class SwFormatContentControl;
class SwContentControl;
/**
@@ -155,4 +157,26 @@ public:
const css::uno::Reference<css::beans::XVetoableChangeListener>& xListener) override;
};
+/// UNO wrapper around SwContentControlManager.
+class SwXContentControls final : public SwSimpleIndexAccessBaseClass, public SwUnoCollection
+{
+ ~SwXContentControls() override;
+
+public:
+ SwXContentControls(SwDoc* pDoc);
+
+ // XIndexAccess
+ sal_Int32 SAL_CALL getCount() override;
+ css::uno::Any SAL_CALL getByIndex(sal_Int32 nIndex) override;
+
+ // XElementAccess
+ css::uno::Type SAL_CALL getElementType() override;
+ sal_Bool SAL_CALL hasElements() override;
+
+ // XServiceInfo
+ OUString SAL_CALL getImplementationName() override;
+ sal_Bool SAL_CALL supportsService(const OUString& rServiceName) override;
+ css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() 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 418f35878f85..263b64a2da8f 100644
--- a/sw/source/core/txtnode/attrcontentcontrol.cxx
+++ b/sw/source/core/txtnode/attrcontentcontrol.cxx
@@ -598,6 +598,25 @@ void SwContentControlManager::Erase(SwTextContentControl* pTextContentControl)
m_aContentControls.end());
}
+SwTextContentControl* SwContentControlManager::Get(size_t nIndex)
+{
+ // Only sort now: the items may not have an associated text node by the time they are inserted
+ // into the container.
+ std::sort(m_aContentControls.begin(), m_aContentControls.end(),
+ [](SwTextContentControl*& pLhs, SwTextContentControl*& pRhs) -> bool {
+ SwNodeOffset nIdxLHS = pLhs->GetTextNode()->GetIndex();
+ SwNodeOffset nIdxRHS = pRhs->GetTextNode()->GetIndex();
+ if (nIdxLHS == nIdxRHS)
+ {
+ return pLhs->GetStart() < pRhs->GetStart();
+ }
+
+ return nIdxLHS < nIdxRHS;
+ });
+
+ return m_aContentControls[nIndex];
+}
+
void SwContentControlManager::dumpAsXml(xmlTextWriterPtr pWriter) const
{
(void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwContentControlManager"));
diff --git a/sw/source/core/unocore/unocontentcontrol.cxx b/sw/source/core/unocore/unocontentcontrol.cxx
index 0e19b7e57f41..bae19e9b6edd 100644
--- a/sw/source/core/unocore/unocontentcontrol.cxx
+++ b/sw/source/core/unocore/unocontentcontrol.cxx
@@ -22,6 +22,7 @@
#include <mutex>
#include <com/sun/star/text/XWordCursor.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
#include <comphelper/interfacecontainer4.hxx>
#include <comphelper/servicehelper.hxx>
@@ -1324,4 +1325,73 @@ uno::Reference<container::XEnumeration> SAL_CALL SwXContentControl::createEnumer
}
}
+SwXContentControls::SwXContentControls(SwDoc* pDoc)
+ : SwUnoCollection(pDoc)
+{
+}
+
+SwXContentControls::~SwXContentControls() {}
+
+sal_Int32 SwXContentControls::getCount()
+{
+ SolarMutexGuard aGuard;
+
+ if (!IsValid())
+ {
+ throw uno::RuntimeException();
+ }
+
+ return GetDoc()->GetContentControlManager().GetCount();
+}
+
+uno::Any SwXContentControls::getByIndex(sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+
+ if (!IsValid())
+ {
+ throw uno::RuntimeException();
+ }
+
+ SwContentControlManager& rManager = GetDoc()->GetContentControlManager();
+ if (nIndex < 0 || o3tl::make_unsigned(nIndex) >= rManager.GetCount())
+ {
+ throw lang::IndexOutOfBoundsException();
+ }
+
+ SwTextContentControl* pTextContentControl = rManager.Get(nIndex);
+ const SwFormatContentControl& rFormatContentControl = pTextContentControl->GetContentControl();
+ uno::Reference<css::text::XTextContent> xContentControl
+ = SwXContentControl::CreateXContentControl(*rFormatContentControl.GetContentControl());
+ uno::Any aRet;
+ aRet <<= xContentControl;
+ return aRet;
+}
+
+uno::Type SwXContentControls::getElementType() { return cppu::UnoType<text::XTextContent>::get(); }
+
+sal_Bool SwXContentControls::hasElements()
+{
+ SolarMutexGuard aGuard;
+
+ if (!IsValid())
+ {
+ throw uno::RuntimeException();
+ }
+
+ return !GetDoc()->GetContentControlManager().IsEmpty();
+}
+
+OUString SwXContentControls::getImplementationName() { return "SwXContentControls"; }
+
+sal_Bool SwXContentControls::supportsService(const OUString& rServiceName)
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SwXContentControls::getSupportedServiceNames()
+{
+ return { "com.sun.star.text.ContentControls" };
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/uno/unotxdoc.cxx b/sw/source/uibase/uno/unotxdoc.cxx
index a233745ae7fd..f3f1911d3ee2 100644
--- a/sw/source/uibase/uno/unotxdoc.cxx
+++ b/sw/source/uibase/uno/unotxdoc.cxx
@@ -167,6 +167,7 @@
#include <IDocumentOutlineNodes.hxx>
#include <SearchResultLocator.hxx>
#include <textcontentcontrol.hxx>
+#include <unocontentcontrol.hxx>
using namespace ::com::sun::star;
using namespace ::com::sun::star::text;
@@ -660,6 +661,18 @@ Reference< XPropertySet > SwXTextDocument::getEndnoteSettings()
return mxXEndnoteSettings;
}
+Reference< XIndexAccess > SwXTextDocument::getContentControls()
+{
+ SolarMutexGuard aGuard;
+ if(!IsValid())
+ throw DisposedException("", static_cast< XTextDocument* >(this));
+ if(!mxXContentControls.is())
+ {
+ mxXContentControls = new SwXContentControls(m_pDocShell->GetDoc());
+ }
+ return mxXContentControls;
+}
+
Reference< util::XReplaceDescriptor > SwXTextDocument::createReplaceDescriptor()
{
SolarMutexGuard aGuard;
@@ -1489,6 +1502,13 @@ void SwXTextDocument::InitNewDoc()
mxXEndnotes.clear();
}
+ if(mxXContentControls.is())
+ {
+ XIndexAccess* pContentControls = mxXContentControls.get();
+ static_cast<SwXContentControls*>(pContentControls)->Invalidate();
+ mxXContentControls.clear();
+ }
+
if(mxXDocumentIndexes.is())
{
XIndexAccess* pIdxs = mxXDocumentIndexes.get();