sw/inc/doc.hxx                                |    3 +
 sw/inc/formatcontentcontrol.hxx               |    1 
 sw/inc/textcontentcontrol.hxx                 |   23 ++++++++
 sw/source/core/doc/doc.cxx                    |    5 +
 sw/source/core/doc/docfmt.cxx                 |    2 
 sw/source/core/doc/docnew.cxx                 |    2 
 sw/source/core/txtnode/attrcontentcontrol.cxx |   68 ++++++++++++++++++++++++--
 sw/source/core/txtnode/thints.cxx             |    2 
 8 files changed, 100 insertions(+), 6 deletions(-)

New commits:
commit a14b2db9acdae043d54b0e5b8dab881fe9ed3c06
Author:     Miklos Vajna <[email protected]>
AuthorDate: Tue Nov 8 08:14:41 2022 +0100
Commit:     Miklos Vajna <[email protected]>
CommitDate: Tue Nov 8 16:39:03 2022 +0100

    sw: introduce a manager for content controls
    
    The VBA API for content controls can access e.g. the 3rd content control
    in the document, see
    <https://learn.microsoft.com/en-us/office/vba/api/word.contentcontrols>.
    To support something similar, first we need to track the content
    controls in the document, otherwise getting the Nth element of that list
    would require scanning the entire document, which would be slow.
    
    SwContentControlManager::m_aContentControls is a plain vector, because
    an o3tl::sorted_vector would require sorting at insert time, but our
    content controls are typically first created and only later inserted,
    and we want to use the insert position as the comparison key when
    sorting.
    
    This just keeps track of content controls (visible in the doc model XML
    dump), somewhat similar to sw::MetaFieldManager or SwFootnoteIdxs.
    
    UNO API to actually expose this is not yet added.
    
    (cherry picked from commit ad950f10dc382ea169f94a0c301ca8c424e7103e)
    
    Change-Id: I3f75334ffef684afc2c05a1bbdb7f247876d27ad
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/142462
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Miklos Vajna <[email protected]>

diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx
index f7749190e3ea..c6b466d9ab3c 100644
--- a/sw/inc/doc.hxx
+++ b/sw/inc/doc.hxx
@@ -135,6 +135,7 @@ class IDocumentExternalData;
 class IDocumentMarkAccess;
 class SetGetExpFields;
 struct SwInsertTableOptions;
+class SwContentControlManager;
 enum class SvMacroItemId : sal_uInt16;
 enum class SvxFrameDirection;
 enum class RndStdIds;
@@ -210,6 +211,7 @@ class SW_DLLPUBLIC SwDoc final
 
     const std::unique_ptr< ::sw::mark::MarkManager> mpMarkManager;
     const std::unique_ptr< ::sw::MetaFieldManager > m_pMetaFieldManager;
+    const std::unique_ptr< ::SwContentControlManager > 
m_pContentControlManager;
     const std::unique_ptr< ::sw::DocumentDrawModelManager > 
m_pDocumentDrawModelManager;
     const std::unique_ptr< ::sw::DocumentRedlineManager > 
m_pDocumentRedlineManager;
     const std::unique_ptr< ::sw::DocumentStateManager > 
m_pDocumentStateManager;
@@ -1625,6 +1627,7 @@ public:
     const css::uno::Reference< css::container::XNameContainer >& 
GetVBATemplateToProjectCache() const { return m_xTemplateToProjectCache; };
     ::sfx2::IXmlIdRegistry& GetXmlIdRegistry();
     ::sw::MetaFieldManager & GetMetaFieldManager();
+    ::SwContentControlManager& GetContentControlManager();
     ::sw::UndoManager      & GetUndoManager();
     ::sw::UndoManager const& GetUndoManager() const;
 
diff --git a/sw/inc/formatcontentcontrol.hxx b/sw/inc/formatcontentcontrol.hxx
index 2cf220b9bcd1..86bc8a0c62b7 100644
--- a/sw/inc/formatcontentcontrol.hxx
+++ b/sw/inc/formatcontentcontrol.hxx
@@ -76,6 +76,7 @@ public:
      * (re-)moved.
      */
     void NotifyChangeTextNode(SwTextNode* pTextNode);
+    SwTextNode* GetTextNode() const;
     static SwFormatContentControl* CreatePoolDefault(sal_uInt16 nWhich);
     std::shared_ptr<SwContentControl> GetContentControl() { return 
m_pContentControl; }
     const std::shared_ptr<SwContentControl>& GetContentControl() const { 
return m_pContentControl; }
diff --git a/sw/inc/textcontentcontrol.hxx b/sw/inc/textcontentcontrol.hxx
index 1c445d812099..dc7d210f79a6 100644
--- a/sw/inc/textcontentcontrol.hxx
+++ b/sw/inc/textcontentcontrol.hxx
@@ -20,15 +20,19 @@
 
 #include "txatbase.hxx"
 
+class SwContentControlManager;
 class SwFormatContentControl;
 
 /// SwTextAttr subclass that tracks the location of the wrapped 
