include/vcl/builder.hxx       |   38 ++---
 include/vcl/builderbase.hxx   |    1 
 include/vcl/widgetbuilder.hxx |  290 ++++++++++++++++++++++++++++++++++++++++++
 vcl/source/window/builder.cxx |  204 -----------------------------
 4 files changed, 308 insertions(+), 225 deletions(-)

New commits:
commit 385bbbd6e1f602d066b00c0913aefa36e75ce5a6
Author:     Michael Weghorn <[email protected]>
AuthorDate: Fri Sep 20 14:03:00 2024 +0200
Commit:     Michael Weghorn <[email protected]>
CommitDate: Wed Sep 25 21:08:59 2024 +0200

    tdf#130857 Move VclBuilder::handleObject to WidgetBuilder base
    
    Move `VclBuilder::handleObject` to the template base class
    `WidgetBuilder` introduced in previous commit
    
        Change-Id: I2d81cc6dd54d796b549357a4444b95627661c623
        Author: OmkarAcharekar <[email protected]>
        Date:   Fri Sep 20 13:33:01 2024 +0200
    
            tdf#130857 refactor VclBuilder: Extract template base class
    
    Add new virtual methods to that base class to override in the
    subclasses. These are currently the ones that `VclBuilder`
    already implements for `vcl::Window`.
    
    More refactoring - in particular for those methods that currently
    still do XML parsing themselves is planned for the future
    once the relevant functionality will be implemented in
    other subclasses. For now, those methods that do XML parsing
    themseslves trigger an assert in the base class implementation
    and remain unchanged in the `VclBuilder` implementation.
    
    One aspect to be aware of is that `WidgetPtr` should explicitly
    be initialized to `nullptr` if not assigned a different value:
    While `VclPtr` that gets used for `VclBuilder` has a default ctor
    that takes care of proper initialization, that's not the case for
    the upcoming `QtBuilder` [1] that just uses `QObject*` for `WidgetPtr`.
    
    [1] https://gerrit.libreoffice.org/c/core/+/161831
    
    Change-Id: I5c1b7201c82ca2c0c2d7389642aee407ebea16ce
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173737
    Reviewed-by: Michael Weghorn <[email protected]>
    Tested-by: Jenkins

diff --git a/include/vcl/builder.hxx b/include/vcl/builder.hxx
index 353d300015b3..3ad480eece64 100644
--- a/include/vcl/builder.hxx
+++ b/include/vcl/builder.hxx
@@ -189,8 +189,8 @@ private:
     void     mungeModel(ComboBox &rTarget, const ListStore &rStore, sal_uInt16 
nActiveId);
     void     mungeModel(SvTabListBox &rTarget, const ListStore &rStore, 
sal_uInt16 nActiveId);
 
-    void insertComboBoxOrListBoxItems(vcl::Window *pWindow, 
VclBuilder::stringmap &rMap,
-                                      const std::vector<ComboBoxTextItem>& 
rItems);
+    void insertComboBoxOrListBoxItems(vcl::Window* pWindow, stringmap& rMap,
+                                      const std::vector<ComboBoxTextItem>& 
rItems) override;
 
     static void     mungeTextBuffer(VclMultiLineEdit &rTarget, const 
TextBuffer &rTextBuffer);
 
@@ -269,10 +269,9 @@ private:
     void tweakInsertedChild(vcl::Window *pParent, vcl::Window* pCurrentChild,
                             std::string_view sType, std::string_view 
sInternalChild) override;
 
