summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustin Luth <justin.luth@collabora.com>2022-11-03 17:59:14 -0400
committerMiklos Vajna <vmiklos@collabora.com>2022-11-15 11:07:06 +0100
commitb8fa94b28a2fbf75edc0d31fbf776d40a227e794 (patch)
tree82298b4d48c17251242faa4f09a143f7fe3a3320
parentAllow using bin/list-dispatch-commands.py with separate builddir (diff)
downloadcore-b8fa94b28a2fbf75edc0d31fbf776d40a227e794.tar.gz
core-b8fa94b28a2fbf75edc0d31fbf776d40a227e794.zip
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>
-rw-r--r--oovbaapi/UnoApi_oovbaapi.mk3
-rw-r--r--oovbaapi/ooo/vba/word/XDropDown.idl31
-rw-r--r--oovbaapi/ooo/vba/word/XListEntries.idl25
-rw-r--r--oovbaapi/ooo/vba/word/XListEntry.idl27
-rw-r--r--sw/Library_vbaswobj.mk3
-rw-r--r--sw/inc/IMark.hxx19
-rw-r--r--sw/qa/core/data/docm/testVBA.docmbin30732 -> 32952 bytes
-rw-r--r--sw/source/core/crsr/bookmark.cxx177
-rw-r--r--sw/source/core/inc/bookmark.hxx9
-rw-r--r--sw/source/ui/vba/vbaformfield.cxx6
-rw-r--r--sw/source/ui/vba/vbaformfielddropdown.cxx101
-rw-r--r--sw/source/ui/vba/vbaformfielddropdown.hxx52
-rw-r--r--sw/source/ui/vba/vbaformfielddropdownlistentries.cxx171
-rw-r--r--sw/source/ui/vba/vbaformfielddropdownlistentries.hxx49
-rw-r--r--sw/source/ui/vba/vbaformfielddropdownlistentry.cxx56
-rw-r--r--sw/source/ui/vba/vbaformfielddropdownlistentry.hxx48
16 files changed, 773 insertions, 4 deletions
diff --git a/oovbaapi/UnoApi_oovbaapi.mk b/oovbaapi/UnoApi_oovbaapi.mk
index 6d83196dbcf6..331cf4937e32 100644
--- a/oovbaapi/UnoApi_oovbaapi.mk
+++ b/oovbaapi/UnoApi_oovbaapi.mk
@@ -1052,6 +1052,7 @@ $(eval $(call gb_UnoApi_add_idlfiles,oovbaapi,ooo/vba/word,\
XDocument \
XDocumentOutgoing \
XDocuments \
+ XDropDown \
XField \
XFields \
XFind \
@@ -1063,6 +1064,8 @@ $(eval $(call gb_UnoApi_add_idlfiles,oovbaapi,ooo/vba/word,\
XGlobals \
XHeaderFooter \
XHeadersFooters \
+ XListEntries \
+ XListEntry \
XListFormat \
XListGalleries \
XListGallery \
diff --git a/oovbaapi/ooo/vba/word/XDropDown.idl b/oovbaapi/ooo/vba/word/XDropDown.idl
new file mode 100644
index 000000000000..d22f2c3299a3
--- /dev/null
+++ b/oovbaapi/ooo/vba/word/XDropDown.idl
@@ -0,0 +1,31 @@
+/* -*- 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/.
+ */
+
+module ooo { module vba { module word {
+
+interface XDropDown
+{
+ interface ooo::vba::XHelperInterface;
+ interface com::sun::star::script::XDefaultProperty;
+
+ /// Default member: True if the specified form field object is a valid drop down form field.
+ [attribute, readonly] boolean Valid;
+
+ /// Returns or sets a number that represents the default drop-down index.
+ [attribute] long Default;
+ /// Returns or sets the index of the selected item in a drop-down form field.
+ [attribute] long Value;
+
+ /// Returns a ListEntries collection that represents all the items in a DropDown object.
+ any ListEntries( [in] any Index );
+};
+
+}; }; };
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oovbaapi/ooo/vba/word/XListEntries.idl b/oovbaapi/ooo/vba/word/XListEntries.idl
new file mode 100644
index 000000000000..5db6b7bd4eb2
--- /dev/null
+++ b/oovbaapi/ooo/vba/word/XListEntries.idl
@@ -0,0 +1,25 @@
+/* -*- 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/.
+ */
+
+module ooo { module vba { module word {
+
+interface XListEntry;
+interface XListEntries
+{
+ interface ooo::vba::XCollection;
+
+ /// Returns a ListEntry object that represents an item added to a drop-down form field.
+ XListEntry Add( [in] string Name, [in] /*optional long*/ any Index ) raises ( com::sun::star::script::BasicErrorException );
+ /// Removes all items from the drop-down form field.
+ void Clear();
+};
+
+}; }; };
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oovbaapi/ooo/vba/word/XListEntry.idl b/oovbaapi/ooo/vba/word/XListEntry.idl
new file mode 100644
index 000000000000..753538a1786f
--- /dev/null
+++ b/oovbaapi/ooo/vba/word/XListEntry.idl
@@ -0,0 +1,27 @@
+/* -*- 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/.
+ */
+
+module ooo { module vba { module word {
+
+interface XListEntry
+{
+ interface ooo::vba::XHelperInterface;
+
+ /// Returns the position of an item in a collection.
+ [attribute, readonly] long Index;
+ /// Returns or sets the name of the specified object.
+ [attribute] string Name;
+
+ /// Deletes the list entry.
+ void Delete();
+};
+
+}; }; };
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
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
index 9abcd091638d..839c8dd9f73c 100644
--- a/sw/qa/core/data/docm/testVBA.docm
+++ b/sw/qa/core/data/docm/testVBA.docm
Binary files differ
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: */