diff options
author | Justin Luth <justin.luth@collabora.com> | 2022-11-03 17:59:14 -0400 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.com> | 2022-11-15 11:07:06 +0100 |
commit | b8fa94b28a2fbf75edc0d31fbf776d40a227e794 (patch) | |
tree | 82298b4d48c17251242faa4f09a143f7fe3a3320 /sw | |
parent | 55c2e9e7e24a4bc2016fc54a5ffaf22aa094eb58 (diff) |
tdf#151548 vba FormFields: Add basic word::XDropDown support
make CppunitTest_sw_macros_test CPPUNIT_TEST_NAME=testVba
This now allows MS Word Basic legacy list box form fields
to be controlled by VBA basic.
-allows getting and setting the text string/list entry
-allows adding and deleting list entries
Change-Id: Ia772c62395c40a6aa0afae2549f15f4ea3304dbf
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/142396
Reviewed-by: Justin Luth <jluth@mail.com>
Tested-by: Jenkins
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Diffstat (limited to 'sw')
-rw-r--r-- | sw/Library_vbaswobj.mk | 3 | ||||
-rw-r--r-- | sw/inc/IMark.hxx | 19 | ||||
-rw-r--r-- | sw/qa/core/data/docm/testVBA.docm | bin | 30732 -> 32952 bytes | |||
-rw-r--r-- | sw/source/core/crsr/bookmark.cxx | 177 | ||||
-rw-r--r-- | sw/source/core/inc/bookmark.hxx | 9 | ||||
-rw-r--r-- | sw/source/ui/vba/vbaformfield.cxx | 6 | ||||
-rw-r--r-- | sw/source/ui/vba/vbaformfielddropdown.cxx | 101 | ||||
-rw-r--r-- | sw/source/ui/vba/vbaformfielddropdown.hxx | 52 | ||||
-rw-r--r-- | sw/source/ui/vba/vbaformfielddropdownlistentries.cxx | 171 | ||||
-rw-r--r-- | sw/source/ui/vba/vbaformfielddropdownlistentries.hxx | 49 | ||||
-rw-r--r-- | sw/source/ui/vba/vbaformfielddropdownlistentry.cxx | 56 | ||||
-rw-r--r-- | sw/source/ui/vba/vbaformfielddropdownlistentry.hxx | 48 |
12 files changed, 687 insertions, 4 deletions
diff --git a/sw/Library_vbaswobj.mk b/sw/Library_vbaswobj.mk index 5785f11f14cf..1b0ca044d565 100644 --- a/sw/Library_vbaswobj.mk +++ b/sw/Library_vbaswobj.mk @@ -75,6 +75,9 @@ $(eval $(call gb_Library_add_exception_objects,vbaswobj,\ sw/source/ui/vba/vbaformfield \ sw/source/ui/vba/vbaformfields \ sw/source/ui/vba/vbaformfieldcheckbox \ + sw/source/ui/vba/vbaformfielddropdown \ + sw/source/ui/vba/vbaformfielddropdownlistentries \ + sw/source/ui/vba/vbaformfielddropdownlistentry \ sw/source/ui/vba/vbaformfieldtextinput \ sw/source/ui/vba/vbaframe \ sw/source/ui/vba/vbaframes \ diff --git a/sw/inc/IMark.hxx b/sw/inc/IMark.hxx index 776d35c2f4e3..c256c2ef997c 100644 --- a/sw/inc/IMark.hxx +++ b/sw/inc/IMark.hxx @@ -125,6 +125,25 @@ namespace sw::mark ICheckboxFieldmark &operator =(ICheckboxFieldmark const&) = delete; }; + class SW_DLLPUBLIC IDropdownFieldmark + : virtual public IFieldmark + { + protected: + IDropdownFieldmark() = default; + + public: + virtual OUString GetContent(sal_Int32* pIndex) const = 0; + virtual OUString GetContent() const override = 0; + virtual void AddContent(const OUString& rText, sal_Int32* pIndex = nullptr) = 0; + virtual void DelContent(sal_Int32 nDelIndex = -1) = 0; + virtual void ReplaceContent(const OUString* pText, sal_Int32* pIndex) = 0; + virtual void ReplaceContent(const OUString& sNewContent) override = 0; + + private: + IDropdownFieldmark(IDropdownFieldmark const &) = delete; + IDropdownFieldmark &operator =(IDropdownFieldmark const&) = delete; + }; + class SW_DLLPUBLIC IDateFieldmark : virtual public IFieldmark { diff --git a/sw/qa/core/data/docm/testVBA.docm b/sw/qa/core/data/docm/testVBA.docm Binary files differindex 9abcd091638d..839c8dd9f73c 100644 --- a/sw/qa/core/data/docm/testVBA.docm +++ b/sw/qa/core/data/docm/testVBA.docm diff --git a/sw/source/core/crsr/bookmark.cxx b/sw/source/core/crsr/bookmark.cxx index da13b5165849..a05e4024db9c 100644 --- a/sw/source/core/crsr/bookmark.cxx +++ b/sw/source/core/crsr/bookmark.cxx @@ -34,6 +34,7 @@ #include <xmloff/odffields.hxx> #include <libxml/xmlwriter.h> #include <comphelper/random.hxx> +#include <comphelper/sequence.hxx> #include <comphelper/anytostring.hxx> #include <sal/log.hxx> #include <svl/numformat.hxx> @@ -749,6 +750,182 @@ namespace sw::mark FieldmarkWithDropDownButton::RemoveButton(); } + /** GetContent + * @param pIndex The zero-based index to retrieve + * [in] if pIndex is null or negative, return the listbox's chosen result, + * else return the indicated entry (or last entry for invalid choice). + * [out] the index of the returned result or -1 if error + */ + OUString DropDownFieldmark::GetContent(sal_Int32* pIndex) const + { + sal_Int32 nIndex = pIndex ? *pIndex : -1; + auto rParameters = *GetParameters(); + if (nIndex < 0) + rParameters[ODF_FORMDROPDOWN_RESULT] >>= nIndex; + + uno::Sequence<OUString> aSeq; + rParameters[ODF_FORMDROPDOWN_LISTENTRY] >>= aSeq; + nIndex = std::min(nIndex, aSeq.getLength() - 1); + + if (nIndex < 0) + { + if (pIndex) + *pIndex = -1; + return OUString(); + } + + if (pIndex) + *pIndex = nIndex; + + return aSeq[nIndex]; + } + + OUString DropDownFieldmark::GetContent() const + { + return GetContent(nullptr); + } + + /** AddContent : INSERTS a new choice + * @param rText: The choice to add to the list choices. + * + * @param pIndex [optional] + * [in] If pIndex is null or invalid, append to the end of the list. + * [out] Modified to point to the position of the choice if it already exists. + */ + void DropDownFieldmark::AddContent(const OUString& rText, sal_Int32* pIndex) + { + uno::Sequence<OUString> aSeq; + sw::mark::IFieldmark::parameter_map_t* pParameters = GetParameters(); + (*pParameters)[ODF_FORMDROPDOWN_LISTENTRY] >>= aSeq; + + // no duplicates: if it already exists, modify the given index to point to it + const sal_Int32 nCurrentTextPos = comphelper::findValue(aSeq, rText); + if (nCurrentTextPos != -1) + { + if (pIndex) + *pIndex = nCurrentTextPos; + return; + } + + const sal_Int32 nLen = aSeq.getLength(); + const sal_Int32 nNewPos = pIndex && *pIndex > -1 ? std::min(*pIndex, nLen) : nLen; + + // need to shift list result index up if adding new entry before it + sal_Int32 nResultIndex = -1; + (*pParameters)[ODF_FORMDROPDOWN_RESULT] >>= nResultIndex; + if (nNewPos <= nResultIndex) + (*pParameters)[ODF_FORMDROPDOWN_RESULT] <<= nResultIndex + 1; + + auto aList = comphelper::sequenceToContainer<std::vector<OUString>>(aSeq); + if (nNewPos < nLen) + aList.insert(aList.begin() + nNewPos, rText); + else + { + *pIndex = nLen; + aList.push_back(rText); + } + + (*pParameters)[ODF_FORMDROPDOWN_LISTENTRY] <<= comphelper::containerToSequence(aList); + Invalidate(); + } + + /** + * ReplaceContent : changes the list result index or renames the existing choices + * @param pText + * [in] If pIndex is null, change the list result index to this provided choice + * (but do nothing if pText is an invalid choice) + * else rename that entry. + * + * @param pIndex + * [in] If pText is null, change the list result index to this provided Index + * (or the last position if it is an invalid choice) + * else rename this entry (doing nothing for invalid indexes). + * [out] If pIndex is invalid, it is modified to use the last position. + * + * This function allows duplicate entries - which is also allowed in MS Word. + */ + void DropDownFieldmark::ReplaceContent(const OUString* pText, sal_Int32* pIndex) + { + if (!pIndex && !pText) + return; + + uno::Sequence<OUString> aSeq; + sw::mark::IFieldmark::parameter_map_t* pParameters = GetParameters(); + (*pParameters)[ODF_FORMDROPDOWN_LISTENTRY] >>= aSeq; + const sal_Int32 nLen = aSeq.getLength(); + + if (!pText) + { + if (*pIndex < 0 || *pIndex >= nLen) + *pIndex = nLen - 1; + + // select pIndex as the new value for the list box + (*pParameters)[ODF_FORMDROPDOWN_RESULT] <<= *pIndex; + Invalidate(); + return; + } + + if (!pIndex) + { + const sal_Int32 nNewPos = comphelper::findValue(aSeq, *pText); + if (nNewPos != -1) + { + (*pParameters)[ODF_FORMDROPDOWN_RESULT] <<= nNewPos; + Invalidate(); + } + return; + } + + if (*pIndex > -1 && *pIndex < nLen) + { + auto aList = comphelper::sequenceToContainer<std::vector<OUString>>(aSeq); + aList[*pIndex] = *pText; + (*pParameters)[ODF_FORMDROPDOWN_LISTENTRY] <<= comphelper::containerToSequence(aList); + Invalidate(); + } + } + + void DropDownFieldmark::ReplaceContent(const OUString& rNewContent) + { + ReplaceContent(&rNewContent, nullptr); + } + + /** + * Remove everything if the given index is negative, else remove the given index (if valid). + * If deleting the currently selected choice, reset the selection to the first choice. + */ + void DropDownFieldmark::DelContent(sal_Int32 nDelIndex) + { + sw::mark::IFieldmark::parameter_map_t* pParameters = GetParameters(); + uno::Sequence<OUString> aSeq; + if (nDelIndex < 0) + { + pParameters->erase(ODF_FORMDROPDOWN_RESULT); + (*pParameters)[ODF_FORMDROPDOWN_LISTENTRY] <<= aSeq; + Invalidate(); + return; + } + + (*pParameters)[ODF_FORMDROPDOWN_LISTENTRY] >>= aSeq; + if (nDelIndex >= aSeq.getLength()) + return; + + // If deleting the current choice, select the first entry instead + // else need to shift list result index down if deleting an entry before it + sal_Int32 nResultIndex = -1; + (*pParameters)[ODF_FORMDROPDOWN_RESULT] >>= nResultIndex; + if (nDelIndex == nResultIndex) + nResultIndex = 0; + else if (nDelIndex < nResultIndex) + --nResultIndex; + + comphelper::removeElementAt(aSeq, nDelIndex); + if (nResultIndex != -1) + (*pParameters)[ODF_FORMDROPDOWN_RESULT] <<= nResultIndex; + (*pParameters)[ODF_FORMDROPDOWN_LISTENTRY] <<= aSeq; + Invalidate(); + } + void DropDownFieldmark::SetPortionPaintArea(const SwRect& rPortionPaintArea) { m_aPortionPaintArea = rPortionPaintArea; diff --git a/sw/source/core/inc/bookmark.hxx b/sw/source/core/inc/bookmark.hxx index 14c176c96a36..075564d1b386 100644 --- a/sw/source/core/inc/bookmark.hxx +++ b/sw/source/core/inc/bookmark.hxx @@ -290,7 +290,8 @@ namespace sw::mark { /// Fieldmark representing a drop-down form field. class DropDownFieldmark final - : public FieldmarkWithDropDownButton + : virtual public IDropdownFieldmark + , public FieldmarkWithDropDownButton { public: DropDownFieldmark(const SwPaM& rPaM, const OUString& rName); @@ -298,6 +299,12 @@ namespace sw::mark { virtual void ShowButton(SwEditWin* pEditWin) override; virtual void RemoveButton() override; + OUString GetContent(sal_Int32* pIndex) const override; + OUString GetContent() const override; + void AddContent(const OUString& rText, sal_Int32* pIndex = nullptr) override; + void DelContent(sal_Int32 nDelIndex = -1) override; + void ReplaceContent(const OUString* pText, sal_Int32* pIndex) override; + void ReplaceContent(const OUString& sNewContent) override; // This method should be called only by the portion so we can now the portion's painting area void SetPortionPaintArea(const SwRect& rPortionPaintArea); diff --git a/sw/source/ui/vba/vbaformfield.cxx b/sw/source/ui/vba/vbaformfield.cxx index dd43e47b84bf..f79c92913f29 100644 --- a/sw/source/ui/vba/vbaformfield.cxx +++ b/sw/source/ui/vba/vbaformfield.cxx @@ -26,6 +26,7 @@ #include "vbaformfield.hxx" #include "vbaformfieldcheckbox.hxx" +#include "vbaformfielddropdown.hxx" #include "vbaformfieldtextinput.hxx" #include "wordvbahelper.hxx" @@ -61,9 +62,8 @@ uno::Any SAL_CALL SwVbaFormField::CheckBox() uno::Any SAL_CALL SwVbaFormField::DropDown() { - // return uno::Any(uno::Reference<word::XDropDown>( - // new SwVbaFormFieldDropDown(mxParent, mxContext, m_rFormField))); - return uno::Any(); + return uno::Any(uno::Reference<word::XDropDown>( + new SwVbaFormFieldDropDown(mxParent, mxContext, m_rFormField))); } uno::Any SAL_CALL SwVbaFormField::TextInput() diff --git a/sw/source/ui/vba/vbaformfielddropdown.cxx b/sw/source/ui/vba/vbaformfielddropdown.cxx new file mode 100644 index 000000000000..a1c3254d766b --- /dev/null +++ b/sw/source/ui/vba/vbaformfielddropdown.cxx @@ -0,0 +1,101 @@ +/* -*- 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 <ooo/vba/word/WdTextFormFieldType.hpp> + +#include "vbaformfielddropdown.hxx" +#include "vbaformfielddropdownlistentries.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +/** + * Official documentation found at https://learn.microsoft.com/en-us/office/vba/api/word.dropdown + * + * DropDown formfields are inline text objects that are only found in MS Word. + * They cannot be created in Excel or in Calc. + * + * Note that VBA might call this a DropDown, but it might not actually be one, + * so make good use of getValid() + */ +SwVbaFormFieldDropDown::SwVbaFormFieldDropDown( + const uno::Reference<ooo::vba::XHelperInterface>& rParent, + const uno::Reference<uno::XComponentContext>& rContext, ::sw::mark::IFieldmark& rFormField) + : SwVbaFormFieldDropDown_BASE(rParent, rContext) + , m_pDropDown(dynamic_cast<sw::mark::IDropdownFieldmark*>(&rFormField)) +{ +} + +SwVbaFormFieldDropDown::~SwVbaFormFieldDropDown() {} + +OUString SwVbaFormFieldDropDown::getDefaultPropertyName() { return "Valid"; } + +sal_Bool SwVbaFormFieldDropDown::getValid() +{ + return m_pDropDown + && IDocumentMarkAccess::GetType(*m_pDropDown) + == IDocumentMarkAccess::MarkType::DROPDOWN_FIELDMARK; +} + +sal_Int32 SwVbaFormFieldDropDown::getDefault() { return getValue(); } + +void SwVbaFormFieldDropDown::setDefault(sal_Int32 nSet) +{ + // Hard to know what to do here, since LO doesn't have a default property for DropDowns. + // Setting this really only makes sense when macro-adding a DropDown. + // In that case, we want it to affect the actual text content. + // However, if an item has already been selected by the user, then this shouldn't do anything. + // Assuming this is only ever set when adding a DropDown seems the sanest approach. + setValue(nSet); +} + +sal_Int32 SwVbaFormFieldDropDown::getValue() +{ + sal_Int32 nRet = 0; + if (!getValid()) + return nRet; + + --nRet; // send -1, which requests being changed to the selected DropDown's zero-based index + m_pDropDown->GetContent(&nRet); + return nRet + 1; +} + +void SwVbaFormFieldDropDown::setValue(sal_Int32 nIndex) +{ + if (!getValid() || nIndex == getValue()) + return; + + // switch to zero-based index for implementation + --nIndex; + m_pDropDown->ReplaceContent(/*pText=*/nullptr, &nIndex); +} + +uno::Any SwVbaFormFieldDropDown::ListEntries(const uno::Any& rIndex) +{ + if (!getValid()) + return uno::Any(); + + uno::Reference<XCollection> xCol( + new SwVbaFormFieldDropDownListEntries(this, mxContext, *m_pDropDown)); + + if (rIndex.hasValue()) + return xCol->Item(rIndex, uno::Any()); + + return uno::Any(xCol); +} + +OUString SwVbaFormFieldDropDown::getServiceImplName() { return "SwVbaFormFieldDropDown"; } + +uno::Sequence<OUString> SwVbaFormFieldDropDown::getServiceNames() +{ + static uno::Sequence<OUString> const aServiceNames{ "ooo.vba.word.DropDown" }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaformfielddropdown.hxx b/sw/source/ui/vba/vbaformfielddropdown.hxx new file mode 100644 index 000000000000..e92caa2f8e8c --- /dev/null +++ b/sw/source/ui/vba/vbaformfielddropdown.hxx @@ -0,0 +1,52 @@ +/* -*- 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/. + */ +#pragma once + +#include <ooo/vba/word/XDropDown.hpp> + +#include <vbahelper/vbahelperinterface.hxx> + +#include <IDocumentMarkAccess.hxx> + +typedef InheritedHelperInterfaceWeakImpl<ooo::vba::word::XDropDown> SwVbaFormFieldDropDown_BASE; + +class SwVbaFormFieldDropDown : public SwVbaFormFieldDropDown_BASE +{ +private: + sw::mark::IDropdownFieldmark* m_pDropDown; + +public: + /// @throws css::uno::RuntimeException + SwVbaFormFieldDropDown(const css::uno::Reference<ooo::vba::XHelperInterface>& rParent, + const css::uno::Reference<css::uno::XComponentContext>& rContext, + sw::mark::IFieldmark& rFormField); + ~SwVbaFormFieldDropDown() override; + + // XDropDown + OUString SAL_CALL getDefaultPropertyName() override; + + // Default member: True if the specified form field object is a valid listbox field + sal_Bool SAL_CALL getValid() override; + + // Returns and sets the index for the default listbox entry + sal_Int32 SAL_CALL getDefault() override; + void SAL_CALL setDefault(sal_Int32 nSet) override; + // Returns and sets the index of the selected listbox entry + sal_Int32 SAL_CALL getValue() override; + void SAL_CALL setValue(sal_Int32 nIndex) override; + + // Returns a ListEntries collection that represents all the available entries + css::uno::Any SAL_CALL ListEntries(const css::uno::Any& rIndex) override; + + // XHelperInterface + OUString getServiceImplName() override; + css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaformfielddropdownlistentries.cxx b/sw/source/ui/vba/vbaformfielddropdownlistentries.cxx new file mode 100644 index 000000000000..926ebeaa9656 --- /dev/null +++ b/sw/source/ui/vba/vbaformfielddropdownlistentries.cxx @@ -0,0 +1,171 @@ +/* -*- 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 <xmloff/odffields.hxx> + +#include "vbaformfielddropdownlistentries.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +static uno::Sequence<OUString> lcl_getListEntries(sw::mark::IDropdownFieldmark& rDropDown) +{ + uno::Sequence<OUString> aSeq; + (*rDropDown.GetParameters())[ODF_FORMDROPDOWN_LISTENTRY] >>= aSeq; + return aSeq; +} + +namespace +{ +class ListEntriesEnumWrapper : public EnumerationHelper_BASE +{ + uno::Reference<container::XIndexAccess> mxIndexAccess; + sal_Int32 nIndex; + +public: + explicit ListEntriesEnumWrapper(uno::Reference<container::XIndexAccess> xIndexAccess) + : mxIndexAccess(xIndexAccess) + , nIndex(0) + { + } + + virtual sal_Bool SAL_CALL hasMoreElements() override + { + return (nIndex < mxIndexAccess->getCount()); + } + + virtual uno::Any SAL_CALL nextElement() override + { + if (nIndex < mxIndexAccess->getCount()) + { + return mxIndexAccess->getByIndex(nIndex++); + } + throw container::NoSuchElementException(); + } +}; + +class ListEntryCollectionHelper + : public ::cppu::WeakImplHelper<container::XIndexAccess, container::XEnumerationAccess> +{ +private: + uno::Reference<XHelperInterface> mxParent; + uno::Reference<uno::XComponentContext> mxContext; + sw::mark::IDropdownFieldmark& m_rDropDown; + +public: + /// @throws css::uno::RuntimeException + ListEntryCollectionHelper(uno::Reference<ov::XHelperInterface> xParent, + uno::Reference<uno::XComponentContext> xContext, + sw::mark::IDropdownFieldmark& rFormField) + : mxParent(xParent) + , mxContext(xContext) + , m_rDropDown(rFormField) + { + } + + virtual sal_Int32 SAL_CALL getCount() override + { + return lcl_getListEntries(m_rDropDown).getLength(); + } + + virtual uno::Any SAL_CALL getByIndex(sal_Int32 Index) override + { + if (Index < 0 || Index >= getCount()) + throw lang::IndexOutOfBoundsException(); + + return uno::Any(uno::Reference<word::XListEntry>( + new SwVbaFormFieldDropDownListEntry(mxParent, mxContext, m_rDropDown, Index))); + } + + virtual uno::Type SAL_CALL getElementType() override + { + return cppu::UnoType<word::XListEntry>::get(); + } + + virtual sal_Bool SAL_CALL hasElements() override { return getCount() != 0; } + + // XEnumerationAccess + virtual uno::Reference<container::XEnumeration> SAL_CALL createEnumeration() override + { + return new ListEntriesEnumWrapper(this); + } +}; +} + +SwVbaFormFieldDropDownListEntries::SwVbaFormFieldDropDownListEntries( + const uno::Reference<XHelperInterface>& xParent, + const uno::Reference<uno::XComponentContext>& xContext, + sw::mark::IDropdownFieldmark& rFormField) + : SwVbaFormFieldDropDownListEntries_BASE( + xParent, xContext, + uno::Reference<container::XIndexAccess>( + new ListEntryCollectionHelper(xParent, xContext, rFormField))) + , m_rDropDown(rFormField) +{ +} + +// XListEntries +uno::Reference<word::XListEntry> + SAL_CALL SwVbaFormFieldDropDownListEntries::Add(const OUString& rName, const uno::Any& rIndex) +{ + sal_Int32 nZIndex = 0; + rIndex >>= nZIndex; + // rIndex is 1-based, nZIndex is 0-based. If rIndex is not given, then add as the last choice. + + // In testing with Word 2010, this gives a compile error: 'ListEntries.Add("Name", 2)' + // This compiles, but gets an unsupported runtime error: 'ListEntries.Add("Name", 2) = "Choice' + // So the only thing that actually works is to simply append: 'ListEntires.Add("Name")' + // but I'll still keep the expected implementation for the broken case. + if (!nZIndex) + nZIndex = SAL_MAX_INT32; + else + --nZIndex; + m_rDropDown.AddContent(rName + "__allowDuplicates", &nZIndex); + m_rDropDown.ReplaceContent(&rName, &nZIndex); + + return uno::Reference<word::XListEntry>( + new SwVbaFormFieldDropDownListEntry(mxParent, mxContext, m_rDropDown, nZIndex)); +} + +void SAL_CALL SwVbaFormFieldDropDownListEntries::Clear() { m_rDropDown.DelContent(); } + +sal_Int32 SwVbaFormFieldDropDownListEntries::getCount() +{ + return lcl_getListEntries(m_rDropDown).getLength(); +} + +// XEnumerationAccess +uno::Type SwVbaFormFieldDropDownListEntries::getElementType() +{ + return cppu::UnoType<word::XListEntry>::get(); +} + +uno::Reference<container::XEnumeration> SwVbaFormFieldDropDownListEntries::createEnumeration() +{ + return new ListEntriesEnumWrapper(m_xIndexAccess); +} + +// SwVbadropDownListEntries_BASE +uno::Any SwVbaFormFieldDropDownListEntries::createCollectionObject(const uno::Any& aSource) +{ + return aSource; +} + +OUString SwVbaFormFieldDropDownListEntries::getServiceImplName() +{ + return "SwVbaFormFieldDropDownListEntries"; +} + +uno::Sequence<OUString> SwVbaFormFieldDropDownListEntries::getServiceNames() +{ + static uno::Sequence<OUString> const sNames{ "ooo.vba.word.ListEntries" }; + return sNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaformfielddropdownlistentries.hxx b/sw/source/ui/vba/vbaformfielddropdownlistentries.hxx new file mode 100644 index 000000000000..ef1339127021 --- /dev/null +++ b/sw/source/ui/vba/vbaformfielddropdownlistentries.hxx @@ -0,0 +1,49 @@ +/* -*- 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/. + */ +#pragma once + +#include <ooo/vba/word/XListEntries.hpp> +#include <ooo/vba/word/XListEntry.hpp> + +#include <vbahelper/vbacollectionimpl.hxx> + +#include "vbaformfielddropdownlistentries.hxx" +#include "vbaformfielddropdownlistentry.hxx" + +typedef CollTestImplHelper<ooo::vba::word::XListEntries> SwVbaFormFieldDropDownListEntries_BASE; + +class SwVbaFormFieldDropDownListEntries : public SwVbaFormFieldDropDownListEntries_BASE +{ +private: + sw::mark::IDropdownFieldmark& m_rDropDown; + +public: + /// @throws css::uno::RuntimeException + SwVbaFormFieldDropDownListEntries( + const css::uno::Reference<ov::XHelperInterface>& xParent, + const css::uno::Reference<css::uno::XComponentContext>& xContext, + sw::mark::IDropdownFieldmark& m_rDropDown); + + // XListEntries + css::uno::Reference<ooo::vba::word::XListEntry> + SAL_CALL Add(const OUString& rName, const css::uno::Any& rIndex) override; + void SAL_CALL Clear() override; + sal_Int32 SAL_CALL getCount() override; + + // XEnumerationAccess + css::uno::Type SAL_CALL getElementType() override; + css::uno::Reference<css::container::XEnumeration> SAL_CALL createEnumeration() override; + + // SwVbaFormFieldDropDownListEntries_BASE + css::uno::Any createCollectionObject(const css::uno::Any& aSource) override; + OUString getServiceImplName() override; + css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaformfielddropdownlistentry.cxx b/sw/source/ui/vba/vbaformfielddropdownlistentry.cxx new file mode 100644 index 000000000000..dd9c94dc727e --- /dev/null +++ b/sw/source/ui/vba/vbaformfielddropdownlistentry.cxx @@ -0,0 +1,56 @@ +/* -*- 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 "vbaformfielddropdownlistentry.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +SwVbaFormFieldDropDownListEntry::SwVbaFormFieldDropDownListEntry( + const uno::Reference<ooo::vba::XHelperInterface>& rParent, + const uno::Reference<uno::XComponentContext>& rContext, + sw::mark::IDropdownFieldmark& rFormField, sal_Int32 nZIndex) + : SwVbaFormFieldDropDownListEntry_BASE(rParent, rContext) + , m_rDropDown(rFormField) + , m_nZIndex(nZIndex) +{ +} + +SwVbaFormFieldDropDownListEntry::~SwVbaFormFieldDropDownListEntry() {} + +// XListEntry +sal_Int32 SAL_CALL SwVbaFormFieldDropDownListEntry::getIndex() { return m_nZIndex + 1; } + +OUString SAL_CALL SwVbaFormFieldDropDownListEntry::getName() +{ + sal_Int32 nZIndex = m_nZIndex; + return m_rDropDown.GetContent(&nZIndex); +} + +void SAL_CALL SwVbaFormFieldDropDownListEntry::setName(const OUString& rSet) +{ + sal_Int32 nZIndex = m_nZIndex; + m_rDropDown.ReplaceContent(&rSet, &nZIndex); +} + +void SwVbaFormFieldDropDownListEntry::Delete() { m_rDropDown.DelContent(m_nZIndex); } + +// XHelperInterface +OUString SwVbaFormFieldDropDownListEntry::getServiceImplName() +{ + return "SwVbaFormFieldDropDownListEntry"; +} + +uno::Sequence<OUString> SwVbaFormFieldDropDownListEntry::getServiceNames() +{ + static uno::Sequence<OUString> const aServiceNames{ "ooo.vba.word.ListEntry" }; + return aServiceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/ui/vba/vbaformfielddropdownlistentry.hxx b/sw/source/ui/vba/vbaformfielddropdownlistentry.hxx new file mode 100644 index 000000000000..bfdd4cf2d6db --- /dev/null +++ b/sw/source/ui/vba/vbaformfielddropdownlistentry.hxx @@ -0,0 +1,48 @@ +/* -*- 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/. + */ +#pragma once + +#include <ooo/vba/word/XListEntry.hpp> + +#include <vbahelper/vbahelperinterface.hxx> + +#include <IDocumentMarkAccess.hxx> + +typedef InheritedHelperInterfaceWeakImpl<ooo::vba::word::XListEntry> + SwVbaFormFieldDropDownListEntry_BASE; + +class SwVbaFormFieldDropDownListEntry : public SwVbaFormFieldDropDownListEntry_BASE +{ +private: + sw::mark::IDropdownFieldmark& m_rDropDown; + // All LO and internal functions are 0-based. Convert to 1-based when sending to VBA + const sal_Int32 m_nZIndex; + +public: + /// @throws css::uno::RuntimeException + SwVbaFormFieldDropDownListEntry( + const css::uno::Reference<ooo::vba::XHelperInterface>& rParent, + const css::uno::Reference<css::uno::XComponentContext>& rContext, + sw::mark::IDropdownFieldmark& rFormField, sal_Int32 nZIndex); + ~SwVbaFormFieldDropDownListEntry() override; + + // XListEntry + sal_Int32 SAL_CALL getIndex() override; + + OUString SAL_CALL getName() override; + void SAL_CALL setName(const OUString& sSet) override; + + void SAL_CALL Delete() override; + + // XHelperInterface + OUString getServiceImplName() override; + css::uno::Sequence<OUString> getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |