[Libreoffice-commits] core.git: Branch 'private/mst/sw_redlinehide_4b' - 3 commits - sw/source

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Fri Dec 7 18:16:17 UTC 2018


 sw/source/core/crsr/findattr.cxx |    2 
 sw/source/core/crsr/findtxt.cxx  |  513 ++++++++++++++++++++++++++++-----------
 sw/source/core/crsr/pam.cxx      |   21 +
 sw/source/core/inc/pamtyp.hxx    |    7 
 4 files changed, 390 insertions(+), 153 deletions(-)

New commits:
commit 10092e58d0efd098f6e9471002d0e7d6d585f687
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Fri Dec 7 19:05:12 2018 +0100
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Dec 7 19:05:12 2018 +0100

    Revert "HACK: ODF import: always hide redlines"
    
    This reverts commit 55a9cc13e3b2d96266b5cac594d8c862c28f4c48.

diff --git a/sw/source/filter/xml/swxml.cxx b/sw/source/filter/xml/swxml.cxx
index 60cc3a5f46a9..f36ffb47a147 100644
--- a/sw/source/filter/xml/swxml.cxx
+++ b/sw/source/filter/xml/swxml.cxx
@@ -856,11 +856,8 @@ ErrCode XMLReader::Read( SwDoc &rDoc, const OUString& rBaseURL, SwPaM &rPaM, con
     if( !(IsOrganizerMode() || IsBlockMode() || m_bInsertMode ||
           m_aOption.IsFormatsOnly() ||
             // sw_redlinehide: disable layout cache for now
-#if 0
-          !*o3tl::doAccess<bool>(xInfoSet->getPropertyValue(sShowChanges))))
-#else
-          true))
-#endif
+          (officecfg::Office::Common::Misc::ExperimentalMode::get(xContext) &&
+            !*o3tl::doAccess<bool>(xInfoSet->getPropertyValue(sShowChanges)))))
     {
         try
         {
@@ -893,10 +890,8 @@ ErrCode XMLReader::Read( SwDoc &rDoc, const OUString& rBaseURL, SwPaM &rPaM, con
     // restore redline mode from import info property set
     RedlineFlags nRedlineFlags = RedlineFlags::ShowInsert;
     aAny = xInfoSet->getPropertyValue( sShowChanges );
-#if 0
     if ( *o3tl::doAccess<bool>(aAny) )
         nRedlineFlags |= RedlineFlags::ShowDelete;
-#endif
     aAny = xInfoSet->getPropertyValue( sRecordChanges );
     if ( *o3tl::doAccess<bool>(aAny) || (aKey.getLength() > 0) )
         nRedlineFlags |= RedlineFlags::On;
commit 55a9cc13e3b2d96266b5cac594d8c862c28f4c48
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Fri Nov 30 18:00:19 2018 +0100
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Dec 7 18:56:27 2018 +0100

    HACK: ODF import: always hide redlines
    
    Change-Id: I275c6738943ee0d74ccacea69af1c1f4c9ede1df

diff --git a/sw/source/filter/xml/swxml.cxx b/sw/source/filter/xml/swxml.cxx
index f36ffb47a147..60cc3a5f46a9 100644
--- a/sw/source/filter/xml/swxml.cxx
+++ b/sw/source/filter/xml/swxml.cxx
@@ -856,8 +856,11 @@ ErrCode XMLReader::Read( SwDoc &rDoc, const OUString& rBaseURL, SwPaM &rPaM, con
     if( !(IsOrganizerMode() || IsBlockMode() || m_bInsertMode ||
           m_aOption.IsFormatsOnly() ||
             // sw_redlinehide: disable layout cache for now
-          (officecfg::Office::Common::Misc::ExperimentalMode::get(xContext) &&
-            !*o3tl::doAccess<bool>(xInfoSet->getPropertyValue(sShowChanges)))))
+#if 0
+          !*o3tl::doAccess<bool>(xInfoSet->getPropertyValue(sShowChanges))))
+#else
+          true))
+#endif
     {
         try
         {
@@ -890,8 +893,10 @@ ErrCode XMLReader::Read( SwDoc &rDoc, const OUString& rBaseURL, SwPaM &rPaM, con
     // restore redline mode from import info property set
     RedlineFlags nRedlineFlags = RedlineFlags::ShowInsert;
     aAny = xInfoSet->getPropertyValue( sShowChanges );
+#if 0
     if ( *o3tl::doAccess<bool>(aAny) )
         nRedlineFlags |= RedlineFlags::ShowDelete;
+#endif
     aAny = xInfoSet->getPropertyValue( sRecordChanges );
     if ( *o3tl::doAccess<bool>(aAny) || (aKey.getLength() > 0) )
         nRedlineFlags |= RedlineFlags::On;
commit 271d845e5400d39453ae6217a80624c10596b5b2
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Fri Dec 7 18:52:54 2018 +0100
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Dec 7 18:56:27 2018 +0100

    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

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 5fe3a757e890..c99ac4f34c9a 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,184 @@
 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), m_tag(tags::Any) {}
+    explicit AmbiguousIndex(TextFrameIndex const value) : m_value(value), m_tag(tags::Frame)  {}
+    explicit AmbiguousIndex(sal_Int32 const value) : m_value(value), m_tag(tags::Model) {}
+    explicit AmbiguousIndex(sal_Int32 const value, tags const tag) : m_value(value), m_tag(tag) {}
+
+    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, std::max(m_tag, rOther.m_tag));
+    }
+};
+
+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 +240,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 +264,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 +285,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 +295,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 +336,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 +363,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
+            {
+                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
-                nEnd = bSrchForward ? nTextLen : 0;
-            sal_Int32 nStart = rContentIdx.GetIndex();
+            {
+                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 +479,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 +516,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 +562,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 +591,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
+                            : nStartInside = 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 +675,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 +692,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 +726,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 +738,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 +775,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 +791,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 +838,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. */
@@ -683,7 +907,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
     {
diff --git a/sw/source/core/crsr/pam.cxx b/sw/source/core/crsr/pam.cxx
index 354adfbbfe37..5e395024ef5d 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,


More information about the Libreoffice-commits mailing list