sw/qa/extras/layout/data/merge_hidden_redline.docx |binary sw/qa/extras/layout/layout2.cxx | 247 ++++++++++++++++++++- sw/source/core/docnode/node.cxx | 6 sw/source/core/inc/rootfrm.hxx | 1 sw/source/core/inc/scriptinfo.hxx | 2 sw/source/core/inc/txtfrm.hxx | 13 - sw/source/core/layout/newfrm.cxx | 2 sw/source/core/text/itrform2.cxx | 10 sw/source/core/text/porlay.cxx | 15 + sw/source/core/text/redlnitr.cxx | 62 ++++- sw/source/core/text/txtfrm.cxx | 73 ++++-- sw/source/core/view/viewsh.cxx | 26 +- 12 files changed, 390 insertions(+), 67 deletions(-)
New commits: commit 43adea12b199622bb703fe731afb3be182f2c17d Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Wed Feb 19 16:25:35 2025 +0100 Commit: Adolfo Jayme Barrientos <fit...@ubuntu.com> CommitDate: Fri Feb 21 13:14:16 2025 +0100 sw: use same paragraph properties as Word for hidden text This is a follow-up to commit 2bcfb7231b5ca74f02274cfb74ca8463f78905d6 "tdf#152872 sw: conditionally hide paragraph breaks". Word determines the paragraph properties differently depending on whether paragraphs are merged by hidden text (where the first paragraph containing non-hidden text wins) or delete redlines (where the last paragraph wins). This fixes the hidden text situation while leaving the delete redline situation as it is. The problem is that CheckParaRedlineMerge() only considers hidden text on the paragraph end marker (RES_PARATR_LIST_AUTOFMT) but not elsewhere in the paragraph, so there are extents for the hidden text. The actual hiding of that is done via ScriptInfo::m_HiddenChg, which cannot be removed and replaced by merging because it is required for Writer's notion of hidden paragraphs in SwTextFrame::IsHiddenNowImpl(). * FindParaPropsNodeIgnoreHidden() skips over nodes that contain only hidden text in case hidden text isn't shown * factor out ScriptInfo::InitScriptInfoHidden() because it is now needed to find the pParaPropsNode, but the rest of InitScriptInfo() requires the pParaPropsNode... * testTdf152872 requires changes as it was relying on ControlCharacters alone toggling the merging list of commits that tweaked setting pParaPropsNode: 58353884dc86bdb3c1464f8bbf8c3e131584b78a (related: tdf#130685) sw: adapt definition of sw_redlinehide index 0 b86ff2c6a88aa41379e74f11e8ec8497ff85ffd0 tdf#118699 sw_redlinehide: need some more changes to use the last node fa5eb82b398e29ae033f7b7c8c8195dfc10cf5b0 tdf#118699 change tracking: don't number empty lines beec1594587d0bf1ea2268f9a435c948b5580278 tdf#125319 sw_redlinehide: handle empty paragraphs more like Word c20308f1b919ca5ce61233068946e5fddb7eadb3 sw_redlinehide_4b: surprising discoveries Change-Id: If0e49a4d105dbf7d71e753967f36f2ec56f21f1d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/181918 Reviewed-by: Michael Stahl <michael.st...@allotropia.de> Tested-by: Jenkins (cherry picked from commit 8712673a445edeb28a5f3029bbcaa096f38d72e6) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/181957 Reviewed-by: Adolfo Jayme Barrientos <fit...@ubuntu.com> diff --git a/sw/qa/extras/layout/data/merge_hidden_redline.docx b/sw/qa/extras/layout/data/merge_hidden_redline.docx new file mode 100644 index 000000000000..7a7013321402 Binary files /dev/null and b/sw/qa/extras/layout/data/merge_hidden_redline.docx differ diff --git a/sw/qa/extras/layout/layout2.cxx b/sw/qa/extras/layout/layout2.cxx index 5dc1e6fff241..9364add9ecaf 100644 --- a/sw/qa/extras/layout/layout2.cxx +++ b/sw/qa/extras/layout/layout2.cxx @@ -20,6 +20,10 @@ #include <o3tl/string_view.hxx> #include <rootfrm.hxx> +#include <pagefrm.hxx> +#include <bodyfrm.hxx> +#include <txtfrm.hxx> +#include <ndtxt.hxx> #include <wrtsh.hxx> #include <IDocumentLayoutAccess.hxx> #include <IDocumentRedlineAccess.hxx> @@ -707,24 +711,25 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf152872) // 5 is empty and hidden assertXPath(pXmlDoc, "/root/page/body/txt[2]/infos/bounds", "height", u"0"); - dispatchCommand(mxComponent, u".uno:ControlCodes"_ustr, {}); + SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); + SwViewOption aViewOptions(*pWrtShell->GetViewOptions()); + aViewOptions.SetShowHiddenChar(true); + aViewOptions.SetViewMetaChars(true); + pWrtShell->ApplyViewOptions(aViewOptions); pXmlDoc = parseLayoutDump(); assertXPath(pXmlDoc, "/root/page[1]/body/txt", 5); assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout", "portion", u"C "); assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout", "portion", u"D"); - // 3 is an empty paragraph with RES_CHRATR_HIDDEN which results in 0-height - // frame; ideally it should only be hidden when control codes are hidden - // and be a full-height frame now, but that needs more work... - assertXPath(pXmlDoc, "/root/page/body/txt[3]/infos/bounds", "height", u"0"); + // 3 is an empty paragraph with RES_CHRATR_HIDDEN + assertXPath(pXmlDoc, "/root/page/body/txt[3]/infos/bounds", "height", u"398"); assertXPath(pXmlDoc, "/root/page/body/txt[4]/SwParaPortion/SwLineLayout", "portion", u"E"); - // 5 is an empty paragraph with RES_CHRATR_HIDDEN which results in 0-height - // frame; ideally it should only be hidden when control codes are hidden - // and be a full-height frame now, but that needs more work... - assertXPath(pXmlDoc, "/root/page/body/txt[5]/infos/bounds", "height", u"0"); + // 5 is an empty paragraph with RES_CHRATR_HIDDEN + assertXPath(pXmlDoc, "/root/page/body/txt[5]/infos/bounds", "height", u"398"); - dispatchCommand(mxComponent, u".uno:ControlCodes"_ustr, {}); + aViewOptions.SetViewMetaChars(false); + pWrtShell->ApplyViewOptions(aViewOptions); pXmlDoc = parseLayoutDump(); @@ -734,6 +739,228 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf152872) assertXPath(pXmlDoc, "/root/page/body/txt[2]/infos/bounds", "height", u"0"); } +CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testHiddenParaProps) +{ + createSwDoc("merge_hidden_redline.docx"); + + SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); + SwViewOption aViewOptions(*pWrtShell->GetViewOptions()); + aViewOptions.SetShowHiddenChar(true); + aViewOptions.SetViewMetaChars(true); + pWrtShell->ApplyViewOptions(aViewOptions); + + // note: do not use layout dump here, because it doesn't work: + // SwTextFrame::Format doesn't actually create the SwMarginPortion for + // non-left-aligned frames; instead, it sets SetFormatAdj() flag and later + // *SwTextPainter* checks via GetAdjusted() if the flag is set and calls + // CalcAdjLine() which inserts the SwMarginPortion. + + SwRootFrame* pRoot = pWrtShell->GetLayout(); + CPPUNIT_ASSERT(pRoot->GetLower()->IsPageFrame()); + SwPageFrame* pPage = static_cast<SwPageFrame*>(pRoot->GetLower()); + CPPUNIT_ASSERT(pPage->GetLower()->IsBodyFrame()); + SwBodyFrame* pBody = static_cast<SwBodyFrame*>(pPage->GetLower()); + CPPUNIT_ASSERT(pBody->GetLower()->IsTextFrame()); + SwTextFrame* pTextFrame = dynamic_cast<SwTextFrame*>(pBody->GetLower()); + + CPPUNIT_ASSERT_EQUAL(u"1 hidden, delete-merge"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + // TODO: redlines don't merge like in Word yet + CPPUNIT_ASSERT_EQUAL(u"Abcdef"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"ghi"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"2 visible, delete-merge"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"abcghi"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"def"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"3 delete-merge"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"def"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"ghi"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"4 delete-merge, delete-merge"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"abc"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"def"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u""_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"5 visible, hidden-merge, visible"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"abc"_ustr, pTextFrame->GetText()); + CPPUNIT_ASSERT_EQUAL( + SvxAdjust::Center, + pTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().Get(RES_PARATR_ADJUST).GetAdjust()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"def"_ustr, pTextFrame->GetText()); + CPPUNIT_ASSERT_EQUAL( + SvxAdjust::Left, + pTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().Get(RES_PARATR_ADJUST).GetAdjust()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"6 hidden-merge, visible"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"abc"_ustr, pTextFrame->GetText()); + CPPUNIT_ASSERT_EQUAL( + SvxAdjust::Center, + pTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().Get(RES_PARATR_ADJUST).GetAdjust()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"def"_ustr, pTextFrame->GetText()); + CPPUNIT_ASSERT_EQUAL( + SvxAdjust::Left, + pTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().Get(RES_PARATR_ADJUST).GetAdjust()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"7 visible, hidden-merge"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"abcdef"_ustr, pTextFrame->GetText()); + CPPUNIT_ASSERT_EQUAL( + SvxAdjust::Center, + pTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().Get(RES_PARATR_ADJUST).GetAdjust()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"ghi"_ustr, pTextFrame->GetText()); + CPPUNIT_ASSERT_EQUAL( + SvxAdjust::Left, + pTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().Get(RES_PARATR_ADJUST).GetAdjust()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"8 visible, delete-merge, visible, hidden-merge, visible"_ustr, + pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"abc"_ustr, pTextFrame->GetText()); + CPPUNIT_ASSERT_EQUAL( + SvxAdjust::Right, + pTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().Get(RES_PARATR_ADJUST).GetAdjust()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"def"_ustr, pTextFrame->GetText()); + CPPUNIT_ASSERT_EQUAL( + SvxAdjust::Center, + pTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().Get(RES_PARATR_ADJUST).GetAdjust()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"ghi"_ustr, pTextFrame->GetText()); + CPPUNIT_ASSERT_EQUAL( + SvxAdjust::Left, + pTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().Get(RES_PARATR_ADJUST).GetAdjust()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"9 hidden-merge"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"abc"_ustr, pTextFrame->GetText()); + CPPUNIT_ASSERT_EQUAL( + SvxAdjust::Center, + pTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().Get(RES_PARATR_ADJUST).GetAdjust()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"def"_ustr, pTextFrame->GetText()); + CPPUNIT_ASSERT_EQUAL( + SvxAdjust::Left, + pTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().Get(RES_PARATR_ADJUST).GetAdjust()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"10 visible, hidden-merge, visible, delete-merge, visible"_ustr, + pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"abc"_ustr, pTextFrame->GetText()); + CPPUNIT_ASSERT_EQUAL( + SvxAdjust::Right, + pTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().Get(RES_PARATR_ADJUST).GetAdjust()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"def"_ustr, pTextFrame->GetText()); + CPPUNIT_ASSERT_EQUAL( + SvxAdjust::Center, + pTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().Get(RES_PARATR_ADJUST).GetAdjust()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"ghi"_ustr, pTextFrame->GetText()); + CPPUNIT_ASSERT_EQUAL( + SvxAdjust::Left, + pTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().Get(RES_PARATR_ADJUST).GetAdjust()); + + aViewOptions.SetShowHiddenChar(false); + pWrtShell->ApplyViewOptions(aViewOptions); + + // the problem was that the wrong SwTextNode was used for properties + pTextFrame = dynamic_cast<SwTextFrame*>(pBody->GetLower()); + CPPUNIT_ASSERT_EQUAL(u"1 hidden, delete-merge"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + // TODO: redlines don't merge like in Word yet + CPPUNIT_ASSERT_EQUAL(u"Abcdef"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"ghi"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"2 visible, delete-merge"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"abcghi"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"def"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"3 delete-merge"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"def"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"ghi"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"4 delete-merge, delete-merge"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"abc"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"def"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u""_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"5 visible, hidden-merge, visible"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"abcdef"_ustr, pTextFrame->GetText()); + CPPUNIT_ASSERT_EQUAL( + SvxAdjust::Center, + pTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().Get(RES_PARATR_ADJUST).GetAdjust()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"6 hidden-merge, visible"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"abcdef"_ustr, pTextFrame->GetText()); + CPPUNIT_ASSERT_EQUAL( + SvxAdjust::Left, + pTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().Get(RES_PARATR_ADJUST).GetAdjust()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"7 visible, hidden-merge"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"abcdefghi"_ustr, pTextFrame->GetText()); + CPPUNIT_ASSERT_EQUAL( + SvxAdjust::Center, + pTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().Get(RES_PARATR_ADJUST).GetAdjust()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"8 visible, delete-merge, visible, hidden-merge, visible"_ustr, + pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"abc"_ustr, pTextFrame->GetText()); + CPPUNIT_ASSERT_EQUAL( + SvxAdjust::Right, + pTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().Get(RES_PARATR_ADJUST).GetAdjust()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"defghi"_ustr, pTextFrame->GetText()); + CPPUNIT_ASSERT_EQUAL( + SvxAdjust::Center, + pTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().Get(RES_PARATR_ADJUST).GetAdjust()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"9 hidden-merge"_ustr, pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"abcdef"_ustr, pTextFrame->GetText()); + CPPUNIT_ASSERT_EQUAL( + SvxAdjust::Left, + pTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().Get(RES_PARATR_ADJUST).GetAdjust()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"10 visible, hidden-merge, visible, delete-merge, visible"_ustr, + pTextFrame->GetText()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"abcdef"_ustr, pTextFrame->GetText()); + CPPUNIT_ASSERT_EQUAL( + SvxAdjust::Right, + pTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().Get(RES_PARATR_ADJUST).GetAdjust()); + pTextFrame = dynamic_cast<SwTextFrame*>(pTextFrame->GetNext()); + CPPUNIT_ASSERT_EQUAL(u"ghi"_ustr, pTextFrame->GetText()); + CPPUNIT_ASSERT_EQUAL( + SvxAdjust::Left, + pTextFrame->GetTextNodeForParaProps()->GetSwAttrSet().Get(RES_PARATR_ADJUST).GetAdjust()); +} + CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf151954) { createSwDoc("tdf151954.docx"); diff --git a/sw/source/core/docnode/node.cxx b/sw/source/core/docnode/node.cxx index d5b86fb90120..aebade8eb36f 100644 --- a/sw/source/core/docnode/node.cxx +++ b/sw/source/core/docnode/node.cxx @@ -1457,8 +1457,10 @@ void SwContentNode::DelFrames(SwRootFrame const*const pLayout) // node as SwFrame::InvalidatePage() will access them. // Note: cannot send via SwClientNotify from dtor // because that would access deleted wrong-lists - sw::UpdateMergedParaForDelete(*pMerged, true, - *static_cast<SwTextNode*>(this), 0, Len()); + sw::UpdateMergedParaForDelete(*pMerged, + pFrame->getRootFrame()->GetParagraphBreakMode(), + static_cast<SwTextFrame *>(pFrame)->GetScriptInfo(), + true, *static_cast<SwTextNode*>(this), 0, Len()); if (this == pMerged->pParaPropsNode) { // otherwise pointer should have been updated to a different node diff --git a/sw/source/core/inc/rootfrm.hxx b/sw/source/core/inc/rootfrm.hxx index d41484ea7576..cecb8e50b1b9 100644 --- a/sw/source/core/inc/rootfrm.hxx +++ b/sw/source/core/inc/rootfrm.hxx @@ -48,6 +48,7 @@ namespace sw { }; enum class FieldmarkMode { ShowCommand = 1, ShowResult = 2, ShowBoth = 3 }; + // this has evolved into something that could be called HiddenTextMode? enum class ParagraphBreakMode { Shown, Hidden }; }; diff --git a/sw/source/core/inc/scriptinfo.hxx b/sw/source/core/inc/scriptinfo.hxx index c60e8d0959a8..5d4814bf2f63 100644 --- a/sw/source/core/inc/scriptinfo.hxx +++ b/sw/source/core/inc/scriptinfo.hxx @@ -104,6 +104,8 @@ public: SwScriptInfo(); ~SwScriptInfo(); + // partial init: only m_HiddenChg/m_Bookmarks + void InitScriptInfoHidden(const SwTextNode& rNode, sw::MergedPara const* pMerged); // determines script changes void InitScriptInfo(const SwTextNode& rNode, sw::MergedPara const* pMerged, bool bRTL); void InitScriptInfo(const SwTextNode& rNode, sw::MergedPara const* pMerged); diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx index 9d48e488316c..c1db19420eeb 100644 --- a/sw/source/core/inc/txtfrm.hxx +++ b/sw/source/core/inc/txtfrm.hxx @@ -33,6 +33,7 @@ namespace com::sun::star::linguistic2 { class XHyphenatedWord; } namespace sw::mark { class MarkBase; } +namespace sw { enum class ParagraphBreakMode; } class SwCharRange; class SwTextNode; class SwTextAttrEnd; @@ -51,6 +52,7 @@ class SwPortionHandler; class SwScriptInfo; enum class ExpandMode; class SwTextAttr; +class SwViewShell; class SwWrtShell; class SwNode; class SwFlyAtContentFrame; @@ -105,6 +107,10 @@ class InsertText; std::pair<SwTextNode*, sal_Int32> MapViewToModel(MergedPara const&, TextFrameIndex nIndex); TextFrameIndex MapModelToView(MergedPara const&, SwTextNode const* pNode, sal_Int32 nIndex); +bool IsShowHiddenChars(SwViewShell const*const pViewShell); +void FindParaPropsNodeIgnoreHidden(MergedPara & rMerged, + sw::ParagraphBreakMode const eMode, SwScriptInfo * pScriptInfo); + // warning: Existing must be used only once; a second use would delete the frame created by the first one... enum class FrameMode { New, Existing }; std::unique_ptr<sw::MergedPara> CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode, FrameMode eMode); @@ -124,6 +130,7 @@ void GotoPrevLayoutTextFrame(SwNodeIndex & rIndex, SwRootFrame const* pLayout); void GotoNextLayoutTextFrame(SwNodeIndex & rIndex, SwRootFrame const* pLayout); TextFrameIndex UpdateMergedParaForDelete(MergedPara & rMerged, + sw::ParagraphBreakMode eMode, SwScriptInfo * pScriptInfo, bool isRealDelete, SwTextNode const& rNode, sal_Int32 nIndex, sal_Int32 nLen); @@ -690,6 +697,7 @@ public: /// Returns the script info stored at the paraportion const SwScriptInfo* GetScriptInfo() const; + SwScriptInfo* GetScriptInfo(); /// Swaps width and height of the text frame void SwapWidthAndHeight(); @@ -999,12 +1007,11 @@ struct MergedPara SwTextNode const* pLastNode; MergedPara(SwTextFrame & rFrame, std::vector<Extent>&& rExtents, OUString aText, - SwTextNode *const pProps, SwTextNode *const pFirst, + SwTextNode *const pFirst, SwTextNode const*const pLast) : listener(rFrame), extents(std::move(rExtents)), mergedText(std::move(aText)) - , pParaPropsNode(pProps), pFirstNode(pFirst), pLastNode(pLast) + , pParaPropsNode(nullptr), pFirstNode(pFirst), pLastNode(pLast) { - assert(pParaPropsNode); assert(pFirstNode); assert(pLastNode); } diff --git a/sw/source/core/layout/newfrm.cxx b/sw/source/core/layout/newfrm.cxx index d2863a91ab93..737c453fb411 100644 --- a/sw/source/core/layout/newfrm.cxx +++ b/sw/source/core/layout/newfrm.cxx @@ -419,7 +419,7 @@ SwRootFrame::SwRootFrame( SwFrameFormat *pFormat, SwViewShell * pSh ) : m_FieldmarkMode(pSh->GetViewOptions()->IsFieldName() ? sw::FieldmarkMode::ShowCommand : sw::FieldmarkMode::ShowResult), - m_ParagraphBreakMode(pSh->GetViewOptions()->IsParagraph() + m_ParagraphBreakMode(sw::IsShowHiddenChars(pSh) ? sw::ParagraphBreakMode::Shown : sw::ParagraphBreakMode::Hidden), mnBrowseWidth(MIN_BROWSE_WIDTH), diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx index 62927c06e13c..290a7ebd558d 100644 --- a/sw/source/core/text/itrform2.cxx +++ b/sw/source/core/text/itrform2.cxx @@ -3340,6 +3340,16 @@ void SwTextFormatter::MergeCharacterBorder( SwLinePortion& rPortion, SwLinePorti Seek(rInf.GetIdx()); } +namespace sw { + bool IsShowHiddenChars(SwViewShell const*const pViewShell) + { + SwViewOption const*const pOpt{pViewShell ? pViewShell->GetViewOptions() : nullptr}; + const bool bShowInDocView{pViewShell && pViewShell->GetWin() && pOpt->IsShowHiddenChar()}; + const bool bShowForPrinting{pViewShell && pOpt->IsShowHiddenChar(true) && pOpt->IsPrinting()}; + return (bShowInDocView || bShowForPrinting); + } +} + namespace { // calculates and sets optimal repaint offset for the current line tools::Long lcl_CalcOptRepaint( SwTextFormatter &rThis, diff --git a/sw/source/core/text/porlay.cxx b/sw/source/core/text/porlay.cxx index 40b45ae691f5..a17f2dd5242b 100644 --- a/sw/source/core/text/porlay.cxx +++ b/sw/source/core/text/porlay.cxx @@ -1134,8 +1134,9 @@ void SwScriptInfo::InitScriptInfo(const SwTextNode& rNode, InitScriptInfo( rNode, pMerged, m_nDefaultDir == UBIDI_RTL ); } -void SwScriptInfo::InitScriptInfo(const SwTextNode& rNode, - sw::MergedPara const*const pMerged, bool bRTL) +// note: must not use pMerged->pParaPropsNode to avoid circular dependency +void SwScriptInfo::InitScriptInfoHidden(const SwTextNode& rNode, + sw::MergedPara const*const pMerged) { assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is()); @@ -1281,6 +1282,14 @@ void SwScriptInfo::InitScriptInfo(const SwTextNode& rNode, m_HiddenChg.push_back( TextFrameIndex(nEnd) ); } } +} + +void SwScriptInfo::InitScriptInfo(const SwTextNode& rNode, + sw::MergedPara const*const pMerged, bool bRTL) +{ + InitScriptInfoHidden(rNode, pMerged); + + const OUString& rText(pMerged ? pMerged->mergedText : rNode.GetText()); // SCRIPT AND SCRIPT RELATED INFORMATION @@ -2372,7 +2381,7 @@ SwScriptInfo* SwScriptInfo::GetScriptInfo( const SwTextNode& rTNd, for( SwTextFrame* pLast = aIter.First(); pLast; pLast = aIter.Next() ) { - pScriptInfo = const_cast<SwScriptInfo*>(pLast->GetScriptInfo()); + pScriptInfo = pLast->GetScriptInfo(); if ( pScriptInfo ) { if (bAllowInvalid || diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx index 9285bf457803..ab9dfb59cea0 100644 --- a/sw/source/core/text/redlnitr.cxx +++ b/sw/source/core/text/redlnitr.cxx @@ -265,6 +265,47 @@ public: namespace sw { +void FindParaPropsNodeIgnoreHidden(sw::MergedPara & rMerged, + sw::ParagraphBreakMode const eMode, SwScriptInfo * pScriptInfo) +{ + if (eMode == sw::ParagraphBreakMode::Hidden) + { + ::std::optional<SwScriptInfo> oScriptInfo; + if (pScriptInfo == nullptr) + { + oScriptInfo.emplace(); + pScriptInfo = &*oScriptInfo; + } + // always init: when called from SwTextFrame::SwClientNotify() it is stale! + pScriptInfo->InitScriptInfoHidden(*rMerged.pFirstNode, &rMerged); + TextFrameIndex nHiddenStart{COMPLETE_STRING}; + TextFrameIndex nHiddenEnd{0}; + pScriptInfo->GetBoundsOfHiddenRange(TextFrameIndex{0}, nHiddenStart, nHiddenEnd); + if (TextFrameIndex{0} == nHiddenStart) + { + if (nHiddenEnd == TextFrameIndex{rMerged.mergedText.getLength()}) + { + rMerged.pParaPropsNode = const_cast<SwTextNode*>(rMerged.pLastNode); + } + else + { // this requires MapViewToModel to never return a position at + // the end of a node (when all its text is hidden) + rMerged.pParaPropsNode = sw::MapViewToModel(rMerged, nHiddenEnd).first; + } + return; + } + } + if (!rMerged.extents.empty()) + { // para props from first node that isn't empty (OOo/LO compat) + rMerged.pParaPropsNode = rMerged.extents.begin()->pNode; + } + else + { // if every node is empty, the last one wins (Word compat) + // (OOo/LO historically used first one) + rMerged.pParaPropsNode = const_cast<SwTextNode*>(rMerged.pLastNode); + } +} + std::unique_ptr<sw::MergedPara> CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode, FrameMode const eMode) @@ -279,7 +320,6 @@ CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode, std::vector<SwSectionNode *> sections; std::vector<sw::Extent> extents; OUStringBuffer mergedText; - SwTextNode * pParaPropsNode(nullptr); SwTextNode * pNode(&rTextNode); sal_Int32 nLastEnd(0); for (auto iter = HideIterator(rTextNode, @@ -421,22 +461,23 @@ CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode, if (extents.empty()) // there was no text anywhere { assert(mergedText.isEmpty()); - pParaPropsNode = pNode; // if every node is empty, the last one wins } else { assert(!mergedText.isEmpty()); - pParaPropsNode = extents.begin()->pNode; // para props from first node that isn't empty } -// pParaPropsNode = &rTextNode; // well, actually... + auto pRet{std::make_unique<sw::MergedPara>(rFrame, std::move(extents), + mergedText.makeStringAndClear(), &rTextNode, nodes.back())}; + FindParaPropsNodeIgnoreHidden(*pRet, rFrame.getRootFrame()->GetParagraphBreakMode(), nullptr); + assert(pRet->pParaPropsNode); // keep lists up to date with visible nodes - if (pParaPropsNode->IsInList() && !pParaPropsNode->GetNum(rFrame.getRootFrame())) + if (pRet->pParaPropsNode->IsInList() && !pRet->pParaPropsNode->GetNum(rFrame.getRootFrame())) { - pParaPropsNode->AddToListRLHidden(); // try to add it... + pRet->pParaPropsNode->AddToListRLHidden(); // try to add it... } for (auto const pTextNode : nodes) { - if (pTextNode != pParaPropsNode) + if (pTextNode != pRet->pParaPropsNode) { pTextNode->RemoveFromListRLHidden(); } @@ -450,12 +491,12 @@ CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode, // for non-first nodes that are already merged with this frame, // need to remove here too, otherwise footnotes can be removed only // by lucky accident, e.g. TruncLines(). - auto itExtent(extents.begin()); + auto itExtent(pRet->extents.begin()); for (auto const pTextNode : nodes) { sal_Int32 nLast(0); std::vector<std::pair<sal_Int32, sal_Int32>> hidden; - for ( ; itExtent != extents.end(); ++itExtent) + for ( ; itExtent != pRet->extents.end(); ++itExtent) { if (itExtent->pNode != pTextNode) { @@ -491,9 +532,6 @@ CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode, pSectionNode->GetSection().GetFormat()->DelFrames(/*rFrame.getRootFrame()*/); } } - auto pRet(std::make_unique<sw::MergedPara>(rFrame, std::move(extents), - mergedText.makeStringAndClear(), pParaPropsNode, &rTextNode, - nodes.back())); for (SwTextNode * pTmp : nodes) { pRet->listener.StartListening(pTmp); diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx index 6f964506c949..30469ddd0746 100644 --- a/sw/source/core/text/txtfrm.cxx +++ b/sw/source/core/text/txtfrm.cxx @@ -1017,6 +1017,7 @@ namespace sw { // 1. if real insert => correct nStart/nEnd for full nLen // 2. if rl un-delete => do not correct nStart/nEnd but just include un-deleted static TextFrameIndex UpdateMergedParaForInsert(MergedPara & rMerged, + sw::ParagraphBreakMode const eMode, SwScriptInfo *const pScriptInfo, bool const isRealInsert, SwTextNode const& rNode, sal_Int32 const nIndex, sal_Int32 const nLen) { @@ -1128,13 +1129,6 @@ static TextFrameIndex UpdateMergedParaForInsert(MergedPara & rMerged, rMerged.extents.emplace(itInsert, const_cast<SwTextNode*>(&rNode), nIndex, nIndex + nLen); text.insert(nTFIndex, rNode.GetText().subView(nIndex, nLen)); nInserted = nLen; - if (rMerged.extents.size() == 1 // also if it was empty! - || rMerged.pParaPropsNode->GetIndex() < rNode.GetIndex()) - { // text inserted after current para-props node - rMerged.pParaPropsNode->RemoveFromListRLHidden(); - rMerged.pParaPropsNode = &const_cast<SwTextNode&>(rNode); - rMerged.pParaPropsNode->AddToListRLHidden(); - } // called from SwRangeRedline::InvalidateRange() if (rNode.GetRedlineMergeFlag() == SwNode::Merge::Hidden) { @@ -1142,12 +1136,24 @@ static TextFrameIndex UpdateMergedParaForInsert(MergedPara & rMerged, } } rMerged.mergedText = text.makeStringAndClear(); + if ((!bInserted && rMerged.extents.size() == 1) // also if it was empty! + || rNode.GetIndex() <= rMerged.pParaPropsNode->GetIndex()) + { // text inserted before current para-props node + SwTextNode *const pOldParaPropsNode{rMerged.pParaPropsNode}; + FindParaPropsNodeIgnoreHidden(rMerged, eMode, pScriptInfo); + if (rMerged.pParaPropsNode != pOldParaPropsNode) + { + pOldParaPropsNode->RemoveFromListRLHidden(); + rMerged.pParaPropsNode->AddToListRLHidden(); + } + } return TextFrameIndex(nInserted); } // 1. if real delete => correct nStart/nEnd for full nLen // 2. if rl delete => do not correct nStart/nEnd but just exclude deleted TextFrameIndex UpdateMergedParaForDelete(MergedPara & rMerged, + sw::ParagraphBreakMode const eMode, SwScriptInfo *const pScriptInfo, bool const isRealDelete, SwTextNode const& rNode, sal_Int32 nIndex, sal_Int32 const nLen) { @@ -1158,7 +1164,7 @@ TextFrameIndex UpdateMergedParaForDelete(MergedPara & rMerged, sal_Int32 nToDelete(nLen); sal_Int32 nDeleted(0); size_t nFoundNode(0); - size_t nErased(0); +// size_t nErased(0); auto it = rMerged.extents.begin(); for (; it != rMerged.extents.end(); ) { @@ -1194,7 +1200,7 @@ TextFrameIndex UpdateMergedParaForDelete(MergedPara & rMerged, bErase = nDeleteHere == it->nEnd - it->nStart; if (bErase) { - ++nErased; +// ++nErased; assert(it->nStart == nIndex); it = rMerged.extents.erase(it); } @@ -1260,21 +1266,23 @@ TextFrameIndex UpdateMergedParaForDelete(MergedPara & rMerged, // can't do: might be last one in node was erased assert(nLen == 0 || rMerged.empty() || (it-1)->nEnd <= nIndex); // note: if first node gets deleted then that must call DelFrames as // pFirstNode is never updated - if (nErased && nErased == nFoundNode) + rMerged.mergedText = text.makeStringAndClear(); +// could be all-hidden now so always check! if (nErased && nErased == nFoundNode) { // all visible text from node was erased #if 1 if (rMerged.pParaPropsNode == &rNode) { - rMerged.pParaPropsNode->RemoveFromListRLHidden(); - rMerged.pParaPropsNode = rMerged.extents.empty() - ? const_cast<SwTextNode*>(rMerged.pLastNode) - : rMerged.extents.front().pNode; - rMerged.pParaPropsNode->AddToListRLHidden(); + SwTextNode *const pOldParaPropsNode{rMerged.pParaPropsNode}; + FindParaPropsNodeIgnoreHidden(rMerged, eMode, pScriptInfo); + if (rMerged.pParaPropsNode != pOldParaPropsNode) + { + pOldParaPropsNode->RemoveFromListRLHidden(); + rMerged.pParaPropsNode->AddToListRLHidden(); + } } #endif // NOPE must listen on all non-hidden nodes; particularly on pLastNode rMerged.listener.EndListening(&const_cast<SwTextNode&>(rNode)); } - rMerged.mergedText = text.makeStringAndClear(); return TextFrameIndex(nDeleted); } @@ -1520,7 +1528,7 @@ bool SwTextFrame::IsHiddenNowImpl() const else // ParaPortion is created in Format, but this is called earlier { SwScriptInfo aInfo; - aInfo.InitScriptInfo(*m_pMergedPara->pFirstNode, m_pMergedPara.get(), IsRightToLeft()); + aInfo.InitScriptInfoHidden(*m_pMergedPara->pFirstNode, m_pMergedPara.get()); aInfo.GetBoundsOfHiddenRange(TextFrameIndex(0), nHiddenStart, nHiddenEnd); } @@ -2134,8 +2142,9 @@ void UpdateMergedParaForMove(sw::MergedPara & rMerged, for (auto const& it : deleted) { sal_Int32 const nStart(it.first - nSourceStart + nDestStart); - TextFrameIndex const nDeleted = UpdateMergedParaForDelete(rMerged, false, - rDestNode, nStart, it.second - it.first); + TextFrameIndex const nDeleted = UpdateMergedParaForDelete(rMerged, + rTextFrame.getRootFrame()->GetParagraphBreakMode(), rTextFrame.GetScriptInfo(), + false, rDestNode, nStart, it.second - it.first); //FIXME asserts valid for join - but if called from split, the new node isn't there yet and it will be added later... assert(nDeleted); // assert(nDeleted == it.second - it.first); if(nDeleted) @@ -2318,7 +2327,9 @@ void SwTextFrame::SwClientNotify(SwModify const& rModify, SfxHint const& rHint) sal_Int32 const nNLen = pRedlineDelText->nLen; nPos = MapModelToView(&rNode, nNPos); // update merged before doing anything else - nLen = UpdateMergedParaForDelete(*m_pMergedPara, false, rNode, nNPos, nNLen); + nLen = UpdateMergedParaForDelete(*m_pMergedPara, + getRootFrame()->GetParagraphBreakMode(), GetScriptInfo(), + false, rNode, nNPos, nNLen); const sal_Int32 m = -nNLen; if (nLen && IsIdxInside(nPos, nLen)) { @@ -2340,7 +2351,9 @@ void SwTextFrame::SwClientNotify(SwModify const& rModify, SfxHint const& rHint) sal_Int32 const nNPos = pRedlineUnDelText->nStart; sal_Int32 const nNLen = pRedlineUnDelText->nLen; nPos = MapModelToView(&rNode, nNPos); - nLen = UpdateMergedParaForInsert(*m_pMergedPara, false, rNode, nNPos, nNLen); + nLen = UpdateMergedParaForInsert(*m_pMergedPara, + getRootFrame()->GetParagraphBreakMode(), GetScriptInfo(), + false, rNode, nNPos, nNLen); if (IsIdxInside(nPos, nLen)) { if (!nLen) @@ -2402,7 +2415,9 @@ void SwTextFrame::SwClientNotify(SwModify const& rModify, SfxHint const& rHint) nLen = TextFrameIndex(pInsertText->nLen); if (m_pMergedPara) { - UpdateMergedParaForInsert(*m_pMergedPara, true, rNode, pInsertText->nPos, pInsertText->nLen); + UpdateMergedParaForInsert(*m_pMergedPara, + getRootFrame()->GetParagraphBreakMode(), GetScriptInfo(), + true, rNode, pInsertText->nPos, pInsertText->nLen); } if( IsIdxInside( nPos, nLen ) ) { @@ -2428,7 +2443,9 @@ void SwTextFrame::SwClientNotify(SwModify const& rModify, SfxHint const& rHint) nPos = MapModelToView(&rNode, pDeleteText->nStart); if (m_pMergedPara) { // update merged before doing anything else - nLen = UpdateMergedParaForDelete(*m_pMergedPara, true, rNode, pDeleteText->nStart, pDeleteText->nLen); + nLen = UpdateMergedParaForDelete(*m_pMergedPara, + getRootFrame()->GetParagraphBreakMode(), GetScriptInfo(), + true, rNode, pDeleteText->nStart, pDeleteText->nLen); } else { @@ -2455,7 +2472,9 @@ void SwTextFrame::SwClientNotify(SwModify const& rModify, SfxHint const& rHint) nPos = MapModelToView(&rNode, pDeleteChar->m_nPos); if (m_pMergedPara) { - nLen = UpdateMergedParaForDelete(*m_pMergedPara, true, rNode, pDeleteChar->m_nPos, 1); + nLen = UpdateMergedParaForDelete(*m_pMergedPara, + getRootFrame()->GetParagraphBreakMode(), GetScriptInfo(), + true, rNode, pDeleteChar->m_nPos, 1); } else { @@ -4179,6 +4198,12 @@ const SwScriptInfo* SwTextFrame::GetScriptInfo() const return pPara ? &pPara->GetScriptInfo() : nullptr; } +SwScriptInfo* SwTextFrame::GetScriptInfo() +{ + SwParaPortion* pPara = GetPara(); + return pPara ? &pPara->GetScriptInfo() : nullptr; +} + /** * Helper function for SwTextFrame::CalcBasePosForFly() */ diff --git a/sw/source/core/view/viewsh.cxx b/sw/source/core/view/viewsh.cxx index 4af997226abc..d3b805af7dc1 100644 --- a/sw/source/core/view/viewsh.cxx +++ b/sw/source/core/view/viewsh.cxx @@ -2428,18 +2428,9 @@ void SwViewShell::ImplApplyViewOptions( const SwViewOption &rOpt ) // ( - SwEndPortion must _no_ longer be generated. ) // - Of course, the screen is something completely different than the printer ... bool const isToggleFieldNames(mpOpt->IsFieldName() != rOpt.IsFieldName()); - - if (mpOpt->IsFieldName() != rOpt.IsFieldName() - || mpOpt->IsParagraph() != rOpt.IsParagraph()) - { - GetLayout()->SetFieldmarkMode( rOpt.IsFieldName() - ? sw::FieldmarkMode::ShowCommand - : sw::FieldmarkMode::ShowResult, - rOpt.IsParagraph() - ? sw::ParagraphBreakMode::Shown - : sw::ParagraphBreakMode::Hidden); - bReformat = true; - } + bool const isToggleLayoutHide{isToggleFieldNames + || mpOpt->IsParagraph() != rOpt.IsParagraph() + || mpOpt->IsShowHiddenChar() != rOpt.IsShowHiddenChar()}; // The map mode is changed, minima/maxima will be attended by UI if( mpOpt->GetZoom() != rOpt.GetZoom() && !IsPreview() ) @@ -2509,6 +2500,17 @@ void SwViewShell::ImplApplyViewOptions( const SwViewOption &rOpt ) mxDoc->GetDocumentSettingManager().set(DocumentSettingId::HTML_MODE, 0 != ::GetHtmlMode(mxDoc->GetDocShell())); + if (isToggleLayoutHide) + { + GetLayout()->SetFieldmarkMode( rOpt.IsFieldName() + ? sw::FieldmarkMode::ShowCommand + : sw::FieldmarkMode::ShowResult, + sw::IsShowHiddenChars(this) + ? sw::ParagraphBreakMode::Shown + : sw::ParagraphBreakMode::Hidden); + bReformat = true; + } + if( bBrowseModeChanged || bHideWhitespaceModeChanged ) { // #i44963# Good occasion to check if page sizes in