SwFormatContentControl.
 class SW_DLLPUBLIC SwTextContentControl final : public SwTextAttrNesting
 {
-    SwTextContentControl(SwFormatContentControl& rAttr, sal_Int32 nStart, 
sal_Int32 nEnd);
+    SwContentControlManager* m_pManager;
+
+    SwTextContentControl(SwContentControlManager* pManager, 
SwFormatContentControl& rAttr,
+                         sal_Int32 nStart, sal_Int32 nEnd);
 
 public:
-    static SwTextContentControl* CreateTextContentControl(SwTextNode* 
pTargetTextNode,
+    static SwTextContentControl* CreateTextContentControl(SwDoc& rDoc, 
SwTextNode* pTargetTextNode,
                                                           
SwFormatContentControl& rAttr,
                                                           sal_Int32 nStart, 
sal_Int32 nEnd,
                                                           bool bIsCopy);
@@ -37,7 +41,22 @@ public:
 
     void ChgTextNode(SwTextNode* pNode);
 
+    SwTextNode* GetTextNode() const;
+
     void dumpAsXml(xmlTextWriterPtr pWriter) const override;
 };
 
+/// Knows all the text content controls in the document.
+class SW_DLLPUBLIC SwContentControlManager
+{
+    /// Non-owning reference to text content controls.
+    std::vector<SwTextContentControl*> m_aContentControls;
+
+public:
+    SwContentControlManager();
+    void Insert(SwTextContentControl* pTextContentControl);
+    void Erase(SwTextContentControl* pTextContentControl);
+    void dumpAsXml(xmlTextWriterPtr pWriter) const;
+};
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/doc/doc.cxx b/sw/source/core/doc/doc.cxx
index 800c264588b6..5abb1d9d92c9 100644
--- a/sw/source/core/doc/doc.cxx
+++ b/sw/source/core/doc/doc.cxx
@@ -130,6 +130,11 @@ sal_Int32 SwDoc::getReferenceCount() const
     return *m_pMetaFieldManager;
 }
 
+::SwContentControlManager& SwDoc::GetContentControlManager()
+{
+    return *m_pContentControlManager;
+}
+
 ::sw::UndoManager & SwDoc::GetUndoManager()
 {
     return *m_pUndoManager;
diff --git a/sw/source/core/doc/docfmt.cxx b/sw/source/core/doc/docfmt.cxx
index 42dfd707c556..c2104cd95857 100644
--- a/sw/source/core/doc/docfmt.cxx
+++ b/sw/source/core/doc/docfmt.cxx
@@ -76,6 +76,7 @@
 #include <modcfg.hxx>
 #include <frameformats.hxx>
 #include <textboxhelper.hxx>
+#include <textcontentcontrol.hxx>
 #include <memory>
 
 using namespace ::com::sun::star::i18n;
@@ -1965,6 +1966,7 @@ void SwDoc::dumpAsXml(xmlTextWriterPtr pWriter) const
     m_PageDescs.dumpAsXml(pWriter);
     maDBData.dumpAsXml(pWriter);
     mpMarkManager->dumpAsXml(pWriter);
+    m_pContentControlManager->dumpAsXml(pWriter);
     m_pUndoManager->dumpAsXml(pWriter);
     m_pDocumentSettingManager->dumpAsXml(pWriter);
     getIDocumentFieldsAccess().GetFieldTypes()->dumpAsXml(pWriter);
diff --git a/sw/source/core/doc/docnew.cxx b/sw/source/core/doc/docnew.cxx
index da65b2957229..66921bc11ee4 100644
--- a/sw/source/core/doc/docnew.cxx
+++ b/sw/source/core/doc/docnew.cxx
@@ -108,6 +108,7 @@
 
 #include <sfx2/Metadatable.hxx>
 #include <fmtmeta.hxx>
+#include <textcontentcontrol.hxx>
 
 #include <svx/xfillit0.hxx>
 #include <unotools/configmgr.hxx>
@@ -207,6 +208,7 @@ SwDoc::SwDoc()
     maOLEModifiedIdle( "sw::SwDoc maOLEModifiedIdle" ),
     mpMarkManager(new ::sw::mark::MarkManager(*this)),
     m_pMetaFieldManager(new ::sw::MetaFieldManager()),
+    m_pContentControlManager(new ::SwContentControlManager()),
     m_pDocumentDrawModelManager( new ::sw::DocumentDrawModelManager( *this ) ),
     m_pDocumentRedlineManager( new ::sw::DocumentRedlineManager( *this ) ),
     m_pDocumentStateManager( new ::sw::DocumentStateManager( *this ) ),
diff --git a/sw/source/core/txtnode/attrcontentcontrol.cxx 
b/sw/source/core/txtnode/attrcontentcontrol.cxx
index dc451ca927e4..418f35878f85 100644
--- a/sw/source/core/txtnode/attrcontentcontrol.cxx
+++ b/sw/source/core/txtnode/attrcontentcontrol.cxx
@@ -136,6 +136,16 @@ void 
SwFormatContentControl::NotifyChangeTextNode(SwTextNode* pTextNode)
     }
 }
 
