sw/qa/extras/layout/data/merge_hidden_redline.docx |binary sw/qa/extras/layout/layout2.cxx | 246 ++++++++++++++++++++- 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, 389 insertions(+), 67 deletions(-)
New commits: commit bf4b4966f5a61fe0daef0c09a9c7a8f4503148b9 Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Wed Feb 19 16:25:35 2025 +0100 Commit: Thorsten Behrens <thorsten.behr...@allotropia.de> CommitDate: Sat Feb 22 14:15:39 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/+/181986 Tested-by: allotropia jenkins <jenk...@allotropia.de> Reviewed-by: Thorsten Behrens <thorsten.behr...@allotropia.de> 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 f5402cbc2c30..f968b10bf698 100644 --- a/sw/qa/extras/layout/layout2.cxx +++ b/sw/qa/extras/layout/layout2.cxx @@ -25,7 +25,10 @@ #include <unotxdoc.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> @@ -875,7 +878,11 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf152872) // 5 is empty and hidden assertXPath(pXmlDoc, "/root/page/body/txt[2]/infos/bounds"_ostr, "height"_ostr, "0"); - dispatchCommand(mxComponent, u".uno:ControlCodes"_ustr, {}); + SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); + SwViewOption aViewOptions(*pWrtShell->GetViewOptions()); + aViewOptions.SetShowHiddenChar(true); + aViewOptions.SetViewMetaChars(true); + pWrtShell->ApplyViewOptions(aViewOptions); discardDumpedLayout(); pXmlDoc = parseLayoutDump(); @@ -885,18 +892,15 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf152872) u"C "_ustr); assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout"_ostr, "portion"_ostr, u"D"_ustr); - // 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"_ostr, "height"_ostr, u"0"_ustr); + // 3 is an empty paragraph with RES_CHRATR_HIDDEN + assertXPath(pXmlDoc, "/root/page/body/txt[3]/infos/bounds"_ostr, "height"_ostr, u"398"_ustr); assertXPath(pXmlDoc, "/root/page/body/txt[4]/SwParaPortion/SwLineLayout"_ostr, "portion"_ostr, u"E"_ustr); - // 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"_ostr, "height"_ostr, "0"); + // 5 is an empty paragraph with RES_CHRATR_HIDDEN + assertXPath(pXmlDoc, "/root/page/body/txt[5]/infos/bounds"_ostr, "height"_ostr, "398"); - dispatchCommand(mxComponent, u".uno:ControlCodes"_ustr, {}); + aViewOptions.SetViewMetaChars(false); + pWrtShell->ApplyViewOptions(aViewOptions); discardDumpedLayout(); pXmlDoc = parseLayoutDump(); @@ -908,6 +912,228 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf152872) assertXPath(pXmlDoc, "/root/page/body/txt[2]/infos/bounds"_ostr, "height"_ostr, "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 ffa6679a5e05..48db4d099d9c 100644 --- a/sw/source/core/docnode/node.cxx +++ b/sw/source/core/docnode/node.cxx @@ -1449,8 +1449,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 f2b53a82f302..a5379002a800 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 377455f6e15f..27a9d8597784 100644 --- a/sw/source/core/inc/scriptinfo.hxx +++ b/sw/source/core/inc/scriptinfo.hxx @@ -105,6 +105,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 a70a824374e7..aec9d88bd9c1 100644 --- a/sw/source/core/inc/txtfrm.hxx +++ b/sw/source/core/inc/txtfrm.hxx @@ -32,6 +32,7 @@ namespace com::sun::star::linguistic2 { class XHyphenatedWord; } namespace sw::mark { class IMark; } +namespace sw { enum class ParagraphBreakMode; } class SwCharRange; class SwTextNode; class SwTextAttrEnd; @@ -50,6 +51,7 @@ class SwPortionHandler; class SwScriptInfo; enum class ExpandMode; class SwTextAttr; +class SwViewShell; class SwWrtShell; class SwNode; class SwFlyAtContentFrame; @@ -106,6 +108,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); @@ -125,6 +131,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); @@ -696,6 +703,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(); @@ -1005,12 +1013,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 786fbb5f2387..d590bda8dabb 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 47e2a4db8047..ffc40527c1ec 100644 --- a/sw/source/core/text/itrform2.cxx +++ b/sw/source/core/text/itrform2.cxx @@ -3300,6 +3300,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 778f7e19b5e3..dfcc776c34d5 100644 --- a/sw/source/core/text/porlay.cxx +++ b/sw/source/core/text/porlay.cxx @@ -1213,8 +1213,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()); @@ -1359,6 +1360,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 @@ -2705,7 +2714,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 afa87aba0963..a49f6d03dc50 100644 --- a/sw/source/core/text/redlnitr.cxx +++ b/sw/source/core/text/redlnitr.cxx @@ -264,6 +264,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) @@ -278,7 +319,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, @@ -420,22 +460,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(); } @@ -449,12 +490,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) { @@ -490,9 +531,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 654a59b30a63..578d24a4b09a 100644 --- a/sw/source/core/text/txtfrm.cxx +++ b/sw/source/core/text/txtfrm.cxx @@ -1018,6 +1018,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) { @@ -1129,13 +1130,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) { @@ -1143,12 +1137,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) { @@ -1159,7 +1165,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(); ) { @@ -1195,7 +1201,7 @@ TextFrameIndex UpdateMergedParaForDelete(MergedPara & rMerged, bErase = nDeleteHere == it->nEnd - it->nStart; if (bErase) { - ++nErased; +// ++nErased; assert(it->nStart == nIndex); it = rMerged.extents.erase(it); } @@ -1261,21 +1267,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); } @@ -1521,7 +1529,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); } @@ -2135,8 +2143,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) @@ -2314,7 +2323,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)) { @@ -2336,7 +2347,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) @@ -2398,7 +2411,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 ) ) { @@ -2424,7 +2439,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 { @@ -2451,7 +2468,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 { @@ -4148,6 +4167,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 00e84594dab5..ac31011e01f6 100644 --- a/sw/source/core/view/viewsh.cxx +++ b/sw/source/core/view/viewsh.cxx @@ -2378,18 +2378,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() ) @@ -2459,6 +2450,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