-    VclPtr<vcl::Window> insertObject(vcl::Window *pParent,
-                    const OUString &rClass, const OUString &rID,
-                    stringmap &rProps, stringmap &rPangoAttributes,
-                    stringmap &rAtkProps);
+    VclPtr<vcl::Window> insertObject(vcl::Window* pParent, const OUString& 
rClass,
+                                     const OUString& rID, stringmap& rProps,
+                                     stringmap& rPangoAttributes, stringmap& 
rAtkProps) override;
 
     VclPtr<vcl::Window> makeObject(vcl::Window *pParent,
                     const OUString &rClass, const OUString &rID,
@@ -290,8 +289,6 @@ private:
     void        extractButtonImage(const OUString &id, stringmap &rMap, bool 
bRadio);
     void        extractMnemonicWidget(const OUString &id, stringmap &rMap);
 
-    VclPtr<vcl::Window> handleObject(vcl::Window *pParent, stringmap 
*pAtkProps, xmlreader::XmlReader &reader, bool bToolbarItem) override;
-
     void applyPackingProperties(vcl::Window* pCurrent, vcl::Window* pParent,
                                 const stringmap& rPackingProperties) override;
 
@@ -309,13 +306,15 @@ private:
 
     void        handleTabChild(vcl::Window *pParent, xmlreader::XmlReader 
&reader) override;
     void handleMenu(xmlreader::XmlReader& reader, vcl::Window* pParent, const 
OUString& rID,
-                    bool bMenuBar);
+                    bool bMenuBar) override;
 
     // if bToolbarItem=true, pParent is the ToolBox that the item belongs to, 
since there's no widget for the item itself
-    void applyAtkProperties(vcl::Window *pWindow, const stringmap& 
rProperties, bool bToolbarItem);
+    void applyAtkProperties(vcl::Window* pWindow, const stringmap& rProperties,
+                            bool bToolbarItem) override;
 
-    static void setPriority(vcl::Window* pWindow, int nPriority);
-    static void setContext(vcl::Window* pWindow, 
std::vector<vcl::EnumContext::Context>&& aContext);
+    void setPriority(vcl::Window* pWindow, int nPriority) override;
+    void setContext(vcl::Window* pWindow,
+                    std::vector<vcl::EnumContext::Context>&& aContext) 
override;
 
     PackingData get_window_packing_data(const vcl::Window *pWindow) const;
     void        set_window_packing_position(const vcl::Window *pWindow, 
sal_Int32 nPosition);
diff --git a/include/vcl/widgetbuilder.hxx b/include/vcl/widgetbuilder.hxx
index a12bff918c0a..da2370ad5845 100644
--- a/include/vcl/widgetbuilder.hxx
+++ b/include/vcl/widgetbuilder.hxx
@@ -9,8 +9,8 @@
 
 #pragma once
 
+#include <sal/log.hxx>
 #include <vcl/builderbase.hxx>
-
 #include <xmlreader/span.hxx>
 #include <xmlreader/xmlreader.hxx>
 
@@ -114,13 +114,159 @@ protected:
         }
     }
 
+    WidgetPtr handleObject(Widget* pParent, stringmap* pAtkProps, 
xmlreader::XmlReader& reader,
+                           bool bToolbarItem)
+    {
+        OUString sClass;
+        OUString sID;
+        OUString sCustomProperty;
+        extractClassAndIdAndCustomProperty(reader, sClass, sID, 
sCustomProperty);
+
+        if (sClass == "GtkListStore" || sClass == "GtkTreeStore")
+        {
+            handleListStore(reader, sID, sClass);
+            return nullptr;
+        }
+        else if (sClass == "GtkMenu")
+        {
+            handleMenu(reader, pParent, sID, false);
+            return nullptr;
+        }
+        else if (sClass == "GtkMenuBar")
+        {
+            handleMenu(reader, pParent, sID, true);
+            return nullptr;
+        }
+        else if (sClass == "GtkSizeGroup")
+        {
+            handleSizeGroup(reader);
+            return nullptr;
+        }
+        else if (sClass == "AtkObject")
+        {
+            assert((pParent || pAtkProps) && "must have one set");
+            assert(!(pParent && pAtkProps) && "must not have both");
+            auto aAtkProperties = handleAtkObject(reader);
+            if (pParent)
+                applyAtkProperties(pParent, aAtkProperties, bToolbarItem);
+            if (pAtkProps)
+                *pAtkProps = std::move(aAtkProperties);
+            return nullptr;
+        }
+
+        int nLevel = 1;
+
+        stringmap aProperties, aPangoAttributes;
+        stringmap aAtkAttributes;
+        std::vector<ComboBoxTextItem> aItems;
+
+        if (!sCustomProperty.isEmpty())
+            aProperties[u"customproperty"_ustr] = sCustomProperty;
+
+        WidgetPtr pCurrentChild = nullptr;
+        while (true)
+        {
+            xmlreader::Span name;
+            int nsId;
+            xmlreader::XmlReader::Result res
+                = reader.nextItem(xmlreader::XmlReader::Text::NONE, &name, 
&nsId);
+
+            if (res == xmlreader::XmlReader::Result::Done)
+                break;
+
+            if (res == xmlreader::XmlReader::Result::Begin)
+            {
+                if (name == "child")
+                {
+                    if (!pCurrentChild)
+                    {
+                        pCurrentChild = insertObject(pParent, sClass, sID, 
aProperties,
+                                                     aPangoAttributes, 
aAtkAttributes);
+                    }
+                    handleChild(pCurrentChild, nullptr, reader, 
isToolbarItemClass(sClass));
+                }
+                else if (name == "items")
+                    aItems = handleItems(reader);
+                else if (name == "style")
+                {
+                    int nPriority = 0;
+                    std::vector<vcl::EnumContext::Context> aContext
+                        = handleStyle(reader, nPriority);
+                    if (nPriority != 0)
+                        setPriority(pCurrentChild, nPriority);
+                    if (!aContext.empty())
+                        setContext(pCurrentChild, std::move(aContext));
+                }
+                else
+                {
+                    ++nLevel;
+                    if (name == "property")
+                        collectProperty(reader, aProperties);
+                    else if (name == "attribute")
+                        collectPangoAttribute(reader, aPangoAttributes);
+                    else if (name == "relation")
+                        collectAtkRelationAttribute(reader, aAtkAttributes);
+                    else if (name == "role")
+                        collectAtkRoleAttribute(reader, aAtkAttributes);
+                    else if (name == "action-widget")
+                        handleActionWidget(reader);
+                }
+            }
+
+            if (res == xmlreader::XmlReader::Result::End)
+            {
+                --nLevel;
+            }
+
+            if (!nLevel)
+                break;
+        }
+
+        if (sClass == "GtkAdjustment")
+        {
+            addAdjustment(sID, aProperties);
+            return nullptr;
+        }
+        else if (sClass == "GtkTextBuffer")
+        {
+            addTextBuffer(sID, aProperties);
+            return nullptr;
+        }
+
+        if (!pCurrentChild)
+        {
+            pCurrentChild
+                = insertObject(pParent, sClass, sID, aProperties, 
aPangoAttributes, aAtkAttributes);
+        }
+
+        if (!aItems.empty())
+            insertComboBoxOrListBoxItems(pCurrentChild, aProperties, aItems);
+
+        return pCurrentChild;
+    }
+
+    virtual void applyAtkProperties(Widget* pWidget, const stringmap& 
rProperties,
+                                    bool bToolbarItem)
+        = 0;
     virtual void applyPackingProperties(Widget* pCurrentChild, Widget* pParent,
                                         const stringmap& rPackingProperties)
         = 0;
+    virtual void insertComboBoxOrListBoxItems(Widget* pWidget, stringmap& rMap,
+                                              const 
std::vector<ComboBoxTextItem>& rItems)
+        = 0;
+
+    virtual WidgetPtr insertObject(Widget* pParent, const OUString& rClass, 
const OUString& rID,
+                                   stringmap& rProps, stringmap& 
rPangoAttributes,
+                                   stringmap& rAtkProps)
+        = 0;
+
     virtual void tweakInsertedChild(Widget* pParent, Widget* pCurrentChild, 
std::string_view sType,
                                     std::string_view sInternalChild)
         = 0;
 
+    virtual void setPriority(Widget* pWidget, int nPriority) = 0;
+    virtual void setContext(Widget* pWidget, 
std::vector<vcl::EnumContext::Context>&& aContext) = 0;
+
     // These methods are currently only implemented by VclBuilder and should be
     // refactored as described in the class documentation above (split into
     // parsing done in this class + overridable methods that don't need 
XmlReader
@@ -128,13 +274,14 @@ protected:
     //
     // Until that's done, other subclasses can be used to handle only those 
.ui files
     // not using the corresponding features (attributes/objects in the .ui 
