cui/source/inc/numpages.hxx                          |    2 
 cui/source/tabpages/numpages.cxx                     |   86 +++++++++++++++++++
 cui/uiconfig/ui/pickbulletpage.ui                    |   56 +++++++++---
 svx/source/sidebar/nbdtmg.cxx                        |   13 ++
 sw/qa/uitest/writer_tests2/formatBulletsNumbering.py |   39 ++++++++
 5 files changed, 178 insertions(+), 18 deletions(-)

New commits:
commit 7cb2062ba4ae54b0ae8f2837096d1322b783f53d
Author:     Tibor Nagy <tibor.nagy.ext...@allotropia.de>
AuthorDate: Wed May 15 11:39:45 2024 +0200
Commit:     Thorsten Behrens <thorsten.behr...@allotropia.de>
CommitDate: Fri Jun 7 22:13:09 2024 +0200

    tdf#69724 Allow to change default bullet symbols in UI
    
    Change-Id: Ife700096fb55ebc752ae289398a36ee78b3e5ccb
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167660
    Tested-by: Jenkins
    Reviewed-by: Nagy Tibor <tibor.nagy.ext...@allotropia.de>
    Tested-by: Gabor Kelemen <gabor.kelemen.ext...@allotropia.de>
    (cherry picked from commit 2e1350593c26a70408b3cf7d1bac2f2ff8309852)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/168370
    Tested-by: allotropia jenkins <jenk...@allotropia.de>
    Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de>

diff --git a/cui/source/inc/numpages.hxx b/cui/source/inc/numpages.hxx
index d693b9e0324f..615f84bfdfe9 100644
--- a/cui/source/inc/numpages.hxx
+++ b/cui/source/inc/numpages.hxx
@@ -95,11 +95,13 @@ class SvxBulletPickTabPage final : public SfxTabPage
 
     OUString            sBulletCharFormatName;
 
+    std::unique_ptr<weld::Button> m_xBtChangeBullet;
     std::unique_ptr<SvxNumValueSet> m_xExamplesVS;
     std::unique_ptr<weld::CustomWeld> m_xExamplesVSWin;
 
     DECL_LINK(NumSelectHdl_Impl, ValueSet*, void);
     DECL_LINK(DoubleClickHdl_Impl, ValueSet*, void);
+    DECL_LINK(ClickAddChangeHdl_Impl, weld::Button&, void);
 public:
     SvxBulletPickTabPage(weld::Container* pPage, weld::DialogController* 
pController, const SfxItemSet& rSet);
     virtual ~SvxBulletPickTabPage() override;
