sd/CppunitTest_sd_ui_func.mk | 88 +++++++++++++++++++++++++++++++++ sd/Module_sd.mk | 1 sd/qa/ui/func/func.cxx | 88 +++++++++++++++++++++++++++++++++ sd/qa/unit/data/odp/none-to-bullet.odp |binary sd/qa/unit/sdmodeltestbase.hxx | 19 +++++++ sd/qa/unit/uiimpress.cxx | 19 ------- sd/source/ui/func/fuolbull.cxx | 8 ++- 7 files changed, 203 insertions(+), 20 deletions(-)
New commits: commit fe9fab9702613b1a5d192821d8a620aa527234b7 Author: Miklos Vajna <[email protected]> AuthorDate: Thu Dec 18 08:21:14 2025 +0100 Commit: Miklos Vajna <[email protected]> CommitDate: Thu Dec 18 13:34:33 2025 +0100 Related: tdf#89365 sd UI, from numbering to bullet: fix defaults Open the bugdoc, start text edit on the only slide, in the only shape. Use the toolbar button to change from no numbering to bullet, some very small bullet with no spacing between the bullet and the text shows up. This happens since commit f60ee00edcc5b0fdee5227bb695448119cddb013 (tdf#89365 sd UI: fix transitioning from a numbered list to a bulleted list, 2025-11-04), previously the numbering to bullet transitioning was broken and you had to click on the "turn on bullets" button twice. A side effect of the old two-step transitioning was that no formatting from the old numbering was kept, so better defaults were used (but the numbering level was lost). Keep the old use-case fixed and fix the new use-case by looking at how this works on master pages: there TextObjectBar::ExecuteImpl()'s FN_NUM_BULLET_ON block calls SdStyleSheetPool::setDefaultOutlineNumberFormatBulletAndIndent() before setting the number format for a specific level of the numbering rule. Do the same for non-master pages in FuBulletAndPosition::SetCurrentBulletsNumbering(): if we transition to a bullet, then use the same defaults in the non-master-page case, too. Note that turning bullets on or off as direct formatting is not ideal: a better style is to assign bullets (or no bullets) to different outline levels in the master page, and then just change the list level of paragraphs in the outliner shape, which avoids this sort of problem in the first place. Change-Id: I4227988593baeaa91cc21525fb895c3acaf3afd7 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195839 Reviewed-by: Miklos Vajna <[email protected]> Tested-by: Jenkins diff --git a/sd/CppunitTest_sd_ui_func.mk b/sd/CppunitTest_sd_ui_func.mk new file mode 100644 index 000000000000..bad465b194d5 --- /dev/null +++ b/sd/CppunitTest_sd_ui_func.mk @@ -0,0 +1,88 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +#************************************************************************* +# +# 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/. +# +#************************************************************************* + +$(eval $(call gb_CppunitTest_CppunitTest,sd_ui_func)) + +$(eval $(call gb_CppunitTest_use_externals,sd_ui_func,\ + boost_headers \ + libxml2 \ +)) + +$(eval $(call gb_CppunitTest_use_common_precompiled_header,sd_ui_func)) + +$(eval $(call gb_CppunitTest_add_exception_objects,sd_ui_func, \ + sd/qa/ui/func/func \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,sd_ui_func, \ + basegfx \ + canvastools \ + comphelper \ + cppcanvas \ + cppu \ + cppuhelper \ + docmodel \ + drawinglayer \ + editeng \ + for \ + forui \ + i18nlangtag \ + i18nutil \ + msfilter \ + oox \ + sal \ + salhelper \ + sax \ + sb \ + sd \ + sfx \ + sot \ + subsequenttest \ + svl \ + svt \ + svx \ + svxcore \ + test \ + tl \ + tk \ + ucbhelper \ + unotest \ + utl \ + vcl \ + xo \ +)) + +$(eval $(call gb_CppunitTest_set_include,sd_ui_func,\ + -I$(SRCDIR)/sd/inc \ + -I$(SRCDIR)/sd/source/ui/inc \ + -I$(SRCDIR)/sd/source/ui/slidesorter/inc \ + -I$(SRCDIR)/sd/qa/unit \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,sd_ui_func)) + +$(eval $(call gb_CppunitTest_use_ure,sd_ui_func)) +$(eval $(call gb_CppunitTest_use_vcl,sd_ui_func)) + +$(eval $(call gb_CppunitTest_use_rdb,sd_ui_func,services)) + +$(eval $(call gb_CppunitTest_use_custom_headers,sd_ui_func,\ + officecfg/registry \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,sd_ui_func)) + +$(eval $(call gb_CppunitTest_add_arguments,sd_ui_func, \ + -env:arg-env=$(gb_Helper_LIBRARY_PATH_VAR)"$$$${$(gb_Helper_LIBRARY_PATH_VAR)+=$$$$$(gb_Helper_LIBRARY_PATH_VAR)}" \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/sd/Module_sd.mk b/sd/Module_sd.mk index aefdbb587dd4..048e2743a835 100644 --- a/sd/Module_sd.mk +++ b/sd/Module_sd.mk @@ -45,6 +45,7 @@ $(eval $(call gb_Module_add_slowcheck_targets,sd,\ CppunitTest_sd_layout_tests \ CppunitTest_sd_misc_tests \ CppunitTest_sd_uiimpress \ + CppunitTest_sd_ui_func \ CppunitTest_sd_html_export_tests \ CppunitTest_sd_activex_controls_tests \ CppunitTest_sd_pdf_import_test \ diff --git a/sd/qa/ui/func/func.cxx b/sd/qa/ui/func/func.cxx new file mode 100644 index 000000000000..f6df8fcc8857 --- /dev/null +++ b/sd/qa/ui/func/func.cxx @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * 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 <sdmodeltestbase.hxx> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/drawing/XDrawPage.hpp> + +#include <comphelper/sequenceashashmap.hxx> +#include <vcl/scheduler.hxx> + +#include <DrawDocShell.hxx> +#include <ViewShell.hxx> +#include <sdpage.hxx> +#include <unomodel.hxx> + +using namespace com::sun::star; + +namespace +{ +/// Covers sd/source/ui/func/ fixes. +class Test : public SdModelTestBase +{ +public: + Test() + : SdModelTestBase(u"/sd/qa/unit/data/"_ustr) + { + } +}; + +CPPUNIT_TEST_FIXTURE(Test, testNoneToBullet) +{ + // Given a document with a shape, the only paragraph has a numbering of type "none": + createSdImpressDoc("odp/none-to-bullet.odp"); + sd::ViewShell* pViewShell = getSdDocShell()->GetViewShell(); + SdPage* pPage = pViewShell->GetActualPage(); + SdrObject* pShape = pPage->GetObj(0); + CPPUNIT_ASSERT(pShape); + SdrView* pView = pViewShell->GetView(); + pView->MarkObj(pShape, pView->GetSdrPageView()); + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT(!pView->IsTextEdit()); + + // When turning the "none" numbering to a bullet: + // Start text edit: + auto pImpressDocument = dynamic_cast<SdXImpressDocument*>(mxComponent.get()); + typeString(pImpressDocument, u"x"); + CPPUNIT_ASSERT(pView->IsTextEdit()); + // Do the switch: + dispatchCommand(mxComponent, u".uno:DefaultBullet"_ustr, {}); + // End text edit: + typeKey(pImpressDocument, KEY_ESCAPE); + + // Then make sure we switch to a bullet with reasonable defaults: + CPPUNIT_ASSERT(!pView->IsTextEdit()); + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), + uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xParagraph(getParagraphFromShape(0, xShape), + uno::UNO_QUERY); + // Check the list level 1 properties: + uno::Reference<container::XIndexAccess> xNumberingRules; + xParagraph->getPropertyValue(u"NumberingRules"_ustr) >>= xNumberingRules; + comphelper::SequenceAsHashMap aNumberingRule(xNumberingRules->getByIndex(0)); + sal_Int32 nLeftMargin{}; + aNumberingRule[u"LeftMargin"_ustr] >>= nLeftMargin; + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1200 + // - Actual : 0 + // i.e. there was no left margin at all, first and later lines did not match on the left hand + // side. + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1200), nLeftMargin); + sal_Int32 nFirstLineOffset{}; + aNumberingRule[u"FirstLineOffset"_ustr] >>= nFirstLineOffset; + CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(-900), nFirstLineOffset); +} +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/qa/unit/data/odp/none-to-bullet.odp b/sd/qa/unit/data/odp/none-to-bullet.odp new file mode 100644 index 000000000000..3526ae3916cf Binary files /dev/null and b/sd/qa/unit/data/odp/none-to-bullet.odp differ diff --git a/sd/qa/unit/sdmodeltestbase.hxx b/sd/qa/unit/sdmodeltestbase.hxx index 8a398520e6a8..135245767d03 100644 --- a/sd/qa/unit/sdmodeltestbase.hxx +++ b/sd/qa/unit/sdmodeltestbase.hxx @@ -34,6 +34,8 @@ #include <com/sun/star/drawing/XDrawPagesSupplier.hpp> #include <com/sun/star/packages/zip/ZipFileAccess.hpp> #include <drawinglayer/XShapeDumper.hxx> +#include <LibreOfficeKit/LibreOfficeKitEnums.h> +#include <vcl/scheduler.hxx> #include <com/sun/star/text/XTextField.hpp> using namespace ::com::sun::star; @@ -184,6 +186,23 @@ public: return pXmlDoc; } + + void typeString(SdXImpressDocument* rImpressDocument, std::u16string_view rStr) + { + for (const char16_t c : rStr) + { + rImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, c, 0); + rImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, c, 0); + Scheduler::ProcessEventsToIdle(); + } + } + + void typeKey(SdXImpressDocument* rImpressDocument, const sal_uInt16 nKey) + { + rImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, nKey); + rImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, nKey); + Scheduler::ProcessEventsToIdle(); + } }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sd/qa/unit/uiimpress.cxx b/sd/qa/unit/uiimpress.cxx index 98b1cdb01974..215af8589928 100644 --- a/sd/qa/unit/uiimpress.cxx +++ b/sd/qa/unit/uiimpress.cxx @@ -80,8 +80,6 @@ public: } void checkCurrentPageNumber(sal_uInt16 nNum); - void typeString(SdXImpressDocument* rImpressDocument, std::u16string_view rStr); - void typeKey(SdXImpressDocument* rImpressDocument, const sal_uInt16 nKey); void insertStringToObject(sal_uInt16 nObj, std::u16string_view rStr, bool bUseEscape); sd::slidesorter::SlideSorterViewShell* getSlideSorterViewShell(); void lcl_search(const OUString& rKey, bool bFindAll = false, bool bBackwards = false); @@ -99,23 +97,6 @@ void SdUiImpressTest::checkCurrentPageNumber(sal_uInt16 nNum) CPPUNIT_ASSERT_EQUAL(nNum, nPageNumber); } -void SdUiImpressTest::typeKey(SdXImpressDocument* rImpressDocument, const sal_uInt16 nKey) -{ - rImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, nKey); - rImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, nKey); - Scheduler::ProcessEventsToIdle(); -} - -void SdUiImpressTest::typeString(SdXImpressDocument* rImpressDocument, std::u16string_view rStr) -{ - for (const char16_t c : rStr) - { - rImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, c, 0); - rImpressDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, c, 0); - Scheduler::ProcessEventsToIdle(); - } -} - void SdUiImpressTest::insertStringToObject(sal_uInt16 nObj, std::u16string_view rStr, bool bUseEscape) { diff --git a/sd/source/ui/func/fuolbull.cxx b/sd/source/ui/func/fuolbull.cxx index ef4dd373fcbc..ecb7c5377a1b 100644 --- a/sd/source/ui/func/fuolbull.cxx +++ b/sd/source/ui/func/fuolbull.cxx @@ -206,7 +206,13 @@ void FuBulletAndPosition::SetCurrentBulletsNumbering(SfxRequest& rReq) { if(nActNumLvl & nMask) { - const SvxNumberFormat& aFmt(aTmpRule.GetLevel(i)); + SvxNumberFormat aFmt(aTmpRule.GetLevel(i)); + if (nSId == FN_SVX_SET_BULLET) + { + // If changing to a bullet, then make its format and indent has a good + // default, similar to what the master page offers: + SdStyleSheetPool::setDefaultOutlineNumberFormatBulletAndIndent(i, aFmt); + } pNumRule->SetLevel(i, aFmt); } nMask <<= 1;