file).
-    virtual WidgetPtr handleObject(Widget* /*pParent*/, stringmap* 
/*pAtkProps*/,
-                                   xmlreader::XmlReader& /*reader*/, bool 
/*bToolbarItem*/)
+    virtual void handleMenu(xmlreader::XmlReader& /*reader*/, Widget* 
/*pParent*/,
+                            const OUString& /*rID*/, bool /*bMenuBar*/)
     {
         assert(false && "Functionality not implemented by this subclass yet.");
-        return nullptr;
     }
+
     virtual void handleTabChild(Widget* /*pParent*/, xmlreader::XmlReader& 
/*reader*/)
+
     {
         assert(false && "Functionality not implemented by this subclass yet.");
     }
diff --git a/vcl/source/window/builder.cxx b/vcl/source/window/builder.cxx
index 3e1fad42fbe5..25bab94a1265 100644
--- a/vcl/source/window/builder.cxx
+++ b/vcl/source/window/builder.cxx
@@ -67,7 +67,6 @@
 #include <messagedialog.hxx>
 #include <ContextVBox.hxx>
 #include <DropdownBox.hxx>
-#include <IPrioritable.hxx>
 #include <OptionalBox.hxx>
 #include <PriorityMergedHBox.hxx>
 #include <PriorityHBox.hxx>
@@ -3571,135 +3570,6 @@ void 
BuilderBase::extractClassAndIdAndCustomProperty(xmlreader::XmlReader& reade
     }
 }
 
