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