1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <com/sun/star/lang/Locale.hpp>
21 #include <com/sun/star/util/SearchOptions.hpp>
22 #include <com/sun/star/util/SearchFlags.hpp>
23 #include <i18npool/languagetag.hxx>
24 #include <hintids.hxx>
25 #include <vcl/svapp.hxx>
26 #include <svl/itemiter.hxx>
27 #include <svl/whiter.hxx>
28 #include <editeng/brkitem.hxx>
29 #include <editeng/colritem.hxx>
30 #include <editeng/fontitem.hxx>
31 #include <fmtpdsc.hxx>
32 #include <txatbase.hxx>
33 #include <fchrfmt.hxx>
34 #include <charfmt.hxx>
36 #include <IDocumentUndoRedo.hxx>
42 #include <crsskip.hxx>
45 using namespace ::com::sun::star
;
46 using namespace ::com::sun::star::lang
;
47 using namespace ::com::sun::star::util
;
49 typedef std::set
<SwFmt
*> SwpFmts
;
51 // Special case for SvxFontItem: only compare the name
52 int CmpAttr( const SfxPoolItem
& rItem1
, const SfxPoolItem
& rItem2
)
54 switch( rItem1
.Which() )
57 return ((SvxFontItem
&)rItem1
).GetFamilyName() ==
58 ((SvxFontItem
&)rItem2
).GetFamilyName();
60 case RES_CHRATR_COLOR
:
61 return ((SvxColorItem
&)rItem1
).GetValue().IsRGBEqual(
62 ((SvxColorItem
&)rItem2
).GetValue() );
64 return ((SwFmtPageDesc
&)rItem1
).GetNumOffset() ==
65 ((SwFmtPageDesc
&)rItem2
).GetNumOffset() &&
66 ((SwFmtPageDesc
&)rItem1
).GetPageDesc() ==
67 ((SwFmtPageDesc
&)rItem2
).GetPageDesc();
69 return rItem1
== rItem2
;
73 const SwTxtAttr
* GetFrwrdTxtHint( const SwpHints
& rHtsArr
, sal_uInt16
& rPos
,
74 xub_StrLen nCntntPos
)
76 while( rPos
< rHtsArr
.Count() )
78 const SwTxtAttr
*pTxtHt
= rHtsArr
.GetStart( rPos
++ );
79 // the start of an attribute has to be in the section
80 if( *pTxtHt
->GetStart() >= nCntntPos
)
81 return pTxtHt
; // valid text attribute
83 return 0; // invalid text attribute
87 const SwTxtAttr
* GetBkwrdTxtHint( const SwpHints
& rHtsArr
, sal_uInt16
& rPos
,
88 xub_StrLen nCntntPos
)
92 const SwTxtAttr
*pTxtHt
= rHtsArr
.GetStart( --rPos
);
93 // the start of an attribute has to be in the section
94 if( *pTxtHt
->GetStart() < nCntntPos
)
95 return pTxtHt
; // valid text attribute
97 return 0; // invalid text attribute
100 static void lcl_SetAttrPam( SwPaM
& rPam
, xub_StrLen nStart
, const xub_StrLen
* pEnd
,
101 const sal_Bool bSaveMark
)
103 xub_StrLen nCntntPos
;
105 nCntntPos
= rPam
.GetMark()->nContent
.GetIndex();
107 nCntntPos
= rPam
.GetPoint()->nContent
.GetIndex();
108 bool bTstEnd
= rPam
.GetPoint()->nNode
== rPam
.GetMark()->nNode
;
110 SwCntntNode
* pCNd
= rPam
.GetCntntNode();
111 rPam
.GetPoint()->nContent
.Assign( pCNd
, nStart
);
112 rPam
.SetMark(); // Point == GetMark
114 // Point points to end of search area or end of attribute
117 if( bTstEnd
&& *pEnd
> nCntntPos
)
118 rPam
.GetPoint()->nContent
= nCntntPos
;
120 rPam
.GetPoint()->nContent
= *pEnd
;
124 // TODO: provide documentation
125 /** search for a text attribute
127 This function searches in a text node for a given attribute.
128 If that is found then the SwPaM contains the section that surrounds the
129 attribute (w.r.t. the search area).
131 @param rTxtNd Text node to search in.
136 @return Returns <true> if found, <false> otherwise.
138 static sal_Bool
lcl_Search( const SwTxtNode
& rTxtNd
, SwPaM
& rPam
,
139 const SfxPoolItem
& rCmpItem
,
140 SwMoveFn fnMove
, sal_Bool bValue
)
142 if ( !rTxtNd
.HasHints() )
144 const SwTxtAttr
*pTxtHt
= 0;
145 sal_Bool bForward
= fnMove
== fnMoveForward
;
146 sal_uInt16 nPos
= bForward
? 0 : rTxtNd
.GetSwpHints().Count();
147 xub_StrLen nCntntPos
= rPam
.GetPoint()->nContent
.GetIndex();
149 while( 0 != ( pTxtHt
=(*fnMove
->fnGetHint
)(rTxtNd
.GetSwpHints(),nPos
,nCntntPos
)))
150 if( pTxtHt
->Which() == rCmpItem
.Which() &&
151 ( !bValue
|| CmpAttr( pTxtHt
->GetAttr(), rCmpItem
)))
153 lcl_SetAttrPam( rPam
, *pTxtHt
->GetStart(), pTxtHt
->GetEnd(), bForward
);
159 /// search for multiple text attributes
160 struct _SwSrchChrAttr
163 xub_StrLen nStt
, nEnd
;
165 _SwSrchChrAttr( const SfxPoolItem
& rItem
,
166 xub_StrLen nStart
, xub_StrLen nAnyEnd
)
167 : nWhich( rItem
.Which() ), nStt( nStart
), nEnd( nAnyEnd
)
173 _SwSrchChrAttr
*pFndArr
, *pStackArr
;
174 xub_StrLen nNdStt
, nNdEnd
;
175 sal_uInt16 nArrStart
, nArrLen
;
176 sal_uInt16 nFound
, nStackCnt
;
182 SwAttrCheckArr( const SfxItemSet
& rSet
, int bForward
, int bNoCollections
);
185 void SetNewSet( const SwTxtNode
& rTxtNd
, const SwPaM
& rPam
);
187 /// how many attributes are there in total?
188 sal_uInt16
Count() const { return aCmpSet
.Count(); }
189 int Found() const { return nFound
== aCmpSet
.Count(); }
192 xub_StrLen
Start() const;
193 xub_StrLen
End() const;
195 xub_StrLen
GetNdStt() const { return nNdStt
; }
196 xub_StrLen
GetNdEnd() const { return nNdEnd
; }
198 int SetAttrFwd( const SwTxtAttr
& rAttr
);
199 int SetAttrBwd( const SwTxtAttr
& rAttr
);
204 SwAttrCheckArr::SwAttrCheckArr( const SfxItemSet
& rSet
, int bFwd
,
206 : aCmpSet( *rSet
.GetPool(), RES_CHRATR_BEGIN
, RES_TXTATR_END
-1 )
208 aCmpSet
.Put( rSet
, sal_False
);
209 bNoColls
= 0 != bNoCollections
;
211 bForward
= 0 != bFwd
;
213 // determine area of Fnd/Stack array (Min/Max)
214 SfxItemIter
aIter( aCmpSet
);
215 nArrStart
= aCmpSet
.GetWhichByPos( aIter
.GetFirstPos() );
216 nArrLen
= aCmpSet
.GetWhichByPos( aIter
.GetLastPos() ) - nArrStart
+1;
218 char* pFndChar
= new char[ nArrLen
* sizeof(_SwSrchChrAttr
) ];
219 char* pStackChar
= new char[ nArrLen
* sizeof(_SwSrchChrAttr
) ];
221 pFndArr
= (_SwSrchChrAttr
*)pFndChar
;
222 pStackArr
= (_SwSrchChrAttr
*)pStackChar
;
225 SwAttrCheckArr::~SwAttrCheckArr()
227 delete[] (char*)pFndArr
;
228 delete[] (char*)pStackArr
;
231 void SwAttrCheckArr::SetNewSet( const SwTxtNode
& rTxtNd
, const SwPaM
& rPam
)
233 memset( pFndArr
, 0, nArrLen
* sizeof(_SwSrchChrAttr
) );
234 memset( pStackArr
, 0, nArrLen
* sizeof(_SwSrchChrAttr
) );
240 nNdStt
= rPam
.GetPoint()->nContent
.GetIndex();
241 nNdEnd
= rPam
.GetPoint()->nNode
== rPam
.GetMark()->nNode
242 ? rPam
.GetMark()->nContent
.GetIndex()
243 : rTxtNd
.GetTxt().Len();
247 nNdEnd
= rPam
.GetPoint()->nContent
.GetIndex();
248 nNdStt
= rPam
.GetPoint()->nNode
== rPam
.GetMark()->nNode
249 ? rPam
.GetMark()->nContent
.GetIndex()
253 if( bNoColls
&& !rTxtNd
.HasSwAttrSet() )
256 const SfxItemSet
& rSet
= rTxtNd
.GetSwAttrSet();
258 SfxItemIter
aIter( aCmpSet
);
259 const SfxPoolItem
* pItem
= aIter
.GetCurItem();
260 const SfxPoolItem
* pFndItem
;
265 if( IsInvalidItem( pItem
) )
267 nWhich
= aCmpSet
.GetWhichByPos( aIter
.GetCurPos() );
268 if( RES_TXTATR_END
<= nWhich
)
269 break; // end of text attributes
271 if( SFX_ITEM_SET
== rSet
.GetItemState( nWhich
, !bNoColls
, &pFndItem
)
272 && !CmpAttr( *pFndItem
, rSet
.GetPool()->GetDefaultItem( nWhich
) ))
274 pFndArr
[ nWhich
- nArrStart
] =
275 _SwSrchChrAttr( *pFndItem
, nNdStt
, nNdEnd
);
281 if( RES_TXTATR_END
<= (nWhich
= pItem
->Which() ))
282 break; // end of text attributes
284 if( CmpAttr( rSet
.Get( nWhich
, !bNoColls
), *pItem
) )
286 pFndArr
[ nWhich
- nArrStart
] =
287 _SwSrchChrAttr( *pItem
, nNdStt
, nNdEnd
);
292 if( aIter
.IsAtEnd() )
294 pItem
= aIter
.NextItem();
299 lcl_IsAttributeIgnorable(xub_StrLen
const nNdStart
, xub_StrLen
const nNdEnd
,
300 _SwSrchChrAttr
const& rTmp
)
302 // #i115528#: if there is a paragraph attribute, it has been added by the
303 // SwAttrCheckArr ctor, and nFound is 1.
304 // if the paragraph is entirely covered by hints that override the paragraph
305 // attribute, then this function must find an attribute to decrement nFound!
306 // so check for an empty search range, let attributes that start/end there
307 // cover it, and hope for the best...
308 return ((nNdEnd
== nNdStart
)
309 ? ((rTmp
.nEnd
< nNdStart
) || (nNdEnd
< rTmp
.nStt
))
310 : ((rTmp
.nEnd
<= nNdStart
) || (nNdEnd
<= rTmp
.nStt
)));
313 int SwAttrCheckArr::SetAttrFwd( const SwTxtAttr
& rAttr
)
315 _SwSrchChrAttr
aTmp( rAttr
.GetAttr(), *rAttr
.GetStart(), *rAttr
.GetAnyEnd() );
317 // ignore all attributes not in search range
318 if (lcl_IsAttributeIgnorable(nNdStt
, nNdEnd
, aTmp
))
323 const SfxPoolItem
* pItem
;
324 // here we explicitly also search in character templates
325 sal_uInt16 nWhch
= rAttr
.Which();
326 SfxWhichIter
* pIter
= NULL
;
327 const SfxPoolItem
* pTmpItem
= NULL
;
328 const SfxItemSet
* pSet
= NULL
;
329 if( RES_TXTATR_CHARFMT
== nWhch
|| RES_TXTATR_AUTOFMT
== nWhch
)
331 if( bNoColls
&& RES_TXTATR_CHARFMT
== nWhch
)
334 pSet
= CharFmt::GetItemSet( rAttr
.GetAttr() );
337 pIter
= new SfxWhichIter( *pSet
);
338 nWhch
= pIter
->FirstWhich();
340 SFX_ITEM_SET
!= pSet
->GetItemState( nWhch
, sal_True
, &pTmpItem
) )
341 nWhch
= pIter
->NextWhich();
347 pTmpItem
= &rAttr
.GetAttr();
350 SfxItemState eState
= aCmpSet
.GetItemState( nWhch
, sal_False
, &pItem
);
351 if( SFX_ITEM_DONTCARE
== eState
|| SFX_ITEM_SET
== eState
)
354 _SwSrchChrAttr
* pCmp
;
356 // first delete all up to start position that are already invalid
357 _SwSrchChrAttr
* pArrPtr
;
359 for( pArrPtr
= pFndArr
, n
= 0; n
< nArrLen
;
361 if( pArrPtr
->nWhich
&& pArrPtr
->nEnd
<= aTmp
.nStt
)
363 pArrPtr
->nWhich
= 0; // deleted
367 // delete all up to start position that are already invalid and
368 // move all "open" ones (= stick out over start position) from stack
371 for( pArrPtr
= pStackArr
, n
=0; n
< nArrLen
; ++n
, ++pArrPtr
)
373 if( !pArrPtr
->nWhich
)
376 if( pArrPtr
->nEnd
<= aTmp
.nStt
)
378 pArrPtr
->nWhich
= 0; // deleted
382 else if( pArrPtr
->nStt
<= aTmp
.nStt
)
384 if( ( pCmp
= &pFndArr
[ n
])->nWhich
)
386 if( pCmp
->nEnd
< pArrPtr
->nEnd
) // extend
387 pCmp
->nEnd
= pArrPtr
->nEnd
;
400 bool bContinue
= false;
402 if( SFX_ITEM_DONTCARE
== eState
)
404 // Will the attribute become valid?
405 if( !CmpAttr( aCmpSet
.GetPool()->GetDefaultItem( nWhch
),
408 // search attribute and extend if needed
409 if( !( pCmp
= &pFndArr
[ nWhch
- nArrStart
])->nWhich
)
411 *pCmp
= aTmp
; // not found, insert
414 else if( pCmp
->nEnd
< aTmp
.nEnd
) // extend?
415 pCmp
->nEnd
= aTmp
.nEnd
;
420 // Will the attribute become valid?
421 else if( CmpAttr( *pItem
, *pTmpItem
) )
423 pFndArr
[ nWhch
- nArrStart
] = aTmp
;
428 // then is has to go on the stack
429 if( !bContinue
&& ( pCmp
= &pFndArr
[ nWhch
- nArrStart
])->nWhich
)
431 // exists on stack, only if it is even bigger
432 if( pCmp
->nEnd
> aTmp
.nEnd
)
434 OSL_ENSURE( !pStackArr
[ nWhch
- nArrStart
].nWhich
,
435 "slot on stack is still in use" );
437 if( aTmp
.nStt
<= pCmp
->nStt
)
438 pCmp
->nStt
= aTmp
.nEnd
;
440 pCmp
->nEnd
= aTmp
.nStt
;
442 pStackArr
[ nWhch
- nArrStart
] = *pCmp
;
451 nWhch
= pIter
->NextWhich();
453 SFX_ITEM_SET
!= pSet
->GetItemState( nWhch
, sal_True
, &pTmpItem
) )
454 nWhch
= pIter
->NextWhich();
465 int SwAttrCheckArr::SetAttrBwd( const SwTxtAttr
& rAttr
)
467 _SwSrchChrAttr
aTmp( rAttr
.GetAttr(), *rAttr
.GetStart(), *rAttr
.GetAnyEnd() );
469 // ignore all attributes not in search range
470 if (lcl_IsAttributeIgnorable(nNdStt
, nNdEnd
, aTmp
))
475 const SfxPoolItem
* pItem
;
476 // here we explicitly also search in character templates
477 sal_uInt16 nWhch
= rAttr
.Which();
478 SfxWhichIter
* pIter
= NULL
;
479 const SfxPoolItem
* pTmpItem
= NULL
;
480 const SfxItemSet
* pSet
= NULL
;
481 if( RES_TXTATR_CHARFMT
== nWhch
|| RES_TXTATR_AUTOFMT
== nWhch
)
483 if( bNoColls
&& RES_TXTATR_CHARFMT
== nWhch
)
486 pSet
= CharFmt::GetItemSet( rAttr
.GetAttr() );
489 pIter
= new SfxWhichIter( *pSet
);
490 nWhch
= pIter
->FirstWhich();
492 SFX_ITEM_SET
!= pSet
->GetItemState( nWhch
, sal_True
, &pTmpItem
) )
493 nWhch
= pIter
->NextWhich();
499 pTmpItem
= &rAttr
.GetAttr();
502 SfxItemState eState
= aCmpSet
.GetItemState( nWhch
, sal_False
, &pItem
);
503 if( SFX_ITEM_DONTCARE
== eState
|| SFX_ITEM_SET
== eState
)
506 _SwSrchChrAttr
* pCmp
;
508 // first delete all up to start position that are already invalid
509 _SwSrchChrAttr
* pArrPtr
;
511 for( pArrPtr
= pFndArr
, n
= 0; n
< nArrLen
; ++n
, ++pArrPtr
)
512 if( pArrPtr
->nWhich
&& pArrPtr
->nStt
>= aTmp
.nEnd
)
514 pArrPtr
->nWhich
= 0; // deleted
518 // delete all up to start position that are already invalid and
519 // move all "open" ones (= stick out over start position) from stack
522 for( pArrPtr
= pStackArr
, n
= 0; n
< nArrLen
; ++n
, ++pArrPtr
)
524 if( !pArrPtr
->nWhich
)
527 if( pArrPtr
->nStt
>= aTmp
.nEnd
)
529 pArrPtr
->nWhich
= 0; // deleted
533 else if( pArrPtr
->nEnd
>= aTmp
.nEnd
)
535 if( ( pCmp
= &pFndArr
[ n
])->nWhich
)
537 if( pCmp
->nStt
> pArrPtr
->nStt
) // extend
538 pCmp
->nStt
= pArrPtr
->nStt
;
551 bool bContinue
= false;
552 if( SFX_ITEM_DONTCARE
== eState
)
554 // Will the attribute become valid?
555 if( !CmpAttr( aCmpSet
.GetPool()->GetDefaultItem( nWhch
),
558 // search attribute and extend if needed
559 if( !( pCmp
= &pFndArr
[ nWhch
- nArrStart
])->nWhich
)
561 *pCmp
= aTmp
; // not found, insert
564 else if( pCmp
->nStt
> aTmp
.nStt
) // extend?
565 pCmp
->nStt
= aTmp
.nStt
;
570 // Will the attribute become valid?
571 else if( CmpAttr( *pItem
, *pTmpItem
))
573 pFndArr
[ nWhch
- nArrStart
] = aTmp
;
578 // then is has to go on the stack
579 if( !bContinue
&& ( pCmp
= &pFndArr
[ nWhch
- nArrStart
])->nWhich
)
581 // exists on stack, only if it is even bigger
582 if( pCmp
->nStt
< aTmp
.nStt
)
584 OSL_ENSURE( !pStackArr
[ nWhch
- nArrStart
].nWhich
,
585 "slot on stack is still in use" );
587 if( aTmp
.nEnd
<= pCmp
->nEnd
)
588 pCmp
->nEnd
= aTmp
.nStt
;
590 pCmp
->nStt
= aTmp
.nEnd
;
592 pStackArr
[ nWhch
- nArrStart
] = *pCmp
;
601 nWhch
= pIter
->NextWhich();
603 SFX_ITEM_SET
!= pSet
->GetItemState( nWhch
, sal_True
, &pTmpItem
) )
604 nWhch
= pIter
->NextWhich();
615 xub_StrLen
SwAttrCheckArr::Start() const
617 xub_StrLen nStart
= nNdStt
;
618 _SwSrchChrAttr
* pArrPtr
= pFndArr
;
619 for( sal_uInt16 n
= 0; n
< nArrLen
; ++n
, ++pArrPtr
)
620 if( pArrPtr
->nWhich
&& pArrPtr
->nStt
> nStart
)
621 nStart
= pArrPtr
->nStt
;
627 xub_StrLen
SwAttrCheckArr::End() const
629 _SwSrchChrAttr
* pArrPtr
= pFndArr
;
630 xub_StrLen nEnd
= nNdEnd
;
631 for( sal_uInt16 n
= 0; n
< nArrLen
; ++n
, ++pArrPtr
)
632 if( pArrPtr
->nWhich
&& pArrPtr
->nEnd
< nEnd
)
633 nEnd
= pArrPtr
->nEnd
;
639 int SwAttrCheckArr::CheckStack()
645 xub_StrLen nSttPos
= Start(), nEndPos
= End();
646 _SwSrchChrAttr
* pArrPtr
;
647 for( pArrPtr
= pStackArr
, n
= 0; n
< nArrLen
; ++n
, ++pArrPtr
)
649 if( !pArrPtr
->nWhich
)
652 if( bForward
? pArrPtr
->nEnd
<= nSttPos
: pArrPtr
->nStt
>= nEndPos
)
654 pArrPtr
->nWhich
= 0; // deleted
656 return nFound
== aCmpSet
.Count();
658 else if( bForward
? pArrPtr
->nStt
< nEndPos
: pArrPtr
->nEnd
> nSttPos
)
660 // move all "open" ones (= stick out over start position) into FndSet
661 OSL_ENSURE( !pFndArr
[ n
].nWhich
, "slot in array is already in use" );
662 pFndArr
[ n
] = *pArrPtr
;
666 return nFound
== aCmpSet
.Count();
669 return nFound
== aCmpSet
.Count();
674 static int lcl_SearchForward( const SwTxtNode
& rTxtNd
, SwAttrCheckArr
& rCmpArr
,
677 xub_StrLen nEndPos
, nSttPos
;
678 rCmpArr
.SetNewSet( rTxtNd
, rPam
);
679 if( !rTxtNd
.HasHints() )
681 if( !rCmpArr
.Found() )
683 nEndPos
= rCmpArr
.GetNdEnd();
684 lcl_SetAttrPam( rPam
, rCmpArr
.GetNdStt(), &nEndPos
, sal_True
);
688 const SwpHints
& rHtArr
= rTxtNd
.GetSwpHints();
689 const SwTxtAttr
* pAttr
;
692 // if everything is already there then check with which it will be ended
693 if( rCmpArr
.Found() )
695 for( ; nPos
< rHtArr
.Count(); ++nPos
)
696 if( !rCmpArr
.SetAttrFwd( *( pAttr
= rHtArr
.GetStart( nPos
)) ) )
698 if( rCmpArr
.GetNdStt() < *pAttr
->GetStart() )
701 lcl_SetAttrPam( rPam
, rCmpArr
.GetNdStt(),
702 pAttr
->GetStart(), sal_True
);
709 if( nPos
== rHtArr
.Count() && rCmpArr
.Found() )
712 nEndPos
= rCmpArr
.GetNdEnd();
713 lcl_SetAttrPam( rPam
, rCmpArr
.GetNdStt(), &nEndPos
, sal_True
);
718 for( ; nPos
< rHtArr
.Count(); ++nPos
)
719 if( rCmpArr
.SetAttrFwd( *( pAttr
= rHtArr
.GetStart( nPos
)) ) )
721 // Do multiple start at that position? Do also check those:
722 nSttPos
= *pAttr
->GetStart();
723 while( ++nPos
< rHtArr
.Count() && nSttPos
==
724 *( pAttr
= rHtArr
.GetStart( nPos
))->GetStart() &&
725 rCmpArr
.SetAttrFwd( *pAttr
) )
727 if( !rCmpArr
.Found() )
730 // then we have our search area
731 if( (nSttPos
= rCmpArr
.Start()) > (nEndPos
= rCmpArr
.End()) )
733 lcl_SetAttrPam( rPam
, nSttPos
, &nEndPos
, sal_True
);
737 if( !rCmpArr
.CheckStack() ||
738 (nSttPos
= rCmpArr
.Start()) > (nEndPos
= rCmpArr
.End()) )
740 lcl_SetAttrPam( rPam
, nSttPos
, &nEndPos
, sal_True
);
745 static int lcl_SearchBackward( const SwTxtNode
& rTxtNd
, SwAttrCheckArr
& rCmpArr
,
748 xub_StrLen nEndPos
, nSttPos
;
749 rCmpArr
.SetNewSet( rTxtNd
, rPam
);
750 if( !rTxtNd
.HasHints() )
752 if( !rCmpArr
.Found() )
754 nEndPos
= rCmpArr
.GetNdEnd();
755 lcl_SetAttrPam( rPam
, rCmpArr
.GetNdStt(), &nEndPos
, sal_False
);
759 const SwpHints
& rHtArr
= rTxtNd
.GetSwpHints();
760 const SwTxtAttr
* pAttr
;
761 sal_uInt16 nPos
= rHtArr
.Count();
763 // if everything is already there then check with which it will be ended
764 if( rCmpArr
.Found() )
767 if( !rCmpArr
.SetAttrBwd( *( pAttr
= rHtArr
.GetEnd( --nPos
)) ) )
769 nSttPos
= *pAttr
->GetAnyEnd();
770 if( nSttPos
< rCmpArr
.GetNdEnd() )
773 nEndPos
= rCmpArr
.GetNdEnd();
774 lcl_SetAttrPam( rPam
, nSttPos
, &nEndPos
, sal_False
);
782 if( !nPos
&& rCmpArr
.Found() )
785 nEndPos
= rCmpArr
.GetNdEnd();
786 lcl_SetAttrPam( rPam
, rCmpArr
.GetNdStt(), &nEndPos
, sal_False
);
792 if( rCmpArr
.SetAttrBwd( *( pAttr
= rHtArr
.GetEnd( --nPos
)) ) )
794 // Do multiple start at that position? Do also check those:
797 nEndPos
= *pAttr
->GetAnyEnd();
798 while( --nPos
&& nEndPos
==
799 *( pAttr
= rHtArr
.GetEnd( nPos
))->GetAnyEnd() &&
800 rCmpArr
.SetAttrBwd( *pAttr
) )
803 if( !rCmpArr
.Found() )
806 // then we have our search area
807 if( (nSttPos
= rCmpArr
.Start()) > (nEndPos
= rCmpArr
.End()) )
809 lcl_SetAttrPam( rPam
, nSttPos
, &nEndPos
, sal_False
);
813 if( !rCmpArr
.CheckStack() ||
814 (nSttPos
= rCmpArr
.Start()) > (nEndPos
= rCmpArr
.End()) )
816 lcl_SetAttrPam( rPam
, nSttPos
, &nEndPos
, sal_False
);
821 static int lcl_Search( const SwCntntNode
& rCNd
, const SfxItemSet
& rCmpSet
, sal_Bool bNoColls
)
823 // search only hard attribution?
824 if( bNoColls
&& !rCNd
.HasSwAttrSet() )
827 const SfxItemSet
& rNdSet
= rCNd
.GetSwAttrSet();
828 SfxItemIter
aIter( rCmpSet
);
829 const SfxPoolItem
* pItem
= aIter
.GetCurItem();
830 const SfxPoolItem
* pNdItem
;
835 if( IsInvalidItem( pItem
))
837 nWhich
= rCmpSet
.GetWhichByPos( aIter
.GetCurPos() );
838 if( SFX_ITEM_SET
!= rNdSet
.GetItemState( nWhich
, !bNoColls
, &pNdItem
)
839 || CmpAttr( *pNdItem
, rNdSet
.GetPool()->GetDefaultItem( nWhich
) ))
844 nWhich
= pItem
->Which();
846 if( !CmpAttr( rNdSet
.Get( nWhich
, !bNoColls
), *pItem
))
850 if( aIter
.IsAtEnd() )
852 pItem
= aIter
.NextItem();
854 return sal_True
; // found
858 sal_Bool
SwPaM::Find( const SfxPoolItem
& rAttr
, sal_Bool bValue
, SwMoveFn fnMove
,
859 const SwPaM
*pRegion
, sal_Bool bInReadOnly
)
861 // determine which attribute is searched:
862 sal_uInt16 nWhich
= rAttr
.Which();
863 int bCharAttr
= isCHRATR(nWhich
) || isTXTATR(nWhich
);
865 SwPaM
* pPam
= MakeRegion( fnMove
, pRegion
);
867 sal_Bool bFound
= sal_False
;
868 sal_Bool bFirst
= sal_True
;
869 sal_Bool bSrchForward
= fnMove
== fnMoveForward
;
871 const SfxPoolItem
* pItem
;
874 // if at beginning/end then move it out of the node
876 ? pPam
->GetPoint()->nContent
.GetIndex() == pPam
->GetCntntNode()->Len()
877 : !pPam
->GetPoint()->nContent
.GetIndex() )
879 if( !(*fnMove
->fnNds
)( &pPam
->GetPoint()->nNode
, sal_False
))
884 SwCntntNode
*pNd
= pPam
->GetCntntNode();
885 xub_StrLen nTmpPos
= bSrchForward
? 0 : pNd
->Len();
886 pPam
->GetPoint()->nContent
.Assign( pNd
, nTmpPos
);
889 while( 0 != ( pNode
= ::GetNode( *pPam
, bFirst
, fnMove
, bInReadOnly
) ) )
893 if( !pNode
->IsTxtNode() ) // CharAttr are only in text nodes
896 if( ((SwTxtNode
*)pNode
)->HasHints() &&
897 lcl_Search( *(SwTxtNode
*)pNode
, *pPam
, rAttr
, fnMove
, bValue
))
899 // set to the values of the attribute
901 *GetPoint() = *pPam
->GetPoint();
902 *GetMark() = *pPam
->GetMark();
906 else if (isTXTATR(nWhich
))
910 // no hard attribution, so check if node was asked for this attr before
911 if( !pNode
->HasSwAttrSet() )
913 SwFmt
* pTmpFmt
= pNode
->GetFmtColl();
914 if( aFmtArr
.find( pTmpFmt
) != aFmtArr
.end() )
915 continue; // collection was requested earlier
916 aFmtArr
.insert( pTmpFmt
);
919 if( SFX_ITEM_SET
== pNode
->GetSwAttrSet().GetItemState( nWhich
,
920 sal_True
, &pItem
) && ( !bValue
|| *pItem
== rAttr
) )
922 // FORWARD: SPoint at the end, GetMark at the beginning of the node
923 // BACKWARD: SPoint at the beginning, GetMark at the end of the node
924 // always: incl. start and incl. end
925 *GetPoint() = *pPam
->GetPoint();
927 pNode
->MakeEndIndex( &GetPoint()->nContent
);
933 // if backward search, switch point and mark
934 if( bFound
&& !bSrchForward
)
942 typedef int (*FnSearchAttr
)( const SwTxtNode
&, SwAttrCheckArr
&, SwPaM
& );
944 sal_Bool
SwPaM::Find( const SfxItemSet
& rSet
, sal_Bool bNoColls
, SwMoveFn fnMove
,
945 const SwPaM
*pRegion
, sal_Bool bInReadOnly
, sal_Bool bMoveFirst
)
947 SwPaM
* pPam
= MakeRegion( fnMove
, pRegion
);
949 sal_Bool bFound
= sal_False
;
950 sal_Bool bFirst
= sal_True
;
951 sal_Bool bSrchForward
= fnMove
== fnMoveForward
;
955 // check which text/char attributes are searched
956 SwAttrCheckArr
aCmpArr( rSet
, bSrchForward
, bNoColls
);
957 SfxItemSet
aOtherSet( GetDoc()->GetAttrPool(),
958 RES_PARATR_BEGIN
, RES_GRFATR_END
-1 );
959 aOtherSet
.Put( rSet
, sal_False
); // got all invalid items
961 FnSearchAttr fnSearch
= bSrchForward
962 ? (&::lcl_SearchForward
)
963 : (&::lcl_SearchBackward
);
965 // if at beginning/end then move it out of the node
968 ? pPam
->GetPoint()->nContent
.GetIndex() == pPam
->GetCntntNode()->Len()
969 : !pPam
->GetPoint()->nContent
.GetIndex() ) )
971 if( !(*fnMove
->fnNds
)( &pPam
->GetPoint()->nNode
, sal_False
))
976 SwCntntNode
*pNd
= pPam
->GetCntntNode();
977 xub_StrLen nTmpPos
= bSrchForward
? 0 : pNd
->Len();
978 pPam
->GetPoint()->nContent
.Assign( pNd
, nTmpPos
);
982 while( 0 != ( pNode
= ::GetNode( *pPam
, bFirst
, fnMove
, bInReadOnly
) ) )
984 if( aCmpArr
.Count() )
986 if( !pNode
->IsTxtNode() ) // CharAttr are only in text nodes
989 if( (!aOtherSet
.Count() ||
990 lcl_Search( *pNode
, aOtherSet
, bNoColls
)) &&
991 (*fnSearch
)( *(SwTxtNode
*)pNode
, aCmpArr
, *pPam
))
993 // set to the values of the attribute
995 *GetPoint() = *pPam
->GetPoint();
996 *GetMark() = *pPam
->GetMark();
1000 continue; // text attribute
1003 if( !aOtherSet
.Count() )
1006 // no hard attribution, so check if node was asked for this attr before
1007 if( !pNode
->HasSwAttrSet() )
1009 SwFmt
* pTmpFmt
= pNode
->GetFmtColl();
1010 if( aFmtArr
.find( pTmpFmt
) != aFmtArr
.end() )
1011 continue; // collection was requested earlier
1012 aFmtArr
.insert( pTmpFmt
);
1015 if( lcl_Search( *pNode
, aOtherSet
, bNoColls
))
1017 // FORWARD: SPoint at the end, GetMark at the beginning of the node
1018 // BACKWARD: SPoint at the beginning, GetMark at the end of the node
1019 // always: incl. start and incl. end
1020 *GetPoint() = *pPam
->GetPoint();
1022 pNode
->MakeEndIndex( &GetPoint()->nContent
);
1028 // if backward search, switch point and mark
1029 if( bFound
&& !bSrchForward
)
1036 /// parameters for search for attributes
1037 struct SwFindParaAttr
: public SwFindParas
1040 const SfxItemSet
*pSet
, *pReplSet
;
1041 const SearchOptions
*pSearchOpt
;
1043 utl::TextSearch
* pSTxt
;
1045 SwFindParaAttr( const SfxItemSet
& rSet
, sal_Bool bNoCollection
,
1046 const SearchOptions
* pOpt
, const SfxItemSet
* pRSet
,
1048 : bValue( bNoCollection
), pSet( &rSet
), pReplSet( pRSet
),
1049 pSearchOpt( pOpt
), rCursor( rCrsr
),pSTxt( 0 ) {}
1051 virtual ~SwFindParaAttr() { delete pSTxt
; }
1053 virtual int Find( SwPaM
* , SwMoveFn
, const SwPaM
*, sal_Bool bInReadOnly
);
1054 virtual int IsReplaceMode() const;
1058 int SwFindParaAttr::Find( SwPaM
* pCrsr
, SwMoveFn fnMove
, const SwPaM
* pRegion
,
1059 sal_Bool bInReadOnly
)
1061 // replace string (only if text given and search is not parameterized)?
1062 sal_Bool bReplaceTxt
= pSearchOpt
&& ( !pSearchOpt
->replaceString
.isEmpty() ||
1064 sal_Bool bReplaceAttr
= pReplSet
&& pReplSet
->Count();
1065 sal_Bool bMoveFirst
= !bReplaceAttr
;
1066 if( bInReadOnly
&& (bReplaceAttr
|| bReplaceTxt
))
1067 bInReadOnly
= sal_False
;
1069 // We search for attributes, should we search for text as well?
1071 SwPaM
aRegion( *pRegion
->GetMark(), *pRegion
->GetPoint() );
1072 SwPaM
* pTextRegion
= &aRegion
;
1073 SwPaM
aSrchPam( *pCrsr
->GetPoint() );
1077 if( pSet
->Count() ) // any attributes?
1080 if( !aSrchPam
.Find( *pSet
, bValue
, fnMove
, &aRegion
, bInReadOnly
, bMoveFirst
) )
1081 return FIND_NOT_FOUND
;
1082 bMoveFirst
= sal_True
;
1085 break; // ok, only attributes, so found
1087 pTextRegion
= &aSrchPam
;
1089 else if( !pSearchOpt
)
1090 return FIND_NOT_FOUND
;
1092 // then search in text of it
1095 SearchOptions
aTmp( *pSearchOpt
);
1097 // search in selection
1098 aTmp
.searchFlag
|= (SearchFlags::REG_NOT_BEGINOFLINE
|
1099 SearchFlags::REG_NOT_ENDOFLINE
);
1101 aTmp
.Locale
= SvtSysLocale().GetLanguageTag().getLocale();
1103 pSTxt
= new utl::TextSearch( aTmp
);
1106 // TODO: searching for attributes in Outliner text?!
1107 sal_Bool bSearchInNotes
= sal_False
;
1109 // continue search in correct section (pTextRegion)
1110 if( aSrchPam
.Find( *pSearchOpt
, bSearchInNotes
, *pSTxt
, fnMove
, pTextRegion
, bInReadOnly
) &&
1111 *aSrchPam
.GetMark() != *aSrchPam
.GetPoint() )
1113 else if( !pSet
->Count() )
1114 return FIND_NOT_FOUND
; // only text and nothing found
1116 *aRegion
.GetMark() = *aSrchPam
.GetPoint();
1119 *pCrsr
->GetPoint() = *aSrchPam
.GetPoint();
1121 *pCrsr
->GetMark() = *aSrchPam
.GetMark();
1127 SearchAlgorithms_REGEXP
== pSearchOpt
->algorithmType
);
1128 SwIndex
& rSttCntIdx
= pCrsr
->Start()->nContent
;
1129 xub_StrLen nSttCnt
= rSttCntIdx
.GetIndex();
1131 // add to shell-cursor-ring so that the regions will be moved enventually
1132 Ring
*pPrevRing
= 0;
1135 pPrevRing
= pRegion
->GetPrev();
1136 ((Ring
*)pRegion
)->MoveRingTo( &rCursor
);
1139 ::std::auto_ptr
<String
> pRepl( (bRegExp
) ?
1140 ReplaceBackReferences( *pSearchOpt
, pCrsr
) : 0 );
1141 rCursor
.GetDoc()->ReplaceRange( *pCrsr
,
1142 (pRepl
.get()) ? *pRepl
: String(pSearchOpt
->replaceString
),
1144 rCursor
.SaveTblBoxCntnt( pCrsr
->GetPoint() );
1148 // and remove region again
1149 Ring
*p
, *pNext
= (Ring
*)pRegion
;
1152 pNext
= p
->GetNext();
1153 p
->MoveTo( (Ring
*)pRegion
);
1154 } while( p
!= pPrevRing
);
1156 rSttCntIdx
= nSttCnt
;
1161 // is the selection still existent?
1162 // all searched attributes are reset to default if
1163 // they are not in ReplaceSet
1164 if( !pSet
->Count() )
1166 pCrsr
->GetDoc()->InsertItemSet( *pCrsr
, *pReplSet
, 0 );
1170 SfxItemPool
* pPool
= pReplSet
->GetPool();
1171 SfxItemSet
aSet( *pPool
, pReplSet
->GetRanges() );
1173 SfxItemIter
aIter( *pSet
);
1174 const SfxPoolItem
* pItem
= aIter
.GetCurItem();
1177 // reset all that are not set with pool defaults
1178 if( !IsInvalidItem( pItem
) && SFX_ITEM_SET
!=
1179 pReplSet
->GetItemState( pItem
->Which(), sal_False
))
1180 aSet
.Put( pPool
->GetDefaultItem( pItem
->Which() ));
1182 if( aIter
.IsAtEnd() )
1184 pItem
= aIter
.NextItem();
1186 aSet
.Put( *pReplSet
);
1187 pCrsr
->GetDoc()->InsertItemSet( *pCrsr
, aSet
, 0 );
1190 return FIND_NO_RING
;
1198 int SwFindParaAttr::IsReplaceMode() const
1200 return ( pSearchOpt
&& !pSearchOpt
->replaceString
.isEmpty() ) ||
1201 ( pReplSet
&& pReplSet
->Count() );
1204 /// search for attributes
1205 sal_uLong
SwCursor::Find( const SfxItemSet
& rSet
, sal_Bool bNoCollections
,
1206 SwDocPositions nStart
, SwDocPositions nEnd
,
1207 sal_Bool
& bCancel
, FindRanges eFndRngs
,
1208 const SearchOptions
* pSearchOpt
,
1209 const SfxItemSet
* pReplSet
)
1211 // switch off OLE-notifications
1212 SwDoc
* pDoc
= GetDoc();
1213 Link
aLnk( pDoc
->GetOle2Link() );
1214 pDoc
->SetOle2Link( Link() );
1216 sal_Bool bReplace
= ( pSearchOpt
&& ( !pSearchOpt
->replaceString
.isEmpty() ||
1217 !rSet
.Count() ) ) ||
1218 (pReplSet
&& pReplSet
->Count());
1219 bool const bStartUndo
= pDoc
->GetIDocumentUndoRedo().DoesUndo() && bReplace
;
1222 pDoc
->GetIDocumentUndoRedo().StartUndo( UNDO_REPLACE
, NULL
);
1225 SwFindParaAttr
aSwFindParaAttr( rSet
, bNoCollections
, pSearchOpt
,
1228 sal_uLong nRet
= FindAll( aSwFindParaAttr
, nStart
, nEnd
, eFndRngs
, bCancel
);
1229 pDoc
->SetOle2Link( aLnk
);
1230 if( nRet
&& bReplace
)
1231 pDoc
->SetModified();
1235 pDoc
->GetIDocumentUndoRedo().EndUndo( UNDO_REPLACE
, NULL
);
1243 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */