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 a26e176abcd40438d19e2a9012db1342bdcaba12
Author:     Miklos Vajna <[email protected]>
AuthorDate: Thu Dec 18 08:21:14 2025 +0100
Commit:     Caolán McNamara <[email protected]>
CommitDate: Thu Dec 18 10:25:02 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/+/195823
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Tested-by: Caolán McNamara <[email protected]>
    Reviewed-by: Caolán McNamara <[email protected]>

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 1cd4fc626342..1e0ff98c8948 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;
@@ -170,6 +172,23 @@ public:
         xPropSet->getPropertyValue(u"TextField"_ustr) >>= xField;
         return xField;
     }
+
+    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 87e563ed030e..4de52c2268b6 100644
--- a/sd/qa/unit/uiimpress.cxx
+++ b/sd/qa/unit/uiimpress.cxx
@@ -76,8 +76,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);
@@ -95,23 +93,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 4ddc89ffac60..0b3bf75fa9fb 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;

Reply via email to