sw/inc/fmtcol.hxx                             |    3 
 sw/inc/ndtxt.hxx                              |   10 -
 sw/inc/paratr.hxx                             |    9 +
 sw/qa/extras/odfexport/data/WordTest_edit.odt |binary
 sw/qa/extras/odfexport/odfexport2.cxx         |  163 ++++++++++++++++++++++++++
 sw/source/core/doc/docfmt.cxx                 |   13 +-
 sw/source/core/doc/fmtcol.cxx                 |   20 ++-
 sw/source/core/layout/frmtool.cxx             |    1 
 sw/source/core/text/itrcrsr.cxx               |   10 -
 sw/source/core/txtnode/ndtxt.cxx              |   94 ++++++++++----
 sw/source/core/txtnode/thints.cxx             |   17 +-
 sw/source/filter/ww8/wrtw8nds.cxx             |   14 +-
 sw/source/filter/ww8/ww8par6.cxx              |    3 
 sw/source/uibase/app/docstyle.cxx             |   17 +-
 14 files changed, 312 insertions(+), 62 deletions(-)

New commits:
commit 0168e1eb65103afde24d4a2a62175946b1c0d33e
Author:     Michael Stahl <michael.st...@allotropia.de>
AuthorDate: Thu Feb 16 19:39:33 2023 +0100
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Fri Feb 24 07:32:30 2023 +0000

    tdf#78510 sw: combine items from SwTextNode and SwNumFormat
    
    Tweak SwTextFormatColl::AreListLevelIndentsApplicable() and
    SwTextNode::AreListLevelIndentsApplicable() to return a bitmask
    so that SvxFirstLineIndentItem and SvxTextLeftMarginItem from paragraph
    or numbering can be freely combined.
    
    Particularly confusing was SwTextNode::GetLeftMarginWithNum()
    and its baffling usage in SwTextMargin::CtorInitTextMargin(); it
    appears easiest (if unintuitive) to interpret its return value as a
    delta to be added to the paragraph's items.
    
    This fixes the ODF interop problem.
    
    It looks like no compat setting is needed because every OOo/LO generated
    document should have either both fo:text-indent and fo:margin-left on a
    paragraph style/list level, or neither.
    
    Change-Id: If20b2556bb5ab5d915a2aa6633525bb44a9be33b
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/147166
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/sw/inc/fmtcol.hxx b/sw/inc/fmtcol.hxx
index 6a477e1f5ca3..c914a6058ccf 100644
--- a/sw/inc/fmtcol.hxx
+++ b/sw/inc/fmtcol.hxx
@@ -143,7 +143,8 @@ public:
         return mbStayAssignedToListLevelOfOutlineStyle;
     }
 
-    bool AreListLevelIndentsApplicable() const;
+    ::sw::ListLevelIndents AreListLevelIndentsApplicable() const;
+    bool AreListLevelIndentsApplicableImpl(sal_uInt16 nWhich) const;
 
     void dumpAsXml(xmlTextWriterPtr pWriter) const;
     virtual void FormatDropNotify(const SwFormatDrop& rDrop) override
diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx
index 0ea123233d69..4b15545b41bc 100644
--- a/sw/inc/ndtxt.hxx
+++ b/sw/inc/ndtxt.hxx
@@ -516,9 +516,10 @@ public:
     /**
        Returns the additional indents of this text node and its numbering.
 
-       @param bTextLeft  ???
+       @param bTextLeft return text-left-margin instead of left-margin
+                        (include negative first-line-indent, see lrspitem.hxx)
 
-       @return additional indents
+       @return additional num indents - a delta to be added to node's items
      */
      tools::Long GetLeftMarginWithNum( bool bTextLeft = false ) const;
 
@@ -693,9 +694,10 @@ public:
           style hierarchy from the paragraph to the paragraph style with the
           list style no indent attributes are found.
 
-        @return boolean
+        @return bitmask
     */
-    bool AreListLevelIndentsApplicable() const;
+    ::sw::ListLevelIndents AreListLevelIndentsApplicable() const;
+    bool AreListLevelIndentsApplicableImpl(sal_uInt16 nWhich) const;
 
     /** Retrieves the list tab stop position, if the paragraph's list level 
defines
         one and this list tab stop has to merged into the tap stops of the 
paragraph
diff --git a/sw/inc/paratr.hxx b/sw/inc/paratr.hxx
index c6848491f8e9..9b5f2b156430 100644
--- a/sw/inc/paratr.hxx
+++ b/sw/inc/paratr.hxx
@@ -38,6 +38,7 @@
 #include <editeng/forbiddenruleitem.hxx>
 #include <editeng/paravertalignitem.hxx>
 #include <editeng/pgrditem.hxx>
+#include <o3tl/typed_flags_set.hxx>
 
 class SwTextNode;
 class IntlWrapper;
@@ -47,6 +48,9 @@ class IntlWrapper;
 class SwFormatDrop;
 
 namespace sw {
+
+    enum class ListLevelIndents { No, FirstLine, LeftMargin };
+
     class SW_DLLPUBLIC FormatDropDefiner {
         protected:
             virtual ~FormatDropDefiner() {};
@@ -55,6 +59,11 @@ namespace sw {
     };
 }
 
+namespace o3tl
+{
+    template<> struct typed_flags<sw::ListLevelIndents> : 
is_typed_flags<sw::ListLevelIndents, 0x03> {};
+}
+
 /** If SwFormatDrop is a Client, it is the CharFormat that describes the font 
for the
    DropCaps. If it is not a Client, formatting uses the CharFormat of the 
paragraph.
    If the CharFormat is modified, this change is propagated to the paragraphs
diff --git a/sw/qa/extras/odfexport/data/WordTest_edit.odt 
b/sw/qa/extras/odfexport/data/WordTest_edit.odt
new file mode 100644
index 000000000000..4c14295e930d
Binary files /dev/null and b/sw/qa/extras/odfexport/data/WordTest_edit.odt 
differ
diff --git a/sw/qa/extras/odfexport/odfexport2.cxx 
b/sw/qa/extras/odfexport/odfexport2.cxx
index 35e22a59f331..db6c4d4240ae 100644
--- a/sw/qa/extras/odfexport/odfexport2.cxx
+++ b/sw/qa/extras/odfexport/odfexport2.cxx
@@ -31,6 +31,7 @@
 #include <comphelper/propertysequence.hxx>
 #include <comphelper/sequenceashashmap.hxx>
 #include <unoprnms.hxx>
+#include <unotxdoc.hxx>
 #include <docsh.hxx>
 
 class Test : public SwModelTestBase
@@ -849,6 +850,168 @@ DECLARE_ODFEXPORT_TEST(testSectionColumnSeparator, 
"section-columns-separator.fo
     CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xColumns, 
"SeparatorLineIsOn"));
 }
 
+DECLARE_ODFEXPORT_TEST(testTdf78510, "WordTest_edit.odt")
+{
+    uno::Reference<container::XIndexAccess> const xLevels1(
+        getProperty<uno::Reference<container::XIndexAccess>>(getParagraph(1), 
"NumberingRules"));
+    ::comphelper::SequenceAsHashMap props1(xLevels1->getByIndex(0));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(-1000), 
props1["FirstLineIndent"].get<sal_Int32>());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(2000), props1["IndentAt"].get<sal_Int32>());
+
+    // 1: inherited from paragraph style and overridden by list
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(getParagraph(1), 
"ParaFirstLineIndent"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1270), 
getProperty<sal_Int32>(getParagraph(1), "ParaLeftMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(getParagraph(1), 
"ParaRightMargin"));
+    // 2: as 1 + paragraph sets firstline
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), 
getProperty<sal_Int32>(getParagraph(2), "ParaFirstLineIndent"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1270), 
getProperty<sal_Int32>(getParagraph(2), "ParaLeftMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(getParagraph(2), 
"ParaRightMargin"));
+    // 3: as 1 + paragraph sets textleft
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(getParagraph(3), 
"ParaFirstLineIndent"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(3000), 
getProperty<sal_Int32>(getParagraph(3), "ParaLeftMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(getParagraph(3), 
"ParaRightMargin"));
+    // 4: as 1 + paragraph sets firstline, textleft
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(-2000), 
getProperty<sal_Int32>(getParagraph(4), "ParaFirstLineIndent"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(3000), 
getProperty<sal_Int32>(getParagraph(4), "ParaLeftMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(getParagraph(4), 
"ParaRightMargin"));
+    // 5: as 1 + paragraph sets firstline
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(-2000), 
getProperty<sal_Int32>(getParagraph(5), "ParaFirstLineIndent"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1270), 
getProperty<sal_Int32>(getParagraph(5), "ParaLeftMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(getParagraph(5), 
"ParaRightMargin"));
+    // 6: as 1
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(getParagraph(6), 
"ParaFirstLineIndent"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1270), 
getProperty<sal_Int32>(getParagraph(6), "ParaLeftMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(getParagraph(6), 
"ParaRightMargin"));
+
+    uno::Reference<container::XIndexAccess> const xLevels8(
+        getProperty<uno::Reference<container::XIndexAccess>>(getParagraph(8), 
"NumberingRules"));
+    ::comphelper::SequenceAsHashMap props8(xLevels8->getByIndex(0));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), 
props8["FirstLineIndent"].get<sal_Int32>());
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1000), props8["IndentAt"].get<sal_Int32>());
+
+    // 8: inherited from paragraph style and overridden by list
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(getParagraph(8), 
"ParaFirstLineIndent"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1270), 
getProperty<sal_Int32>(getParagraph(8), "ParaLeftMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(getParagraph(8), 
"ParaRightMargin"));
+    // 9: as 8 + paragraph sets firstline
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(2000), 
getProperty<sal_Int32>(getParagraph(9), "ParaFirstLineIndent"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1270), 
getProperty<sal_Int32>(getParagraph(9), "ParaLeftMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty<sal_Int32>(getParagraph(9), 
"ParaRightMargin"));
+    // 10: as 8 + paragraph sets textleft
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), 
getProperty<sal_Int32>(getParagraph(10), "ParaFirstLineIndent"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(3000), 
getProperty<sal_Int32>(getParagraph(10), "ParaLeftMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), 
getProperty<sal_Int32>(getParagraph(10), "ParaRightMargin"));
+    // 11: as 8 + paragraph sets firstline, textleft
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(-2000), 
getProperty<sal_Int32>(getParagraph(11), "ParaFirstLineIndent"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(3000), 
getProperty<sal_Int32>(getParagraph(11), "ParaLeftMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), 
getProperty<sal_Int32>(getParagraph(11), "ParaRightMargin"));
+    // 12: as 8 + paragraph sets firstline
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(-2000), 
getProperty<sal_Int32>(getParagraph(12), "ParaFirstLineIndent"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1270), 
getProperty<sal_Int32>(getParagraph(12), "ParaLeftMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), 
getProperty<sal_Int32>(getParagraph(12), "ParaRightMargin"));
+    // 13: as 8
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), 
getProperty<sal_Int32>(getParagraph(13), "ParaFirstLineIndent"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1270), 
getProperty<sal_Int32>(getParagraph(13), "ParaLeftMargin"));
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), 
getProperty<sal_Int32>(getParagraph(13), "ParaRightMargin"));
+
+    // unfortunately it appears that the portions don't have a position
+    // so it's not possible to check the first-line-offset that's applied
+    // (the first-line-indent is computed on the fly in SwTextMargin when
+    // painting)
+    {
+        xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/infos/prtBounds", 
"left", "567");
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/infos/prtBounds", 
"right", "9359");
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/infos/prtBounds", 
"left", "1134");
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/infos/prtBounds", 
"right", "9359");
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/infos/prtBounds", 
"left", "1134");
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/infos/prtBounds", 
"right", "9359");
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[4]/infos/prtBounds", 
"left", "567");
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[4]/infos/prtBounds", 
"right", "9359");
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[5]/infos/prtBounds", 
"left", "0");
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[5]/infos/prtBounds", 
"right", "9359");
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[6]/infos/prtBounds", 
"left", "567");
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[6]/infos/prtBounds", 
"right", "9359");
+
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[8]/infos/prtBounds", 
"left", "567");
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[8]/infos/prtBounds", 
"right", "9359");
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[9]/infos/prtBounds", 
"left", "567");
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[9]/infos/prtBounds", 
"right", "9359");
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[10]/infos/prtBounds", 
"left", "1701");
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[10]/infos/prtBounds", 
"right", "9359");
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[11]/infos/prtBounds", 
"left", "567");
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[11]/infos/prtBounds", 
"right", "9359");
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[12]/infos/prtBounds", 
"left", "-567");
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[12]/infos/prtBounds", 
"right", "9359");
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[13]/infos/prtBounds", 
"left", "567");
+        assertXPath(pXmlDoc, "/root/page[1]/body/txt[13]/infos/prtBounds", 
"right", "9359");
+    }
+
+    // now check the positions where text is actually painted -
+    // wonder how fragile this is...
+    // FIXME some platform difference, 1st one is 2306 on Linux, 3087 on WNT ?
+#ifndef WNT
+    {
+        SwDocShell *const 
pShell(dynamic_cast<SwXTextDocument&>(*mxComponent).GetDocShell());
+        std::shared_ptr<GDIMetaFile> pMetaFile = pShell->GetPreviewMetaFile();
+        MetafileXmlDump aDumper;
+        xmlDocUniquePtr pXmlDoc = dumpAndParse(aDumper, *pMetaFile);
+
+        // 1: inherited from paragraph style and overridden by list
+        // bullet char is extra
+
+        assertXPath(pXmlDoc, "//textarray[1]", "x", "2306");
+        // text is after a tab from list - haven't checked if that is correct?
+        assertXPath(pXmlDoc, "//textarray[2]", "x", "2873");
+        // second line
+        assertXPath(pXmlDoc, "//textarray[3]", "x", "2873");
+        // 2: as 1 + paragraph sets firstline
+        assertXPath(pXmlDoc, "//textarray[4]", "x", "3440");
+        assertXPath(pXmlDoc, "//textarray[5]", "x", "3593");
+        assertXPath(pXmlDoc, "//textarray[6]", "x", "2873");
+        // 3: as 1 + paragraph sets textleft
+        assertXPath(pXmlDoc, "//textarray[7]", "x", "2873");
+        assertXPath(pXmlDoc, "//textarray[8]", "x", "3440");
+        assertXPath(pXmlDoc, "//textarray[9]", "x", "3440");
+        // 4: as 1 + paragraph sets firstline, textleft
+        assertXPath(pXmlDoc, "//textarray[10]", "x", "2306");
+        assertXPath(pXmlDoc, "//textarray[11]", "x", "3440");
+        assertXPath(pXmlDoc, "//textarray[12]", "x", "3440");
+        // 5: as 1 + paragraph sets firstline
+        assertXPath(pXmlDoc, "//textarray[13]", "x", "1739");
+        assertXPath(pXmlDoc, "//textarray[14]", "x", "2873");
+        assertXPath(pXmlDoc, "//textarray[15]", "x", "2873");
+        // 6: as 1
+        assertXPath(pXmlDoc, "//textarray[16]", "x", "2306");
+        assertXPath(pXmlDoc, "//textarray[17]", "x", "2873");
+
+        // 8: inherited from paragraph style and overridden by list
+        assertXPath(pXmlDoc, "//textarray[18]", "x", "2873");
+        assertXPath(pXmlDoc, "//textarray[19]", "x", "3746");
+        assertXPath(pXmlDoc, "//textarray[20]", "x", "2306");
+        // 9: as 8 + paragraph sets firstline
+        assertXPath(pXmlDoc, "//textarray[21]", "x", "3440");
+        assertXPath(pXmlDoc, "//textarray[22]", "x", "3746");
+        assertXPath(pXmlDoc, "//textarray[23]", "x", "2306");
+        // 10: as 8 + paragraph sets textleft
+        assertXPath(pXmlDoc, "//textarray[24]", "x", "4007");
+        assertXPath(pXmlDoc, "//textarray[25]", "x", "4880");
+        assertXPath(pXmlDoc, "//textarray[26]", "x", "3440");
+        // 11: as 8 + paragraph sets firstline, textleft
+        assertXPath(pXmlDoc, "//textarray[27]", "x", "2306");
+        assertXPath(pXmlDoc, "//textarray[28]", "x", "3440");
+        assertXPath(pXmlDoc, "//textarray[29]", "x", "3440");
+        // 12: as 8 + paragraph sets firstline
+        assertXPath(pXmlDoc, "//textarray[30]", "x", "1172");
+        assertXPath(pXmlDoc, "//textarray[31]", "x", "1739");
+        assertXPath(pXmlDoc, "//textarray[32]", "x", "2306");
+        // 13: as 8
+        assertXPath(pXmlDoc, "//textarray[33]", "x", "2873");
+        assertXPath(pXmlDoc, "//textarray[34]", "x", "3746");
+    }
+#endif
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/doc/docfmt.cxx b/sw/source/core/doc/docfmt.cxx
index e990919ed719..f633dd4985b7 100644
--- a/sw/source/core/doc/docfmt.cxx
+++ b/sw/source/core/doc/docfmt.cxx
@@ -1653,7 +1653,8 @@ void SwDoc::MoveLeftMargin(const SwPaM& rPam, bool 
bRight, bool bModulus,
             SvxTextLeftMarginItem 
leftMargin(pTNd->SwContentNode::GetAttr(RES_MARGIN_TEXTLEFT));
 
             // #i93873# See also lcl_MergeListLevelIndentAsLRSpaceItem in 
thints.cxx
-            if ( pTNd->AreListLevelIndentsApplicable() )
+            ::sw::ListLevelIndents const 
indents(pTNd->AreListLevelIndentsApplicable());
+            if (indents != ::sw::ListLevelIndents::No)
             {
                 const SwNumRule* pRule = pTNd->GetNumRule();
                 if ( pRule )
@@ -1664,8 +1665,14 @@ void SwDoc::MoveLeftMargin(const SwPaM& rPam, bool 
bRight, bool bModulus,
                         const SwNumFormat& rFormat = 
pRule->Get(o3tl::narrowing<sal_uInt16>(nListLevel));
                         if ( rFormat.GetPositionAndSpaceMode() == 
SvxNumberFormat::LABEL_ALIGNMENT )
                         {
-                            leftMargin.SetTextLeft(rFormat.GetIndentAt());
-                            
firstLine.SetTextFirstLineOffset(static_cast<short>(rFormat.GetFirstLineIndent()));
+                            if (indents & ::sw::ListLevelIndents::LeftMargin)
+                            {
+                                leftMargin.SetTextLeft(rFormat.GetIndentAt());
+                            }
+                            if (indents & ::sw::ListLevelIndents::FirstLine)
+                            {
+                                
firstLine.SetTextFirstLineOffset(static_cast<short>(rFormat.GetFirstLineIndent()));
+                            }
                         }
                     }
                 }
diff --git a/sw/source/core/doc/fmtcol.cxx b/sw/source/core/doc/fmtcol.cxx
index 95cd8754fb44..734fd1312325 100644
--- a/sw/source/core/doc/fmtcol.cxx
+++ b/sw/source/core/doc/fmtcol.cxx
@@ -472,7 +472,21 @@ sal_uInt16 SwTextFormatColl::ResetAllFormatAttr()
     return nRet;
 }
 
-bool SwTextFormatColl::AreListLevelIndentsApplicable() const
+::sw::ListLevelIndents SwTextFormatColl::AreListLevelIndentsApplicable() const
+{
+    ::sw::ListLevelIndents ret(::sw::ListLevelIndents::No);
+    if (AreListLevelIndentsApplicableImpl(RES_MARGIN_FIRSTLINE))
+    {
+        ret |= ::sw::ListLevelIndents::FirstLine;
+    }
+    if (AreListLevelIndentsApplicableImpl(RES_MARGIN_TEXTLEFT))
+    {
+        ret |= ::sw::ListLevelIndents::LeftMargin;
+    }
+    return ret;
+}
+
+bool SwTextFormatColl::AreListLevelIndentsApplicableImpl(sal_uInt16 const 
nWhich) const
 {
     bool bAreListLevelIndentsApplicable( true );
 
@@ -481,7 +495,7 @@ bool SwTextFormatColl::AreListLevelIndentsApplicable() const
         // no list style applied to paragraph style
         bAreListLevelIndentsApplicable = false;
     }
-    else if ( GetItemState( RES_LR_SPACE, false ) == SfxItemState::SET )
+    else if (GetItemState(nWhich, false ) == SfxItemState::SET)
     {
         // paragraph style has hard-set indent attributes
         bAreListLevelIndentsApplicable = false;
@@ -501,7 +515,7 @@ bool SwTextFormatColl::AreListLevelIndentsApplicable() const
         const SwTextFormatColl* pColl = dynamic_cast<const 
SwTextFormatColl*>(DerivedFrom());
         while ( pColl )
         {
-            if ( pColl->GetAttrSet().GetItemState( RES_LR_SPACE, false ) == 
SfxItemState::SET )
+            if (pColl->GetAttrSet().GetItemState(nWhich, false) == 
SfxItemState::SET)
             {
                 // indent attributes found in the paragraph style hierarchy.
                 bAreListLevelIndentsApplicable = false;
diff --git a/sw/source/core/layout/frmtool.cxx 
b/sw/source/core/layout/frmtool.cxx
index bcdb49c292eb..966500ecfeac 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -2257,7 +2257,6 @@ SwBorderAttrs::SwBorderAttrs(const sw::BorderCacheOwner* 
pOwner, const SwFrame*
         m_pFirstLineIndent.reset(m_rAttrSet.GetFirstLineIndent().Clone());
         m_pTextLeftMargin.reset(m_rAttrSet.GetTextLeftMargin().Clone());
         m_pRightMargin.reset(m_rAttrSet.GetRightMargin().Clone());
-        
pTextFrame->GetTextNodeForParaProps()->ClearLRSpaceItemDueToListLevelIndents(m_pFirstLineIndent,
 m_pTextLeftMargin);
         assert(m_pFirstLineIndent);
         assert(m_pTextLeftMargin);
     }
diff --git a/sw/source/core/text/itrcrsr.cxx b/sw/source/core/text/itrcrsr.cxx
index 7158aa9f0d8f..7963b0aa177c 100644
--- a/sw/source/core/text/itrcrsr.cxx
+++ b/sw/source/core/text/itrcrsr.cxx
@@ -167,7 +167,7 @@ void SwTextMargin::CtorInitTextMargin( SwTextFrame 
*pNewFrame, SwTextSizeInfo *p
     // #i111284#
     const SwTextNode *pTextNode = m_pFrame->GetTextNodeForParaProps();
     const bool bLabelAlignmentActive = IsLabelAlignmentActive( *pTextNode );
-    const bool bListLevelIndentsApplicable = 
pTextNode->AreListLevelIndentsApplicable();
+    const bool bListLevelIndentsApplicable = 
pTextNode->AreListLevelIndentsApplicable() != ::sw::ListLevelIndents::No;
     const bool bListLevelIndentsApplicableAndLabelAlignmentActive = 
bListLevelIndentsApplicable && bLabelAlignmentActive;
 
     // Carefully adjust the text formatting ranges.
@@ -192,9 +192,7 @@ void SwTextMargin::CtorInitTextMargin( SwTextFrame 
*pNewFrame, SwTextSizeInfo *p
                 // #i95907#
                 // #i111284#
                 // rSpace.GetLeft() + rSpace.GetTextLeft();
-                ( bListLevelIndentsApplicableAndLabelAlignmentActive
-                  ? 0
-                  : (rTextLeftMargin.GetLeft(rFirstLine) - 
rTextLeftMargin.GetTextLeft()));
+                (rTextLeftMargin.GetLeft(rFirstLine) - 
rTextLeftMargin.GetTextLeft());
     }
     else
     {
@@ -210,9 +208,7 @@ void SwTextMargin::CtorInitTextMargin( SwTextFrame 
*pNewFrame, SwTextSizeInfo *p
                     pNode->GetLeftMarginWithNum() -
                     // #i95907#
                     // #i111284#
-                    ( bListLevelIndentsApplicableAndLabelAlignmentActive
-                      ? 0
-                      : (rTextLeftMargin.GetLeft(rFirstLine) - 
rTextLeftMargin.GetTextLeft()));
+                    (rTextLeftMargin.GetLeft(rFirstLine) - 
rTextLeftMargin.GetTextLeft());
         }
         else
         {
diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx
index ed2065f02c70..63ad3c93bbdd 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -3301,17 +3301,28 @@ tools::Long SwTextNode::GetLeftMarginWithNum( bool 
bTextLeft ) const
         }
         else if ( rFormat.GetPositionAndSpaceMode() == 
SvxNumberFormat::LABEL_ALIGNMENT )
         {
-            if ( AreListLevelIndentsApplicable() )
+            ::sw::ListLevelIndents const 
indents(AreListLevelIndentsApplicable());
+            // note: the result is *always* added to either the left-margin
+            // or the text-left-margin of the node itself by the caller.
+            // so first, subtract what the caller has computed anyway,
+            // and then add the value according to combination of
+            // list/paragraph items. (this is rather inelegant)
+            SvxFirstLineIndentItem 
firstLine(GetSwAttrSet().GetFirstLineIndent());
+            SvxTextLeftMarginItem 
leftMargin(GetSwAttrSet().GetTextLeftMargin());
+            nRet = bTextLeft
+                ? - leftMargin.GetTextLeft()
+                : - leftMargin.GetLeft(firstLine);
+            if (indents & ::sw::ListLevelIndents::LeftMargin)
             {
-                nRet = rFormat.GetIndentAt();
-                // #i90401#
-                // Only negative first line indents have consider for the left 
margin
-                if ( !bTextLeft &&
-                     rFormat.GetFirstLineIndent() < 0 )
-                {
-                    nRet = nRet + rFormat.GetFirstLineIndent();
-                }
+                leftMargin.SetTextLeft(rFormat.GetIndentAt());
             }
+            if (indents & ::sw::ListLevelIndents::FirstLine)
+            {
+                firstLine.SetTextFirstLineOffset(rFormat.GetFirstLineIndent());
+            }
+            nRet += bTextLeft
+                ? leftMargin.GetTextLeft()
+                : leftMargin.GetLeft(firstLine);
         }
     }
 
@@ -3342,7 +3353,7 @@ bool SwTextNode::GetFirstLineOfsWithNum( short& rFLOffset 
) const
             }
             else if ( rFormat.GetPositionAndSpaceMode() == 
SvxNumberFormat::LABEL_ALIGNMENT )
             {
-                if ( AreListLevelIndentsApplicable() )
+                if (AreListLevelIndentsApplicable() & 
::sw::ListLevelIndents::FirstLine)
                 {
                     rFLOffset = rFormat.GetFirstLineIndent();
                 }
@@ -3382,18 +3393,24 @@ SwTwips 
SwTextNode::GetAdditionalIndentForStartingNewList() const
         }
         else if ( rFormat.GetPositionAndSpaceMode() == 
SvxNumberFormat::LABEL_ALIGNMENT )
         {
-            if ( AreListLevelIndentsApplicable() )
-            {
-                nAdditionalIndent = rFormat.GetIndentAt() + 
rFormat.GetFirstLineIndent();
-            }
-            else
+            // note: there was an apparent bug here, list GetIndentAt()
+            // was interpreted as left-margin not text-left-margin unlike every
+            // other use of it.
+            ::sw::ListLevelIndents const 
indents(AreListLevelIndentsApplicable());
+            SvxFirstLineIndentItem const& rFirst(
+                    indents & ::sw::ListLevelIndents::FirstLine
+                    ? SvxFirstLineIndentItem(rFormat.GetFirstLineIndent(), 
RES_MARGIN_FIRSTLINE)
+                    : GetSwAttrSet().GetFirstLineIndent());
+            SvxTextLeftMarginItem const& rLeft(
+                    indents & ::sw::ListLevelIndents::LeftMargin
+                    ? SvxTextLeftMarginItem(rFormat.GetIndentAt(), 
RES_MARGIN_TEXTLEFT)
+                    : GetSwAttrSet().GetTextLeftMargin());
+            nAdditionalIndent = rLeft.GetLeft(rFirst);
+            if (!(indents & ::sw::ListLevelIndents::FirstLine))
             {
-                SvxFirstLineIndentItem const& 
rFirst(GetSwAttrSet().GetFirstLineIndent());
-                nAdditionalIndent = 
GetSwAttrSet().GetTextLeftMargin().GetLeft(rFirst);
                 if 
(getIDocumentSettingAccess()->get(DocumentSettingId::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING))
                 {
-                    nAdditionalIndent = nAdditionalIndent -
-                        
GetSwAttrSet().GetFirstLineIndent().GetTextFirstLineOffset();
+                    nAdditionalIndent = nAdditionalIndent - 
rFirst.GetTextFirstLineOffset();
                 }
             }
         }
@@ -3412,7 +3429,8 @@ void SwTextNode::ClearLRSpaceItemDueToListLevelIndents(
         std::unique_ptr<SvxFirstLineIndentItem>& o_rFirstLineItem,
         std::unique_ptr<SvxTextLeftMarginItem>& o_rTextLeftMarginItem) const
 {
-    if ( AreListLevelIndentsApplicable() )
+    ::sw::ListLevelIndents const result(AreListLevelIndentsApplicable());
+    if (result != ::sw::ListLevelIndents::No)
     {
         const SwNumRule* pRule = GetNumRule();
         if ( pRule && GetActualListLevel() >= 0 )
@@ -3420,8 +3438,14 @@ void SwTextNode::ClearLRSpaceItemDueToListLevelIndents(
             const SwNumFormat& rFormat = 
pRule->Get(lcl_BoundListLevel(GetActualListLevel()));
             if ( rFormat.GetPositionAndSpaceMode() == 
SvxNumberFormat::LABEL_ALIGNMENT )
             {
-                o_rFirstLineItem = 
std::make_unique<SvxFirstLineIndentItem>(RES_MARGIN_FIRSTLINE);
-                o_rTextLeftMarginItem = 
std::make_unique<SvxTextLeftMarginItem>(RES_MARGIN_TEXTLEFT);
+                if (result & ::sw::ListLevelIndents::FirstLine)
+                {
+                    o_rFirstLineItem = 
std::make_unique<SvxFirstLineIndentItem>(RES_MARGIN_FIRSTLINE);
+                }
+                if (result & ::sw::ListLevelIndents::LeftMargin)
+                {
+                    o_rTextLeftMarginItem = 
std::make_unique<SvxTextLeftMarginItem>(RES_MARGIN_TEXTLEFT);
+                }
             }
         }
     }
@@ -3439,7 +3463,7 @@ tools::Long SwTextNode::GetLeftMarginForTabCalculation() 
const
         const SwNumFormat& rFormat = 
pRule->Get(lcl_BoundListLevel(GetActualListLevel()));
         if ( rFormat.GetPositionAndSpaceMode() == 
SvxNumberFormat::LABEL_ALIGNMENT )
         {
-            if ( AreListLevelIndentsApplicable() )
+            if (AreListLevelIndentsApplicable() & 
::sw::ListLevelIndents::LeftMargin)
             {
                 nLeftMarginForTabCalc = rFormat.GetIndentAt();
                 bLeftMarginForTabCalcSetToListLevelIndent = true;
@@ -4610,9 +4634,23 @@ OUString SwTextNode::GetListId() const
       style hierarchy from the paragraph to the paragraph style with the
       list style no indent attributes are found.
 
-    @return boolean
+    @return bitmask
 */
