From 267c6f2ac71f92999e969232431ba04678e7437e Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 07:54:39 +0200 Subject: Adding upstream version 4:24.2.0. Signed-off-by: Daniel Baumann --- sw/source/ui/vba/vbacontentcontrols.cxx | 268 ++++++++++++++++++++++++++++++++ 1 file changed, 268 insertions(+) create mode 100644 sw/source/ui/vba/vbacontentcontrols.cxx (limited to 'sw/source/ui/vba/vbacontentcontrols.cxx') diff --git a/sw/source/ui/vba/vbacontentcontrols.cxx b/sw/source/ui/vba/vbacontentcontrols.cxx new file mode 100644 index 0000000000..37199e2cec --- /dev/null +++ b/sw/source/ui/vba/vbacontentcontrols.cxx @@ -0,0 +1,268 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +#include +#include +#include + +#include "vbacontentcontrol.hxx" +#include "vbacontentcontrols.hxx" +#include "wordvbahelper.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +// Helper function to access the content controls +// @param rIndex +// [in] negative indexes indicate the need to search by name, otherwise get by index, +// using SAL_MAX_INT32 to indicate the need to just get the total count. +// [out] rIndex indicates the found index, or the total number of content controls +static std::shared_ptr +lcl_getContentControl(std::u16string_view sName, std::u16string_view sTag, + std::u16string_view sTitle, sal_Int32& rIndex, + const uno::Reference& xTextDocument, + uno::Sequence* pElementNames = nullptr) +{ + SwDoc* pDoc = word::getDocShell(xTextDocument)->GetDoc(); + if (!pDoc) + return nullptr; + + assert(sTag.empty() || sTitle.empty()); // only one grouping at a time is allowed + + std::shared_ptr pControl; + std::vector vElementNames; + SwContentControlManager& rManager = pDoc->GetContentControlManager(); + const size_t nLen = rManager.GetCount(); + if (!pElementNames && rIndex > 0 && sName.empty() && sTag.empty() && sTitle.empty()) + { + size_t i = static_cast(rIndex); + // This is the normal get-by-index/getCount mode - no need for fancy filtering. + if (i < nLen) + pControl = rManager.Get(i)->GetContentControl().GetContentControl(); + else + rIndex = nLen; + } + else + { + // loop through everything collecting names, filtering by Tag/Title + sal_Int32 nCounter = 0; + for (size_t i = 0; i < nLen; ++i) + { + pControl = rManager.Get(i)->GetContentControl().GetContentControl(); + if (!sTag.empty() && sTag != pControl->GetTag()) + { + pControl = nullptr; + continue; + } + if (!sTitle.empty() && sTitle != pControl->GetAlias()) + { + pControl = nullptr; + continue; + } + + // When treated as a name, consider the integer ID to be unsigned + const OUString sID = OUString::number(static_cast(pControl->GetId())); + if (!sName.empty() && sName != sID) + { + pControl = nullptr; + continue; + } + + if (pElementNames) + vElementNames.push_back(sID); + + if (rIndex == nCounter || !sName.empty()) + break; + + pControl = nullptr; + ++nCounter; + } + rIndex = nCounter; + } + if (pElementNames) + *pElementNames = comphelper::containerToSequence(vElementNames); + return pControl; +} + +namespace +{ +class ContentControlsEnumWrapper : public EnumerationHelper_BASE +{ + uno::Reference mxIndexAccess; + sal_Int32 mnIndex; + +public: + explicit ContentControlsEnumWrapper(uno::Reference xIndexAccess) + : mxIndexAccess(std::move(xIndexAccess)) + , mnIndex(0) + { + } + + sal_Bool SAL_CALL hasMoreElements() override { return (mnIndex < mxIndexAccess->getCount()); } + + uno::Any SAL_CALL nextElement() override + { + if (mnIndex < mxIndexAccess->getCount()) + { + return mxIndexAccess->getByIndex(mnIndex++); + } + throw container::NoSuchElementException(); + } +}; + +class ContentControlCollectionHelper + : public ::cppu::WeakImplHelper +{ +private: + uno::Reference mxParent; + uno::Reference mxContext; + uno::Reference mxTextDocument; + const OUString m_sTag; + const OUString m_sTitle; + std::shared_ptr m_pCache; + +public: + /// @throws css::uno::RuntimeException + ContentControlCollectionHelper(uno::Reference xParent, + uno::Reference xContext, + uno::Reference xTextDocument, + const OUString& rTag, const OUString& rTitle) + + : mxParent(std::move(xParent)) + , mxContext(std::move(xContext)) + , mxTextDocument(std::move(xTextDocument)) + , m_sTag(rTag) + , m_sTitle(rTitle) + { + } + + // XIndexAccess + sal_Int32 SAL_CALL getCount() override + { + sal_Int32 nCount = SAL_MAX_INT32; + lcl_getContentControl(u"", m_sTag, m_sTitle, nCount, mxTextDocument); + return nCount == SAL_MAX_INT32 || nCount < 0 ? 0 : nCount; + } + + uno::Any SAL_CALL getByIndex(sal_Int32 Index) override + { + m_pCache = lcl_getContentControl(u"", m_sTag, m_sTitle, Index, mxTextDocument); + if (!m_pCache) + throw lang::IndexOutOfBoundsException(); + + return uno::Any(uno::Reference( + new SwVbaContentControl(mxParent, mxContext, mxTextDocument, m_pCache))); + } + + // XNameAccess + uno::Sequence SAL_CALL getElementNames() override + { + sal_Int32 nCount = SAL_MAX_INT32; + uno::Sequence aSeq; + lcl_getContentControl(u"", m_sTag, m_sTitle, nCount, mxTextDocument, &aSeq); + return aSeq; + } + + uno::Any SAL_CALL getByName(const OUString& aName) override + { + if (!hasByName(aName)) + throw container::NoSuchElementException(); + + return uno::Any(uno::Reference( + new SwVbaContentControl(mxParent, mxContext, mxTextDocument, m_pCache))); + } + + sal_Bool SAL_CALL hasByName(const OUString& aName) override + { + sal_Int32 nCount = -1; + m_pCache = lcl_getContentControl(aName, m_sTag, m_sTitle, nCount, mxTextDocument); + return m_pCache != nullptr; + } + + // XElementAccess + uno::Type SAL_CALL getElementType() override + { + return cppu::UnoType::get(); + } + + sal_Bool SAL_CALL hasElements() override { return getCount() != 0; } + + // XEnumerationAccess + uno::Reference SAL_CALL createEnumeration() override + { + return new ContentControlsEnumWrapper(this); + } +}; +} + +/** + * Content Controls can be accessed and filtered in many different ways. + * Surprisingly however, there is no clear, descriptive "by name" access. + * Instead, each content control (probably) has a unique _signed-integer_ identifier, + * which can be passed to Item() as a float or _unsigned-integer_ string + * (to differentiate it from getByIndex). + * + * Index access can be filtered by Tag, Title, Range, and XML link. + * TODO: add filtering for Range, SelectLinkedControls, SelectUnlinkedControls + */ +SwVbaContentControls::SwVbaContentControls(const uno::Reference& xParent, + const uno::Reference& xContext, + const uno::Reference& xTextDocument, + const OUString& rTag, const OUString& rTitle) + : SwVbaContentControls_BASE( + xParent, xContext, + uno::Reference( + new ContentControlCollectionHelper(xParent, xContext, xTextDocument, rTag, rTitle))) +{ +} + +// uno::Reference SwVbaContentControls::Add(const uno::Any& Range, +// sal_Int32 Type) +// { +// sw::mark::IFieldmark* pFieldmark = nullptr; +// switch (Type) +// { +// case ooo::vba::word::WdFieldType::wdFieldFormCheckBox: +// break; +// case ooo::vba::word::WdFieldType::wdFieldFormDropDown: +// break; +// case ooo::vba::word::WdFieldType::wdFieldFormTextInput: +// default:; +// } +// +// return uno::Reference( +// new SwVbaContentControl(mxParent, mxContext, m_xTextDocument, pFieldmark)); +// } + +// XEnumerationAccess +uno::Type SwVbaContentControls::getElementType() +{ + return cppu::UnoType::get(); +} + +uno::Reference SwVbaContentControls::createEnumeration() +{ + return new ContentControlsEnumWrapper(m_xIndexAccess); +} + +uno::Any SwVbaContentControls::createCollectionObject(const uno::Any& aSource) { return aSource; } + +OUString SwVbaContentControls::getServiceImplName() { return "SwVbaContentControls"; } + +uno::Sequence SwVbaContentControls::getServiceNames() +{ + static uno::Sequence const sNames{ "ooo.vba.word.ContentControls" }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3