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):
