From 6feeb066375e6b330e2ce9b3fdbfff6ef3cfdc15 Mon Sep 17 00:00:00 2001 From: Michael Stahl Date: Thu, 7 Jun 2018 17:37:52 +0200 Subject: sw_redlinehide: Add sw::WrongListIterator The simplest way to deal with the problem that wrong-lists are on the SwTextNode is to just take them as-is and iterate over them in a merged SwTextFrame. This may give results that users may disapprove of, but i'm not sure how likely it is in practice to e.g. start a delete redline in the middle of a word and end it in another paragraph. Perhaps it would be better to move the SwWrongLists to the SwTextFrame, but that is probably more work. Also add missing SwTextNode function overloads for "const", so we don't need mutable SwTextNodes. Change-Id: I9742e3793abe090cf58ad3f27b51e89be86a1964 --- sw/inc/ndtxt.hxx | 3 + sw/source/core/inc/wrong.hxx | 36 +++++++ sw/source/core/text/wrong.cxx | 195 ++++++++++++++++++++++++++++++++++++++ sw/source/core/txtnode/txtedt.cxx | 10 ++ 4 files changed, 244 insertions(+) (limited to 'sw') diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx index 894f8c078635..d1a8801eb9c7 100644 --- a/sw/inc/ndtxt.hxx +++ b/sw/inc/ndtxt.hxx @@ -194,8 +194,11 @@ public: const SwWrongList* GetWrong() const; void SetGrammarCheck( SwGrammarMarkUp* pNew, bool bDelete = true ); SwGrammarMarkUp* GetGrammarCheck(); + // return SwWrongList because *function pointer* return values aren't covariant + SwWrongList const* GetGrammarCheck() const; void SetSmartTags( SwWrongList* pNew, bool bDelete = true ); SwWrongList* GetSmartTags(); + SwWrongList const* GetSmartTags() const; void TryCharSetExpandToNum(const SfxItemSet& pCharSet); /// End: Data collected during idle time diff --git a/sw/source/core/inc/wrong.hxx b/sw/source/core/inc/wrong.hxx index 0aa575434483..831c5bb7f99a 100644 --- a/sw/source/core/inc/wrong.hxx +++ b/sw/source/core/inc/wrong.hxx @@ -32,6 +32,7 @@ #include #include #include +#include "TextFrameIndex.hxx" class SwWrongList; @@ -331,6 +332,41 @@ public: bool LookForEntry( sal_Int32 nBegin, sal_Int32 nEnd ); }; +class SwTextNode; +class SwTextFrame; + +namespace sw { + +struct MergedPara; + +class WrongListIterator +{ +private: + SwWrongList const* (SwTextNode::*const m_pGetWrongList)() const; + sw::MergedPara const*const m_pMergedPara; + size_t m_CurrentExtent; + TextFrameIndex m_CurrentIndex; + TextFrameIndex m_CurrentNodeIndex; + SwWrongList const*const m_pWrongList; + +public: + /// for the text frame + WrongListIterator(SwTextFrame const& rFrame, + SwWrongList const* (SwTextNode::*pGetWrongList)() const); + /// for SwTextSlot + WrongListIterator(SwWrongList const& rWrongList); + + bool Check(TextFrameIndex &rStart, TextFrameIndex &rLen); + const SwWrongArea* GetWrongElement(TextFrameIndex nStart); + + bool LooksUseful() { return m_pMergedPara || m_pWrongList; } + bool MergedOrSame(SwWrongList const*const pList) const { + return m_pMergedPara || m_pWrongList == pList; + } +}; + +} // namespace sw + #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/text/wrong.cxx b/sw/source/core/text/wrong.cxx index 20fdac821985..bdad843a43f8 100644 --- a/sw/source/core/text/wrong.cxx +++ b/sw/source/core/text/wrong.cxx @@ -20,6 +20,9 @@ #include #include +#include +#include + #include SwWrongArea::SwWrongArea( const OUString& rType, WrongListType listType, @@ -659,4 +662,196 @@ void SwWrongList::Insert( const OUString& rType, maList.insert(aIter, SwWrongArea( rType, meType, xPropertyBag, nNewPos, nNewLen) ); } +namespace sw { + +WrongListIterator::WrongListIterator(SwTextFrame const& rFrame, + SwWrongList const* (SwTextNode::*pGetWrongList)() const) + : m_pGetWrongList(pGetWrongList) + , m_pMergedPara(rFrame.GetMergedPara()) + , m_CurrentExtent(0) + , m_CurrentIndex(0) + , m_CurrentNodeIndex(0) + , m_pWrongList(m_pMergedPara + ? nullptr + : (rFrame.GetTextNodeFirst()->*pGetWrongList)()) +{ +} + +WrongListIterator::WrongListIterator(SwWrongList const& rWrongList) + : m_pGetWrongList(nullptr) + , m_pMergedPara(nullptr) + , m_CurrentExtent(0) + , m_CurrentIndex(0) + , m_CurrentNodeIndex(0) + , m_pWrongList(&rWrongList) +{ +} + +bool WrongListIterator::Check(TextFrameIndex & rStart, TextFrameIndex & rLen) +{ + if (m_pMergedPara) + { + if (rStart < m_CurrentIndex) + { // rewind + m_CurrentExtent = 0; + m_CurrentIndex = TextFrameIndex(0); + m_CurrentNodeIndex = TextFrameIndex(0); + } + while (m_CurrentExtent < m_pMergedPara->extents.size()) + { + sw::Extent const& rExtent(m_pMergedPara->extents[m_CurrentExtent]); + if (rStart + rLen <= m_CurrentIndex) + { + return false; + } + else if (rStart < m_CurrentIndex) + { + rLen -= (m_CurrentIndex - rStart); + assert(0 < sal_Int32(rLen)); + rStart = m_CurrentIndex; + } + if (m_CurrentIndex <= rStart && + rStart < m_CurrentIndex + TextFrameIndex(rExtent.nEnd - rExtent.nStart)) + { + SwWrongList const*const pWrongList((rExtent.pNode->*m_pGetWrongList)()); + // found the extent containing start - first, call Check + sal_Int32 nStart(rExtent.nStart + sal_Int32(rStart - m_CurrentIndex)); // (m_CurrentIndex - m_CurrentNodeIndex)); + sal_Int32 nLen; + if (sal_Int32(rLen) < rExtent.nEnd - nStart) + { + nLen = sal_Int32(rLen); + } + else + { + sal_Int32 nInLen(rLen); + nLen = rExtent.nEnd - nStart; + nInLen -= nLen; + for (size_t i = m_CurrentExtent + 1; + i < m_pMergedPara->extents.size(); ++i) + { + sw::Extent const& rExtentEnd(m_pMergedPara->extents[i]); + if (rExtentEnd.pNode != rExtent.pNode) + { + nInLen = 0; + break; + } + // add gap too + nLen += rExtentEnd.nStart - m_pMergedPara->extents[i-1].nEnd; + if (nInLen <= rExtentEnd.nEnd - rExtentEnd.nStart) + { + nLen += nInLen; + nInLen = 0; + break; + } + nLen += rExtentEnd.nEnd - rExtentEnd.nStart; + nInLen -= rExtentEnd.nEnd - rExtentEnd.nStart; + } + } + if (pWrongList && pWrongList->Check(nStart, nLen)) + { + // check if there's overlap with this extent + if (rExtent.nStart <= nStart && nStart < rExtent.nEnd) + { + // yes - now compute end position / length + sal_Int32 const nEnd(nStart + nLen); + rStart = m_CurrentIndex + TextFrameIndex(nStart - rExtent.nStart); + TextFrameIndex const nOrigLen(rLen); + if (nEnd <= rExtent.nEnd) + { + rLen = TextFrameIndex(nEnd - nStart); + } + else // have to search other extents for the end... + { + rLen = TextFrameIndex(rExtent.nEnd - nStart); + for (size_t i = m_CurrentExtent + 1; + i < m_pMergedPara->extents.size(); ++i) + { + sw::Extent const& rExtentEnd(m_pMergedPara->extents[i]); + if (rExtentEnd.pNode != rExtent.pNode + || nEnd <= rExtentEnd.nStart) + { + break; + } + if (nEnd <= rExtentEnd.nEnd) + { + rLen += TextFrameIndex(nEnd - rExtentEnd.nStart); + break; + } + rLen += TextFrameIndex(rExtentEnd.nEnd - rExtentEnd.nStart); + } + } + assert(rLen <= nOrigLen); (void) nOrigLen; + return true; + } + } + } + m_CurrentIndex += TextFrameIndex(rExtent.nEnd - rExtent.nStart); + ++m_CurrentExtent; + if (m_CurrentExtent < m_pMergedPara->extents.size() && + rExtent.pNode != m_pMergedPara->extents[m_CurrentExtent].pNode) + { + m_CurrentNodeIndex = m_CurrentIndex; // reset + } + } + return false; + } + else if (m_pWrongList) + { + sal_Int32 nStart(rStart); + sal_Int32 nLen(rLen); + bool const bRet(m_pWrongList->Check(nStart, nLen)); + rStart = TextFrameIndex(nStart); + rLen = TextFrameIndex(nLen); + return bRet; + } + return false; +} + +const SwWrongArea* +WrongListIterator::GetWrongElement(TextFrameIndex const nStart) +{ + if (m_pMergedPara) + { + if (nStart < m_CurrentIndex) + { // rewind + m_CurrentExtent = 0; + m_CurrentIndex = TextFrameIndex(0); + m_CurrentNodeIndex = TextFrameIndex(0); + } + while (m_CurrentExtent < m_pMergedPara->extents.size()) + { + sw::Extent const& rExtent(m_pMergedPara->extents[m_CurrentExtent]); + if (m_CurrentIndex <= nStart && + nStart <= m_CurrentIndex + TextFrameIndex(rExtent.nEnd - rExtent.nStart)) + { + // note: the returned object isn't wrapped because fntcache.cxx + // does not look at its positions, only its formatting props + SwWrongList const*const pWrongList((rExtent.pNode->*m_pGetWrongList)()); + if (pWrongList) + { + sal_Int32 const nNStart(rExtent.nStart + sal_Int32(nStart - m_CurrentIndex)); // (m_CurrentIndex - m_CurrentNodeIndex)); + sal_Int16 const nPos(pWrongList->GetWrongPos(nNStart)); + return pWrongList->GetElement(nPos); + } + } + m_CurrentIndex += TextFrameIndex(rExtent.nEnd - rExtent.nStart); + ++m_CurrentExtent; + if (m_CurrentExtent < m_pMergedPara->extents.size() && + rExtent.pNode != m_pMergedPara->extents[m_CurrentExtent].pNode) + { + m_CurrentNodeIndex = m_CurrentIndex; // reset + } + } + return nullptr; + } + else if (m_pWrongList) + { + sal_Int16 const nPos(m_pWrongList->GetWrongPos(sal_Int32(nStart))); + return m_pWrongList->GetElement(nPos); + } + return nullptr; +} + +} // namespace sw + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/txtnode/txtedt.cxx b/sw/source/core/txtnode/txtedt.cxx index 1f1468b1429d..7a646fc2b8ed 100644 --- a/sw/source/core/txtnode/txtedt.cxx +++ b/sw/source/core/txtnode/txtedt.cxx @@ -2216,6 +2216,11 @@ SwGrammarMarkUp* SwTextNode::GetGrammarCheck() return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pGrammarCheck : nullptr; } +SwWrongList const* SwTextNode::GetGrammarCheck() const +{ + return static_cast(const_cast(this)->GetGrammarCheck()); +} + void SwTextNode::SetSmartTags( SwWrongList* pNew, bool bDelete ) { OSL_ENSURE( !pNew || SwSmartTagMgr::Get().IsSmartTagsEnabled(), @@ -2236,6 +2241,11 @@ SwWrongList* SwTextNode::GetSmartTags() return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pSmartTags : nullptr; } +SwWrongList const* SwTextNode::GetSmartTags() const +{ + return const_cast(const_cast(this)->GetSmartTags()); +} + void SwTextNode::SetWordCountDirty( bool bNew ) const { if ( m_pParaIdleData_Impl ) -- cgit