cui/source/inc/chardlg.hxx                      |    2 
 cui/source/tabpages/chardlg.cxx                 |   52 +++++++++++-------------
 vcl/Library_vclplug_qt5.mk                      |    2 
 vcl/Library_vclplug_qt6.mk                      |    2 
 vcl/inc/qt5/QtAccessibleInterimChildWidget.hxx  |   41 ++++++++++++++++++
 vcl/inc/qt5/QtAccessibleInterimParentWidget.hxx |   43 +++++++++++++++++++
 vcl/inc/qt5/QtAccessibleWidget.hxx              |   26 ++++++------
 vcl/inc/qt6/QtAccessibleInterimChildWidget.hxx  |   12 +++++
 vcl/inc/qt6/QtAccessibleInterimParentWidget.hxx |   12 +++++
 vcl/qt5/QtAccessibleInterimChildWidget.cxx      |   25 +++++++++++
 vcl/qt5/QtAccessibleInterimParentWidget.cxx     |   38 +++++++++++++++++
 vcl/qt5/QtAccessibleWidget.cxx                  |   33 +++++++++++++++
 vcl/qt5/QtInstance.cxx                          |   10 ++++
 vcl/qt6/QtAccessibleInterimChildWidget.cxx      |   12 +++++
 vcl/qt6/QtAccessibleInterimParentWidget.cxx     |   12 +++++
 15 files changed, 281 insertions(+), 41 deletions(-)

New commits:
commit f175b90aeb5758916ed0e56a8d9d7fc0791d2794
Author:     Michael Weghorn <[email protected]>
AuthorDate: Wed Feb 4 15:30:04 2026 +0100
Commit:     Michael Weghorn <[email protected]>
CommitDate: Wed Feb 4 21:45:28 2026 +0100

    cui: Return ref in SvxCharNamePage::GetFontList
    
    The method always returns a non-null FontList*.
    Return by reference instead, and drop now no longer
    nededed assert/DBG_ASSERT.
    
    Change-Id: Id2aa688b2aaef59a5fdd1669bb205bb63e508775
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198693
    Reviewed-by: Michael Weghorn <[email protected]>
    Tested-by: Jenkins

diff --git a/cui/source/inc/chardlg.hxx b/cui/source/inc/chardlg.hxx
index 3a357660bf93..e3f1240774f6 100644
--- a/cui/source/inc/chardlg.hxx
+++ b/cui/source/inc/chardlg.hxx
@@ -109,7 +109,7 @@ private:
     ScopedVclPtrInstance<VirtualDevice> m_xVDev;
 
     void                Initialize();
-    const FontList*     GetFontList() const;
+    const FontList& GetFontList() const;
     void                UpdatePreview_Impl();
     void                FillStyleBox_Impl(const weld::Widget& rBox);
     void                FillSizeBox_Impl(const weld::Widget& rBox);
diff --git a/cui/source/tabpages/chardlg.cxx b/cui/source/tabpages/chardlg.cxx
index 5507e176436f..cf36f32c01b2 100644
--- a/cui/source/tabpages/chardlg.cxx
+++ b/cui/source/tabpages/chardlg.cxx
@@ -338,7 +338,7 @@ void SvxCharNamePage::Initialize()
     m_pImpl->m_aUpdateIdle.SetInvokeHandler( LINK( this, SvxCharNamePage, 
UpdateHdl_Impl ) );
 }
 
-const FontList* SvxCharNamePage::GetFontList() const
+const FontList& SvxCharNamePage::GetFontList() const
 {
     if ( !m_pImpl->m_pFontList )
     {
@@ -358,7 +358,7 @@ const FontList* SvxCharNamePage::GetFontList() const
         }
     }
 
-    return m_pImpl->m_pFontList.get();
+    return *m_pImpl->m_pFontList;
 }
 
 
@@ -442,28 +442,28 @@ void SvxCharNamePage::UpdatePreview_Impl()
     SvxFont& rCJKFont = GetPreviewCJKFont();
     SvxFont& rCTLFont = GetPreviewCTLFont();
     // Font
-    const FontList* pFontList = GetFontList();
+    const FontList& rFontList = GetFontList();
 
     FontMetric aWestFontMetric = calcFontMetrics(rFont, this, 
m_xWestFontNameLB.get(),
         m_xWestFontStyleLB.get(), m_xWestFontSizeLB.get(), 
m_xWestFontLanguageLB.get(),
-        pFontList, GetWhich(SID_ATTR_CHAR_FONT),
+        &rFontList, GetWhich(SID_ATTR_CHAR_FONT),
         GetWhich(SID_ATTR_CHAR_FONTHEIGHT));
 
-    m_xWestFontTypeFT->set_label(pFontList->GetFontMapText(aWestFontMetric));
+    m_xWestFontTypeFT->set_label(rFontList.GetFontMapText(aWestFontMetric));
 
     FontMetric aEastFontMetric = calcFontMetrics(rCJKFont, this, 
m_xEastFontNameLB.get(),
         m_xEastFontStyleLB.get(), m_xEastFontSizeLB.get(), 
m_xEastFontLanguageLB.get(),
-        pFontList, GetWhich(SID_ATTR_CHAR_CJK_FONT),
+        &rFontList, GetWhich(SID_ATTR_CHAR_CJK_FONT),
         GetWhich(SID_ATTR_CHAR_CJK_FONTHEIGHT));
 
-    m_xEastFontTypeFT->set_label(pFontList->GetFontMapText(aEastFontMetric));
+    m_xEastFontTypeFT->set_label(rFontList.GetFontMapText(aEastFontMetric));
 
     FontMetric aCTLFontMetric = calcFontMetrics(rCTLFont,
         this, m_xCTLFontNameLB.get(), m_xCTLFontStyleLB.get(), 
m_xCTLFontSizeLB.get(),
-        m_xCTLFontLanguageLB.get(), pFontList, 
GetWhich(SID_ATTR_CHAR_CTL_FONT),
+        m_xCTLFontLanguageLB.get(), &rFontList, 
GetWhich(SID_ATTR_CHAR_CTL_FONT),
         GetWhich(SID_ATTR_CHAR_CTL_FONTHEIGHT));
 
-    m_xCTLFontTypeFT->set_label(pFontList->GetFontMapText(aCTLFontMetric));
+    m_xCTLFontTypeFT->set_label(rFontList.GetFontMapText(aCTLFontMetric));
 
     m_aPreviewWin.Invalidate();
 }
@@ -499,8 +499,7 @@ void SvxCharNamePage::EnableFeatureButton(const 
weld::Widget& rNameBox)
 
 void SvxCharNamePage::FillStyleBox_Impl(const weld::Widget& rNameBox)
 {
-    const FontList* pFontList = GetFontList();
-    assert(pFontList && "no fontlist");
+    const FontList& rFontList = GetFontList();
 
     FontStyleBox* pStyleBox = nullptr;
     OUString sFontName;
@@ -526,7 +525,7 @@ void SvxCharNamePage::FillStyleBox_Impl(const weld::Widget& 
rNameBox)
         return;
     }
 
-    pStyleBox->Fill(sFontName, pFontList);
+    pStyleBox->Fill(sFontName, &rFontList);
 
     if ( !m_pImpl->m_bInSearchMode )
         return;
@@ -535,18 +534,17 @@ void SvxCharNamePage::FillStyleBox_Impl(const 
weld::Widget& rNameBox)
     // "not bold" and "not italic"
     OUString aEntry = m_pImpl->m_aNoStyleText;
     const char sS[] = "%1";
-    aEntry = aEntry.replaceFirst( sS, pFontList->GetBoldStr() );
+    aEntry = aEntry.replaceFirst(sS, rFontList.GetBoldStr());
     m_pImpl->m_nExtraEntryPos = pStyleBox->get_count();
     pStyleBox->append_text( aEntry );
     aEntry = m_pImpl->m_aNoStyleText;
-    aEntry = aEntry.replaceFirst( sS, pFontList->GetItalicStr() );
+    aEntry = aEntry.replaceFirst(sS, rFontList.GetItalicStr());
     pStyleBox->append_text(aEntry);
 }
 
 void SvxCharNamePage::FillSizeBox_Impl(const weld::Widget& rNameBox)
 {
-    const FontList* pFontList = GetFontList();
-    DBG_ASSERT( pFontList, "no fontlist" );
+    const FontList& rFontList = GetFontList();
 
     FontSizeBox* pSizeBox = nullptr;
 
@@ -568,7 +566,7 @@ void SvxCharNamePage::FillSizeBox_Impl(const weld::Widget& 
rNameBox)
         return;
     }
 
-    pSizeBox->Fill( pFontList );
+    pSizeBox->Fill(&rFontList);
 }
 
 namespace
@@ -635,8 +633,8 @@ void SvxCharNamePage::Reset_Impl( const SfxItemSet& rSet, 
LanguageGroup eLangGrp
             break;
     }
 
-    const FontList* pFontList = GetFontList();
-    FillFontNames(*pNameBox, *pFontList);
+    const FontList& rFontList = GetFontList();
+    FillFontNames(*pNameBox, rFontList);
 
     const SvxFontItem* pFontItem = nullptr;
     SfxItemState eState = rSet.GetItemState( nWhich );
