oovbaapi/ooo/vba/word/XFormField.idl  |   50 ++++++
 oovbaapi/ooo/vba/word/XFormFields.idl |    7 
 sw/Library_vbaswobj.mk                |    2 
 sw/inc/IMark.hxx                      |    8 -
 sw/source/ui/vba/vbadocument.cxx      |   10 -
 sw/source/ui/vba/vbaformfield.cxx     |  255 ++++++++++++++++++++++++++++++++++
 sw/source/ui/vba/vbaformfield.hxx     |   98 +++++++++++++
 sw/source/ui/vba/vbaformfields.cxx    |  249 +++++++++++++++++++++++++++++++++
 sw/source/ui/vba/vbaformfields.hxx    |   53 +++++++
 9 files changed, 724 insertions(+), 8 deletions(-)

New commits:
commit a76cf059f0f99b216b3c54f9b8613999b69bf804
Author:     Justin Luth <justin.l...@collabora.com>
AuthorDate: Wed Nov 9 17:02:03 2022 -0500
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Mon Nov 21 11:25:41 2022 +0100

    tdf#151548 vba FormFields: Add basic word::XFormField support
    
    Squashed commit including followups from various people.
    
    Unit tests will come in the following commits that represent
    actual FormFields that have content/results.
    
    This lays the foundation for adding
    Checkboxes, Textinputs, and Dropdowns.
    
    Change-Id: If85ae25f881198d5a0699b3350a7eb20b1735c45
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/142507
    Reviewed-by: Justin Luth <jl...@mail.com>
    Tested-by: Jenkins
    Reviewed-by: Tor Lillqvist <t...@collabora.com>
    
    private field 'm_xModel' is not used [-Werror,-Wunused-private-field]
    
    ever since
        commit 2a26f136a36791c06caa895d5a25f4633fd10651
        Author: Justin Luth <justin.l...@collabora.com>
        Date:   Wed Nov 9 17:02:03 2022 -0500
        tdf#151548 vba FormFields: Add basic word::XFormField support
    
    Plus, this code is std::move'ing a value into a "&" field, which is
    very wrong
    
    Change-Id: Ia8bbf6e0eaa524ca0f5bbf7624f4b9555920f993
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/142545
    Tested-by: Jenkins
    Reviewed-by: Justin Luth <jl...@mail.com>
    
    Fix typos
    
    Change-Id: Id924e4747d6a3d81b69da28910c8e096565b9b68
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/142538
    Tested-by: Julien Nabet <serval2...@yahoo.fr>
    Reviewed-by: Julien Nabet <serval2...@yahoo.fr>
    
    Clean up some seeming copy/paste mistakes
    
    ...all introduced with 2a26f136a36791c06caa895d5a25f4633fd10651 "tdf#151548 
vba
    FormFields: Add basic word::XFormField support":
    
    For the SwVbaFormField ctor, std::move of a const lvalue has no effect here.
    (And I just don't bother applying the move-from-pass-by-value-param 
optimization
    here.)
    
    For FormFieldCollectionHelper, consistently make the data members non-const 
