[Libreoffice-commits] core.git: editeng/source include/editeng sw/inc sw/qa sw/source writerfilter/source

Vasily Melenchuk (via logerrit) logerrit at kemper.freedesktop.org
Mon Apr 27 20:36:49 UTC 2020


 editeng/source/items/numitem.cxx                 |    8 -
 include/editeng/numitem.hxx                      |    3 
 sw/inc/unoprnms.hxx                              |    1 
 sw/qa/extras/ooxmlexport/ooxmlexport.cxx         |    5 
 sw/qa/extras/ooxmlexport/ooxmlexport10.cxx       |   22 ---
 sw/qa/extras/rtfexport/rtfexport.cxx             |    8 -
 sw/qa/extras/rtfimport/rtfimport.cxx             |  156 +++++++++--------------
 sw/source/core/doc/number.cxx                    |  116 ++++++++++-------
 sw/source/core/unocore/unosett.cxx               |   15 ++
 sw/source/filter/ww8/wrtw8num.cxx                |    8 +
 writerfilter/source/dmapper/NumberingManager.cxx |   73 +---------
 writerfilter/source/dmapper/NumberingManager.hxx |    5 
 writerfilter/source/dmapper/PropertyIds.cxx      |    1 
 writerfilter/source/dmapper/PropertyIds.hxx      |    1 
 14 files changed, 191 insertions(+), 231 deletions(-)

New commits:
commit 7459b9ecb54a298f02d19089620149718f8d8d48
Author:     Vasily Melenchuk <vasily.melenchuk at cib.de>
AuthorDate: Mon Apr 13 11:06:29 2020 +0300
Commit:     Thorsten Behrens <Thorsten.Behrens at CIB.de>
CommitDate: Mon Apr 27 22:36:12 2020 +0200

    tdf#116883: sw: support for lists level format string
    
    Multilevel lists are more flexible in case of DOCX. There is
    supported custom format for any level in DOCX unlike in LO
    and ODT where we are limited only with prefix and suffix
    for hardcoded list levels separated by dot. At the same time
    DOCX can have lists not only "1.2.3.4", but "1/2/3/4" or even
    "1!2>3)4" and such format can vary on each list level.
    
    Here is basic implementation for list format as a core feature
    for all documents and old way (prefix-suffix + ".") is left
    as fallback.
    
    Practically its usage is currently implemented only in DOCX
    import/export.
    
    Some RTF/OOXML unittests were redesigned: since we are not creating
    prefix/suffix for these formats conditions should be checked in
    a different way.
    
    Change-Id: I1ec58bcc5874d4fa19aee6a1f42bf1671d853b14
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/92106
    Tested-by: Jenkins
    Reviewed-by: Thorsten Behrens <Thorsten.Behrens at CIB.de>

diff --git a/editeng/source/items/numitem.cxx b/editeng/source/items/numitem.cxx
index 82d511b00715..d6f1769d11ac 100644
--- a/editeng/source/items/numitem.cxx
+++ b/editeng/source/items/numitem.cxx
@@ -347,9 +347,10 @@ SvxNumberFormat& SvxNumberFormat::operator=( const SvxNumberFormat& rFormat )
     mnListtabPos = rFormat.mnListtabPos;
     mnFirstLineIndent = rFormat.mnFirstLineIndent;
     mnIndentAt = rFormat.mnIndentAt;
-    eVertOrient         = rFormat.eVertOrient ;
-    sPrefix             = rFormat.sPrefix     ;
-    sSuffix             = rFormat.sSuffix     ;
+    eVertOrient         = rFormat.eVertOrient;
+    sPrefix             = rFormat.sPrefix;
+    sSuffix             = rFormat.sSuffix;
+    sListFormat         = rFormat.sListFormat;
     aGraphicSize        = rFormat.aGraphicSize  ;
     nBulletColor        = rFormat.nBulletColor   ;
     nBulletRelSize      = rFormat.nBulletRelSize;
@@ -384,6 +385,7 @@ bool  SvxNumberFormat::operator==( const SvxNumberFormat& rFormat) const
         eVertOrient         != rFormat.eVertOrient ||
         sPrefix             != rFormat.sPrefix     ||
         sSuffix             != rFormat.sSuffix     ||
+        sListFormat         != rFormat.sListFormat ||
         aGraphicSize        != rFormat.aGraphicSize  ||
         nBulletColor        != rFormat.nBulletColor   ||
         nBulletRelSize      != rFormat.nBulletRelSize ||
diff --git a/include/editeng/numitem.hxx b/include/editeng/numitem.hxx
index 12686b80b2aa..1b8c4b130463 100644
--- a/include/editeng/numitem.hxx
+++ b/include/editeng/numitem.hxx
@@ -107,6 +107,7 @@ public:
 private:
     OUString            sPrefix;
     OUString            sSuffix;
+    OUString            sListFormat;        // Format string ">%1.%2<" can be used instead of prefix/suffix
 
     SvxAdjust           eNumAdjust;
 
@@ -171,6 +172,8 @@ public:
     const OUString& GetPrefix() const { return sPrefix;}
     void            SetSuffix(const OUString& rSet) { sSuffix = rSet;}
     const OUString& GetSuffix() const { return sSuffix;}
