include/vcl/builderbase.hxx   |    1 
 vcl/inc/qt5/QtBuilder.hxx     |    1 
 vcl/qt5/QtBuilder.cxx         |   53 ++++++++++++++++++++++++++++++++++++------
 vcl/qt5/QtInstanceBuilder.cxx |    1 
 vcl/source/window/builder.cxx |   25 +++++++++++--------
 5 files changed, 64 insertions(+), 17 deletions(-)

New commits:
commit be0d872afc8a1b7dd9d740893f9bc1b5ed94f45f
Author:     Michael Weghorn <m.wegh...@posteo.de>
AuthorDate: Fri Apr 11 10:31:09 2025 +0200
Commit:     Michael Weghorn <m.wegh...@posteo.de>
CommitDate: Fri Apr 11 19:43:49 2025 +0200

    tdf#130857 qt weld: Support Math's "Spacing" dialog
    
    Declare support for Math's "Format" -> "Spacing"
    dialog.
    
    This means that native Qt widgets are used for that dialog
    now when using the qt5 or qt6 VCL plugin and starting LO with
    environment variable SAL_VCL_QT_USE_WELDED_WIDGETS=1 set.
    
    This dialog makes use of the GtkRadioMenuItem support
    added in previous commit
    
        Change-Id: I2c9e8d2ecbef4b09a95bfb2f8057e714b984a329
        Author: Michael Weghorn <m.wegh...@posteo.de>
        Date:   Fri Apr 11 10:24:33 2025 +0200
    
            tdf#130857 qt weld: Support "GtkRadioMenuItem"
    
    Currently, the image isn't always updated when choosing
    a different category via "Category" menu button. This
    will be addressed in a separate commit.
    
    Change-Id: I3018c5a76cd863332ac8560a926105ae76327a38
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/184025
    Reviewed-by: Michael Weghorn <m.wegh...@posteo.de>
    Tested-by: Jenkins

diff --git a/vcl/qt5/QtInstanceBuilder.cxx b/vcl/qt5/QtInstanceBuilder.cxx
index 682b98b4e6ef..187f1070dea9 100644
--- a/vcl/qt5/QtInstanceBuilder.cxx
+++ b/vcl/qt5/QtInstanceBuilder.cxx
@@ -102,6 +102,7 @@ bool QtInstanceBuilder::IsUIFileSupported(const OUString& 
rUIFile)
         u"modules/smath/ui/fontsizedialog.ui"_ustr,
         u"modules/smath/ui/savedefaultsdialog.ui"_ustr,
         u"modules/smath/ui/smathsettings.ui"_ustr,
+        u"modules/smath/ui/spacingdialog.ui"_ustr,
         u"modules/spropctrlr/ui/taborder.ui"_ustr,
         u"modules/swriter/ui/authenticationsettingsdialog.ui"_ustr,
         u"modules/swriter/ui/columnwidth.ui"_ustr,
commit 5492c9bfa51ab45b936c6191066640608384c0e1
Author:     Michael Weghorn <m.wegh...@posteo.de>
AuthorDate: Fri Apr 11 10:24:33 2025 +0200
Commit:     Michael Weghorn <m.wegh...@posteo.de>
CommitDate: Fri Apr 11 19:43:42 2025 +0200

    tdf#130857 qt weld: Support "GtkRadioMenuItem"
    
    Implement support for GtkRadioMenuItem [1] menu items
    in .ui files.
    
    Reuse the logic implemented for "GtkMenuItem". In addition,
    support the "group" property which specifies what radio button
    group the item belongs to.
    For GTK, this is the ID of another GtkRadioMenuItem object.
    For Qt, use a QActionGroup. Let it be owned by the QMenu
    that  the menu items belong to, so it is deleted together with
    the menu.
    
    (The Qt concept of QActionGroup is basically the same as
    QButtonGroup for radio buttons, see also
    QtBuilder::setRadioButtonGroup.)
    
    From a quick test, VclBuilder doesn't seem to evaluate the
    "group" property, but seems to use some logic that simply
    considers adjacent radio menu items as part of the same group.
    
    This will be used by Math's "Format" -> "Spacing" dialog,
    for which support will be declared in an upcoming commit.
    
    [1] https://docs.gtk.org/gtk3/class.RadioMenuItem.html
    [2] https://docs.gtk.org/gtk3/property.RadioMenuItem.group.html
    
    Change-Id: Id0eece0eef65b8c52f77996c67662584f5665726
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/184024
    Tested-by: Jenkins
    Reviewed-by: Michael Weghorn <m.wegh...@posteo.de>

