diff options
author | Michael Stahl <Michael.Stahl@cib.de> | 2020-11-03 22:11:59 +0100 |
---|---|---|
committer | Michael Stahl <Michael.Stahl@cib.de> | 2020-11-06 21:56:40 +0100 |
commit | 8548f71c5b471819194299a21128ac96cdf297b0 (patch) | |
tree | 5592384d69544dca71483df28756727f4723cca5 | |
parent | c0bc67de53e70e87dcc7c072e34e147852088cc2 (diff) |
CheckParaRedlineMerge
Change-Id: I4c6eac864da4b4bf531437e555a3994fd2670367
-rw-r--r-- | sw/source/core/text/redlnitr.cxx | 212 |
1 files changed, 210 insertions, 2 deletions
diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx index b878f26e27f5..33b55600e30a 100644 --- a/sw/source/core/text/redlnitr.cxx +++ b/sw/source/core/text/redlnitr.cxx @@ -35,6 +35,9 @@ #include <doc.hxx> #include <IDocumentRedlineAccess.hxx> #include <IDocumentLayoutAccess.hxx> +#include <IDocumentMarkAccess.hxx> +#include <IMark.hxx> +#include <bookmrk.hxx> #include <rootfrm.hxx> #include <breakit.hxx> #include <vcl/commandevent.hxx> @@ -47,14 +50,211 @@ using namespace ::com::sun::star; +namespace { + +class HideIterator +{ +private: + IDocumentRedlineAccess const& m_rIDRA; + IDocumentMarkAccess const& m_rIDMA; + bool const m_isHideRedlines; + sw::FieldmarkMode const m_eFieldmarkMode; + SwPosition const m_Start; + /// next redline + SwRedlineTable::size_type m_RedlineIndex; + /// next fieldmark + std::pair<sw::mark::IFieldmark const*, std::unique_ptr<SwPosition>> m_Fieldmark; + std::optional<SwPosition> m_oNextFieldmarkHide; + /// current start/end pair + SwPosition const* m_pStartPos; + SwPosition const* m_pEndPos; + +public: + SwPosition const* GetStartPos() const { return m_pStartPos; } + SwPosition const* GetEndPos() const { return m_pEndPos; } + + HideIterator(SwTextNode & rTextNode, bool const isHideRedlines, sw::FieldmarkMode const eMode) + : m_rIDRA(rTextNode.getIDocumentRedlineAccess()) + , m_rIDMA(*rTextNode.getIDocumentMarkAccess()) + , m_isHideRedlines(isHideRedlines) + , m_eFieldmarkMode(eMode) + , m_Start(rTextNode, 0) + , m_RedlineIndex(m_rIDRA.GetRedlinePos(rTextNode, RedlineType::Any)) + , m_pStartPos(nullptr) + //, m_pEndPos(nullptr) + , m_pEndPos(&m_Start) + { + } + + // delete redlines and fieldmarks can't overlap, due to sw::CalcBreaks() + // and no combining of adjacent redlines + // -> dummy chars are delete-redlined *iff* entire fieldmark is + bool Next(/*SwTextNode const* pNode, sal_Int32 */) + { + SwPosition const* pNextRedlineHide(nullptr); + assert(m_pEndPos); + if (m_isHideRedlines) + { + // position on current or next redline + for (; m_RedlineIndex < m_rIDRA.GetRedlineTable().size(); ++m_RedlineIndex) + { + SwRangeRedline const*const pRed = m_rIDRA.GetRedlineTable()[m_RedlineIndex]; + + //if (pNode->GetIndex() < pRed->Start()->nNode.GetIndex()) + if (m_pEndPos->nNode.GetIndex() < pRed->Start()->nNode.GetIndex()) + break; + + if (pRed->GetType() != RedlineType::Delete) + continue; + + SwPosition const*const pStart(pRed->Start()); + SwPosition const*const pEnd(pRed->End()); + if (*pStart == *pEnd) + { // only allowed while moving (either way?) + // assert(IDocumentRedlineAccess::IsHideChanges(rIDRA.GetRedlineFlags())); + continue; + } + if (pStart->nNode.GetNode().IsTableNode()) + { + assert(pEnd->nNode == m_Start.nNode && pEnd->nContent.GetIndex() == 0); + continue; // known pathology, ignore it + } + // TODO? + if (*m_pEndPos <= *pStart) + { + pNextRedlineHide = pStart; + break; // the next one + } + //m_pStartPos = pStart; + //m_pEndPos = pEnd; + } + } + + // how to iterate ... m_pSepPos + pFM for the start / end ? + // position on current or next fieldmark + //SwPosition const* pNextFieldmarkHide(nullptr); + std::optional<SwPosition> oNextFieldmarkHide; + m_oNextFieldmarkHide.reset(); + if (m_eFieldmarkMode != sw::FieldmarkMode::ShowBoth) + { + sal_Unicode const magic = m_eFieldmarkMode == sw::FieldmarkMode::ShowResult + ? CH_TXT_ATR_FIELDSTART + : CH_TXT_ATR_FIELDSEP; + sal_Int32 const nPos = m_pEndPos->nNode.GetNode().GetTextNode()->GetText().indexOf(magic, + m_pEndPos->nContent.GetIndex()); +#if 0 + sal_Int32 nPos = pNode->GetText().indexOf(magic, + m_Fieldmark.first + ? HideCommand + ? m_Fieldmark.first->GetEndPos() + : *m_Fieldmark.second + : 0); +#endif + if (nPos != -1) + { + m_oNextFieldmarkHide.emplace(*m_pEndPos->nNode.GetNode().GetTextNode(), nPos); + sw::mark::IFieldmark const*const pFieldmark( + m_eFieldmarkMode == sw::FieldmarkMode::ShowResult + ? m_rIDMA.getFieldmarkAt(*m_oNextFieldmarkHide) + : m_rIDMA.getFieldmarkFor(*m_oNextFieldmarkHide)); + assert(pFieldmark); + m_Fieldmark.first = pFieldmark; +#if 1 + if (m_eFieldmarkMode == sw::FieldmarkMode::ShowResult) + { + m_Fieldmark.second.reset( + new SwPosition(sw::mark::FindFieldSep(*m_Fieldmark.first))); + ++m_Fieldmark.second->nContent; + ++m_oNextFieldmarkHide->nContent; // skip start + } + else + { + m_Fieldmark.second.reset( + new SwPosition(pFieldmark->GetMarkEnd())); + --m_Fieldmark.second->nContent; + } +#endif +#if 0 + ++m_oNextFieldmarkHide->nContent; // skip + if (m_eFieldmarkMode == sw::FieldmarkMode::ShowCommand) + { + m_Fieldmark.second.reset( + new SwPosition(pFieldmark->GetMarkEnd())); + } + else + { + m_Fieldmark.second.reset( + new SwPosition(sw::mark::FindFieldSep(*m_Fieldmark.first))); + ++m_Fieldmark.second->nContent; + } + m_Fieldmark.second.reset(new SwPosition( + m_eFieldmarkMode == sw::FieldmarkMode::ShowCommand + ? pFieldmark->GetMarkEnd() - 1 + : sw::mark::FindFieldSep(*m_Fieldmark.first))); +#endif + //WRONG NODe assert(m_pEndPos->nNode.GetNode().GetTextNode()->GetNext()[m_Fieldmark.second] == CH_TXTATR_BREAKWORD); + //pNextFieldmarkHide = &tmp; /// FIXME UAF + // FIXME2: hide the sep? or the start? or none? + // ... how does cursor travel work? there should be just 2 visible fieldchar... + // ... MapViewToModel end-biased -> hide char at end? + // ... actually it doesn't matter: hide at the end and cursor moves in at the start; hide at the start and cursor moves in at the end + // ... BUT what about start at start of para / end at end of para ... + // want to have pos. outside + pos. inside => always hide SEP? + // FIXME3: in case the start char is hidden -> must merge with prev redline? + // end -> next + // NO - CheckParaRedlineMerge already merges + } + } + + // the = case may depend on which CH is hidden ? + if (pNextRedlineHide + //&& (!pNextFieldmarkHide || *pNextRedlineHide <= *pNextFieldmarkHide)) + && (!m_oNextFieldmarkHide || *pNextRedlineHide <= *m_oNextFieldmarkHide)) + { + SwRangeRedline const*const pRed(m_rIDRA.GetRedlineTable()[m_RedlineIndex]); + m_pStartPos = pRed->Start(); + m_pEndPos = pRed->End(); + ++m_RedlineIndex; + return true; + } + //else if (pNextFieldmarkHide) + else if (m_oNextFieldmarkHide) + { + //assert(!pNextRedlineHide || *pNextFieldmarkHide < *pNextRedlineHide); + assert(!pNextRedlineHide || *m_oNextFieldmarkHide < *pNextRedlineHide); + // ??? how to iterate vs not + //m_pStartPos = pNextFieldmarkHide; // FIXME UAF + m_pStartPos = &*m_oNextFieldmarkHide; +#if 0 + m_pEndPos = m_eFieldmarkMode == sw::FieldmarkMode::ShowResult + ? m_Fieldmark.second.get() + : &m_Fieldmark.first->GetMarkEnd(); +#else + m_pEndPos = m_Fieldmark.second.get(); +#endif + return true; + } + else // nothing + { + //assert(!pNextRedlineHide && !pNextFieldmarkHide); + assert(!pNextRedlineHide && !m_oNextFieldmarkHide); + m_pStartPos = nullptr; + m_pEndPos = nullptr; + return false; + } + } +}; + +} + namespace sw { std::unique_ptr<sw::MergedPara> CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode, FrameMode const eMode) { - IDocumentRedlineAccess const& rIDRA = rTextNode.getIDocumentRedlineAccess(); - if (!rFrame.getRootFrame()->IsHideRedlines()) +// IDocumentRedlineAccess const& rIDRA = rTextNode.getIDocumentRedlineAccess(); + if (!rFrame.getRootFrame()->HasMergedParas()) { return nullptr; } @@ -67,6 +267,11 @@ CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode, SwTextNode * pParaPropsNode(nullptr); SwTextNode * pNode(&rTextNode); sal_Int32 nLastEnd(0); + for (auto iter = HideIterator(rTextNode, + rFrame.getRootFrame()->IsHideRedlines(), + rFrame.getRootFrame()->GetFieldmarkMode()); iter.Next(); ) + { +#if 0 for (auto i = rIDRA.GetRedlinePos(rTextNode, RedlineType::Any); i < rIDRA.GetRedlineTable().size(); ++i) { @@ -90,6 +295,9 @@ CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode, assert(&pEnd->nNode.GetNode() == &rTextNode && pEnd->nContent.GetIndex() == 0); continue; // known pathology, ignore it } +#endif + SwPosition const*const pStart(iter.GetStartPos()); + SwPosition const*const pEnd(iter.GetEndPos()); bHaveRedlines = true; assert(pNode != &rTextNode || &pStart->nNode.GetNode() == &rTextNode); // detect calls with wrong start node if (pStart->nContent != nLastEnd) // not 0 so we eliminate adjacent deletes |