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