diff --git a/vcl/inc/qt5/QtBuilder.hxx b/vcl/inc/qt5/QtBuilder.hxx
index 371c2af22d17..ca469e31a622 100644
--- a/vcl/inc/qt5/QtBuilder.hxx
+++ b/vcl/inc/qt5/QtBuilder.hxx
@@ -92,6 +92,7 @@ private:
     static void setEntryProperties(QLineEdit& rLineEdit, stringmap& rProps);
     static void setLabelProperties(QLabel& rLabel, stringmap& rProps);
     static void setMessageDialogProperties(QMessageBox& rMessageBox, 
stringmap& rProps);
+    static void setMenuActionGroup(QMenu* pMenu, QAction* pAction, const 
OUString& rRadioGroupId);
     void setMenuButtonProperties(QToolButton& rButton, stringmap& rProps, 
QWidget* pParentWidget);
     void setScaleProperties(QSlider& rSlider, stringmap& rProps);
     void setSpinButtonProperties(QDoubleSpinBox& rSpinBox, stringmap& rProps);
diff --git a/vcl/qt5/QtBuilder.cxx b/vcl/qt5/QtBuilder.cxx
index 20e5c86cfd3b..7d5214f133af 100644
--- a/vcl/qt5/QtBuilder.cxx
+++ b/vcl/qt5/QtBuilder.cxx
@@ -20,7 +20,13 @@
 #include <rtl/ustrbuf.hxx>
 #include <vcl/qt/QtUtils.hxx>
 
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+#include <QtGui/QActionGroup>
+#endif
 #include <QtGui/QStandardItemModel>
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+#include <QtWidgets/QActionGroup>
+#endif
 #include <QtWidgets/QButtonGroup>
 #include <QtWidgets/QCheckBox>
 #include <QtWidgets/QComboBox>
@@ -598,20 +604,53 @@ QMenu* QtBuilder::createMenu(const OUString& rId)
     return pMenu;
 }
 
