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() );
