From b8fa94b28a2fbf75edc0d31fbf776d40a227e794 Mon Sep 17 00:00:00 2001 From: Justin Luth Date: Thu, 3 Nov 2022 17:59:14 -0400 Subject: [PATCH] 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 Tested-by: Jenkins Reviewed-by: Miklos Vajna --- oovbaapi/UnoApi_oovbaapi.mk | 3 + oovbaapi/ooo/vba/word/XDropDown.idl | 31 +++ oovbaapi/ooo/vba/word/XListEntries.idl | 25 +++ oovbaapi/ooo/vba/word/XListEntry.idl | 27 +++ sw/Library_vbaswobj.mk | 3 + sw/inc/IMark.hxx | 19 ++ sw/qa/core/data/docm/testVBA.docm | Bin 30732 -> 32952 bytes sw/source/core/crsr/bookmark.cxx | 177 ++++++++++++++++++ sw/source/core/inc/bookmark.hxx | 9 +- sw/source/ui/vba/vbaformfield.cxx | 6 +- sw/source/ui/vba/vbaformfielddropdown.cxx | 101 ++++++++++ sw/source/ui/vba/vbaformfielddropdown.hxx | 52 +++++ .../vba/vbaformfielddropdownlistentries.cxx | 171 +++++++++++++++++ .../vba/vbaformfielddropdownlistentries.hxx | 49 +++++ .../ui/vba/vbaformfielddropdownlistentry.cxx | 56 ++++++ .../ui/vba/vbaformfielddropdownlistentry.hxx | 48 +++++ 16 files changed, 773 insertions(+), 4 deletions(-) create mode 100644 oovbaapi/ooo/vba/word/XDropDown.idl create mode 100644 oovbaapi/ooo/vba/word/XListEntries.idl create mode 100644 oovbaapi/ooo/vba/word/XListEntry.idl create mode 100644 sw/source/ui/vba/vbaformfielddropdown.cxx create mode 100644 sw/source/ui/vba/vbaformfielddropdown.hxx create mode 100644 sw/source/ui/vba/vbaformfielddropdownlistentries.cxx create mode 100644 sw/source/ui/vba/vbaformfielddropdownlistentries.hxx create mode 100644 sw/source/ui/vba/vbaformfielddropdownlistentry.cxx create mode 100644 sw/source/ui/vba/vbaformfielddropdownlistentry.hxx 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 9abcd091638d2b03ab79b60cccaadd96ef639d12..839c8dd9f73cb7bc84370d69b05ce0fe23f88a50 100644 GIT binary patch delta 15823 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 Tf06`wBp-N^LA7}QPw4*z9~h}8 delta 13566 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 Y1OWaA@c*lK(H0c%PY#Xf_}`xY1BkjE0{{R3 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 #include #include +#include #include #include #include @@ -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 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 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>(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 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>(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 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( - // new SwVbaFormFieldDropDown(mxParent, mxContext, m_rFormField))); - return uno::Any(); + return uno::Any(uno::Reference( + 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 + +#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& rParent, + const uno::Reference& rContext, ::sw::mark::IFieldmark& rFormField) + : SwVbaFormFieldDropDown_BASE(rParent, rContext) + , m_pDropDown(dynamic_cast(&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 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 SwVbaFormFieldDropDown::getServiceNames() +{ + static uno::Sequence 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 + +#include + +#include + +typedef InheritedHelperInterfaceWeakImpl SwVbaFormFieldDropDown_BASE; + +class SwVbaFormFieldDropDown : public SwVbaFormFieldDropDown_BASE +{ +private: + sw::mark::IDropdownFieldmark* m_pDropDown; + +public: + /// @throws css::uno::RuntimeException + SwVbaFormFieldDropDown(const css::uno::Reference& rParent, + const css::uno::Reference& 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 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 + +#include "vbaformfielddropdownlistentries.hxx" + +using namespace ::ooo::vba; +using namespace ::com::sun::star; + +static uno::Sequence lcl_getListEntries(sw::mark::IDropdownFieldmark& rDropDown) +{ + uno::Sequence aSeq; + (*rDropDown.GetParameters())[ODF_FORMDROPDOWN_LISTENTRY] >>= aSeq; + return aSeq; +} + +namespace +{ +class ListEntriesEnumWrapper : public EnumerationHelper_BASE +{ + uno::Reference mxIndexAccess; + sal_Int32 nIndex; + +public: + explicit ListEntriesEnumWrapper(uno::Reference 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 +{ +private: + uno::Reference mxParent; + uno::Reference mxContext; + sw::mark::IDropdownFieldmark& m_rDropDown; + +public: + /// @throws css::uno::RuntimeException + ListEntryCollectionHelper(uno::Reference xParent, + uno::Reference 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( + new SwVbaFormFieldDropDownListEntry(mxParent, mxContext, m_rDropDown, Index))); + } + + virtual uno::Type SAL_CALL getElementType() override + { + return cppu::UnoType::get(); + } + + virtual sal_Bool SAL_CALL hasElements() override { return getCount() != 0; } + + // XEnumerationAccess + virtual uno::Reference SAL_CALL createEnumeration() override + { + return new ListEntriesEnumWrapper(this); + } +}; +} + +SwVbaFormFieldDropDownListEntries::SwVbaFormFieldDropDownListEntries( + const uno::Reference& xParent, + const uno::Reference& xContext, + sw::mark::IDropdownFieldmark& rFormField) + : SwVbaFormFieldDropDownListEntries_BASE( + xParent, xContext, + uno::Reference( + new ListEntryCollectionHelper(xParent, xContext, rFormField))) + , m_rDropDown(rFormField) +{ +} + +// XListEntries +uno::Reference + 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( + 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::get(); +} + +uno::Reference 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 SwVbaFormFieldDropDownListEntries::getServiceNames() +{ + static uno::Sequence 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 +#include + +#include + +#include "vbaformfielddropdownlistentries.hxx" +#include "vbaformfielddropdownlistentry.hxx" + +typedef CollTestImplHelper SwVbaFormFieldDropDownListEntries_BASE; + +class SwVbaFormFieldDropDownListEntries : public SwVbaFormFieldDropDownListEntries_BASE +{ +private: + sw::mark::IDropdownFieldmark& m_rDropDown; + +public: + /// @throws css::uno::RuntimeException + SwVbaFormFieldDropDownListEntries( + const css::uno::Reference& xParent, + const css::uno::Reference& xContext, + sw::mark::IDropdownFieldmark& m_rDropDown); + + // XListEntries + css::uno::Reference + 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 SAL_CALL createEnumeration() override; + + // SwVbaFormFieldDropDownListEntries_BASE + css::uno::Any createCollectionObject(const css::uno::Any& aSource) override; + OUString getServiceImplName() override; + css::uno::Sequence 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& rParent, + const uno::Reference& 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 SwVbaFormFieldDropDownListEntry::getServiceNames() +{ + static uno::Sequence 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 + +#include + +#include + +typedef InheritedHelperInterfaceWeakImpl + 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& rParent, + const css::uno::Reference& 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 getServiceNames() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */