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  lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(),
730  &pAttr->GetStart(), true );
731  return true;
732  }
733  // continue search
734  break;
735  }
736 
737  if( nPos == rHtArr.Count() && rCmpArr.Found() )
738  {
739  // found
740  nEndPos = rCmpArr.GetNdEnd();
741  lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, true );
742  return true;
743  }
744  }
745 
746  sal_Int32 nSttPos;
747  for( ; nPos < rHtArr.Count(); ++nPos )
748  if( rCmpArr.SetAttrFwd( *( pAttr = rHtArr.Get( nPos )) ) )
749  {
750  // Do multiple start at that position? Do also check those:
751  nSttPos = pAttr->GetStart();
752  while( ++nPos < rHtArr.Count() && nSttPos ==
753  ( pAttr = rHtArr.Get( nPos ))->GetStart() &&
754  rCmpArr.SetAttrFwd( *pAttr ) )
755  ;
756 
757  if( !rCmpArr.Found() )
758  continue;
759 
760  // then we have our search area
761  if( (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
762  return false;
763 
764  lcl_SetAttrPam( rPam, nSttPos, &nEndPos, true );
765  return true;
766  }
767 
768  if( !rCmpArr.CheckStack() ||
769  (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
770  return false;
771 
772  lcl_SetAttrPam( rPam, nSttPos, &nEndPos, true );
773  return true;
774 }
775 
776 static bool lcl_SearchBackward( const SwTextNode& rTextNd, SwAttrCheckArr& rCmpArr,
777  SwPaM& rPam )
778 {
779  sal_Int32 nEndPos;
780  rCmpArr.SetNewSet( rTextNd, rPam );
781  if( !rTextNd.HasHints() )
782  {
783  if( !rCmpArr.Found() )
784  return false;
785  nEndPos = rCmpArr.GetNdEnd();
786  lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, false );
787  return true;
788  }
789 
790  const SwpHints& rHtArr = rTextNd.GetSwpHints();
791  const SwTextAttr* pAttr;
792  size_t nPos = rHtArr.Count();
793  sal_Int32 nSttPos;
794 
795  // if everything is already there then check with which it will be ended
796  if( rCmpArr.Found() )
797  {
798  while( nPos )
799  if( !rCmpArr.SetAttrBwd( *( pAttr = rHtArr.GetSortedByEnd( --nPos )) ) )
800  {
801  nSttPos = *pAttr->GetAnyEnd();
802  if( nSttPos < rCmpArr.GetNdEnd() )
803  {
804  // found end
805  nEndPos = rCmpArr.GetNdEnd();
806  lcl_SetAttrPam( rPam, nSttPos, &nEndPos, false );
807  return true;
808  }
809 
810  // continue search
811  break;
812  }
813 
814  if( !nPos && rCmpArr.Found() )
815  {
816  // found
817  nEndPos = rCmpArr.GetNdEnd();
818  lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, false );
819  return true;
820  }
821  }
822 
823  while( nPos )
824  if( rCmpArr.SetAttrBwd( *( pAttr = rHtArr.GetSortedByEnd( --nPos )) ) )
825  {
826  // Do multiple start at that position? Do also check those:
827  if( nPos )
828  {
829  nEndPos = *pAttr->GetAnyEnd();
830  while( --nPos && nEndPos ==
831  *( pAttr = rHtArr.GetSortedByEnd( nPos ))->GetAnyEnd() &&
832  rCmpArr.SetAttrBwd( *pAttr ) )
833  ;
834  }
835  if( !rCmpArr.Found() )
836  continue;
837 
838  // then we have our search area
839  if( (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
840  return false;
841 
842  lcl_SetAttrPam( rPam, nSttPos, &nEndPos, false );
843  return true;
844  }
845 
846  if( !rCmpArr.CheckStack() ||
847  (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
848  return false;
849 
850  lcl_SetAttrPam( rPam, nSttPos, &nEndPos, false );
851  return true;
852 }
853 
854 static bool lcl_Search( const SwContentNode& rCNd, const SfxItemSet& rCmpSet, bool bNoColls )
855 {
856  // search only hard attribution?
857  if( bNoColls && !rCNd.HasSwAttrSet() )
858  return false;
859 
860  const SfxItemSet& rNdSet = rCNd.GetSwAttrSet();
861  SfxItemIter aIter( rCmpSet );
862  const SfxPoolItem* pItem = aIter.GetCurItem();
863  const SfxPoolItem* pNdItem;
864  sal_uInt16 nWhich;
865 
866  while( true )
867  {
868  if( IsInvalidItem( pItem ))
869  {
870  nWhich = rCmpSet.GetWhichByPos( aIter.GetCurPos() );
871  if( SfxItemState::SET != rNdSet.GetItemState( nWhich, !bNoColls, &pNdItem )
872  || CmpAttr( *pNdItem, rNdSet.GetPool()->GetDefaultItem( nWhich ) ))
873  return false;
874  }
875  else
876  {
877  nWhich = pItem->Which();
878 
879  if( !CmpAttr( rNdSet.Get( nWhich, !bNoColls ), *pItem ))
880  return false;
881  }
882 
883  if( aIter.IsAtEnd() )
884  break;
885  pItem = aIter.NextItem();
886  }
887  return true; // found
888 }
889 
890 namespace sw {
891 
892 bool FindAttrImpl(SwPaM & rSearchPam,
893  const SfxPoolItem& rAttr, SwMoveFnCollection const & fnMove,
894  const SwPaM & rRegion, bool bInReadOnly,
895  SwRootFrame const*const pLayout)
896 {
897  // determine which attribute is searched:
898  const sal_uInt16 nWhich = rAttr.Which();
899  bool bCharAttr = isCHRATR(nWhich) || isTXTATR(nWhich);
900  assert(isTXTATR(nWhich)); // sw_redlinehide: only works for non-formatting hints such as needed in UpdateFields; use FindAttrsImpl for others
901 
902  std::unique_ptr<SwPaM> pPam(sw::MakeRegion(fnMove, rRegion));
903 
904  bool bFound = false;
905  bool bFirst = true;
906  const bool bSrchForward = &fnMove == &fnMoveForward;
907  SwContentNode * pNode;
908 
909  // if at beginning/end then move it out of the node
910  if( bSrchForward
911  ? pPam->GetPoint()->nContent.GetIndex() == pPam->GetContentNode()->Len()
912  : !pPam->GetPoint()->nContent.GetIndex() )
913  {
914  if( !(*fnMove.fnNds)( &pPam->GetPoint()->nNode, false ))
915  {
916  return false;
917  }
918  SwContentNode *pNd = pPam->GetContentNode();
919  pPam->GetPoint()->nContent.Assign( pNd, bSrchForward ? 0 : pNd->Len() );
920  }
921 
922  while (nullptr != (pNode = ::GetNode(*pPam, bFirst, fnMove, bInReadOnly, pLayout)))
923  {
924  if( bCharAttr )
925  {
926  if( !pNode->IsTextNode() ) // CharAttr are only in text nodes
927  continue;
928 
929  SwTextFrame const*const pFrame(pLayout
930  ? static_cast<SwTextFrame const*>(pNode->getLayoutFrame(pLayout))
931  : nullptr);
932  if (pFrame)
933  {
934  SwTextNode const* pAttrNode(nullptr);
935  SwTextAttr const* pAttr(nullptr);
936  if (bSrchForward)
937  {
938  sw::MergedAttrIter iter(*pFrame);
939  do
940  {
941  pAttr = iter.NextAttr(&pAttrNode);
942  }
943  while (pAttr
944  && (pAttrNode->GetIndex() < pPam->GetPoint()->nNode.GetIndex()
945  || (pAttrNode->GetIndex() == pPam->GetPoint()->nNode.GetIndex()
946  && pAttr->GetStart() < pPam->GetPoint()->nContent.GetIndex())
947  || pAttr->Which() != nWhich));
948  }
949  else
950  {
951  sw::MergedAttrIterReverse iter(*pFrame);
952  do
953  {
954  pAttr = iter.PrevAttr(&pAttrNode);
955  }
956  while (pAttr
957  && (pPam->GetPoint()->nNode.GetIndex() < pAttrNode->GetIndex()
958  || (pPam->GetPoint()->nNode.GetIndex() == pAttrNode->GetIndex()
959  && pPam->GetPoint()->nContent.GetIndex() <= pAttr->GetStart())
960  || pAttr->Which() != nWhich));
961  }
962  if (pAttr)
963  {
964  assert(pAttrNode);
965  pPam->GetPoint()->nNode = *pAttrNode;
966  lcl_SetAttrPam(*pPam, pAttr->GetStart(), pAttr->End(), bSrchForward);
967  bFound = true;
968  break;
969  }
970  }
971  else if (!pLayout && pNode->GetTextNode()->HasHints() &&
972  lcl_SearchAttr(*pNode->GetTextNode(), *pPam, rAttr, fnMove))
973  {
974  bFound = true;
975  }
976  if (bFound)
977  {
978  // set to the values of the attribute
979  rSearchPam.SetMark();
980  *rSearchPam.GetPoint() = *pPam->GetPoint();
981  *rSearchPam.GetMark() = *pPam->GetMark();
982  break;
983  }
984  else if (isTXTATR(nWhich))
985  continue;
986  }
987 
988 #if 0
989  // no hard attribution, so check if node was asked for this attr before
990  if( !pNode->HasSwAttrSet() )
991  {
992  SwFormat* pTmpFormat = pNode->GetFormatColl();
993  if( !aFormatArr.insert( pTmpFormat ).second )
994  continue; // collection was requested earlier
995  }
996 
997  if( SfxItemState::SET == pNode->GetSwAttrSet().GetItemState( nWhich,
998  true, &pItem ))
999  {
1000  // FORWARD: SPoint at the end, GetMark at the beginning of the node
1001  // BACKWARD: SPoint at the beginning, GetMark at the end of the node
1002  // always: incl. start and incl. end
1003  *rSearchPam.GetPoint() = *pPam->GetPoint();
1004  rSearchPam.SetMark();
1005  pNode->MakeEndIndex( &rSearchPam.GetPoint()->nContent );
1006  bFound = true;
1007  break;
1008  }
1009 #endif
1010  }
1011 
1012  // if backward search, switch point and mark
1013  if( bFound && !bSrchForward )
1014  rSearchPam.Exchange();
1015 
1016  return bFound;
1017 }
1018 
1019 } // namespace sw
1020 
1021 typedef bool (*FnSearchAttr)( const SwTextNode&, SwAttrCheckArr&, SwPaM& );
1022 
1023 static bool FindAttrsImpl(SwPaM & rSearchPam,
1024  const SfxItemSet& rSet, bool bNoColls, SwMoveFnCollection const & fnMove,
1025  const SwPaM & rRegion, bool bInReadOnly, bool bMoveFirst,
1026  SwRootFrame const*const pLayout)
1027 {
1028  std::unique_ptr<SwPaM> pPam(sw::MakeRegion(fnMove, rRegion));
1029 
1030  bool bFound = false;
1031  bool bFirst = true;
1032  const bool bSrchForward = &fnMove == &fnMoveForward;
1033  SwContentNode * pNode;
1034  SwpFormats aFormatArr;
1035 
1036  // check which text/char attributes are searched
1037  SwAttrCheckArr aCmpArr( rSet, bSrchForward, bNoColls );
1038  SfxItemSet aOtherSet( rSearchPam.GetDoc()->GetAttrPool(),
1040  aOtherSet.Put( rSet, false ); // got all invalid items
1041 
1042  FnSearchAttr fnSearch = bSrchForward
1043  ? (&::lcl_SearchForward)
1044  : (&::lcl_SearchBackward);
1045 
1046  // if at beginning/end then move it out of the node
1047  if( bMoveFirst &&
1048  ( bSrchForward
1049  ? pPam->GetPoint()->nContent.GetIndex() == pPam->GetContentNode()->Len()
1050  : !pPam->GetPoint()->nContent.GetIndex() ) )
1051  {
1052  if( !(*fnMove.fnNds)( &pPam->GetPoint()->nNode, false ))
1053  {
1054  return false;
1055  }
1056  SwContentNode *pNd = pPam->GetContentNode();
1057  pPam->GetPoint()->nContent.Assign( pNd, bSrchForward ? 0 : pNd->Len() );
1058  }
1059 
1060  while (nullptr != (pNode = ::GetNode(*pPam, bFirst, fnMove, bInReadOnly, pLayout)))
1061  {
1062  SwTextFrame const*const pFrame(pLayout && pNode->IsTextNode()
1063  ? static_cast<SwTextFrame const*>(pNode->getLayoutFrame(pLayout))
1064  : nullptr);
1065  assert(!pLayout || !pNode->IsTextNode() || pFrame);
1066  // sw_redlinehide: it's apparently not possible to find break items
1067  // with the UI, so checking one node is enough
1068  SwContentNode const& rPropsNode(*(pFrame
1069  ? pFrame->GetTextNodeForParaProps()
1070  : pNode));
1071 
1072  if( aCmpArr.Count() )
1073  {
1074  if( !pNode->IsTextNode() ) // CharAttr are only in text nodes
1075  continue;
1076 
1077  if (aOtherSet.Count() &&
1078  !lcl_Search(rPropsNode, aOtherSet, bNoColls))
1079  {
1080  continue;
1081  }
1082  sw::MergedPara const*const pMergedPara(pFrame ? pFrame->GetMergedPara() : nullptr);
1083  if (pMergedPara)
1084  {
1085  SwPosition const& rStart(*pPam->Start());
1086  SwPosition const& rEnd(*pPam->End());
1087  // no extents? fall back to searching index 0 of propsnode
1088  // to find its node items
1089  if (pMergedPara->extents.empty())
1090  {
1091  if (rStart.nNode.GetIndex() <= rPropsNode.GetIndex()
1092  && rPropsNode.GetIndex() <= rEnd.nNode.GetIndex())
1093  {
1094  SwPaM tmp(rPropsNode, 0, rPropsNode, 0);
1095  bFound = (*fnSearch)(*pNode->GetTextNode(), aCmpArr, tmp);
1096  if (bFound)
1097  {
1098  *pPam = tmp;
1099  }
1100  }
1101  }
1102  else
1103  {
1104  // iterate the extents, and intersect with input pPam:
1105  // the found ranges should never include delete redlines
1106  // so that subsequent Replace will not affect them
1107  for (size_t i = 0; i < pMergedPara->extents.size(); ++i)
1108  {
1109  auto const rExtent(pMergedPara->extents[bSrchForward
1110  ? i
1111  : pMergedPara->extents.size() - i - 1]);
1112  if (rExtent.pNode->GetIndex() < rStart.nNode.GetIndex()
1113  || rEnd.nNode.GetIndex() < rExtent.pNode->GetIndex())
1114  {
1115  continue;
1116  }
1117  sal_Int32 const nStart(rExtent.pNode == &rStart.nNode.GetNode()
1118  ? rStart.nContent.GetIndex()
1119  : 0);
1120  if (rExtent.nEnd <= nStart)
1121  {
1122  continue;
1123  }
1124  sal_Int32 const nEnd(rExtent.pNode == &rEnd.nNode.GetNode()
1125  ? rEnd.nContent.GetIndex()
1126  : rExtent.pNode->Len());
1127  if (nEnd < rExtent.nStart
1128  || (nStart != nEnd && nEnd == rExtent.nStart))
1129  {
1130  continue;
1131  }
1132  SwPaM tmp(*rExtent.pNode, std::max(nStart, rExtent.nStart),
1133  *rExtent.pNode, std::min(nEnd, rExtent.nEnd));
1134  tmp.Normalize(bSrchForward);
1135  bFound = (*fnSearch)(*rExtent.pNode, aCmpArr, tmp);
1136  if (bFound)
1137  {
1138  *pPam = tmp;
1139  break;
1140  }
1141  }
1142  }
1143  }
1144  else
1145  {
1146  bFound = (*fnSearch)(*pNode->GetTextNode(), aCmpArr, *pPam);
1147  }
1148  if (bFound)
1149  {
1150  // set to the values of the attribute
1151  rSearchPam.SetMark();
1152  *rSearchPam.GetPoint() = *pPam->GetPoint();
1153  *rSearchPam.GetMark() = *pPam->GetMark();
1154  break;
1155  }
1156  continue; // text attribute
1157  }
1158 
1159  if( !aOtherSet.Count() )
1160  continue;
1161 
1162  // no hard attribution, so check if node was asked for this attr before
1163  // (as an optimisation)
1164  if (!rPropsNode.HasSwAttrSet())
1165  {
1166  SwFormat* pTmpFormat = rPropsNode.GetFormatColl();
1167  if( !aFormatArr.insert( pTmpFormat ).second )
1168  continue; // collection was requested earlier
1169  }
1170 
1171  if (lcl_Search(rPropsNode, aOtherSet, bNoColls))
1172  {
1173  // FORWARD: SPoint at the end, GetMark at the beginning of the node
1174  // BACKWARD: SPoint at the beginning, GetMark at the end of the node
1175  if (pFrame)
1176  {
1177  *rSearchPam.GetPoint() = *pPam->GetPoint();
1178  rSearchPam.SetMark();
1179  *rSearchPam.GetMark() = pFrame->MapViewToModelPos(
1180  TextFrameIndex(bSrchForward ? pFrame->GetText().getLength() : 0));
1181  }
1182  else
1183  {
1184  *rSearchPam.GetPoint() = *pPam->GetPoint();
1185  rSearchPam.SetMark();
1186  if (bSrchForward)
1187  {
1188  pNode->MakeEndIndex( &rSearchPam.GetPoint()->nContent );
1189  }
1190  else
1191  {
1192  pNode->MakeStartIndex( &rSearchPam.GetPoint()->nContent );
1193  }
1194  }
1195  bFound = true;
1196  break;
1197  }
1198  }
1199 
1200  // if backward search, switch point and mark
1201  if( bFound && !bSrchForward )
1202  rSearchPam.Exchange();
1203 
1204  return bFound;
1205 }
1206 
1209 {
1210  bool const m_bNoCollection;
1215  std::unique_ptr<utl::TextSearch> pSText;
1216 
1217  SwFindParaAttr( const SfxItemSet& rSet, bool bNoCollection,
1218  const i18nutil::SearchOptions2* pOpt, const SfxItemSet* pRSet,
1219  SwCursor& rCursor, SwRootFrame const*const pLayout)
1220  : m_bNoCollection(bNoCollection)
1221  , pSet( &rSet )
1222  , pReplSet( pRSet )
1223  , pSearchOpt( pOpt )
1224  , m_rCursor(rCursor)
1225  , m_pLayout(pLayout)
1226  {}
1227 
1228  virtual ~SwFindParaAttr() {}
1229 
1230  virtual int DoFind(SwPaM &, SwMoveFnCollection const &, const SwPaM &, bool bInReadOnly) override;
1231  virtual bool IsReplaceMode() const override;
1232 };
1233 
1234 int SwFindParaAttr::DoFind(SwPaM & rCursor, SwMoveFnCollection const & fnMove,
1235  const SwPaM & rRegion, bool bInReadOnly)
1236 {
1237  // replace string (only if text given and search is not parameterized)?
1238  bool bReplaceText = pSearchOpt && ( !pSearchOpt->replaceString.isEmpty() ||
1239  !pSet->Count() );
1240  bool bReplaceAttr = pReplSet && pReplSet->Count();
1241  bool bMoveFirst = !bReplaceAttr;
1242  if( bInReadOnly && (bReplaceAttr || bReplaceText ))
1243  bInReadOnly = false;
1244 
1245  // We search for attributes, should we search for text as well?
1246  {
1247  SwPaM aRegion( *rRegion.GetMark(), *rRegion.GetPoint() );
1248  SwPaM* pTextRegion = &aRegion;
1249  SwPaM aSrchPam( *rCursor.GetPoint() );
1250 
1251  while( true )
1252  {
1253  if( pSet->Count() ) // any attributes?
1254  {
1255  // first attributes
1256  if (!FindAttrsImpl(aSrchPam, *pSet, m_bNoCollection, fnMove, aRegion, bInReadOnly, bMoveFirst, m_pLayout))
1257  return FIND_NOT_FOUND;
1258  bMoveFirst = true;
1259 
1260  if( !pSearchOpt )
1261  break; // ok, only attributes, so found
1262 
1263  pTextRegion = &aSrchPam;
1264  }
1265  else if( !pSearchOpt )
1266  return FIND_NOT_FOUND;
1267 
1268  // then search in text of it
1269  if( !pSText )
1270  {
1272 
1273  // search in selection
1274  aTmp.searchFlag |= (SearchFlags::REG_NOT_BEGINOFLINE |
1275  SearchFlags::REG_NOT_ENDOFLINE);
1276 
1278 
1279  pSText.reset( new utl::TextSearch( aTmp ) );
1280  }
1281 
1282  // TODO: searching for attributes in Outliner text?!
1283 
1284  // continue search in correct section (pTextRegion)
1285  if (sw::FindTextImpl(aSrchPam, *pSearchOpt, false/*bSearchInNotes*/, *pSText, fnMove, *pTextRegion, bInReadOnly, m_pLayout) &&
1286  *aSrchPam.GetMark() != *aSrchPam.GetPoint() )
1287  break; // found
1288  else if( !pSet->Count() )
1289  return FIND_NOT_FOUND; // only text and nothing found
1290 
1291  *aRegion.GetMark() = *aSrchPam.GetPoint();
1292  }
1293 
1294  *rCursor.GetPoint() = *aSrchPam.GetPoint();
1295  rCursor.SetMark();
1296  *rCursor.GetMark() = *aSrchPam.GetMark();
1297  }
1298 
1299  if( bReplaceText )
1300  {
1301  const bool bRegExp(
1302  SearchAlgorithms2::REGEXP == pSearchOpt->AlgorithmType2);
1303  SwIndex& rSttCntIdx = rCursor.Start()->nContent;
1304  const sal_Int32 nSttCnt = rSttCntIdx.GetIndex();
1305 
1306  // add to shell-cursor-ring so that the regions will be moved eventually
1307  SwPaM* pPrevRing(nullptr);
1308  if( bRegExp )
1309  {
1310  pPrevRing = const_cast<SwPaM &>(rRegion).GetPrev();
1311  const_cast<SwPaM &>(rRegion).GetRingContainer().merge( m_rCursor.GetRingContainer() );
1312  }
1313 
1315  if (bRegExp)
1316  xRepl = sw::ReplaceBackReferences(*pSearchOpt, &rCursor, m_pLayout);
1317  sw::ReplaceImpl(rCursor,
1318  xRepl ? *xRepl : pSearchOpt->replaceString, bRegExp,
1319  *m_rCursor.GetDoc(), m_pLayout);
1320 
1321  m_rCursor.SaveTableBoxContent( rCursor.GetPoint() );
1322 
1323  if( bRegExp )
1324  {
1325  // and remove region again
1326  SwPaM* p;
1327  SwPaM* pNext = const_cast<SwPaM*>(&rRegion);
1328  do {
1329  p = pNext;
1330  pNext = p->GetNext();
1331  p->MoveTo(const_cast<SwPaM*>(&rRegion));
1332  } while( p != pPrevRing );
1333  }
1334  rSttCntIdx = nSttCnt;
1335  }
1336 
1337  if( bReplaceAttr )
1338  {
1339  // is the selection still existent?
1340  // all searched attributes are reset to default if
1341  // they are not in ReplaceSet
1342  if( !pSet->Count() )
1343  {
1346  }
1347  else
1348  {
1349  SfxItemPool* pPool = pReplSet->GetPool();
1350  SfxItemSet aSet( *pPool, pReplSet->GetRanges() );
1351 
1352  SfxItemIter aIter( *pSet );
1353  const SfxPoolItem* pItem = aIter.GetCurItem();
1354  while( true )
1355  {
1356  // reset all that are not set with pool defaults
1357  if( !IsInvalidItem( pItem ) && SfxItemState::SET !=
1358  pReplSet->GetItemState( pItem->Which(), false ))
1359  aSet.Put( pPool->GetDefaultItem( pItem->Which() ));
1360 
1361  if( aIter.IsAtEnd() )
1362  break;
1363  pItem = aIter.NextItem();
1364  }
1365  aSet.Put( *pReplSet );
1367  rCursor, aSet, SetAttrMode::DEFAULT, m_pLayout);
1368  }
1369 
1370  return FIND_NO_RING;
1371  }
1372  else
1373  return FIND_FOUND;
1374 }
1375 
1377 {
1378  return ( pSearchOpt && !pSearchOpt->replaceString.isEmpty() ) ||
1379  ( pReplSet && pReplSet->Count() );
1380 }
1381 
1383 sal_uLong SwCursor::FindAttrs( const SfxItemSet& rSet, bool bNoCollections,
1384  SwDocPositions nStart, SwDocPositions nEnd,
1385  bool& bCancel, FindRanges eFndRngs,
1386  const i18nutil::SearchOptions2* pSearchOpt,
1387  const SfxItemSet* pReplSet,
1388  SwRootFrame const*const pLayout)
1389 {
1390  // switch off OLE-notifications
1391  SwDoc* pDoc = GetDoc();
1392  Link<bool,void> aLnk( pDoc->GetOle2Link() );
1393  pDoc->SetOle2Link( Link<bool,void>() );
1394 
1395  bool bReplace = ( pSearchOpt && ( !pSearchOpt->replaceString.isEmpty() ||
1396  !rSet.Count() ) ) ||
1397  (pReplSet && pReplSet->Count());
1398  bool const bStartUndo = pDoc->GetIDocumentUndoRedo().DoesUndo() && bReplace;
1399  if (bStartUndo)
1400  {
1401  pDoc->GetIDocumentUndoRedo().StartUndo( SwUndoId::REPLACE, nullptr );
1402  }
1403 
1404  SwFindParaAttr aSwFindParaAttr( rSet, bNoCollections, pSearchOpt,
1405  pReplSet, *this, pLayout );
1406 
1407  sal_uLong nRet = FindAll( aSwFindParaAttr, nStart, nEnd, eFndRngs, bCancel );
1408  pDoc->SetOle2Link( aLnk );
1409  if( nRet && bReplace )
1410  pDoc->getIDocumentState().SetModified();
1411 
1412  if (bStartUndo)
1413  {
1414  pDoc->GetIDocumentUndoRedo().EndUndo( SwUndoId::REPLACE, nullptr );
1415  }
1416 
1417  return nRet;
1418 }
1419 
1420 /* 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:1217
sal_Int32 & GetStart()
start position
Definition: txatbase.hxx:77
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:1383
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:229
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 drop-down form field.
Definition: accframe.hxx:34
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:176
#define RES_TXTATR_CHARFMT
Definition: hintids.hxx:142
sal_uInt16 Which() const
Definition: txatbase.hxx:105
const OUString & GetText() const
Returns the text portion we want to edit (for inline see underneath)
Definition: txtfrm.cxx:1278
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:1214
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:1211
SwIndex nContent
Definition: pam.hxx:38
const i18nutil::SearchOptions2 * pSearchOpt
Definition: findattr.cxx:1212
const Link< bool, void > & GetOle2Link() const
Definition: doc.hxx:1317
GetHint fnGetHint
Definition: pamtyp.hxx:76
FindRanges
Definition: cshtyp.hxx:90
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:952
#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:1213
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:892
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:1288
size_t Count() const
Definition: ndhints.hxx:152
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:154
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
virtual ~SwFindParaAttr()
Definition: findattr.cxx:1228
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:854
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:135
#define RES_CHRATR_BEGIN
Definition: hintids.hxx:68
parameters for search for attributes
Definition: findattr.cxx:1208
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:808
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
const sal_Int32 * GetAnyEnd() const
end (if available), else start
Definition: txatbase.hxx:147
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:76
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:1211
const sal_Int32 * End() const
Definition: txatbase.hxx:142
sal_uInt16 nWhich
Definition: findattr.cxx:184
virtual bool IsReplaceMode() const override
Definition: findattr.cxx:1376
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:1023
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:153
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:1215
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:1234
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:1233
bool const m_bNoCollection
Definition: findattr.cxx:1210
virtual void SaveTableBoxContent(const SwPosition *pPos)
Definition: swcrsr.cxx:719
bool(* FnSearchAttr)(const SwTextNode &, SwAttrCheckArr &, SwPaM &)
Definition: findattr.cxx:1021
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:842
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:776
search for multiple text attributes
Definition: findattr.cxx:182