+void QtBuilder::setMenuActionGroup(QMenu* pMenu, QAction* pAction, const 
OUString& rRadioGroupId)
+{
+    // use QActionGroup owned by and set as property for the QMenu
+    QActionGroup* pActionGroup = nullptr;
+    const OString sPropertyKey = OUString(u"ACTIONGROUP::"_ustr + 
rRadioGroupId).toUtf8();
+    QVariant aVariant = pMenu->property(sPropertyKey.getStr());
+    if (aVariant.isValid())
+    {
+        assert(aVariant.canConvert<QActionGroup*>());
+        pActionGroup = aVariant.value<QActionGroup*>();
+    }
+    else
+    {
+        pActionGroup = new QActionGroup(pMenu);
+        pMenu->setProperty(sPropertyKey.getStr(), 
QVariant::fromValue(pActionGroup));
+        // insert the menu item which defines the group (whose ID matches the 
group's ID)
+        QAction* pIdAction = 
pMenu->findChild<QAction*>(toQString(rRadioGroupId));
+        assert(pIdAction && "No action with the ID that the group refers to");
+        pActionGroup->addAction(pIdAction);
+    }
+
+    pActionGroup->addAction(pAction);
+}
+
 void QtBuilder::insertMenuObject(QMenu* pParent, QMenu* pSubMenu, const 
OUString& rClass,
                                  const OUString& rID, stringmap& rProps, 
stringmap&, accelmap&)
 {
     assert(!pSubMenu && "Handling not implemented yet");
     (void)pSubMenu;
 
-    if (rClass == "GtkMenuItem")
-    {
-        const OUString sLabel = extractLabel(rProps);
-        QAction* pAction = pParent->addAction(toQString(sLabel));
-        pAction->setObjectName(toQString(rID));
+    const OUString sLabel = extractLabel(rProps);
+    QAction* pAction = pParent->addAction(toQString(sLabel));
+    pAction->setObjectName(toQString(rID));
 
-        const OUString sActionName(extractActionName(rProps));
-        QtInstanceMenu::setActionName(*pAction, sActionName);
+    const OUString sActionName(extractActionName(rProps));
+    QtInstanceMenu::setActionName(*pAction, sActionName);
+
+    if (rClass == u"GtkMenuItem")
+    {
+        // nothing else to do
+    }
+    else if (rClass == u"GtkRadioMenuItem")
+    {
+        pAction->setCheckable(true);
+        const OUString sGroup = extractGroup(rProps);
+        if (!sGroup.isEmpty())
+            setMenuActionGroup(pParent, pAction, sGroup);
     }
     else
     {
commit e61975fac8148c667374d815fb376a273f304d24
Author:     Michael Weghorn <m.wegh...@posteo.de>
AuthorDate: Fri Apr 11 09:59:47 2025 +0200
Commit:     Michael Weghorn <m.wegh...@posteo.de>
CommitDate: Fri Apr 11 19:43:36 2025 +0200

    tdf#130857 vcl: Extract BuilderBase::extractGroup helper
    
    This will allow to reuse the existing logic
    to also process the "group" property for
    GtkRadioMenuItem objects [1] in an upcoming commit
    for QtBuilder.
    
    [1] https://docs.gtk.org/gtk3/property.RadioMenuItem.group.html
    
    Change-Id: Ib0b545132dffedc5c33b34ff37d39473c6797343
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/184023
    Reviewed-by: Michael Weghorn <m.wegh...@posteo.de>
    Tested-by: Jenkins

diff --git a/include/vcl/builderbase.hxx b/include/vcl/builderbase.hxx
index 181f9461a68f..950d0922140d 100644
--- a/include/vcl/builderbase.hxx
+++ b/include/vcl/builderbase.hxx
@@ -87,6 +87,7 @@ protected:
     static void collectAccelerator(xmlreader::XmlReader& reader, accelmap& 
rMap);
     stringmap collectPackingProperties(xmlreader::XmlReader& reader);
     void collectProperty(xmlreader::XmlReader& rReader, stringmap& rMap) const;
+    static OUString extractGroup(stringmap& rMap);
     static bool extractHeadersVisible(stringmap& rMap);
     static bool extractEntry(stringmap& rMap);
     static OUString extractIconName(stringmap& rMap);
diff --git a/vcl/source/window/builder.cxx b/vcl/source/window/builder.cxx
index 0817f527d739..9103933538b7 100644
--- a/vcl/source/window/builder.cxx
+++ b/vcl/source/window/builder.cxx
@@ -1079,16 +1079,11 @@ namespace
 
 void BuilderBase::extractRadioButtonGroup(const OUString &id, stringmap &rMap)
 {
-    VclBuilder::stringmap::iterator aFind = rMap.find(u"group"_ustr);
-    if (aFind != rMap.end())
-    {
-        OUString sID = aFind->second;
-        sal_Int32 nDelim = sID.indexOf(':');
-        if (nDelim != -1)
-            sID = sID.copy(0, nDelim);
-        m_pParserState->m_aRadioButtonGroupMaps.emplace_back(id, sID);
-        rMap.erase(aFind);
-    }
+    const OUString sGroupId = extractGroup(rMap);
+    if (sGroupId.isEmpty())
+        return;
+
+    m_pParserState->m_aRadioButtonGroupMaps.emplace_back(id, sGroupId);
 }
 
 void VclBuilder::connectNumericFormatterAdjustment(const OUString &id, const 
OUString &rAdjustment)
@@ -3370,6 +3365,16 @@ bool BuilderBase::extractEntry(VclBuilder::stringmap 
&rMap)
     return extractBoolEntry(rMap, u"has-entry"_ustr, false);
 }
 
+OUString BuilderBase::extractGroup(stringmap& rMap)
+{
+    OUString sGroup = extractStringEntry(rMap, u"group"_ustr);
+    sal_Int32 nDelim = sGroup.indexOf(':');
+    if (nDelim != -1)
+        sGroup = sGroup.copy(0, nDelim);
+
+    return sGroup;
+}
+
 bool BuilderBase::extractHeadersVisible(VclBuilder::stringmap& rMap)
 {
     return extractBoolEntry(rMap, u"headers-visible"_ustr, true);

Reply via email to