sw/inc/list.hxx | 23 +++++++- sw/inc/ndtxt.hxx | 15 ++++- sw/qa/extras/layout/data/tdf115523.fodt | 42 +++++++++++++++ sw/qa/extras/layout/layout2.cxx | 27 ++++++++-- sw/source/core/doc/list.cxx | 13 +++- sw/source/core/text/txtfld.cxx | 43 +++++++++++++--- sw/source/core/txtnode/ndtxt.cxx | 86 ++++++++++++++++++++++++-------- 7 files changed, 208 insertions(+), 41 deletions(-)
New commits: commit 9d429619fa04fb30dc8ab48dcc23d523f50b7aae Author: László Németh <nem...@numbertext.org> AuthorDate: Thu Jun 23 12:11:22 2022 +0200 Commit: László Németh <nem...@numbertext.org> CommitDate: Fri Jun 24 21:14:31 2022 +0200 tdf#115523 sw_redlinenum: show correct, also original numbering in Show Changes mode, according to the name "Show Changes" and according to the interoperability requirements. Instead of the fake numbering which counted the deleted list items in Show Changes mode, e.g.: "3. This was the third originally, but now it's the second list item." now show the correct number followed by the original number within braces: "2.[3.] This was the third originally, but now it's the second list item." Note: the tabulators after the longer numbering are replaced with spaces to avoid messy indentation in Show Changes mode. New enum values for the alternative lists: SwListRedlineType::SHOW - the original (fake) numbering in Show Changes mode SwListRedlineType::HIDDEN - the original numbering of Hide Changes mode, and new numbering in Show Changes mode SwListRedlineType::ORIGTEXT - the new numbering of Show Changes mode to show the original numbering of the deleted or inserted list items Follow-up to commit c180c9447256588fe5e7991e06642883574760ae "sw_redlinehide_3: add second SwNodeNum to SwTextNode". Change-Id: Ieaca550561c5d5a7ac5d9defb9c7fa283d6aa674 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136313 Tested-by: Jenkins Reviewed-by: László Németh <nem...@numbertext.org> (cherry picked from commit 093588f4b4914e95a6f1604777b6d74c684b654e) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136333 Tested-by: László Németh <nem...@numbertext.org> diff --git a/sw/inc/list.hxx b/sw/inc/list.hxx index 14acb303ae07..d62d3a46ea86 100644 --- a/sw/inc/list.hxx +++ b/sw/inc/list.hxx @@ -29,6 +29,13 @@ class SwDoc; class SwNumRule; class SwNodes; +enum class SwListRedlineType +{ + SHOW, + HIDDEN, + ORIGTEXT, +}; + class SwList { public: @@ -44,7 +51,7 @@ class SwList void SetDefaultListStyleName(OUString const&); void InsertListItem(SwNodeNum& rNodeNum, - bool isHiddenRedlines, + SwListRedlineType eRedlines, const int nLevel, const SwDoc& rDoc); static void RemoveListItem(SwNodeNum& rNodeNum, const SwDoc& rDoc); @@ -84,10 +91,20 @@ class SwList /// the previous node on the same level. /// The nodes of pRootRLHidden are a subset of the nodes of pRoot. std::unique_ptr<SwNodeNum> pRootRLHidden; + /// Tree that is missing those nodes that are merged or hidden + /// by insert redlines; this is only used if there is a layout + /// that has IsHideRedlines() disabled, and the numbering of the + /// original text is also shown. + /// A third tree is needed because not only are the numbers in + /// the nodes different, the structure of the tree may be different + /// The nodes of pRootOrigText are a subset of the nodes of pRoot. + std::unique_ptr<SwNodeNum> pRootOrigText; /// top-level SwNodes section std::unique_ptr<SwPaM> pSection; - tListTreeForRange(std::unique_ptr<SwNodeNum> p1, std::unique_ptr<SwNodeNum> p2, std::unique_ptr<SwPaM> p3) - : pRoot(std::move(p1)), pRootRLHidden(std::move(p2)), pSection(std::move(p3)) {} + tListTreeForRange(std::unique_ptr<SwNodeNum> p1, std::unique_ptr<SwNodeNum> p2, + std::unique_ptr<SwNodeNum> p3, std::unique_ptr<SwPaM> p4) + : pRoot(std::move(p1)), pRootRLHidden(std::move(p2)), + pRootOrigText(std::move(p3)), pSection(std::move(p4)) {} }; std::vector<tListTreeForRange> maListTrees; diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx index a2ca71ea197c..8007beff59cd 100644 --- a/sw/inc/ndtxt.hxx +++ b/sw/inc/ndtxt.hxx @@ -25,6 +25,7 @@ #include "IDocumentContentOperations.hxx" #include "SwNumberTreeTypes.hxx" #include "hintids.hxx" +#include "list.hxx" #include "modeltoviewhelper.hxx" #include "ndhints.hxx" #include "node.hxx" @@ -94,6 +95,7 @@ class SW_DLLPUBLIC SwTextNode final mutable std::unique_ptr<SwNodeNum> mpNodeNum; ///< Numbering for this paragraph. mutable std::unique_ptr<SwNodeNum> mpNodeNumRLHidden; ///< Numbering for this paragraph (hidden redlines) + mutable std::unique_ptr<SwNodeNum> mpNodeNumOrig; ///< Numbering for this paragraph (before changes) OUString m_Text; @@ -439,10 +441,12 @@ public: */ SwNumRule *GetNumRule(bool bInParent = true) const; - const SwNodeNum* GetNum(SwRootFrame const* pLayout = nullptr) const; + const SwNodeNum* GetNum(SwRootFrame const* pLayout = nullptr, + SwListRedlineType eRedline = SwListRedlineType::SHOW) const; void DoNum(std::function<void (SwNodeNum &)> const&); - SwNumberTree::tNumberVector GetNumberVector(SwRootFrame const* pLayout = nullptr) const; + SwNumberTree::tNumberVector GetNumberVector(SwRootFrame const* pLayout = nullptr, + SwListRedlineType eRedline = SwListRedlineType::SHOW) const; /** Returns if this text node is an outline. @@ -477,7 +481,8 @@ public: */ OUString GetNumString( const bool _bInclPrefixAndSuffixStrings = true, const unsigned int _nRestrictToThisLevel = MAXLEVEL, - SwRootFrame const* pLayout = nullptr) const; + SwRootFrame const* pLayout = nullptr, + SwListRedlineType eRedline = SwListRedlineType::SHOW) const; /** Returns the additional indents of this text node and its numbering. @@ -572,7 +577,7 @@ public: @return the actual list level of this text node, if it is a list item, -1 otherwise */ - int GetActualListLevel() const; + int GetActualListLevel(SwListRedlineType eRedline = SwListRedlineType::SHOW) const; /** Returns outline level of this text node. @@ -787,8 +792,10 @@ public: void AddToList(); void AddToListRLHidden(); + void AddToListOrig(); void RemoveFromList(); void RemoveFromListRLHidden(); + void RemoveFromListOrig(); bool IsInList() const; bool IsFirstOfNumRule(SwRootFrame const& rLayout) const; diff --git a/sw/qa/extras/layout/data/tdf115523.fodt b/sw/qa/extras/layout/data/tdf115523.fodt new file mode 100644 index 000000000000..a9989995642f --- /dev/null +++ b/sw/qa/extras/layout/data/tdf115523.fodt @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oas is:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names: experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:automatic-styles> + <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Standard" style:list-style-name="L1"> + <style:text-properties officeooo:rsid="001fa9e2" officeooo:paragraph-rsid="001fa9e2"/> + </style:style> + <text:list-style style:name="L1"> + <text:list-level-style-number text:level="1" text:style-name="Numbering_20_Symbols" style:num-suffix="." style:num-format="1"> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab" text:list-tab-stop-position="1.27cm" fo:text-indent="-0.635cm" fo:margin-left="1.27cm"/> + </style:list-level-properties> + </text:list-level-style-number> + </text:list-style> + </office:automatic-styles> + <office:body> + <office:text> + <office:forms form:automatic-focus="false" form:apply-design-mode="false"/> + <text:tracked-changes text:track-changes="false"> + <text:changed-region xml:id="ct93898744546976" text:id="ct93898744546976"> + <text:deletion> + <office:change-info> + <dc:creator>Unknown Author</dc:creator> + <dc:date>2019-10-22T08:48:10</dc:date> + </office:change-info> + </text:deletion> + </text:changed-region> + </text:tracked-changes> + <text:list text:style-name="L1"> + <text:list-item> + <text:p text:style-name="P2">It<text:change-start text:change-id="ct93898744546976"/></text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P2"><text:change-end text:change-id="ct93898744546976"/>em</text:p> + </text:list-item> + <text:list-item> + <text:p text:style-name="P2">Item</text:p> + </text:list-item> + </text:list> + </office:text> + </office:body> +</office:document> diff --git a/sw/qa/extras/layout/layout2.cxx b/sw/qa/extras/layout/layout2.cxx index a47642acfb8d..57e06f05553e 100644 --- a/sw/qa/extras/layout/layout2.cxx +++ b/sw/qa/extras/layout/layout2.cxx @@ -304,13 +304,34 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testRedlineNumberInNumbering) // (and not COL_GREEN color of the tracked text movement, see testRedlineMoving) elements assertXPath( pXmlDoc, - "/metafile/push/push/push/textcolor[not(@color='#000000') and not(@color='#008000')]", 6); + "/metafile/push/push/push/textcolor[not(@color='#000000') and not(@color='#008000')]", 5); // tdf#145068 numbering shows changes in the associated list item, not the next one // This was 1 (black numbering of the first list item previously) assertXPath(pXmlDoc, "/metafile/push/push/push/font[4][@color='#000000']", 0); } +CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testRedlineNumbering) +{ + SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf115523.fodt"); + SwDocShell* pShell = pDoc->GetDocShell(); + + // Dump the rendering of the first page as an XML file. + std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile(); + MetafileXmlDump dumper; + + xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile); + CPPUNIT_ASSERT(pXmlDoc); + + // Show the correct and the original line numbering instead of counting + // the deleted list items in Show Changes mode, as part of the list + assertXPathContent(pXmlDoc, "/metafile/push/push/push/textarray[1]/text", "1."); + // This was "2." (deleted text node, now its text content is part of the first list item) + assertXPathContent(pXmlDoc, "/metafile/push/push/push/textarray[3]/text", "[2.] "); + // This was "3." (now it's the second list item) + assertXPathContent(pXmlDoc, "/metafile/push/push/push/textarray[5]/text", "2.[3.] "); +} + CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testRedlineNumberInFootnote) { SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf85610.fodt"); @@ -488,8 +509,8 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf145225_RedlineMovingWithBadInsertio // insert a tracked paragraph break in middle of the second list item, i.e. split it dispatchCommand(mxComponent, ".uno:GoToStartOfDoc", {}); dispatchCommand(mxComponent, ".uno:TrackChanges", {}); - pWrtShell->Down(false, 1); - pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false); + // positionate the cursor in the middle of the second list item + pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 4, /*bBasicCall=*/false); pWrtShell->SplitNode(false); CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(1), pEditShell->GetRedlineCount()); diff --git a/sw/source/core/doc/list.cxx b/sw/source/core/doc/list.cxx index 7965856519cc..9543e083d711 100644 --- a/sw/source/core/doc/list.cxx +++ b/sw/source/core/doc/list.cxx @@ -37,6 +37,7 @@ SwList::SwList( const OUString& sListId, SwPaM aPam( *pNode, *pNode->EndOfSectionNode() ); maListTrees.emplace_back( + std::make_unique<SwNodeNum>( &rDefaultListStyle ), std::make_unique<SwNodeNum>( &rDefaultListStyle ), std::make_unique<SwNodeNum>( &rDefaultListStyle ), std::make_unique<SwPaM>( *(aPam.Start()), *(aPam.End()) )); @@ -58,6 +59,7 @@ SwList::~SwList() COVERITY_NOEXCEPT_FALSE { SwNodeNum::HandleNumberTreeRootNodeDelete(*(rNumberTree.pRoot)); SwNodeNum::HandleNumberTreeRootNodeDelete(*(rNumberTree.pRootRLHidden)); + SwNodeNum::HandleNumberTreeRootNodeDelete(*(rNumberTree.pRootOrigText)); } } @@ -73,7 +75,7 @@ bool SwList::HasNodes() const return false; } -void SwList::InsertListItem(SwNodeNum& rNodeNum, bool const isHiddenRedlines, +void SwList::InsertListItem(SwNodeNum& rNodeNum, SwListRedlineType const eRedline, const int nLevel, const SwDoc& rDoc) { const SwPosition aPosOfNodeNum( rNodeNum.GetPosition() ); @@ -88,9 +90,11 @@ void SwList::InsertListItem(SwNodeNum& rNodeNum, bool const isHiddenRedlines, if ( pRangeNodes == pNodesOfNodeNum && *pStart <= aPosOfNodeNum && aPosOfNodeNum <= *pEnd) { - auto const& pRoot(isHiddenRedlines + auto const& pRoot(SwListRedlineType::HIDDEN == eRedline ? rNumberTree.pRootRLHidden - : rNumberTree.pRoot); + : SwListRedlineType::SHOW == eRedline + ? rNumberTree.pRoot + : rNumberTree.pRootOrigText); pRoot->AddChild(&rNodeNum, nLevel, rDoc); break; } @@ -108,6 +112,7 @@ void SwList::InvalidateListTree() { rNumberTree.pRoot->InvalidateTree(); rNumberTree.pRootRLHidden->InvalidateTree(); + rNumberTree.pRootOrigText->InvalidateTree(); } } @@ -117,6 +122,7 @@ void SwList::ValidateListTree(const SwDoc& rDoc) { rNumberTree.pRoot->NotifyInvalidChildren(rDoc); rNumberTree.pRootRLHidden->NotifyInvalidChildren(rDoc); + rNumberTree.pRootOrigText->NotifyInvalidChildren(rDoc); } } @@ -162,6 +168,7 @@ void SwList::NotifyItemsOnListLevel( const int nLevel ) { rNumberTree.pRoot->NotifyNodesOnListLevel( nLevel ); rNumberTree.pRootRLHidden->NotifyNodesOnListLevel( nLevel ); + rNumberTree.pRootOrigText->NotifyNodesOnListLevel( nLevel ); } } diff --git a/sw/source/core/text/txtfld.cxx b/sw/source/core/text/txtfld.cxx index 06cb7388378e..f935e8d8ab93 100644 --- a/sw/source/core/text/txtfld.cxx +++ b/sw/source/core/text/txtfld.cxx @@ -563,15 +563,15 @@ static const SwRangeRedline* lcl_GetRedlineAtNodeInsertionOrDeletion( const SwTe return nullptr; } -static void lcl_setRedlineAttr( SwTextFormatInfo &rInf, const SwTextNode& rTextNode, const std::unique_ptr<SwFont>& pNumFnt ) +static bool lcl_setRedlineAttr( SwTextFormatInfo &rInf, const SwTextNode& rTextNode, const std::unique_ptr<SwFont>& pNumFnt ) { if ( rInf.GetVsh()->GetLayout()->IsHideRedlines() ) - return; + return false; bool bIsMoved; const SwRangeRedline* pRedlineNum = lcl_GetRedlineAtNodeInsertionOrDeletion( rTextNode, bIsMoved ); if (!pRedlineNum) - return; + return false; // moved text: dark green with double underline or strikethrough if ( bIsMoved ) @@ -581,7 +581,7 @@ static void lcl_setRedlineAttr( SwTextFormatInfo &rInf, const SwTextNode& rTextN pNumFnt->SetStrikeout(STRIKEOUT_DOUBLE); else pNumFnt->SetUnderline(LINESTYLE_DOUBLE); - return; + return true; } SwAttrPool& rPool = rInf.GetVsh()->GetDoc()->GetAttrPool(); @@ -602,6 +602,8 @@ static void lcl_setRedlineAttr( SwTextFormatInfo &rInf, const SwTextNode& rTextN pNumFnt->SetUnderline(pItem->GetLineStyle()); if (const SvxCrossedOutItem* pItem = aSet.GetItemIfSet(RES_CHRATR_CROSSEDOUT)) pNumFnt->SetStrikeout( pItem->GetStrikeout() ); + + return true; } SwNumberPortion *SwTextFormatter::NewNumberPortion( SwTextFormatInfo &rInf ) const @@ -730,11 +732,35 @@ SwNumberPortion *SwTextFormatter::NewNumberPortion( SwTextFormatInfo &rInf ) con } else { - OUString aText( pTextNd->GetNumString(true, MAXLEVEL, m_pFrame->getRootFrame()) ); - if ( !aText.isEmpty() ) + // Show Changes mode shows the actual numbering (SwListRedlineType::HIDDEN) and + // the original one (SwListRedlineType::ORIGTEXT) instead of the fake numbering + // (SwListRedlineType::SHOW, which counts removed and inserted numbered paragraphs + // in a single list) + bool bHasHiddenNum = false; + OUString aText( pTextNd->GetNumString(true, MAXLEVEL, m_pFrame->getRootFrame(), SwListRedlineType::HIDDEN) ); + const SwDoc& rDoc = pTextNd->GetDoc(); + const SwRedlineTable& rTable = rDoc.getIDocumentRedlineAccess().GetRedlineTable(); + if ( rTable.size() && !rInf.GetVsh()->GetLayout()->IsHideRedlines() ) { - aText += pTextNd->GetLabelFollowedBy(); + OUString aHiddenText( pTextNd->GetNumString(true, MAXLEVEL, m_pFrame->getRootFrame(), SwListRedlineType::ORIGTEXT) ); + + if ( !aText.isEmpty() || !aHiddenText.isEmpty() ) + { + if (aText != aHiddenText && !aHiddenText.isEmpty()) + { + bHasHiddenNum = true; + // show also original number after the actual one enclosed in [ and ], + // and replace tabulator with space to avoid messy indentation + // resulted by the longer numbering, e.g. "1.[2.]" instead of "1.". + aText = aText + "[" + aHiddenText + "]" + + pTextNd->GetLabelFollowedBy().replaceAll("\t", " "); + } + else if (!aText.isEmpty()) + aText += pTextNd->GetLabelFollowedBy(); + } } + else if (!aText.isEmpty()) + aText += pTextNd->GetLabelFollowedBy(); // Not just an optimization ... // A number portion without text will be assigned a width of 0. @@ -763,7 +789,8 @@ SwNumberPortion *SwTextFormatter::NewNumberPortion( SwTextFormatInfo &rInf ) con checkApplyParagraphMarkFormatToNumbering(pNumFnt.get(), rInf, pIDSA, pFormat); - lcl_setRedlineAttr( rInf, *pTextNd, pNumFnt ); + if ( !lcl_setRedlineAttr( rInf, *pTextNd, pNumFnt ) && bHasHiddenNum ) + pNumFnt->SetColor(NON_PRINTING_CHARACTER_COLOR); // we do not allow a vertical font pNumFnt->SetVertical( pNumFnt->GetOrientation(), m_pFrame->IsVertical() ); diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx index 691c42e3c900..72cd894e045e 100644 --- a/sw/source/core/txtnode/ndtxt.cxx +++ b/sw/source/core/txtnode/ndtxt.cxx @@ -72,7 +72,6 @@ #include <SwNodeNum.hxx> #include <svl/grabbagitem.hxx> #include <svl/intitem.hxx> -#include <list.hxx> #include <sortedobjs.hxx> #include <calbck.hxx> #include <attrhint.hxx> @@ -3160,24 +3159,24 @@ bool SwTextNode::HasBullet() const //i53420 added max outline parameter OUString SwTextNode::GetNumString( const bool _bInclPrefixAndSuffixStrings, const unsigned int _nRestrictToThisLevel, - SwRootFrame const*const pLayout) const + SwRootFrame const*const pLayout, SwListRedlineType eRedline) const { if (GetDoc().IsClipBoard() && m_oNumStringCache) { // #i111677# do not expand number strings in clipboard documents return *m_oNumStringCache; } - const SwNumRule* pRule = GetNum(pLayout) ? GetNum(pLayout)->GetNumRule() : nullptr; + const SwNumRule* pRule = GetNum(pLayout, eRedline) ? GetNum(pLayout, eRedline)->GetNumRule() : nullptr; if ( pRule && IsCountedInList() ) { SvxNumberType const& rNumberType( - pRule->Get( lcl_BoundListLevel(GetActualListLevel()) ) ); + pRule->Get( lcl_BoundListLevel(GetActualListLevel(eRedline)) ) ); if (rNumberType.IsTextFormat() || (style::NumberingType::NUMBER_NONE == rNumberType.GetNumberingType())) { - return pRule->MakeNumString( GetNum(pLayout)->GetNumberVector(), + return pRule->MakeNumString( GetNum(pLayout, eRedline)->GetNumberVector(), _bInclPrefixAndSuffixStrings, _nRestrictToThisLevel, nullptr, @@ -3992,11 +3991,13 @@ SwFormatColl* SwTextNode::ChgFormatColl( SwFormatColl *pNewColl ) return pOldColl; } -const SwNodeNum* SwTextNode::GetNum(SwRootFrame const*const pLayout) const +const SwNodeNum* SwTextNode::GetNum(SwRootFrame const*const pLayout, SwListRedlineType eRedline) const { // invariant: it's only in list in Hide mode if it's in list in normal mode assert(mpNodeNum || !mpNodeNumRLHidden); - return pLayout && pLayout->IsHideRedlines() ? mpNodeNumRLHidden.get() : mpNodeNum.get(); + return (pLayout && pLayout->IsHideRedlines()) || SwListRedlineType::HIDDEN == eRedline + ? mpNodeNumRLHidden.get() + : ( SwListRedlineType::ORIGTEXT == eRedline ? mpNodeNumOrig.get() : mpNodeNum.get() ); } void SwTextNode::DoNum(std::function<void (SwNodeNum &)> const& rFunc) @@ -4014,9 +4015,9 @@ void SwTextNode::DoNum(std::function<void (SwNodeNum &)> const& rFunc) } SwNumberTree::tNumberVector -SwTextNode::GetNumberVector(SwRootFrame const*const pLayout) const +SwTextNode::GetNumberVector(SwRootFrame const*const pLayout, SwListRedlineType eRedline) const { - if (SwNodeNum const*const pNum = GetNum(pLayout)) + if (SwNodeNum const*const pNum = GetNum(pLayout, eRedline)) { return pNum->GetNumberVector(); } @@ -4137,11 +4138,13 @@ int SwTextNode::GetAttrListLevel() const return nAttrListLevel; } -int SwTextNode::GetActualListLevel() const +int SwTextNode::GetActualListLevel(SwListRedlineType eRedline) const { - assert(!GetNum() || !mpNodeNumRLHidden || // must be in sync - GetNum()->GetLevelInListTree() == mpNodeNumRLHidden->GetLevelInListTree()); - return GetNum() ? GetNum()->GetLevelInListTree() : -1; + assert(SwListRedlineType::SHOW != eRedline || + !GetNum(nullptr, SwListRedlineType::SHOW) || !mpNodeNumRLHidden || // must be in sync + GetNum(nullptr, SwListRedlineType::SHOW)->GetLevelInListTree() == + mpNodeNumRLHidden->GetLevelInListTree()); + return GetNum(nullptr, eRedline) ? GetNum(nullptr, eRedline)->GetLevelInListTree() : -1; } void SwTextNode::SetListRestart( bool bRestart ) @@ -4318,10 +4321,30 @@ void SwTextNode::AddToList() assert(!mpNodeNum); mpNodeNum.reset(new SwNodeNum(this, false)); - pList->InsertListItem(*mpNodeNum, false, GetAttrListLevel(), GetDoc()); + pList->InsertListItem(*mpNodeNum, SwListRedlineType::SHOW, GetAttrListLevel(), GetDoc()); + + // set redline lists + bool bRecordChanges = GetDoc().GetDocShell() && GetDoc().GetDocShell()->IsChangeRecording(); + if (!bRecordChanges || GetDoc().IsInXMLImport() || GetDoc().IsInWriterfilterImport() ) + { + const SwRedlineTable& rRedTable = GetDoc().getIDocumentRedlineAccess().GetRedlineTable(); + SwRedlineTable::size_type nRedlPos = GetDoc().getIDocumentRedlineAccess().GetRedlinePos(*this, RedlineType::Insert); + // paragraph start is not in a tracked insertion + if ( SwRedlineTable::npos == nRedlPos || GetIndex() <= rRedTable[nRedlPos]->Start()->nNode.GetNode().GetIndex() ) + { + AddToListOrig(); + + SwRedlineTable::size_type nRedlPosDel = GetDoc().getIDocumentRedlineAccess().GetRedlinePos(*this, RedlineType::Delete); + if ( SwRedlineTable::npos == nRedlPosDel ) + AddToListRLHidden(); + } + } + else if ( bRecordChanges ) + AddToListRLHidden(); + // iterate all frames & if there's one with hidden layout... SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> iter(*this); - for (SwTextFrame* pFrame = iter.First(); pFrame; pFrame = iter.Next()) + for (SwTextFrame* pFrame = iter.First(); pFrame && !mpNodeNumRLHidden; pFrame = iter.Next()) { if (pFrame->getRootFrame()->IsHideRedlines()) { @@ -4337,18 +4360,28 @@ void SwTextNode::AddToList() void SwTextNode::AddToListRLHidden() { if (mpNodeNumRLHidden) - { - assert(false); - OSL_FAIL( "<SwTextNode::AddToListRLHidden()> - the text node is already added to a list. Serious defect" ); return; - } SwList *const pList(FindList(this)); if (pList) { assert(!mpNodeNumRLHidden); mpNodeNumRLHidden.reset(new SwNodeNum(this, true)); - pList->InsertListItem(*mpNodeNumRLHidden, true, GetAttrListLevel(), GetDoc()); + pList->InsertListItem(*mpNodeNumRLHidden, SwListRedlineType::HIDDEN, GetAttrListLevel(), GetDoc()); + } +} + +void SwTextNode::AddToListOrig() +{ + if (mpNodeNumOrig) + return; + + SwList *const pList(FindList(this)); + if (pList) + { + assert(!mpNodeNumOrig); + mpNodeNumOrig.reset(new SwNodeNum(this, true)); + pList->InsertListItem(*mpNodeNumOrig, SwListRedlineType::ORIGTEXT, GetAttrListLevel(), GetDoc()); } } @@ -4356,6 +4389,7 @@ void SwTextNode::RemoveFromList() { // sw_redlinehide: ensure it's removed from the other half too! RemoveFromListRLHidden(); + RemoveFromListOrig(); if ( IsInList() ) { SwList::RemoveListItem(*mpNodeNum, GetDoc()); @@ -4377,6 +4411,18 @@ void SwTextNode::RemoveFromListRLHidden() } } +void SwTextNode::RemoveFromListOrig() +{ + if (mpNodeNumOrig) // direct access because RemoveFromList doesn't have layout + { + assert(mpNodeNumOrig->GetParent() || !GetNodes().IsDocNodes()); + SwList::RemoveListItem(*mpNodeNumOrig, GetDoc()); + mpNodeNumOrig.reset(); + + SetWordCountDirty( true ); + } +} + bool SwTextNode::IsInList() const { return GetNum() != nullptr && GetNum()->GetParent() != nullptr;