xref: /core/sw/source/core/crsr/findtxt.cxx (revision 02c352d7)
161355e51SSebastian Spaeth /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2caaeb0a0SMichael Meeks /*
3caaeb0a0SMichael Meeks  * This file is part of the LibreOffice project.
4caaeb0a0SMichael Meeks  *
5caaeb0a0SMichael Meeks  * This Source Code Form is subject to the terms of the Mozilla Public
6caaeb0a0SMichael Meeks  * License, v. 2.0. If a copy of the MPL was not distributed with this
7caaeb0a0SMichael Meeks  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8caaeb0a0SMichael Meeks  *
9caaeb0a0SMichael Meeks  * This file incorporates work covered by the following license notice:
10caaeb0a0SMichael Meeks  *
11caaeb0a0SMichael Meeks  *   Licensed to the Apache Software Foundation (ASF) under one or more
12caaeb0a0SMichael Meeks  *   contributor license agreements. See the NOTICE file distributed
13caaeb0a0SMichael Meeks  *   with this work for additional information regarding copyright
14caaeb0a0SMichael Meeks  *   ownership. The ASF licenses this file to you under the Apache
15caaeb0a0SMichael Meeks  *   License, Version 2.0 (the "License"); you may not use this file
16caaeb0a0SMichael Meeks  *   except in compliance with the License. You may obtain a copy of
17caaeb0a0SMichael Meeks  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18caaeb0a0SMichael Meeks  */
1984a3db80SJens-Heiner Rechtien 
2033aead22SMiklos Vajna #include <memory>
2133aead22SMiklos Vajna 
226dc901b7SThomas Lange #include <com/sun/star/util/SearchFlags.hpp>
2333623f31SGabor Kelemen #include <com/sun/star/util/SearchResult.hpp>
2446b52c22SCaolán McNamara #include <comphelper/lok.hxx>
25aef7feb3SStephan Bergmann #include <o3tl/safeint.hxx>
26e12fa18cSGabor Kelemen #include <rtl/ustrbuf.hxx>
2707355d26SMiklos Vajna #include <svx/svdview.hxx>
2807355d26SMiklos Vajna #include <svl/srchitem.hxx>
2907355d26SMiklos Vajna #include <sfx2/sfxsids.hrc>
3007355d26SMiklos Vajna #include <editeng/outliner.hxx>
312633d5f9SGabor Kelemen #include <osl/diagnose.h>
323145216bSMichael Stahl 
331633fb26SMiklos Vajna #include <wrtsh.hxx>
3442fe0555SFrank Meies #include <txatritr.hxx>
3584a3db80SJens-Heiner Rechtien #include <fldbas.hxx>
3684a3db80SJens-Heiner Rechtien #include <fmtfld.hxx>
3784a3db80SJens-Heiner Rechtien #include <txtfld.hxx>
3877e67e7cSMichael Stahl #include <txtfrm.hxx>
395e81b966SMichael Stahl #include <rootfrm.hxx>
4084a3db80SJens-Heiner Rechtien #include <swcrsr.hxx>
415e81b966SMichael Stahl #include <redline.hxx>
4284a3db80SJens-Heiner Rechtien #include <doc.hxx>
433145216bSMichael Stahl #include <IDocumentUndoRedo.hxx>
4464e13a14SValentin Kettner #include <IDocumentState.hxx>
45bdc1824eSMiklos Vajna #include <IDocumentDrawModelAccess.hxx>
465e81b966SMichael Stahl #include <IDocumentRedlineAccess.hxx>
47122b1498SMiklos Vajna #include <dcontact.hxx>
4884a3db80SJens-Heiner Rechtien #include <pamtyp.hxx>
4984a3db80SJens-Heiner Rechtien #include <ndtxt.hxx>
5084a3db80SJens-Heiner Rechtien #include <swundo.hxx>
5150c0114cSMichael Stahl #include <UndoInsert.hxx>
5242fe0555SFrank Meies #include <breakit.hxx>
5319f251c2SJens-Heiner Rechtien #include <docsh.hxx>
5419f251c2SJens-Heiner Rechtien #include <PostItMgr.hxx>
55dce533e0SMiklos Vajna #include <view.hxx>
5619f251c2SJens-Heiner Rechtien 
57429fbc98SJens-Heiner Rechtien using namespace ::com::sun::star;
58429fbc98SJens-Heiner Rechtien using namespace util;
596dc901b7SThomas Lange 
60f853ec31SStephan Bergmann namespace {
61f853ec31SStephan Bergmann 
6277e67e7cSMichael Stahl /// because the Find may be called on the View or the Model, we need an index
6377e67e7cSMichael Stahl /// afflicted by multiple personality disorder
6477e67e7cSMichael Stahl struct AmbiguousIndex
6577e67e7cSMichael Stahl {
6677e67e7cSMichael Stahl private:
6777e67e7cSMichael Stahl     sal_Int32 m_value;
6877e67e7cSMichael Stahl 
6977e67e7cSMichael Stahl #ifndef NDEBUG
7077e67e7cSMichael Stahl     enum class tags : char { Any, Frame, Model };
7177e67e7cSMichael Stahl     tags m_tag;
7277e67e7cSMichael Stahl #endif
7377e67e7cSMichael Stahl 
7477e67e7cSMichael Stahl public:
7577e67e7cSMichael Stahl     AmbiguousIndex() : m_value(-1)
7677e67e7cSMichael Stahl #ifndef NDEBUG
7777e67e7cSMichael Stahl            , m_tag(tags::Any)
7877e67e7cSMichael Stahl #endif
7977e67e7cSMichael Stahl     {}
8077e67e7cSMichael Stahl     explicit AmbiguousIndex(sal_Int32 const value
8177e67e7cSMichael Stahl #ifndef NDEBUG
8277e67e7cSMichael Stahl             , tags const tag
8377e67e7cSMichael Stahl #endif
8477e67e7cSMichael Stahl         )   : m_value(value)
8577e67e7cSMichael Stahl #ifndef NDEBUG
8677e67e7cSMichael Stahl             , m_tag(tag)
8777e67e7cSMichael Stahl #endif
8877e67e7cSMichael Stahl     {}
8977e67e7cSMichael Stahl 
9077e67e7cSMichael Stahl     sal_Int32 & GetAnyIndex() { return m_value; } ///< for arithmetic
9177e67e7cSMichael Stahl     sal_Int32 const& GetAnyIndex() const { return m_value; } ///< for arithmetic
9277e67e7cSMichael Stahl     TextFrameIndex GetFrameIndex() const
9377e67e7cSMichael Stahl     {
9477e67e7cSMichael Stahl         assert(m_tag != tags::Model);
9577e67e7cSMichael Stahl         return TextFrameIndex(m_value);
9677e67e7cSMichael Stahl     }
9777e67e7cSMichael Stahl     sal_Int32 GetModelIndex() const
9877e67e7cSMichael Stahl     {
9977e67e7cSMichael Stahl         assert(m_tag != tags::Frame);
10077e67e7cSMichael Stahl         return m_value;
10177e67e7cSMichael Stahl     }
10277e67e7cSMichael Stahl     void SetFrameIndex(TextFrameIndex const value)
10377e67e7cSMichael Stahl     {
10477e67e7cSMichael Stahl #ifndef NDEBUG
10577e67e7cSMichael Stahl         m_tag = tags::Frame;
10677e67e7cSMichael Stahl #endif
10777e67e7cSMichael Stahl         m_value = sal_Int32(value);
10877e67e7cSMichael Stahl     }
10977e67e7cSMichael Stahl     void SetModelIndex(sal_Int32 const value)
11077e67e7cSMichael Stahl     {
11177e67e7cSMichael Stahl #ifndef NDEBUG
11277e67e7cSMichael Stahl         m_tag = tags::Model;
11377e67e7cSMichael Stahl #endif
11477e67e7cSMichael Stahl         m_value = value;
11577e67e7cSMichael Stahl     }
11677e67e7cSMichael Stahl 
11777e67e7cSMichael Stahl     bool operator ==(AmbiguousIndex const& rOther) const
11877e67e7cSMichael Stahl     {
11977e67e7cSMichael Stahl         assert(m_tag == tags::Any || rOther.m_tag == tags::Any || m_tag == rOther.m_tag);
12077e67e7cSMichael Stahl         return m_value == rOther.m_value;
12177e67e7cSMichael Stahl     }
12277e67e7cSMichael Stahl     bool operator <=(AmbiguousIndex const& rOther) const
12377e67e7cSMichael Stahl     {
12477e67e7cSMichael Stahl         assert(m_tag == tags::Any || rOther.m_tag == tags::Any || m_tag == rOther.m_tag);
12577e67e7cSMichael Stahl         return m_value <= rOther.m_value;
12677e67e7cSMichael Stahl     }
12777e67e7cSMichael Stahl     bool operator < (AmbiguousIndex const& rOther) const
12877e67e7cSMichael Stahl     {
12977e67e7cSMichael Stahl         assert(m_tag == tags::Any || rOther.m_tag == tags::Any || m_tag == rOther.m_tag);
13077e67e7cSMichael Stahl         return m_value <  rOther.m_value;
13177e67e7cSMichael Stahl     }
13277e67e7cSMichael Stahl     AmbiguousIndex operator - (AmbiguousIndex const& rOther) const
13377e67e7cSMichael Stahl     {
13477e67e7cSMichael Stahl         assert(m_tag == tags::Any || rOther.m_tag == tags::Any || m_tag == rOther.m_tag);
13577e67e7cSMichael Stahl         return AmbiguousIndex(m_value - rOther.m_value
13677e67e7cSMichael Stahl #ifndef NDEBUG
13777e67e7cSMichael Stahl                 , std::max(m_tag, rOther.m_tag)
13877e67e7cSMichael Stahl #endif
13977e67e7cSMichael Stahl             );
14077e67e7cSMichael Stahl     }
14177e67e7cSMichael Stahl };
14277e67e7cSMichael Stahl 
14377e67e7cSMichael Stahl class MaybeMergedIter
14477e67e7cSMichael Stahl {
1459ad252b2SStephan Bergmann     std::optional<sw::MergedAttrIter> m_oMergedIter;
14677e67e7cSMichael Stahl     SwTextNode const*const m_pNode;
14777e67e7cSMichael Stahl     size_t m_HintIndex;
14877e67e7cSMichael Stahl 
14977e67e7cSMichael Stahl public:
15077e67e7cSMichael Stahl     MaybeMergedIter(SwTextFrame const*const pFrame, SwTextNode const*const pNode)
15177e67e7cSMichael Stahl         : m_pNode(pNode)
15277e67e7cSMichael Stahl         , m_HintIndex(0)
15377e67e7cSMichael Stahl     {
15477e67e7cSMichael Stahl         if (pFrame)
15577e67e7cSMichael Stahl         {
15677e67e7cSMichael Stahl             m_oMergedIter.emplace(*pFrame);
15777e67e7cSMichael Stahl         }
15877e67e7cSMichael Stahl     }
15977e67e7cSMichael Stahl 
16077e67e7cSMichael Stahl     SwTextAttr const* NextAttr(SwTextNode const*& rpNode)
16177e67e7cSMichael Stahl     {
16277e67e7cSMichael Stahl         if (m_oMergedIter)
16377e67e7cSMichael Stahl         {
16477e67e7cSMichael Stahl             return m_oMergedIter->NextAttr(&rpNode);
16577e67e7cSMichael Stahl         }
16677e67e7cSMichael Stahl         if (SwpHints const*const pHints = m_pNode->GetpSwpHints())
16777e67e7cSMichael Stahl         {
16877e67e7cSMichael Stahl             if (m_HintIndex < pHints->Count())
16977e67e7cSMichael Stahl             {
17077e67e7cSMichael Stahl                 rpNode = m_pNode;
17177e67e7cSMichael Stahl                 return pHints->Get(m_HintIndex++);
17277e67e7cSMichael Stahl             }
17377e67e7cSMichael Stahl         }
17477e67e7cSMichael Stahl         return nullptr;
17577e67e7cSMichael Stahl     }
17677e67e7cSMichael Stahl };
17777e67e7cSMichael Stahl 
178f853ec31SStephan Bergmann }
179f853ec31SStephan Bergmann 
1807b28b6ccSMichael Stahl static OUString
18177e67e7cSMichael Stahl lcl_CleanStr(const SwTextNode& rNd,
18277e67e7cSMichael Stahl              SwTextFrame const*const pFrame,
18377e67e7cSMichael Stahl              SwRootFrame const*const pLayout,
18477e67e7cSMichael Stahl              AmbiguousIndex const nStart, AmbiguousIndex & rEnd,
18577e67e7cSMichael Stahl              std::vector<AmbiguousIndex> &rArr,
18677e67e7cSMichael Stahl              bool const bRemoveSoftHyphen, bool const bRemoveCommentAnchors)
18784a3db80SJens-Heiner Rechtien {
18877e67e7cSMichael Stahl     OUStringBuffer buf(pLayout ? pFrame->GetText() : rNd.GetText());
189c0ac13caSNigel Hawkins     rArr.clear();
19084a3db80SJens-Heiner Rechtien 
19177e67e7cSMichael Stahl     MaybeMergedIter iter(pLayout ? pFrame : nullptr, pLayout ? nullptr : &rNd);
1921e8d97f7SJens-Heiner Rechtien 
19377e67e7cSMichael Stahl     AmbiguousIndex nSoftHyphen = nStart;
19477e67e7cSMichael Stahl     AmbiguousIndex nHintStart;
1951e8d97f7SJens-Heiner Rechtien     bool bNewHint       = true;
1961e8d97f7SJens-Heiner Rechtien     bool bNewSoftHyphen = true;
19777e67e7cSMichael Stahl     const AmbiguousIndex nEnd = rEnd;
19877e67e7cSMichael Stahl     std::vector<AmbiguousIndex> aReplaced;
19977e67e7cSMichael Stahl     SwTextNode const* pNextHintNode(nullptr);
20077e67e7cSMichael Stahl     SwTextAttr const* pNextHint(iter.NextAttr(pNextHintNode));
2011e8d97f7SJens-Heiner Rechtien 
2021e8d97f7SJens-Heiner Rechtien     do
20384a3db80SJens-Heiner Rechtien     {
2041e8d97f7SJens-Heiner Rechtien         if ( bNewHint )
20577e67e7cSMichael Stahl         {
20677e67e7cSMichael Stahl             if (pLayout)
20777e67e7cSMichael Stahl             {
20877e67e7cSMichael Stahl                 nHintStart.SetFrameIndex(pNextHint
20977e67e7cSMichael Stahl                         ? pFrame->MapModelToView(pNextHintNode, pNextHint->GetStart())
21077e67e7cSMichael Stahl                         : TextFrameIndex(-1));
21177e67e7cSMichael Stahl             }
21277e67e7cSMichael Stahl             else
21377e67e7cSMichael Stahl             {
21477e67e7cSMichael Stahl                 nHintStart.SetModelIndex(pNextHint ? pNextHint->GetStart() : -1);
21577e67e7cSMichael Stahl             }
21677e67e7cSMichael Stahl         }
21784a3db80SJens-Heiner Rechtien 
2181e8d97f7SJens-Heiner Rechtien         if ( bNewSoftHyphen )
2190295c8a3SMichael Stahl         {
22077e67e7cSMichael Stahl             if (pLayout)
22177e67e7cSMichael Stahl             {
22277e67e7cSMichael Stahl                 nSoftHyphen.SetFrameIndex(TextFrameIndex(bRemoveSoftHyphen
22377e67e7cSMichael Stahl                     ? pFrame->GetText().indexOf(CHAR_SOFTHYPHEN, nSoftHyphen.GetAnyIndex())
22477e67e7cSMichael Stahl                     : -1));
22577e67e7cSMichael Stahl             }
22677e67e7cSMichael Stahl             else
22777e67e7cSMichael Stahl             {
22877e67e7cSMichael Stahl                 nSoftHyphen.SetModelIndex(bRemoveSoftHyphen
22977e67e7cSMichael Stahl                     ? rNd.GetText().indexOf(CHAR_SOFTHYPHEN, nSoftHyphen.GetAnyIndex())
23077e67e7cSMichael Stahl                     : -1);
23177e67e7cSMichael Stahl             }
2320295c8a3SMichael Stahl         }
23384a3db80SJens-Heiner Rechtien 
2341e8d97f7SJens-Heiner Rechtien         bNewHint       = false;
2351e8d97f7SJens-Heiner Rechtien         bNewSoftHyphen = false;
23677e67e7cSMichael Stahl         AmbiguousIndex nStt;
23784a3db80SJens-Heiner Rechtien 
2381e8d97f7SJens-Heiner Rechtien         // Check if next stop is a hint.
23977e67e7cSMichael Stahl         if (0 <= nHintStart.GetAnyIndex()
24077e67e7cSMichael Stahl             && (-1 == nSoftHyphen.GetAnyIndex() || nHintStart < nSoftHyphen)
2410295c8a3SMichael Stahl             && nHintStart < nEnd )
2421e8d97f7SJens-Heiner Rechtien         {
2431e8d97f7SJens-Heiner Rechtien             nStt = nHintStart;
2441e8d97f7SJens-Heiner Rechtien             bNewHint = true;
2451e8d97f7SJens-Heiner Rechtien         }
2461e8d97f7SJens-Heiner Rechtien         // Check if next stop is a soft hyphen.
24777e67e7cSMichael Stahl         else if (   -1 != nSoftHyphen.GetAnyIndex()
24877e67e7cSMichael Stahl                  && (-1 == nHintStart.GetAnyIndex() || nSoftHyphen < nHintStart)
249156a0235SMichael Stahl                  && nSoftHyphen < nEnd)
2501e8d97f7SJens-Heiner Rechtien         {
2511e8d97f7SJens-Heiner Rechtien             nStt = nSoftHyphen;
2521e8d97f7SJens-Heiner Rechtien             bNewSoftHyphen = true;
2531e8d97f7SJens-Heiner Rechtien         }
2541e8d97f7SJens-Heiner Rechtien         // If nSoftHyphen == nHintStart, the current hint *must* be a hint with an end.
25577e67e7cSMichael Stahl         else if (-1 != nSoftHyphen.GetAnyIndex() && nSoftHyphen == nHintStart)
2561e8d97f7SJens-Heiner Rechtien         {
2571e8d97f7SJens-Heiner Rechtien             nStt = nSoftHyphen;
2581e8d97f7SJens-Heiner Rechtien             bNewHint = true;
2591e8d97f7SJens-Heiner Rechtien             bNewSoftHyphen = true;
2601e8d97f7SJens-Heiner Rechtien         }
2611e8d97f7SJens-Heiner Rechtien         else
2621e8d97f7SJens-Heiner Rechtien             break;
26384a3db80SJens-Heiner Rechtien 
26477e67e7cSMichael Stahl         AmbiguousIndex nCurrent(nStt);
26577e67e7cSMichael Stahl         nCurrent.GetAnyIndex() -= rArr.size();
26684a3db80SJens-Heiner Rechtien 
2671e8d97f7SJens-Heiner Rechtien         if ( bNewHint )
2681e8d97f7SJens-Heiner Rechtien         {
26925cf4dadSCaolán McNamara             if (pNextHint && pNextHint->HasDummyChar() && (nStart <= nStt))
27084a3db80SJens-Heiner Rechtien             {
27177e67e7cSMichael Stahl                 switch (pNextHint->Which())
27284a3db80SJens-Heiner Rechtien                 {
2731e8d97f7SJens-Heiner Rechtien                 case RES_TXTATR_FLYCNT:
2740921642eSOliver-Rainer Wittmann                 case RES_TXTATR_FIELD:
2751e8d97f7SJens-Heiner Rechtien                 case RES_TXTATR_REFMARK:
2760921642eSOliver-Rainer Wittmann                 case RES_TXTATR_TOXMARK:
277b0157386SKurt Zenker                 case RES_TXTATR_META:
278b0157386SKurt Zenker                 case RES_TXTATR_METAFIELD:
279b0157386SKurt Zenker                     {
280e7540edeSPhilipp Riemer                         // (1998) they are desired as separators and
281e7540edeSPhilipp Riemer                         // belong not any longer to a word.
282e7540edeSPhilipp Riemer                         // they should also be ignored at a
283e7540edeSPhilipp Riemer                         // beginning/end of a sentence if blank. Those are
284e7540edeSPhilipp Riemer                         // simply removed if first. If at the end, we keep the
285e7540edeSPhilipp Riemer                         // replacement and remove afterwards all at a string's
286e7540edeSPhilipp Riemer                         // end (might be normal 0x7f).
28777e67e7cSMichael Stahl                         const bool bEmpty = pNextHint->Which() != RES_TXTATR_FIELD
28877e67e7cSMichael Stahl                             || (static_txtattr_cast<SwTextField const*>(pNextHint)->GetFormatField().GetField()->ExpandField(true, pLayout).isEmpty());
289f51ce842SJohnny_M                         if ( bEmpty && nStart == nCurrent )
2900921642eSOliver-Rainer Wittmann                         {
291f51ce842SJohnny_M                             rArr.push_back( nCurrent );
292d8270636SMiklos Vajna                             if (rEnd.GetAnyIndex() > nCurrent.GetAnyIndex())
293d8270636SMiklos Vajna                             {
294d8270636SMiklos Vajna                                 --rEnd.GetAnyIndex();
295d8270636SMiklos Vajna                             }
29677e67e7cSMichael Stahl                             buf.remove(nCurrent.GetAnyIndex(), 1);
2970921642eSOliver-Rainer Wittmann                         }
2981e8d97f7SJens-Heiner Rechtien                         else
2990921642eSOliver-Rainer Wittmann                         {
3001e8d97f7SJens-Heiner Rechtien                             if ( bEmpty )
301f51ce842SJohnny_M                                 aReplaced.push_back( nCurrent );
30277e67e7cSMichael Stahl                             buf[nCurrent.GetAnyIndex()] = '\x7f';
303419295f1SJustin Luth                         }
3040921642eSOliver-Rainer Wittmann                     }
30584a3db80SJens-Heiner Rechtien                     break;
30616db6243SJustin Luth                 case RES_TXTATR_ANNOTATION:
30716db6243SJustin Luth                     {
30816db6243SJustin Luth                         if( bRemoveCommentAnchors )
30916db6243SJustin Luth                         {
310f51ce842SJohnny_M                             rArr.push_back( nCurrent );
311d8270636SMiklos Vajna                             if (rEnd.GetAnyIndex() > nCurrent.GetAnyIndex())
312d8270636SMiklos Vajna                             {
313d8270636SMiklos Vajna                                 --rEnd.GetAnyIndex();
314d8270636SMiklos Vajna                             }
31577e67e7cSMichael Stahl                             buf.remove( nCurrent.GetAnyIndex(), 1 );
31616db6243SJustin Luth                         }
31716db6243SJustin Luth                     }
31816db6243SJustin Luth                     break;
319419295f1SJustin Luth                 default:
320419295f1SJustin Luth                     OSL_FAIL( "unknown case in lcl_CleanStr" );
321419295f1SJustin Luth                     break;
3221e8d97f7SJens-Heiner Rechtien                 }
32384a3db80SJens-Heiner Rechtien             }
32477e67e7cSMichael Stahl             pNextHint = iter.NextAttr(pNextHintNode);
32584a3db80SJens-Heiner Rechtien         }
3261e8d97f7SJens-Heiner Rechtien 
3271e8d97f7SJens-Heiner Rechtien         if ( bNewSoftHyphen )
32884a3db80SJens-Heiner Rechtien         {
329f51ce842SJohnny_M             rArr.push_back( nCurrent );
330d8270636SMiklos Vajna 
331d8270636SMiklos Vajna             // If the soft hyphen to be removed is past the end of the range we're searching in,
332d8270636SMiklos Vajna             // don't adjust the end.
333d8270636SMiklos Vajna             if (rEnd.GetAnyIndex() > nCurrent.GetAnyIndex())
334d8270636SMiklos Vajna             {
335d8270636SMiklos Vajna                 --rEnd.GetAnyIndex();
336d8270636SMiklos Vajna             }
337d8270636SMiklos Vajna 
33877e67e7cSMichael Stahl             buf.remove(nCurrent.GetAnyIndex(), 1);
33977e67e7cSMichael Stahl             ++nSoftHyphen.GetAnyIndex();
3401e8d97f7SJens-Heiner Rechtien         }
3411e8d97f7SJens-Heiner Rechtien     }
3421e8d97f7SJens-Heiner Rechtien     while ( true );
3431e8d97f7SJens-Heiner Rechtien 
34477e67e7cSMichael Stahl     for (auto i = aReplaced.size(); i; )
3451e8d97f7SJens-Heiner Rechtien     {
34677e67e7cSMichael Stahl         const AmbiguousIndex nTmp = aReplaced[ --i ];
34777e67e7cSMichael Stahl         if (nTmp.GetAnyIndex() == buf.getLength() - 1)
3481e8d97f7SJens-Heiner Rechtien         {
34977e67e7cSMichael Stahl             buf.truncate(nTmp.GetAnyIndex());
350c0ac13caSNigel Hawkins             rArr.push_back( nTmp );
35177e67e7cSMichael Stahl             --rEnd.GetAnyIndex();
35284a3db80SJens-Heiner Rechtien         }
35384a3db80SJens-Heiner Rechtien     }
35484a3db80SJens-Heiner Rechtien 
3557b28b6ccSMichael Stahl     return buf.makeStringAndClear();
35684a3db80SJens-Heiner Rechtien }
35784a3db80SJens-Heiner Rechtien 
35892560b2dSMichael Stahl static bool DoSearch(SwPaM & rSearchPam,
35992560b2dSMichael Stahl     const i18nutil::SearchOptions2& rSearchOpt, utl::TextSearch& rSText,
36092560b2dSMichael Stahl     SwMoveFnCollection const & fnMove,
36192560b2dSMichael Stahl     bool bSrchForward, bool bRegSearch, bool bChkEmptyPara, bool bChkParaEnd,
36277e67e7cSMichael Stahl     AmbiguousIndex & nStart, AmbiguousIndex & nEnd, AmbiguousIndex nTextLen,
36377e67e7cSMichael Stahl     SwTextNode const* pNode, SwTextFrame const* pTextFrame,
36477e67e7cSMichael Stahl     SwRootFrame const* pLayout, SwPaM* pPam);
36592560b2dSMichael Stahl 
36692560b2dSMichael Stahl namespace sw {
36792560b2dSMichael Stahl 
3681159f588SNoel Grandin // @param xSearchItem allocate in parent so we can do so outside the calling loop
36992560b2dSMichael Stahl bool FindTextImpl(SwPaM & rSearchPam,
37092560b2dSMichael Stahl         const i18nutil::SearchOptions2& rSearchOpt, bool bSearchInNotes,
37192560b2dSMichael Stahl         utl::TextSearch& rSText,
37292560b2dSMichael Stahl         SwMoveFnCollection const & fnMove, const SwPaM & rRegion,
3731159f588SNoel Grandin         bool bInReadOnly, SwRootFrame const*const pLayout,
3741159f588SNoel Grandin         std::unique_ptr<SvxSearchItem>& xSearchItem)
37584a3db80SJens-Heiner Rechtien {
37696461715SOlivier Hallot     if( rSearchOpt.searchString.isEmpty() )
3774af491dfSMatteo Casalin         return false;
37884a3db80SJens-Heiner Rechtien 
3798fa80d74SNoel Grandin     std::optional<SwPaM> oPam;
3808fa80d74SNoel Grandin     sw::MakeRegion(fnMove, rRegion, oPam);
381fd405ab4SNoel Grandin     const bool bSrchForward = &fnMove == &fnMoveForward;
382c2509337SNoel Grandin     SwPosition& rPtPos = *oPam->GetPoint();
38384a3db80SJens-Heiner Rechtien 
384e7540edeSPhilipp Riemer     // If bFound is true then the string was found and is between nStart and nEnd
3854af491dfSMatteo Casalin     bool bFound = false;
386e7540edeSPhilipp Riemer     // start position in text or initial position
3876aa35db3SNoel Grandin     bool bFirst = true;
388ab465b90SChristian Lohmaier     SwContentNode * pNode;
38984a3db80SJens-Heiner Rechtien 
390224ecda0SEike Rathke     const bool bRegSearch = SearchAlgorithms2::REGEXP == rSearchOpt.AlgorithmType2;
3914af491dfSMatteo Casalin     const bool bChkEmptyPara = bRegSearch && 2 == rSearchOpt.searchString.getLength() &&
392fe99ee36SStephan Bergmann                         ( rSearchOpt.searchString == "^$" ||
393fe99ee36SStephan Bergmann                           rSearchOpt.searchString == "$^" );
394fe99ee36SStephan Bergmann     const bool bChkParaEnd = bRegSearch && rSearchOpt.searchString == "$";
3954575bd10Sjp 
3961159f588SNoel Grandin     if (!xSearchItem)
3971159f588SNoel Grandin     {
3981159f588SNoel Grandin         xSearchItem.reset(new SvxSearchItem(SID_SEARCH_ITEM)); // this is a very expensive operation (calling configmgr etc.)
3991159f588SNoel Grandin         xSearchItem->SetSearchOptions(rSearchOpt);
4001159f588SNoel Grandin         xSearchItem->SetBackward(!bSrchForward);
4011159f588SNoel Grandin     }
4028d754e86SJan Holesovsky 
4035d15480cSPhilipp Riemer     // LanguageType eLastLang = 0;
4048fa80d74SNoel Grandin     while (nullptr != (pNode = ::GetNode(*oPam, bFirst, fnMove, bInReadOnly, pLayout)))
40584a3db80SJens-Heiner Rechtien     {
406ab465b90SChristian Lohmaier         if( pNode->IsTextNode() )
40784a3db80SJens-Heiner Rechtien         {
408ab465b90SChristian Lohmaier             SwTextNode& rTextNode = *pNode->GetTextNode();
40977e67e7cSMichael Stahl             SwTextFrame const*const pFrame(pLayout
41077e67e7cSMichael Stahl                 ? static_cast<SwTextFrame const*>(rTextNode.getLayoutFrame(pLayout))
41177e67e7cSMichael Stahl                 : nullptr);
41277e67e7cSMichael Stahl             assert(!pLayout || pFrame);
41377e67e7cSMichael Stahl             AmbiguousIndex nTextLen;
41477e67e7cSMichael Stahl             if (pLayout)
41577e67e7cSMichael Stahl             {
41677e67e7cSMichael Stahl                 nTextLen.SetFrameIndex(TextFrameIndex(pFrame->GetText().getLength()));
41777e67e7cSMichael Stahl             }
41884a3db80SJens-Heiner Rechtien             else
41977e67e7cSMichael Stahl             {
42077e67e7cSMichael Stahl                 nTextLen.SetModelIndex(rTextNode.GetText().getLength());
42177e67e7cSMichael Stahl             }
42277e67e7cSMichael Stahl             AmbiguousIndex nEnd;
42377e67e7cSMichael Stahl             if (pLayout
4248fa80d74SNoel Grandin                     ? FrameContainsNode(*pFrame, oPam->GetMark()->GetNodeIndex())
425c2509337SNoel Grandin                     : rPtPos.GetNode() == oPam->GetMark()->GetNode())
42677e67e7cSMichael Stahl             {
42777e67e7cSMichael Stahl                 if (pLayout)
42877e67e7cSMichael Stahl                 {
4298fa80d74SNoel Grandin                     nEnd.SetFrameIndex(pFrame->MapModelToViewPos(*oPam->GetMark()));
43077e67e7cSMichael Stahl                 }
43177e67e7cSMichael Stahl                 else
43277e67e7cSMichael Stahl                 {
4338fa80d74SNoel Grandin                     nEnd.SetModelIndex(oPam->GetMark()->GetContentIndex());
43477e67e7cSMichael Stahl                 }
43577e67e7cSMichael Stahl             }
43677e67e7cSMichael Stahl             else
43777e67e7cSMichael Stahl             {
43877e67e7cSMichael Stahl                 if (bSrchForward)
43977e67e7cSMichael Stahl                 {
44077e67e7cSMichael Stahl                     nEnd = nTextLen;
44177e67e7cSMichael Stahl                 }
44277e67e7cSMichael Stahl                 else
44377e67e7cSMichael Stahl                 {
44477e67e7cSMichael Stahl                     if (pLayout)
44577e67e7cSMichael Stahl                     {
44677e67e7cSMichael Stahl                         nEnd.SetFrameIndex(TextFrameIndex(0));
44777e67e7cSMichael Stahl                     }
44877e67e7cSMichael Stahl                     else
44977e67e7cSMichael Stahl                     {
45077e67e7cSMichael Stahl                         nEnd.SetModelIndex(0);
45177e67e7cSMichael Stahl                     }
45277e67e7cSMichael Stahl                 }
45377e67e7cSMichael Stahl             }
45477e67e7cSMichael Stahl             AmbiguousIndex nStart;
45577e67e7cSMichael Stahl             if (pLayout)
45677e67e7cSMichael Stahl             {
4578fa80d74SNoel Grandin                 nStart.SetFrameIndex(pFrame->MapModelToViewPos(*oPam->GetPoint()));
45877e67e7cSMichael Stahl             }
45977e67e7cSMichael Stahl             else
46077e67e7cSMichael Stahl             {
461c2509337SNoel Grandin                 nStart.SetModelIndex(rPtPos.GetContentIndex());
46277e67e7cSMichael Stahl             }
46384a3db80SJens-Heiner Rechtien 
46419f251c2SJens-Heiner Rechtien             /* #i80135# */
4655d15480cSPhilipp Riemer             // if there are SwPostItFields inside our current node text, we
466cb6d67c2STor Lillqvist             // split the text into separate pieces and search for text inside
4675d15480cSPhilipp Riemer             // the pieces as well as inside the fields
46877e67e7cSMichael Stahl             MaybeMergedIter iter(pLayout ? pFrame : nullptr, pLayout ? nullptr : &rTextNode);
46942fe0555SFrank Meies 
4705d15480cSPhilipp Riemer             // count PostItFields by looping over all fields
47177e67e7cSMichael Stahl             std::vector<std::pair<SwTextAttr const*, AmbiguousIndex>> postits;
47277e67e7cSMichael Stahl             if (bSearchInNotes)
47384a3db80SJens-Heiner Rechtien             {
47419f251c2SJens-Heiner Rechtien                 if (!bSrchForward)
47519f251c2SJens-Heiner Rechtien                 {
476ebeff3f0SMatteo Casalin                     std::swap(nStart, nEnd);
47719f251c2SJens-Heiner Rechtien                 }
4781f4ef5a8Sjp 
47977e67e7cSMichael Stahl                 SwTextNode const* pTemp(nullptr);
48077e67e7cSMichael Stahl                 while (SwTextAttr const*const pTextAttr = iter.NextAttr(pTemp))
48184a3db80SJens-Heiner Rechtien                 {
482ab465b90SChristian Lohmaier                     if ( pTextAttr->Which()==RES_TXTATR_ANNOTATION )
483c87703d6SFrank Meies                     {
48477e67e7cSMichael Stahl                         AmbiguousIndex aPos;
48577e67e7cSMichael Stahl                         aPos.SetModelIndex(pTextAttr->GetStart());
48677e67e7cSMichael Stahl                         if (pLayout)
48777e67e7cSMichael Stahl                         {
48877e67e7cSMichael Stahl                             aPos.SetFrameIndex(pFrame->MapModelToView(pTemp, aPos.GetModelIndex()));
48977e67e7cSMichael Stahl                         }
49077e67e7cSMichael Stahl                         if ((nStart <= aPos) && (aPos <= nEnd))
491c87703d6SFrank Meies                         {
49277e67e7cSMichael Stahl                             postits.emplace_back(pTextAttr, aPos);
493c87703d6SFrank Meies                         }
494c87703d6SFrank Meies                     }
49584a3db80SJens-Heiner Rechtien                 }
49684a3db80SJens-Heiner Rechtien 
49719f251c2SJens-Heiner Rechtien                 if (!bSrchForward)
49842fe0555SFrank Meies                 {
499ebeff3f0SMatteo Casalin                     std::swap(nStart, nEnd);
50019f251c2SJens-Heiner Rechtien                 }
50119f251c2SJens-Heiner Rechtien 
50219f251c2SJens-Heiner Rechtien             }
50342fe0555SFrank Meies 
50455dfe2c1SCaolán McNamara             SwDocShell *const pDocShell = pNode->GetDoc().GetDocShell();
5052fc13fefSCaolán McNamara             SwWrtShell *const pWrtShell = pDocShell ? pDocShell->GetWrtShell() : nullptr;
5062fc13fefSCaolán McNamara             SwPostItMgr *const pPostItMgr = pWrtShell ? pWrtShell->GetPostItMgr() : nullptr;
507513cbeb4SMichael Stahl 
50807355d26SMiklos Vajna             // If there is an active text edit, then search there.
509122b1498SMiklos Vajna             bool bEndedTextEdit = false;
5102fc13fefSCaolán McNamara             SdrView* pSdrView = pWrtShell ? pWrtShell->GetDrawView() : nullptr;
511122b1498SMiklos Vajna             if (pSdrView)
51207355d26SMiklos Vajna             {
513122b1498SMiklos Vajna                 // If the edited object is not anchored to this node, then ignore it.
514122b1498SMiklos Vajna                 SdrObject* pObject = pSdrView->GetTextEditObject();
515122b1498SMiklos Vajna                 if (pObject)
516122b1498SMiklos Vajna                 {
517122b1498SMiklos Vajna                     if (SwFrameFormat* pFrameFormat = FindFrameFormat(pObject))
518122b1498SMiklos Vajna                     {
519dd90710aSNoel Grandin                         const SwNode* pAnchorNode = pFrameFormat->GetAnchor().GetAnchorNode();
520dd90710aSNoel Grandin                         if (!pAnchorNode || (pLayout
521dd90710aSNoel Grandin                                 ? !FrameContainsNode(*pFrame, pAnchorNode->GetIndex())
522dd90710aSNoel Grandin                                 : pAnchorNode->GetIndex() != pNode->GetIndex()))
52301b49802SStephan Bergmann                             pObject = nullptr;
524122b1498SMiklos Vajna                     }
525122b1498SMiklos Vajna                 }
526122b1498SMiklos Vajna 
527122b1498SMiklos Vajna                 if (pObject)
52807355d26SMiklos Vajna                 {
5291159f588SNoel Grandin                     sal_uInt16 nResult = pSdrView->GetTextEditOutlinerView()->StartSearchAndReplace(*xSearchItem);
53007355d26SMiklos Vajna                     if (!nResult)
531995ecbdcSMiklos Vajna                     {
53207355d26SMiklos Vajna                         // If not found, end the text edit.
53307355d26SMiklos Vajna                         pSdrView->SdrEndTextEdit();
5341633fb26SMiklos Vajna                         const Point aPoint(pSdrView->GetAllMarkedRect().TopLeft());
535995ecbdcSMiklos Vajna                         pSdrView->UnmarkAll();
536c81106f5SJan Holesovsky                         pWrtShell->CallSetCursor(&aPoint, true);
5371633fb26SMiklos Vajna                         pWrtShell->Edit();
538122b1498SMiklos Vajna                         bEndedTextEdit = true;
539995ecbdcSMiklos Vajna                     }
54007355d26SMiklos Vajna                     else
54107355d26SMiklos Vajna                     {
54207355d26SMiklos Vajna                         bFound = true;
54307355d26SMiklos Vajna                         break;
54407355d26SMiklos Vajna                     }
54507355d26SMiklos Vajna                 }
54607355d26SMiklos Vajna             }
54707355d26SMiklos Vajna 
54846b52c22SCaolán McNamara             if (comphelper::LibreOfficeKit::isActive())
549bdc1824eSMiklos Vajna             {
55046b52c22SCaolán McNamara                 // Writer and editeng selections are not supported in parallel.
55146b52c22SCaolán McNamara                 SvxSearchItem* pSearchItem = SwView::GetSearchItem();
55246b52c22SCaolán McNamara                 // If we just finished search in shape text, don't attempt to do that again.
55346b52c22SCaolán McNamara                 if (!bEndedTextEdit && !(pSearchItem && pSearchItem->GetCommand() == SvxSearchCmd::FIND_ALL))
554122b1498SMiklos Vajna                 {
55546b52c22SCaolán McNamara                     // If there are any shapes anchored to this node, search there.
55655dfe2c1SCaolán McNamara                     SwPaM aPaM(pNode->GetDoc().GetNodes().GetEndOfContent());
55777e67e7cSMichael Stahl                     if (pLayout)
55877e67e7cSMichael Stahl                     {
55977e67e7cSMichael Stahl                         *aPaM.GetPoint() = pFrame->MapViewToModelPos(nStart.GetFrameIndex());
56077e67e7cSMichael Stahl                     }
56177e67e7cSMichael Stahl                     else
56277e67e7cSMichael Stahl                     {
5639afc3e27SNoel Grandin                         aPaM.GetPoint()->Assign(rTextNode, nStart.GetModelIndex());
56477e67e7cSMichael Stahl                     }
56546b52c22SCaolán McNamara                     aPaM.SetMark();
56677e67e7cSMichael Stahl                     if (pLayout)
56777e67e7cSMichael Stahl                     {
568c2509337SNoel Grandin                         aPaM.GetMark()->Assign( (pFrame->GetMergedPara()
56977e67e7cSMichael Stahl                                 ? *pFrame->GetMergedPara()->pLastNode
57077e67e7cSMichael Stahl                                 : rTextNode)
571c2509337SNoel Grandin                             .GetIndex() + 1 );
57277e67e7cSMichael Stahl                     }
57377e67e7cSMichael Stahl                     else
57477e67e7cSMichael Stahl                     {
575c2509337SNoel Grandin                         aPaM.GetMark()->Assign( rTextNode.GetIndex() + 1 );
57677e67e7cSMichael Stahl                     }
57755dfe2c1SCaolán McNamara                     if (pNode->GetDoc().getIDocumentDrawModelAccess().Search(aPaM, *xSearchItem) && pSdrView)
578122b1498SMiklos Vajna                     {
57946b52c22SCaolán McNamara                         if (SdrObject* pObject = pSdrView->GetTextEditObject())
580122b1498SMiklos Vajna                         {
58146b52c22SCaolán McNamara                             if (SwFrameFormat* pFrameFormat = FindFrameFormat(pObject))
582122b1498SMiklos Vajna                             {
583dd90710aSNoel Grandin                                 const SwNode* pAnchorNode = pFrameFormat->GetAnchor().GetAnchorNode();
584dd90710aSNoel Grandin                                 if (pAnchorNode)
58546b52c22SCaolán McNamara                                 {
58646b52c22SCaolán McNamara                                     // Set search position to the shape's anchor point.
587dd90710aSNoel Grandin                                     rSearchPam.GetPoint()->Assign(*pAnchorNode);
58892560b2dSMichael Stahl                                     rSearchPam.SetMark();
58946b52c22SCaolán McNamara                                     bFound = true;
59046b52c22SCaolán McNamara                                     break;
59146b52c22SCaolán McNamara                                 }
592122b1498SMiklos Vajna                             }
593122b1498SMiklos Vajna                         }
594122b1498SMiklos Vajna                     }
595122b1498SMiklos Vajna                 }
596bdc1824eSMiklos Vajna             }
597bdc1824eSMiklos Vajna 
59819f251c2SJens-Heiner Rechtien             // do we need to finish a note?
599513cbeb4SMichael Stahl             if (pPostItMgr && pPostItMgr->HasActiveSidebarWin())
60019f251c2SJens-Heiner Rechtien             {
60119f251c2SJens-Heiner Rechtien                 if (bSearchInNotes)
60219f251c2SJens-Heiner Rechtien                 {
60377e67e7cSMichael Stahl                     if (!postits.empty())
60442fe0555SFrank Meies                     {
60577e67e7cSMichael Stahl                         if (bSrchForward)
60677e67e7cSMichael Stahl                         {
60777e67e7cSMichael Stahl                             postits.erase(postits.begin());
60877e67e7cSMichael Stahl                         }
60977e67e7cSMichael Stahl                         else
61077e67e7cSMichael Stahl                         {
61177e67e7cSMichael Stahl                             postits.pop_back(); // hope that's the right one?
61277e67e7cSMichael Stahl                         }
61342fe0555SFrank Meies                     }
6141a8915efSAndrea Gelmini                     //search inside, finish and put focus back into the doc
615513cbeb4SMichael Stahl                     if (pPostItMgr->FinishSearchReplace(rSearchOpt,bSrchForward))
61619f251c2SJens-Heiner Rechtien                     {
61719f251c2SJens-Heiner Rechtien                         bFound = true ;
61819f251c2SJens-Heiner Rechtien                         break;
61919f251c2SJens-Heiner Rechtien                     }
62019f251c2SJens-Heiner Rechtien                 }
62119f251c2SJens-Heiner Rechtien                 else
62219f251c2SJens-Heiner Rechtien                 {
62301b49802SStephan Bergmann                     pPostItMgr->SetActiveSidebarWin(nullptr);
62419f251c2SJens-Heiner Rechtien                 }
62519f251c2SJens-Heiner Rechtien             }
62642fe0555SFrank Meies 
62777e67e7cSMichael Stahl             if (!postits.empty())
62819f251c2SJens-Heiner Rechtien             {
62919f251c2SJens-Heiner Rechtien                 // now we have to split
63077e67e7cSMichael Stahl                 AmbiguousIndex nStartInside;
63177e67e7cSMichael Stahl                 AmbiguousIndex nEndInside;
63277e67e7cSMichael Stahl                 sal_Int32 aLoop = bSrchForward ? 0 : postits.size();
63319f251c2SJens-Heiner Rechtien 
634aef7feb3SStephan Bergmann                 while ((0 <= aLoop) && (o3tl::make_unsigned(aLoop) <= postits.size()))
63519f251c2SJens-Heiner Rechtien                 {
63619f251c2SJens-Heiner Rechtien                     if (bSrchForward)
63719f251c2SJens-Heiner Rechtien                     {
63877e67e7cSMichael Stahl                         if (aLoop == 0)
63977e67e7cSMichael Stahl                         {
64077e67e7cSMichael Stahl                             nStartInside = nStart;
64177e67e7cSMichael Stahl                         }
64277e67e7cSMichael Stahl                         else if (pLayout)
64377e67e7cSMichael Stahl                         {
64477e67e7cSMichael Stahl                             nStartInside.SetFrameIndex(postits[aLoop - 1].second.GetFrameIndex() + TextFrameIndex(1));
64577e67e7cSMichael Stahl                         }
64677e67e7cSMichael Stahl                         else
64777e67e7cSMichael Stahl                         {
64877e67e7cSMichael Stahl                             nStartInside.SetModelIndex(postits[aLoop - 1].second.GetModelIndex() + 1);
64977e67e7cSMichael Stahl                         }
65077e67e7cSMichael Stahl                         nEndInside = static_cast<size_t>(aLoop) == postits.size()
65177e67e7cSMichael Stahl                             ? nEnd
65277e67e7cSMichael Stahl                             : postits[aLoop].second;
653ab465b90SChristian Lohmaier                         nTextLen = nEndInside - nStartInside;
65419f251c2SJens-Heiner Rechtien                     }
65519f251c2SJens-Heiner Rechtien                     else
65619f251c2SJens-Heiner Rechtien                     {
65777e67e7cSMichael Stahl                         nStartInside = static_cast<size_t>(aLoop) == postits.size()
65877e67e7cSMichael Stahl                             ? nStart
65977e67e7cSMichael Stahl                             : postits[aLoop].second;
66077e67e7cSMichael Stahl                         if (aLoop == 0)
66177e67e7cSMichael Stahl                         {
66277e67e7cSMichael Stahl                             nEndInside = nEnd;
66377e67e7cSMichael Stahl                         }
66477e67e7cSMichael Stahl                         else if (pLayout)
66577e67e7cSMichael Stahl                         {
66677e67e7cSMichael Stahl                             nEndInside.SetFrameIndex(postits[aLoop - 1].second.GetFrameIndex() + TextFrameIndex(1));
66777e67e7cSMichael Stahl                         }
66877e67e7cSMichael Stahl                         else
66977e67e7cSMichael Stahl                         {
67077e67e7cSMichael Stahl                             nEndInside.SetModelIndex(postits[aLoop - 1].second.GetModelIndex() + 1);
67177e67e7cSMichael Stahl                         }
672ab465b90SChristian Lohmaier                         nTextLen = nStartInside - nEndInside;
67319f251c2SJens-Heiner Rechtien                     }
67419f251c2SJens-Heiner Rechtien                     // search inside the text between a note
67592560b2dSMichael Stahl                     bFound = DoSearch( rSearchPam,
67692560b2dSMichael Stahl                                        rSearchOpt, rSText, fnMove, bSrchForward,
677611eb8edSPhilipp Riemer                                        bRegSearch, bChkEmptyPara, bChkParaEnd,
67877e67e7cSMichael Stahl                                        nStartInside, nEndInside, nTextLen,
67977e67e7cSMichael Stahl                                        pNode->GetTextNode(), pFrame, pLayout,
6808fa80d74SNoel Grandin                                        oPam ? &*oPam : nullptr );
681611eb8edSPhilipp Riemer                     if ( bFound )
68219f251c2SJens-Heiner Rechtien                         break;
68319f251c2SJens-Heiner Rechtien                     else
68419f251c2SJens-Heiner Rechtien                     {
68519f251c2SJens-Heiner Rechtien                         // we should now be right in front of a note, search inside
68677e67e7cSMichael Stahl                         if (bSrchForward
68777e67e7cSMichael Stahl                             ? (static_cast<size_t>(aLoop) != postits.size())
68877e67e7cSMichael Stahl                             : (aLoop != 0))
68919f251c2SJens-Heiner Rechtien                         {
69077e67e7cSMichael Stahl                             const SwTextAttr *const pTextAttr = bSrchForward
69177e67e7cSMichael Stahl                                 ? postits[aLoop].first
69277e67e7cSMichael Stahl                                 : postits[aLoop - 1].first;
69372f368f6SMichael Stahl                             if (pPostItMgr && pPostItMgr->SearchReplace(
694ab465b90SChristian Lohmaier                                     static_txtattr_cast<SwTextField const*>(pTextAttr)->GetFormatField(),rSearchOpt,bSrchForward))
69519f251c2SJens-Heiner Rechtien                             {
69619f251c2SJens-Heiner Rechtien                                 bFound = true ;
69719f251c2SJens-Heiner Rechtien                                 break;
69819f251c2SJens-Heiner Rechtien                             }
69919f251c2SJens-Heiner Rechtien                         }
70019f251c2SJens-Heiner Rechtien                     }
70119f251c2SJens-Heiner Rechtien                     aLoop = bSrchForward ? aLoop+1 : aLoop-1;
70242fe0555SFrank Meies                 }
70319f251c2SJens-Heiner Rechtien             }
70419f251c2SJens-Heiner Rechtien             else
70519f251c2SJens-Heiner Rechtien             {
7065d15480cSPhilipp Riemer                 // if there is no SwPostItField inside or searching inside notes
7075d15480cSPhilipp Riemer                 // is disabled, we search the whole length just like before
70892560b2dSMichael Stahl                 bFound = DoSearch( rSearchPam,
70992560b2dSMichael Stahl                                    rSearchOpt, rSText, fnMove, bSrchForward,
710611eb8edSPhilipp Riemer                                    bRegSearch, bChkEmptyPara, bChkParaEnd,
71177e67e7cSMichael Stahl                                    nStart, nEnd, nTextLen,
71277e67e7cSMichael Stahl                                    pNode->GetTextNode(), pFrame, pLayout,
7138fa80d74SNoel Grandin                                    oPam ? &*oPam : nullptr );
71419f251c2SJens-Heiner Rechtien             }
71519f251c2SJens-Heiner Rechtien             if (bFound)
71619f251c2SJens-Heiner Rechtien                 break;
71719f251c2SJens-Heiner Rechtien         }
71819f251c2SJens-Heiner Rechtien     }
71919f251c2SJens-Heiner Rechtien     return bFound;
72019f251c2SJens-Heiner Rechtien }
72142fe0555SFrank Meies 
72292560b2dSMichael Stahl } // namespace sw
72392560b2dSMichael Stahl 
72492560b2dSMichael Stahl bool DoSearch(SwPaM & rSearchPam,
72592560b2dSMichael Stahl         const i18nutil::SearchOptions2& rSearchOpt, utl::TextSearch& rSText,
726fd405ab4SNoel Grandin                       SwMoveFnCollection const & fnMove, bool bSrchForward, bool bRegSearch,
7274af491dfSMatteo Casalin                       bool bChkEmptyPara, bool bChkParaEnd,
72877e67e7cSMichael Stahl         AmbiguousIndex & nStart, AmbiguousIndex & nEnd, AmbiguousIndex const nTextLen,
72977e67e7cSMichael Stahl         SwTextNode const*const pNode, SwTextFrame const*const pFrame,
73077e67e7cSMichael Stahl         SwRootFrame const*const pLayout, SwPaM* pPam)
73119f251c2SJens-Heiner Rechtien {
73219f251c2SJens-Heiner Rechtien     bool bFound = false;
733a606244dSNoel Grandin     SwPosition& rPtPos = *pPam->GetPoint();
7347b28b6ccSMichael Stahl     OUString sCleanStr;
73577e67e7cSMichael Stahl     std::vector<AmbiguousIndex> aFltArr;
736c70d49c7SNoel Grandin     LanguageType eLastLang = LANGUAGE_SYSTEM;
737e544f449SAndrea Gelmini     // if the search string contains a soft hyphen,
7385d15480cSPhilipp Riemer     // we don't strip them from the text:
73919f251c2SJens-Heiner Rechtien     bool bRemoveSoftHyphens = true;
74016db6243SJustin Luth     // if the search string contains a comment, we don't strip them from the text
74116db6243SJustin Luth     const bool bRemoveCommentAnchors = rSearchOpt.searchString.indexOf( CH_TXTATR_INWORD ) == -1;
7429349f5cdSPhilipp Riemer 
74319f251c2SJens-Heiner Rechtien     if ( bRegSearch )
74419f251c2SJens-Heiner Rechtien     {
745dca5163bSMichael Stahl         if (   -1 != rSearchOpt.searchString.indexOf("\\xAD")
746dca5163bSMichael Stahl             || -1 != rSearchOpt.searchString.indexOf("\\x{00AD}")
747dca5163bSMichael Stahl             || -1 != rSearchOpt.searchString.indexOf("\\u00AD")
748*02c352d7SStéphane Guillou             || -1 != rSearchOpt.searchString.indexOf("\\u00ad")
749dca5163bSMichael Stahl             || -1 != rSearchOpt.searchString.indexOf("\\U000000AD")
750dca5163bSMichael Stahl             || -1 != rSearchOpt.searchString.indexOf("\\N{SOFT HYPHEN}"))
751dca5163bSMichael Stahl         {
75219f251c2SJens-Heiner Rechtien              bRemoveSoftHyphens = false;
753dca5163bSMichael Stahl         }
75419f251c2SJens-Heiner Rechtien     }
75519f251c2SJens-Heiner Rechtien     else
75619f251c2SJens-Heiner Rechtien     {
75719f251c2SJens-Heiner Rechtien         if ( 1 == rSearchOpt.searchString.getLength() &&
75819f251c2SJens-Heiner Rechtien              CHAR_SOFTHYPHEN == rSearchOpt.searchString.toChar() )
75919f251c2SJens-Heiner Rechtien              bRemoveSoftHyphens = false;
76019f251c2SJens-Heiner Rechtien     }
76142fe0555SFrank Meies 
76219f251c2SJens-Heiner Rechtien     if( bSrchForward )
76377e67e7cSMichael Stahl         sCleanStr = lcl_CleanStr(*pNode, pFrame, pLayout, nStart, nEnd,
76416db6243SJustin Luth                         aFltArr, bRemoveSoftHyphens, bRemoveCommentAnchors);
76519f251c2SJens-Heiner Rechtien     else
76677e67e7cSMichael Stahl         sCleanStr = lcl_CleanStr(*pNode, pFrame, pLayout, nEnd, nStart,
76716db6243SJustin Luth                         aFltArr, bRemoveSoftHyphens, bRemoveCommentAnchors);
76842fe0555SFrank Meies 
769c5a9da1eSNoel Grandin     std::unique_ptr<SwScriptIterator> pScriptIter;
7707f33ed41SCarsten Driesner     sal_uInt16 nSearchScript = 0;
7717f33ed41SCarsten Driesner     sal_uInt16 nCurrScript = 0;
77219f251c2SJens-Heiner Rechtien 
7736e531f33SCaolán McNamara     if (SearchAlgorithms2::APPROXIMATE == rSearchOpt.AlgorithmType2)
77419f251c2SJens-Heiner Rechtien     {
77577e67e7cSMichael Stahl         pScriptIter.reset(new SwScriptIterator(sCleanStr, nStart.GetAnyIndex(), bSrchForward));
7760fdd7580SMiklos Vajna         nSearchScript = g_pBreakIt->GetRealScriptOfText( rSearchOpt.searchString, 0 );
77719f251c2SJens-Heiner Rechtien     }
77819f251c2SJens-Heiner Rechtien 
77977e67e7cSMichael Stahl     const AmbiguousIndex nStringEnd = nEnd;
7803bc5cb3cSEike Rathke     bool bZeroMatch = false;    // zero-length match, i.e. only $ anchor as regex
7813bc5cb3cSEike Rathke     while ( ((bSrchForward && nStart < nStringEnd) ||
78277e67e7cSMichael Stahl             (!bSrchForward && nStringEnd < nStart)) && !bZeroMatch )
78319f251c2SJens-Heiner Rechtien     {
7845d15480cSPhilipp Riemer         // SearchAlgorithms_APPROXIMATE works on a per word base so we have to
7855d15480cSPhilipp Riemer         // provide the text searcher with the correct locale, because it uses
7865d15480cSPhilipp Riemer         // the break-iterator
78719f251c2SJens-Heiner Rechtien         if ( pScriptIter )
78819f251c2SJens-Heiner Rechtien         {
78977e67e7cSMichael Stahl             nEnd.GetAnyIndex() = pScriptIter->GetScriptChgPos();
79019f251c2SJens-Heiner Rechtien             nCurrScript = pScriptIter->GetCurrScript();
79119f251c2SJens-Heiner Rechtien             if ( nSearchScript == nCurrScript )
7924575bd10Sjp             {
79377e67e7cSMichael Stahl                 const LanguageType eCurrLang = pLayout
79477e67e7cSMichael Stahl                         ? pFrame->GetLangOfChar(bSrchForward
79577e67e7cSMichael Stahl                                 ? nStart.GetFrameIndex()
79677e67e7cSMichael Stahl                                 : nEnd.GetFrameIndex(),
79777e67e7cSMichael Stahl                             0, true)
79877e67e7cSMichael Stahl                         : pNode->GetLang(bSrchForward
79977e67e7cSMichael Stahl                                 ? nStart.GetModelIndex()
80077e67e7cSMichael Stahl                                 : nEnd.GetModelIndex());
80119f251c2SJens-Heiner Rechtien 
80219f251c2SJens-Heiner Rechtien                 if ( eCurrLang != eLastLang )
8034575bd10Sjp                 {
80419f251c2SJens-Heiner Rechtien                     const lang::Locale aLocale(
8050fdd7580SMiklos Vajna                             g_pBreakIt->GetLocale( eCurrLang ) );
806599f0cbeSEike Rathke                     rSText.SetLocale( utl::TextSearch::UpgradeToSearchOptions2( rSearchOpt), aLocale );
80719f251c2SJens-Heiner Rechtien                     eLastLang = eCurrLang;
8084575bd10Sjp                 }
8094575bd10Sjp             }
81019f251c2SJens-Heiner Rechtien             pScriptIter->Next();
81119f251c2SJens-Heiner Rechtien         }
81277e67e7cSMichael Stahl         AmbiguousIndex nProxyStart = nStart;
81377e67e7cSMichael Stahl         AmbiguousIndex nProxyEnd = nEnd;
81419f251c2SJens-Heiner Rechtien         if( nSearchScript == nCurrScript &&
81577e67e7cSMichael Stahl                 (rSText.*fnMove.fnSearch)( sCleanStr, &nProxyStart.GetAnyIndex(), &nProxyEnd.GetAnyIndex(), nullptr) &&
8166a080679SNorbert Thiebaud                 !(bZeroMatch = (nProxyStart == nProxyEnd)))
81719f251c2SJens-Heiner Rechtien         {
8182e5ec4f5SCaolán McNamara             nStart = nProxyStart;
8192e5ec4f5SCaolán McNamara             nEnd = nProxyEnd;
820e7540edeSPhilipp Riemer             // set section correctly
82192560b2dSMichael Stahl             *rSearchPam.GetPoint() = *pPam->GetPoint();
82292560b2dSMichael Stahl             rSearchPam.SetMark();
82319f251c2SJens-Heiner Rechtien 
824e7540edeSPhilipp Riemer             // adjust start and end
825c0ac13caSNigel Hawkins             if( !aFltArr.empty() )
82619f251c2SJens-Heiner Rechtien             {
827e7540edeSPhilipp Riemer                 // if backward search, switch positions temporarily
82877e67e7cSMichael Stahl                 if (!bSrchForward) { std::swap(nStart, nEnd); }
82919f251c2SJens-Heiner Rechtien 
83077e67e7cSMichael Stahl                 AmbiguousIndex nNew = nStart;
831ebeff3f0SMatteo Casalin                 for (size_t n = 0; n < aFltArr.size() && aFltArr[ n ] <= nStart; ++n )
832ebeff3f0SMatteo Casalin                 {
83377e67e7cSMichael Stahl                     ++nNew.GetAnyIndex();
834ebeff3f0SMatteo Casalin                 }
8359349f5cdSPhilipp Riemer 
83619f251c2SJens-Heiner Rechtien                 nStart = nNew;
83702f80eefSCaolán McNamara                 nNew = nEnd;
838ebeff3f0SMatteo Casalin                 for( size_t n = 0; n < aFltArr.size() && aFltArr[ n ] < nEnd; ++n )
839ebeff3f0SMatteo Casalin                 {
84077e67e7cSMichael Stahl                     ++nNew.GetAnyIndex();
841ebeff3f0SMatteo Casalin                 }
84219f251c2SJens-Heiner Rechtien 
843611eb8edSPhilipp Riemer                 nEnd = nNew;
844e7540edeSPhilipp Riemer                 // if backward search, switch positions temporarily
84502f80eefSCaolán McNamara                 if( !bSrchForward ) { std::swap(nStart, nEnd); }
84619f251c2SJens-Heiner Rechtien             }
84777e67e7cSMichael Stahl             if (pLayout)
84877e67e7cSMichael Stahl             {
84977e67e7cSMichael Stahl                 *rSearchPam.GetMark() = pFrame->MapViewToModelPos(nStart.GetFrameIndex());
85077e67e7cSMichael Stahl                 *rSearchPam.GetPoint() = pFrame->MapViewToModelPos(nEnd.GetFrameIndex());
85177e67e7cSMichael Stahl             }
85277e67e7cSMichael Stahl             else
85377e67e7cSMichael Stahl             {
854a606244dSNoel Grandin                 rSearchPam.GetMark()->SetContent( nStart.GetModelIndex() );
855a606244dSNoel Grandin                 rSearchPam.GetPoint()->SetContent( nEnd.GetModelIndex() );
85677e67e7cSMichael Stahl             }
85719f251c2SJens-Heiner Rechtien 
858e7540edeSPhilipp Riemer             // if backward search, switch point and mark
859e7540edeSPhilipp Riemer             if( !bSrchForward )
86092560b2dSMichael Stahl                 rSearchPam.Exchange();
8614af491dfSMatteo Casalin             bFound = true;
86219f251c2SJens-Heiner Rechtien             break;
86319f251c2SJens-Heiner Rechtien         }
8646a080679SNorbert Thiebaud         else
8656a080679SNorbert Thiebaud         {
866dd9972f5SMatteo Casalin             nEnd = nProxyEnd;
8676a080679SNorbert Thiebaud         }
868611eb8edSPhilipp Riemer         nStart = nEnd;
8695d15480cSPhilipp Riemer     }
87019f251c2SJens-Heiner Rechtien 
871c5a9da1eSNoel Grandin     pScriptIter.reset();
87219f251c2SJens-Heiner Rechtien 
87319f251c2SJens-Heiner Rechtien     if ( bFound )
87419f251c2SJens-Heiner Rechtien         return true;
87577e67e7cSMichael Stahl     else if ((bChkEmptyPara && !nStart.GetAnyIndex() && !nTextLen.GetAnyIndex())
87677e67e7cSMichael Stahl              || bChkParaEnd)
87719f251c2SJens-Heiner Rechtien     {
87892560b2dSMichael Stahl         *rSearchPam.GetPoint() = *pPam->GetPoint();
87977e67e7cSMichael Stahl         if (pLayout)
88077e67e7cSMichael Stahl         {
88177e67e7cSMichael Stahl             *rSearchPam.GetPoint() = pFrame->MapViewToModelPos(
88277e67e7cSMichael Stahl                 bChkParaEnd ? nTextLen.GetFrameIndex() : TextFrameIndex(0));
88377e67e7cSMichael Stahl         }
88477e67e7cSMichael Stahl         else
88577e67e7cSMichael Stahl         {
886a606244dSNoel Grandin             rSearchPam.GetPoint()->SetContent( bChkParaEnd ? nTextLen.GetModelIndex() : 0 );
88777e67e7cSMichael Stahl         }
88892560b2dSMichael Stahl         rSearchPam.SetMark();
88977e67e7cSMichael Stahl         const SwNode *const pSttNd = bSrchForward
890c1c195afSNoel Grandin             ? &rSearchPam.GetPoint()->GetNode() // end of the frame
891a606244dSNoel Grandin             : &rPtPos.GetNode(); // keep the bug as-is for now...
8923bc5cb3cSEike Rathke         /* FIXME: this condition does not work for !bSrchForward backward
8933bc5cb3cSEike Rathke          * search, it probably never did. (pSttNd != &rNdIdx.GetNode())
8943bc5cb3cSEike Rathke          * is never true in this case. */
895a606244dSNoel Grandin         if( (bSrchForward || pSttNd != &rPtPos.GetNode()) &&
89692560b2dSMichael Stahl             rSearchPam.Move(fnMoveForward, GoInContent) &&
897c1c195afSNoel Grandin             (!bSrchForward || pSttNd != &rSearchPam.GetPoint()->GetNode()) &&
898961d42e1SNoel Grandin             SwNodeOffset(1) == abs(rSearchPam.GetPoint()->GetNodeIndex() -
899961d42e1SNoel Grandin                                    rSearchPam.GetMark()->GetNodeIndex()))
90019f251c2SJens-Heiner Rechtien         {
901ec998b5dSPhilipp Riemer             // if backward search, switch point and mark
902ec998b5dSPhilipp Riemer             if( !bSrchForward )
90392560b2dSMichael Stahl                 rSearchPam.Exchange();
90419f251c2SJens-Heiner Rechtien             return true;
90584a3db80SJens-Heiner Rechtien         }
90684a3db80SJens-Heiner Rechtien     }
90784a3db80SJens-Heiner Rechtien     return bFound;
90884a3db80SJens-Heiner Rechtien }
90984a3db80SJens-Heiner Rechtien 
910f853ec31SStephan Bergmann namespace {
911f853ec31SStephan Bergmann 
912e7540edeSPhilipp Riemer /// parameters for search and replace in text
91384a3db80SJens-Heiner Rechtien struct SwFindParaText : public SwFindParas
91484a3db80SJens-Heiner Rechtien {
9154c09fc48SNoel Grandin     const i18nutil::SearchOptions2& m_rSearchOpt;
916bf9c9623SMiklos Vajna     SwCursor& m_rCursor;
91777e67e7cSMichael Stahl     SwRootFrame const* m_pLayout;
918bf9c9623SMiklos Vajna     utl::TextSearch m_aSText;
91917e712ccSNoel Grandin     bool m_bReplace;
92017e712ccSNoel Grandin     bool m_bSearchInNotes;
921bf9c9623SMiklos Vajna 
92277e67e7cSMichael Stahl     SwFindParaText(const i18nutil::SearchOptions2& rOpt, bool bSearchInNotes,
92377e67e7cSMichael Stahl             bool bRepl, SwCursor& rCursor, SwRootFrame const*const pLayout)
92477e67e7cSMichael Stahl         : m_rSearchOpt( rOpt )
92577e67e7cSMichael Stahl         , m_rCursor( rCursor )
92677e67e7cSMichael Stahl         , m_pLayout(pLayout)
92777e67e7cSMichael Stahl         , m_aSText( utl::TextSearch::UpgradeToSearchOptions2(rOpt) )
92877e67e7cSMichael Stahl         , m_bReplace( bRepl )
92977e67e7cSMichael Stahl         , m_bSearchInNotes( bSearchInNotes )
93084a3db80SJens-Heiner Rechtien     {}
9311159f588SNoel Grandin     virtual int DoFind(SwPaM &, SwMoveFnCollection const &, const SwPaM &, bool bInReadOnly, std::unique_ptr<SvxSearchItem>& xSearchItem) override;
932b36963c0SStephan Bergmann     virtual bool IsReplaceMode() const override;
933429fbc98SJens-Heiner Rechtien     virtual ~SwFindParaText();
93484a3db80SJens-Heiner Rechtien };
93584a3db80SJens-Heiner Rechtien 
936f853ec31SStephan Bergmann }
937f853ec31SStephan Bergmann 
938429fbc98SJens-Heiner Rechtien SwFindParaText::~SwFindParaText()
939429fbc98SJens-Heiner Rechtien {
940429fbc98SJens-Heiner Rechtien }
94184a3db80SJens-Heiner Rechtien 
94292560b2dSMichael Stahl int SwFindParaText::DoFind(SwPaM & rCursor, SwMoveFnCollection const & fnMove,
9431159f588SNoel Grandin                           const SwPaM & rRegion, bool bInReadOnly,
9441159f588SNoel Grandin                           std::unique_ptr<SvxSearchItem>& xSearchItem)
94584a3db80SJens-Heiner Rechtien {
946bf9c9623SMiklos Vajna     if( bInReadOnly && m_bReplace )
9476aa35db3SNoel Grandin         bInReadOnly = false;
94884a3db80SJens-Heiner Rechtien 
94977e67e7cSMichael Stahl     const bool bFnd = sw::FindTextImpl(rCursor, m_rSearchOpt, m_bSearchInNotes,
9501159f588SNoel Grandin             m_aSText, fnMove, rRegion, bInReadOnly, m_pLayout, xSearchItem);
95184a3db80SJens-Heiner Rechtien 
952bf9c9623SMiklos Vajna     if( bFnd && m_bReplace ) // replace string
95384a3db80SJens-Heiner Rechtien     {
954e7540edeSPhilipp Riemer         // use replace method in SwDoc
955224ecda0SEike Rathke         const bool bRegExp(SearchAlgorithms2::REGEXP == m_rSearchOpt.AlgorithmType2);
956a606244dSNoel Grandin         const sal_Int32 nSttCnt = rCursor.Start()->GetContentIndex();
957af35e637SJulien Nabet         // add to shell-cursor-ring so that the regions will be moved eventually
95866fc1853SBjoern Michaelsen         SwPaM* pPrev(nullptr);
95984a3db80SJens-Heiner Rechtien         if( bRegExp )
96084a3db80SJens-Heiner Rechtien         {
96192560b2dSMichael Stahl             pPrev = const_cast<SwPaM&>(rRegion).GetPrev();
96292560b2dSMichael Stahl             const_cast<SwPaM&>(rRegion).GetRingContainer().merge( m_rCursor.GetRingContainer() );
96384a3db80SJens-Heiner Rechtien         }
96484a3db80SJens-Heiner Rechtien 
9659ad252b2SStephan Bergmann         std::optional<OUString> xRepl;
96605044640SNoel Grandin         if (bRegExp)
96705044640SNoel Grandin             xRepl = sw::ReplaceBackReferences(m_rSearchOpt, &rCursor, m_pLayout);
9685e81b966SMichael Stahl         bool const bReplaced = sw::ReplaceImpl(rCursor,
96905044640SNoel Grandin                 xRepl ? *xRepl : m_rSearchOpt.replaceString,
97093099409SCaolán McNamara                 bRegExp, m_rCursor.GetDoc(), m_pLayout);
9715e81b966SMichael Stahl 
97292560b2dSMichael Stahl         m_rCursor.SaveTableBoxContent( rCursor.GetPoint() );
97384a3db80SJens-Heiner Rechtien 
97484a3db80SJens-Heiner Rechtien         if( bRegExp )
97584a3db80SJens-Heiner Rechtien         {
976e7540edeSPhilipp Riemer             // and remove region again
97766fc1853SBjoern Michaelsen             SwPaM* p;
97892560b2dSMichael Stahl             SwPaM* pNext(const_cast<SwPaM*>(&rRegion));
97984a3db80SJens-Heiner Rechtien             do {
98084a3db80SJens-Heiner Rechtien                 p = pNext;
98184a3db80SJens-Heiner Rechtien                 pNext = p->GetNext();
98292560b2dSMichael Stahl                 p->MoveTo(const_cast<SwPaM*>(&rRegion));
98384a3db80SJens-Heiner Rechtien             } while( p != pPrev );
98484a3db80SJens-Heiner Rechtien         }
985ddadc1eeSMichael Stahl         if (bRegExp && !bReplaced)
986ddadc1eeSMichael Stahl         {   // fdo#80715 avoid infinite loop if join failed
987fd405ab4SNoel Grandin             bool bRet = ((&fnMoveForward == &fnMove) ? &GoNextPara : &GoPrevPara)
98892560b2dSMichael Stahl                 (rCursor, fnMove);
989ddadc1eeSMichael Stahl             (void) bRet;
990ab465b90SChristian Lohmaier             assert(bRet); // if join failed, next node must be SwTextNode
991ddadc1eeSMichael Stahl         }
992ddadc1eeSMichael Stahl         else
993a606244dSNoel Grandin             rCursor.Start()->SetContent(nSttCnt);
99484a3db80SJens-Heiner Rechtien         return FIND_NO_RING;
99584a3db80SJens-Heiner Rechtien     }
99684a3db80SJens-Heiner Rechtien     return bFnd ? FIND_FOUND : FIND_NOT_FOUND;
99784a3db80SJens-Heiner Rechtien }
99884a3db80SJens-Heiner Rechtien 
999c963d7e6SStephan Bergmann bool SwFindParaText::IsReplaceMode() const
100084a3db80SJens-Heiner Rechtien {
1001bf9c9623SMiklos Vajna     return m_bReplace;
100284a3db80SJens-Heiner Rechtien }
100384a3db80SJens-Heiner Rechtien 
10044d42aeaeSNoel Grandin sal_Int32 SwCursor::Find_Text( const i18nutil::SearchOptions2& rSearchOpt, bool bSearchInNotes,
1005611eb8edSPhilipp Riemer                           SwDocPositions nStart, SwDocPositions nEnd,
100677e67e7cSMichael Stahl                           bool& bCancel, FindRanges eFndRngs, bool bReplace,
100777e67e7cSMichael Stahl                           SwRootFrame const*const pLayout)
100884a3db80SJens-Heiner Rechtien {
1009e7540edeSPhilipp Riemer     // switch off OLE-notifications
101093099409SCaolán McNamara     SwDoc& rDoc = GetDoc();
101193099409SCaolán McNamara     Link<bool,void> aLnk( rDoc.GetOle2Link() );
101293099409SCaolán McNamara     rDoc.SetOle2Link( Link<bool,void>() );
101384a3db80SJens-Heiner Rechtien 
101493099409SCaolán McNamara     bool const bStartUndo = rDoc.GetIDocumentUndoRedo().DoesUndo() && bReplace;
10153145216bSMichael Stahl     if (bStartUndo)
10163145216bSMichael Stahl     {
101793099409SCaolán McNamara         rDoc.GetIDocumentUndoRedo().StartUndo( SwUndoId::REPLACE, nullptr );
10183145216bSMichael Stahl     }
101984a3db80SJens-Heiner Rechtien 
1020f0b5e02bSTakeshi Abe     bool bSearchSel = 0 != (rSearchOpt.searchFlag & SearchFlags::REG_NOT_BEGINOFLINE);
10216dc901b7SThomas Lange     if( bSearchSel )
10220ae2d98dSStephan Bergmann         eFndRngs = static_cast<FindRanges>(eFndRngs | FindRanges::InSel);
102377e67e7cSMichael Stahl     SwFindParaText aSwFindParaText(rSearchOpt, bSearchInNotes, bReplace, *this, pLayout);
10244d42aeaeSNoel Grandin     sal_Int32 nRet = FindAll( aSwFindParaText, nStart, nEnd, eFndRngs, bCancel );
102593099409SCaolán McNamara     rDoc.SetOle2Link( aLnk );
102684a3db80SJens-Heiner Rechtien     if( nRet && bReplace )
102793099409SCaolán McNamara         rDoc.getIDocumentState().SetModified();
102884a3db80SJens-Heiner Rechtien 
10293145216bSMichael Stahl     if (bStartUndo)
10303145216bSMichael Stahl     {
103199a6c72cSMichael Stahl         SwRewriter rewriter(MakeUndoReplaceRewriter(
103299a6c72cSMichael Stahl                 nRet, rSearchOpt.searchString, rSearchOpt.replaceString));
103393099409SCaolán McNamara         rDoc.GetIDocumentUndoRedo().EndUndo( SwUndoId::REPLACE, & rewriter );
10343145216bSMichael Stahl     }
103584a3db80SJens-Heiner Rechtien     return nRet;
103684a3db80SJens-Heiner Rechtien }
103784a3db80SJens-Heiner Rechtien 
10385e81b966SMichael Stahl namespace sw {
10395e81b966SMichael Stahl 
10405e81b966SMichael Stahl bool ReplaceImpl(
10415e81b966SMichael Stahl         SwPaM & rCursor,
10425e81b966SMichael Stahl         OUString const& rReplacement,
10435e81b966SMichael Stahl         bool const bRegExp,
10445e81b966SMichael Stahl         SwDoc & rDoc,
10455e81b966SMichael Stahl         SwRootFrame const*const pLayout)
10465e81b966SMichael Stahl {
10475e81b966SMichael Stahl     bool bReplaced(true);
10485e81b966SMichael Stahl     IDocumentContentOperations & rIDCO(rDoc.getIDocumentContentOperations());
10495e81b966SMichael Stahl #if 0
10505e81b966SMichael Stahl     // FIXME there's some problem with multiple redlines here on Undo
10515e81b966SMichael Stahl     std::vector<std::shared_ptr<SwUnoCursor>> ranges;
10525e81b966SMichael Stahl     if (rDoc.getIDocumentRedlineAccess().IsRedlineOn()
10535e81b966SMichael Stahl         || !pLayout
10545e81b966SMichael Stahl         || !pLayout->IsHideRedlines()
10555e81b966SMichael Stahl         || sw::GetRanges(ranges, rDoc, rCursor))
10565e81b966SMichael Stahl     {
10575e81b966SMichael Stahl         bReplaced = rIDCO.ReplaceRange(rCursor, rReplacement, bRegExp);
10585e81b966SMichael Stahl     }
10595e81b966SMichael Stahl     else
10605e81b966SMichael Stahl     {
10615e81b966SMichael Stahl         assert(!ranges.empty());
10623a02b5f8SNoel Grandin         assert(ranges.front()->GetPoint()->GetNode() == ranges.front()->GetMark()->GetNode());
10635e81b966SMichael Stahl         bReplaced = rIDCO.ReplaceRange(*ranges.front(), rReplacement, bRegExp);
10645e81b966SMichael Stahl         for (auto it = ranges.begin() + 1; it != ranges.end(); ++it)
10655e81b966SMichael Stahl         {
10665e81b966SMichael Stahl             bReplaced &= rIDCO.DeleteAndJoin(**it);
10675e81b966SMichael Stahl         }
10685e81b966SMichael Stahl     }
10695e81b966SMichael Stahl #else
10705e81b966SMichael Stahl     IDocumentRedlineAccess const& rIDRA(rDoc.getIDocumentRedlineAccess());
10715e81b966SMichael Stahl     if (pLayout && pLayout->IsHideRedlines()
10725e81b966SMichael Stahl         && !rIDRA.IsRedlineOn() // otherwise: ReplaceRange will handle it
10735e81b966SMichael Stahl         && (rIDRA.GetRedlineFlags() & RedlineFlags::ShowDelete)) // otherwise: ReplaceRange will DeleteRedline()
10745e81b966SMichael Stahl     {
10755e81b966SMichael Stahl         SwRedlineTable::size_type tmp;
10765e81b966SMichael Stahl         rIDRA.GetRedline(*rCursor.Start(), &tmp);
10775e81b966SMichael Stahl         while (tmp < rIDRA.GetRedlineTable().size())
10785e81b966SMichael Stahl         {
10795e81b966SMichael Stahl             SwRangeRedline const*const pRedline(rIDRA.GetRedlineTable()[tmp]);
10805e81b966SMichael Stahl             if (*rCursor.End() <= *pRedline->Start())
10815e81b966SMichael Stahl             {
10825e81b966SMichael Stahl                 break;
10835e81b966SMichael Stahl             }
10845e81b966SMichael Stahl             if (*pRedline->End() <= *rCursor.Start())
10855e81b966SMichael Stahl             {
10865e81b966SMichael Stahl                 ++tmp;
10875e81b966SMichael Stahl                 continue;
10885e81b966SMichael Stahl             }
108928bff4bdSNoel Grandin             if (pRedline->GetType() == RedlineType::Delete)
10905e81b966SMichael Stahl             {
10915e81b966SMichael Stahl                 assert(*pRedline->Start() != *pRedline->End());
10925e81b966SMichael Stahl                 // search in hidden layout can't overlap redlines
10935e81b966SMichael Stahl                 assert(*rCursor.Start() <= *pRedline->Start() && *pRedline->End() <= *rCursor.End());
10945e81b966SMichael Stahl                 SwPaM pam(*pRedline, nullptr);
10955e81b966SMichael Stahl                 bReplaced &= rIDCO.DeleteAndJoin(pam);
10965e81b966SMichael Stahl             }
10975e81b966SMichael Stahl             else
10985e81b966SMichael Stahl             {
10995e81b966SMichael Stahl                 ++tmp;
11005e81b966SMichael Stahl             }
11015e81b966SMichael Stahl         }
11025e81b966SMichael Stahl     }
11035e81b966SMichael Stahl     bReplaced &= rIDCO.ReplaceRange(rCursor, rReplacement, bRegExp);
11045e81b966SMichael Stahl #endif
11055e81b966SMichael Stahl     return bReplaced;
11065e81b966SMichael Stahl }
11075e81b966SMichael Stahl 
11089ad252b2SStephan Bergmann std::optional<OUString> ReplaceBackReferences(const i18nutil::SearchOptions2& rSearchOpt,
11095e81b966SMichael Stahl         SwPaM *const pPam, SwRootFrame const*const pLayout)
111044aa8f21SVladimir Glazounov {
11119ad252b2SStephan Bergmann     std::optional<OUString> xRet;
111244aa8f21SVladimir Glazounov     if( pPam && pPam->HasMark() &&
1113224ecda0SEike Rathke         SearchAlgorithms2::REGEXP == rSearchOpt.AlgorithmType2 )
111444aa8f21SVladimir Glazounov     {
1115edc5240aSNoel Grandin         SwContentNode const*const pTextNode = pPam->GetPointContentNode();
1116edc5240aSNoel Grandin         SwContentNode const*const pMarkTextNode = pPam->GetMarkContentNode();
111783122addSMichael Stahl         if (!pTextNode || !pTextNode->IsTextNode()
111883122addSMichael Stahl             || !pMarkTextNode || !pMarkTextNode->IsTextNode())
11195e81b966SMichael Stahl         {
112005044640SNoel Grandin             return xRet;
11215e81b966SMichael Stahl         }
11225e81b966SMichael Stahl         SwTextFrame const*const pFrame(pLayout
11235e81b966SMichael Stahl             ? static_cast<SwTextFrame const*>(pTextNode->getLayoutFrame(pLayout))
11245e81b966SMichael Stahl             : nullptr);
11259bb369edSJustin Luth         const bool bParaEnd = rSearchOpt.searchString == "$" || rSearchOpt.searchString == "^$" || rSearchOpt.searchString == "$^";
11265e81b966SMichael Stahl         if (bParaEnd || (pLayout
1127961d42e1SNoel Grandin                 ? sw::FrameContainsNode(*pFrame, pPam->GetMark()->GetNodeIndex())
112883122addSMichael Stahl                 : pTextNode == pMarkTextNode))
112944aa8f21SVladimir Glazounov         {
1130599f0cbeSEike Rathke             utl::TextSearch aSText( utl::TextSearch::UpgradeToSearchOptions2( rSearchOpt) );
1131796aeeb0SMichael Stahl             SearchResult aResult;
1132796aeeb0SMichael Stahl             OUString aReplaceStr( rSearchOpt.replaceString );
1133796aeeb0SMichael Stahl             if (bParaEnd)
11345e81b966SMichael Stahl             {
1135796aeeb0SMichael Stahl                 OUString const aStr("\\n");
1136796aeeb0SMichael Stahl                 aResult.subRegExpressions = 1;
11373d469248SMike Kaganski                 aResult.startOffset = { 0 };
11383d469248SMike Kaganski                 aResult.endOffset = { aStr.getLength() };
1139796aeeb0SMichael Stahl                 aSText.ReplaceBackReferences( aReplaceStr, aStr, aResult );
1140796aeeb0SMichael Stahl                 xRet = aReplaceStr;
11415e81b966SMichael Stahl             }
11425e81b966SMichael Stahl             else
11435e81b966SMichael Stahl             {
1144796aeeb0SMichael Stahl                 AmbiguousIndex nStart;
1145796aeeb0SMichael Stahl                 AmbiguousIndex nEnd;
1146796aeeb0SMichael Stahl                 if (pLayout)
11479bb369edSJustin Luth                 {
1148796aeeb0SMichael Stahl                     nStart.SetFrameIndex(pFrame->MapModelToViewPos(*pPam->Start()));
1149796aeeb0SMichael Stahl                     nEnd.SetFrameIndex(pFrame->MapModelToViewPos(*pPam->End()));
1150796aeeb0SMichael Stahl                 }
1151796aeeb0SMichael Stahl                 else
1152796aeeb0SMichael Stahl                 {
1153af23d1c1SNoel Grandin                     nStart.SetModelIndex(pPam->Start()->GetContentIndex());
1154af23d1c1SNoel Grandin                     nEnd.SetModelIndex(pPam->End()->GetContentIndex());
1155796aeeb0SMichael Stahl                 }
1156657ec7ffSMike Kaganski                 std::vector<AmbiguousIndex> aFltArr;
1157657ec7ffSMike Kaganski                 OUString const aStr = lcl_CleanStr(*pTextNode->GetTextNode(), pFrame, pLayout,
1158657ec7ffSMike Kaganski                                                    nStart, nEnd, aFltArr, false, false);
1159796aeeb0SMichael Stahl                 if (aSText.SearchForward(aStr, &nStart.GetAnyIndex(), &nEnd.GetAnyIndex(), &aResult))
1160796aeeb0SMichael Stahl                 {
1161796aeeb0SMichael Stahl                     aSText.ReplaceBackReferences( aReplaceStr, aStr, aResult );
1162796aeeb0SMichael Stahl                     xRet = aReplaceStr;
11639bb369edSJustin Luth                 }
116444aa8f21SVladimir Glazounov             }
116544aa8f21SVladimir Glazounov         }
116644aa8f21SVladimir Glazounov     }
116705044640SNoel Grandin     return xRet;
116844aa8f21SVladimir Glazounov }
116984a3db80SJens-Heiner Rechtien 
11705e81b966SMichael Stahl } // namespace sw
11715e81b966SMichael Stahl 
117261355e51SSebastian Spaeth /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1173