diff --git a/cui/source/tabpages/numpages.cxx b/cui/source/tabpages/numpages.cxx
index 1220d2a9d9eb..17269ef88d38 100644
--- a/cui/source/tabpages/numpages.cxx
+++ b/cui/source/tabpages/numpages.cxx
@@ -328,6 +328,7 @@ SvxBulletPickTabPage::SvxBulletPickTabPage(weld::Container* 
pPage, weld::DialogC
     , bModified(false)
     , bPreset(false)
     , nNumItemId(SID_ATTR_NUMBERING_RULE)
+    , m_xBtChangeBullet(m_xBuilder->weld_button("changeBulletBtn"))
     , m_xExamplesVS(new 
SvxNumValueSet(m_xBuilder->weld_scrolled_window("valuesetwin", true)))
     , m_xExamplesVSWin(new weld::CustomWeld(*m_xBuilder, "valueset", 
*m_xExamplesVS))
 {
@@ -335,6 +336,7 @@ SvxBulletPickTabPage::SvxBulletPickTabPage(weld::Container* 
pPage, weld::DialogC
     m_xExamplesVS->init(NumberingPageType::BULLET);
     m_xExamplesVS->SetSelectHdl(LINK(this, SvxBulletPickTabPage, 
NumSelectHdl_Impl));
     m_xExamplesVS->SetDoubleClickHdl(LINK(this, SvxBulletPickTabPage, 
DoubleClickHdl_Impl));
+    m_xBtChangeBullet->connect_clicked(LINK(this, SvxBulletPickTabPage, 
ClickAddChangeHdl_Impl));
 }
 
 SvxBulletPickTabPage::~SvxBulletPickTabPage()
@@ -461,6 +463,90 @@ IMPL_LINK_NOARG(SvxBulletPickTabPage, DoubleClickHdl_Impl, 
ValueSet*, void)
     rOk.clicked();
 }
 
+IMPL_LINK_NOARG(SvxBulletPickTabPage, ClickAddChangeHdl_Impl, weld::Button&, 
void)
+{
+    SvxCharacterMap aMap(GetFrameWeld(), nullptr, nullptr);
+
+    sal_uInt16 nMask = 1;
+    std::optional<vcl::Font> pFmtFont;
+    bool bSameBullet = true;
+    sal_UCS4 cBullet = 0;
+    bool bFirst = true;
+    for (sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
+    {
+        if (nActNumLvl & nMask)
+        {
+            const SvxNumberFormat& rCurFmt = pActNum->GetLevel(i);
+            if (bFirst)
+            {
+                cBullet = rCurFmt.GetBulletChar();
+            }
+            else if (rCurFmt.GetBulletChar() != cBullet)
+            {
+                bSameBullet = false;
+                break;
+            }
+            if (!pFmtFont)
+                pFmtFont = rCurFmt.GetBulletFont();
+            bFirst = false;
+        }
+        nMask <<= 1;
+    }
+
+    if (pFmtFont)
+        aMap.SetCharFont(*pFmtFont);
+    if (bSameBullet)
+        aMap.SetChar(cBullet);
+    if (aMap.run() != RET_OK)
+        return;
+
+    sal_Unicode cChar = aMap.GetChar();
+    vcl::Font aActBulletFont = aMap.GetCharFont();
+
+    sal_uInt16 _nMask = 1;
+    for (sal_uInt16 i = 0; i < pActNum->GetLevelCount(); i++)
+    {
+        if (nActNumLvl & _nMask)
+        {
+            SvxNumberFormat aNumFmt(pActNum->GetLevel(i));
+            aNumFmt.SetBulletFont(&aActBulletFont);
+            aNumFmt.SetBulletChar(cChar);
+            pActNum->SetLevel(i, aNumFmt);
+        }
+        _nMask <<= 1;
+    }
+
+    css::uno::Sequence<OUString> 
aBulletSymbols(officecfg::Office::Common::BulletsNumbering::DefaultBullets::get());
+    css::uno::Sequence<OUString> 
aBulletSymbolsFonts(officecfg::Office::Common::BulletsNumbering::DefaultBulletsFonts::get());
+    css::uno::Sequence<OUString> aBulletSymbolsList(aBulletSymbols.size());
+    css::uno::Sequence<OUString> 
aBulletSymbolsFontsList(aBulletSymbolsFonts.size());
+    auto aBulletSymbolsListRange = asNonConstRange(aBulletSymbolsList);
+    auto aBulletSymbolsFontsListRange = 
asNonConstRange(aBulletSymbolsFontsList);
+
+    sal_uInt16 nIndex = m_xExamplesVS->GetSelectedItemId() - 1;
+    for (size_t i = 0; i < aBulletSymbols.size(); ++i)
+    {
+        if (i == nIndex)
+        {
+            aBulletSymbolsListRange[i] = OUStringChar(cChar);
+            aBulletSymbolsFontsListRange[i] = aActBulletFont.GetFamilyName();
+        }
+        else
+        {
+            aBulletSymbolsListRange[i] = aBulletSymbols[i];
+            aBulletSymbolsFontsListRange[i] = aBulletSymbolsFonts[i];
+        }
+    }
+
+    std::shared_ptr<comphelper::ConfigurationChanges> 
batch(comphelper::ConfigurationChanges::create());
+    
officecfg::Office::Common::BulletsNumbering::DefaultBullets::set(aBulletSymbolsList,
 batch);
+    
officecfg::Office::Common::BulletsNumbering::DefaultBulletsFonts::set(aBulletSymbolsFontsList,
 batch);
+    batch->commit();
+
+    m_xExamplesVS->SetFormat();
+    m_xExamplesVS->Invalidate();
+}
+
 void SvxBulletPickTabPage::PageCreated(const SfxAllItemSet& aSet)
 {
     const SfxStringItem* pBulletCharFmt = 
aSet.GetItem<SfxStringItem>(SID_BULLET_CHAR_FMT, false);
diff --git a/cui/uiconfig/ui/pickbulletpage.ui 
b/cui/uiconfig/ui/pickbulletpage.ui
index 589874506853..fade087747f3 100644
--- a/cui/uiconfig/ui/pickbulletpage.ui
+++ b/cui/uiconfig/ui/pickbulletpage.ui
@@ -2,37 +2,63 @@
 <!-- Generated with glade 3.40.0 -->
 <interface domain="cui">
   <requires lib="gtk+" version="3.20"/>
-  <object class="GtkScrolledWindow" id="PickBulletPage">
+  <object class="GtkGrid" id="PickBulletPage">
     <property name="visible">True</property>
-    <property name="can-focus">True</property>
+    <property name="can-focus">False</property>
     <property name="margin-start">6</property>
     <property name="margin-end">6</property>
     <property name="margin-top">6</property>
     <property name="margin-bottom">6</property>
     <property name="hexpand">True</property>
     <property name="vexpand">True</property>
-    <property name="hscrollbar-policy">never</property>
-    <property name="vscrollbar-policy">never</property>
-    <property name="shadow-type">in</property>
+    <property name="row-spacing">6</property>
     <child>
-      <object class="GtkViewport">
+      <object class="GtkScrolledWindow" id="valusetwin">
         <property name="visible">True</property>
-        <property name="can-focus">False</property>
+        <property name="can-focus">True</property>
+        <property name="hexpand">True</property>
+        <property name="vexpand">True</property>
+        <property name="hscrollbar-policy">never</property>
+        <property name="vscrollbar-policy">never</property>
+        <property name="shadow-type">in</property>
         <child>
-          <object class="GtkDrawingArea" id="valueset">
+          <object class="GtkViewport">
             <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="pickbulletpage|extended_tip|valueset">Click the 
bullet style that you want to use.</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="pickbulletpage|extended_tip|valueset">Click the 
bullet style that you want to use.</property>
+                  </object>
+                </child>
               </object>
             </child>
           </object>
         </child>
       </object>
+      <packing>
+        <property name="left-attach">1</property>
+        <property name="top-attach">0</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkButton" id="changeBulletBtn">
+        <property name="label" translatable="yes" 
context="pickbulletpage|changeBulletBtn">Change Bullet</property>
+        <property name="visible">True</property>
+        <property name="can-focus">True</property>
+        <property name="receives-default">False</property>
+        <property name="halign">end</property>
+      </object>
+        <packing>
+          <property name="left-attach">1</property>
+          <property name="top-attach">2</property>
+        </packing>
     </child>
     <child internal-child="accessible">
       <object class="AtkObject" id="PickBulletPage-atkobject">
diff --git a/svx/source/sidebar/nbdtmg.cxx b/svx/source/sidebar/nbdtmg.cxx
index dca5e176e571..23ced8069310 100644
--- a/svx/source/sidebar/nbdtmg.cxx
+++ b/svx/source/sidebar/nbdtmg.cxx
@@ -277,9 +277,11 @@ sal_uInt16 
BulletsTypeMgr::GetNBOIndexForNumRule(SvxNumRule& aNum,sal_uInt16 mLe
 
     const SvxNumberFormat& aFmt(aNum.GetLevel(nActLv));
     sal_UCS4 cChar = aFmt.GetBulletChar();
+
+    css::uno::Sequence<OUString> 
aBulletSymbols(officecfg::Office::Common::BulletsNumbering::DefaultBullets::get());
     for(sal_uInt16 i = nFromIndex; i < DEFAULT_BULLET_TYPES; i++)
     {
-        if ( (cChar == pActualBullets[i]->cBulletChar) ||
+        if ( (cChar == aBulletSymbols[i].toChar()) ||
              (cChar == 9830 && 57356 == pActualBullets[i]->cBulletChar) ||
              (cChar == 9632 && 57354 == pActualBullets[i]->cBulletChar)   )
         {
@@ -320,8 +322,13 @@ void BulletsTypeMgr::ApplyNumRule(SvxNumRule& aNum, 
sal_uInt16 nIndex, sal_uInt1
 {
     if ( nIndex >= DEFAULT_BULLET_TYPES )
         return;
-    sal_UCS4 cChar = pActualBullets[nIndex]->cBulletChar;
-    const vcl::Font& rActBulletFont = pActualBullets[nIndex]->aFont;
+
+    css::uno::Sequence<OUString> 
aBulletSymbols(officecfg::Office::Common::BulletsNumbering::DefaultBullets::get());
+    css::uno::Sequence<OUString> 
aBulletFontSymbols(officecfg::Office::Common::BulletsNumbering::DefaultBulletsFonts::get());
+
+    sal_UCS4 cChar = aBulletSymbols[nIndex].toChar();
+    vcl::Font& rActBulletFont = pActualBullets[nIndex]->aFont;
+    rActBulletFont.SetFamilyName(aBulletFontSymbols[nIndex]);
 
     sal_uInt16 nMask = 1;
     OUString sBulletCharFormatName = GetBulletCharFmtName();
diff --git a/sw/qa/uitest/writer_tests2/formatBulletsNumbering.py 
b/sw/qa/uitest/writer_tests2/formatBulletsNumbering.py
index abf090f7d16e..e5ff843fa0f6 100644
--- a/sw/qa/uitest/writer_tests2/formatBulletsNumbering.py
+++ b/sw/qa/uitest/writer_tests2/formatBulletsNumbering.py
@@ -17,6 +17,45 @@ from uitest.uihelper.common import change_measurement_unit
 
 class formatBulletsNumbering(UITestCase):
 
+   def test_bullets_and_numbering_change_bullet(self):
+        with self.ui_test.create_doc_in_start_center("writer"):
+
+            # Set the "black down-pointing triangle" bullet in the third item
+            with 
self.ui_test.execute_dialog_through_command(".uno:BulletsAndNumberingDialog") 
as xDialog:
+                # Select the BulletPage's selector
+                xTabs = xDialog.getChild("tabcontrol")
+                select_pos(xTabs, "0")
+                xBulletPage = xDialog.getChild("PickBulletPage")
+                xSelector = xBulletPage.getChild("valueset")
+
+                # Select element number 3
+                xSelector.executeAction("CHOOSE", mkPropertyValues({"POS": 
"3"}))
+                
self.assertEqual(get_state_as_dict(xSelector)["SelectedItemId"], "3")
+                xChangeBulletBtn = xBulletPage.getChild("changeBulletBtn")
+                with 
self.ui_test.execute_blocking_action(xChangeBulletBtn.executeAction, 
args=('CLICK', ())) as xCharSetDialog:
+                    xCharSet = xCharSetDialog.getChild("showcharset")
+                    xCharSet.executeAction("SELECT", 
mkPropertyValues({"COLUMN": "21", "ROW": "1"}))
+
+            # Check that the "black down-pointing triangle" bullet is the 
third item
+            with 
self.ui_test.execute_dialog_through_command(".uno:BulletsAndNumberingDialog") 
as xDialog:
+                # Select the BulletPage's selector
+                xTabs = xDialog.getChild("tabcontrol")
+                select_pos(xTabs, "0")
+                xBulletPage = xDialog.getChild("PickBulletPage")
+                xSelector = xBulletPage.getChild("valueset")
+
+                # Select element number 3
+                xSelector.executeAction("CHOOSE", mkPropertyValues({"POS": 
"3"}))
+                
self.assertEqual(get_state_as_dict(xSelector)["SelectedItemId"], "3")
+                xChangeBulletBtn = xBulletPage.getChild("changeBulletBtn")
+                with 
self.ui_test.execute_blocking_action(xChangeBulletBtn.executeAction, 
args=('CLICK', ())) as xCharSetDialog:
+                    xHexText = xCharSetDialog.getChild("hexvalue")
+                    xDecText = xCharSetDialog.getChild("decimalvalue")
+                    # Check the "black down-pointing triangle" bullet Hex and 
Decimal value
+                    self.assertEqual(get_state_as_dict(xHexText)["Text"], 
"25BC")
+                    self.assertEqual(get_state_as_dict(xDecText)["Text"], 
"9660")
+
+
    def test_bullets_and_numbering_dialog_tab_position(self):
         with self.ui_test.create_doc_in_start_center("writer"):
 

Reply via email to