include/vcl/weld/IconView.hxx       |    4 ++-
 include/vcl/weld/ItemView.hxx       |    3 ++
 sd/source/ui/sidebar/LayoutMenu.cxx |   43 +++++++++++++++++++++++++-----------
 sd/source/ui/sidebar/LayoutMenu.hxx |    3 +-
 vcl/Library_vcl.mk                  |    1 
 vcl/inc/qt5/QtInstanceIconView.hxx  |    2 -
 vcl/inc/qt5/QtInstanceItemView.hxx  |    2 +
 vcl/inc/salvtables.hxx              |    4 ++-
 vcl/qt5/QtInstanceIconView.cxx      |    2 -
 vcl/qt5/QtInstanceItemView.cxx      |    9 +++++++
 vcl/source/app/salvtables.cxx       |   17 +++++++++-----
 vcl/source/weld/IconView.cxx        |   23 +++++++++++++++++++
 vcl/unx/gtk3/gtkinst.cxx            |   27 +++++++++++++++++-----
 13 files changed, 110 insertions(+), 30 deletions(-)

New commits:
commit 39eacfffbdedfc0e19cf6b46e7dc30720041dcbb
Author:     Michael Weghorn <[email protected]>
AuthorDate: Wed Dec 17 17:38:37 2025 +0100
Commit:     Michael Weghorn <[email protected]>
CommitDate: Thu Dec 18 07:21:20 2025 +0100

    sd a11y: Allow opening "Layout" context menu using keyboard
    
    So far, the context menu for the currently selected
    layout in the Impress "Layout" sidebar section could
    only be opened using the mouse, not the keyboard.
    
    Make both cases work, by implementing a command
    handler that handles the CommandId::ContextMenu
    case instead of a mouse event handler.
    
    If the context menu was opened using the keyboard,
    use the center of the currently selected item's
    rect as the position for the context menu.
    
    To trigger this:
    
    * start Impress
    * open the "Properties" sidebar panel
    * in the "Layouts" section, move between layouts
      using the keyboard
    * press the context menu key (or Shift+F10) to
      open the context menu for the currently selected
      item
    
    This makes use of the new method introduced in
    previous commit
    
        Change-Id: Icac5e42196e8c490cc95131508d427e87d1bcb57
        Author: Michael Weghorn <[email protected]>
        Date:   Wed Dec 17 17:15:08 2025 +0100
    
            weld: Add weld::IconView::get_rect taking iter param
    
    Change-Id: Iaae1b413b3b237f22c05d389f5960e1ae72a99e8
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195803
    Tested-by: Jenkins
    Reviewed-by: Michael Weghorn <[email protected]>

diff --git a/sd/source/ui/sidebar/LayoutMenu.cxx 
b/sd/source/ui/sidebar/LayoutMenu.cxx
index 9732ad120011..9b2a93a98977 100644
--- a/sd/source/ui/sidebar/LayoutMenu.cxx
+++ b/sd/source/ui/sidebar/LayoutMenu.cxx
@@ -152,7 +152,7 @@ void LayoutMenu::implConstruct( DrawDocShell& 
rDocumentShell )
     (void) rDocumentShell;
 
     mxLayoutIconView->connect_item_activated(LINK(this, LayoutMenu, 
LayoutSelected));
-    mxLayoutIconView->connect_mouse_press(LINK(this, LayoutMenu, 
MousePressHdl));
+    mxLayoutIconView->connect_command(LINK(this, LayoutMenu, CommandHdl));
     InvalidateContent();
 
     Link<::sdtools::EventMultiplexerEvent&,void> aEventListenerLink 
(LINK(this,LayoutMenu,EventMultiplexerListener));
@@ -225,25 +225,42 @@ ui::LayoutSize LayoutMenu::GetHeightForWidth (const 
sal_Int32 nWidth)
     return css::ui::LayoutSize(nPreferredHeight, nPreferredHeight, 
nPreferredHeight);
 }
 
-IMPL_LINK(LayoutMenu, MousePressHdl, const MouseEvent&, rMEvet, bool)
+IMPL_LINK(LayoutMenu, CommandHdl, const CommandEvent&, rEvent, bool)
 {
-    if (!rMEvet.IsRight())
+    if (rEvent.GetCommand() != CommandEventId::ContextMenu)
         return false;
 
-    const Point& pPos = rMEvet.GetPosPixel();
-    for (int i = 0; i < mxLayoutIconView->n_children(); i++)
+    Point aPos;
+    if (rEvent.IsMouseEvent())
     {
-        const ::tools::Rectangle aRect = mxLayoutIconView->get_rect(i);
-        if (aRect.Contains(pPos))
+        aPos = rEvent.GetMousePosPixel();
+        bool bFound = false;
+        for (int i = 0; i < mxLayoutIconView->n_children(); i++)
         {
-            bInContextMenuOperation = true;
-            mxLayoutIconView->select(i);
-            ShowContextMenu(pPos);
-            bInContextMenuOperation = false;
-            break;
+            const ::tools::Rectangle aRect = mxLayoutIconView->get_rect(i);
+            if (aRect.Contains(aPos))
+            {
+                mxLayoutIconView->select(i);
+                bFound = true;
+                break;
+            }
         }
+        if (!bFound)
+            return false;
+    }
+    else
+    {
+        std::unique_ptr<weld::TreeIter> pSelected = 
mxLayoutIconView->make_iterator();
+        if (!mxLayoutIconView->get_selected(pSelected.get()))
+            return false;
+        aPos = mxLayoutIconView->get_rect(*pSelected).Center();
     }
-    return false;
+
+    bInContextMenuOperation = true;
+    ShowContextMenu(aPos);
+    bInContextMenuOperation = false;
+
+    return true;
 }
 
 void LayoutMenu::InsertPageWithLayout (AutoLayout aLayout)
diff --git a/sd/source/ui/sidebar/LayoutMenu.hxx 
b/sd/source/ui/sidebar/LayoutMenu.hxx
index 74b9e860db3c..0a50f9a8cb38 100644
--- a/sd/source/ui/sidebar/LayoutMenu.hxx
+++ b/sd/source/ui/sidebar/LayoutMenu.hxx
@@ -162,7 +162,8 @@ private:
     /** When clicked then set the current page of the view in the center pane.
     */
     DECL_LINK(LayoutSelected, weld::IconView&, bool);
-    DECL_LINK(MousePressHdl, const MouseEvent&, bool);
+    DECL_LINK(CommandHdl, const CommandEvent&, bool);
+
     DECL_LINK(StateChangeHandler, const OUString&, void);
     DECL_LINK(EventMultiplexerListener, ::sdtools::EventMultiplexerEvent&, 
void);
     DECL_LINK(MenuSelectAsyncHdl, void*, void);
commit 3e0e0429aab01faafeb4faccbb5aa2800cbd9315
Author:     Michael Weghorn <[email protected]>
AuthorDate: Wed Dec 17 17:15:08 2025 +0100
Commit:     Michael Weghorn <[email protected]>
CommitDate: Thu Dec 18 07:21:13 2025 +0100

    weld: Add weld::IconView::get_rect taking iter param
    
    Change the virtual weld::IconView::get_rect param from
    an index/position to a weld::TreeIter and implement
    that one in the toolkit-specific implementations.
    
    For the existing variant taking an index, implement
    it directly in the weld::IconView base class instead,
    by converting the index to a iterator and calling
    the variant taking an iterator.
    
    This makes use of the method introduced in previous commit
    
        Change-Id: I6c09044ba50556dd57fdc7bce399ba334efeada9
        Author: Michael Weghorn <[email protected]>
        Date:   Wed Dec 17 16:47:31 2025 +0100
    
            weld: Add method to get ItemView iter for position
    
    , see also that commit's commit message for more background.
    
    Other methods could be converted/deduplicated in a similar
    way, e.g. various weld::TreeView ones that currently have custom
    toolkit-specific implementations for both variants.
    
    No change intended or seen e.g. for the following use
    case that makes use of the index-based method
    (see LayoutMenu::MousePressHdl):
    
    * start Impress
    * open the "Properties" sidebar panel
    * in the "Layouts" section, right-click one of
      the layouts to open the context menu for the
      given layout
    
    The new iterator-based method will be used in an
    upcoming commit to implement logic to also allow
    opening the menu using the keyboard (by pressing
    the context menu key when one of the IconView items
    has focus).
    
    Change-Id: Icac5e42196e8c490cc95131508d427e87d1bcb57
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195802
    Reviewed-by: Michael Weghorn <[email protected]>
    Tested-by: Jenkins

diff --git a/include/vcl/weld/IconView.hxx b/include/vcl/weld/IconView.hxx
index 41cf3667f2a5..f2ae0010dff3 100644
--- a/include/vcl/weld/IconView.hxx
+++ b/include/vcl/weld/IconView.hxx
@@ -156,9 +156,11 @@ public:
         enable_notify_events();
     }
 
-    virtual tools::Rectangle get_rect(int pos) const = 0;
+    tools::Rectangle get_rect(int pos) const;
 
     //via iter
+    virtual tools::Rectangle get_rect(const TreeIter& rIter) const = 0;
+
     void set_cursor(const TreeIter& rIter)
     {
         disable_notify_events();
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index df79327f38cc..21edbbcb515e 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -582,6 +582,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
     vcl/source/uitest/uitest \
     vcl/source/uitest/uno/uiobject_uno \
     vcl/source/uitest/uno/uitest_uno \
+    vcl/source/weld/IconView \
     vcl/source/weld/ItemView \
     vcl/source/weld/weldutils \
     vcl/backendtest/outputdevice/bitmap \
diff --git a/vcl/inc/qt5/QtInstanceIconView.hxx 
b/vcl/inc/qt5/QtInstanceIconView.hxx
index 925e5ba94454..cd99b165d2f0 100644
--- a/vcl/inc/qt5/QtInstanceIconView.hxx
+++ b/vcl/inc/qt5/QtInstanceIconView.hxx
@@ -53,7 +53,7 @@ public:
     virtual void set_item_accessible_name(int nPos, const OUString& rName) 
override;
     virtual void set_item_tooltip_text(int nPos, const OUString& rToolTip) 
override;
     virtual void do_remove(int pos) override;
-    virtual tools::Rectangle get_rect(int pos) const override;
+    virtual tools::Rectangle get_rect(const weld::TreeIter& rIter) const 
override;
 
     virtual bool get_selected(weld::TreeIter* pIter) const override;
     virtual bool get_cursor(weld::TreeIter* pIter) const override;
diff --git a/vcl/inc/salvtables.hxx b/vcl/inc/salvtables.hxx
index ece96df091b8..510857561bbe 100644
--- a/vcl/inc/salvtables.hxx
+++ b/vcl/inc/salvtables.hxx
@@ -1984,7 +1984,7 @@ public:
 
     virtual OUString get_text(const weld::TreeIter& rIter) const override;
 
-    virtual tools::Rectangle get_rect(int pos) const override;
+    virtual tools::Rectangle get_rect(const weld::TreeIter& rIter) const 
override;
 
     virtual ~SalInstanceIconView() override;
 };
diff --git a/vcl/qt5/QtInstanceIconView.cxx b/vcl/qt5/QtInstanceIconView.cxx
index 66dc3220ca04..8b4e6e2b5ece 100644
--- a/vcl/qt5/QtInstanceIconView.cxx
+++ b/vcl/qt5/QtInstanceIconView.cxx
@@ -202,7 +202,7 @@ void QtInstanceIconView::set_item_tooltip_text(int nPos, 
const OUString& rToolTi
 
 void QtInstanceIconView::do_remove(int) { assert(false && "Not implemented 
yet"); }
 
-tools::Rectangle QtInstanceIconView::get_rect(int) const
+tools::Rectangle QtInstanceIconView::get_rect(const weld::TreeIter&) const
 {
     assert(false && "Not implemented yet");
     return tools::Rectangle();
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index cb1b4ca541ca..7c367961a103 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -5602,13 +5602,10 @@ void SalInstanceIconView::set_item_tooltip_text(int 
pos, const OUString& rToolTi
     pEntry->SetToolTip(rToolTip);
 }
 
-tools::Rectangle SalInstanceIconView::get_rect(int pos) const
+tools::Rectangle SalInstanceIconView::get_rect(const weld::TreeIter& rIter) 
const
 {
-    SvTreeListEntry* aEntry = m_xIconView->GetEntry(nullptr, pos);
-    if (aEntry == nullptr)
-        return tools::Rectangle();
-
-    return m_xIconView->GetBoundingRect(aEntry);
+    const SalInstanceTreeIter& rVclIter = static_cast<const 
SalInstanceTreeIter&>(rIter);
+    return m_xIconView->GetBoundingRect(rVclIter.iter);
 }
 
 SalInstanceIconView::~SalInstanceIconView()
diff --git a/vcl/source/weld/IconView.cxx b/vcl/source/weld/IconView.cxx
new file mode 100644
index 000000000000..810b700c4e45
--- /dev/null
+++ b/vcl/source/weld/IconView.cxx
@@ -0,0 +1,23 @@
+/* -*- 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 <vcl/weld/IconView.hxx>
+
+namespace weld
+{
+tools::Rectangle IconView::get_rect(int pos) const
+{
+    if (std::unique_ptr<weld::TreeIter> pIter = get_iterator(pos))
+        return get_rect(*pIter);
+
+    return {};
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx
index fb5d99b3d4f8..44e86f527967 100644
--- a/vcl/unx/gtk3/gtkinst.cxx
+++ b/vcl/unx/gtk3/gtkinst.cxx
@@ -16842,14 +16842,10 @@ private:
         return sRet;
     }
 
-    tools::Rectangle get_rect(int pos) const override
+    tools::Rectangle get_rect(const weld::TreeIter& rIter) const override
     {
-        GtkTreeModel* pModel = GTK_TREE_MODEL(m_pTreeStore);
-        GtkTreeIter rIter;
-        if (!gtk_tree_model_iter_nth_child(pModel, &rIter, nullptr, pos))
-            return tools::Rectangle();
-
         const GtkInstanceTreeIter& rGtkIter = static_cast<const 
GtkInstanceTreeIter&>(rIter);
+        GtkTreeModel* pModel = GTK_TREE_MODEL(m_pTreeStore);
         GtkTreePath* path
             = gtk_tree_model_get_path(pModel, 
const_cast<GtkTreeIter*>(&rGtkIter.iter));
 
commit 02b66aa3fd4e798d6ac2a3d1ed0c7a0bdee00de4
Author:     Michael Weghorn <[email protected]>
AuthorDate: Wed Dec 17 16:47:31 2025 +0100
Commit:     Michael Weghorn <[email protected]>
CommitDate: Thu Dec 18 07:21:06 2025 +0100

    weld: Add method to get ItemView iter for position
    
    Introduce weld::ItemView::get_iterator that returns
    a weld::TreeIter pointing to the item at the
    given position/index if the position is valid, otherwise
    a unique_ptr not owning anything.
    
    This can be used in upcoming commits to unify the
    iter-based and index-based methods in the weld::ItemView
    subclasses (weld::TreeView, weld::IconView) or easily
    provide both variants without having to implement
    the whole logic twice in every implementation.
    (If the gtk, vcl and qt implementations provide an
    iter-based implementation, the abstract base class
    can implement the index-based one itself, by converting
    the index to an iter and calling the variant taking
    an iter.)
    
    Change-Id: I6c09044ba50556dd57fdc7bce399ba334efeada9
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195801
    Tested-by: Jenkins
    Reviewed-by: Michael Weghorn <[email protected]>

diff --git a/include/vcl/weld/ItemView.hxx b/include/vcl/weld/ItemView.hxx
index 5366bf1007a7..45efb333fcb8 100644
--- a/include/vcl/weld/ItemView.hxx
+++ b/include/vcl/weld/ItemView.hxx
@@ -22,6 +22,9 @@ protected:
 
 public:
     virtual std::unique_ptr<TreeIter> make_iterator(const TreeIter* pOrig = 
nullptr) const = 0;
+
+    virtual std::unique_ptr<TreeIter> get_iterator(int nPos) const = 0;
+
     virtual bool get_selected(TreeIter* pIter) const = 0;
     virtual bool get_cursor(TreeIter* pIter) const = 0;
 
diff --git a/vcl/inc/qt5/QtInstanceItemView.hxx 
b/vcl/inc/qt5/QtInstanceItemView.hxx
index 927ce329d259..5f13195b8eb9 100644
--- a/vcl/inc/qt5/QtInstanceItemView.hxx
+++ b/vcl/inc/qt5/QtInstanceItemView.hxx
@@ -32,6 +32,8 @@ public:
     virtual std::unique_ptr<weld::TreeIter> make_iterator(const 
weld::TreeIter* pOrig
                                                           = nullptr) const 
override;
 
+    virtual std::unique_ptr<weld::TreeIter> get_iterator(int nPos) const 
override;
+
 protected:
     QModelIndex modelIndex(int nRow, int nCol = 0,
                            const QModelIndex& rParentIndex = QModelIndex()) 
const;
diff --git a/vcl/inc/salvtables.hxx b/vcl/inc/salvtables.hxx
index bcbc43485956..ece96df091b8 100644
--- a/vcl/inc/salvtables.hxx
+++ b/vcl/inc/salvtables.hxx
@@ -1498,6 +1498,8 @@ protected:
 public:
     virtual std::unique_ptr<weld::TreeIter> make_iterator(const 
weld::TreeIter* pOrig
                                                           = nullptr) const 
override;
+
+    virtual std::unique_ptr<weld::TreeIter> get_iterator(int nPos) const 
override;
 };
 
 class SalInstanceTreeView : public SalInstanceItemView, public virtual 
weld::TreeView
diff --git a/vcl/qt5/QtInstanceItemView.cxx b/vcl/qt5/QtInstanceItemView.cxx
index fa19b30bc10b..d9c72c7e8fa3 100644
--- a/vcl/qt5/QtInstanceItemView.cxx
+++ b/vcl/qt5/QtInstanceItemView.cxx
@@ -22,6 +22,15 @@ std::unique_ptr<weld::TreeIter> 
QtInstanceItemView::make_iterator(const weld::Tr
     return std::make_unique<QtInstanceTreeIter>(aIndex);
 }
 
+std::unique_ptr<weld::TreeIter> QtInstanceItemView::get_iterator(int nPos) 
const
+{
+    const QModelIndex aIndex = modelIndex(nPos);
+    if (aIndex.isValid())
+        return std::make_unique<QtInstanceTreeIter>(aIndex);
+
+    return {};
+}
+
 void QtInstanceItemView::do_clear()
 {
     SolarMutexGuard g;
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index e56ff6961d5b..cb1b4ca541ca 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -3524,6 +3524,14 @@ SalInstanceItemView::make_iterator(const weld::TreeIter* 
pOrig) const
         new SalInstanceTreeIter(static_cast<const 
SalInstanceTreeIter*>(pOrig)));
 }
 
+std::unique_ptr<weld::TreeIter> SalInstanceItemView::get_iterator(int nPos) 
const
+{
+    if (SvTreeListEntry* pEntry = m_pTreeListBox->GetEntry(nPos))
+        return std::make_unique<SalInstanceTreeIter>(pEntry);
+
+    return {};
+}
+
 void SalInstanceItemView::do_clear()
 {
     m_pTreeListBox->Clear();
diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx
index 9edda284a070..fb5d99b3d4f8 100644
--- a/vcl/unx/gtk3/gtkinst.cxx
+++ b/vcl/unx/gtk3/gtkinst.cxx
@@ -15776,6 +15776,15 @@ public:
         rGtkDest.iter = rGtkSource.iter;
     }
 
+    virtual std::unique_ptr<weld::TreeIter> get_iterator(int nPos) const 
override
+    {
+        GtkTreeIter iter;
+        if (gtk_tree_model_iter_nth_child(m_pTreeModel, &iter, nullptr, nPos))
+            return std::make_unique<GtkInstanceTreeIter>(iter);
+
+        return {};
+    }
+
     virtual bool get_selected(weld::TreeIter* pIter) const override
     {
         GtkInstanceTreeIter* pGtkIter = 
static_cast<GtkInstanceTreeIter*>(pIter);
@@ -16985,6 +16994,16 @@ public:
         m_nIdCol = std::max(m_nTextCol, m_nImageCol) + 1;
     }
 
+    virtual std::unique_ptr<weld::TreeIter> get_iterator(int nPos) const 
override
+    {
+        GtkTreeModel* pModel = GTK_TREE_MODEL(m_pTreeStore);
+        GtkTreeIter iter;
+        if (gtk_tree_model_iter_nth_child(pModel, &iter, nullptr, nPos))
+            return std::make_unique<GtkInstanceTreeIter>(iter);
+
+        return {};
+    }
+
     virtual int get_item_width() const override
     {
         return gtk_icon_view_get_item_width(m_pIconView);

Reply via email to