diff options
author | Michael Stahl <Michael.Stahl@cib.de> | 2018-12-04 15:57:47 +0100 |
---|---|---|
committer | Thorsten Behrens <Thorsten.Behrens@CIB.de> | 2018-12-18 22:30:16 +0100 |
commit | 71531cf13471993333373161d01577a637460fe8 (patch) | |
tree | a2c1931554dc8bad58a400956a135490aa48bf02 /sw | |
parent | f326fd99376d0ccd434dfc3596d769a63adac5ca (diff) |
sw_redlinehide_4b: adapt FindText()
Generally speaking, the find functions should find the strings that are
visible in the document view. However, they may also be called from
SwXTextDocument functions, where they ought to find the strings that are
actually in the document model.
So concoct some funny helper types and adapt this so it can handle both
cases; it's not pretty but maybe it even works.
Change-Id: I1917398ff928e922673353e75e8fb724dc042031
(cherry picked from commit 77e67e7cd2baeca13c357fbda4c44a90db23de11)
Diffstat (limited to 'sw')
-rw-r--r-- | sw/inc/swcrsr.hxx | 3 | ||||
-rw-r--r-- | sw/source/core/crsr/crsrsh.cxx | 2 | ||||
-rw-r--r-- | sw/source/core/crsr/findattr.cxx | 2 | ||||
-rw-r--r-- | sw/source/core/crsr/findtxt.cxx | 544 | ||||
-rw-r--r-- | sw/source/core/crsr/pam.cxx | 21 | ||||
-rw-r--r-- | sw/source/core/inc/pamtyp.hxx | 7 |
6 files changed, 419 insertions, 160 deletions
diff --git a/sw/inc/swcrsr.hxx b/sw/inc/swcrsr.hxx index 2ae2f58924d2..cd07cafdf46a 100644 --- a/sw/inc/swcrsr.hxx +++ b/sw/inc/swcrsr.hxx @@ -117,7 +117,8 @@ public: SwDocPositions nStart, SwDocPositions nEnde, bool& bCancel, FindRanges, - bool bReplace = false ); + bool bReplace = false, + SwRootFrame const*const pLayout = nullptr); sal_uLong FindFormat( const SwTextFormatColl& rFormatColl, SwDocPositions nStart, SwDocPositions nEnde, bool& bCancel, diff --git a/sw/source/core/crsr/crsrsh.cxx b/sw/source/core/crsr/crsrsh.cxx index 335d44ea6fcf..1085a34a655f 100644 --- a/sw/source/core/crsr/crsrsh.cxx +++ b/sw/source/core/crsr/crsrsh.cxx @@ -3328,7 +3328,7 @@ sal_uLong SwCursorShell::Find_Text( const i18nutil::SearchOptions2& rSearchOpt, m_pTableCursor = nullptr; SwCallLink aLk( *this ); // watch Cursor-Moves; call Link if needed sal_uLong nRet = m_pCurrentCursor->Find_Text(rSearchOpt, bSearchInNotes, eStart, eEnd, - bCancel, eRng, bReplace ); + bCancel, eRng, bReplace, GetLayout()); if( nRet || bCancel ) UpdateCursor(); return nRet; diff --git a/sw/source/core/crsr/findattr.cxx b/sw/source/core/crsr/findattr.cxx index 4999c07d734b..9da44ada4dfe 100644 --- a/sw/source/core/crsr/findattr.cxx +++ b/sw/source/core/crsr/findattr.cxx @@ -1135,7 +1135,7 @@ int SwFindParaAttr::DoFind(SwPaM & rCursor, SwMoveFnCollection const & fnMove, // TODO: searching for attributes in Outliner text?! // continue search in correct section (pTextRegion) - if (sw::FindTextImpl(aSrchPam, *pSearchOpt, false/*bSearchInNotes*/, *pSText, fnMove, *pTextRegion, bInReadOnly) && + if (sw::FindTextImpl(aSrchPam, *pSearchOpt, false/*bSearchInNotes*/, *pSText, fnMove, *pTextRegion, bInReadOnly, nullptr/*FIXME*/) && *aSrchPam.GetMark() != *aSrchPam.GetPoint() ) break; // found else if( !pSet->Count() ) diff --git a/sw/source/core/crsr/findtxt.cxx b/sw/source/core/crsr/findtxt.cxx index 85a77e86f772..85c6cb7fd11a 100644 --- a/sw/source/core/crsr/findtxt.cxx +++ b/sw/source/core/crsr/findtxt.cxx @@ -35,6 +35,7 @@ #include <fmtfld.hxx> #include <txtatr.hxx> #include <txtfld.hxx> +#include <txtfrm.hxx> #include <swcrsr.hxx> #include <doc.hxx> #include <IDocumentUndoRedo.hxx> @@ -54,59 +55,198 @@ using namespace ::com::sun::star; using namespace util; +/// because the Find may be called on the View or the Model, we need an index +/// afflicted by multiple personality disorder +struct AmbiguousIndex +{ +private: + sal_Int32 m_value; + +#ifndef NDEBUG + enum class tags : char { Any, Frame, Model }; + tags m_tag; +#endif + +public: + AmbiguousIndex() : m_value(-1) +#ifndef NDEBUG + , m_tag(tags::Any) +#endif + {} + explicit AmbiguousIndex(sal_Int32 const value +#ifndef NDEBUG + , tags const tag +#endif + ) : m_value(value) +#ifndef NDEBUG + , m_tag(tag) +#endif + {} + + sal_Int32 & GetAnyIndex() { return m_value; } ///< for arithmetic + sal_Int32 const& GetAnyIndex() const { return m_value; } ///< for arithmetic + TextFrameIndex GetFrameIndex() const + { + assert(m_tag != tags::Model); + return TextFrameIndex(m_value); + } + sal_Int32 GetModelIndex() const + { + assert(m_tag != tags::Frame); + return m_value; + } + void SetFrameIndex(TextFrameIndex const value) + { +#ifndef NDEBUG + m_tag = tags::Frame; +#endif + m_value = sal_Int32(value); + } + void SetModelIndex(sal_Int32 const value) + { +#ifndef NDEBUG + m_tag = tags::Model; +#endif + m_value = value; + } + + bool operator ==(AmbiguousIndex const& rOther) const + { + assert(m_tag == tags::Any || rOther.m_tag == tags::Any || m_tag == rOther.m_tag); + return m_value == rOther.m_value; + } + bool operator <=(AmbiguousIndex const& rOther) const + { + assert(m_tag == tags::Any || rOther.m_tag == tags::Any || m_tag == rOther.m_tag); + return m_value <= rOther.m_value; + } + bool operator < (AmbiguousIndex const& rOther) const + { + assert(m_tag == tags::Any || rOther.m_tag == tags::Any || m_tag == rOther.m_tag); + return m_value < rOther.m_value; + } + AmbiguousIndex operator - (AmbiguousIndex const& rOther) const + { + assert(m_tag == tags::Any || rOther.m_tag == tags::Any || m_tag == rOther.m_tag); + return AmbiguousIndex(m_value - rOther.m_value +#ifndef NDEBUG + , std::max(m_tag, rOther.m_tag) +#endif + ); + } +}; + +class MaybeMergedIter +{ + boost::optional<sw::MergedAttrIter> m_oMergedIter; + SwTextNode const*const m_pNode; + size_t m_HintIndex; + +public: + MaybeMergedIter(SwTextFrame const*const pFrame, SwTextNode const*const pNode) + : m_pNode(pNode) + , m_HintIndex(0) + { + if (pFrame) + { + m_oMergedIter.emplace(*pFrame); + } + } + + SwTextAttr const* NextAttr(SwTextNode const*& rpNode) + { + if (m_oMergedIter) + { + return m_oMergedIter->NextAttr(&rpNode); + } + if (SwpHints const*const pHints = m_pNode->GetpSwpHints()) + { + if (m_HintIndex < pHints->Count()) + { + rpNode = m_pNode; + return pHints->Get(m_HintIndex++); + } + } + return nullptr; + } +}; + static OUString -lcl_CleanStr(const SwTextNode& rNd, sal_Int32 const nStart, sal_Int32& rEnd, - std::vector<sal_Int32> &rArr, bool const bRemoveSoftHyphen, bool const bRemoveCommentAnchors) +lcl_CleanStr(const SwTextNode& rNd, + SwTextFrame const*const pFrame, + SwRootFrame const*const pLayout, + AmbiguousIndex const nStart, AmbiguousIndex & rEnd, + std::vector<AmbiguousIndex> &rArr, + bool const bRemoveSoftHyphen, bool const bRemoveCommentAnchors) { - OUStringBuffer buf(rNd.GetText()); + OUStringBuffer buf(pLayout ? pFrame->GetText() : rNd.GetText()); rArr.clear(); - const SwpHints *pHts = rNd.GetpSwpHints(); + MaybeMergedIter iter(pLayout ? pFrame : nullptr, pLayout ? nullptr : &rNd); - size_t n = 0; - sal_Int32 nSoftHyphen = nStart; - sal_Int32 nHintStart = -1; + AmbiguousIndex nSoftHyphen = nStart; + AmbiguousIndex nHintStart; bool bNewHint = true; bool bNewSoftHyphen = true; - const sal_Int32 nEnd = rEnd; - std::vector<sal_Int32> aReplaced; + const AmbiguousIndex nEnd = rEnd; + std::vector<AmbiguousIndex> aReplaced; + SwTextNode const* pNextHintNode(nullptr); + SwTextAttr const* pNextHint(iter.NextAttr(pNextHintNode)); do { if ( bNewHint ) - nHintStart = pHts && n < pHts->Count() ? - pHts->Get(n)->GetStart() : - -1; + { + if (pLayout) + { + nHintStart.SetFrameIndex(pNextHint + ? pFrame->MapModelToView(pNextHintNode, pNextHint->GetStart()) + : TextFrameIndex(-1)); + } + else + { + nHintStart.SetModelIndex(pNextHint ? pNextHint->GetStart() : -1); + } + } if ( bNewSoftHyphen ) { - nSoftHyphen = bRemoveSoftHyphen - ? rNd.GetText().indexOf(CHAR_SOFTHYPHEN, nSoftHyphen) - : -1; + if (pLayout) + { + nSoftHyphen.SetFrameIndex(TextFrameIndex(bRemoveSoftHyphen + ? pFrame->GetText().indexOf(CHAR_SOFTHYPHEN, nSoftHyphen.GetAnyIndex()) + : -1)); + } + else + { + nSoftHyphen.SetModelIndex(bRemoveSoftHyphen + ? rNd.GetText().indexOf(CHAR_SOFTHYPHEN, nSoftHyphen.GetAnyIndex()) + : -1); + } } bNewHint = false; bNewSoftHyphen = false; - sal_Int32 nStt = 0; + AmbiguousIndex nStt; // Check if next stop is a hint. - if ( nHintStart>=0 - && (-1 == nSoftHyphen || nHintStart < nSoftHyphen) + if (0 <= nHintStart.GetAnyIndex() + && (-1 == nSoftHyphen.GetAnyIndex() || nHintStart < nSoftHyphen) && nHintStart < nEnd ) { nStt = nHintStart; bNewHint = true; } // Check if next stop is a soft hyphen. - else if ( -1 != nSoftHyphen - && (-1 == nHintStart || nSoftHyphen < nHintStart) + else if ( -1 != nSoftHyphen.GetAnyIndex() + && (-1 == nHintStart.GetAnyIndex() || nSoftHyphen < nHintStart) && nSoftHyphen < nEnd) { nStt = nSoftHyphen; bNewSoftHyphen = true; } // If nSoftHyphen == nHintStart, the current hint *must* be a hint with an end. - else if (-1 != nSoftHyphen && nSoftHyphen == nHintStart) + else if (-1 != nSoftHyphen.GetAnyIndex() && nSoftHyphen == nHintStart) { nStt = nSoftHyphen; bNewHint = true; @@ -115,14 +255,14 @@ lcl_CleanStr(const SwTextNode& rNd, sal_Int32 const nStart, sal_Int32& rEnd, else break; - const sal_Int32 nCurrent = nStt - rArr.size(); + AmbiguousIndex nCurrent(nStt); + nCurrent.GetAnyIndex() -= rArr.size(); if ( bNewHint ) { - const SwTextAttr* pHt = pHts->Get(n); - if ( pHt->HasDummyChar() && (nStt >= nStart) ) + if (pNextHint->HasDummyChar() && (nStart <= nStt)) { - switch( pHt->Which() ) + switch (pNextHint->Which()) { case RES_TXTATR_FLYCNT: case RES_TXTATR_FTN: @@ -139,19 +279,19 @@ lcl_CleanStr(const SwTextNode& rNd, sal_Int32 const nStart, sal_Int32& rEnd, // simply removed if first. If at the end, we keep the // replacement and remove afterwards all at a string's // end (might be normal 0x7f). - const bool bEmpty = pHt->Which() != RES_TXTATR_FIELD - || (static_txtattr_cast<SwTextField const*>(pHt)->GetFormatField().GetField()->ExpandField(true, nullptr).isEmpty()); + const bool bEmpty = pNextHint->Which() != RES_TXTATR_FIELD + || (static_txtattr_cast<SwTextField const*>(pNextHint)->GetFormatField().GetField()->ExpandField(true, pLayout).isEmpty()); if ( bEmpty && nStart == nCurrent ) { rArr.push_back( nCurrent ); - --rEnd; - buf.remove(nCurrent, 1); + --rEnd.GetAnyIndex(); + buf.remove(nCurrent.GetAnyIndex(), 1); } else { if ( bEmpty ) aReplaced.push_back( nCurrent ); - buf[nCurrent] = '\x7f'; + buf[nCurrent.GetAnyIndex()] = '\x7f'; } } break; @@ -160,8 +300,8 @@ lcl_CleanStr(const SwTextNode& rNd, sal_Int32 const nStart, sal_Int32& rEnd, if( bRemoveCommentAnchors ) { rArr.push_back( nCurrent ); - --rEnd; - buf.remove( nCurrent, 1 ); + --rEnd.GetAnyIndex(); + buf.remove( nCurrent.GetAnyIndex(), 1 ); } } break; @@ -170,69 +310,40 @@ lcl_CleanStr(const SwTextNode& rNd, sal_Int32 const nStart, sal_Int32& rEnd, break; } } - ++n; + pNextHint = iter.NextAttr(pNextHintNode); } if ( bNewSoftHyphen ) { rArr.push_back( nCurrent ); - --rEnd; - buf.remove(nCurrent, 1); - ++nSoftHyphen; + --rEnd.GetAnyIndex(); + buf.remove(nCurrent.GetAnyIndex(), 1); + ++nSoftHyphen.GetAnyIndex(); } } while ( true ); - for( std::vector<sal_Int32>::size_type i = aReplaced.size(); i; ) + for (auto i = aReplaced.size(); i; ) { - const sal_Int32 nTmp = aReplaced[ --i ]; - if (nTmp == buf.getLength() - 1) + const AmbiguousIndex nTmp = aReplaced[ --i ]; + if (nTmp.GetAnyIndex() == buf.getLength() - 1) { - buf.truncate(nTmp); + buf.truncate(nTmp.GetAnyIndex()); rArr.push_back( nTmp ); - --rEnd; + --rEnd.GetAnyIndex(); } } return buf.makeStringAndClear(); } -// skip all non SwPostIts inside the array -static size_t GetPostIt(sal_Int32 aCount,const SwpHints *pHts) -{ - size_t aIndex = 0; - while (aCount) - { - for (size_t i = 0; i < pHts->Count(); ++i ) - { - aIndex++; - const SwTextAttr* pTextAttr = pHts->Get(i); - if ( pTextAttr->Which() == RES_TXTATR_ANNOTATION ) - { - aCount--; - if (!aCount) - break; - } - } - } - // throw away all following non postits - for( size_t i = aIndex; i < pHts->Count(); ++i ) - { - const SwTextAttr* pTextAttr = pHts->Get(i); - if ( pTextAttr->Which() == RES_TXTATR_ANNOTATION ) - break; - else - aIndex++; - } - return aIndex; -} - static bool DoSearch(SwPaM & rSearchPam, const i18nutil::SearchOptions2& rSearchOpt, utl::TextSearch& rSText, SwMoveFnCollection const & fnMove, bool bSrchForward, bool bRegSearch, bool bChkEmptyPara, bool bChkParaEnd, - sal_Int32 &nStart, sal_Int32 &nEnd, sal_Int32 nTextLen, SwNode* pNode, - SwPaM* pPam); + AmbiguousIndex & nStart, AmbiguousIndex & nEnd, AmbiguousIndex nTextLen, + SwTextNode const* pNode, SwTextFrame const* pTextFrame, + SwRootFrame const* pLayout, SwPaM* pPam); namespace sw { @@ -240,7 +351,7 @@ bool FindTextImpl(SwPaM & rSearchPam, const i18nutil::SearchOptions2& rSearchOpt, bool bSearchInNotes, utl::TextSearch& rSText, SwMoveFnCollection const & fnMove, const SwPaM & rRegion, - bool bInReadOnly) + bool bInReadOnly, SwRootFrame const*const pLayout) { if( rSearchOpt.searchString.isEmpty() ) return false; @@ -267,47 +378,95 @@ bool FindTextImpl(SwPaM & rSearchPam, aSearchItem.SetBackward(!bSrchForward); // LanguageType eLastLang = 0; - while( nullptr != ( pNode = ::GetNode( *pPam, bFirst, fnMove, bInReadOnly ) )) + while (nullptr != (pNode = ::GetNode(*pPam, bFirst, fnMove, bInReadOnly, pLayout))) { if( pNode->IsTextNode() ) { SwTextNode& rTextNode = *pNode->GetTextNode(); - sal_Int32 nTextLen = rTextNode.GetText().getLength(); - sal_Int32 nEnd; - if( rNdIdx == pPam->GetMark()->nNode ) - nEnd = pPam->GetMark()->nContent.GetIndex(); + SwTextFrame const*const pFrame(pLayout + ? static_cast<SwTextFrame const*>(rTextNode.getLayoutFrame(pLayout)) + : nullptr); + assert(!pLayout || pFrame); + AmbiguousIndex nTextLen; + if (pLayout) + { + nTextLen.SetFrameIndex(TextFrameIndex(pFrame->GetText().getLength())); + } else - nEnd = bSrchForward ? nTextLen : 0; - sal_Int32 nStart = rContentIdx.GetIndex(); + { + nTextLen.SetModelIndex(rTextNode.GetText().getLength()); + } + AmbiguousIndex nEnd; + if (pLayout + ? FrameContainsNode(*pFrame, pPam->GetMark()->nNode.GetIndex()) + : rNdIdx == pPam->GetMark()->nNode) + { + if (pLayout) + { + nEnd.SetFrameIndex(pFrame->MapModelToViewPos(*pPam->GetMark())); + } + else + { + nEnd.SetModelIndex(pPam->GetMark()->nContent.GetIndex()); + } + } + else + { + if (bSrchForward) + { + nEnd = nTextLen; + } + else + { + if (pLayout) + { + nEnd.SetFrameIndex(TextFrameIndex(0)); + } + else + { + nEnd.SetModelIndex(0); + } + } + } + AmbiguousIndex nStart; + if (pLayout) + { + nStart.SetFrameIndex(pFrame->MapModelToViewPos(*pPam->GetPoint())); + } + else + { + nStart.SetModelIndex(rContentIdx.GetIndex()); + } /* #i80135# */ // if there are SwPostItFields inside our current node text, we // split the text into separate pieces and search for text inside // the pieces as well as inside the fields - const SwpHints *pHts = rTextNode.GetpSwpHints(); + MaybeMergedIter iter(pLayout ? pFrame : nullptr, pLayout ? nullptr : &rTextNode); // count PostItFields by looping over all fields - sal_Int32 aNumberPostits = 0; - sal_Int32 aIgnore = 0; - if (pHts && bSearchInNotes) + std::vector<std::pair<SwTextAttr const*, AmbiguousIndex>> postits; + if (bSearchInNotes) { if (!bSrchForward) { std::swap(nStart, nEnd); } - for( size_t i = 0; i < pHts->Count(); ++i ) + SwTextNode const* pTemp(nullptr); + while (SwTextAttr const*const pTextAttr = iter.NextAttr(pTemp)) { - const SwTextAttr* pTextAttr = pHts->Get(i); if ( pTextAttr->Which()==RES_TXTATR_ANNOTATION ) { - const sal_Int32 aPos = pTextAttr->GetStart(); - if ( (aPos >= nStart) && (aPos <= nEnd) ) - aNumberPostits++; - else + AmbiguousIndex aPos; + aPos.SetModelIndex(pTextAttr->GetStart()); + if (pLayout) + { + aPos.SetFrameIndex(pFrame->MapModelToView(pTemp, aPos.GetModelIndex())); + } + if ((nStart <= aPos) && (aPos <= nEnd)) { - if (bSrchForward) - aIgnore++; + postits.emplace_back(pTextAttr, aPos); } } } @@ -335,7 +494,9 @@ bool FindTextImpl(SwPaM & rSearchPam, if (SwFrameFormat* pFrameFormat = FindFrameFormat(pObject)) { const SwPosition* pPosition = pFrameFormat->GetAnchor().GetContentAnchor(); - if (!pPosition || pPosition->nNode.GetIndex() != pNode->GetIndex()) + if (!pPosition || (pLayout + ? !FrameContainsNode(*pFrame, pPosition->nNode.GetIndex()) + : pPosition->nNode.GetIndex() != pNode->GetIndex())) pObject = nullptr; } } @@ -370,10 +531,29 @@ bool FindTextImpl(SwPaM & rSearchPam, { // If there are any shapes anchored to this node, search there. SwPaM aPaM(pNode->GetDoc()->GetNodes().GetEndOfContent()); - aPaM.GetPoint()->nNode = rTextNode; - aPaM.GetPoint()->nContent.Assign(aPaM.GetPoint()->nNode.GetNode().GetTextNode(), nStart); + if (pLayout) + { + *aPaM.GetPoint() = pFrame->MapViewToModelPos(nStart.GetFrameIndex()); + } + else + { + aPaM.GetPoint()->nNode = rTextNode; + aPaM.GetPoint()->nContent.Assign( + aPaM.GetPoint()->nNode.GetNode().GetTextNode(), + nStart.GetModelIndex()); + } aPaM.SetMark(); - aPaM.GetMark()->nNode = rTextNode.GetIndex() + 1; + if (pLayout) + { + aPaM.GetMark()->nNode = (pFrame->GetMergedPara() + ? *pFrame->GetMergedPara()->pLastNode + : rTextNode) + .GetIndex() + 1; + } + else + { + aPaM.GetMark()->nNode = rTextNode.GetIndex() + 1; + } aPaM.GetMark()->nContent.Assign(aPaM.GetMark()->nNode.GetNode().GetTextNode(), 0); if (pNode->GetDoc()->getIDocumentDrawModelAccess().Search(aPaM, aSearchItem) && pSdrView) { @@ -397,18 +577,21 @@ bool FindTextImpl(SwPaM & rSearchPam, } } - sal_Int32 aStart = 0; // do we need to finish a note? if (pPostItMgr && pPostItMgr->HasActiveSidebarWin()) { if (bSearchInNotes) { - if (bSrchForward) - aStart++; - else + if (!postits.empty()) { - if (aNumberPostits) - --aNumberPostits; + if (bSrchForward) + { + postits.erase(postits.begin()); + } + else + { + postits.pop_back(); // hope that's the right one? + } } //search inside, finish and put focus back into the doc if (pPostItMgr->FinishSearchReplace(rSearchOpt,bSrchForward)) @@ -423,43 +606,72 @@ bool FindTextImpl(SwPaM & rSearchPam, } } - if (aNumberPostits) + if (!postits.empty()) { // now we have to split - sal_Int32 nStartInside = 0; - sal_Int32 nEndInside = 0; - sal_Int32 aLoop= bSrchForward ? aStart : aNumberPostits; + AmbiguousIndex nStartInside; + AmbiguousIndex nEndInside; + sal_Int32 aLoop = bSrchForward ? 0 : postits.size(); - while ( (aLoop>=0) && (aLoop<=aNumberPostits)) + while ((0 <= aLoop) && (static_cast<size_t>(aLoop) <= postits.size())) { if (bSrchForward) { - nStartInside = aLoop==0 ? nStart : pHts->Get(GetPostIt(aLoop+aIgnore-1,pHts))->GetStart()+1; - nEndInside = aLoop==aNumberPostits ? nEnd : pHts->Get(GetPostIt(aLoop+aIgnore,pHts))->GetStart(); + if (aLoop == 0) + { + nStartInside = nStart; + } + else if (pLayout) + { + nStartInside.SetFrameIndex(postits[aLoop - 1].second.GetFrameIndex() + TextFrameIndex(1)); + } + else + { + nStartInside.SetModelIndex(postits[aLoop - 1].second.GetModelIndex() + 1); + } + nEndInside = static_cast<size_t>(aLoop) == postits.size() + ? nEnd + : postits[aLoop].second; nTextLen = nEndInside - nStartInside; } else { - nStartInside = aLoop==aNumberPostits ? nStart : pHts->Get(GetPostIt(aLoop+aIgnore,pHts))->GetStart(); - nEndInside = aLoop==0 ? nEnd : pHts->Get(GetPostIt(aLoop+aIgnore-1,pHts))->GetStart()+1; + nStartInside = static_cast<size_t>(aLoop) == postits.size() + ? nStart + : postits[aLoop].second; + if (aLoop == 0) + { + nEndInside = nEnd; + } + else if (pLayout) + { + nEndInside.SetFrameIndex(postits[aLoop - 1].second.GetFrameIndex() + TextFrameIndex(1)); + } + else + { + nEndInside.SetModelIndex(postits[aLoop - 1].second.GetModelIndex() + 1); + } nTextLen = nStartInside - nEndInside; } // search inside the text between a note bFound = DoSearch( rSearchPam, rSearchOpt, rSText, fnMove, bSrchForward, bRegSearch, bChkEmptyPara, bChkParaEnd, - nStartInside, nEndInside, nTextLen, pNode, + nStartInside, nEndInside, nTextLen, + pNode->GetTextNode(), pFrame, pLayout, pPam.get() ); if ( bFound ) break; else { // we should now be right in front of a note, search inside - if ( (bSrchForward && (GetPostIt(aLoop + aIgnore,pHts) < pHts->Count()) ) || ( !bSrchForward && (aLoop!=0) )) + if (bSrchForward + ? (static_cast<size_t>(aLoop) != postits.size()) + : (aLoop != 0)) { - const SwTextAttr* pTextAttr = bSrchForward - ? pHts->Get(GetPostIt(aLoop+aIgnore,pHts)) - : pHts->Get(GetPostIt(aLoop+aIgnore-1,pHts)); + const SwTextAttr *const pTextAttr = bSrchForward + ? postits[aLoop].first + : postits[aLoop - 1].first; if (pPostItMgr && pPostItMgr->SearchReplace( static_txtattr_cast<SwTextField const*>(pTextAttr)->GetFormatField(),rSearchOpt,bSrchForward)) { @@ -478,7 +690,9 @@ bool FindTextImpl(SwPaM & rSearchPam, bFound = DoSearch( rSearchPam, rSearchOpt, rSText, fnMove, bSrchForward, bRegSearch, bChkEmptyPara, bChkParaEnd, - nStart, nEnd, nTextLen, pNode, pPam.get() ); + nStart, nEnd, nTextLen, + pNode->GetTextNode(), pFrame, pLayout, + pPam.get() ); } if (bFound) break; @@ -493,14 +707,14 @@ bool DoSearch(SwPaM & rSearchPam, const i18nutil::SearchOptions2& rSearchOpt, utl::TextSearch& rSText, SwMoveFnCollection const & fnMove, bool bSrchForward, bool bRegSearch, bool bChkEmptyPara, bool bChkParaEnd, - sal_Int32 &nStart, sal_Int32 &nEnd, sal_Int32 nTextLen, - SwNode* pNode, SwPaM* pPam) + AmbiguousIndex & nStart, AmbiguousIndex & nEnd, AmbiguousIndex const nTextLen, + SwTextNode const*const pNode, SwTextFrame const*const pFrame, + SwRootFrame const*const pLayout, SwPaM* pPam) { bool bFound = false; SwNodeIndex& rNdIdx = pPam->GetPoint()->nNode; - const SwNode* pSttNd = &rNdIdx.GetNode(); OUString sCleanStr; - std::vector<sal_Int32> aFltArr; + std::vector<AmbiguousIndex> aFltArr; LanguageType eLastLang = LANGUAGE_SYSTEM; // if the search string contains a soft hyphen, // we don't strip them from the text: @@ -527,10 +741,10 @@ bool DoSearch(SwPaM & rSearchPam, } if( bSrchForward ) - sCleanStr = lcl_CleanStr(*pNode->GetTextNode(), nStart, nEnd, + sCleanStr = lcl_CleanStr(*pNode, pFrame, pLayout, nStart, nEnd, aFltArr, bRemoveSoftHyphens, bRemoveCommentAnchors); else - sCleanStr = lcl_CleanStr(*pNode->GetTextNode(), nEnd, nStart, + sCleanStr = lcl_CleanStr(*pNode, pFrame, pLayout, nEnd, nStart, aFltArr, bRemoveSoftHyphens, bRemoveCommentAnchors); std::unique_ptr<SwScriptIterator> pScriptIter; @@ -539,28 +753,32 @@ bool DoSearch(SwPaM & rSearchPam, if (SearchAlgorithms2::APPROXIMATE == rSearchOpt.AlgorithmType2) { - pScriptIter.reset(new SwScriptIterator( sCleanStr, nStart, bSrchForward )); + pScriptIter.reset(new SwScriptIterator(sCleanStr, nStart.GetAnyIndex(), bSrchForward)); nSearchScript = g_pBreakIt->GetRealScriptOfText( rSearchOpt.searchString, 0 ); } - const sal_Int32 nStringEnd = nEnd; + const AmbiguousIndex nStringEnd = nEnd; bool bZeroMatch = false; // zero-length match, i.e. only $ anchor as regex while ( ((bSrchForward && nStart < nStringEnd) || - (! bSrchForward && nStart > nStringEnd)) && !bZeroMatch ) + (!bSrchForward && nStringEnd < nStart)) && !bZeroMatch ) { // SearchAlgorithms_APPROXIMATE works on a per word base so we have to // provide the text searcher with the correct locale, because it uses // the break-iterator if ( pScriptIter ) { - nEnd = pScriptIter->GetScriptChgPos(); + nEnd.GetAnyIndex() = pScriptIter->GetScriptChgPos(); nCurrScript = pScriptIter->GetCurrScript(); if ( nSearchScript == nCurrScript ) { - const LanguageType eCurrLang = - pNode->GetTextNode()->GetLang( bSrchForward ? - nStart : - nEnd ); + const LanguageType eCurrLang = pLayout + ? pFrame->GetLangOfChar(bSrchForward + ? nStart.GetFrameIndex() + : nEnd.GetFrameIndex(), + 0, true) + : pNode->GetLang(bSrchForward + ? nStart.GetModelIndex() + : nEnd.GetModelIndex()); if ( eCurrLang != eLastLang ) { @@ -572,10 +790,10 @@ bool DoSearch(SwPaM & rSearchPam, } pScriptIter->Next(); } - sal_Int32 nProxyStart = nStart; - sal_Int32 nProxyEnd = nEnd; + AmbiguousIndex nProxyStart = nStart; + AmbiguousIndex nProxyEnd = nEnd; if( nSearchScript == nCurrScript && - (rSText.*fnMove.fnSearch)( sCleanStr, &nProxyStart, &nProxyEnd, nullptr ) && + (rSText.*fnMove.fnSearch)( sCleanStr, &nProxyStart.GetAnyIndex(), &nProxyEnd.GetAnyIndex(), nullptr) && !(bZeroMatch = (nProxyStart == nProxyEnd))) { nStart = nProxyStart; @@ -588,27 +806,35 @@ bool DoSearch(SwPaM & rSearchPam, if( !aFltArr.empty() ) { // if backward search, switch positions temporarily - if( !bSrchForward ) { std::swap(nStart, nEnd); } + if (!bSrchForward) { std::swap(nStart, nEnd); } - sal_Int32 nNew = nStart; + AmbiguousIndex nNew = nStart; for (size_t n = 0; n < aFltArr.size() && aFltArr[ n ] <= nStart; ++n ) { - ++nNew; + ++nNew.GetAnyIndex(); } nStart = nNew; nNew = nEnd; for( size_t n = 0; n < aFltArr.size() && aFltArr[ n ] < nEnd; ++n ) { - ++nNew; + ++nNew.GetAnyIndex(); } nEnd = nNew; // if backward search, switch positions temporarily if( !bSrchForward ) { std::swap(nStart, nEnd); } } - rSearchPam.GetMark()->nContent = nStart; - rSearchPam.GetPoint()->nContent = nEnd; + if (pLayout) + { + *rSearchPam.GetMark() = pFrame->MapViewToModelPos(nStart.GetFrameIndex()); + *rSearchPam.GetPoint() = pFrame->MapViewToModelPos(nEnd.GetFrameIndex()); + } + else + { + rSearchPam.GetMark()->nContent = nStart.GetModelIndex(); + rSearchPam.GetPoint()->nContent = nEnd.GetModelIndex(); + } // if backward search, switch point and mark if( !bSrchForward ) @@ -627,11 +853,23 @@ bool DoSearch(SwPaM & rSearchPam, if ( bFound ) return true; - else if( ( bChkEmptyPara && !nStart && !nTextLen ) || bChkParaEnd) + else if ((bChkEmptyPara && !nStart.GetAnyIndex() && !nTextLen.GetAnyIndex()) + || bChkParaEnd) { *rSearchPam.GetPoint() = *pPam->GetPoint(); - rSearchPam.GetPoint()->nContent = bChkParaEnd ? nTextLen : 0; + if (pLayout) + { + *rSearchPam.GetPoint() = pFrame->MapViewToModelPos( + bChkParaEnd ? nTextLen.GetFrameIndex() : TextFrameIndex(0)); + } + else + { + rSearchPam.GetPoint()->nContent = bChkParaEnd ? nTextLen.GetModelIndex() : 0; + } rSearchPam.SetMark(); + const SwNode *const pSttNd = bSrchForward + ? &rSearchPam.GetPoint()->nNode.GetNode() // end of the frame + : &rNdIdx.GetNode(); // keep the bug as-is for now... /* FIXME: this condition does not work for !bSrchForward backward * search, it probably never did. (pSttNd != &rNdIdx.GetNode()) * is never true in this case. */ @@ -655,13 +893,19 @@ struct SwFindParaText : public SwFindParas { const i18nutil::SearchOptions2& m_rSearchOpt; SwCursor& m_rCursor; + SwRootFrame const* m_pLayout; utl::TextSearch m_aSText; bool const m_bReplace; bool const m_bSearchInNotes; - SwFindParaText( const i18nutil::SearchOptions2& rOpt, bool bSearchInNotes, bool bRepl, SwCursor& rCursor ) - : m_rSearchOpt( rOpt ), m_rCursor( rCursor ), m_aSText( utl::TextSearch::UpgradeToSearchOptions2( rOpt) ), - m_bReplace( bRepl ), m_bSearchInNotes( bSearchInNotes ) + SwFindParaText(const i18nutil::SearchOptions2& rOpt, bool bSearchInNotes, + bool bRepl, SwCursor& rCursor, SwRootFrame const*const pLayout) + : m_rSearchOpt( rOpt ) + , m_rCursor( rCursor ) + , m_pLayout(pLayout) + , m_aSText( utl::TextSearch::UpgradeToSearchOptions2(rOpt) ) + , m_bReplace( bRepl ) + , m_bSearchInNotes( bSearchInNotes ) {} virtual int DoFind(SwPaM &, SwMoveFnCollection const &, const SwPaM &, bool bInReadOnly) override; virtual bool IsReplaceMode() const override; @@ -678,7 +922,8 @@ int SwFindParaText::DoFind(SwPaM & rCursor, SwMoveFnCollection const & fnMove, if( bInReadOnly && m_bReplace ) bInReadOnly = false; - const bool bFnd = sw::FindTextImpl(rCursor, m_rSearchOpt, m_bSearchInNotes, m_aSText, fnMove, rRegion, bInReadOnly); + const bool bFnd = sw::FindTextImpl(rCursor, m_rSearchOpt, m_bSearchInNotes, + m_aSText, fnMove, rRegion, bInReadOnly, m_pLayout); if( bFnd && m_bReplace ) // replace string { @@ -732,7 +977,8 @@ bool SwFindParaText::IsReplaceMode() const sal_uLong SwCursor::Find_Text( const i18nutil::SearchOptions2& rSearchOpt, bool bSearchInNotes, SwDocPositions nStart, SwDocPositions nEnd, - bool& bCancel, FindRanges eFndRngs, bool bReplace ) + bool& bCancel, FindRanges eFndRngs, bool bReplace, + SwRootFrame const*const pLayout) { // switch off OLE-notifications SwDoc* pDoc = GetDoc(); @@ -748,7 +994,7 @@ sal_uLong SwCursor::Find_Text( const i18nutil::SearchOptions2& rSearchOpt, bool bool bSearchSel = 0 != (rSearchOpt.searchFlag & SearchFlags::REG_NOT_BEGINOFLINE); if( bSearchSel ) eFndRngs = static_cast<FindRanges>(eFndRngs | FindRanges::InSel); - SwFindParaText aSwFindParaText( rSearchOpt, bSearchInNotes, bReplace, *this ); + SwFindParaText aSwFindParaText(rSearchOpt, bSearchInNotes, bReplace, *this, pLayout); sal_uLong nRet = FindAll( aSwFindParaText, nStart, nEnd, eFndRngs, bCancel ); pDoc->SetOle2Link( aLnk ); if( nRet && bReplace ) diff --git a/sw/source/core/crsr/pam.cxx b/sw/source/core/crsr/pam.cxx index 354adfbbfe37..3583e0d2794c 100644 --- a/sw/source/core/crsr/pam.cxx +++ b/sw/source/core/crsr/pam.cxx @@ -735,24 +735,26 @@ bool SwPaM::HasReadonlySel( bool bFormView ) const /// @param rbFirst If <true> then first time request. If so than the position of /// the PaM must not be changed! SwContentNode* GetNode( SwPaM & rPam, bool& rbFirst, SwMoveFnCollection const & fnMove, - bool bInReadOnly ) + bool const bInReadOnly, SwRootFrame const*const i_pLayout) { + SwRootFrame const*const pLayout(i_pLayout ? i_pLayout : + rPam.GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout()); SwContentNode * pNd = nullptr; if( ((*rPam.GetPoint()).*fnMove.fnCmpOp)( *rPam.GetMark() ) || ( *rPam.GetPoint() == *rPam.GetMark() && rbFirst ) ) { - SwContentFrame* pFrame; if( rbFirst ) { rbFirst = false; pNd = rPam.GetContentNode(); if( pNd ) { + SwContentFrame const*const pFrame(pNd->getLayoutFrame(pLayout)); if( ( - nullptr == ( pFrame = pNd->getLayoutFrame( pNd->GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout() ) ) || + nullptr == pFrame || ( !bInReadOnly && pFrame->IsProtected() ) || - (pFrame->IsTextFrame() && static_cast<SwTextFrame*>(pFrame)->IsHiddenNow()) + (pFrame->IsTextFrame() && static_cast<SwTextFrame const*>(pFrame)->IsHiddenNow()) ) || ( !bInReadOnly && pNd->FindSectionNode() && pNd->FindSectionNode()->GetSection().IsProtect() @@ -773,6 +775,12 @@ SwContentNode* GetNode( SwPaM & rPam, bool& rbFirst, SwMoveFnCollection const & // go to next/previous ContentNode while( true ) { + if (i_pLayout && aPos.nNode.GetNode().IsTextNode()) + { + auto const fal(sw::GetFirstAndLastNode(*pLayout, aPos.nNode)); + aPos.nNode = bSrchForward ? *fal.second : *fal.first; + } + pNd = bSrchForward ? rNodes.GoNextSection( &aPos.nNode, true, !bInReadOnly ) : SwNodes::GoPrevSection( &aPos.nNode, true, !bInReadOnly ); @@ -783,10 +791,11 @@ SwContentNode* GetNode( SwPaM & rPam, bool& rbFirst, SwMoveFnCollection const & if( (aPos.*fnMove.fnCmpOp)( *rPam.GetMark() ) ) { // only in AutoTextSection can be nodes that are hidden - if( nullptr == ( pFrame = pNd->getLayoutFrame( pNd->GetDoc()->getIDocumentLayoutAccess().GetCurrentLayout() ) ) || + SwContentFrame const*const pFrame(pNd->getLayoutFrame(pLayout)); + if (nullptr == pFrame || ( !bInReadOnly && pFrame->IsProtected() ) || ( pFrame->IsTextFrame() && - static_cast<SwTextFrame*>(pFrame)->IsHiddenNow() ) ) + static_cast<SwTextFrame const*>(pFrame)->IsHiddenNow())) { pNd = nullptr; continue; diff --git a/sw/source/core/inc/pamtyp.hxx b/sw/source/core/inc/pamtyp.hxx index b8a81a090387..a0ebf2bea708 100644 --- a/sw/source/core/inc/pamtyp.hxx +++ b/sw/source/core/inc/pamtyp.hxx @@ -29,6 +29,7 @@ class SwPaM; class SwTextAttr; class SwFormat; class SfxPoolItem; +class SwRootFrame; namespace i18nutil { struct SearchOptions2; @@ -75,7 +76,8 @@ struct SwMoveFnCollection }; // function prototype for searching -SwContentNode* GetNode( SwPaM&, bool&, SwMoveFnCollection const &, bool bInReadOnly = false ); +SwContentNode* GetNode(SwPaM&, bool&, SwMoveFnCollection const &, + bool bInReadOnly = false, SwRootFrame const* pLayout = nullptr); namespace sw { @@ -88,7 +90,8 @@ namespace sw { bool bSearchInNotes, utl::TextSearch& rSText, SwMoveFnCollection const & fnMove, - const SwPaM & rRegion, bool bInReadOnly = false); + const SwPaM & rRegion, bool bInReadOnly, + SwRootFrame const* pLayout); bool FindFormatImpl(SwPaM & rSearchPam, const SwFormat& rFormat, SwMoveFnCollection const & fnMove, |