+SwTextNode* SwFormatContentControl::GetTextNode() const
+{
+    if (!m_pContentControl)
+    {
+        return nullptr;
+    }
+
+    return m_pContentControl->GetTextNode();
+}
+
 // This SwFormatContentControl has been cloned and points at the same 
SwContentControl as the
 // source: this function copies the SwContentControl.
 void SwFormatContentControl::DoCopy(SwTextNode& rTargetTextNode)
@@ -495,7 +505,8 @@ SwContentControlListItem::ItemsFromAny(const css::uno::Any& 
rVal)
     return aRet;
 }
 
-SwTextContentControl* 
SwTextContentControl::CreateTextContentControl(SwTextNode* pTargetTextNode,
+SwTextContentControl* SwTextContentControl::CreateTextContentControl(SwDoc& 
rDoc,
+                                                                     
SwTextNode* pTargetTextNode,
                                                                      
SwFormatContentControl& rAttr,
                                                                      sal_Int32 
nStart,
                                                                      sal_Int32 
nEnd, bool bIsCopy)
@@ -510,17 +521,21 @@ SwTextContentControl* 
SwTextContentControl::CreateTextContentControl(SwTextNode*
         }
         rAttr.DoCopy(*pTargetTextNode);
     }
-    auto pTextContentControl(new SwTextContentControl(rAttr, nStart, nEnd));
+    SwContentControlManager* pManager = &rDoc.GetContentControlManager();
+    auto pTextContentControl(new SwTextContentControl(pManager, rAttr, nStart, 
nEnd));
     return pTextContentControl;
 }
 
-SwTextContentControl::SwTextContentControl(SwFormatContentControl& rAttr, 
sal_Int32 nStart,
+SwTextContentControl::SwTextContentControl(SwContentControlManager* pManager,
+                                           SwFormatContentControl& rAttr, 
sal_Int32 nStart,
                                            sal_Int32 nEnd)
     : SwTextAttr(rAttr, nStart)
     , SwTextAttrNesting(rAttr, nStart, nEnd)
+    , m_pManager(pManager)
 {
     rAttr.SetTextAttr(this);
     SetHasDummyChar(true);
+    m_pManager->Insert(this);
 }
 
 SwTextContentControl::~SwTextContentControl()
@@ -538,9 +553,28 @@ void SwTextContentControl::ChgTextNode(SwTextNode* pNode)
     if (rFormatContentControl.GetTextAttr() == this)
     {
         rFormatContentControl.NotifyChangeTextNode(pNode);
+
+        if (pNode)
+        {
+            m_pManager = &pNode->GetDoc().GetContentControlManager();
+        }
+        else
+        {
+            if (m_pManager)
+            {
+                m_pManager->Erase(this);
+            }
+            m_pManager = nullptr;
+        }
     }
 }
 
+SwTextNode* SwTextContentControl::GetTextNode() const
+{
+    auto& rFormatContentControl = static_cast<const 
SwFormatContentControl&>(GetAttr());
+    return rFormatContentControl.GetTextNode();
+}
+
 void SwTextContentControl::dumpAsXml(xmlTextWriterPtr pWriter) const
 {
     (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwTextContentControl"));
@@ -550,4 +584,32 @@ void SwTextContentControl::dumpAsXml(xmlTextWriterPtr 
pWriter) const
     (void)xmlTextWriterEndElement(pWriter);
 }
 
+SwContentControlManager::SwContentControlManager() {}
+
+void SwContentControlManager::Insert(SwTextContentControl* pTextContentControl)
+{
+    m_aContentControls.push_back(pTextContentControl);
+}
+
+void SwContentControlManager::Erase(SwTextContentControl* pTextContentControl)
+{
+    m_aContentControls.erase(
+        std::remove(m_aContentControls.begin(), m_aContentControls.end(), 
pTextContentControl),
+        m_aContentControls.end());
+}
+
+void SwContentControlManager::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+    (void)xmlTextWriterStartElement(pWriter, 
BAD_CAST("SwContentControlManager"));
+    (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", 
this);
+    for (const auto& pContentControl : m_aContentControls)
+    {
+        (void)xmlTextWriterStartElement(pWriter, 
BAD_CAST("SwTextContentControl"));
+        (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), 
"%p", pContentControl);
+        (void)xmlTextWriterEndElement(pWriter);
+    }
+
+    (void)xmlTextWriterEndElement(pWriter);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/thints.cxx 
b/sw/source/core/txtnode/thints.cxx
index 7bb9c3a03798..c2d37e058c3b 100644
--- a/sw/source/core/txtnode/thints.cxx
+++ b/sw/source/core/txtnode/thints.cxx
@@ -1160,7 +1160,7 @@ SwTextAttr* MakeTextAttr(
         break;
     case RES_TXTATR_CONTENTCONTROL:
         pNew = SwTextContentControl::CreateTextContentControl(
-            pTextNode, static_cast<SwFormatContentControl&>(rNew), nStt, nEnd,
+            rDoc, pTextNode, static_cast<SwFormatContentControl&>(rNew), nStt, 
nEnd,
             bIsCopy == CopyOrNewType::Copy);
         break;
     default:

Reply via email to