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