From ab6176e88f78d0b3aa2490fbc7858304c2d4a437 Mon Sep 17 00:00:00 2001 From: Michael Stahl Date: Wed, 19 Jan 2022 12:10:35 +0100 Subject: tdf#139638 sw_fieldmarkhide: hide fieldmark command in ModelToViewHelper The crash happened because the generated ToX text contained CH_TXTATR but the fieldmarks themselves were not copied. Just filter everything except the result of the fieldmark. Change-Id: I349e7793987624e64f5afe08dfa2ca977368156b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/128605 Tested-by: Jenkins Reviewed-by: Michael Stahl --- sw/source/core/txtnode/modeltoviewhelper.cxx | 95 ++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/sw/source/core/txtnode/modeltoviewhelper.cxx b/sw/source/core/txtnode/modeltoviewhelper.cxx index c8c6095726cb..a5ae25962862 100644 --- a/sw/source/core/txtnode/modeltoviewhelper.cxx +++ b/sw/source/core/txtnode/modeltoviewhelper.cxx @@ -31,7 +31,9 @@ #include #include #include +#include #include +#include #include namespace { @@ -104,6 +106,99 @@ ModelToViewHelper::ModelToViewHelper(const SwTextNode &rNode, if (eMode & ExpandMode::HideDeletions) SwScriptInfo::selectRedLineDeleted(rNode, aHiddenMulti); + if (eMode & ExpandMode::ExpandFields) + { + // hide fieldmark commands + IDocumentMarkAccess const& rIDMA(*rNode.GetDoc().getIDocumentMarkAccess()); + ::std::deque<::std::pair> startedFields; + SwPaM cursor(rNode, 0); + while (true) + { + sw::mark::IFieldmark const* pFieldMark(nullptr); + while (true) // loop to skip NonTextFieldmarks, those are handled later + { + pFieldMark = rIDMA.getFieldmarkFor(*cursor.GetPoint()); + if (pFieldMark == nullptr + || pFieldMark->GetMarkStart().nNode.GetNode().GetTextNode()->GetText()[ + pFieldMark->GetMarkStart().nContent.GetIndex()] + != CH_TXT_ATR_FORMELEMENT) + { + break; + } + pFieldMark = nullptr; + if (!cursor.Move(fnMoveBackward, GoInContent)) + { + break; + } + } + if (!pFieldMark) + { + break; + } + assert(pFieldMark->GetMarkStart().nNode.GetNode().GetTextNode()->GetText()[pFieldMark->GetMarkStart().nContent.GetIndex()] != CH_TXT_ATR_FORMELEMENT); + // getFieldmarkFor may also return one that starts at rNode,0 - + // skip it, must be handled in loop below + if (pFieldMark->GetMarkStart().nNode < rNode) + { + SwPosition const sepPos(::sw::mark::FindFieldSep(*pFieldMark)); + startedFields.emplace_front(pFieldMark, sepPos.nNode < rNode); + *cursor.GetPoint() = pFieldMark->GetMarkStart(); + } + if (!cursor.Move(fnMoveBackward, GoInContent)) + { + break; + } + } + ::std::optional oStartHidden; + if (!::std::all_of(startedFields.begin(), startedFields.end(), + [](auto const& it) { return it.second; })) + { + oStartHidden.emplace(0); // node starts out hidden as field command + } + for (sal_Int32 i = 0; i < rNode.GetText().getLength(); ++i) + { + switch (rNode.GetText()[i]) + { + case CH_TXT_ATR_FIELDSTART: + { + auto const pFieldMark(rIDMA.getFieldmarkAt(SwPosition(const_cast(rNode), i))); + assert(pFieldMark); + startedFields.emplace_back(pFieldMark, false); + if (!oStartHidden) + { + oStartHidden.emplace(i); + } + break; + } + case CH_TXT_ATR_FIELDSEP: + { + assert(startedFields.back().first->IsCoveringPosition(SwPosition(const_cast(rNode), i))); + startedFields.back().second = true; + assert(oStartHidden); + if (::std::all_of(startedFields.begin(), startedFields.end(), + [](auto const& it) { return it.second; })) + { + // i is still hidden but the Range end is oddly "-1" + aHiddenMulti.Select({*oStartHidden, i}, true); + oStartHidden.reset(); + } + break; + } + case CH_TXT_ATR_FIELDEND: + { + assert(startedFields.back().first == rIDMA.getFieldmarkAt(SwPosition(const_cast(rNode), i))); + startedFields.pop_back(); + aHiddenMulti.Select({i, i}, true); + break; + } + } + } + if (oStartHidden && rNode.Len() != 0) + { + aHiddenMulti.Select({*oStartHidden, rNode.Len() - 1}, true); + } + } + std::vector aBlocks; sal_Int32 nShownStart = 0; -- cgit v1.2.3