+    void            SetListFormat(const OUString& rSet) { sListFormat = rSet; }
+    const OUString& GetListFormat() const { return sListFormat; }
 
     void                    SetCharFormatName(const OUString& rSet){ sCharStyleName = rSet; }
     virtual OUString        GetCharFormatName()const;
diff --git a/sw/inc/unoprnms.hxx b/sw/inc/unoprnms.hxx
index 4e1e565868b7..1f79400bb28a 100644
--- a/sw/inc/unoprnms.hxx
+++ b/sw/inc/unoprnms.hxx
@@ -77,6 +77,7 @@
 #define UNO_NAME_ANCHOR_CHAR_STYLE_NAME "AnchorCharStyleName"
 #define UNO_NAME_SUFFIX "Suffix"
 #define UNO_NAME_PREFIX "Prefix"
+#define UNO_NAME_LIST_FORMAT "ListFormat"
 #define UNO_NAME_PARENT_NUMBERING "ParentNumbering"
 #define UNO_NAME_CHAR_FONT_NAME "CharFontName"
 #define UNO_NAME_CHAR_FONT_STYLE_NAME "CharFontStyleName"
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
index cced1b33e2ba..0b142d51141a 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
@@ -765,7 +765,10 @@ DECLARE_OOXMLEXPORT_TEST(testNumOverrideLvltext, "num-override-lvltext.docx")
 {
     uno::Reference<container::XIndexAccess> xRules = getProperty< uno::Reference<container::XIndexAccess> >(getStyles("NumberingStyles")->getByName("WWNum1"), "NumberingRules");
     // This was 1, i.e. the numbering on the second level was "1", not "1.1".
-    CPPUNIT_ASSERT_EQUAL(sal_Int16(2), comphelper::SequenceAsHashMap(xRules->getByIndex(1))["ParentNumbering"].get<sal_Int16>());
+    // Check the praragraph properties, not the list ones, since they can differ due to overrides
+    uno::Reference<beans::XPropertySet> xPara(getParagraph(1), uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(1), getProperty<sal_Int16>(xPara, "NumberingLevel"));
+    CPPUNIT_ASSERT_EQUAL(OUString("1.1"), getProperty<OUString>(xPara, "ListLabelString"));
 
     // The paragraph marker's red font color was inherited by the number portion, this was ff0000.
     CPPUNIT_ASSERT_EQUAL(OUString("ffffffff"), parseDump("//Special[@nType='PortionType::Number']/SwFont", "color"));
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx
index 3e0d3752187f..d8eafc1d60b1 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx
@@ -858,25 +858,11 @@ DECLARE_OOXMLEXPORT_TEST(testTdf65955_2, "tdf65955_2.odt")
 
 DECLARE_OOXMLEXPORT_TEST(testChtOutlineNumberingOoxml, "chtoutline.docx")
 {
-    const sal_Unicode aExpectedPrefix[2] = { 0x7b2c, 0x0020 };
-    const sal_Unicode aExpectedSuffix[2] = { 0x0020, 0x7ae0 };
-    uno::Reference< text::XChapterNumberingSupplier > xChapterNumberingSupplier(mxComponent, uno::UNO_QUERY);
-    uno::Reference< container::XIndexAccess> xLevels(xChapterNumberingSupplier->getChapterNumberingRules());
-    uno::Sequence<beans::PropertyValue> aProps;
-    xLevels->getByIndex(0) >>= aProps; // 1st level
-
-    OUString aSuffix,aPrefix;
-    for (int i = 0; i < aProps.getLength(); ++i)
-    {
-        const beans::PropertyValue& rProp = aProps[i];
+    const sal_Unicode aExpectedNumbering[] = { 0x7b2c, ' ', '1', ' ', 0x7ae0 };
 
-        if (rProp.Name == "Suffix")
-            aSuffix = rProp.Value.get<OUString>();
-        if (rProp.Name == "Prefix")
-            aPrefix = rProp.Value.get<OUString>();
-    }
-    CPPUNIT_ASSERT_EQUAL(OUString(aExpectedPrefix,SAL_N_ELEMENTS(aExpectedPrefix)), aPrefix);
-    CPPUNIT_ASSERT_EQUAL(OUString(aExpectedSuffix,SAL_N_ELEMENTS(aExpectedSuffix)), aSuffix);
+    uno::Reference<beans::XPropertySet> xPara(getParagraph(1), uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(OUString(aExpectedNumbering,SAL_N_ELEMENTS(aExpectedNumbering)),
+        getProperty<OUString>(xPara, "ListLabelString"));
 }
 
 DECLARE_OOXMLEXPORT_TEST(mathtype, "mathtype.docx")
diff --git a/sw/qa/extras/rtfexport/rtfexport.cxx b/sw/qa/extras/rtfexport/rtfexport.cxx
index cf2cb780bb12..535374da8863 100644
--- a/sw/qa/extras/rtfexport/rtfexport.cxx
+++ b/sw/qa/extras/rtfexport/rtfexport.cxx
@@ -659,16 +659,16 @@ DECLARE_RTFEXPORT_TEST(testFdo66682, "fdo66682.rtf")
     uno::Sequence<beans::PropertyValue> aProps;
     xLevels->getByIndex(0) >>= aProps; // 1st level
 
-    OUString aSuffix;
+    OUString aListFormat;
     for (int i = 0; i < aProps.getLength(); ++i)
     {
         const beans::PropertyValue& rProp = aProps[i];
 
-        if (rProp.Name == "Suffix")
-            aSuffix = rProp.Value.get<OUString>();
+        if (rProp.Name == "ListFormat")
+            aListFormat = rProp.Value.get<OUString>();
     }
     // Suffix was '\0' instead of ' '.
-    CPPUNIT_ASSERT_EQUAL(OUString(" "), aSuffix);
+    CPPUNIT_ASSERT_EQUAL(OUString(" %1 "), aListFormat);
 }
 
 DECLARE_RTFEXPORT_TEST(testParaShadow, "para-shadow.rtf")
diff --git a/sw/qa/extras/rtfimport/rtfimport.cxx b/sw/qa/extras/rtfimport/rtfimport.cxx
index f9d4e3cbdb6e..08d7d647c167 100644
--- a/sw/qa/extras/rtfimport/rtfimport.cxx
+++ b/sw/qa/extras/rtfimport/rtfimport.cxx
@@ -141,21 +141,52 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf108943)
 CPPUNIT_TEST_FIXTURE(Test, testFdo46662)
 {
     load(mpTestDocumentPath, "fdo46662.rtf");
-    uno::Reference<beans::XPropertySet> xPropertySet(
-        getStyles("NumberingStyles")->getByName("WWNum3"), uno::UNO_QUERY);
-    uno::Reference<container::XIndexAccess> xLevels(
-        xPropertySet->getPropertyValue("NumberingRules"), uno::UNO_QUERY);
-    uno::Sequence<beans::PropertyValue> aProps;
-    xLevels->getByIndex(1) >>= aProps; // 2nd level
 
-    for (int i = 0; i < aProps.getLength(); ++i)
+    OUString listStyle;
+
     {
-        const beans::PropertyValue& rProp = aProps[i];
+        uno::Reference<beans::XPropertySet> xPara(getParagraph(1), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(0),
+                             getProperty<sal_Int16>(xPara, "NumberingLevel"));
+        CPPUNIT_ASSERT(xPara->getPropertyValue("NumberingStyleName") >>= listStyle);
+        CPPUNIT_ASSERT(listStyle.startsWith("WWNum"));
+        CPPUNIT_ASSERT_EQUAL(OUString("1"), getProperty<OUString>(xPara, "ListLabelString"));
+    }
+
+    {
+        uno::Reference<beans::XPropertySet> xPara(getParagraph(2), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(1),
+                             getProperty<sal_Int16>(xPara, "NumberingLevel"));
+        CPPUNIT_ASSERT(xPara->getPropertyValue("NumberingStyleName") >>= listStyle);
+        CPPUNIT_ASSERT(listStyle.startsWith("WWNum"));
+        CPPUNIT_ASSERT_EQUAL(OUString("1.1"), getProperty<OUString>(xPara, "ListLabelString"));
+    }
+
+    {
+        uno::Reference<beans::XPropertySet> xPara(getParagraph(3), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(2),
+                             getProperty<sal_Int16>(xPara, "NumberingLevel"));
+        CPPUNIT_ASSERT(xPara->getPropertyValue("NumberingStyleName") >>= listStyle);
+        CPPUNIT_ASSERT(listStyle.startsWith("WWNum"));
+        CPPUNIT_ASSERT_EQUAL(OUString("1.1.1"), getProperty<OUString>(xPara, "ListLabelString"));
+    }
+
+    {
+        uno::Reference<beans::XPropertySet> xPara(getParagraph(4), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(3),
+                             getProperty<sal_Int16>(xPara, "NumberingLevel"));
+        CPPUNIT_ASSERT(xPara->getPropertyValue("NumberingStyleName") >>= listStyle);
+        CPPUNIT_ASSERT(listStyle.startsWith("WWNum"));
+        CPPUNIT_ASSERT_EQUAL(OUString("1.1.1.1"), getProperty<OUString>(xPara, "ListLabelString"));
+    }
 
-        if (rProp.Name == "ParentNumbering")
-            CPPUNIT_ASSERT_EQUAL(sal_Int16(2), rProp.Value.get<sal_Int16>());
-        else if (rProp.Name == "Suffix")
-            CPPUNIT_ASSERT_EQUAL(sal_Int32(0), rProp.Value.get<OUString>().getLength());
+    {
+        uno::Reference<beans::XPropertySet> xPara(getParagraph(5), uno::UNO_QUERY);
+        CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(0),
+                             getProperty<sal_Int16>(xPara, "NumberingLevel"));
+        CPPUNIT_ASSERT(xPara->getPropertyValue("NumberingStyleName") >>= listStyle);
+        CPPUNIT_ASSERT(listStyle.startsWith("WWNum"));
+        CPPUNIT_ASSERT_EQUAL(OUString("2"), getProperty<OUString>(xPara, "ListLabelString"));
     }
 }
 
