1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <comphelper/sequence.hxx>
11 #include <sal/log.hxx>
15 #include <textcontentcontrol.hxx>
17 #include "vbacontentcontrol.hxx"
18 #include "vbacontentcontrols.hxx"
19 #include "wordvbahelper.hxx"
21 using namespace ::ooo::vba
;
22 using namespace ::com::sun::star
;
24 // Helper function to access the content controls
26 // [in] negative indexes indicate the need to search by name, otherwise get by index,
27 // using SAL_MAX_INT32 to indicate the need to just get the total count.
28 // [out] rIndex indicates the found index, or the total number of content controls
29 static std::shared_ptr
<SwContentControl
>
30 lcl_getContentControl(std::u16string_view sName
, std::u16string_view sTag
,
31 std::u16string_view sTitle
, sal_Int32
& rIndex
,
32 const uno::Reference
<text::XTextDocument
>& xTextDocument
,
33 uno::Sequence
<OUString
>* pElementNames
= nullptr)
35 SwDoc
* pDoc
= word::getDocShell(xTextDocument
)->GetDoc();
39 assert(sTag
.empty() || sTitle
.empty()); // only one grouping at a time is allowed
41 std::shared_ptr
<SwContentControl
> pControl
;
42 std::vector
<OUString
> vElementNames
;
43 SwContentControlManager
& rManager
= pDoc
->GetContentControlManager();
44 const size_t nLen
= rManager
.GetCount();
45 if (!pElementNames
&& rIndex
> 0 && sName
.empty() && sTag
.empty() && sTitle
.empty())
47 size_t i
= static_cast<size_t>(rIndex
);
48 // This is the normal get-by-index/getCount mode - no need for fancy filtering.
50 pControl
= rManager
.Get(i
)->GetContentControl().GetContentControl();
56 // loop through everything collecting names, filtering by Tag/Title
57 sal_Int32 nCounter
= 0;
58 for (size_t i
= 0; i
< nLen
; ++i
)
60 pControl
= rManager
.Get(i
)->GetContentControl().GetContentControl();
61 if (!sTag
.empty() && sTag
!= pControl
->GetTag())
66 if (!sTitle
.empty() && sTitle
!= pControl
->GetAlias())
72 // When treated as a name, consider the integer ID to be unsigned
73 const OUString sID
= OUString::number(static_cast<sal_uInt32
>(pControl
->GetId()));
74 if (!sName
.empty() && sName
!= sID
)
81 vElementNames
.push_back(sID
);
83 if (rIndex
== nCounter
|| !sName
.empty())
92 *pElementNames
= comphelper::containerToSequence(vElementNames
);
98 class ContentControlsEnumWrapper
: public EnumerationHelper_BASE
100 uno::Reference
<container::XIndexAccess
> mxIndexAccess
;
104 explicit ContentControlsEnumWrapper(uno::Reference
<container::XIndexAccess
> xIndexAccess
)
105 : mxIndexAccess(std::move(xIndexAccess
))
110 sal_Bool SAL_CALL
hasMoreElements() override
{ return (mnIndex
< mxIndexAccess
->getCount()); }
112 uno::Any SAL_CALL
nextElement() override
114 if (mnIndex
< mxIndexAccess
->getCount())
116 return mxIndexAccess
->getByIndex(mnIndex
++);
118 throw container::NoSuchElementException();
122 class ContentControlCollectionHelper
123 : public ::cppu::WeakImplHelper
<container::XNameAccess
, container::XIndexAccess
,
124 container::XEnumerationAccess
>
127 uno::Reference
<XHelperInterface
> mxParent
;
128 uno::Reference
<uno::XComponentContext
> mxContext
;
129 uno::Reference
<text::XTextDocument
> mxTextDocument
;
130 const OUString m_sTag
;
131 const OUString m_sTitle
;
132 std::shared_ptr
<SwContentControl
> m_pCache
;
135 /// @throws css::uno::RuntimeException
136 ContentControlCollectionHelper(uno::Reference
<ov::XHelperInterface
> xParent
,
137 uno::Reference
<uno::XComponentContext
> xContext
,
138 uno::Reference
<text::XTextDocument
> xTextDocument
,
139 const OUString
& rTag
, const OUString
& rTitle
)
141 : mxParent(std::move(xParent
))
142 , mxContext(std::move(xContext
))
143 , mxTextDocument(std::move(xTextDocument
))
150 sal_Int32 SAL_CALL
getCount() override
152 sal_Int32 nCount
= SAL_MAX_INT32
;
153 lcl_getContentControl(u
"", m_sTag
, m_sTitle
, nCount
, mxTextDocument
);
154 return nCount
== SAL_MAX_INT32
|| nCount
< 0 ? 0 : nCount
;
157 uno::Any SAL_CALL
getByIndex(sal_Int32 Index
) override
159 m_pCache
= lcl_getContentControl(u
"", m_sTag
, m_sTitle
, Index
, mxTextDocument
);
161 throw lang::IndexOutOfBoundsException();
163 return uno::Any(uno::Reference
<word::XContentControl
>(
164 new SwVbaContentControl(mxParent
, mxContext
, mxTextDocument
, m_pCache
)));
168 uno::Sequence
<OUString
> SAL_CALL
getElementNames() override
170 sal_Int32 nCount
= SAL_MAX_INT32
;
171 uno::Sequence
<OUString
> aSeq
;
172 lcl_getContentControl(u
"", m_sTag
, m_sTitle
, nCount
, mxTextDocument
, &aSeq
);
176 uno::Any SAL_CALL
getByName(const OUString
& aName
) override
178 if (!hasByName(aName
))
179 throw container::NoSuchElementException();
181 return uno::Any(uno::Reference
<word::XContentControl
>(
182 new SwVbaContentControl(mxParent
, mxContext
, mxTextDocument
, m_pCache
)));
185 sal_Bool SAL_CALL
hasByName(const OUString
& aName
) override
187 sal_Int32 nCount
= -1;
188 m_pCache
= lcl_getContentControl(aName
, m_sTag
, m_sTitle
, nCount
, mxTextDocument
);
189 return m_pCache
!= nullptr;
193 uno::Type SAL_CALL
getElementType() override
195 return cppu::UnoType
<word::XContentControl
>::get();
198 sal_Bool SAL_CALL
hasElements() override
{ return getCount() != 0; }
200 // XEnumerationAccess
201 uno::Reference
<container::XEnumeration
> SAL_CALL
createEnumeration() override
203 return new ContentControlsEnumWrapper(this);
209 * Content Controls can be accessed and filtered in many different ways.
210 * Surprisingly however, there is no clear, descriptive "by name" access.
211 * Instead, each content control (probably) has a unique _signed-integer_ identifier,
212 * which can be passed to Item() as a float or _unsigned-integer_ string
213 * (to differentiate it from getByIndex).
215 * Index access can be filtered by Tag, Title, Range, and XML link.
216 * TODO: add filtering for Range, SelectLinkedControls, SelectUnlinkedControls
218 SwVbaContentControls::SwVbaContentControls(const uno::Reference
<XHelperInterface
>& xParent
,
219 const uno::Reference
<uno::XComponentContext
>& xContext
,
220 const uno::Reference
<text::XTextDocument
>& xTextDocument
,
221 const OUString
& rTag
, const OUString
& rTitle
)
222 : SwVbaContentControls_BASE(
224 uno::Reference
<container::XIndexAccess
>(
225 new ContentControlCollectionHelper(xParent
, xContext
, xTextDocument
, rTag
, rTitle
)))
229 // uno::Reference<ooo::vba::word::XContentControl> SwVbaContentControls::Add(const uno::Any& Range,
232 // sw::mark::IFieldmark* pFieldmark = nullptr;
235 // case ooo::vba::word::WdFieldType::wdFieldFormCheckBox:
237 // case ooo::vba::word::WdFieldType::wdFieldFormDropDown:
239 // case ooo::vba::word::WdFieldType::wdFieldFormTextInput:
243 // return uno::Reference<ooo::vba::word::XContentControl>(
244 // new SwVbaContentControl(mxParent, mxContext, m_xTextDocument, pFieldmark));
247 // XEnumerationAccess
248 uno::Type
SwVbaContentControls::getElementType()
250 return cppu::UnoType
<word::XContentControl
>::get();
253 uno::Reference
<container::XEnumeration
> SwVbaContentControls::createEnumeration()
255 return new ContentControlsEnumWrapper(m_xIndexAccess
);
258 uno::Any
SwVbaContentControls::createCollectionObject(const uno::Any
& aSource
) { return aSource
; }
260 OUString
SwVbaContentControls::getServiceImplName() { return "SwVbaContentControls"; }
262 uno::Sequence
<OUString
> SwVbaContentControls::getServiceNames()
264 static uno::Sequence
<OUString
> const sNames
{ "ooo.vba.word.ContentControls" };
268 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */