cui/source/inc/numpages.hxx                          |    8 -
 cui/source/tabpages/numpages.cxx                     |   78 +++++++++++++------
 cui/uiconfig/ui/pickgraphicpage.ui                   |   42 +++++-----
 include/svx/svxbmpnumiconview.hxx                    |    3 
 svx/source/dialog/svxbmpnumiconview.cxx              |   71 +++++++++++++++++
 sw/qa/uitest/writer_tests2/formatBulletsNumbering.py |   18 ++--
 6 files changed, 168 insertions(+), 52 deletions(-)

New commits:
commit 1d53216a54453f07c45738daadb47db84c4870cc
Author:     Parth Raiyani <[email protected]>
AuthorDate: Mon Aug 25 20:57:56 2025 +0530
Commit:     Szymon Kłos <[email protected]>
CommitDate: Fri Sep 12 17:11:38 2025 +0200

    Switch to IconView from ValueSet for pick graphic page
    
    - Replaced SvxNumValueSet with weld::IconView in numpages
    - Updated UI in pickgraphicpage.ui to include GtkIconView and GtkTreeStore
    - added tooltip support
    - updated relevant test cases
    
    Change-Id: Ib6b1b0bcca18edc18668dd977b34397a6d86b4bc
    Signed-off-by: Parth Raiyani <[email protected]>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/189849
    Reviewed-by: Szymon Kłos <[email protected]>
    Tested-by: Jenkins CollaboraOffice <[email protected]>

diff --git a/cui/source/inc/numpages.hxx b/cui/source/inc/numpages.hxx
index 66bae32e71d2..35d26bfc929f 100644
--- a/cui/source/inc/numpages.hxx
+++ b/cui/source/inc/numpages.hxx
@@ -178,11 +178,11 @@ class SvxBitmapPickTabPage final : public SfxTabPage
 
     std::unique_ptr<weld::Label> m_xErrorText;
     std::unique_ptr<weld::Button> m_xBtBrowseFile;
-    std::unique_ptr<SvxBmpNumValueSet> m_xExamplesVS;
-    std::unique_ptr<weld::CustomWeld> m_xExamplesVSWin;
+    std::unique_ptr<weld::IconView> m_xExamplesIV;
 
-    DECL_LINK(NumSelectHdl_Impl, ValueSet*, void);
-    DECL_LINK(DoubleClickHdl_Impl, ValueSet*, void);
+    DECL_LINK(NumSelectHdl_Impl, weld::IconView&, void);
+    DECL_LINK(DoubleClickHdl_Impl, weld::IconView&, bool);
+    DECL_LINK(QueryTooltipHdl, const weld::TreeIter&, OUString);
     DECL_LINK(ClickAddBrowseHdl_Impl, weld::Button&, void);
 
 public:
diff --git a/cui/source/tabpages/numpages.cxx b/cui/source/tabpages/numpages.cxx
index b1f1cc894a4c..618249000715 100644
--- a/cui/source/tabpages/numpages.cxx
+++ b/cui/source/tabpages/numpages.cxx
@@ -859,14 +859,15 @@ 
SvxBitmapPickTabPage::SvxBitmapPickTabPage(weld::Container* pPage, weld::DialogC
     , bPreset(false)
     , m_xErrorText(m_xBuilder->weld_label(u"errorft"_ustr))
     , m_xBtBrowseFile(m_xBuilder->weld_button(u"browseBtn"_ustr))
-    , m_xExamplesVS(new 
SvxBmpNumValueSet(m_xBuilder->weld_scrolled_window(u"valuesetwin"_ustr, true)))
-    , m_xExamplesVSWin(new weld::CustomWeld(*m_xBuilder, u"valueset"_ustr, 
*m_xExamplesVS))
+    , m_xExamplesIV(m_xBuilder->weld_icon_view(u"pick_graphic_iconview"_ustr))
 {
     SetExchangeSupport();
 
-    m_xExamplesVS->init();
-    m_xExamplesVS->SetSelectHdl(LINK(this, SvxBitmapPickTabPage, 
NumSelectHdl_Impl));
-    m_xExamplesVS->SetDoubleClickHdl(LINK(this, SvxBitmapPickTabPage, 
DoubleClickHdl_Impl));
+    GalleryExplorer::BeginLocking(GALLERY_THEME_BULLETS);
+    SvxBmpNumIconView::PopulateBitmapIconView(m_xExamplesIV.get());
+    m_xExamplesIV->connect_selection_changed(LINK(this, SvxBitmapPickTabPage, 
NumSelectHdl_Impl));
+    m_xExamplesIV->connect_item_activated(LINK(this, SvxBitmapPickTabPage, 
DoubleClickHdl_Impl));
+    m_xExamplesIV->connect_query_tooltip(LINK(this, SvxBitmapPickTabPage, 
QueryTooltipHdl));
     m_xBtBrowseFile->connect_clicked(LINK(this, SvxBitmapPickTabPage, 
ClickAddBrowseHdl_Impl));
 
     if(comphelper::LibreOfficeKit::isActive())
@@ -880,7 +881,7 @@ SvxBitmapPickTabPage::SvxBitmapPickTabPage(weld::Container* 
pPage, weld::DialogC
     size_t i = 0;
     for (auto & grfName : aGrfNames)
     {
-        m_xExamplesVS->InsertItem( i + 1, i);
+        VclPtr<VirtualDevice> pVDev = 
SvxBmpNumIconView::CreateBitmapBulletPreview(i);
 
         INetURLObject aObj(grfName);
         if (aObj.GetProtocol() == INetProtocol::File)
@@ -890,7 +891,8 @@ SvxBitmapPickTabPage::SvxBitmapPickTabPage(weld::Container* 
pPage, weld::DialogC
             grfName = 
aObj.GetLastName(INetURLObject::DecodeMechanism::Unambiguous);
         }
 
-        m_xExamplesVS->SetItemText( i + 1, grfName );
+        OUString sId = OUString::number(i);
+        m_xExamplesIV->insert(-1, &grfName, &sId, pVDev, nullptr);
         ++i;
     }
 
@@ -900,16 +902,14 @@ 
SvxBitmapPickTabPage::SvxBitmapPickTabPage(weld::Container* pPage, weld::DialogC
     }
     else
     {
-        m_xExamplesVS->Show();
-        m_xExamplesVS->SetFormat();
-        m_xExamplesVS->Invalidate();
+        m_xExamplesIV->show();
     }
 }
 
 SvxBitmapPickTabPage::~SvxBitmapPickTabPage()
 {
-    m_xExamplesVSWin.reset();
-    m_xExamplesVS.reset();
+    GalleryExplorer::EndLocking(GALLERY_THEME_BULLETS);
+    m_xExamplesIV.reset();
 }
 
 std::unique_ptr<SfxTabPage> SvxBitmapPickTabPage::Create(weld::Container* 
pPage, weld::DialogController* pController,
@@ -937,14 +937,14 @@ void  SvxBitmapPickTabPage::ActivatePage(const 
SfxItemSet& rSet)
     if(pActNum && *pSaveNum != *pActNum)
     {
         *pActNum = *pSaveNum;
-        m_xExamplesVS->SetNoSelection();
+        m_xExamplesIV->unselect_all();
     }
 
     if(!aGrfNames.empty() &&
         (pActNum && (!lcl_IsNumFmtSet(pActNum.get(), nActNumLvl) || 
bIsPreset)))
     {
-        m_xExamplesVS->SelectItem(1);
-        NumSelectHdl_Impl(m_xExamplesVS.get());
+        m_xExamplesIV->select(0);
+        NumSelectHdl_Impl(*m_xExamplesIV);
         bPreset = true;
     }
     bPreset |= bIsPreset;
@@ -998,14 +998,39 @@ void  SvxBitmapPickTabPage::Reset( const SfxItemSet* rSet 
)
         *pActNum = *pSaveNum;
 }
 
-IMPL_LINK_NOARG(SvxBitmapPickTabPage, NumSelectHdl_Impl, ValueSet*, void)
+IMPL_LINK(SvxBitmapPickTabPage, QueryTooltipHdl, const weld::TreeIter&, rIter, 
OUString)
+{
+    const OUString sId = m_xExamplesIV->get_id(rIter);
+    if (sId.isEmpty())
+        return OUString();
+
+    sal_Int32 nIndex = sId.toInt32();
+
+    if (nIndex >= 0 && nIndex < static_cast<sal_Int32>(aGrfNames.size()))
+    {
+        OUString sImageName = aGrfNames[nIndex];
+        INetURLObject aObj(sImageName);
+        if (aObj.GetProtocol() == INetProtocol::File)
+        {
+            aObj.removeExtension();
+            sImageName = 
aObj.GetLastName(INetURLObject::DecodeMechanism::Unambiguous);
+        }
+
+        return sImageName;
+    }
+
+    return OUString();
+}
+
+IMPL_LINK_NOARG(SvxBitmapPickTabPage, NumSelectHdl_Impl, weld::IconView&, void)
 {
     if(!pActNum)
         return;
 
     bPreset = false;
     bModified = true;
-    sal_uInt16 nIdx = m_xExamplesVS->GetSelectedItemId() - 1;
+    OUString sId = m_xExamplesIV->get_selected_id();
+    sal_uInt16 nIdx = !sId.isEmpty() ? sId.toInt32() : 0;
 
     sal_uInt16 nMask = 1;
     for(sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
@@ -1034,11 +1059,16 @@ IMPL_LINK_NOARG(SvxBitmapPickTabPage, 
NumSelectHdl_Impl, ValueSet*, void)
     }
 }
 
-IMPL_LINK_NOARG(SvxBitmapPickTabPage, DoubleClickHdl_Impl, ValueSet*, void)
+IMPL_LINK_NOARG(SvxBitmapPickTabPage, DoubleClickHdl_Impl, weld::IconView&, 
bool)
 {
-    NumSelectHdl_Impl(m_xExamplesVS.get());
+    if(m_xExamplesIV->get_selected_id().isEmpty())
+        return false;
+
+    NumSelectHdl_Impl(*m_xExamplesIV);
     weld::Button& rOk = GetDialogController()->GetOKButton();
     rOk.clicked();
+
+    return true;
 }
 
 IMPL_LINK_NOARG(SvxBitmapPickTabPage, ClickAddBrowseHdl_Impl, weld::Button&, 
void)
@@ -1117,7 +1147,8 @@ IMPL_LINK_NOARG(SvxBitmapPickTabPage, 
ClickAddBrowseHdl_Impl, weld::Button&, voi
     size_t i = 0;
     for (auto & grfName : aGrfNames)
     {
-        m_xExamplesVS->InsertItem( i + 1, i);
+        VclPtr<VirtualDevice> pVDev = 
SvxBmpNumIconView::CreateBitmapBulletPreview(i);
+
         INetURLObject aObj(grfName);
         if (aObj.GetProtocol() == INetProtocol::File)
         {
@@ -1125,7 +1156,9 @@ IMPL_LINK_NOARG(SvxBitmapPickTabPage, 
ClickAddBrowseHdl_Impl, weld::Button&, voi
             aObj.removeExtension();
             grfName = 
aObj.GetLastName(INetURLObject::DecodeMechanism::Unambiguous);
         }
-        m_xExamplesVS->SetItemText( i + 1, grfName );
+
+        OUString sId = OUString::number(i);
+        m_xExamplesIV->insert(-1, &grfName, &sId, pVDev, nullptr);
         ++i;
     }
 
@@ -1135,8 +1168,7 @@ IMPL_LINK_NOARG(SvxBitmapPickTabPage, 
ClickAddBrowseHdl_Impl, weld::Button&, voi
     }
     else
     {
-        m_xExamplesVS->Show();
-        m_xExamplesVS->SetFormat();
+        m_xExamplesIV->show();
     }
 }
 
diff --git a/cui/uiconfig/ui/pickgraphicpage.ui 
b/cui/uiconfig/ui/pickgraphicpage.ui
index ea7342844a14..234c2e2ec17a 100644
--- a/cui/uiconfig/ui/pickgraphicpage.ui
+++ b/cui/uiconfig/ui/pickgraphicpage.ui
@@ -2,6 +2,14 @@
 <!-- Generated with glade 3.40.0 -->
 <interface domain="cui">
   <requires lib="gtk+" version="3.20"/>
+  <object class="GtkTreeStore" id="liststore1">
+    <columns>
+      <!-- column-name pixbuf -->
+      <column type="GdkPixbuf"/>
+      <!-- column-name id -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
   <!-- n-columns=2 n-rows=3 -->
   <object class="GtkGrid" id="PickGraphicPage">
     <property name="visible">True</property>
@@ -14,7 +22,7 @@
     <property name="vexpand">True</property>
     <property name="row-spacing">6</property>
     <child>
-      <object class="GtkScrolledWindow" id="valuesetwin">
+      <object class="GtkScrolledWindow">
         <property name="visible">True</property>
         <property name="can-focus">True</property>
         <property name="hexpand">True</property>
@@ -22,28 +30,26 @@
         <property name="hscrollbar-policy">never</property>
         <property name="shadow-type">in</property>
         <child>
-          <object class="GtkViewport">
+          <object class="GtkIconView" id="pick_graphic_iconview">
             <property name="visible">True</property>
-            <property name="can-focus">False</property>
-            <child>
-              <object class="GtkDrawingArea" id="valueset">
-                <property name="visible">True</property>
-                <property name="can-focus">True</property>
-                <property name="events">GDK_BUTTON_PRESS_MASK | 
GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | 
GDK_STRUCTURE_MASK</property>
-                <property name="hexpand">True</property>
-                <property name="vexpand">True</property>
-                <child internal-child="accessible">
-                  <object class="AtkObject" id="valueset-atkobject">
-                    <property name="AtkObject::accessible-description" 
translatable="yes" context="pickgraphicpage|extended_tip|valueset">Click the 
graphics that you want to use as bullets.</property>
-                  </object>
-                </child>
+            <property name="can-focus">True</property>
+            <property name="hexpand">True</property>
+            <property name="vexpand">True</property>
+            <property name="model">liststore1</property>
+            <property name="pixbuf-column">0</property>
+            <property name="columns">4</property>
+            <property name="item-width">80</property>
+            <property name="selection-mode">single</property>
+            <child internal-child="accessible">
+              <object class="AtkObject" id="pick_graphic_iconview-atkobject">
+                <property name="AtkObject::accessible-description" 
translatable="yes" 
context="pickgraphicpage|extended_tip|pick_graphic_iconview">Click the graphics 
that you want to use as bullets.</property>
               </object>
             </child>
           </object>
         </child>
       </object>
       <packing>
-        <property name="left-attach">1</property>
+        <property name="left-attach">0</property>
         <property name="top-attach">0</property>
       </packing>
     </child>
@@ -68,8 +74,8 @@
         <property name="halign">end</property>
       </object>
       <packing>
-        <property name="left-attach">1</property>
-        <property name="top-attach">2</property>
+        <property name="left-attach">0</property>
+        <property name="top-attach">1</property>
       </packing>
     </child>
     <child>
diff --git a/include/svx/svxbmpnumiconview.hxx 
b/include/svx/svxbmpnumiconview.hxx
index 853ad3ae29a1..44c6cc583cda 100644
--- a/include/svx/svxbmpnumiconview.hxx
+++ b/include/svx/svxbmpnumiconview.hxx
@@ -68,6 +68,9 @@ public:
         Reference<XNumberingFormatter> const& xFormat,
         const Locale& rLocale,
         std::vector<std::pair<OUString, OUString>> maCustomBullets = 
std::vector<std::pair<OUString, OUString>>());
+
+    static VclPtr<VirtualDevice> CreateBitmapBulletPreview(sal_uInt32 
nGalleryIndex);
+    static void PopulateBitmapIconView(weld::IconView* pIconView);
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svx/source/dialog/svxbmpnumiconview.cxx 
b/svx/source/dialog/svxbmpnumiconview.cxx
index 84582570821c..ae8a48655e60 100644
--- a/svx/source/dialog/svxbmpnumiconview.cxx
+++ b/svx/source/dialog/svxbmpnumiconview.cxx
@@ -29,7 +29,8 @@
 #include <svx/dialmgr.hxx>
 #include <svx/strings.hrc>
 #include <officecfg/Office/Common.hxx>
-
+#include <svx/gallery.hxx>
+#include <vcl/graph.hxx>
 #include <svx/svxbmpnumiconview.hxx>
 
 using namespace com::sun::star::uno;
@@ -536,4 +537,72 @@ void SvxBmpNumIconView::SetOutlineNumberingSettings(
     }
 }
 
+VclPtr<VirtualDevice> SvxBmpNumIconView::CreateBitmapBulletPreview(sal_uInt32 
nGalleryIndex)
+{
+    VclPtr<VirtualDevice> pVDev = VclPtr<VirtualDevice>::Create();
+    Size aRectSize(150, 200);
+    pVDev->SetOutputSizePixel(aRectSize);
+
+    const Color aBackColor(COL_WHITE);
+    const Color aTextColor(COL_BLACK);
+
+    pVDev->SetFillColor(aBackColor);
+    pVDev->SetLineColor(aTextColor);
+    pVDev->DrawRect(tools::Rectangle(Point(0,0), aRectSize));
+
+    tools::Long nRectWidth = aRectSize.Width();
+    tools::Long nRectHeight = aRectSize.Height();
+    Size aGraphicSize(nRectHeight/8, nRectHeight/8);
+
+    pVDev->SetLineColor(COL_LIGHTGRAY);
+    Point aStart(nRectWidth * 25 / 100, 0);
+    Point aEnd(nRectWidth * 9 / 10, 0);
+    for (sal_uInt16 i = 11; i < 100; i += 33)
+    {
+        aStart.setY(nRectHeight * i / 100);
+        aEnd.setY(aStart.Y());
+        pVDev->DrawLine(aStart, aEnd);
+        aStart.setY(nRectHeight * (i + 11) / 100);
+        aEnd.setY(aStart.Y());
+        pVDev->DrawLine(aStart, aEnd);
+    }
+
+    Graphic aGraphic;
+    if (GalleryExplorer::GetGraphicObj(GALLERY_THEME_BULLETS, nGalleryIndex, 
&aGraphic))
+    {
+        Point aPos(5, 0);
+        for (sal_uInt16 i = 0; i < 3; i++)
+        {
+            sal_uInt16 nY = 11 + i * 33;
+            aPos.setY(nRectHeight * nY / 100);
+            aGraphic.Draw(*pVDev, aPos, aGraphicSize);
+        }
+    }
+    else
+    {
+        vcl::Font aFont("Arial", Size(0, 12));
+        pVDev->SetFont(aFont);
+        pVDev->DrawText(Point(10, 50), u"No Image"_ustr);
+    }
+
+    return pVDev;
+}
+
+void SvxBmpNumIconView::PopulateBitmapIconView(weld::IconView* pIconView)
+{
+    if (!pIconView)
+        return;
+
+    pIconView->clear();
+
+    sal_uInt32 nCount = GalleryExplorer::GetSdrObjCount(GALLERY_THEME_BULLETS);
+
+    for (sal_uInt32 i = 0; i < std::min(nCount, sal_uInt32(8)); ++i)
+    {
+        VclPtr<VirtualDevice> pVDev = CreateBitmapBulletPreview(i);
+        OUString sId = OUString::number(i);
+        pIconView->insert(-1, nullptr, &sId, pVDev, nullptr);
+    }
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/uitest/writer_tests2/formatBulletsNumbering.py 
b/sw/qa/uitest/writer_tests2/formatBulletsNumbering.py
index 843d35f62483..31810c8af751 100644
--- a/sw/qa/uitest/writer_tests2/formatBulletsNumbering.py
+++ b/sw/qa/uitest/writer_tests2/formatBulletsNumbering.py
@@ -297,16 +297,22 @@ class formatBulletsNumbering(UITestCase):
                 xTabs = xDialog.getChild("tabcontrol")
                 select_pos(xTabs, "3")
                 xGraphicPage = xDialog.getChild("PickGraphicPage")
-                xselector = xGraphicPage.getChild("valueset")
-                self.assertEqual(get_state_as_dict(xselector)["ItemsCount"], 
"92")
+                xselector = xGraphicPage.getChild("pick_graphic_iconview")
                 # Select element num 22
-                xselector.executeAction("CHOOSE", mkPropertyValues({"POS": 
"22"}))
+                element22 = xselector.getChild("21")
+                element22.executeAction("SELECT", mkPropertyValues({}))
+                self.assertEqual(get_state_as_dict(xselector)["VisibleCount"], 
"92")
                 
self.assertEqual(get_state_as_dict(xselector)["SelectedItemPos"], "21")
-                
self.assertEqual(get_state_as_dict(xselector)["SelectedItemId"], "22")
+                
self.assertEqual(get_state_as_dict(xselector)["SelectedItemId"], "21")
+                
self.assertEqual(get_state_as_dict(xselector)["SelectEntryText"], 
"Bullet15-Arrow-Blue")
+
                 # Select element num 73
-                xselector.executeAction("CHOOSE", mkPropertyValues({"POS": 
"73"}))
+                element73 = xselector.getChild("72")
+                element73.executeAction("SELECT", mkPropertyValues({}))
+                self.assertEqual(get_state_as_dict(xselector)["VisibleCount"], 
"92")
                 
self.assertEqual(get_state_as_dict(xselector)["SelectedItemPos"], "72")
-                
self.assertEqual(get_state_as_dict(xselector)["SelectedItemId"], "73")
+                
self.assertEqual(get_state_as_dict(xselector)["SelectedItemId"], "72")
+                
self.assertEqual(get_state_as_dict(xselector)["SelectEntryText"], "orgsqare")
 
 
    def test_bullets_and_numbering_document_bullet_list(self):

Reply via email to