sw/qa/extras/uiwriter/uiwriter11.cxx |   30 ++++++++++++++++++++++++++++++
 sw/source/core/doc/docfmt.cxx        |   19 ++++++++++++++++++-
 2 files changed, 48 insertions(+), 1 deletion(-)

New commits:
commit 0ec76b148622dd20b0353d0eed72896dadb8a8ed
Author:     Jonathan Clark <[email protected]>
AuthorDate: Tue Feb 17 22:11:01 2026 -0700
Commit:     Jonathan Clark <[email protected]>
CommitDate: Thu Feb 19 03:01:18 2026 +0100

    tdf#151857 sw: Preserve paragraph direction after para style change
    
    Users intuitively understand writing direction to be a part of document
    content, rather than document formatting. Although we use formatting
    machinery for paragraph direction, we should treat that as an
    implementation detail and handle direction separately in a manner that
    makes sense to users. (See tdf#40496 for example, discussing why Clear
    DF doesn't clear paragraph direction.)
    
    This change updates Writer so it no longer clears paragraph direction
    direct formatting when changing paragraph style, consistent with the
    above reasoning.
    
    Change-Id: Icdfe79e3732457df84ba1da0eca100597307562d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/199651
    Reviewed-by: Jonathan Clark <[email protected]>
    Tested-by: Jenkins

diff --git a/sw/qa/extras/uiwriter/uiwriter11.cxx 
b/sw/qa/extras/uiwriter/uiwriter11.cxx
index 7c27d74729c1..2b2b9ca9d1a1 100644
--- a/sw/qa/extras/uiwriter/uiwriter11.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter11.cxx
@@ -14,6 +14,7 @@
 #include <vcl/pdf/PDFPageObjectType.hxx>
 #include <vcl/scheduler.hxx>
 
+#include <comphelper/propertysequence.hxx>
 #include <comphelper/propertyvalue.hxx>
 #include <comphelper/sequence.hxx>
 #include <comphelper/scopeguard.hxx>
@@ -646,6 +647,35 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest11, testTdf169651)
     pWrtShell->UnfloatFlyFrame();
 }
 
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest11, 
testTdf151857ParaStylePreservesWritingMode)
+{
+    createSwDoc();
+    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
+    CPPUNIT_ASSERT(pWrtShell);
+
+    // Initially, paragraphs have environment writing mode and automatic 
writing mode enabled
+    CPPUNIT_ASSERT_EQUAL(short(4),
+                         getProperty<short>(getRun(getParagraph(1), 1), 
u"WritingMode"_ustr));
+    CPPUNIT_ASSERT(getProperty<bool>(getRun(getParagraph(1), 1), 
u"WritingModeAutomatic"_ustr));
+
+    dispatchCommand(mxComponent, u".uno:ParaRightToLeft"_ustr, {});
+
+    CPPUNIT_ASSERT_EQUAL(short(1),
+                         getProperty<short>(getRun(getParagraph(1), 1), 
u"WritingMode"_ustr));
+    CPPUNIT_ASSERT(!getProperty<bool>(getRun(getParagraph(1), 1), 
u"WritingModeAutomatic"_ustr));
+
+    uno::Sequence<beans::PropertyValue> aPropertyValues = 
comphelper::InitPropertySequence({
+        { "Style", uno::Any(u"Heading 1"_ustr) },
+        { "FamilyName", uno::Any(u"ParagraphStyles"_ustr) },
+    });
+    dispatchCommand(mxComponent, u".uno:StyleApply"_ustr, aPropertyValues);
+
+    // Verify that changing the paragraph style preserves the writing mode DF
+    CPPUNIT_ASSERT_EQUAL(short(1),
+                         getProperty<short>(getRun(getParagraph(1), 1), 
u"WritingMode"_ustr));
+    CPPUNIT_ASSERT(!getProperty<bool>(getRun(getParagraph(1), 1), 
u"WritingModeAutomatic"_ustr));
+}
+
 } // end of anonymous namespace
 CPPUNIT_PLUGIN_IMPLEMENT();
 
diff --git a/sw/source/core/doc/docfmt.cxx b/sw/source/core/doc/docfmt.cxx
index 3a7a2ce6998d..d289f7ec2cd9 100644
--- a/sw/source/core/doc/docfmt.cxx
+++ b/sw/source/core/doc/docfmt.cxx
@@ -116,10 +116,14 @@ static bool lcl_RstAttr( SwNode* pNd, void* pArgs )
 
         // remove unused attribute RES_LR_SPACE
         // add list attributes, except RES_PARATR_LIST_AUTOFMT
+        // tdf#151857: Frame direction is conceptually an aspect of language, 
rather than text
+        // formatting. Preserve paragraph direction across resets.
         SfxItemSetFixed<
                 RES_PARATR_NUMRULE, RES_PARATR_NUMRULE,
+                RES_PARATR_AUTOFRAMEDIR, RES_PARATR_AUTOFRAMEDIR,
                 RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_AUTOFMT - 1,
                 RES_PAGEDESC, RES_BREAK,
+                RES_FRAMEDIR, RES_FRAMEDIR,
                 RES_FRMATR_STYLE_NAME, RES_FRMATR_CONDITIONAL_STYLE_NAME> 
aSavedAttrsSet(rDoc.GetAttrPool());
         const SfxItemSet* pAttrSetOfNode = pNode->GetpSwAttrSet();
 
@@ -171,6 +175,18 @@ static bool lcl_RstAttr( SwNode* pNd, void* pArgs )
             aSavedAttrsSet.Put(*pItem);
             aClearWhichIds.push_back(RES_FRMATR_CONDITIONAL_STYLE_NAME);
         }
+        if (auto pItem = pAttrSetOfNode->GetItemIfSet(RES_PARATR_AUTOFRAMEDIR);
+            pItem && !pItem->GetValue())
+        {
+            aSavedAttrsSet.Put(*pItem);
+            aClearWhichIds.push_back(RES_PARATR_AUTOFRAMEDIR);
+        }
+        if (auto pItem = pAttrSetOfNode->GetItemIfSet(RES_FRAMEDIR, false);
+            pItem && pItem->GetValue() != SvxFrameDirection::Environment)
+        {
+            aSavedAttrsSet.Put(*pItem);
+            aClearWhichIds.push_back(RES_FRAMEDIR);
+        }
 
         // do not clear items directly from item set and only clear to be kept
         // attributes, if no deletion item set is found.
@@ -199,7 +215,8 @@ static bool lcl_RstAttr( SwNode* pNd, void* pArgs )
                            pItem->Which() != RES_BREAK &&
                            pItem->Which() != RES_FRMATR_STYLE_NAME &&
                            pItem->Which() != RES_FRMATR_CONDITIONAL_STYLE_NAME 
&&
-                           pItem->Which() != RES_PARATR_NUMRULE ) ||
+                           pItem->Which() != RES_PARATR_NUMRULE &&
+                           pItem->Which() != RES_FRAMEDIR ) ||
                          ( aSavedAttrsSet.GetItemState( pItem->Which(), false 
) != SfxItemState::SET ) )
                     {
                         pNode->ResetAttr( pItem->Which() );

Reply via email to