diff options
-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 eb5b21b84669..f8e3bdd8a997 100644 --- a/sw/source/core/crsr/crsrsh.cxx +++ b/sw/source/core/crsr/crsrsh.cxx @@ -3330,7 +3330,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 b70a2219d0b3..c37df0a1fd69 100644 --- a/sw/source/core/crsr/findtxt.cxx +++ b/sw/source/core/crsr/findtxt.cxx @@ -34,6 +34,7 @@ #include <fmtfld.hxx> #include <txtatr.hxx> #include <txtfld.hxx> +#include <txtfrm.hxx> #include <swcrsr.hxx> #include <doc.hxx> #include <IDocumentUndoRedo.hxx> @@ -53,59 +54,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; @@ -114,14 +254,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: @@ -138,19 +278,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; @@ -159,8 +299,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; @@ -169,69 +309,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 { @@ -239,7 +350,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; @@ -266,47 +377,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); } } } @@ -334,7 +493,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; } } @@ -369,10 +530,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) { @@ -396,18 +576,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)) @@ -422,43 +605,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)) { @@ -477,7 +689,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; @@ -492,14 +706,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: @@ -526,10 +740,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; @@ -538,28 +752,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 ) { @@ -571,10 +789,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; @@ -587,27 +805,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 ) @@ -626,11 +852,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. */ @@ -654,13 +892,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; @@ -677,7 +921,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 { @@ -731,7 +976,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(); @@ -747,7 +993,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, |