@@ -698,8 +696,8 @@ void SvxCharNamePage::Reset_Impl( const SfxItemSet& rSet, 
LanguageGroup eLangGrp
     // currently chosen font
     if ( bStyle && pFontItem )
     {
-        FontMetric aFontMetric = pFontList->Get( pFontItem->GetFamilyName(), 
eWeight, eItalic );
-        pStyleBox->set_active_text( pFontList->GetStyleName( aFontMetric ) );
+        FontMetric aFontMetric = rFontList.Get(pFontItem->GetFamilyName(), 
eWeight, eItalic);
+        pStyleBox->set_active_text(rFontList.GetStyleName(aFontMetric));
     }
     else if ( !m_pImpl->m_bInSearchMode || !bStyle )
     {
@@ -707,8 +705,8 @@ void SvxCharNamePage::Reset_Impl( const SfxItemSet& rSet, 
LanguageGroup eLangGrp
     }
     else if ( bStyle )
     {
-        FontMetric aFontMetric = pFontList->Get( OUString(), eWeight, eItalic 
);
-        pStyleBox->set_active_text( pFontList->GetStyleName( aFontMetric ) );
+        FontMetric aFontMetric = rFontList.Get(OUString(), eWeight, eItalic);
+        pStyleBox->set_active_text(rFontList.GetStyleName(aFontMetric));
     }
     if (!bStyleAvailable)
     {
@@ -793,8 +791,8 @@ void SvxCharNamePage::Reset_Impl( const SfxItemSet& rSet, 
LanguageGroup eLangGrp
             break;
     }
 
-    OUString sMapText(pFontList->GetFontMapText(
-        pFontList->Get(pNameBox->get_active_text(), 
pStyleBox->get_active_text())));
+    OUString sMapText(rFontList.GetFontMapText(
+        rFontList.Get(pNameBox->get_active_text(), 
pStyleBox->get_active_text())));
 
     switch (eLangGrp)
     {
@@ -865,12 +863,12 @@ bool SvxCharNamePage::FillItemSet_Impl( SfxItemSet& rSet, 
LanguageGroup eLangGrp
 
     bool bChanged = true;
     const OUString aFontName  = pNameBox->get_active_text();
-    const FontList* pFontList = GetFontList();
+    const FontList& rFontList = GetFontList();
     OUString aStyleBoxText = pStyleBox->get_active_text();
     int nEntryPos = pStyleBox->find_text(aStyleBoxText);
     if (nEntryPos >= m_pImpl->m_nExtraEntryPos)
         aStyleBoxText.clear();
-    FontMetric aInfo( pFontList->Get( aFontName, aStyleBoxText ) );
+    FontMetric aInfo(rFontList.Get( aFontName, aStyleBoxText));
     SvxFontItem aFontItem( aInfo.GetFamilyTypeMaybeAskConfig(), 
aInfo.GetFamilyName(), aInfo.GetStyleName(),
                            aInfo.GetPitchMaybeAskConfig(), aInfo.GetCharSet(), 
nWhich );
     pOld = GetOldItem( rSet, nSlot );
commit 848ea40b419a04bd50f2e79f5d5d7c1401ef7bb9
Author:     Michael Weghorn <[email protected]>
AuthorDate: Wed Feb 4 14:52:17 2026 +0100
Commit:     Michael Weghorn <[email protected]>
CommitDate: Wed Feb 4 21:45:21 2026 +0100

    tdf#130857 qt weld a11y: Include Qt widgets in a11y tree for interim case
    
    In case of only native Qt widgets or only vcl widgets
    being used for a window/dialog, the corresponding QWidget
    or vcl::Window a11y logic ensures that all child widgets are
    included in the a11y tree as needed.
    
    However, in the case where native Qt widgets are used inside
    of/as children of vcl widgets, i.e. the interim builder case,
    this is not the case. Neither the vcl::Window that
    hosts the QWidget tree reports the QWidget's a11y
    implementation as its child, nor does the QWidget's
    a11y implementation report the vcl::Window's a11y
    implementation as its parent, unless corresponding
    logic is implemented.
    
    This commit implements the corresponding logic for this
    to work as expected, by adding 2 new a11y implementations
    used for the Qt-based VCL plugins:
    
    * QtAccessibleInterimParentWidget is the a11y implementation
      used for the vcl widget that hosts the QWidget subtree
      and takes care of reporting the topmost QWidget as its
      (only) child.
    * QtAccessibleInterimChildWidget is the a11y implementation
      for the topmost Qt widget hosted inside the vcl
      widget and takes care of reporting the
      corresponding parent.
    
    Both of these are created in QtAccessibleWidget::customFactory.
    QtInstance::CreateInterimBuilder sets a property
    on the topmost Qt widget so that the a11y parent
    can be retrieved inside QtAccessibleWidget::customFactory.
    
    Sample scenario to test with the dialog newly supported
    since
    
        commit 4acb564b7683e9394926b3c509c904bd21a80b8d
        Author: Michael Weghorn <[email protected]>
        Date:   Tue Feb 3 15:56:17 2026 +0100
    
            tdf#130857 qt weld: Support Form Navigator
    
    :
    
    * start LO writer with the qt6 VCL plugin and
      SAL_VCL_QT_USE_WELDED_WIDGETS=1
    * "Form" -> "Form Navigator..."
    * start Accerciser and verify that all widgets
      (including the tree view) are contained in
      the dialog's a11y tree
    * For all objects, ensure that the parent/child relationship
      is correct/consistent, by selecting the object in
      Accerciser's treeview and using Accerciser's IPython console:
    
        In [46]: acc.parent.get_child_at_index(acc.get_index_in_parent()) == acc
        Out[46]: True
    
    Change-Id: I76e6b6c85c1604bd2b16d8f94e1921889b8da91a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198688
    Tested-by: Jenkins
    Reviewed-by: Michael Weghorn <[email protected]>

diff --git a/vcl/Library_vclplug_qt5.mk b/vcl/Library_vclplug_qt5.mk
index dec8ed5afadd..f8b173eb80e6 100644
--- a/vcl/Library_vclplug_qt5.mk
+++ b/vcl/Library_vclplug_qt5.mk
@@ -78,6 +78,8 @@ endif
 
 $(eval $(call gb_Library_add_exception_objects,vclplug_qt5,\
     vcl/qt5/QtAccessibleEventListener \
+    vcl/qt5/QtAccessibleInterimChildWidget \
+    vcl/qt5/QtAccessibleInterimParentWidget \
     vcl/qt5/QtAccessibleRegistry \
     vcl/qt5/QtAccessibleWidget \
     vcl/qt5/QtBitmap \
diff --git a/vcl/Library_vclplug_qt6.mk b/vcl/Library_vclplug_qt6.mk
index 7bb5302f876e..52afca3ddb07 100644
--- a/vcl/Library_vclplug_qt6.mk
+++ b/vcl/Library_vclplug_qt6.mk
@@ -77,6 +77,8 @@ endif
 
 $(eval $(call gb_Library_add_exception_objects,vclplug_qt6,\
     vcl/qt6/QtAccessibleEventListener \
+    vcl/qt6/QtAccessibleInterimChildWidget \
+    vcl/qt6/QtAccessibleInterimParentWidget \
     vcl/qt6/QtAccessibleRegistry \
     vcl/qt6/QtAccessibleWidget \
     vcl/qt6/QtBitmap \
diff --git a/vcl/inc/qt5/QtAccessibleInterimChildWidget.hxx 
b/vcl/inc/qt5/QtAccessibleInterimChildWidget.hxx
new file mode 100644
index 000000000000..9d6c19e50d03
--- /dev/null
+++ b/vcl/inc/qt5/QtAccessibleInterimChildWidget.hxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * 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 <QtWidgets/QAccessibleWidget>
+
+/**
+ * Accessibility implementation for Qt widget that is the (single) direct
+ * accessible child of a VCL widget when a native Qt widget (sub)tree is used
+ * inside vcl widgets.
+ *
+ * This is used to ensure that the vcl widget is reported as the Qt widget's
+ * accessible parent.
+ *
+ * The counterpart to ensure that the Qt widget is reported as the vcl widget's
+ * accessible child is QtAccessibleInterimParentWidget.
+ *
+ * See also QtInstance::CreateInterimBuilder.
+ */
+class QtAccessibleInterimChildWidget : public QAccessibleWidget
+{
+    QObject* const m_pParent;
+
+public:
+    static constexpr const char* PROPERTY_INTERIM_PARENT = "interim-parent";
+
+    QtAccessibleInterimChildWidget(QWidget* w, QObject* pParent,
+                                   QAccessible::Role eRole = 
QAccessible::Client,
+                                   const QString& rName = QString());
+
+    virtual QAccessibleInterface* parent() const override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/vcl/inc/qt5/QtAccessibleInterimParentWidget.hxx 
b/vcl/inc/qt5/QtAccessibleInterimParentWidget.hxx
new file mode 100644
index 000000000000..2d187ef3ee87
--- /dev/null
+++ b/vcl/inc/qt5/QtAccessibleInterimParentWidget.hxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * 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 "QtAccessibleWidget.hxx"
+
+#include <QtWidgets/QWidget>
+
+/**
+ * Accessibility implementation for the vcl widget that is the (accessible)
+ * parent of a Qt widget when a native Qt widget (sub)tree is used
+ * inside vcl widgets.
+ *
+ * This is used to ensure that the Qt widget is reported as the vcl widget's
+ * accessible child.
+ *
+ * The counterpart to ensure that the vcl widget is reported as the Qt widget's
+ * accessible parent is QtAccessibleInterimChildWidget.
+ *
+ * See also QtInstance::CreateInterimBuilder.
+ */
+class QtAccessibleInterimParentWidget : public QtAccessibleWidget
+{
+    QWidget* m_pNativeChild = nullptr;
+
+public:
+    QtAccessibleInterimParentWidget(
+        const css::uno::Reference<css::accessibility::XAccessible>& 
xAccessible, QObject& rObject,
+        QWidget* pNativeChild);
+
+    int childCount() const override;
+    QAccessibleInterface* child(int index) const override;
+    int indexOfChild(const QAccessibleInterface* pChild) const override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/vcl/inc/qt5/QtAccessibleWidget.hxx 
b/vcl/inc/qt5/QtAccessibleWidget.hxx
index f8b0f10769e2..6abc9fd0c3fa 100644
--- a/vcl/inc/qt5/QtAccessibleWidget.hxx
+++ b/vcl/inc/qt5/QtAccessibleWidget.hxx
@@ -40,24 +40,24 @@ class XAccessibleTable;
 class QtFrame;
 class QtWidget;
 
-class QtAccessibleWidget final : public QObject,
-                                 public QAccessibleInterface,
-                                 public QAccessibleActionInterface,
+class QtAccessibleWidget : public QObject,
+                           public QAccessibleInterface,
+                           public QAccessibleActionInterface,
 #ifndef Q_MOC_RUN
 #if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
-                                 public QAccessibleAttributesInterface,
+                           public QAccessibleAttributesInterface,
 #endif
 #endif
-                                 public QAccessibleTextInterface,
-                                 public QAccessibleEditableTextInterface,
+                           public QAccessibleTextInterface,
+                           public QAccessibleEditableTextInterface,
 #ifndef Q_MOC_RUN
 #if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
-                                 public QAccessibleSelectionInterface,
+                           public QAccessibleSelectionInterface,
 #endif
 #endif
-                                 public QAccessibleTableCellInterface,
-                                 public QAccessibleTableInterface,
-                                 public QAccessibleValueInterface
+                           public QAccessibleTableCellInterface,
+                           public QAccessibleTableInterface,
+                           public QAccessibleValueInterface
 {
     Q_OBJECT
 
diff --git a/vcl/inc/qt6/QtAccessibleInterimChildWidget.hxx 
b/vcl/inc/qt6/QtAccessibleInterimChildWidget.hxx
new file mode 100644
index 000000000000..7be6573672b8
--- /dev/null
+++ b/vcl/inc/qt6/QtAccessibleInterimChildWidget.hxx
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * 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 "../qt5/QtAccessibleInterimChildWidget.hxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/vcl/inc/qt6/QtAccessibleInterimParentWidget.hxx 
b/vcl/inc/qt6/QtAccessibleInterimParentWidget.hxx
new file mode 100644
index 000000000000..56ed1abd39e7
--- /dev/null
+++ b/vcl/inc/qt6/QtAccessibleInterimParentWidget.hxx
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * 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 "../qt5/QtAccessibleInterimParentWidget.hxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/vcl/qt5/QtAccessibleInterimChildWidget.cxx 
b/vcl/qt5/QtAccessibleInterimChildWidget.cxx
new file mode 100644
index 000000000000..323b785c25fc
--- /dev/null
+++ b/vcl/qt5/QtAccessibleInterimChildWidget.cxx
@@ -0,0 +1,25 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * 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 <QtAccessibleInterimChildWidget.hxx>
+
+QtAccessibleInterimChildWidget::QtAccessibleInterimChildWidget(QWidget* w, 
QObject* pParent,
+                                                               
QAccessible::Role eRole,
+                                                               const QString& 
rName)
+    : QAccessibleWidget(w, eRole, rName)
+    , m_pParent(pParent)
+{
+}
+
+QAccessibleInterface* QtAccessibleInterimChildWidget::parent() const
+{
+    return QAccessible::queryAccessibleInterface(m_pParent);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/vcl/qt5/QtAccessibleInterimParentWidget.cxx 
b/vcl/qt5/QtAccessibleInterimParentWidget.cxx
new file mode 100644
index 000000000000..46f225e60841
--- /dev/null
+++ b/vcl/qt5/QtAccessibleInterimParentWidget.cxx
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * 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 <QtAccessibleInterimParentWidget.hxx>
+
+QtAccessibleInterimParentWidget::QtAccessibleInterimParentWidget(
+    const css::uno::Reference<css::accessibility::XAccessible>& xAccessible, 
QObject& rObject,
+    QWidget* pNativeChild)
+    : QtAccessibleWidget(xAccessible, rObject)
+    , m_pNativeChild(pNativeChild)
+{
+}
+
+int QtAccessibleInterimParentWidget::childCount() const { return 1; }
+
+QAccessibleInterface* QtAccessibleInterimParentWidget::child(int index) const
+{
+    if (index == 0)
+        return QAccessible::queryAccessibleInterface(m_pNativeChild);
+
+    return nullptr;
+}
+
+int QtAccessibleInterimParentWidget::indexOfChild(const QAccessibleInterface* 
pChild) const
+{
+    if (pChild && pChild->object() == m_pNativeChild)
+        return 0;
+
+    return -1;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/vcl/qt5/QtAccessibleWidget.cxx b/vcl/qt5/QtAccessibleWidget.cxx
index 41f14ab35ad5..ee74404091df 100644
--- a/vcl/qt5/QtAccessibleWidget.cxx
+++ b/vcl/qt5/QtAccessibleWidget.cxx
@@ -23,6 +23,8 @@
 #include <QtGui/QAccessibleInterface>
 
 #include <QtAccessibleEventListener.hxx>
+#include <QtAccessibleInterimChildWidget.hxx>
+#include <QtAccessibleInterimParentWidget.hxx>
 #include <QtAccessibleRegistry.hxx>
 #include <QtFrame.hxx>
 #include <QtTools.hxx>
@@ -56,7 +58,9 @@
 #include <comphelper/AccessibleImplementationHelper.hxx>
 #include <sal/log.hxx>
 #include <vcl/accessibility/AccessibleTextAttributeHelper.hxx>
+#include <vcl/accessibility/vclxaccessiblecomponent.hxx>
 #include <vcl/qt/QtUtils.hxx>
+#include <vcl/syschild.hxx>
 
 using namespace css;
 using namespace css::accessibility;
@@ -806,6 +810,16 @@ QAccessibleInterface* 
QtAccessibleWidget::customFactory(const QString& classname
     if (!pObject)
         return nullptr;
 
+    QVariant aInterimParentProp
+        = 
pObject->property(QtAccessibleInterimChildWidget::PROPERTY_INTERIM_PARENT);
+    if (!aInterimParentProp.isNull())
+    {
+        assert(aInterimParentProp.canConvert<QObject*>());
+        QObject* pParent = aInterimParentProp.value<QObject*>();
+        assert(pObject->isWidgetType());
+        return new 
QtAccessibleInterimChildWidget(static_cast<QWidget*>(pObject), pParent);
+    }
+
     const QVariant aAccVariant = pObject->property(PROPERTY_ACCESSIBLE);
     if (aAccVariant.isValid() && aAccVariant.canConvert<QtAccessibleWidget*>())
     {
@@ -833,6 +847,25 @@ QAccessibleInterface* 
QtAccessibleWidget::customFactory(const QString& classname
         QtXAccessible* pXAccessible = static_cast<QtXAccessible*>(pObject);
         if (pXAccessible->m_xAccessible.is())
         {
+            if (VCLXAccessibleComponent* pVCLAccComponent
+                = 
dynamic_cast<VCLXAccessibleComponent*>(pXAccessible->m_xAccessible.get()))
+            {
+                VclPtr<vcl::Window> pWindow = pVCLAccComponent->GetWindow();
+                if (pWindow && pWindow->GetType() == 
WindowType::SYSTEMCHILDWINDOW)
+                {
+                    // when native Qt widgets are used inside vcl widgets, 
make sure those
+                    // are included in the a11y tree, see also 
QtInstance::CreateInterimBuilder
+                    const SystemEnvData* pEnvData
+                        = 
static_cast<SystemChildWindow*>(pWindow.get())->GetSystemData();
+                    if (QWidget* pNativeChild
+                        = pEnvData ? static_cast<QWidget*>(pEnvData->pWidget) 
: nullptr)
+                    {
+                        return new 
QtAccessibleInterimParentWidget(pXAccessible->m_xAccessible,
+                                                                   *pObject, 
pNativeChild);
+                    }
+                }
+            }
+
             QtAccessibleWidget* pRet
                 = new QtAccessibleWidget(pXAccessible->m_xAccessible, 
*pObject);
             // clear the reference in the QtXAccessible, no longer needed now 
that the QtAccessibleWidget holds one
diff --git a/vcl/qt5/QtInstance.cxx b/vcl/qt5/QtInstance.cxx
index 37786c5d7e49..0077c3acaba6 100644
--- a/vcl/qt5/QtInstance.cxx
+++ b/vcl/qt5/QtInstance.cxx
@@ -22,6 +22,8 @@
 
 #include <com/sun/star/lang/IllegalArgumentException.hpp>
 
+#include <QtAccessibleRegistry.hxx>
+#include <QtAccessibleInterimChildWidget.hxx>
 #include <QtBitmap.hxx>
 #include <QtClipboard.hxx>
 #include <QtData.hxx>
@@ -950,6 +952,14 @@ std::unique_ptr<weld::Builder> 
QtInstance::CreateInterimBuilder(vcl::Window* pPa
     assert(pEnvData);
 
     QWidget* pWidget = static_cast<QWidget*>(pEnvData->pWidget);
+
+    // set property to identify native Qt widget's a11y parent in 
QtAccessibleWidget::customFactory
+    rtl::Reference<comphelper::OAccessible> pParentAccessible = 
pEmbedWindow->GetAccessible();
+    QObject* pParentObject = 
QtAccessibleRegistry::getQObject(pParentAccessible);
+    assert(pParentObject);
+    
pWidget->setProperty(QtAccessibleInterimChildWidget::PROPERTY_INTERIM_PARENT,
+                         QVariant::fromValue(pParentObject));
+
     pWidget->show();
 
     return std::make_unique<QtInstanceBuilder>(pWidget, rUIRoot, rUIFile);
diff --git a/vcl/qt6/QtAccessibleInterimChildWidget.cxx 
b/vcl/qt6/QtAccessibleInterimChildWidget.cxx
new file mode 100644
index 000000000000..640b90278996
--- /dev/null
+++ b/vcl/qt6/QtAccessibleInterimChildWidget.cxx
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * 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 "../qt5/QtAccessibleInterimChildWidget.cxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/vcl/qt6/QtAccessibleInterimParentWidget.cxx 
b/vcl/qt6/QtAccessibleInterimParentWidget.cxx
new file mode 100644
index 000000000000..8ed4c4e7ec4f
--- /dev/null
+++ b/vcl/qt6/QtAccessibleInterimParentWidget.cxx
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * 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 "../qt5/QtAccessibleInterimParentWidget.cxx"
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
commit 2da4cc3f1a62abc0c34437dc10bb4f3a97c62075
Author:     Michael Weghorn <[email protected]>
AuthorDate: Wed Feb 4 11:46:28 2026 +0100
Commit:     Michael Weghorn <[email protected]>
CommitDate: Wed Feb 4 21:45:13 2026 +0100

    qt a11y: Move QtAccessibleWidget member vars to one place
    
    In order to improve readability, don't spread them across
    multiple places in the class declaration.
    
    Change-Id: I12be2d5d7d4a6cacf332be5eae7913e2e0ba6c7c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/198667
    Reviewed-by: Michael Weghorn <[email protected]>
    Tested-by: Jenkins

diff --git a/vcl/inc/qt5/QtAccessibleWidget.hxx 
b/vcl/inc/qt5/QtAccessibleWidget.hxx
index ce29c8af052e..f8b0f10769e2 100644
--- a/vcl/inc/qt5/QtAccessibleWidget.hxx
+++ b/vcl/inc/qt5/QtAccessibleWidget.hxx
@@ -61,6 +61,9 @@ class QtAccessibleWidget final : public QObject,
 {
     Q_OBJECT
 
+    css::uno::Reference<css::accessibility::XAccessible> m_xAccessible;
+    QObject& m_rObject;
+
 public:
     QtAccessibleWidget(const 
css::uno::Reference<css::accessibility::XAccessible>& xAccessible,
                        QObject& rObject);
@@ -197,7 +200,6 @@ public:
                                     const 
rtl::Reference<comphelper::OAccessible>& rAccessible);
 
 private:
-    css::uno::Reference<css::accessibility::XAccessible> m_xAccessible;
     css::uno::Reference<css::accessibility::XAccessibleContext> 
getAccessibleContextImpl() const;
     css::uno::Reference<css::accessibility::XAccessibleTable> 
getAccessibleTableForParent() const;
 
@@ -208,8 +210,6 @@ private:
         css::uno::Reference<Interface> xInterface(xContext, 
css::uno::UNO_QUERY);
         return xInterface.is();
     }
-
-    QObject& m_rObject;
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */

Reply via email to