(a
    const css::uno::Reference wouldn't make that much sense anyway, as it 
doesn't
    transitively apply const'ness also to the referenced object) and 
non-reference,
    and make the FormFieldCollectionHelper params non-const (and non-reference) 
to
    make the move-from-pass-by-value-param optimization actually work here.
    
    (I came across this code with an upcoming loplugin:constmove that flags
    suspicious uses of std::move involving const-qualified types.)
    
    Change-Id: Ib41d4671b33871eddff41bc20ea38de02d616046
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/142568
    Tested-by: Jenkins
    Reviewed-by: Stephan Bergmann <sberg...@redhat.com>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/142644
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Justin Luth <jl...@mail.com>

diff --git a/oovbaapi/ooo/vba/word/XFormField.idl 
b/oovbaapi/ooo/vba/word/XFormField.idl
index f8a4f411d44f..2b879fb6c652 100644
--- a/oovbaapi/ooo/vba/word/XFormField.idl
+++ b/oovbaapi/ooo/vba/word/XFormField.idl
@@ -27,12 +27,60 @@ module ooo {  module vba {  module word {
 interface XFormField
 {
     interface ooo::vba::XHelperInterface;
+    interface com::sun::star::script::XDefaultProperty;
 
+    /// Default member: returns the field type from WdFieldType
+    [attribute, readonly] long Type;
+
+    /**
+     * Returns or sets true if references to the specified form field
+     * are automatically updated whenever the field is exited.
+     */
+    [attribute] boolean CalculateOnExit;
+    /// Returns or sets a string that represents the result of the specified 
form field
     [attribute] string Result;
+    /// Returns or sets true if a form field is enabled
     [attribute] boolean Enabled;
+    /// Returns or sets the macro name that runs on keyboard (tab) navigation 
into the field
+    [attribute] string EntryMacro;
+    /// Returns or sets an exit macro name that runs on keyboard (tab) 
navigation out of the field
+    [attribute] string ExitMacro;
+    /**
+     * Returns or sets the text that's displayed in a message box
+     * when the form field has the focus and the user presses F1.
+     *
+     * When OwnHelp is False, HelpText specifies the name of an AutoText entry
+     * that contains help text for the form field
+     */
+    [attribute] string HelpText;
+    /**
+     * Returns or sets the specifies the source of the F1 text that's 
displayed in a message box
+     * If True, the text specified by the HelpText property is displayed.
+     * If False, the text in the AutoText entry specified by the HelpText 
property is displayed.
+     */
+    [attribute] boolean OwnHelp;
+    /// returns or sets the name of the specified object.
+    [attribute] string Name;
+    /// Returns or sets the text that is displayed in the status bar when a 
form field has the focus
+    [attribute] string StatusText;
+    /** OwnStatus:
+     * If True, the text specified by the StatusText property is displayed.
+     * If False, the text of the AutoText entry specified by the StatusText 
property is displayed.
+     */
+    [attribute] boolean OwnStatus;
 
     any CheckBox();
-
+    any DropDown();
+    any TextInput();
+    /// Returns the next form field in the collection.
+    any Next();
+    /// returns the previous form field in the collection.
+    any Previous();
+    /**
+     * Represents a contiguous area in a document.
+     * Each Range object is defined by a starting and ending character 
position.
+     */
+    any Range();
 };
 
 }; }; };
diff --git a/oovbaapi/ooo/vba/word/XFormFields.idl 
b/oovbaapi/ooo/vba/word/XFormFields.idl
index 42191375955e..4d266909cb77 100644
--- a/oovbaapi/ooo/vba/word/XFormFields.idl
+++ b/oovbaapi/ooo/vba/word/XFormFields.idl
@@ -28,10 +28,15 @@
 module ooo {  module vba {  module word {
 
 
-
+interface XFormField;
 interface XFormFields
 {
     interface ::ooo::vba::XCollection;
+
+    ///Returns and sets if shading is applied to form XFormFields
+    [attribute] boolean  Shaded;
+    /// Returns a FormField object that represents a new WdFieldType added at 
a range
+    //XFormField Add( [in] any Range, [in] long Type ) raises ( 
com::sun::star::script::BasicErrorException );
 };
 
 }; }; };