-bool SwTextNode::AreListLevelIndentsApplicable() const
+::sw::ListLevelIndents SwTextNode::AreListLevelIndentsApplicable() const
+{
+    ::sw::ListLevelIndents ret(::sw::ListLevelIndents::No);
+    if (AreListLevelIndentsApplicableImpl(RES_MARGIN_FIRSTLINE))
+    {
+        ret |= ::sw::ListLevelIndents::FirstLine;
+    }
+    if (AreListLevelIndentsApplicableImpl(RES_MARGIN_TEXTLEFT))
+    {
+        ret |= ::sw::ListLevelIndents::LeftMargin;
+    }
+    return ret;
+}
+
+bool SwTextNode::AreListLevelIndentsApplicableImpl(sal_uInt16 const nWhich) 
const
 {
     bool bAreListLevelIndentsApplicable( true );
 
@@ -4622,7 +4660,7 @@ bool SwTextNode::AreListLevelIndentsApplicable() const
         bAreListLevelIndentsApplicable = false;
     }
     else if ( HasSwAttrSet() &&
-              GetpSwAttrSet()->GetItemState( RES_LR_SPACE, false ) == 
SfxItemState::SET )
+             GetpSwAttrSet()->GetItemState(nWhich, false) == SfxItemState::SET)
     {
         // paragraph has hard-set indent attributes
         bAreListLevelIndentsApplicable = false;
@@ -4643,7 +4681,7 @@ bool SwTextNode::AreListLevelIndentsApplicable() const
         const SwTextFormatColl* pColl = GetTextColl();
         while ( pColl )
         {
-            if ( pColl->GetAttrSet().GetItemState( RES_LR_SPACE, false ) == 
SfxItemState::SET )
+            if (pColl->GetAttrSet().GetItemState(nWhich, false) == 
SfxItemState::SET)
             {
                 // indent attributes found in the paragraph style hierarchy.
                 bAreListLevelIndentsApplicable = false;
@@ -4693,7 +4731,7 @@ bool SwTextNode::GetListTabStopPosition( tools::Long& 
nListTabStopPosition ) con
             {
                 // tab stop position are treated to be relative to the "before 
text"
                 // indent value of the paragraph. Thus, adjust 
<nListTabStopPos>.
-                if ( AreListLevelIndentsApplicable() )
+                if (AreListLevelIndentsApplicable() & 
::sw::ListLevelIndents::LeftMargin)
                 {
                     nListTabStopPosition -= rFormat.GetIndentAt();
                 }
diff --git a/sw/source/core/txtnode/thints.cxx 
b/sw/source/core/txtnode/thints.cxx
index c31afa4abead..871304abeaa8 100644
--- a/sw/source/core/txtnode/thints.cxx
+++ b/sw/source/core/txtnode/thints.cxx
@@ -2112,7 +2112,8 @@ public:
 static void lcl_MergeListLevelIndentAsLRSpaceItem( const SwTextNode& rTextNode,
                                             SfxItemSet& rSet )
 {
-    if ( !rTextNode.AreListLevelIndentsApplicable() )
+    ::sw::ListLevelIndents const 
indents(rTextNode.AreListLevelIndentsApplicable());
+    if (indents == ::sw::ListLevelIndents::No)
         return;
 
     const SwNumRule* pRule = rTextNode.GetNumRule();
@@ -2121,10 +2122,16 @@ static void lcl_MergeListLevelIndentAsLRSpaceItem( 
const SwTextNode& rTextNode,
         const SwNumFormat& rFormat = 
pRule->Get(o3tl::narrowing<sal_uInt16>(rTextNode.GetActualListLevel()));
         if ( rFormat.GetPositionAndSpaceMode() == 
SvxNumberFormat::LABEL_ALIGNMENT )
         {
-            SvxTextLeftMarginItem const leftMargin(rFormat.GetIndentAt(), 
RES_MARGIN_TEXTLEFT);
-            SvxFirstLineIndentItem const 
firstLine(static_cast<short>(rFormat.GetFirstLineIndent()), 
RES_MARGIN_FIRSTLINE);
-            rSet.Put(firstLine);
-            rSet.Put(leftMargin);
+            if (indents & ::sw::ListLevelIndents::FirstLine)
+            {
+                SvxFirstLineIndentItem const 
firstLine(static_cast<short>(rFormat.GetFirstLineIndent()), 
RES_MARGIN_FIRSTLINE);
+                rSet.Put(firstLine);
+            }
+            if (indents & ::sw::ListLevelIndents::LeftMargin)
+            {
+                SvxTextLeftMarginItem const leftMargin(rFormat.GetIndentAt(), 
RES_MARGIN_TEXTLEFT);
+                rSet.Put(leftMargin);
+            }
         }
     }
 }
diff --git a/sw/source/filter/ww8/wrtw8nds.cxx 
b/sw/source/filter/ww8/wrtw8nds.cxx
index 9bcc4e1e2d30..61d73c32f242 100644
--- a/sw/source/filter/ww8/wrtw8nds.cxx
+++ b/sw/source/filter/ww8/wrtw8nds.cxx
@@ -2970,11 +2970,17 @@ void MSWordExportBase::OutputTextNode( SwTextNode& 
rNode )
                         // style is applied via paragraph style and the list 
level
                         // indent values are not applicable.
                         if ( pFormat->GetPositionAndSpaceMode() ==
-                                                
SvxNumberFormat::LABEL_ALIGNMENT &&
-                             !rNode.AreListLevelIndentsApplicable() )
+                                    SvxNumberFormat::LABEL_ALIGNMENT)
                         {
-                            oTmpSet->Put(firstLine);
-                            oTmpSet->Put(leftMargin);
+                            ::sw::ListLevelIndents const 
indents(rNode.AreListLevelIndentsApplicable());
+                            if (indents & ::sw::ListLevelIndents::FirstLine)
+                            {
+                                oTmpSet->Put(firstLine);
+                            }
+                            if (indents & ::sw::ListLevelIndents::LeftMargin)
+                            {
+                                oTmpSet->Put(leftMargin);
+                            }
                         }
                     }
                 }
diff --git a/sw/source/filter/ww8/ww8par6.cxx b/sw/source/filter/ww8/ww8par6.cxx
index 4186bfbc3fc8..bdf8607f4d5b 100644
--- a/sw/source/filter/ww8/ww8par6.cxx
+++ b/sw/source/filter/ww8/ww8par6.cxx
@@ -4240,7 +4240,8 @@ void SwWW8ImplReader::Read_LR( sal_uInt16 nId, const 
sal_uInt8* pData, short nLe
     // W8ImplReader::RegisterNumFormatOnTextNode).
     // Need to apply the list format to the paragraph here.
     SwTextNode* pTextNode = m_pPaM->GetPointNode().GetTextNode();
-    if( pTextNode && pTextNode->AreListLevelIndentsApplicable() )
+    if (pTextNode
+        && pTextNode->AreListLevelIndentsApplicable() != 
::sw::ListLevelIndents::No)
     {
         SwNumRule * pNumRule = pTextNode->GetNumRule();
         if( pNumRule )
diff --git a/sw/source/uibase/app/docstyle.cxx 
b/sw/source/uibase/app/docstyle.cxx
index 9c8f3c3eb4af..6e0ffc5d1cdd 100644
--- a/sw/source/uibase/app/docstyle.cxx
+++ b/sw/source/uibase/app/docstyle.cxx
@@ -1422,7 +1422,8 @@ void SwDocStyleSheet::MergeIndentAttrsOfListStyle( 
SfxItemSet& rSet )
     }
 
     OSL_ENSURE( m_pColl, "<SwDocStyleSheet::MergeIndentAttrsOfListStyle(..)> - 
missing paragraph style");
-    if ( !m_pColl->AreListLevelIndentsApplicable() )
+    ::sw::ListLevelIndents const 
indents(m_pColl->AreListLevelIndentsApplicable());
+    if (indents == ::sw::ListLevelIndents::No)
         return;
 
     OSL_ENSURE( m_pColl->GetItemState( RES_PARATR_NUMRULE ) == 
SfxItemState::SET,
@@ -1437,10 +1438,16 @@ void SwDocStyleSheet::MergeIndentAttrsOfListStyle( 
SfxItemSet& rSet )
         const SwNumFormat& rFormat = pRule->Get( 0 );
         if ( rFormat.GetPositionAndSpaceMode() == 
SvxNumberFormat::LABEL_ALIGNMENT )
         {
-            SvxFirstLineIndentItem const 
firstLine(static_cast<short>(rFormat.GetFirstLineIndent()), 
RES_MARGIN_FIRSTLINE);
-            SvxTextLeftMarginItem const leftMargin(rFormat.GetIndentAt(), 
RES_MARGIN_TEXTLEFT);
-            rSet.Put(firstLine);
-            rSet.Put(leftMargin);
+            if (indents & ::sw::ListLevelIndents::FirstLine)
+            {
+                SvxFirstLineIndentItem const 
firstLine(static_cast<short>(rFormat.GetFirstLineIndent()), 
RES_MARGIN_FIRSTLINE);
+                rSet.Put(firstLine);
+            }
+            if (indents & ::sw::ListLevelIndents::LeftMargin)
+            {
+                SvxTextLeftMarginItem const leftMargin(rFormat.GetIndentAt(), 
RES_MARGIN_TEXTLEFT);
+                rSet.Put(leftMargin);
+            }
         }
     }
 }

Reply via email to