-VclPtr<vcl::Window> VclBuilder::handleObject(vcl::Window *pParent, stringmap 
*pAtkProps, xmlreader::XmlReader &reader, bool bToolbarItem)
-{
-    OUString sClass;
-    OUString sID;
-    OUString sCustomProperty;
-    extractClassAndIdAndCustomProperty(reader, sClass, sID, sCustomProperty);
-
-    if (sClass == "GtkListStore" || sClass == "GtkTreeStore")
-    {
-        handleListStore(reader, sID, sClass);
-        return nullptr;
-    }
-    else if (sClass == "GtkMenu")
-    {
-        handleMenu(reader, pParent, sID, false);
-        return nullptr;
-    }
-    else if (sClass == "GtkMenuBar")
-    {
-        handleMenu(reader, pParent, sID, true);
-        return nullptr;
-    }
-    else if (sClass == "GtkSizeGroup")
-    {
-        handleSizeGroup(reader);
-        return nullptr;
-    }
-    else if (sClass == "AtkObject")
-    {
-        assert((pParent || pAtkProps) && "must have one set");
-        assert(!(pParent && pAtkProps) && "must not have both");
-        auto aAtkProperties = handleAtkObject(reader);
-        if (pParent)
-            applyAtkProperties(pParent, aAtkProperties, bToolbarItem);
-        if (pAtkProps)
-            *pAtkProps = std::move(aAtkProperties);
-        return nullptr;
-    }
-
-    int nLevel = 1;
-
-    stringmap aProperties, aPangoAttributes;
-    stringmap aAtkAttributes;
-    std::vector<ComboBoxTextItem> aItems;
-
-    if (!sCustomProperty.isEmpty())
-        aProperties[u"customproperty"_ustr] = sCustomProperty;
-
-    VclPtr<vcl::Window> pCurrentChild;
-    while(true)
-    {
-        xmlreader::Span name;
-        int nsId;
-        xmlreader::XmlReader::Result res = reader.nextItem(
-            xmlreader::XmlReader::Text::NONE, &name, &nsId);
-
-        if (res == xmlreader::XmlReader::Result::Done)
-            break;
-
-        if (res == xmlreader::XmlReader::Result::Begin)
-        {
-            if (name == "child")
-            {
-                if (!pCurrentChild)
-                {
-                    pCurrentChild = insertObject(pParent, sClass, sID,
-                        aProperties, aPangoAttributes, aAtkAttributes);
-                }
-                handleChild(pCurrentChild, nullptr, reader, 
isToolbarItemClass(sClass));
-            }
-            else if (name == "items")
-                aItems = handleItems(reader);
-            else if (name == "style")
-            {
-                int nPriority = 0;
-                std::vector<vcl::EnumContext::Context> aContext = 
handleStyle(reader, nPriority);
-                if (nPriority != 0)
-                    setPriority(pCurrentChild, nPriority);
-                if (!aContext.empty())
-                    setContext(pCurrentChild, std::move(aContext));
-            }
-            else
-            {
-                ++nLevel;
-                if (name == "property")
-                    collectProperty(reader, aProperties);
-                else if (name == "attribute")
-                    collectPangoAttribute(reader, aPangoAttributes);
-                else if (name == "relation")
-                    collectAtkRelationAttribute(reader, aAtkAttributes);
-                else if (name == "role")
-                    collectAtkRoleAttribute(reader, aAtkAttributes);
-                else if (name == "action-widget")
-                    handleActionWidget(reader);
-            }
-        }
-
-        if (res == xmlreader::XmlReader::Result::End)
-        {
-            --nLevel;
-        }
-
-        if (!nLevel)
-            break;
-    }
-
-    if (sClass == "GtkAdjustment")
-    {
-        addAdjustment(sID, aProperties);
-        return nullptr;
-    }
-    else if (sClass == "GtkTextBuffer")
-    {
-        addTextBuffer(sID, aProperties);
-        return nullptr;
-    }
-
-    if (!pCurrentChild)
-    {
-        pCurrentChild = insertObject(pParent, sClass, sID, aProperties,
-            aPangoAttributes, aAtkAttributes);
-    }
-
-    if (!aItems.empty())
-        insertComboBoxOrListBoxItems(pCurrentChild, aProperties, aItems);
-
-    return pCurrentChild;
-}
-
 void BuilderBase::handleInterfaceDomain(xmlreader::XmlReader& rReader)
 {
     xmlreader::Span name = rReader.getAttributeValue(false);
commit f61ecf25636d401f862c4de226c04237e1fb2f69
Author:     OmkarAcharekar <[email protected]>
AuthorDate: Fri Sep 20 13:33:01 2024 +0200
Commit:     Michael Weghorn <[email protected]>
CommitDate: Wed Sep 25 21:08:50 2024 +0200

    tdf#130857 refactor VclBuilder: Extract template base class
    
    Refactor `VclBuilder` by extracting the `handleChild` method
    and moving it into a new template base class `WidgetBuilder`,
    so both `VclBuilder` and an upcoming `QtBuilder` (see [1])
    can share the common logic to parse the .ui file and override
    the virtual methods like `applyPackingProperties`,
    `tweakInsertedChild` etc. to handle toolkit specific cases,
    as mentioned as one potential approach in Caolán's email [2].
    
    The new class has 2 template parameters `Widget` and `WidgetPtr`
    to account for the fact that `VclBuilder` doesn't just use
    `vcl::Window*`, but there's a specific class, `VclPtr`.
    
    As the inline comments say, more refactoring will be needed
    to abstract the current `VclBuilder` implementations
    of various methods from the `vcl::Window` specifics and
    make them reusable for other subclasses as well, but this
    commit is a start. The idea is to allow for incrementally
    refactoring aspects relevant for specific .ui files/features
    rather than having to refactor everything and implement
    support for all widget types at once, see also
    
        commit 9b3a2996e710fee11145dcbbe38a6f1e6f646ec8
        Author: OmkarAcharekar <[email protected]>
        Date:   Wed Sep 18 09:35:09 2024 +0200
    
            tdf#130857 qt weld: Add QtInstanceBuilder skeleton
    
    which adds an initially empty list of .ui files that
    should be handled by the upcoming Qt-based implementation.
    
    [1] https://gerrit.libreoffice.org/c/core/+/161831
    [2] 
https://lists.freedesktop.org/archives/libreoffice/2023-December/091288.html
    
    Co-authored-by: Michael Weghorn <[email protected]>
    Change-Id: I2d81cc6dd54d796b549357a4444b95627661c623
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163103
    Tested-by: Jenkins
    Reviewed-by: Michael Weghorn <[email protected]>

diff --git a/include/vcl/builder.hxx b/include/vcl/builder.hxx
index 8adf844c55e4..353d300015b3 100644
--- a/include/vcl/builder.hxx
+++ b/include/vcl/builder.hxx
@@ -15,7 +15,7 @@
 #include <tools/fldunit.hxx>
 #include <vcl/dllapi.h>
 #include <utility>
-#include <vcl/builderbase.hxx>
+#include <vcl/widgetbuilder.hxx>
 #include <vcl/window.hxx>
 #include <vcl/vclptr.hxx>
 #include <vcl/toolboxid.hxx>
@@ -54,7 +54,7 @@ namespace xmlreader { class XmlReader; }
 namespace com::sun::star::frame { class XFrame; }
 
 /// Creates a hierarchy of vcl::Windows (widgets) from a .ui file for dialogs, 
sidebar, etc.
-class VCL_DLLPUBLIC VclBuilder : public BuilderBase
+class VCL_DLLPUBLIC VclBuilder : public WidgetBuilder<vcl::Window, 
VclPtr<vcl::Window>>
 {
 public:
     /// These functions create a new widget with parent pParent and return it 
in rRet
@@ -267,7 +267,7 @@ private:
 private:
     // tweak newly inserted child depending on window type
     void tweakInsertedChild(vcl::Window *pParent, vcl::Window* pCurrentChild,
-                            std::string_view sType, std::string_view 
sInternalChild);
+                            std::string_view sType, std::string_view 
sInternalChild) override;
 
     VclPtr<vcl::Window> insertObject(vcl::Window *pParent,
                     const OUString &rClass, const OUString &rID,
@@ -290,15 +290,10 @@ private:
     void        extractButtonImage(const OUString &id, stringmap &rMap, bool 
bRadio);
     void        extractMnemonicWidget(const OUString &id, stringmap &rMap);
 
-    // either pParent or pAtkProps must be set, pParent for a child of a 
widget, pAtkProps for
-    // collecting the atk info for a GtkMenuItem,
-    // if bToolbarItem=true, pParent is the ToolBox that the item belongs to, 
since there's no widget for the item itself
-    void        handleChild(vcl::Window *pParent, stringmap *pAtkProps, 
xmlreader::XmlReader &reader, bool bToolbarItem = false);
-    // if bToolbarItem=true, pParent is the ToolBox that the item belongs to, 
since there's no widget for the item itself
-    VclPtr<vcl::Window> handleObject(vcl::Window *pParent, stringmap 
*pAtkProps, xmlreader::XmlReader &reader, bool bToolbarItem);
+    VclPtr<vcl::Window> handleObject(vcl::Window *pParent, stringmap 
*pAtkProps, xmlreader::XmlReader &reader, bool bToolbarItem) override;
 
     void applyPackingProperties(vcl::Window* pCurrent, vcl::Window* pParent,
-                                const stringmap& rPackingProperties);
+                                const stringmap& rPackingProperties) override;
 
     void        insertMenuObject(
                    Menu *pParent,
@@ -312,7 +307,7 @@ private:
     void        handleMenuChild(Menu *pParent, xmlreader::XmlReader &reader);
     void        handleMenuObject(Menu *pParent, xmlreader::XmlReader &reader);
 
-    void        handleTabChild(vcl::Window *pParent, xmlreader::XmlReader 
&reader);
+    void        handleTabChild(vcl::Window *pParent, xmlreader::XmlReader 
&reader) override;
     void handleMenu(xmlreader::XmlReader& reader, vcl::Window* pParent, const 
OUString& rID,
                     bool bMenuBar);
 
diff --git a/include/vcl/builderbase.hxx b/include/vcl/builderbase.hxx
index 9c6e744ba8b9..3c833c054434 100644
--- a/include/vcl/builderbase.hxx
+++ b/include/vcl/builderbase.hxx
@@ -44,6 +44,7 @@ public:
 
 protected:
     BuilderBase(const OUString& rUIFile, bool bLegacy);
+    virtual ~BuilderBase() = default;
 
     struct ListStore
     {
diff --git a/include/vcl/widgetbuilder.hxx b/include/vcl/widgetbuilder.hxx
new file mode 100644
index 000000000000..a12bff918c0a
--- /dev/null
+++ b/include/vcl/widgetbuilder.hxx
@@ -0,0 +1,143 @@
+/* -*- 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 <vcl/builderbase.hxx>
+
+#include <xmlreader/span.hxx>
+#include <xmlreader/xmlreader.hxx>
+
+/* Template class for a Builder to create a hierarchy of widgets from a .ui 
file
+ * for dialogs, sidebar, etc.
+ *
+ * The idea is for this class to parse the .ui file and call overridable 
methods
+ * so subclasses can create the widgets of a specific toolkit.
+ *
+ * VclBuilder is the implementation using LibreOffice's own VCL toolkit
+ * and there is a work-in-progress implementation using native Qt widgets
+ * at https://gerrit.libreoffice.org/c/core/+/161831 .
+ *
+ * Currently, .ui file parsing isn't yet fully done by this class as described
+ * above, but needs further refactoring to split the corresponding VclBuilder
+ * methods into methods that do the parsing (which should reside in this class)
+ * and overridable methods to actually create the widgets,... (which should 
reside in
+ * VclBuilder and other subclasses).
+ */
+template <typename Widget, typename WidgetPtr> class WidgetBuilder : public 
BuilderBase
+{
+protected:
+    WidgetBuilder(const OUString& rUIFile, bool bLegacy)
+        : BuilderBase(rUIFile, bLegacy)
+    {
+    }
+    virtual ~WidgetBuilder() = default;
+
+    // either pParent or pAtkProps must be set, pParent for a child of a 
widget, pAtkProps for
+    // collecting the atk info for a GtkMenuItem or tab child
+    void handleChild(Widget* pParent, stringmap* pAtkProps, 
xmlreader::XmlReader& reader,
+                     bool bToolbarItem = false)
+    {
+        xmlreader::Span name;
+        int nsId;
+        OString sType, sInternalChild;
+
+        while (reader.nextAttribute(&nsId, &name))
+        {
+            if (name == "type")
+            {
+                name = reader.getAttributeValue(false);
+                sType = OString(name.begin, name.length);
+            }
+            else if (name == "internal-child")
+            {
+                name = reader.getAttributeValue(false);
+                sInternalChild = OString(name.begin, name.length);
+            }
+        }
+
+        if (sType == "tab")
+        {
+            handleTabChild(pParent, reader);
+            return;
+        }
+
+        WidgetPtr pCurrentChild = nullptr;
+        int nLevel = 1;
+        while (true)
+        {
+            xmlreader::XmlReader::Result res
+                = reader.nextItem(xmlreader::XmlReader::Text::NONE, &name, 
&nsId);
+
+            if (res == xmlreader::XmlReader::Result::Begin)
+            {
+                if (name == "object" || name == "placeholder")
+                {
+                    pCurrentChild = handleObject(pParent, pAtkProps, reader, 
bToolbarItem);
+
+                    bool bObjectInserted = pCurrentChild && pParent != 
pCurrentChild;
+                    if (bObjectInserted)
+                        tweakInsertedChild(pParent, pCurrentChild, sType, 
sInternalChild);
+                }
+                else if (name == "packing")
+                {
+                    const stringmap aPackingProperties = 
collectPackingProperties(reader);
+                    applyPackingProperties(pCurrentChild, pParent, 
aPackingProperties);
+                }
+                else if (name == "interface")
+                {
+                    while (reader.nextAttribute(&nsId, &name))
+                    {
+                        if (name == "domain")
+                            handleInterfaceDomain(reader);
+                    }
+                    ++nLevel;
+                }
+                else
+                    ++nLevel;
+            }
+
+            if (res == xmlreader::XmlReader::Result::End)
+                --nLevel;
+
+            if (!nLevel)
+                break;
+
+            if (res == xmlreader::XmlReader::Result::Done)
+                break;
+        }
+    }
+
+    virtual void applyPackingProperties(Widget* pCurrentChild, Widget* pParent,
+                                        const stringmap& rPackingProperties)
+        = 0;
+    virtual void tweakInsertedChild(Widget* pParent, Widget* pCurrentChild, 
std::string_view sType,
+                                    std::string_view sInternalChild)
+        = 0;
+
+    // These methods are currently only implemented by VclBuilder and should be
+    // refactored as described in the class documentation above (split into
+    // parsing done in this class + overridable methods that don't need 
XmlReader
+    // that get implemented in the sublasses)
+    //
+    // Until that's done, other subclasses can be used to handle only those 
.ui files
+    // not using the corresponding features (attributes/objects in the .ui 
file).
+    virtual WidgetPtr handleObject(Widget* /*pParent*/, stringmap* 
/*pAtkProps*/,
+                                   xmlreader::XmlReader& /*reader*/, bool 
/*bToolbarItem*/)
+    {
+        assert(false && "Functionality not implemented by this subclass yet.");
+        return nullptr;
+    }
+    virtual void handleTabChild(Widget* /*pParent*/, xmlreader::XmlReader& 
/*reader*/)
+    {
+        assert(false && "Functionality not implemented by this subclass yet.");
+    }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/window/builder.cxx b/vcl/source/window/builder.cxx
index 9a95b64294e3..3e1fad42fbe5 100644
--- a/vcl/source/window/builder.cxx
+++ b/vcl/source/window/builder.cxx
@@ -491,7 +491,7 @@ void BuilderBase::resetParserState() { 
m_pParserState.reset(); }
 VclBuilder::VclBuilder(vcl::Window* pParent, const OUString& sUIDir, const 
OUString& sUIFile,
                        OUString sID, css::uno::Reference<css::frame::XFrame> 
xFrame,
                        bool bLegacy, const NotebookBarAddonsItem* 
pNotebookBarAddonsItem)
-    : BuilderBase(sUIFile, bLegacy)
+    : WidgetBuilder(sUIFile, bLegacy)
     , m_pNotebookBarAddonsItem(pNotebookBarAddonsItem
                                    ? new 
NotebookBarAddonsItem(*pNotebookBarAddonsItem)
                                    : new NotebookBarAddonsItem{})
@@ -2837,78 +2837,6 @@ void VclBuilder::tweakInsertedChild(vcl::Window 
*pParent, vcl::Window* pCurrentC
     }
 }
 
-void VclBuilder::handleChild(vcl::Window *pParent, stringmap* pAtkProps, 
xmlreader::XmlReader &reader, bool bToolbarItem)
-{
-    xmlreader::Span name;
-    int nsId;
-    OString sType, sInternalChild;
-
-    while (reader.nextAttribute(&nsId, &name))
-    {
-        if (name == "type")
-        {
-            name = reader.getAttributeValue(false);
-            sType = OString(name.begin, name.length);
-        }
-        else if (name == "internal-child")
-        {
-            name = reader.getAttributeValue(false);
-            sInternalChild = OString(name.begin, name.length);
-        }
-    }
-
-    if (sType == "tab")
-    {
-        handleTabChild(pParent, reader);
-        return;
-    }
-
-    VclPtr<vcl::Window> pCurrentChild;
-    int nLevel = 1;
-    while(true)
-    {
-        xmlreader::XmlReader::Result res = reader.nextItem(
-            xmlreader::XmlReader::Text::NONE, &name, &nsId);
-
-        if (res == xmlreader::XmlReader::Result::Begin)
-        {
-            if (name == "object" || name == "placeholder")
-            {
-                pCurrentChild = handleObject(pParent, pAtkProps, reader, 
bToolbarItem);
-
-                bool bObjectInserted = pCurrentChild && pParent != 
pCurrentChild;
-                if (bObjectInserted)
-                    tweakInsertedChild(pParent, pCurrentChild, sType, 
sInternalChild);
-            }
-            else if (name == "packing")
-            {
-                const stringmap aPackingProperties = 
collectPackingProperties(reader);
-                applyPackingProperties(pCurrentChild, pParent, 
aPackingProperties);
-            }
-            else if (name == "interface")
-            {
-                while (reader.nextAttribute(&nsId, &name))
-                {
-                    if (name == "domain")
-                        handleInterfaceDomain(reader);
-                }
-                ++nLevel;
-            }
-            else
-                ++nLevel;
-        }
-
-        if (res == xmlreader::XmlReader::Result::End)
-            --nLevel;
-
-        if (!nLevel)
-            break;
-
-        if (res == xmlreader::XmlReader::Result::Done)
-            break;
-    }
-}
-
 void BuilderBase::collectPangoAttribute(xmlreader::XmlReader& reader, 
stringmap& rMap)
 {
     xmlreader::Span span;

Reply via email to