LibreOffice Module sw (master)  1
findattr.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <com/sun/star/lang/Locale.hpp>
21 #include <com/sun/star/util/SearchAlgorithms2.hpp>
22 #include <com/sun/star/util/SearchFlags.hpp>
24 #include <i18nutil/searchopt.hxx>
25 #include <unotools/syslocale.hxx>
26 #include <hintids.hxx>
27 #include <vcl/svapp.hxx>
28 #include <vcl/settings.hxx>
29 #include <svl/itemiter.hxx>
30 #include <svl/whiter.hxx>
32 #include <editeng/colritem.hxx>
33 #include <editeng/fontitem.hxx>
34 #include <fmtpdsc.hxx>
35 #include <txatbase.hxx>
36 #include <fchrfmt.hxx>
37 #include <charfmt.hxx>
38 #include <doc.hxx>
39 #include <IDocumentUndoRedo.hxx>
40 #include <IDocumentState.hxx>
41 #include <swcrsr.hxx>
42 #include <editsh.hxx>
43 #include <ndtxt.hxx>
44 #include <pamtyp.hxx>
45 #include <txtfrm.hxx>
46 #include <swundo.hxx>
47 #include <boost/optional.hpp>
48 
49 #include <algorithm>
50 #include <memory>
51 
52 using namespace ::com::sun::star;
53 using namespace ::com::sun::star::lang;
54 using namespace ::com::sun::star::util;
55 
56 typedef std::set<SwFormat*> SwpFormats;
57 
58 // Special case for SvxFontItem: only compare the name
59 static bool CmpAttr( const SfxPoolItem& rItem1, const SfxPoolItem& rItem2 )
60 {
61  switch( rItem1.Which() )
62  {
63  case RES_CHRATR_FONT:
64  return static_cast<const SvxFontItem&>(rItem1).GetFamilyName() ==
65  static_cast<const SvxFontItem&>(rItem2).GetFamilyName();
66 
67  case RES_CHRATR_COLOR:
68  return static_cast<const SvxColorItem&>(rItem1).GetValue().IsRGBEqual(
69  static_cast<const SvxColorItem&>(rItem2).GetValue() );
70  case RES_PAGEDESC:
71  bool bNumOffsetEqual = false;
72  ::boost::optional<sal_uInt16> const oNumOffset1 =
73  static_cast<const SwFormatPageDesc&>(rItem1).GetNumOffset();
74  ::boost::optional<sal_uInt16> const oNumOffset2 =
75  static_cast<const SwFormatPageDesc&>(rItem2).GetNumOffset();
76  if (!oNumOffset1 && !oNumOffset2)
77  {
78  bNumOffsetEqual = true;
79  }
80  else if (oNumOffset1 && oNumOffset2)
81  {
82  bNumOffsetEqual = oNumOffset1.get() == oNumOffset2.get();
83  }
84  else
85  {
86  bNumOffsetEqual = false;
87  }
88 
89  if (!bNumOffsetEqual)
90  return false;
91 
92  return static_cast<const SwFormatPageDesc&>(rItem1).GetPageDesc() == static_cast<const SwFormatPageDesc&>(rItem2).GetPageDesc();
93  }
94  return rItem1 == rItem2;
95 }
96 
97 const SwTextAttr* GetFrwrdTextHint( const SwpHints& rHtsArr, size_t& rPos,
98  sal_Int32 nContentPos )
99 {
100  while( rPos < rHtsArr.Count() )
101  {
102  const SwTextAttr *pTextHt = rHtsArr.Get( rPos++ );
103  // the start of an attribute has to be in the section
104  if( pTextHt->GetStart() >= nContentPos )
105  return pTextHt; // valid text attribute
106  }
107  return nullptr; // invalid text attribute
108 }
109 
110 const SwTextAttr* GetBkwrdTextHint( const SwpHints& rHtsArr, size_t& rPos,
111  sal_Int32 nContentPos )
112 {
113  while( rPos > 0 )
114  {
115  const SwTextAttr *pTextHt = rHtsArr.Get( --rPos );
116  // the start of an attribute has to be in the section
117  if( pTextHt->GetStart() < nContentPos )
118  return pTextHt; // valid text attribute
119  }
120  return nullptr; // invalid text attribute
121 }
122 
123 static void lcl_SetAttrPam( SwPaM& rPam, sal_Int32 nStart, const sal_Int32* pEnd,
124  const bool bSaveMark )
125 {
126  sal_Int32 nContentPos;
127  if( bSaveMark )
128  nContentPos = rPam.GetMark()->nContent.GetIndex();
129  else
130  nContentPos = rPam.GetPoint()->nContent.GetIndex();
131  bool bTstEnd = rPam.GetPoint()->nNode == rPam.GetMark()->nNode;
132 
133  SwContentNode* pCNd = rPam.GetContentNode();
134  rPam.GetPoint()->nContent.Assign( pCNd, nStart );
135  rPam.SetMark(); // Point == GetMark
136 
137  // Point points to end of search area or end of attribute
138  if( pEnd )
139  {
140  if( bTstEnd && *pEnd > nContentPos )
141  rPam.GetPoint()->nContent = nContentPos;
142  else
143  rPam.GetPoint()->nContent = *pEnd;
144  }
145 }
146 
147 // TODO: provide documentation
160 static bool lcl_SearchAttr( const SwTextNode& rTextNd, SwPaM& rPam,
161  const SfxPoolItem& rCmpItem,
162  SwMoveFnCollection const & fnMove)
163 {
164  if ( !rTextNd.HasHints() )
165  return false;
166 
167  const SwTextAttr *pTextHt = nullptr;
168  bool bForward = &fnMove == &fnMoveForward;
169  size_t nPos = bForward ? 0 : rTextNd.GetSwpHints().Count();
170  sal_Int32 nContentPos = rPam.GetPoint()->nContent.GetIndex();
171 
172  while( nullptr != ( pTextHt=(*fnMove.fnGetHint)(rTextNd.GetSwpHints(),nPos,nContentPos)))
173  if (pTextHt->Which() == rCmpItem.Which())
174  {
175  lcl_SetAttrPam( rPam, pTextHt->GetStart(), pTextHt->End(), bForward );
176  return true;
177  }
178  return false;
179 }
180 
183 {
184  sal_uInt16 nWhich;
185  sal_Int32 nStt;
186  sal_Int32 nEnd;
187 
188  SwSrchChrAttr(): nWhich(0), nStt(0), nEnd(0) {}
189 
190  SwSrchChrAttr( const SfxPoolItem& rItem,
191  sal_Int32 nStart, sal_Int32 nAnyEnd )
192  : nWhich( rItem.Which() ), nStt( nStart ), nEnd( nAnyEnd )
193  {}
194 };
195 
197 {
199  sal_Int32 m_nNodeStart;
200  sal_Int32 m_nNodeEnd;
201  sal_uInt16 m_nArrStart, m_nArrLen;
202  sal_uInt16 m_nFound, m_nStackCount;
204  bool const m_bNoColls;
205  bool const m_bForward;
206 
207 public:
208  SwAttrCheckArr( const SfxItemSet& rSet, bool bForward, bool bNoCollections );
209  ~SwAttrCheckArr();
210 
211  void SetNewSet( const SwTextNode& rTextNd, const SwPaM& rPam );
212 
214  sal_uInt16 Count() const { return m_aComapeSet.Count(); }
215  bool Found() const { return m_nFound == m_aComapeSet.Count(); }
216  bool CheckStack();
217 
218  sal_Int32 Start() const;
219  sal_Int32 End() const;
220 
221  sal_Int32 GetNdStt() const { return m_nNodeStart; }
222  sal_Int32 GetNdEnd() const { return m_nNodeEnd; }
223 
224  bool SetAttrFwd( const SwTextAttr& rAttr );
225  bool SetAttrBwd( const SwTextAttr& rAttr );
226 };
227 
229  bool bNoCollections )
230  : m_nNodeStart(0)
231  , m_nNodeEnd(0)
232  , m_nFound(0)
233  , m_nStackCount(0)
234  , m_aComapeSet( *rSet.GetPool(), svl::Items<RES_CHRATR_BEGIN, RES_TXTATR_END-1>{} )
235  , m_bNoColls(bNoCollections)
236  , m_bForward(bFwd)
237 {
238  m_aComapeSet.Put( rSet, false );
239 
240  // determine area of Fnd/Stack array (Min/Max)
241  SfxItemIter aIter( m_aComapeSet );
242  m_nArrStart = m_aComapeSet.GetWhichByPos( aIter.GetFirstPos() );
243  m_nArrLen = m_aComapeSet.GetWhichByPos( aIter.GetLastPos() ) - m_nArrStart+1;
244 
245  char* pFndChar = new char[ m_nArrLen * sizeof(SwSrchChrAttr) ];
246  char* pStackChar = new char[ m_nArrLen * sizeof(SwSrchChrAttr) ];
247 
248  m_pFindArr = reinterpret_cast<SwSrchChrAttr*>(pFndChar);
249  m_pStackArr = reinterpret_cast<SwSrchChrAttr*>(pStackChar);
250 }
251 
253 {
254  delete[] reinterpret_cast<char*>(m_pFindArr);
255  delete[] reinterpret_cast<char*>(m_pStackArr);
256 }
257 
258 void SwAttrCheckArr::SetNewSet( const SwTextNode& rTextNd, const SwPaM& rPam )
259 {
260  std::fill(m_pFindArr, m_pFindArr + m_nArrLen, SwSrchChrAttr());
262  m_nFound = 0;
263  m_nStackCount = 0;
264 
265  if( m_bForward )
266  {
268  m_nNodeEnd = rPam.GetPoint()->nNode == rPam.GetMark()->nNode
269  ? rPam.GetMark()->nContent.GetIndex()
270  : rTextNd.GetText().getLength();
271  }
272  else
273  {
274  m_nNodeEnd = rPam.GetPoint()->nContent.GetIndex();
275  m_nNodeStart = rPam.GetPoint()->nNode == rPam.GetMark()->nNode
276  ? rPam.GetMark()->nContent.GetIndex()
277  : 0;
278  }
279 
280  if( m_bNoColls && !rTextNd.HasSwAttrSet() )
281  return ;
282 
283  const SfxItemSet& rSet = rTextNd.GetSwAttrSet();
284 
285  SfxItemIter aIter( m_aComapeSet );
286  const SfxPoolItem* pItem = aIter.GetCurItem();
287  const SfxPoolItem* pFndItem;
288  sal_uInt16 nWhich;
289 
290  while( true )
291  {
292  if( IsInvalidItem( pItem ) )
293  {
294  nWhich = m_aComapeSet.GetWhichByPos( aIter.GetCurPos() );
295  if( RES_TXTATR_END <= nWhich )
296  break; // end of text attributes
297 
298  if( SfxItemState::SET == rSet.GetItemState( nWhich, !m_bNoColls, &pFndItem )
299  && !CmpAttr( *pFndItem, rSet.GetPool()->GetDefaultItem( nWhich ) ))
300  {
301  m_pFindArr[ nWhich - m_nArrStart ] =
302  SwSrchChrAttr( *pFndItem, m_nNodeStart, m_nNodeEnd );
303  m_nFound++;
304  }
305  }
306  else
307  {
308  if( RES_TXTATR_END <= (nWhich = pItem->Which() ))
309  break; // end of text attributes
310 
311  if( CmpAttr( rSet.Get( nWhich, !m_bNoColls ), *pItem ) )
312  {
313  m_pFindArr[ nWhich - m_nArrStart ] =
315  m_nFound++;
316  }
317  }
318 
319  if( aIter.IsAtEnd() )
320  break;
321  pItem = aIter.NextItem();
322  }
323 }
324 
325 static bool
326 lcl_IsAttributeIgnorable(sal_Int32 const nNdStart, sal_Int32 const nNdEnd,
327  SwSrchChrAttr const& rTmp)
328 {
329  // #i115528#: if there is a paragraph attribute, it has been added by the
330  // SwAttrCheckArr ctor, and nFound is 1.
331  // if the paragraph is entirely covered by hints that override the paragraph
332  // attribute, then this function must find an attribute to decrement nFound!
333  // so check for an empty search range, let attributes that start/end there
334  // cover it, and hope for the best...
335  return ((nNdEnd == nNdStart)
336  ? ((rTmp.nEnd < nNdStart) || (nNdEnd < rTmp.nStt))
337  : ((rTmp.nEnd <= nNdStart) || (nNdEnd <= rTmp.nStt)));
338 }
339 
341 {
342  SwSrchChrAttr aTmp( rAttr.GetAttr(), rAttr.GetStart(), rAttr.GetAnyEnd() );
343 
344  // ignore all attributes not in search range
346  {
347  return Found();
348  }
349 
350  const SfxPoolItem* pItem;
351  // here we explicitly also search in character templates
352  sal_uInt16 nWhch = rAttr.Which();
353  std::unique_ptr<SfxWhichIter> pIter;
354  const SfxPoolItem* pTmpItem = nullptr;
355  const SfxItemSet* pSet = nullptr;
356  if( RES_TXTATR_CHARFMT == nWhch || RES_TXTATR_AUTOFMT == nWhch )
357  {
358  if( m_bNoColls && RES_TXTATR_CHARFMT == nWhch )
359  return Found();
360  pTmpItem = nullptr;
361  pSet = CharFormat::GetItemSet( rAttr.GetAttr() );
362  if ( pSet )
363  {
364  pIter.reset(new SfxWhichIter( *pSet ));
365  nWhch = pIter->FirstWhich();
366  while( nWhch &&
367  SfxItemState::SET != pSet->GetItemState( nWhch, true, &pTmpItem ) )
368  nWhch = pIter->NextWhich();
369  if( !nWhch )
370  pTmpItem = nullptr;
371  }
372  }
373  else
374  pTmpItem = &rAttr.GetAttr();
375 
376  while( pTmpItem )
377  {
378  SfxItemState eState = m_aComapeSet.GetItemState( nWhch, false, &pItem );
379  if( SfxItemState::DONTCARE == eState || SfxItemState::SET == eState )
380  {
381  sal_uInt16 n;
382  SwSrchChrAttr* pCmp;
383 
384  // first delete all up to start position that are already invalid
385  SwSrchChrAttr* pArrPtr;
386  if( m_nFound )
387  for( pArrPtr = m_pFindArr, n = 0; n < m_nArrLen;
388  ++n, ++pArrPtr )
389  if( pArrPtr->nWhich && pArrPtr->nEnd <= aTmp.nStt )
390  {
391  pArrPtr->nWhich = 0; // deleted
392  m_nFound--;
393  }
394 
395  // delete all up to start position that are already invalid and
396  // move all "open" ones (= stick out over start position) from stack
397  // into FndSet
398  if( m_nStackCount )
399  for( pArrPtr = m_pStackArr, n=0; n < m_nArrLen; ++n, ++pArrPtr )
400  {
401  if( !pArrPtr->nWhich )
402  continue;
403 
404  if( pArrPtr->nEnd <= aTmp.nStt )
405  {
406  pArrPtr->nWhich = 0; // deleted
407  if( !--m_nStackCount )
408  break;
409  }
410  else if( pArrPtr->nStt <= aTmp.nStt )
411  {
412  if( ( pCmp = &m_pFindArr[ n ])->nWhich )
413  {
414  if( pCmp->nEnd < pArrPtr->nEnd ) // extend
415  pCmp->nEnd = pArrPtr->nEnd;
416  }
417  else
418  {
419  *pCmp = *pArrPtr;
420  m_nFound++;
421  }
422  pArrPtr->nWhich = 0;
423  if( !--m_nStackCount )
424  break;
425  }
426  }
427 
428  bool bContinue = false;
429 
430  if( SfxItemState::DONTCARE == eState )
431  {
432  // Will the attribute become valid?
433  if( !CmpAttr( m_aComapeSet.GetPool()->GetDefaultItem( nWhch ),
434  *pTmpItem ))
435  {
436  // search attribute and extend if needed
437  if( !( pCmp = &m_pFindArr[ nWhch - m_nArrStart ])->nWhich )
438  {
439  *pCmp = aTmp; // not found, insert
440  m_nFound++;
441  }
442  else if( pCmp->nEnd < aTmp.nEnd ) // extend?
443  pCmp->nEnd = aTmp.nEnd;
444 
445  bContinue = true;
446  }
447  }
448  // Will the attribute become valid?
449  else if( CmpAttr( *pItem, *pTmpItem ) )
450  {
451  m_pFindArr[ nWhch - m_nArrStart ] = aTmp;
452  ++m_nFound;
453  bContinue = true;
454  }
455 
456  // then is has to go on the stack
457  if( !bContinue && ( pCmp = &m_pFindArr[ nWhch - m_nArrStart ])->nWhich )
458  {
459  // exists on stack, only if it is even bigger
460  if( pCmp->nEnd > aTmp.nEnd )
461  {
462  OSL_ENSURE( !m_pStackArr[ nWhch - m_nArrStart ].nWhich,
463  "slot on stack is still in use" );
464 
465  if( aTmp.nStt <= pCmp->nStt )
466  pCmp->nStt = aTmp.nEnd;
467  else
468  pCmp->nEnd = aTmp.nStt;
469 
470  m_pStackArr[ nWhch - m_nArrStart ] = *pCmp;
471  m_nStackCount++;
472  }
473  pCmp->nWhich = 0;
474  m_nFound--;
475  }
476  }
477  if( pIter )
478  {
479  assert(pSet && "otherwise no pIter");
480  nWhch = pIter->NextWhich();
481  while( nWhch &&
482  SfxItemState::SET != pSet->GetItemState( nWhch, true, &pTmpItem ) )
483  nWhch = pIter->NextWhich();
484  if( !nWhch )
485  break;
486  }
487  else
488  break;
489  }
490  pIter.reset();
491  return Found();
492 }
493 
495 {
496  SwSrchChrAttr aTmp( rAttr.GetAttr(), rAttr.GetStart(), rAttr.GetAnyEnd() );
497 
498  // ignore all attributes not in search range
500  {
501  return Found();
502  }
503 
504  const SfxPoolItem* pItem;
505  // here we explicitly also search in character templates
506  sal_uInt16 nWhch = rAttr.Which();
507  std::unique_ptr<SfxWhichIter> pIter;
508  const SfxPoolItem* pTmpItem = nullptr;
509  const SfxItemSet* pSet = nullptr;
510  if( RES_TXTATR_CHARFMT == nWhch || RES_TXTATR_AUTOFMT == nWhch )
511  {
512  if( m_bNoColls && RES_TXTATR_CHARFMT == nWhch )
513  return Found();
514 
515  pSet = CharFormat::GetItemSet( rAttr.GetAttr() );
516  if ( pSet )
517  {
518  pIter.reset( new SfxWhichIter( *pSet ) );
519  nWhch = pIter->FirstWhich();
520  while( nWhch &&
521  SfxItemState::SET != pSet->GetItemState( nWhch, true, &pTmpItem ) )
522  nWhch = pIter->NextWhich();
523  if( !nWhch )
524  pTmpItem = nullptr;
525  }
526  }
527  else
528  pTmpItem = &rAttr.GetAttr();
529 
530  while( pTmpItem )
531  {
532  SfxItemState eState = m_aComapeSet.GetItemState( nWhch, false, &pItem );
533  if( SfxItemState::DONTCARE == eState || SfxItemState::SET == eState )
534  {
535  sal_uInt16 n;
536  SwSrchChrAttr* pCmp;
537 
538  // first delete all up to start position that are already invalid
539  SwSrchChrAttr* pArrPtr;
540  if( m_nFound )
541  for( pArrPtr = m_pFindArr, n = 0; n < m_nArrLen; ++n, ++pArrPtr )
542  if( pArrPtr->nWhich && pArrPtr->nStt >= aTmp.nEnd )
543  {
544  pArrPtr->nWhich = 0; // deleted
545  m_nFound--;
546  }
547 
548  // delete all up to start position that are already invalid and
549  // move all "open" ones (= stick out over start position) from stack
550  // into FndSet
551  if( m_nStackCount )
552  for( pArrPtr = m_pStackArr, n = 0; n < m_nArrLen; ++n, ++pArrPtr )
553  {
554  if( !pArrPtr->nWhich )
555  continue;
556 
557  if( pArrPtr->nStt >= aTmp.nEnd )
558  {
559  pArrPtr->nWhich = 0; // deleted
560  if( !--m_nStackCount )
561  break;
562  }
563  else if( pArrPtr->nEnd >= aTmp.nEnd )
564  {
565  if( ( pCmp = &m_pFindArr[ n ])->nWhich )
566  {
567  if( pCmp->nStt > pArrPtr->nStt ) // extend
568  pCmp->nStt = pArrPtr->nStt;
569  }
570  else
571  {
572  *pCmp = *pArrPtr;
573  m_nFound++;
574  }
575  pArrPtr->nWhich = 0;
576  if( !--m_nStackCount )
577  break;
578  }
579  }
580 
581  bool bContinue = false;
582  if( SfxItemState::DONTCARE == eState )
583  {
584  // Will the attribute become valid?
585  if( !CmpAttr( m_aComapeSet.GetPool()->GetDefaultItem( nWhch ),
586  *pTmpItem ) )
587  {
588  // search attribute and extend if needed
589  if( !( pCmp = &m_pFindArr[ nWhch - m_nArrStart ])->nWhich )
590  {
591  *pCmp = aTmp; // not found, insert
592  m_nFound++;
593  }
594  else if( pCmp->nStt > aTmp.nStt ) // extend?
595  pCmp->nStt = aTmp.nStt;
596 
597  bContinue = true;
598  }
599  }
600  // Will the attribute become valid?
601  else if( CmpAttr( *pItem, *pTmpItem ))
602  {
603  m_pFindArr[ nWhch - m_nArrStart ] = aTmp;
604  ++m_nFound;
605  bContinue = true;
606  }
607 
608  // then is has to go on the stack
609  if( !bContinue && ( pCmp = &m_pFindArr[ nWhch - m_nArrStart ])->nWhich )
610  {
611  // exists on stack, only if it is even bigger
612  if( pCmp->nStt < aTmp.nStt )
613  {
614  OSL_ENSURE( !m_pStackArr[ nWhch - m_nArrStart ].nWhich,
615  "slot on stack is still in use" );
616 
617  if( aTmp.nEnd <= pCmp->nEnd )
618  pCmp->nEnd = aTmp.nStt;
619  else
620  pCmp->nStt = aTmp.nEnd;
621 
622  m_pStackArr[ nWhch - m_nArrStart ] = *pCmp;
623  m_nStackCount++;
624  }
625  pCmp->nWhich = 0;
626  m_nFound--;
627  }
628  }
629  if( pIter )
630  {
631  assert(pSet && "otherwise no pIter");
632  nWhch = pIter->NextWhich();
633  while( nWhch &&
634  SfxItemState::SET != pSet->GetItemState( nWhch, true, &pTmpItem ) )
635  nWhch = pIter->NextWhich();
636  if( !nWhch )
637  break;
638  }
639  else
640  break;
641  }
642  pIter.reset();
643  return Found();
644 }
645 
646 sal_Int32 SwAttrCheckArr::Start() const
647 {
648  sal_Int32 nStart = m_nNodeStart;
649  SwSrchChrAttr* pArrPtr = m_pFindArr;
650  for( sal_uInt16 n = 0; n < m_nArrLen; ++n, ++pArrPtr )
651  if( pArrPtr->nWhich && pArrPtr->nStt > nStart )
652  nStart = pArrPtr->nStt;
653 
654  return nStart;
655 }
656 
657 sal_Int32 SwAttrCheckArr::End() const
658 {
659  SwSrchChrAttr* pArrPtr = m_pFindArr;
660  sal_Int32 nEnd = m_nNodeEnd;
661  for( sal_uInt16 n = 0; n < m_nArrLen; ++n, ++pArrPtr )
662  if( pArrPtr->nWhich && pArrPtr->nEnd < nEnd )
663  nEnd = pArrPtr->nEnd;
664 
665  return nEnd;
666 }
667 
669 {
670  if( !m_nStackCount )
671  return false;
672 
673  sal_uInt16 n;
674  const sal_Int32 nSttPos = Start();
675  const sal_Int32 nEndPos = End();
676  SwSrchChrAttr* pArrPtr;
677  for( pArrPtr = m_pStackArr, n = 0; n < m_nArrLen; ++n, ++pArrPtr )
678  {
679  if( !pArrPtr->nWhich )
680  continue;
681 
682  if( m_bForward ? pArrPtr->nEnd <= nSttPos : pArrPtr->nStt >= nEndPos )
683  {
684  pArrPtr->nWhich = 0; // deleted
685  if( !--m_nStackCount )
686  return m_nFound == m_aComapeSet.Count();
687  }
688  else if( m_bForward ? pArrPtr->nStt < nEndPos : pArrPtr->nEnd > nSttPos )
689  {
690  // move all "open" ones (= stick out over start position) into FndSet
691  OSL_ENSURE( !m_pFindArr[ n ].nWhich, "slot in array is already in use" );
692  m_pFindArr[ n ] = *pArrPtr;
693  pArrPtr->nWhich = 0;
694  m_nFound++;
695  if( !--m_nStackCount )
696  return m_nFound == m_aComapeSet.Count();
697  }
698  }
699  return m_nFound == m_aComapeSet.Count();
700 }
701 
702 static bool lcl_SearchForward( const SwTextNode& rTextNd, SwAttrCheckArr& rCmpArr,
703  SwPaM& rPam )
704 {
705  sal_Int32 nEndPos;
706  rCmpArr.SetNewSet( rTextNd, rPam );
707  if( !rTextNd.HasHints() )
708  {
709  if( !rCmpArr.Found() )
710  return false;
711  nEndPos = rCmpArr.GetNdEnd();
712  lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, true );
713  return true;
714  }
715 
716  const SwpHints& rHtArr = rTextNd.GetSwpHints();
717  const SwTextAttr* pAttr;
718  size_t nPos = 0;
719 
720  // if everything is already there then check with which it will be ended
721  if( rCmpArr.Found() )
722  {
723  for( ; nPos < rHtArr.Count(); ++nPos )
724  if( !rCmpArr.SetAttrFwd( *( pAttr = rHtArr.Get( nPos )) ) )
725  {
726  if( rCmpArr.GetNdStt() < pAttr->GetStart() )
727  {
728  // found end
729  auto nTmpStart = pAttr->GetStart();
730  lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(),
731  &nTmpStart, true );
732  return true;
733  }
734  // continue search
735  break;
736  }
737 
738  if( nPos == rHtArr.Count() && rCmpArr.Found() )
739  {
740  // found
741  nEndPos = rCmpArr.GetNdEnd();
742  lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, true );
743  return true;
744  }
745  }
746 
747  sal_Int32 nSttPos;
748  for( ; nPos < rHtArr.Count(); ++nPos )
749  if( rCmpArr.SetAttrFwd( *( pAttr = rHtArr.Get( nPos )) ) )
750  {
751  // Do multiple start at that position? Do also check those:
752  nSttPos = pAttr->GetStart();
753  while( ++nPos < rHtArr.Count() && nSttPos ==
754  ( pAttr = rHtArr.Get( nPos ))->GetStart() &&
755  rCmpArr.SetAttrFwd( *pAttr ) )
756  ;
757 
758  if( !rCmpArr.Found() )
759  continue;
760 
761  // then we have our search area
762  if( (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
763  return false;
764 
765  lcl_SetAttrPam( rPam, nSttPos, &nEndPos, true );
766  return true;
767  }
768 
769  if( !rCmpArr.CheckStack() ||
770  (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
771  return false;
772 
773  lcl_SetAttrPam( rPam, nSttPos, &nEndPos, true );
774  return true;
775 }
776 
777 static bool lcl_SearchBackward( const SwTextNode& rTextNd, SwAttrCheckArr& rCmpArr,
778  SwPaM& rPam )
779 {
780  sal_Int32 nEndPos;
781  rCmpArr.SetNewSet( rTextNd, rPam );
782  if( !rTextNd.HasHints() )
783  {
784  if( !rCmpArr.Found() )
785  return false;
786  nEndPos = rCmpArr.GetNdEnd();
787  lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, false );
788  return true;
789  }
790 
791  const SwpHints& rHtArr = rTextNd.GetSwpHints();
792  const SwTextAttr* pAttr;
793  size_t nPos = rHtArr.Count();
794  sal_Int32 nSttPos;
795 
796  // if everything is already there then check with which it will be ended
797  if( rCmpArr.Found() )
798  {
799  while( nPos )
800  if( !rCmpArr.SetAttrBwd( *( pAttr = rHtArr.GetSortedByEnd( --nPos )) ) )
801  {
802  nSttPos = pAttr->GetAnyEnd();
803  if( nSttPos < rCmpArr.GetNdEnd() )
804  {
805  // found end
806  nEndPos = rCmpArr.GetNdEnd();
807  lcl_SetAttrPam( rPam, nSttPos, &nEndPos, false );
808  return true;
809  }
810 
811  // continue search
812  break;
813  }
814 
815  if( !nPos && rCmpArr.Found() )
816  {
817  // found
818  nEndPos = rCmpArr.GetNdEnd();
819  lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, false );
820  return true;
821  }
822  }
823 
824  while( nPos )
825  if( rCmpArr.SetAttrBwd( *( pAttr = rHtArr.GetSortedByEnd( --nPos )) ) )
826  {
827  // Do multiple start at that position? Do also check those:
828  if( nPos )
829  {
830  nEndPos = pAttr->GetAnyEnd();
831  while( --nPos && nEndPos ==
832  ( pAttr = rHtArr.GetSortedByEnd( nPos ))->GetAnyEnd() &&
833  rCmpArr.SetAttrBwd( *pAttr ) )
834  ;
835  }
836  if( !rCmpArr.Found() )
837  continue;
838 
839  // then we have our search area
840  if( (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
841  return false;
842 
843  lcl_SetAttrPam( rPam, nSttPos, &nEndPos, false );
844  return true;
845  }
846 
847  if( !rCmpArr.CheckStack() ||
848  (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
849  return false;
850 
851  lcl_SetAttrPam( rPam, nSttPos, &nEndPos, false );
852  return true;
853 }
854 
855 static bool lcl_Search( const SwContentNode& rCNd, const SfxItemSet& rCmpSet, bool bNoColls )
856 {
857  // search only hard attribution?
858  if( bNoColls && !rCNd.HasSwAttrSet() )
859  return false;
860 
861  const SfxItemSet& rNdSet = rCNd.GetSwAttrSet();
862  SfxItemIter aIter( rCmpSet );
863  const SfxPoolItem* pItem = aIter.GetCurItem();
864  const SfxPoolItem* pNdItem;
865  sal_uInt16 nWhich;
866 
867  while( true )
868  {
869  if( IsInvalidItem( pItem ))
870  {
871  nWhich = rCmpSet.GetWhichByPos( aIter.GetCurPos() );
872  if( SfxItemState::SET != rNdSet.GetItemState( nWhich, !bNoColls, &pNdItem )
873  || CmpAttr( *pNdItem, rNdSet.GetPool()->GetDefaultItem( nWhich ) ))
874  return false;
875  }
876  else
877  {
878  nWhich = pItem->Which();
879 
880  if( !CmpAttr( rNdSet.Get( nWhich, !bNoColls ), *pItem ))
881  return false;
882  }
883 
884  if( aIter.IsAtEnd() )
885  break;
886  pItem = aIter.NextItem();
887  }
888  return true; // found
889 }
890 
891 namespace sw {
892 
893 bool FindAttrImpl(SwPaM & rSearchPam,
894  const SfxPoolItem& rAttr, SwMoveFnCollection const & fnMove,
895  const SwPaM & rRegion, bool bInReadOnly,
896  SwRootFrame const*const pLayout)
897 {
898  // determine which attribute is searched:
899  const sal_uInt16 nWhich = rAttr.Which();
900  bool bCharAttr = isCHRATR(nWhich) || isTXTATR(nWhich);
901  assert(isTXTATR(nWhich)); // sw_redlinehide: only works for non-formatting hints such as needed in UpdateFields; use FindAttrsImpl for others
902 
903  std::unique_ptr<SwPaM> pPam(sw::MakeRegion(fnMove, rRegion));
904 
905  bool bFound = false;
906  bool bFirst = true;
907  const bool bSrchForward = &fnMove == &fnMoveForward;
908  SwContentNode * pNode;
909 
910  // if at beginning/end then move it out of the node
911  if( bSrchForward
912  ? pPam->GetPoint()->nContent.GetIndex() == pPam->GetContentNode()->Len()
913  : !pPam->GetPoint()->nContent.GetIndex() )
914  {
915  if( !(*fnMove.fnNds)( &pPam->GetPoint()->nNode, false ))
916  {
917  return false;
918  }
919  SwContentNode *pNd = pPam->GetContentNode();
920  pPam->GetPoint()->nContent.Assign( pNd, bSrchForward ? 0 : pNd->Len() );
921  }
922 
923  while (nullptr != (pNode = ::GetNode(*pPam, bFirst, fnMove, bInReadOnly, pLayout)))
924  {
925  if( bCharAttr )
926  {
927  if( !pNode->IsTextNode() ) // CharAttr are only in text nodes
928  continue;
929 
930  SwTextFrame const*const pFrame(pLayout
931  ? static_cast<SwTextFrame const*>(pNode->getLayoutFrame(pLayout))
932  : nullptr);
933  if (pFrame)
934  {
935  SwTextNode const* pAttrNode(nullptr);
936  SwTextAttr const* pAttr(nullptr);
937  if (bSrchForward)
938  {
939  sw::MergedAttrIter iter(*pFrame);
940  do
941  {
942  pAttr = iter.NextAttr(&pAttrNode);
943  }
944  while (pAttr
945  && (pAttrNode->GetIndex() < pPam->GetPoint()->nNode.GetIndex()
946  || (pAttrNode->GetIndex() == pPam->GetPoint()->nNode.GetIndex()
947  && pAttr->GetStart() < pPam->GetPoint()->nContent.GetIndex())
948  || pAttr->Which() != nWhich));
949  }
950  else
951  {
952  sw::MergedAttrIterReverse iter(*pFrame);
953  do
954  {
955  pAttr = iter.PrevAttr(&pAttrNode);
956  }
957  while (pAttr
958  && (pPam->GetPoint()->nNode.GetIndex() < pAttrNode->GetIndex()
959  || (pPam->GetPoint()->nNode.GetIndex() == pAttrNode->GetIndex()
960  && pPam->GetPoint()->nContent.GetIndex() <= pAttr->GetStart())
961  || pAttr->Which() != nWhich));
962  }
963  if (pAttr)
964  {
965  assert(pAttrNode);
966  pPam->GetPoint()->nNode = *pAttrNode;
967  lcl_SetAttrPam(*pPam, pAttr->GetStart(), pAttr->End(), bSrchForward);
968  bFound = true;
969  break;
970  }
971  }
972  else if (!pLayout && pNode->GetTextNode()->HasHints() &&
973  lcl_SearchAttr(*pNode->GetTextNode(), *pPam, rAttr, fnMove))
974  {
975  bFound = true;
976  }
977  if (bFound)
978  {
979  // set to the values of the attribute
980  rSearchPam.SetMark();
981  *rSearchPam.GetPoint() = *pPam->GetPoint();
982  *rSearchPam.GetMark() = *pPam->GetMark();
983  break;
984  }
985  else if (isTXTATR(nWhich))
986  continue;
987  }
988 
989 #if 0
990  // no hard attribution, so check if node was asked for this attr before
991  if( !pNode->HasSwAttrSet() )
992  {
993  SwFormat* pTmpFormat = pNode->GetFormatColl();
994  if( !aFormatArr.insert( pTmpFormat ).second )
995  continue; // collection was requested earlier
996  }
997 
998  if( SfxItemState::SET == pNode->GetSwAttrSet().GetItemState( nWhich,
999  true, &pItem ))
1000  {
1001  // FORWARD: SPoint at the end, GetMark at the beginning of the node
1002  // BACKWARD: SPoint at the beginning, GetMark at the end of the node
1003  // always: incl. start and incl. end
1004  *rSearchPam.GetPoint() = *pPam->GetPoint();
1005  rSearchPam.SetMark();
1006  pNode->MakeEndIndex( &rSearchPam.GetPoint()->nContent );
1007  bFound = true;
1008  break;
1009  }
1010 #endif
1011  }
1012 
1013  // if backward search, switch point and mark
1014  if( bFound && !bSrchForward )
1015  rSearchPam.Exchange();
1016 
1017  return bFound;
1018 }
1019 
1020 } // namespace sw
1021 
1022 typedef bool (*FnSearchAttr)( const SwTextNode&, SwAttrCheckArr&, SwPaM& );
1023 
1024 static bool FindAttrsImpl(SwPaM & rSearchPam,
1025  const SfxItemSet& rSet, bool bNoColls, SwMoveFnCollection const & fnMove,
1026  const SwPaM & rRegion, bool bInReadOnly, bool bMoveFirst,
1027  SwRootFrame const*const pLayout)
1028 {
1029  std::unique_ptr<SwPaM> pPam(sw::MakeRegion(fnMove, rRegion));
1030 
1031  bool bFound = false;
1032  bool bFirst = true;
1033  const bool bSrchForward = &fnMove == &fnMoveForward;
1034  SwContentNode * pNode;
1035  SwpFormats aFormatArr;
1036 
1037  // check which text/char attributes are searched
1038  SwAttrCheckArr aCmpArr( rSet, bSrchForward, bNoColls );
1039  SfxItemSet aOtherSet( rSearchPam.GetDoc()->GetAttrPool(),
1041  aOtherSet.Put( rSet, false ); // got all invalid items
1042 
1043  FnSearchAttr fnSearch = bSrchForward
1044  ? (&::lcl_SearchForward)
1045  : (&::lcl_SearchBackward);
1046 
1047  // if at beginning/end then move it out of the node
1048  if( bMoveFirst &&
1049  ( bSrchForward
1050  ? pPam->GetPoint()->nContent.GetIndex() == pPam->GetContentNode()->Len()
1051  : !pPam->GetPoint()->nContent.GetIndex() ) )
1052  {
1053  if( !(*fnMove.fnNds)( &pPam->GetPoint()->nNode, false ))
1054  {
1055  return false;
1056  }
1057  SwContentNode *pNd = pPam->GetContentNode();
1058  pPam->GetPoint()->nContent.Assign( pNd, bSrchForward ? 0 : pNd->Len() );
1059  }
1060 
1061  while (nullptr != (pNode = ::GetNode(*pPam, bFirst, fnMove, bInReadOnly, pLayout)))
1062  {
1063  SwTextFrame const*const pFrame(pLayout && pNode->IsTextNode()
1064  ? static_cast<SwTextFrame const*>(pNode->getLayoutFrame(pLayout))
1065  : nullptr);
1066  assert(!pLayout || !pNode->IsTextNode() || pFrame);
1067  // sw_redlinehide: it's apparently not possible to find break items
1068  // with the UI, so checking one node is enough
1069  SwContentNode const& rPropsNode(*(pFrame
1070  ? pFrame->GetTextNodeForParaProps()
1071  : pNode));
1072 
1073  if( aCmpArr.Count() )
1074  {
1075  if( !pNode->IsTextNode() ) // CharAttr are only in text nodes
1076  continue;
1077 
1078  if (aOtherSet.Count() &&
1079  !lcl_Search(rPropsNode, aOtherSet, bNoColls))
1080  {
1081  continue;
1082  }
1083  sw::MergedPara const*const pMergedPara(pFrame ? pFrame->GetMergedPara() : nullptr);
1084  if (pMergedPara)
1085  {
1086  SwPosition const& rStart(*pPam->Start());
1087  SwPosition const& rEnd(*pPam->End());
1088  // no extents? fall back to searching index 0 of propsnode
1089  // to find its node items
1090  if (pMergedPara->extents.empty())
1091  {
1092  if (rStart.nNode.GetIndex() <= rPropsNode.GetIndex()
1093  && rPropsNode.GetIndex() <= rEnd.nNode.GetIndex())
1094  {
1095  SwPaM tmp(rPropsNode, 0, rPropsNode, 0);
1096  bFound = (*fnSearch)(*pNode->GetTextNode(), aCmpArr, tmp);
1097  if (bFound)
1098  {
1099  *pPam = tmp;
1100  }
1101  }
1102  }
1103  else
1104  {
1105  // iterate the extents, and intersect with input pPam:
1106  // the found ranges should never include delete redlines
1107  // so that subsequent Replace will not affect them
1108  for (size_t i = 0; i < pMergedPara->extents.size(); ++i)
1109  {
1110  auto const rExtent(pMergedPara->extents[bSrchForward
1111  ? i
1112  : pMergedPara->extents.size() - i - 1]);
1113  if (rExtent.pNode->GetIndex() < rStart.nNode.GetIndex()
1114  || rEnd.nNode.GetIndex() < rExtent.pNode->GetIndex())
1115  {
1116  continue;
1117  }
1118  sal_Int32 const nStart(rExtent.pNode == &rStart.nNode.GetNode()
1119  ? rStart.nContent.GetIndex()
1120  : 0);
1121  if (rExtent.nEnd <= nStart)
1122  {
1123  continue;
1124  }
1125  sal_Int32 const nEnd(rExtent.pNode == &rEnd.nNode.GetNode()
1126  ? rEnd.nContent.GetIndex()
1127  : rExtent.pNode->Len());
1128  if (nEnd < rExtent.nStart
1129  || (nStart != nEnd && nEnd == rExtent.nStart))
1130  {
1131  continue;
1132  }
1133  SwPaM tmp(*rExtent.pNode, std::max(nStart, rExtent.nStart),
1134  *rExtent.pNode, std::min(nEnd, rExtent.nEnd));
1135  tmp.Normalize(bSrchForward);
1136  bFound = (*fnSearch)(*rExtent.pNode, aCmpArr, tmp);
1137  if (bFound)
1138  {
1139  *pPam = tmp;
1140  break;
1141  }
1142  }
1143  }
1144  }
1145  else
1146  {
1147  bFound = (*fnSearch)(*pNode->GetTextNode(), aCmpArr, *pPam);
1148  }
1149  if (bFound)
1150  {
1151  // set to the values of the attribute
1152  rSearchPam.SetMark();
1153  *rSearchPam.GetPoint() = *pPam->GetPoint();
1154  *rSearchPam.GetMark() = *pPam->GetMark();
1155  break;
1156  }
1157  continue; // text attribute
1158  }
1159 
1160  if( !aOtherSet.Count() )
1161  continue;
1162 
1163  // no hard attribution, so check if node was asked for this attr before
1164  // (as an optimisation)
1165  if (!rPropsNode.HasSwAttrSet())
1166  {
1167  SwFormat* pTmpFormat = rPropsNode.GetFormatColl();
1168  if( !aFormatArr.insert( pTmpFormat ).second )
1169  continue; // collection was requested earlier
1170  }
1171 
1172  if (lcl_Search(rPropsNode, aOtherSet, bNoColls))
1173  {
1174  // FORWARD: SPoint at the end, GetMark at the beginning of the node
1175  // BACKWARD: SPoint at the beginning, GetMark at the end of the node
1176  if (pFrame)
1177  {
1178  *rSearchPam.GetPoint() = *pPam->GetPoint();
1179  rSearchPam.SetMark();
1180  *rSearchPam.GetMark() = pFrame->MapViewToModelPos(
1181  TextFrameIndex(bSrchForward ? pFrame->GetText().getLength() : 0));
1182  }
1183  else
1184  {
1185  *rSearchPam.GetPoint() = *pPam->GetPoint();
1186  rSearchPam.SetMark();
1187  if (bSrchForward)
1188  {
1189  pNode->MakeEndIndex( &rSearchPam.GetPoint()->nContent );
1190  }
1191  else
1192  {
1193  pNode->MakeStartIndex( &rSearchPam.GetPoint()->nContent );
1194  }
1195  }
1196  bFound = true;
1197  break;
1198  }
1199  }
1200 
1201  // if backward search, switch point and mark
1202  if( bFound && !bSrchForward )
1203  rSearchPam.Exchange();
1204 
1205  return bFound;
1206 }
1207 
1210 {
1211  bool const m_bNoCollection;
1216  std::unique_ptr<utl::TextSearch> pSText;
1217 
1218  SwFindParaAttr( const SfxItemSet& rSet, bool bNoCollection,
1219  const i18nutil::SearchOptions2* pOpt, const SfxItemSet* pRSet,
1220  SwCursor& rCursor, SwRootFrame const*const pLayout)
1221  : m_bNoCollection(bNoCollection)
1222  , pSet( &rSet )
1223  , pReplSet( pRSet )
1224  , pSearchOpt( pOpt )
1225  , m_rCursor(rCursor)
1226  , m_pLayout(pLayout)
1227  {}
1228 
1229  virtual ~SwFindParaAttr() {}
1230 
1231  virtual int DoFind(SwPaM &, SwMoveFnCollection const &, const SwPaM &, bool bInReadOnly) override;
1232  virtual bool IsReplaceMode() const override;
1233 };
1234 
1235 int SwFindParaAttr::DoFind(SwPaM & rCursor, SwMoveFnCollection const & fnMove,
1236  const SwPaM & rRegion, bool bInReadOnly)
1237 {
1238  // replace string (only if text given and search is not parameterized)?
1239  bool bReplaceText = pSearchOpt && ( !pSearchOpt->replaceString.isEmpty() ||
1240  !pSet->Count() );
1241  bool bReplaceAttr = pReplSet && pReplSet->Count();
1242  bool bMoveFirst = !bReplaceAttr;
1243  if( bInReadOnly && (bReplaceAttr || bReplaceText ))
1244  bInReadOnly = false;
1245 
1246  // We search for attributes, should we search for text as well?
1247  {
1248  SwPaM aRegion( *rRegion.GetMark(), *rRegion.GetPoint() );
1249  SwPaM* pTextRegion = &aRegion;
1250  SwPaM aSrchPam( *rCursor.GetPoint() );
1251 
1252  while( true )
1253  {
1254  if( pSet->Count() ) // any attributes?
1255  {
1256  // first attributes
1257  if (!FindAttrsImpl(aSrchPam, *pSet, m_bNoCollection, fnMove, aRegion, bInReadOnly, bMoveFirst, m_pLayout))
1258  return FIND_NOT_FOUND;
1259  bMoveFirst = true;
1260 
1261  if( !pSearchOpt )
1262  break; // ok, only attributes, so found
1263 
1264  pTextRegion = &aSrchPam;
1265  }
1266  else if( !pSearchOpt )
1267  return FIND_NOT_FOUND;
1268 
1269  // then search in text of it
1270  if( !pSText )
1271  {
1273 
1274  // search in selection
1275  aTmp.searchFlag |= (SearchFlags::REG_NOT_BEGINOFLINE |
1276  SearchFlags::REG_NOT_ENDOFLINE);
1277 
1279 
1280  pSText.reset( new utl::TextSearch( aTmp ) );
1281  }
1282 
1283  // TODO: searching for attributes in Outliner text?!
1284 
1285  // continue search in correct section (pTextRegion)
1286  if (sw::FindTextImpl(aSrchPam, *pSearchOpt, false/*bSearchInNotes*/, *pSText, fnMove, *pTextRegion, bInReadOnly, m_pLayout) &&
1287  *aSrchPam.GetMark() != *aSrchPam.GetPoint() )
1288  break; // found
1289  else if( !pSet->Count() )
1290  return FIND_NOT_FOUND; // only text and nothing found
1291 
1292  *aRegion.GetMark() = *aSrchPam.GetPoint();
1293  }
1294 
1295  *rCursor.GetPoint() = *aSrchPam.GetPoint();
1296  rCursor.SetMark();
1297  *rCursor.GetMark() = *aSrchPam.GetMark();
1298  }
1299 
1300  if( bReplaceText )
1301  {
1302  const bool bRegExp(
1303  SearchAlgorithms2::REGEXP == pSearchOpt->AlgorithmType2);
1304  SwIndex& rSttCntIdx = rCursor.Start()->nContent;
1305  const sal_Int32 nSttCnt = rSttCntIdx.GetIndex();
1306 
1307  // add to shell-cursor-ring so that the regions will be moved eventually
1308  SwPaM* pPrevRing(nullptr);
1309  if( bRegExp )
1310  {
1311  pPrevRing = const_cast<SwPaM &>(rRegion).GetPrev();
1312  const_cast<SwPaM &>(rRegion).GetRingContainer().merge( m_rCursor.GetRingContainer() );
1313  }
1314 
1316  if (bRegExp)
1317  xRepl = sw::ReplaceBackReferences(*pSearchOpt, &rCursor, m_pLayout);
1318  sw::ReplaceImpl(rCursor,
1319  xRepl ? *xRepl : pSearchOpt->replaceString, bRegExp,
1320  *m_rCursor.GetDoc(), m_pLayout);
1321 
1322  m_rCursor.SaveTableBoxContent( rCursor.GetPoint() );
1323 
1324  if( bRegExp )
1325  {
1326  // and remove region again
1327  SwPaM* p;
1328  SwPaM* pNext = const_cast<SwPaM*>(&rRegion);
1329  do {
1330  p = pNext;
1331  pNext = p->GetNext();
1332  p->MoveTo(const_cast<SwPaM*>(&rRegion));
1333  } while( p != pPrevRing );
1334  }
1335  rSttCntIdx = nSttCnt;
1336  }
1337 
1338  if( bReplaceAttr )
1339  {
1340  // is the selection still existent?
1341  // all searched attributes are reset to default if
1342  // they are not in ReplaceSet
1343  if( !pSet->Count() )
1344  {
1347  }
1348  else
1349  {
1350  SfxItemPool* pPool = pReplSet->GetPool();
1351  SfxItemSet aSet( *pPool, pReplSet->GetRanges() );
1352 
1353  SfxItemIter aIter( *pSet );
1354  const SfxPoolItem* pItem = aIter.GetCurItem();
1355  while( true )
1356  {
1357  // reset all that are not set with pool defaults
1358  if( !IsInvalidItem( pItem ) && SfxItemState::SET !=
1359  pReplSet->GetItemState( pItem->Which(), false ))
1360  aSet.Put( pPool->GetDefaultItem( pItem->Which() ));
1361 
1362  if( aIter.IsAtEnd() )
1363  break;
1364  pItem = aIter.NextItem();
1365  }
1366  aSet.Put( *pReplSet );
1368  rCursor, aSet, SetAttrMode::DEFAULT, m_pLayout);
1369  }
1370 
1371  return FIND_NO_RING;
1372  }
1373  else
1374  return FIND_FOUND;
1375 }
1376 
1378 {
1379  return ( pSearchOpt && !pSearchOpt->replaceString.isEmpty() ) ||
1380  ( pReplSet && pReplSet->Count() );
1381 }
1382 
1384 sal_uLong SwCursor::FindAttrs( const SfxItemSet& rSet, bool bNoCollections,
1385  SwDocPositions nStart, SwDocPositions nEnd,
1386  bool& bCancel, FindRanges eFndRngs,
1387  const i18nutil::SearchOptions2* pSearchOpt,
1388  const SfxItemSet* pReplSet,
1389  SwRootFrame const*const pLayout)
1390 {
1391  // switch off OLE-notifications
1392  SwDoc* pDoc = GetDoc();
1393  Link<bool,void> aLnk( pDoc->GetOle2Link() );
1394  pDoc->SetOle2Link( Link<bool,void>() );
1395 
1396  bool bReplace = ( pSearchOpt && ( !pSearchOpt->replaceString.isEmpty() ||
1397  !rSet.Count() ) ) ||
1398  (pReplSet && pReplSet->Count());
1399  bool const bStartUndo = pDoc->GetIDocumentUndoRedo().DoesUndo() && bReplace;
1400  if (bStartUndo)
1401  {
1402  pDoc->GetIDocumentUndoRedo().StartUndo( SwUndoId::REPLACE, nullptr );
1403  }
1404 
1405  SwFindParaAttr aSwFindParaAttr( rSet, bNoCollections, pSearchOpt,
1406  pReplSet, *this, pLayout );
1407 
1408  sal_uLong nRet = FindAll( aSwFindParaAttr, nStart, nEnd, eFndRngs, bCancel );
1409  pDoc->SetOle2Link( aLnk );
1410  if( nRet && bReplace )
1411  pDoc->getIDocumentState().SetModified();
1412 
1413  if (bStartUndo)
1414  {
1415  pDoc->GetIDocumentUndoRedo().EndUndo( SwUndoId::REPLACE, nullptr );
1416  }
1417 
1418  return nRet;
1419 }
1420 
1421 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
SwFindParaAttr(const SfxItemSet &rSet, bool bNoCollection, const i18nutil::SearchOptions2 *pOpt, const SfxItemSet *pRSet, SwCursor &rCursor, SwRootFrame const *const pLayout)
Definition: findattr.cxx:1218
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:149
virtual sal_Int32 Len() const
Definition: node.cxx:1183
sal_uLong GetIndex() const
Definition: node.hxx:282
#define RES_GRFATR_END
Definition: hintids.hxx:258
bool CheckStack()
Definition: findattr.cxx:668
Marks a position in the document model.
Definition: pam.hxx:35
SwContentNode * GetNode(SwPaM &rPam, bool &rbFirst, SwMoveFnCollection const &fnMove, bool const bInReadOnly, SwRootFrame const *const i_pLayout)
This function returns the next node in direction of search.
Definition: pam.cxx:756
sal_Int32 nEnd
Definition: findattr.cxx:186
Pagedescriptor Client of SwPageDesc that is "described" by the attribute.
Definition: fmtpdsc.hxx:35
sal_Int32 Start() const
Definition: findattr.cxx:646
bool isCHRATR(const sal_uInt16 nWhich)
Definition: hintids.hxx:342
const OUString & GetText() const
Definition: ndtxt.hxx:211
std::unique_ptr< SwPaM > MakeRegion(SwMoveFnCollection const &fnMove, const SwPaM &rOrigRg)
make a new region
Definition: pam.cxx:503
std::string GetValue
bool isTXTATR(const sal_uInt16 nWhich)
Definition: hintids.hxx:356
const SwTextAttr * GetBkwrdTextHint(const SwpHints &rHtsArr, size_t &rPos, sal_Int32 nContentPos)
Definition: findattr.cxx:110
sal_uInt16 m_nFound
Definition: findattr.cxx:202
SwNodeIndex nNode
Definition: pam.hxx:37
virtual void InsertItemSet(const SwPaM &rRg, const SfxItemSet &, const SetAttrMode nFlags=SetAttrMode::DEFAULT, SwRootFrame const *pLayout=nullptr)=0
boost::optional< OUString > ReplaceBackReferences(const i18nutil::SearchOptions2 &rSearchOpt, SwPaM *const pPam, SwRootFrame const *const pLayout)
Helperfunction to resolve backward references in regular expressions.
Definition: findtxt.cxx:1091
virtual void SetModified()=0
Must be called manually at changes of format.
sal_uIntPtr sal_uLong
const SwPosition * GetMark() const
Definition: pam.hxx:209
sal_uLong FindAttrs(const SfxItemSet &rSet, bool bNoCollections, SwDocPositions nStart, SwDocPositions nEnde, bool &bCancel, FindRanges, const i18nutil::SearchOptions2 *pSearchOpt, const SfxItemSet *rReplSet=nullptr, SwRootFrame const *const pLayout=nullptr)
search for attributes
Definition: findattr.cxx:1384
sal_Int32 End() const
Definition: findattr.cxx:657
sw::MergedPara * GetMergedPara()
Definition: txtfrm.hxx:438
SwContentFrame * getLayoutFrame(const SwRootFrame *, const SwPosition *pPos=nullptr, std::pair< Point, bool > const *pViewPosAndCalcFrame=nullptr) const
Definition: node.cxx:1150
virtual SwUndoId EndUndo(SwUndoId const eUndoId, SwRewriter const *const pRewriter)=0
Closes undo block.
Definition: doc.hxx:185
void SetOle2Link(const Link< bool, void > &rLink)
Definition: doc.hxx:1316
SwTextAttr const * PrevAttr(SwTextNode const **ppNode=nullptr)
Definition: txtfrm.cxx:234
static bool lcl_IsAttributeIgnorable(sal_Int32 const nNdStart, sal_Int32 const nNdEnd, SwSrchChrAttr const &rTmp)
Definition: findattr.cxx:326
#define RES_CHRATR_FONT
Definition: hintids.hxx:75
bool IsAtEnd() const
SwTextAttr * GetSortedByEnd(size_t nPos) const
Definition: ndhints.hxx:158
Dialog to specify the properties of date form field.
Definition: accfrmobj.cxx:40
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:176
#define RES_TXTATR_CHARFMT
Definition: hintids.hxx:142
sal_uInt16 Which() const
Definition: txatbase.hxx:110
const OUString & GetText() const
Returns the text portion we want to edit (for inline see underneath)
Definition: txtfrm.cxx:1282
sal_Int32 GetAnyEnd() const
end (if available), else start
Definition: txatbase.hxx:153
static bool CmpAttr(const SfxPoolItem &rItem1, const SfxPoolItem &rItem2)
Definition: findattr.cxx:59
IDocumentContentOperations const & getIDocumentContentOperations() const
Definition: doc.cxx:347
#define RES_TXTATR_END
Definition: hintids.hxx:158
The root element of a Writer document layout.
Definition: rootfrm.hxx:79
void MoveTo(value_type *pDestRing)
Removes this item from its current ring container and adds it to another ring container.
Definition: ring.hxx:135
SwRootFrame const * m_pLayout
Definition: findattr.cxx:1215
const css::lang::Locale & getLocale(bool bResolveSystem=true) const
SwTextAttr const * NextAttr(SwTextNode const **ppNode=nullptr)
Definition: txtfrm.cxx:97
void SetNewSet(const SwTextNode &rTextNd, const SwPaM &rPam)
Definition: findattr.cxx:258
sal_Int32 GetNdEnd() const
Definition: findattr.cxx:222
SwDocPositions
Definition: cshtyp.hxx:103
SwContentNode * GetContentNode(bool bPoint=true) const
Definition: pam.hxx:229
SwSrchChrAttr * m_pStackArr
Definition: findattr.cxx:198
bool FindTextImpl(SwPaM &rSearchPam, const i18nutil::SearchOptions2 &rSearchOpt, bool bSearchInNotes, utl::TextSearch &rSText, SwMoveFnCollection const &fnMove, const SwPaM &rRegion, bool bInReadOnly, SwRootFrame const *const pLayout)
Search.
Definition: findtxt.cxx:356
const SfxItemSet * pReplSet
Definition: findattr.cxx:1212
SwIndex nContent
Definition: pam.hxx:38
const i18nutil::SearchOptions2 * pSearchOpt
Definition: findattr.cxx:1213
const Link< bool, void > & GetOle2Link() const
Definition: doc.hxx:1317
GetHint fnGetHint
Definition: pamtyp.hxx:76
FindRanges
Definition: cshtyp.hxx:90
sal_Int32 GetStart() const
Definition: txatbase.hxx:82
sal_Int32 nStt
Definition: findattr.cxx:185
SfxItemSet m_aComapeSet
Definition: findattr.cxx:203
Describes parts of multiple text nodes, which will form a text frame, even when redlines are hidden a...
Definition: txtfrm.hxx:954
#define RES_PARATR_BEGIN
Definition: hintids.hxx:160
virtual bool DoesUndo() const =0
Is Undo enabled?
SwPaM * GetNext()
Definition: pam.hxx:264
SwCursor & m_rCursor
Definition: findattr.cxx:1214
void Normalize(bool bPointFirst=true)
Normalizes PaM, i.e.
Definition: pam.cxx:520
bool FindAttrImpl(SwPaM &rSearchPam, const SfxPoolItem &rAttr, SwMoveFnCollection const &fnMove, const SwPaM &rRegion, bool bInReadOnly, SwRootFrame const *const pLayout)
Definition: findattr.cxx:893
css::lang::Locale Locale
Base class for various Writer styles.
Definition: format.hxx:43
#define RES_CHRATR_COLOR
Definition: hintids.hxx:71
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:136
SwTextNode const * GetTextNodeForParaProps() const
Definition: txtfrm.cxx:1292
size_t Count() const
Definition: ndhints.hxx:142
virtual SwUndoId StartUndo(SwUndoId const eUndoId, SwRewriter const *const pRewriter)=0
Opens undo block.
sal_uLong FindAll(SwFindParas &, SwDocPositions, SwDocPositions, FindRanges, bool &bCancel)
Definition: swcrsr.cxx:925
SwTextAttr * Get(size_t nPos) const
Definition: ndhints.hxx:144
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
virtual ~SwFindParaAttr()
Definition: findattr.cxx:1229
const SwPosition * GetPoint() const
Definition: pam.hxx:207
const SwTextAttr * GetFrwrdTextHint(const SwpHints &rHtsArr, size_t &rPos, sal_Int32 nContentPos)
Definition: findattr.cxx:97
SwIndex & Assign(SwIndexReg *, sal_Int32)
Definition: index.cxx:198
static bool lcl_Search(const SwContentNode &rCNd, const SfxItemSet &rCmpSet, bool bNoColls)
Definition: findattr.cxx:855
bool const m_bNoColls
Definition: findattr.cxx:204
void Exchange()
Definition: pam.cxx:471
int i
SwContentNode * GetContentNode()
Definition: node.hxx:615
sal_uInt16 Count() const
void MakeStartIndex(SwIndex *pIdx)
Definition: node.hxx:391
const SfxPoolItem * NextItem()
bool SetAttrFwd(const SwTextAttr &rAttr)
Definition: findattr.cxx:340
SwDoc * GetDoc() const
Definition: pam.hxx:243
Marks a character position inside a document model node.
Definition: index.hxx:37
const SfxItemSet * GetItemSet(const SfxPoolItem &rAttr)
Returns the item set associated with an character/inet/auto style.
Definition: atrstck.cxx:133
#define RES_CHRATR_BEGIN
Definition: hintids.hxx:68
parameters for search for attributes
Definition: findattr.cxx:1209
IDocumentState const & getIDocumentState() const
Definition: doc.cxx:426
SwAttrCheckArr(const SfxItemSet &rSet, bool bForward, bool bNoCollections)
Definition: findattr.cxx:228
sal_uInt16 m_nArrLen
Definition: findattr.cxx:201
SwpHints & GetSwpHints()
getters for SwpHints
Definition: ndtxt.hxx:809
bool HasSwAttrSet() const
Definition: node.hxx:444
ring_container GetRingContainer()
Definition: ring.hxx:240
sal_uInt16 GetWhichByPos(sal_uInt16 nPos) const
bool ReplaceImpl(SwPaM &rCursor, OUString const &rReplacement, bool const bRegExp, SwDoc &rDoc, SwRootFrame const *const pLayout)
Definition: findtxt.cxx:1023
const SfxPoolItem & GetDefaultItem(sal_uInt16 nWhich) const
SfxItemPool * GetPool() const
const int FIND_NO_RING
Definition: swcrsr.hxx:36
const SwPosition * Start() const
Definition: pam.hxx:212
SwSrchChrAttr * m_pFindArr
Definition: findattr.cxx:198
sal_uInt16 GetCurPos() const
sal_Int32 GetNdStt() const
Definition: findattr.cxx:221
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
sal_Int32 m_nNodeEnd
Definition: findattr.cxx:200
bool SetAttrBwd(const SwTextAttr &rAttr)
Definition: findattr.cxx:494
#define RES_TXTATR_AUTOFMT
Definition: hintids.hxx:140
An SwTextAttr container, stores all directly formatted text portions for a text node.
Definition: ndhints.hxx:67
SfxItemState
const SfxPoolItem & Get(sal_uInt16 nWhich, bool bSrchInParent=true) const
sal_uInt16 m_nStackCount
Definition: findattr.cxx:202
SwMoveFnCollection const & fnMoveForward
SwPam::Move()/Find() default argument.
Definition: paminit.cxx:59
const int FIND_FOUND
Definition: swcrsr.hxx:35
bool Found() const
Definition: findattr.cxx:215
sal_Int32 GetIndex() const
Definition: index.hxx:95
bool const m_bForward
Definition: findattr.cxx:205
const SfxItemSet * pSet
Definition: findattr.cxx:1212
const sal_Int32 * End() const
Definition: txatbase.hxx:148
sal_uInt16 nWhich
Definition: findattr.cxx:184
virtual bool IsReplaceMode() const override
Definition: findattr.cxx:1377
static bool FindAttrsImpl(SwPaM &rSearchPam, const SfxItemSet &rSet, bool bNoColls, SwMoveFnCollection const &fnMove, const SwPaM &rRegion, bool bInReadOnly, bool bMoveFirst, SwRootFrame const *const pLayout)
Definition: findattr.cxx:1024
const SwAttrSet & GetSwAttrSet() const
Does node has already its own auto-attributes? Access to SwAttrSet.
Definition: node.hxx:723
sal_uInt16 m_nArrStart
Definition: findattr.cxx:201
const SfxPoolItem & GetAttr() const
Definition: txatbase.hxx:159
const sal_uInt16 * GetRanges() const
const LanguageTag & GetLanguageTag() const
SwFormatColl * GetFormatColl() const
Definition: node.hxx:447
const int FIND_NOT_FOUND
Definition: swcrsr.hxx:34
std::unique_ptr< utl::TextSearch > pSText
Definition: findattr.cxx:1216
virtual void SetMark()
Unless this is called, the getter method of Mark will return Point.
Definition: pam.cxx:457
bool IsInvalidItem(const SfxPoolItem *pItem)
#define RES_PAGEDESC
Definition: hintids.hxx:198
virtual int DoFind(SwPaM &, SwMoveFnCollection const &, const SwPaM &, bool bInReadOnly) override
Definition: findattr.cxx:1235
SwSrchChrAttr(const SfxPoolItem &rItem, sal_Int32 nStart, sal_Int32 nAnyEnd)
Definition: findattr.cxx:190
sal_Int32 nPos
o3tl::strong_int< sal_Int32, struct Tag_TextFrameIndex > TextFrameIndex
Denotes a character index in a text frame at a layout level, after extent mapping from a text node at...
bool IsTextNode() const
Definition: node.hxx:636
SwPosition MapViewToModelPos(TextFrameIndex nIndex) const
Definition: txtfrm.cxx:1237
bool const m_bNoCollection
Definition: findattr.cxx:1211
virtual void SaveTableBoxContent(const SwPosition *pPos)
Definition: swcrsr.cxx:719
bool(* FnSearchAttr)(const SwTextNode &, SwAttrCheckArr &, SwPaM &)
Definition: findattr.cxx:1022
sal_uInt16 Count() const
how many attributes are there in total?
Definition: findattr.cxx:214
static void lcl_SetAttrPam(SwPaM &rPam, sal_Int32 nStart, const sal_Int32 *pEnd, const bool bSaveMark)
Definition: findattr.cxx:123
void MakeEndIndex(SwIndex *pIdx)
Definition: node.hxx:392
sal_uInt16 Which() const
static bool lcl_SearchForward(const SwTextNode &rTextNd, SwAttrCheckArr &rCmpArr, SwPaM &rPam)
Definition: findattr.cxx:702
std::set< SwFormat * > SwpFormats
Definition: findattr.cxx:56
const SfxPoolItem * GetCurItem() const
const SwAttrPool & GetAttrPool() const
Definition: doc.hxx:1307
static bool lcl_SearchAttr(const SwTextNode &rTextNd, SwPaM &rPam, const SfxPoolItem &rCmpItem, SwMoveFnCollection const &fnMove)
search for a text attribute
Definition: findattr.cxx:160
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:843
bool HasHints() const
Definition: ndtxt.hxx:221
sal_Int32 m_nNodeStart
Definition: findattr.cxx:199
static bool lcl_SearchBackward(const SwTextNode &rTextNd, SwAttrCheckArr &rCmpArr, SwPaM &rPam)
Definition: findattr.cxx:777
search for multiple text attributes
Definition: findattr.cxx:182