@@ -1037,25 +1068,12 @@ CPPUNIT_TEST_FIXTURE(Test, testCp950listleveltext1)
 {
     load(mpTestDocumentPath, "cp950listleveltext1.rtf");
     // suffix with Chinese only ( most common case generated by MSO2010 TC)
-    const sal_Unicode aExpectedSuffix[1]
-        = { 0x3001 }; // This is a dot that is generally used as suffix of Chinese list number
-    uno::Reference<beans::XPropertySet> xPropertySet(
-        getStyles("NumberingStyles")->getByName("WWNum3"), uno::UNO_QUERY);
-    uno::Reference<container::XIndexAccess> xLevels(
-        xPropertySet->getPropertyValue("NumberingRules"), uno::UNO_QUERY);
-    uno::Sequence<beans::PropertyValue> aProps;
-    xLevels->getByIndex(0) >>= aProps; // 1st level
-
-    OUString aSuffix;
-    for (int i = 0; i < aProps.getLength(); ++i)
-    {
-        const beans::PropertyValue& rProp = aProps[i];
+    // This is a dot that is generally used as suffix of Chinese list number
+    const sal_Unicode aExpectedNumbering[] = { 0x4e00, 0x3001 };
 
-        if (rProp.Name == "Suffix")
-            aSuffix = rProp.Value.get<OUString>();
-    }
-    // Suffix was '\0' instead of ' '.
-    CPPUNIT_ASSERT_EQUAL(OUString(aExpectedSuffix, SAL_N_ELEMENTS(aExpectedSuffix)), aSuffix);
+    uno::Reference<beans::XPropertySet> xPara(getParagraph(1), uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(OUString(aExpectedNumbering, SAL_N_ELEMENTS(aExpectedNumbering)),
+                         getProperty<OUString>(xPara, "ListLabelString"));
 }
 
 // This testcase illustrate leveltext with multibyte strings coded in cp950 ( BIG5 ).
@@ -1063,85 +1081,35 @@ CPPUNIT_TEST_FIXTURE(Test, testCp950listleveltext2)
 {
     load(mpTestDocumentPath, "cp950listleveltext2.rtf");
     // Prefix and suffix with Chinese only ( tweaked from default in MSO2010 TC)
-    const sal_Unicode aExpectedPrefix[2] = { 0x524d, 0x7f6e };
-    const sal_Unicode aExpectedSuffix[3] = { 0x3001, 0x5f8c, 0x7f6e };
+    const sal_Unicode aExpectedNumbering[] = { 0x524d, 0x7f6e, 0x7532, 0x3001, 0x5f8c, 0x7f6e };
 
-    uno::Reference<beans::XPropertySet> xPropertySet(
-        getStyles("NumberingStyles")->getByName("WWNum1"), uno::UNO_QUERY);
-    uno::Reference<container::XIndexAccess> xLevels(
-        xPropertySet->getPropertyValue("NumberingRules"), uno::UNO_QUERY);
-    uno::Sequence<beans::PropertyValue> aProps;
-    xLevels->getByIndex(0) >>= aProps; // 1st level
-
-    OUString aSuffix, aPrefix;
-    for (int i = 0; i < aProps.getLength(); ++i)
-    {
-        const beans::PropertyValue& rProp = aProps[i];
-
-        if (rProp.Name == "Suffix")
-            aSuffix = rProp.Value.get<OUString>();
-        if (rProp.Name == "Prefix")
-            aPrefix = rProp.Value.get<OUString>();
-    }
-    // Suffix was '\0' instead of ' '.
-    CPPUNIT_ASSERT_EQUAL(OUString(aExpectedPrefix, SAL_N_ELEMENTS(aExpectedPrefix)), aPrefix);
-    CPPUNIT_ASSERT_EQUAL(OUString(aExpectedSuffix, SAL_N_ELEMENTS(aExpectedSuffix)), aSuffix);
+    uno::Reference<beans::XPropertySet> xPara(getParagraph(1), uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(OUString(aExpectedNumbering, SAL_N_ELEMENTS(aExpectedNumbering)),
+                         getProperty<OUString>(xPara, "ListLabelString"));
 }
 
 // This testcase illustrate leveltext with multibyte strings coded in cp950 ( BIG5 )
 CPPUNIT_TEST_FIXTURE(Test, testCp950listleveltext3)
 {
     load(mpTestDocumentPath, "cp950listleveltext3.rtf");
-    // Prefix and suffix that mix Chinese and English ( tweaked from default in MSO2010 TC)
-    const sal_Unicode aExpectedPrefix[4] = { 0x524d, 0x0061, 0x7f6e, 0x0062 };
-    const sal_Unicode aExpectedSuffix[6] = { 0x3001, 0x0063, 0x5f8c, 0x0064, 0x7f6e, 0x0065 };
+    // Numbering is a mix Chinese and English ( tweaked from default in MSO2010 TC)
+    const sal_Unicode aExpectedNumbering[] = { 0x524d, 0x0061, 0x7f6e, 0x0062, 0x7532, 0x3001,
+                                               0x0063, 0x5f8c, 0x0064, 0x7f6e, 0x0065 };
 
-    uno::Reference<beans::XPropertySet> xPropertySet(
-        getStyles("NumberingStyles")->getByName("WWNum1"), uno::UNO_QUERY);
-    uno::Reference<container::XIndexAccess> xLevels(
-        xPropertySet->getPropertyValue("NumberingRules"), uno::UNO_QUERY);
-    uno::Sequence<beans::PropertyValue> aProps;
-    xLevels->getByIndex(0) >>= aProps; // 1st level
-
-    OUString aSuffix, aPrefix;
-    for (int i = 0; i < aProps.getLength(); ++i)
-    {
-        const beans::PropertyValue& rProp = aProps[i];
-
-        if (rProp.Name == "Suffix")
-            aSuffix = rProp.Value.get<OUString>();
-        if (rProp.Name == "Prefix")
-            aPrefix = rProp.Value.get<OUString>();
-    }
-    // Suffix was '\0' instead of ' '.
-    CPPUNIT_ASSERT_EQUAL(OUString(aExpectedPrefix, SAL_N_ELEMENTS(aExpectedPrefix)), aPrefix);
-    CPPUNIT_ASSERT_EQUAL(OUString(aExpectedSuffix, SAL_N_ELEMENTS(aExpectedSuffix)), aSuffix);
+    uno::Reference<beans::XPropertySet> xPara(getParagraph(1), uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(OUString(aExpectedNumbering, SAL_N_ELEMENTS(aExpectedNumbering)),
+                         getProperty<OUString>(xPara, "ListLabelString"));
 }
 
 CPPUNIT_TEST_FIXTURE(Test, testChtOutlineNumberingRtf)
 {
     load(mpTestDocumentPath, "chtoutline.rtf");
-    const sal_Unicode aExpectedPrefix[2] = { 0x7b2c, 0x0020 };
-    const sal_Unicode aExpectedSuffix[2] = { 0x0020, 0x7ae0 };
-    uno::Reference<text::XChapterNumberingSupplier> xChapterNumberingSupplier(mxComponent,
-                                                                              uno::UNO_QUERY);
-    uno::Reference<container::XIndexAccess> xLevels(
-        xChapterNumberingSupplier->getChapterNumberingRules());
-    uno::Sequence<beans::PropertyValue> aProps;
-    xLevels->getByIndex(0) >>= aProps; // 1st level
 
-    OUString aSuffix, aPrefix;
-    for (int i = 0; i < aProps.getLength(); ++i)
-    {
-        const beans::PropertyValue& rProp = aProps[i];
+    const sal_Unicode aExpectedNumbering[] = { 0x7b2c, ' ', '1', ' ', 0x7ae0 };
 
-        if (rProp.Name == "Suffix")
-            aSuffix = rProp.Value.get<OUString>();
-        if (rProp.Name == "Prefix")
-            aPrefix = rProp.Value.get<OUString>();
-    }
-    CPPUNIT_ASSERT_EQUAL(OUString(aExpectedPrefix, SAL_N_ELEMENTS(aExpectedPrefix)), aPrefix);
-    CPPUNIT_ASSERT_EQUAL(OUString(aExpectedSuffix, SAL_N_ELEMENTS(aExpectedSuffix)), aSuffix);
+    uno::Reference<beans::XPropertySet> xPara(getParagraph(1), uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(OUString(aExpectedNumbering, SAL_N_ELEMENTS(aExpectedNumbering)),
+                         getProperty<OUString>(xPara, "ListLabelString"));
 }
 
 CPPUNIT_TEST_FIXTURE(Test, testTdf90046)
diff --git a/sw/source/core/doc/number.cxx b/sw/source/core/doc/number.cxx
index cce3aefe0714..d26c48fe579d 100644
--- a/sw/source/core/doc/number.cxx
+++ b/sw/source/core/doc/number.cxx
@@ -642,64 +642,94 @@ OUString SwNumRule::MakeNumString( const SwNumberTree::tNumberVector & rNumVecto
         const SwNumFormat& rMyNFormat = Get( static_cast<sal_uInt16>(nLevel) );
 
         {
-            SwNumberTree::tNumberVector::size_type i = nLevel;
+            css::lang::Locale aLocale( LanguageTag::convertToLocale(nLang));
 
-            if( !IsContinusNum() &&
-                // - do not include upper levels, if level isn't numbered.
-                rMyNFormat.GetNumberingType() != SVX_NUM_NUMBER_NONE &&
-                rMyNFormat.GetIncludeUpperLevels() )  // Just the own level?
+            OUString sLevelFormat = rMyNFormat.GetListFormat();
+            if (!sLevelFormat.isEmpty())
             {
-                sal_uInt8 n = rMyNFormat.GetIncludeUpperLevels();
-                if( 1 < n )
+                // In this case we are ignoring GetIncludeUpperLevels: we put all
+                // level nubers requested by level format
+                for (SwNumberTree::tNumberVector::size_type i=0; i <= nLevel; ++i)
                 {
-                    if( i+1 >= n )
-                        i -= n - 1;
+                    OUString sReplacement;
+                    if (rNumVector[i])
+                    {
+                        if (bOnlyArabic)
+                            sReplacement = OUString::number(rNumVector[i]);
+                        else
+                            sReplacement = Get(i).GetNumStr(rNumVector[i], aLocale);
+                    }
                     else
-                        i = 0;
+                        sReplacement = "0";        // all 0 level are a 0
+
+                    OUString sFind("%" + OUString::number(i + 1));
+                    sal_Int32 nPosition = sLevelFormat.indexOf(sFind);
+                    if (nPosition >= 0)
+                        sLevelFormat = sLevelFormat.replaceAt(nPosition, sFind.getLength(), sReplacement);
                 }
+                aStr = sLevelFormat;
             }
-
-            css::lang::Locale aLocale( LanguageTag::convertToLocale(nLang));
-
-            for( ; i <= nLevel; ++i )
+            else
             {
-                const SwNumFormat& rNFormat = Get( i );
-                if( SVX_NUM_NUMBER_NONE == rNFormat.GetNumberingType() )
+                // Fallback case: level format is not defined
+                // So use old way with levels joining by dot "."
+                SwNumberTree::tNumberVector::size_type i = nLevel;
+
+                if (!IsContinusNum() &&
+                    // - do not include upper levels, if level isn't numbered.
+                    rMyNFormat.GetNumberingType() != SVX_NUM_NUMBER_NONE &&
+                    rMyNFormat.GetIncludeUpperLevels())  // Just the own level?
                 {
-                    // Should 1.1.1 --> 2. NoNum --> 1..1 or 1.1 ??
-                    //                 if( i != rNum.nMyLevel )
-                    //                    aStr += ".";
-                    continue;
+                    sal_uInt8 n = rMyNFormat.GetIncludeUpperLevels();
+                    if (1 < n)
+                    {
+                        if (i + 1 >= n)
+                            i -= n - 1;
+                        else
+                            i = 0;
+                    }
                 }
 
-                if( rNumVector[ i ] )
+                for (; i <= nLevel; ++i)
                 {
-                    if( bOnlyArabic )
-                        aStr.append(OUString::number( rNumVector[ i ] ));
+                    const SwNumFormat& rNFormat = Get(i);
+                    if (SVX_NUM_NUMBER_NONE == rNFormat.GetNumberingType())
+                    {
+                        // Should 1.1.1 --> 2. NoNum --> 1..1 or 1.1 ??
+                        //                 if( i != rNum.nMyLevel )
+                        //                    aStr += ".";
+                        continue;
+                    }
+
+                    if (rNumVector[i])
+                    {
+                        if (bOnlyArabic)
+                            aStr.append(OUString::number(rNumVector[i]));
+                        else
+                            aStr.append(rNFormat.GetNumStr(rNumVector[i], aLocale));
+                    }
                     else
-                        aStr.append(rNFormat.GetNumStr( rNumVector[ i ], aLocale ));
+                        aStr.append("0");        // all 0 level are a 0
+                    if (i != nLevel && !aStr.isEmpty())
+                        aStr.append(".");
                 }
-                else
-                    aStr.append("0");        // all 0 level are a 0
-                if( i != nLevel && !aStr.isEmpty() )
-                    aStr.append(".");
-            }
 
-            // The type doesn't have any number, so don't append
-            // the post-/prefix string
-            if( bInclStrings && !bOnlyArabic &&
-                SVX_NUM_CHAR_SPECIAL != rMyNFormat.GetNumberingType() &&
-                SVX_NUM_BITMAP != rMyNFormat.GetNumberingType() )
-            {
-                const OUString& sPrefix = rMyNFormat.GetPrefix();
-                const OUString& sSuffix = rMyNFormat.GetSuffix();
-
-                aStr.insert(0, sPrefix);
-                aStr.append(sSuffix);
-                if ( pExtremities )
+                // The type doesn't have any number, so don't append
+                // the post-/prefix string
+                if (bInclStrings && !bOnlyArabic &&
+                    SVX_NUM_CHAR_SPECIAL != rMyNFormat.GetNumberingType() &&
+                    SVX_NUM_BITMAP != rMyNFormat.GetNumberingType())
                 {
-                    pExtremities->nPrefixChars = sPrefix.getLength();
-                    pExtremities->nSuffixChars = sSuffix.getLength();
+                    const OUString& sPrefix = rMyNFormat.GetPrefix();
+                    const OUString& sSuffix = rMyNFormat.GetSuffix();
+
+                    aStr.insert(0, sPrefix);
+                    aStr.append(sSuffix);
+                    if (pExtremities)
+                    {
+                        pExtremities->nPrefixChars = sPrefix.getLength();
+                        pExtremities->nSuffixChars = sSuffix.getLength();
+                    }
                 }
             }
         }
diff --git a/sw/source/core/unocore/unosett.cxx b/sw/source/core/unocore/unosett.cxx
index 612a938cc621..2257a49faf1e 100644
--- a/sw/source/core/unocore/unosett.cxx
+++ b/sw/source/core/unocore/unosett.cxx
@@ -1334,6 +1334,10 @@ uno::Sequence<beans::PropertyValue> SwXNumberingRules::GetPropertiesForNumFormat
     aUString = rFormat.GetSuffix();
     aPropertyValues.push_back(comphelper::makePropertyValue("Suffix", aUString));
 
+    //listformat
+    aUString = rFormat.GetListFormat();
+    aPropertyValues.push_back(comphelper::makePropertyValue("ListFormat", aUString));
+
     //char style name
 
     aUString.clear();
@@ -1573,7 +1577,9 @@ void SwXNumberingRules::SetPropertiesToNumFormat(
         // these two are accepted but ignored for some reason
         UNO_NAME_BULLET_REL_SIZE,               // 25
         UNO_NAME_BULLET_COLOR,                  // 26
-        UNO_NAME_GRAPHIC_URL                    // 27
+        UNO_NAME_GRAPHIC_URL,                   // 27
+
+        UNO_NAME_LIST_FORMAT                    // 28
     };
 
     enum {
@@ -2027,6 +2033,13 @@ void SwXNumberingRules::SetPropertiesToNumFormat(
                         bWrongArg = true;
                 }
                 break;
+                case 28: //"ListFormat",
+                {
+                    OUString uTmp;
+                    pProp->Value >>= uTmp;
+                    aFormat.SetListFormat(uTmp);
+                }
+                break;
             }
         }
         if(!bWrongArg && (pSetBrush || pSetSize || pSetVOrient))
diff --git a/sw/source/filter/ww8/wrtw8num.cxx b/sw/source/filter/ww8/wrtw8num.cxx
index d0babf006ed3..cc6795aeb3b2 100644
--- a/sw/source/filter/ww8/wrtw8num.cxx
+++ b/sw/source/filter/ww8/wrtw8num.cxx
@@ -490,7 +490,13 @@ void MSWordExportBase::NumberingLevel(
     const vcl::Font* pBulletFont=nullptr;
     rtl_TextEncoding eChrSet=0;
     FontFamily eFamily=FAMILY_DECORATIVE;
-    if (SVX_NUM_CHAR_SPECIAL == rFormat.GetNumberingType() ||
+
+    if (!rRule.Get(nLvl).GetListFormat().isEmpty())
+    {
+        // We have stored list format, use it
+        sNumStr = rRule.Get(nLvl).GetListFormat();
+    }
+    else if (SVX_NUM_CHAR_SPECIAL == rFormat.GetNumberingType() ||
         SVX_NUM_BITMAP == rFormat.GetNumberingType())
     {
         sNumStr = OUString(rFormat.GetBulletChar());
diff --git a/writerfilter/source/dmapper/NumberingManager.cxx b/writerfilter/source/dmapper/NumberingManager.cxx
index b855028c40f0..0cd64a26e417 100644
--- a/writerfilter/source/dmapper/NumberingManager.cxx
+++ b/writerfilter/source/dmapper/NumberingManager.cxx
@@ -42,6 +42,7 @@
 #include <tools/diagnose_ex.h>
 #include <comphelper/sequence.hxx>
 #include <comphelper/propertyvalue.hxx>
+#include <comphelper/string.hxx>
 
 using namespace com::sun::star;
 
@@ -150,55 +151,6 @@ void ListLevel::SetParaStyle( const tools::SvRef< StyleSheetEntry >& pStyle )
         && styleId[ RTL_CONSTASCII_LENGTH( "Heading " ) ] <= '9' );
 }
 
-sal_Int16 ListLevel::GetParentNumbering( const OUString& sText, sal_Int16 nLevel,
-        OUString& rPrefix, OUString& rSuffix )
-{
-    sal_Int16 nParentNumbering = 1;
-
-    //now parse the text to find %n from %1 to %nLevel+1
-    //everything before the first % and the last %x is prefix and suffix
-    OUString sLevelText( sText );
-    sal_Int32 nCurrentIndex = 0;
-    sal_Int32 nFound = sLevelText.indexOf( '%', nCurrentIndex );
-    if( nFound > 0 )
-    {
-        rPrefix = sLevelText.copy( 0, nFound );
-        sLevelText = sLevelText.copy( nFound );
-    }
-    sal_Int32 nMinLevel = nLevel;
-    //now the text should either be empty or start with %
-    nFound = sLevelText.getLength( ) > 1 ? 0 : -1;
-    while( nFound >= 0 )
-    {
-        if( sLevelText.getLength() > 1 )
-        {
-            sal_Unicode cLevel = sLevelText[1];
-            if( cLevel >= '1' && cLevel <= '9' )
-            {
-                if( cLevel - '1' < nMinLevel )
-                    nMinLevel = cLevel - '1';
-                //remove first char - next char is removed later
-                sLevelText = sLevelText.copy( 1 );
-            }
-        }
-        //remove old '%' or number
-        sLevelText = sLevelText.copy( 1 );
-        nCurrentIndex = 0;
-        nFound = sLevelText.indexOf( '%', nCurrentIndex );
-        //remove the text before the next %
-        if(nFound > 0)
-            sLevelText = sLevelText.copy( nFound -1 );
-    }
-    if( nMinLevel < nLevel )
-    {
-        nParentNumbering = sal_Int16( nLevel - nMinLevel + 1);
-    }
-
-    rSuffix = sLevelText;
-
-    return nParentNumbering;
-}
-
 uno::Sequence<beans::PropertyValue> ListLevel::GetProperties(bool bDefaults)
 {
     uno::Sequence<beans::PropertyValue> aLevelProps = GetLevelProperties(bDefaults);
@@ -598,19 +550,11 @@ void ListDef::CreateNumberingRules( DomainMapper& rDMapper,
                 if (pLevel.get() && !pLevel->GetBulletChar().isEmpty())
                     sText = pLevel->GetBulletChar( );
 
-                OUString sPrefix;
-                OUString sSuffix;
-                OUString& rPrefix = sPrefix;
-                OUString& rSuffix = sSuffix;
-                sal_Int16 nParentNum = ListLevel::GetParentNumbering(
-                       sText, nLevel, rPrefix, rSuffix );
-
-                aLvlProps.push_back(comphelper::makePropertyValue(getPropertyName(PROP_PREFIX), rPrefix));
-
                 if (sText.isEmpty())
                 {
                     // Empty <w:lvlText>? Then put a Unicode "zero width space" as a suffix, so LabelFollowedBy is still shown, as in Word.
                     // With empty suffix, Writer does not show LabelFollowedBy, either.
+                    OUString sSuffix;
                     auto it = std::find_if(aLvlProps.begin(), aLvlProps.end(), [](const beans::PropertyValue& rValue) { return rValue.Name == "NumberingType"; });
                     if (it != aLvlProps.end())
                     {
@@ -627,12 +571,19 @@ void ListDef::CreateNumberingRules( DomainMapper& rDMapper,
                         }
 
                         if (bLabelFollowedBy && nNumberFormat == style::NumberingType::NUMBER_NONE)
-                            rSuffix = OUString(u'\x200B');
+                            sSuffix = OUString(u'\x200B');
                     }
+                    aLvlProps.push_back(comphelper::makePropertyValue(getPropertyName(PROP_SUFFIX), sSuffix));
                 }
+                else
+                {
+                    aLvlProps.push_back(comphelper::makePropertyValue(getPropertyName(PROP_LIST_FORMAT), sText));
 
-                aLvlProps.push_back(comphelper::makePropertyValue(getPropertyName(PROP_SUFFIX), rSuffix));
-                aLvlProps.push_back(comphelper::makePropertyValue(getPropertyName(PROP_PARENT_NUMBERING), nParentNum));
+                    // Total count of replacement holders is determining amount of required parent numbering to include
+                    // TODO: not sure how "%" symbol is escaped. This is not supported yet
+                    sal_Int16 nParentNum = comphelper::string::getTokenCount(sText, '%');
+                    aLvlProps.push_back(comphelper::makePropertyValue(getPropertyName(PROP_PARENT_NUMBERING), nParentNum));
+                }
 
                 aLvlProps.push_back(comphelper::makePropertyValue(getPropertyName(PROP_POSITION_AND_SPACE_MODE), sal_Int16(text::PositionAndSpaceMode::LABEL_ALIGNMENT)));
 
diff --git a/writerfilter/source/dmapper/NumberingManager.hxx b/writerfilter/source/dmapper/NumberingManager.hxx
index 6fed0a0be801..9719e74d87f4 100644
--- a/writerfilter/source/dmapper/NumberingManager.hxx
+++ b/writerfilter/source/dmapper/NumberingManager.hxx
@@ -88,11 +88,6 @@ public:
     bool HasValues() const;
 
     // UNO mapping functions
-
-    // rPrefix and rSuffix are out parameters
-    static sal_Int16 GetParentNumbering( const OUString& sText, sal_Int16 nLevel,
-        OUString& rPrefix, OUString& rSuffix );
-
     css::uno::Sequence<css::beans::PropertyValue> GetProperties(bool bDefaults);
 
     css::uno::Sequence<css::beans::PropertyValue> GetCharStyleProperties();
diff --git a/writerfilter/source/dmapper/PropertyIds.cxx b/writerfilter/source/dmapper/PropertyIds.cxx
index 64a9ee063f77..7428097f0953 100644
--- a/writerfilter/source/dmapper/PropertyIds.cxx
+++ b/writerfilter/source/dmapper/PropertyIds.cxx
@@ -206,6 +206,7 @@ OUString getPropertyName( PropertyIds eId )
         case PROP_LEVEL_FOLLOW           :    sName = "LabelFollowedBy"; break;
         case PROP_LEVEL_PARAGRAPH_STYLES :    sName = "LevelParagraphStyles"; break;
         case PROP_LEVEL_FORMAT           :    sName = "LevelFormat"; break;
+        case PROP_LIST_FORMAT            :    sName = "ListFormat"; break;
         case PROP_TOKEN_TYPE             :    sName = "TokenType"; break;
         case PROP_TOKEN_HYPERLINK_START  :    sName = "TokenHyperlinkStart"; break;
         case PROP_TOKEN_HYPERLINK_END    :    sName = "TokenHyperlinkEnd"; break;
diff --git a/writerfilter/source/dmapper/PropertyIds.hxx b/writerfilter/source/dmapper/PropertyIds.hxx
index 9fe42ee69ac1..e30aeb813e1c 100644
--- a/writerfilter/source/dmapper/PropertyIds.hxx
+++ b/writerfilter/source/dmapper/PropertyIds.hxx
@@ -207,6 +207,7 @@ enum PropertyIds
         ,PROP_LEVEL_FORMAT
         ,PROP_LEVEL_PARAGRAPH_STYLES
         ,PROP_LISTTAB_STOP_POSITION
+        ,PROP_LIST_FORMAT
         ,PROP_MACRO_NAME
         ,PROP_NAME
         ,PROP_NUMBERING_LEVEL


More information about the Libreoffice-commits mailing list