diff --git a/sw/Library_vbaswobj.mk b/sw/Library_vbaswobj.mk
index bcebe38b912a..a2405f755ccb 100644
--- a/sw/Library_vbaswobj.mk
+++ b/sw/Library_vbaswobj.mk
@@ -72,6 +72,8 @@ $(eval $(call gb_Library_add_exception_objects,vbaswobj,\
     sw/source/ui/vba/vbacells \
     sw/source/ui/vba/vbacolumn \
     sw/source/ui/vba/vbacolumns \
+    sw/source/ui/vba/vbaformfield \
+    sw/source/ui/vba/vbaformfields \
     sw/source/ui/vba/vbaframe \
     sw/source/ui/vba/vbaframes \
     sw/source/ui/vba/vbalistformat \
diff --git a/sw/inc/IMark.hxx b/sw/inc/IMark.hxx
index 151c9a9333fb..776d35c2f4e3 100644
--- a/sw/inc/IMark.hxx
+++ b/sw/inc/IMark.hxx
@@ -102,6 +102,10 @@ namespace sw::mark
             virtual void SetFieldname(const OUString& rFieldname) =0;
             virtual void SetFieldHelptext(const OUString& rFieldHelptext) =0;
             virtual void Invalidate() = 0;
+
+            virtual OUString GetContent() const { return OUString(); }
+            virtual void ReplaceContent(const OUString& /*sNewContent*/) {}
+
         private:
             IFieldmark(IFieldmark const &) = delete;
             IFieldmark &operator =(IFieldmark const&) = delete;
@@ -128,8 +132,8 @@ namespace sw::mark
             IDateFieldmark() = default;
 
         public:
-            virtual OUString GetContent() const = 0;
-            virtual void ReplaceContent(const OUString& sNewContent) = 0;
+            virtual OUString GetContent() const override = 0;
+            virtual void ReplaceContent(const OUString& sNewContent) override 
= 0;
 
             virtual std::pair<bool, double> GetCurrentDate() const = 0;
             virtual void SetCurrentDate(double fDate) = 0;
diff --git a/sw/source/ui/vba/vbadocument.cxx b/sw/source/ui/vba/vbadocument.cxx
index 656a2bb942e5..16e4f762abb1 100644
--- a/sw/source/ui/vba/vbadocument.cxx
+++ b/sw/source/ui/vba/vbadocument.cxx
@@ -22,6 +22,7 @@
 
 #include "vbafilterpropsfromformat.hxx"
 #include "vbadocument.hxx"
+#include "vbaformfields.hxx"
 #include "vbarange.hxx"
 #include "vbarangehelper.hxx"
 #include "vbadocumentproperties.hxx"
@@ -273,11 +274,12 @@ SwVbaDocument::TablesOfContents( const uno::Any& index )
     return uno::makeAny( xCol );
 }
 
-uno::Any SAL_CALL
-SwVbaDocument::FormFields( const uno::Any& /*index*/ )
+uno::Any SAL_CALL SwVbaDocument::FormFields(const uno::Any& index)
 {
-    uno::Reference< XCollection > xCol;
-    return uno::makeAny( xCol );
+    uno::Reference<XCollection> xCol(new SwVbaFormFields(this, mxContext, 
mxModel));
+    if (index.hasValue())
+        return xCol->Item(index, uno::Any());
+    return uno::Any(xCol);
 }
 
 uno::Any SAL_CALL
diff --git a/sw/source/ui/vba/vbaformfield.cxx 
b/sw/source/ui/vba/vbaformfield.cxx
new file mode 100644
index 000000000000..b873002a6f11
--- /dev/null
+++ b/sw/source/ui/vba/vbaformfield.cxx
@@ -0,0 +1,255 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ooo/vba/word/WdFieldType.hpp>
+
+#include <sal/log.hxx>
+
+#include <doc.hxx>
+#include <docsh.hxx>
+
+#include "vbaformfield.hxx"
+#include "wordvbahelper.hxx"
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+/**
+ * Information about the method and properties of FormFields was gathered from
+ * https://www.codevba.com/Word/FormField.htm
+ *
+ * FormFields are inline text objects that are only found in MS Word.
+ * They cannot be created in Excel or in Calc.
+ *
+ * There are three specific kinds of FormFields: CheckBox, DropDown, and 
TextInput.
+ */
+SwVbaFormField::SwVbaFormField(const 
uno::Reference<ooo::vba::XHelperInterface>& rParent,
+                               const uno::Reference<uno::XComponentContext>& 
rContext,
+                               const uno::Reference<frame::XModel>& xModel,
+                               sw::mark::IFieldmark& rFormField)
+    : SwVbaFormField_BASE(rParent, rContext)
+    , mxModel(xModel)
+    , m_rFormField(rFormField)
+{
+}
+
+SwVbaFormField::~SwVbaFormField() {}
+
+uno::Any SAL_CALL SwVbaFormField::CheckBox()
+{
+    // return uno::Any(uno::Reference<word::XCheckBox>(
+    //     new SwVbaFormFieldCheckBox(mxParent, mxContext, m_rFormField)));
+    return uno::Any();
+}
+
+uno::Any SAL_CALL SwVbaFormField::DropDown()
+{
+    // return uno::Any(uno::Reference<word::XDropDown>(
+    //     new SwVbaFormFieldDropDown(mxParent, mxContext, m_rFormField)));
+    return uno::Any();
+}
+
+uno::Any SAL_CALL SwVbaFormField::TextInput()
+{
+    // return uno::Any(uno::Reference<word::XTextInput>(
+    //     new SwVbaFormFieldTextInput(mxParent, mxContext, m_rFormField)));
+    return uno::Any();
+}
+
+uno::Any SAL_CALL SwVbaFormField::Previous()
+{
+    SwDoc* pDoc = word::getDocShell(mxModel)->GetDoc();
+    if (!pDoc)
+        return uno::Any();
+
+    const IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess();
+    if (!pMarkAccess)
+        return uno::Any();
+
+    sw::mark::IFieldmark* pFieldMark = 
pMarkAccess->getFieldmarkBefore(m_rFormField.GetMarkPos());
+
+    // DateFields are a LO specialty, and do not exist natively in MS 
documents. Ignore if added...
+    auto pDateField = dynamic_cast<sw::mark::IDateFieldmark*>(pFieldMark);
+    while (pDateField)
+    {
+        pFieldMark = pMarkAccess->getFieldmarkBefore(pDateField->GetMarkPos());
+        pDateField = dynamic_cast<sw::mark::IDateFieldmark*>(pFieldMark);
+    }
+
+    if (!pFieldMark)
+        return uno::Any();
+
+    return uno::Any(uno::Reference<word::XFormField>(
+        new SwVbaFormField(mxParent, mxContext, mxModel, *pFieldMark)));
+}
+
+uno::Any SAL_CALL SwVbaFormField::Next()
+{
+    SwDoc* pDoc = word::getDocShell(mxModel)->GetDoc();
+    if (!pDoc)
+        return uno::Any();
+
+    const IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess();
+    if (!pMarkAccess)
+        return uno::Any();
+
+    sw::mark::IFieldmark* pFieldMark = 
pMarkAccess->getFieldmarkAfter(m_rFormField.GetMarkPos());
+
+    // DateFields are a LO specialty, and do not exist natively in MS 
documents. Ignore if added...
+    auto pDateField = dynamic_cast<sw::mark::IDateFieldmark*>(pFieldMark);
+    while (pDateField)
+    {
+        pFieldMark = pMarkAccess->getFieldmarkAfter(pDateField->GetMarkPos());
+        pDateField = dynamic_cast<sw::mark::IDateFieldmark*>(pFieldMark);
+    }
+
+    if (!pFieldMark)
+        return uno::Any();
+
+    return uno::Any(uno::Reference<word::XFormField>(
+        new SwVbaFormField(mxParent, mxContext, mxModel, *pFieldMark)));
+}
+
+uno::Any SAL_CALL SwVbaFormField::Range()
+{
+    SAL_INFO("sw.vba", "SwVbaFormField::getRange stub");
+    return uno::Any();
+}
+
+OUString SwVbaFormField::getDefaultPropertyName() { return "Type"; }
+
+sal_Int32 SwVbaFormField::getType()
+{
+    IDocumentMarkAccess::MarkType aType = 
IDocumentMarkAccess::GetType(m_rFormField);
+    if (aType == IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK)
+        return ooo::vba::word::WdFieldType::wdFieldFormCheckBox;
+    else if (aType == IDocumentMarkAccess::MarkType::TEXT_FIELDMARK)
+        return ooo::vba::word::WdFieldType::wdFieldFormTextInput;
+    return ooo::vba::word::WdFieldType::wdFieldFormDropDown;
+}
+
+sal_Bool SwVbaFormField::getCalculateOnExit()
+{
+    SAL_INFO("sw.vba", "SwVbaFormField::getCalculateOnExit stub");
+    return false;
+}
+
+void SwVbaFormField::setCalculateOnExit(sal_Bool /*bSet*/)
+{
+    SAL_INFO("sw.vba", "SwVbaFormField::setCalculateOnExit stub");
+}
+
+sal_Bool SwVbaFormField::getEnabled()
+{
+    SAL_INFO("sw.vba", "SwVbaFormField::getEnabled stub");
+    return true;
+}
+
+void SwVbaFormField::setEnabled(sal_Bool /*bSet*/)
+{
+    SAL_INFO("sw.vba", "SwVbaFormField::setEnabled stub");
+}
+
+OUString SwVbaFormField::getEntryMacro()
+{
+    OUString sMacro;
+    (*m_rFormField.GetParameters())["EntryMacro"] >>= sMacro;
+    return sMacro;
+}
+
+void SwVbaFormField::setEntryMacro(const OUString& rSet)
+{
+    (*m_rFormField.GetParameters())["EntryMacro"] <<= rSet;
+}
+
+OUString SwVbaFormField::getExitMacro()
+{
+    OUString sMacro;
+    (*m_rFormField.GetParameters())["ExitMacro"] >>= sMacro;
+    return sMacro;
+}
+
+void SwVbaFormField::setExitMacro(const OUString& rSet)
+{
+    (*m_rFormField.GetParameters())["ExitMacro"] <<= rSet;
+}
+
+OUString SwVbaFormField::getHelpText() { return 
m_rFormField.GetFieldHelptext(); }
+
+void SwVbaFormField::setHelpText(const OUString& rSet) { 
m_rFormField.SetFieldHelptext(rSet); }
+
+sal_Bool SwVbaFormField::getOwnHelp()
+{
+    SAL_INFO("sw.vba", "SwVbaFormField::getOwnHelp stub");
+    return true;
+}
+
+void SwVbaFormField::setOwnHelp(sal_Bool /*bSet*/)
+{
+    SAL_INFO("sw.vba", "SwVbaFormField::setOwnHelp stub");
+}
+
+OUString SwVbaFormField::getName() { return m_rFormField.GetName(); }
+
+void SwVbaFormField::setName(const OUString& rSet)
+{
+    SAL_WARN("sw.vba", "SwVbaFormField::setName[" << rSet << "] stub");
+}
+
+OUString SwVbaFormField::getResult() { return m_rFormField.GetContent(); }
+
+void SwVbaFormField::setResult(const OUString& rSet)
+{
+    if (dynamic_cast<sw::mark::ICheckboxFieldmark*>(&m_rFormField))
+        m_rFormField.ReplaceContent("false");
+    else
+        m_rFormField.ReplaceContent(rSet);
+}
+
+OUString SwVbaFormField::getStatusText()
+{
+    SAL_INFO("sw.vba", "SwVbaFormField::getStatusText stub");
+    return OUString();
+}
+
+void SwVbaFormField::setStatusText(const OUString& rSet)
+{
+    SAL_INFO("sw.vba", "SwVbaFormField::setStatusText[" << rSet << "] stub");
+}
+
+sal_Bool SwVbaFormField::getOwnStatus()
+{
+    SAL_INFO("sw.vba", "SwVbaFormField::getOwnStatus stub");
+    return true;
+}
+
+void SwVbaFormField::setOwnStatus(sal_Bool /*bSet*/)
+{
+    SAL_INFO("sw.vba", "SwVbaFormField::setOwnStatus stub");
+}
+
+OUString SwVbaFormField::getServiceImplName() { return "SwVbaFormField"; }
+
+uno::Sequence<OUString> SwVbaFormField::getServiceNames()
+{
+    static uno::Sequence<OUString> const aServiceNames{ 
"ooo.vba.word.FormField" };
+    return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbaformfield.hxx 
b/sw/source/ui/vba/vbaformfield.hxx
new file mode 100644
index 000000000000..14f44fc3c779
--- /dev/null
+++ b/sw/source/ui/vba/vbaformfield.hxx
@@ -0,0 +1,98 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SW_SOURCE_UI_VBA_VBAFORMFIELD_HXX
+#define INCLUDED_SW_SOURCE_UI_VBA_VBAFORMFIELD_HXX
+
+#include <ooo/vba/word/XFormField.hpp>
+
+#include <vbahelper/vbahelperinterface.hxx>
+
+#include <IDocumentMarkAccess.hxx>
+
+typedef InheritedHelperInterfaceWeakImpl<ooo::vba::word::XFormField> 
SwVbaFormField_BASE;
+
+class SwVbaFormField : public SwVbaFormField_BASE
+{
+private:
+    css::uno::Reference<css::frame::XModel> mxModel;
+    sw::mark::IFieldmark& m_rFormField;
+
+public:
+    /// @throws css::uno::RuntimeException
+    SwVbaFormField(const css::uno::Reference<ooo::vba::XHelperInterface>& 
rParent,
+                   const css::uno::Reference<css::uno::XComponentContext>& 
rContext,
+                   const css::uno::Reference<css::frame::XModel>& xModel,
+                   sw::mark::IFieldmark& rFormField);
+    virtual ~SwVbaFormField() override;
+
+    // XFormField Methods
+    virtual OUString SAL_CALL getDefaultPropertyName() override;
+
+    virtual css::uno::Any SAL_CALL CheckBox() override;
+    virtual css::uno::Any SAL_CALL DropDown() override;
+    virtual css::uno::Any SAL_CALL TextInput() override;
+    virtual css::uno::Any SAL_CALL Previous() override;
+    virtual css::uno::Any SAL_CALL Next() override;
+    virtual css::uno::Any SAL_CALL Range() override;
+
+    // Indicates which of the three form fields this is: 
oovbaapi/ooo/vba/word/WdFieldType.idl
+    virtual sal_Int32 SAL_CALL getType() override;
+    // True if references to the specified form field
+    // are automatically updated whenever the field is exited
+    virtual sal_Bool SAL_CALL getCalculateOnExit() override;
+    virtual void SAL_CALL setCalculateOnExit(sal_Bool bSet) override;
+    virtual sal_Bool SAL_CALL getEnabled() override;
+    virtual void SAL_CALL setEnabled(sal_Bool bSet) override;
+    virtual OUString SAL_CALL getEntryMacro() override;
+    virtual void SAL_CALL setEntryMacro(const OUString& rSet) override;
+    virtual OUString SAL_CALL getExitMacro() override;
+    virtual void SAL_CALL setExitMacro(const OUString& rSet) override;
+    /*
+     * If the OwnHelp property is set to True,
+     * HelpText specifies the text string value.
+     * If OwnHelp is set to False, HelpText specifies the name of an AutoText 
entry
+     * that contains help text for the form field.
+     */
+    virtual OUString SAL_CALL getHelpText() override;
+    virtual void SAL_CALL setHelpText(const OUString& rSet) override;
+    virtual sal_Bool SAL_CALL getOwnHelp() override;
+    virtual void SAL_CALL setOwnHelp(sal_Bool bSet) override;
+
+    virtual OUString SAL_CALL getName() override;
+    virtual void SAL_CALL setName(const OUString& rSet) override;
+    virtual OUString SAL_CALL getResult() override;
+    virtual void SAL_CALL setResult(const OUString& rSet) override;
+    /*
+     * If the OwnStatus property is set to True,
+     * StatusText specifies the status bar value.
+     * If OwnStatus is set to False, StatusText specifies the name of an 
AutoText entry
+     * that contains status bar text for the form field.
+     */
+    virtual OUString SAL_CALL getStatusText() override;
+    virtual void SAL_CALL setStatusText(const OUString& rSet) override;
+    virtual sal_Bool SAL_CALL getOwnStatus() override;
+    virtual void SAL_CALL setOwnStatus(sal_Bool bSet) override;
+
+    // XHelperInterface
+    virtual OUString getServiceImplName() override;
+    virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAFORMFIELD_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbaformfields.cxx 
b/sw/source/ui/vba/vbaformfields.cxx
new file mode 100644
index 000000000000..d9b7b6200c1d
--- /dev/null
+++ b/sw/source/ui/vba/vbaformfields.cxx
@@ -0,0 +1,249 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <comphelper/sequence.hxx>
+#include <sal/log.hxx>
+
+#include <doc.hxx>
+#include <docsh.hxx>
+#include <IDocumentMarkAccess.hxx>
+
+#include "vbaformfield.hxx"
+#include "vbaformfields.hxx"
+#include "wordvbahelper.hxx"
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+// Helper function to access the fieldmarks
+// @param rIndex serves multiple purposes
+//        [in] -1 to indicate searching using the provided name, SAL_MAX_INT32 
for totals
+//        [out] rIndex indicates the found index, or the total number of 
fieldmarks
+static sw::mark::IFieldmark* lcl_getFieldmark(std::string_view rName, 
sal_Int32& rIndex,
+                                              const 
css::uno::Reference<frame::XModel>& xModel,
+                                              uno::Sequence<OUString>* 
pElementNames = nullptr)
+{
+    SwDoc* pDoc = word::getDocShell(xModel)->GetDoc();
+    if (!pDoc)
+        return nullptr;
+
+    IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess();
+    if (!pMarkAccess)
+        return nullptr;
+
+    sal_Int32 nCounter = 0;
+    std::vector<OUString> vElementNames;
+    IDocumentMarkAccess::iterator aIter = pMarkAccess->getFieldmarksBegin();
+    while (aIter != pMarkAccess->getFieldmarksEnd())
+    {
+        switch (IDocumentMarkAccess::GetType(**aIter))
+        {
+            case IDocumentMarkAccess::MarkType::CHECKBOX_FIELDMARK:
+            case IDocumentMarkAccess::MarkType::DROPDOWN_FIELDMARK:
+            case IDocumentMarkAccess::MarkType::TEXT_FIELDMARK:
+            {
+                if (rIndex < 0
+                    && 
(*aIter)->GetName().equalsIgnoreAsciiCase(OUString::fromUtf8(rName)))
+                {
+                    rIndex = nCounter;
+                    return dynamic_cast<sw::mark::IFieldmark*>(*aIter);
+                }
+                else if (rIndex == nCounter)
+                    return dynamic_cast<sw::mark::IFieldmark*>(*aIter);
+
+                ++nCounter;
+                if (pElementNames)
+                    vElementNames.push_back((*aIter)->GetName());
+                break;
+            }
+            default:;
+        }
+        aIter++;
+    }
+    rIndex = nCounter;
+    if (pElementNames)
+        *pElementNames = comphelper::containerToSequence(vElementNames);
+    return nullptr;
+}
+
+namespace
+{
+class FormFieldsEnumWrapper : public EnumerationHelper_BASE
+{
+    uno::Reference<container::XIndexAccess> mxIndexAccess;
+    sal_Int32 nIndex;
+
+public:
+    explicit FormFieldsEnumWrapper(uno::Reference<container::XIndexAccess> 
xIndexAccess)
+        : mxIndexAccess(std::move(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 FormFieldCollectionHelper
+    : public ::cppu::WeakImplHelper<container::XNameAccess, 
container::XIndexAccess,
+                                    container::XEnumerationAccess>
+{
+private:
+    uno::Reference<XHelperInterface> mxParent;
+    uno::Reference<uno::XComponentContext> mxContext;
+    css::uno::Reference<frame::XModel> mxModel;
+    sw::mark::IFieldmark* m_pCache;
+
+public:
+    /// @throws css::uno::RuntimeException
+    FormFieldCollectionHelper(css::uno::Reference<ov::XHelperInterface> 
xParent,
+                              css::uno::Reference<css::uno::XComponentContext> 
xContext,
+                              css::uno::Reference<frame::XModel> xModel)
+        : mxParent(std::move(xParent))
+        , mxContext(std::move(xContext))
+        , mxModel(std::move(xModel))
+    {
+    }
+
+    // XIndexAccess
+    virtual sal_Int32 SAL_CALL getCount() override
+    {
+        sal_Int32 nCount = SAL_MAX_INT32;
+        lcl_getFieldmark("", nCount, mxModel);
+        return nCount == SAL_MAX_INT32 ? 0 : nCount;
+    }
+
+    virtual uno::Any SAL_CALL getByIndex(sal_Int32 Index) override
+    {
+        m_pCache = lcl_getFieldmark("", Index, mxModel);
+        if (!m_pCache)
+            throw css::lang::IndexOutOfBoundsException();
+
+        return uno::Any(uno::Reference<word::XFormField>(
+            new SwVbaFormField(mxParent, mxContext, mxModel, *m_pCache)));
+    }
+
+    // XNameAccess
+    virtual uno::Sequence<OUString> SAL_CALL getElementNames() override
+    {
+        sal_Int32 nCount = SAL_MAX_INT32;
+        uno::Sequence<OUString> aSeq;
+        lcl_getFieldmark("", nCount, mxModel, &aSeq);
+        return aSeq;
+    }
+
+    virtual uno::Any SAL_CALL getByName(const OUString& aName) override
+    {
+        if (!hasByName(aName))
+            throw container::NoSuchElementException();
+
+        return uno::Any(uno::Reference<word::XFormField>(
+            new SwVbaFormField(mxParent, mxContext, mxModel, *m_pCache)));
+    }
+
+    virtual sal_Bool SAL_CALL hasByName(const OUString& aName) override
+    {
+        sal_Int32 nCount = -1;
+        m_pCache = lcl_getFieldmark(aName.toUtf8(), nCount, mxModel);
+        return m_pCache != nullptr;
+    }
+
+    // XElementAccess
+    virtual uno::Type SAL_CALL getElementType() override
+    {
+        return cppu::UnoType<word::XFormField>::get();
+    }
+
+    virtual sal_Bool SAL_CALL hasElements() override { return getCount() != 0; 
}
+
+    // XEnumerationAccess
+    virtual uno::Reference<container::XEnumeration> SAL_CALL 
createEnumeration() override
+    {
+        return new FormFieldsEnumWrapper(this);
+    }
+};
+}
+
+SwVbaFormFields::SwVbaFormFields(const uno::Reference<XHelperInterface>& 
xParent,
+                                 const uno::Reference<uno::XComponentContext>& 
xContext,
+                                 const uno::Reference<frame::XModel>& xModel)
+    : SwVbaFormFields_BASE(xParent, xContext,
+                           uno::Reference<container::XIndexAccess>(
+                               new FormFieldCollectionHelper(xParent, 
xContext, xModel)))
+{
+}
+
+sal_Bool SwVbaFormFields::getShaded()
+{
+    SAL_INFO("sw.vba", "SwVbaFormFields::getShaded stub");
+    return false;
+}
+
+void SwVbaFormFields::setShaded(sal_Bool /*bSet*/)
+{
+    SAL_INFO("sw.vba", "SwVbaFormFields::setShaded stub");
+}
+
+// uno::Reference<ooo::vba::word::XFormField> SwVbaFormFields::Add(const 
css::uno::Any& Range,
+//                                                                 sal_Int32 
Type)
+// {
+//     sw::mark::IFieldmark* pFieldmark = nullptr;
+//     switch (Type)
+//     {
+//         case ooo::vba::word::WdFieldType::wdFieldFormCheckBox:
+//             break;
+//         case ooo::vba::word::WdFieldType::wdFieldFormDropDown:
+//             break;
+//         case ooo::vba::word::WdFieldType::wdFieldFormTextInput:
+//         default:;
+//     }
+//
+//     return uno::Reference<ooo::vba::word::XFormField>(
+//         new SwVbaFormField(mxParent, mxContext, m_xModel, *pFieldmark));
+// }
+
+// XEnumerationAccess
+uno::Type SwVbaFormFields::getElementType() { return 
cppu::UnoType<word::XFormField>::get(); }
+
+uno::Reference<container::XEnumeration> SwVbaFormFields::createEnumeration()
+{
+    return new FormFieldsEnumWrapper(m_xIndexAccess);
+}
+
+uno::Any SwVbaFormFields::createCollectionObject(const css::uno::Any& aSource) 
{ return aSource; }
+
+OUString SwVbaFormFields::getServiceImplName() { return "SwVbaFormFields"; }
+
+css::uno::Sequence<OUString> SwVbaFormFields::getServiceNames()
+{
+    static uno::Sequence<OUString> const sNames{ "ooo.vba.word.FormFields" };
+    return sNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/ui/vba/vbaformfields.hxx 
b/sw/source/ui/vba/vbaformfields.hxx
new file mode 100644
index 000000000000..59226e5ea6f8
--- /dev/null
+++ b/sw/source/ui/vba/vbaformfields.hxx
@@ -0,0 +1,53 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef INCLUDED_SW_SOURCE_UI_VBA_VBAFORMFIELDS_HXX
+#define INCLUDED_SW_SOURCE_UI_VBA_VBAFORMFIELDS_HXX
+
+#include <ooo/vba/word/XFormFields.hpp>
+
+#include <vbahelper/vbacollectionimpl.hxx>
+
+typedef CollTestImplHelper<ooo::vba::word::XFormFields> SwVbaFormFields_BASE;
+
+class SwVbaFormFields : public SwVbaFormFields_BASE
+{
+public:
+    /// @throws css::uno::RuntimeException
+    SwVbaFormFields(const css::uno::Reference<ov::XHelperInterface>& xParent,
+                    const css::uno::Reference<css::uno::XComponentContext>& 
xContext,
+                    const css::uno::Reference<css::frame::XModel>& xModel);
+
+    // XFormFields
+    virtual sal_Bool SAL_CALL getShaded() override;
+    virtual void SAL_CALL setShaded(sal_Bool bSet) override;
+    //virtual css::uno::Reference<ooo::vba::word::XFormField> SAL_CALL 
Add(const css::uno::Any& Range, sal_Int32 Type) override;
+
+    // XEnumerationAccess
+    virtual css::uno::Type SAL_CALL getElementType() override;
+    virtual css::uno::Reference<css::container::XEnumeration> SAL_CALL 
createEnumeration() override;
+
+    // SwVbaFormFields_BASE
+    virtual css::uno::Any createCollectionObject(const css::uno::Any& aSource) 
override;
+    virtual OUString getServiceImplName() override;
+    virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+#endif // INCLUDED_SW_SOURCE_UI_VBA_VBAFORMFIELDS_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to