1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: findattr.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include <com/sun/star/lang/Locale.hpp>
36 #include <com/sun/star/util/SearchOptions.hpp>
37 #include <com/sun/star/util/SearchFlags.hpp>
38 #include <i18npool/mslangid.hxx>
39 #include <hintids.hxx>
40 #include <vcl/svapp.hxx>
41 #include <svtools/itemiter.hxx>
42 #include <svtools/whiter.hxx>
43 #include <svx/brkitem.hxx>
44 #include <svx/colritem.hxx>
45 #include <svx/fontitem.hxx>
46 #include <fmtpdsc.hxx>
47 #include <txatbase.hxx>
48 #include <fchrfmt.hxx>
49 #include <charfmt.hxx>
56 #include <crsskip.hxx>
59 using namespace ::com::sun::star
;
60 using namespace ::com::sun::star::lang
;
61 using namespace ::com::sun::star::util
;
63 SV_DECL_PTRARR_SORT( SwpFmts
, SwFmt
*, 0, 4 )
64 SV_IMPL_PTRARR_SORT( SwpFmts
, SwFmt
* )
66 // Sonderbehandlung fuer SvxFontItem, nur den Namen vergleichen:
67 int CmpAttr( const SfxPoolItem
& rItem1
, const SfxPoolItem
& rItem2
)
69 switch( rItem1
.Which() )
72 return ((SvxFontItem
&)rItem1
).GetFamilyName() ==
73 ((SvxFontItem
&)rItem2
).GetFamilyName();
75 case RES_CHRATR_COLOR
:
76 return ((SvxColorItem
&)rItem1
).GetValue().IsRGBEqual(
77 ((SvxColorItem
&)rItem2
).GetValue() );
79 return ((SwFmtPageDesc
&)rItem1
).GetNumOffset() ==
80 ((SwFmtPageDesc
&)rItem2
).GetNumOffset() &&
81 ((SwFmtPageDesc
&)rItem1
).GetPageDesc() ==
82 ((SwFmtPageDesc
&)rItem2
).GetPageDesc();
84 return rItem1
== rItem2
;
88 const SwTxtAttr
* GetFrwrdTxtHint( const SwpHints
& rHtsArr
, USHORT
& rPos
,
89 xub_StrLen nCntntPos
)
91 while( rPos
< rHtsArr
.Count() )
93 const SwTxtAttr
*pTxtHt
= rHtsArr
.GetStart( rPos
++ );
94 // der Start vom Attribut muss innerhalb des Bereiches liegen !!
95 if( *pTxtHt
->GetStart() >= nCntntPos
)
96 return pTxtHt
; // gueltiges TextAttribut
98 return 0; // kein gueltiges TextAttribut
102 const SwTxtAttr
* GetBkwrdTxtHint( const SwpHints
& rHtsArr
, USHORT
& rPos
,
103 xub_StrLen nCntntPos
)
107 //Hack mit cast fuer das Update
108 const SwTxtAttr
*pTxtHt
= rHtsArr
.GetStart( --rPos
);
109 // der Start vom Attribut muss innerhalb des Bereiches liegen !!
110 if( *pTxtHt
->GetStart() < nCntntPos
)
111 return pTxtHt
; // gueltiges TextAttribut
113 return 0; // kein gueltiges TextAttribut
117 void lcl_SetAttrPam( SwPaM
& rPam
, xub_StrLen nStart
, const xub_StrLen
* pEnde
,
118 const BOOL bSaveMark
)
120 xub_StrLen nCntntPos
;
122 nCntntPos
= rPam
.GetMark()->nContent
.GetIndex();
124 nCntntPos
= rPam
.GetPoint()->nContent
.GetIndex();
125 BOOL bTstEnde
= rPam
.GetPoint()->nNode
== rPam
.GetMark()->nNode
;
127 SwCntntNode
* pCNd
= rPam
.GetCntntNode();
128 rPam
.GetPoint()->nContent
.Assign( pCNd
, nStart
);
129 rPam
.SetMark(); // Point == GetMark
131 // Point zeigt auf das Ende vom SuchBereich oder Ende vom Attribut
134 if( bTstEnde
&& *pEnde
> nCntntPos
)
135 rPam
.GetPoint()->nContent
= nCntntPos
;
137 rPam
.GetPoint()->nContent
= *pEnde
;
141 //------------------ Suche nach einem Text Attribut -----------------------
143 // diese Funktion sucht in einem TextNode nach dem vorgegebenen Attribut.
144 // Wird es gefunden, dann hat der SwPaM den Bereich der das Attribut
145 // umspannt, unter Beachtung des Suchbereiches
148 BOOL
lcl_Search( const SwTxtNode
& rTxtNd
, SwPaM
& rPam
,
149 const SfxPoolItem
& rCmpItem
,
150 SwMoveFn fnMove
, BOOL bValue
)
152 if ( !rTxtNd
.HasHints() )
154 const SwTxtAttr
*pTxtHt
= 0;
155 BOOL bForward
= fnMove
== fnMoveForward
;
156 USHORT nPos
= bForward
? 0 : rTxtNd
.GetSwpHints().Count();
157 xub_StrLen nCntntPos
= rPam
.GetPoint()->nContent
.GetIndex();
159 while( 0 != ( pTxtHt
=(*fnMove
->fnGetHint
)(rTxtNd
.GetSwpHints(),nPos
,nCntntPos
)))
160 if( pTxtHt
->Which() == rCmpItem
.Which() &&
161 ( !bValue
|| CmpAttr( pTxtHt
->GetAttr(), rCmpItem
)))
163 lcl_SetAttrPam( rPam
, *pTxtHt
->GetStart(), pTxtHt
->GetEnd(), bForward
);
170 //------------------ Suche nach mehren Text Attributen -------------------
172 struct _SwSrchChrAttr
175 xub_StrLen nStt
, nEnd
;
177 _SwSrchChrAttr( const SfxPoolItem
& rItem
,
178 xub_StrLen nStart
, xub_StrLen nAnyEnd
)
179 : nWhich( rItem
.Which() ), nStt( nStart
), nEnd( nAnyEnd
)
185 _SwSrchChrAttr
*pFndArr
, *pStackArr
;
186 xub_StrLen nNdStt
, nNdEnd
;
187 USHORT nArrStart
, nArrLen
;
188 USHORT nFound
, nStackCnt
;
194 SwAttrCheckArr( const SfxItemSet
& rSet
, int bForward
, int bNoCollections
);
197 void SetNewSet( const SwTxtNode
& rTxtNd
, const SwPaM
& rPam
);
199 // wieviele Attribute ueberhaupt ??
200 USHORT
Count() const { return aCmpSet
.Count(); }
201 int Found() const { return nFound
== aCmpSet
.Count(); }
204 xub_StrLen
Start() const;
205 xub_StrLen
End() const;
207 xub_StrLen
GetNdStt() const { return nNdStt
; }
208 xub_StrLen
GetNdEnd() const { return nNdEnd
; }
210 int SetAttrFwd( const SwTxtAttr
& rAttr
);
211 int SetAttrBwd( const SwTxtAttr
& rAttr
);
216 SwAttrCheckArr::SwAttrCheckArr( const SfxItemSet
& rSet
, int bFwd
,
218 : aCmpSet( *rSet
.GetPool(), RES_CHRATR_BEGIN
, RES_TXTATR_END
-1 )
220 aCmpSet
.Put( rSet
, FALSE
);
221 bNoColls
= 0 != bNoCollections
;
223 bForward
= 0 != bFwd
;
225 // Bestimmen den Bereich des Fnd/Stack-Arrays (Min/Max)
226 SfxItemIter
aIter( aCmpSet
);
227 nArrStart
= aCmpSet
.GetWhichByPos( aIter
.GetFirstPos() );
228 nArrLen
= aCmpSet
.GetWhichByPos( aIter
.GetLastPos() ) - nArrStart
+1;
230 char* pFndChar
= new char[ nArrLen
* sizeof(_SwSrchChrAttr
) ];
231 char* pStackChar
= new char[ nArrLen
* sizeof(_SwSrchChrAttr
) ];
233 pFndArr
= (_SwSrchChrAttr
*)pFndChar
;
234 pStackArr
= (_SwSrchChrAttr
*)pStackChar
;
237 SwAttrCheckArr::~SwAttrCheckArr()
239 delete[] (char*)pFndArr
;
240 delete[] (char*)pStackArr
;
243 void SwAttrCheckArr::SetNewSet( const SwTxtNode
& rTxtNd
, const SwPaM
& rPam
)
245 memset( pFndArr
, 0, nArrLen
* sizeof(_SwSrchChrAttr
) );
246 memset( pStackArr
, 0, nArrLen
* sizeof(_SwSrchChrAttr
) );
252 nNdStt
= rPam
.GetPoint()->nContent
.GetIndex();
253 nNdEnd
= rPam
.GetPoint()->nNode
== rPam
.GetMark()->nNode
254 ? rPam
.GetMark()->nContent
.GetIndex()
255 : rTxtNd
.GetTxt().Len();
259 nNdEnd
= rPam
.GetPoint()->nContent
.GetIndex();
260 nNdStt
= rPam
.GetPoint()->nNode
== rPam
.GetMark()->nNode
261 ? rPam
.GetMark()->nContent
.GetIndex()
265 if( bNoColls
&& !rTxtNd
.HasSwAttrSet() )
268 const SfxItemSet
& rSet
= rTxtNd
.GetSwAttrSet();
269 // if( !rSet.Count() )
272 SfxItemIter
aIter( aCmpSet
);
273 const SfxPoolItem
* pItem
= aIter
.GetCurItem();
274 const SfxPoolItem
* pFndItem
;
279 // nur testen, ob vorhanden ist ?
280 if( IsInvalidItem( pItem
) )
282 nWhich
= aCmpSet
.GetWhichByPos( aIter
.GetCurPos() );
283 if( RES_TXTATR_END
<= nWhich
)
284 break; // Ende der TextAttribute
286 if( SFX_ITEM_SET
== rSet
.GetItemState( nWhich
, !bNoColls
, &pFndItem
)
287 && !CmpAttr( *pFndItem
, rSet
.GetPool()->GetDefaultItem( nWhich
) ))
289 pFndArr
[ nWhich
- nArrStart
] =
290 _SwSrchChrAttr( *pFndItem
, nNdStt
, nNdEnd
);
296 if( RES_TXTATR_END
<= (nWhich
= pItem
->Which() ))
297 break; // Ende der TextAttribute
299 //JP 27.02.95: wenn nach defaults gesucht wird, dann muss man bis zum Pool
301 // if( SFX_ITEM_SET == rSet.GetItemState( nWhich, !bNoColls, &pFndItem )
302 // && *pFndItem == *pItem )
303 if( CmpAttr( rSet
.Get( nWhich
, !bNoColls
), *pItem
) )
305 pFndArr
[ nWhich
- nArrStart
] =
306 _SwSrchChrAttr( *pItem
, nNdStt
, nNdEnd
);
311 if( aIter
.IsAtEnd() )
313 pItem
= aIter
.NextItem();
316 int SwAttrCheckArr::SetAttrFwd( const SwTxtAttr
& rAttr
)
318 _SwSrchChrAttr
aTmp( rAttr
.GetAttr(), *rAttr
.GetStart(), *rAttr
.GetAnyEnd() );
319 // alle die nicht im Bereich sind -> ignorieren
320 if( aTmp
.nEnd
<= nNdStt
|| aTmp
.nStt
>= nNdEnd
)
323 const SfxPoolItem
* pItem
;
325 // --------------------------------------------------------------
326 // Hier wird jetzt ausdruecklich auch in Zeichenvorlagen gesucht
327 // --------------------------------------------------------------
328 USHORT nWhch
= rAttr
.Which();
329 SfxWhichIter
* pIter
= NULL
;
330 const SfxPoolItem
* pTmpItem
= NULL
;
331 const SfxItemSet
* pSet
= NULL
;
332 if( RES_TXTATR_CHARFMT
== nWhch
|| RES_TXTATR_AUTOFMT
== nWhch
)
334 if( bNoColls
&& RES_TXTATR_CHARFMT
== nWhch
)
337 pSet
= CharFmt::GetItemSet( rAttr
.GetAttr() );
340 pIter
= new SfxWhichIter( *pSet
);
341 nWhch
= pIter
->FirstWhich();
343 SFX_ITEM_SET
!= pSet
->GetItemState( nWhch
, TRUE
, &pTmpItem
) )
344 nWhch
= pIter
->NextWhich();
350 pTmpItem
= &rAttr
.GetAttr();
353 SfxItemState eState
= aCmpSet
.GetItemState( nWhch
, FALSE
, &pItem
);
354 if( SFX_ITEM_DONTCARE
== eState
|| SFX_ITEM_SET
== eState
)
357 _SwSrchChrAttr
* pCmp
;
359 // loesche erstmal alle, die bis zu der Start Position schon wieder
362 _SwSrchChrAttr
* pArrPtr
;
364 for( pArrPtr
= pFndArr
, n
= 0; n
< nArrLen
;
366 if( pArrPtr
->nWhich
&& pArrPtr
->nEnd
<= aTmp
.nStt
)
368 pArrPtr
->nWhich
= 0; // geloescht
372 // loesche erstmal alle, die bis zu der Start Position schon wieder
373 // ungueltig sind. Und verschiebe alle die "offen" sind, heisst ueber
374 // die Start Position ragen, vom Stack in den FndSet
377 for( pArrPtr
= pStackArr
, n
=0; n
< nArrLen
; ++n
, ++pArrPtr
)
379 if( !pArrPtr
->nWhich
)
382 if( pArrPtr
->nEnd
<= aTmp
.nStt
)
384 pArrPtr
->nWhich
= 0; // geloescht
388 else if( pArrPtr
->nStt
<= aTmp
.nStt
)
390 if( ( pCmp
= &pFndArr
[ n
])->nWhich
)
392 if( pCmp
->nEnd
< pArrPtr
->nEnd
) // erweitern
393 pCmp
->nEnd
= pArrPtr
->nEnd
;
406 BOOL bContinue
= FALSE
;
408 if( SFX_ITEM_DONTCARE
== eState
)
410 // wird Attribut gueltig ?
411 if( !CmpAttr( aCmpSet
.GetPool()->GetDefaultItem( nWhch
),
414 // suche das Attribut und erweiter es gegebenenfalls
415 if( !( pCmp
= &pFndArr
[ nWhch
- nArrStart
])->nWhich
)
417 *pCmp
= aTmp
; // nicht gefunden, eintragen
420 else if( pCmp
->nEnd
< aTmp
.nEnd
) // erweitern ?
421 pCmp
->nEnd
= aTmp
.nEnd
;
426 // wird Attribut gueltig ?
427 else if( CmpAttr( *pItem
, *pTmpItem
) )
429 pFndArr
[ nWhch
- nArrStart
] = aTmp
;
434 // tja, dann muss es auf den Stack
435 if( !bContinue
&& ( pCmp
= &pFndArr
[ nWhch
- nArrStart
])->nWhich
)
437 // vorhanden, auf den Stack. Aber nur wenn es noch grosser ist
438 if( pCmp
->nEnd
> aTmp
.nEnd
)
440 ASSERT( !pStackArr
[ nWhch
- nArrStart
].nWhich
,
441 "Stack-Platz ist noch belegt" );
444 // JP 22.08.96: nur Ende manipulieren reicht nicht. Bug 30547
445 // pCmp->nStt = aTmp.nEnd;
446 if( aTmp
.nStt
<= pCmp
->nStt
)
447 pCmp
->nStt
= aTmp
.nEnd
;
449 pCmp
->nEnd
= aTmp
.nStt
;
452 pStackArr
[ nWhch
- nArrStart
] = *pCmp
;
461 nWhch
= pIter
->NextWhich();
463 SFX_ITEM_SET
!= pSet
->GetItemState( nWhch
, TRUE
, &pTmpItem
) )
464 nWhch
= pIter
->NextWhich();
475 int SwAttrCheckArr::SetAttrBwd( const SwTxtAttr
& rAttr
)
477 _SwSrchChrAttr
aTmp( rAttr
.GetAttr(), *rAttr
.GetStart(), *rAttr
.GetAnyEnd() );
478 // alle die nicht im Bereich sind -> ignorieren
479 if( aTmp
.nEnd
< nNdStt
|| aTmp
.nStt
>= nNdEnd
)
482 const SfxPoolItem
* pItem
;
483 // --------------------------------------------------------------
484 // Hier wird jetzt ausdruecklich auch in Zeichenvorlagen gesucht
485 // --------------------------------------------------------------
486 USHORT nWhch
= rAttr
.Which();
487 SfxWhichIter
* pIter
= NULL
;
488 const SfxPoolItem
* pTmpItem
= NULL
;
489 const SfxItemSet
* pSet
= NULL
;
490 if( RES_TXTATR_CHARFMT
== nWhch
|| RES_TXTATR_AUTOFMT
== nWhch
)
492 if( bNoColls
&& RES_TXTATR_CHARFMT
== nWhch
)
495 pSet
= CharFmt::GetItemSet( rAttr
.GetAttr() );
498 pIter
= new SfxWhichIter( *pSet
);
499 nWhch
= pIter
->FirstWhich();
501 SFX_ITEM_SET
!= pSet
->GetItemState( nWhch
, TRUE
, &pTmpItem
) )
502 nWhch
= pIter
->NextWhich();
508 pTmpItem
= &rAttr
.GetAttr();
511 SfxItemState eState
= aCmpSet
.GetItemState( nWhch
, FALSE
, &pItem
);
512 if( SFX_ITEM_DONTCARE
== eState
|| SFX_ITEM_SET
== eState
)
515 _SwSrchChrAttr
* pCmp
;
517 // loesche erstmal alle, die bis zu der Start Position schon wieder
520 _SwSrchChrAttr
* pArrPtr
;
522 for( pArrPtr
= pFndArr
, n
= 0; n
< nArrLen
; ++n
, ++pArrPtr
)
523 if( pArrPtr
->nWhich
&& pArrPtr
->nStt
>= aTmp
.nEnd
)
525 pArrPtr
->nWhich
= 0; // geloescht
529 // loesche erstmal alle, die bis zu der Start Position schon wieder
530 // ungueltig sind. Und verschiebe alle die "offen" sind, heisst ueber
531 // die Start Position ragen, vom Stack in den FndSet
534 for( pArrPtr
= pStackArr
, n
= 0; n
< nArrLen
; ++n
, ++pArrPtr
)
536 if( !pArrPtr
->nWhich
)
539 if( pArrPtr
->nStt
>= aTmp
.nEnd
)
541 pArrPtr
->nWhich
= 0; // geloescht
545 else if( pArrPtr
->nEnd
>= aTmp
.nEnd
)
547 if( ( pCmp
= &pFndArr
[ n
])->nWhich
)
549 if( pCmp
->nStt
> pArrPtr
->nStt
) // erweitern
550 pCmp
->nStt
= pArrPtr
->nStt
;
563 BOOL bContinue
= FALSE
;
564 if( SFX_ITEM_DONTCARE
== eState
)
566 // wird Attribut gueltig ?
567 if( !CmpAttr( aCmpSet
.GetPool()->GetDefaultItem( nWhch
),
570 // suche das Attribut und erweiter es gegebenenfalls
571 if( !( pCmp
= &pFndArr
[ nWhch
- nArrStart
])->nWhich
)
573 *pCmp
= aTmp
; // nicht gefunden, eintragen
576 else if( pCmp
->nStt
> aTmp
.nStt
) // erweitern ?
577 pCmp
->nStt
= aTmp
.nStt
;
582 // wird Attribut gueltig ?
583 else if( CmpAttr( *pItem
, *pTmpItem
))
585 pFndArr
[ nWhch
- nArrStart
] = aTmp
;
590 // tja, dann muss es auf den Stack
591 if( !bContinue
&& ( pCmp
= &pFndArr
[ nWhch
- nArrStart
])->nWhich
)
593 // vorhanden, auf den Stack. Aber nur wenn es noch grosser ist
594 if( pCmp
->nStt
< aTmp
.nStt
)
596 ASSERT( !pStackArr
[ nWhch
- nArrStart
].nWhich
,
597 "Stack-Platz ist noch belegt" );
600 // JP 22.08.96: nur Ende manipulieren reicht nicht. Bug 30547
601 // pCmp->nEnd = aTmp.nStt;
602 if( aTmp
.nEnd
<= pCmp
->nEnd
)
603 pCmp
->nEnd
= aTmp
.nStt
;
605 pCmp
->nStt
= aTmp
.nEnd
;
608 pStackArr
[ nWhch
- nArrStart
] = *pCmp
;
617 nWhch
= pIter
->NextWhich();
619 SFX_ITEM_SET
!= pSet
->GetItemState( nWhch
, TRUE
, &pTmpItem
) )
620 nWhch
= pIter
->NextWhich();
631 xub_StrLen
SwAttrCheckArr::Start() const
633 xub_StrLen nStart
= nNdStt
;
634 _SwSrchChrAttr
* pArrPtr
= pFndArr
;
635 for( USHORT n
= 0; n
< nArrLen
; ++n
, ++pArrPtr
)
636 if( pArrPtr
->nWhich
&& pArrPtr
->nStt
> nStart
)
637 nStart
= pArrPtr
->nStt
;
643 xub_StrLen
SwAttrCheckArr::End() const
645 _SwSrchChrAttr
* pArrPtr
= pFndArr
;
646 xub_StrLen nEnd
= nNdEnd
;
647 for( USHORT n
= 0; n
< nArrLen
; ++n
, ++pArrPtr
)
648 if( pArrPtr
->nWhich
&& pArrPtr
->nEnd
< nEnd
)
649 nEnd
= pArrPtr
->nEnd
;
655 int SwAttrCheckArr::CheckStack()
661 xub_StrLen nSttPos
= Start(), nEndPos
= End();
662 _SwSrchChrAttr
* pArrPtr
;
663 for( pArrPtr
= pStackArr
, n
= 0; n
< nArrLen
; ++n
, ++pArrPtr
)
665 if( !pArrPtr
->nWhich
)
668 if( bForward
? pArrPtr
->nEnd
<= nSttPos
: pArrPtr
->nStt
>= nEndPos
)
670 pArrPtr
->nWhich
= 0; // geloescht
672 return nFound
== aCmpSet
.Count();
674 else if( bForward
? pArrPtr
->nStt
< nEndPos
: pArrPtr
->nEnd
> nSttPos
)
676 // alle die "offen" sind, heisst ueber die Start Position ragen,
678 ASSERT( !pFndArr
[ n
].nWhich
, "Array-Platz ist noch belegt" );
679 pFndArr
[ n
] = *pArrPtr
;
683 return nFound
== aCmpSet
.Count();
686 return nFound
== aCmpSet
.Count();
691 int lcl_SearchForward( const SwTxtNode
& rTxtNd
, SwAttrCheckArr
& rCmpArr
,
694 xub_StrLen nEndPos
, nSttPos
;
695 rCmpArr
.SetNewSet( rTxtNd
, rPam
);
696 if( !rTxtNd
.HasHints() )
698 if( !rCmpArr
.Found() )
700 nEndPos
= rCmpArr
.GetNdEnd();
701 lcl_SetAttrPam( rPam
, rCmpArr
.GetNdStt(), &nEndPos
, TRUE
);
705 // dann gehe mal durch das nach "Start" sortierte Array
706 const SwpHints
& rHtArr
= rTxtNd
.GetSwpHints();
707 const SwTxtAttr
* pAttr
;
710 // sollte jetzt schon alles vorhanden sein, dann teste, mit welchem
711 // das wieder beendet wird.
712 if( rCmpArr
.Found() )
714 for( ; nPos
< rHtArr
.Count(); ++nPos
)
715 if( !rCmpArr
.SetAttrFwd( *( pAttr
= rHtArr
.GetStart( nPos
)) ) )
717 if( rCmpArr
.GetNdStt() < *pAttr
->GetStart() )
719 // dann haben wir unser Ende:
720 lcl_SetAttrPam( rPam
, rCmpArr
.GetNdStt(),
721 pAttr
->GetStart(), TRUE
);
724 // ansonsten muessen wir weiter suchen
728 if( nPos
== rHtArr
.Count() && rCmpArr
.Found() )
730 // dann haben wir unseren Bereich
731 nEndPos
= rCmpArr
.GetNdEnd();
732 lcl_SetAttrPam( rPam
, rCmpArr
.GetNdStt(), &nEndPos
, TRUE
);
737 for( ; nPos
< rHtArr
.Count(); ++nPos
)
738 if( rCmpArr
.SetAttrFwd( *( pAttr
= rHtArr
.GetStart( nPos
)) ) )
740 // sollten noch mehr auf der gleichen Position anfangen ??
741 // auch die noch mit testen !!
742 nSttPos
= *pAttr
->GetStart();
743 while( ++nPos
< rHtArr
.Count() && nSttPos
==
744 *( pAttr
= rHtArr
.GetStart( nPos
))->GetStart() &&
745 rCmpArr
.SetAttrFwd( *pAttr
) )
747 if( !rCmpArr
.Found() )
750 // dann haben wir den Bereich zusammen
751 if( (nSttPos
= rCmpArr
.Start()) > (nEndPos
= rCmpArr
.End()) )
753 lcl_SetAttrPam( rPam
, nSttPos
, &nEndPos
, TRUE
);
757 if( !rCmpArr
.CheckStack() ||
758 (nSttPos
= rCmpArr
.Start()) > (nEndPos
= rCmpArr
.End()) )
760 lcl_SetAttrPam( rPam
, nSttPos
, &nEndPos
, TRUE
);
765 int lcl_SearchBackward( const SwTxtNode
& rTxtNd
, SwAttrCheckArr
& rCmpArr
,
768 xub_StrLen nEndPos
, nSttPos
;
769 rCmpArr
.SetNewSet( rTxtNd
, rPam
);
770 if( !rTxtNd
.HasHints() )
772 if( !rCmpArr
.Found() )
774 nEndPos
= rCmpArr
.GetNdEnd();
775 lcl_SetAttrPam( rPam
, rCmpArr
.GetNdStt(), &nEndPos
, FALSE
);
779 // dann gehe mal durch das nach "Start" sortierte Array
780 const SwpHints
& rHtArr
= rTxtNd
.GetSwpHints();
781 const SwTxtAttr
* pAttr
;
782 USHORT nPos
= rHtArr
.Count();
784 // sollte jetzt schon alles vorhanden sein, dann teste, mit welchem
785 // das wieder beendet wird.
786 if( rCmpArr
.Found() )
789 if( !rCmpArr
.SetAttrBwd( *( pAttr
= rHtArr
.GetEnd( --nPos
)) ) )
791 nSttPos
= *pAttr
->GetAnyEnd();
792 if( nSttPos
< rCmpArr
.GetNdEnd() )
794 // dann haben wir unser Ende:
795 nEndPos
= rCmpArr
.GetNdEnd();
796 lcl_SetAttrPam( rPam
, nSttPos
, &nEndPos
, FALSE
);
800 // ansonsten muessen wir weiter suchen
804 if( !nPos
&& rCmpArr
.Found() )
806 // dann haben wir unseren Bereich
807 nEndPos
= rCmpArr
.GetNdEnd();
808 lcl_SetAttrPam( rPam
, rCmpArr
.GetNdStt(), &nEndPos
, FALSE
);
814 if( rCmpArr
.SetAttrBwd( *( pAttr
= rHtArr
.GetEnd( --nPos
)) ) )
816 // sollten noch mehr auf der gleichen Position anfangen ??
817 // auch die noch mit testen !!
820 nEndPos
= *pAttr
->GetAnyEnd();
821 while( --nPos
&& nEndPos
==
822 *( pAttr
= rHtArr
.GetEnd( nPos
))->GetAnyEnd() &&
823 rCmpArr
.SetAttrBwd( *pAttr
) )
826 if( !rCmpArr
.Found() )
830 // dann haben wir den Bereich zusammen
831 if( (nSttPos
= rCmpArr
.Start()) > (nEndPos
= rCmpArr
.End()) )
833 lcl_SetAttrPam( rPam
, nSttPos
, &nEndPos
, FALSE
);
837 if( !rCmpArr
.CheckStack() ||
838 (nSttPos
= rCmpArr
.Start()) > (nEndPos
= rCmpArr
.End()) )
840 lcl_SetAttrPam( rPam
, nSttPos
, &nEndPos
, FALSE
);
845 int lcl_Search( const SwCntntNode
& rCNd
, const SfxItemSet
& rCmpSet
, BOOL bNoColls
)
847 // nur die harte Attributierung suchen ?
848 if( bNoColls
&& !rCNd
.HasSwAttrSet() )
851 const SfxItemSet
& rNdSet
= rCNd
.GetSwAttrSet();
852 SfxItemIter
aIter( rCmpSet
);
853 const SfxPoolItem
* pItem
= aIter
.GetCurItem();
854 const SfxPoolItem
* pNdItem
;
859 // nur testen, ob vorhanden ist ?
860 if( IsInvalidItem( pItem
))
862 nWhich
= rCmpSet
.GetWhichByPos( aIter
.GetCurPos() );
863 if( SFX_ITEM_SET
!= rNdSet
.GetItemState( nWhich
, !bNoColls
, &pNdItem
)
864 || CmpAttr( *pNdItem
, rNdSet
.GetPool()->GetDefaultItem( nWhich
) ))
869 nWhich
= pItem
->Which();
870 //JP 27.02.95: wenn nach defaults gesucht wird, dann muss man bis zum Pool
872 // if( SFX_ITEM_SET != rNdSet.GetItemState( nWhich, !bNoColls, &pNdItem )
873 // || *pNdItem != *pItem )
874 if( !CmpAttr( rNdSet
.Get( nWhich
, !bNoColls
), *pItem
))
878 if( aIter
.IsAtEnd() )
880 pItem
= aIter
.NextItem();
882 return TRUE
; // wurde gefunden
886 BOOL
SwPaM::Find( const SfxPoolItem
& rAttr
, BOOL bValue
, SwMoveFn fnMove
,
887 const SwPaM
*pRegion
, BOOL bInReadOnly
)
889 // stelle fest welches Attribut gesucht wird:
890 USHORT nWhich
= rAttr
.Which();
891 int bCharAttr
= isCHRATR(nWhich
) || isTXTATR(nWhich
);
893 SwPaM
* pPam
= MakeRegion( fnMove
, pRegion
);
897 BOOL bSrchForward
= fnMove
== fnMoveForward
;
899 const SfxPoolItem
* pItem
;
902 // Wenn am Anfang/Ende, aus dem Node moven
904 ? pPam
->GetPoint()->nContent
.GetIndex() == pPam
->GetCntntNode()->Len()
905 : !pPam
->GetPoint()->nContent
.GetIndex() )
907 if( !(*fnMove
->fnNds
)( &pPam
->GetPoint()->nNode
, FALSE
))
912 SwCntntNode
*pNd
= pPam
->GetCntntNode();
913 xub_StrLen nTmpPos
= bSrchForward
? 0 : pNd
->Len();
914 pPam
->GetPoint()->nContent
.Assign( pNd
, nTmpPos
);
917 while( 0 != ( pNode
= ::GetNode( *pPam
, bFirst
, fnMove
, bInReadOnly
) ) )
921 if( !pNode
->IsTxtNode() ) // CharAttr sind nur in TextNodes
924 if( ((SwTxtNode
*)pNode
)->HasHints() &&
925 lcl_Search( *(SwTxtNode
*)pNode
, *pPam
, rAttr
, fnMove
, bValue
))
927 // setze auf die Werte vom Attribut
929 *GetPoint() = *pPam
->GetPoint();
930 *GetMark() = *pPam
->GetMark();
934 else if (isTXTATR(nWhich
))
935 continue; // --> also weiter
938 // keine harte Attributierung, dann pruefe, ob die Vorlage schon
939 // mal nach dem Attribut befragt wurde
940 if( !pNode
->HasSwAttrSet() )
942 const SwFmt
* pTmpFmt
= pNode
->GetFmtColl();
943 if( aFmtArr
.Count() && aFmtArr
.Seek_Entry( pTmpFmt
))
944 continue; // die Collection wurde schon mal befragt
945 aFmtArr
.Insert( pTmpFmt
);
948 if( SFX_ITEM_SET
== pNode
->GetSwAttrSet().GetItemState( nWhich
,
949 TRUE
, &pItem
) && ( !bValue
|| *pItem
== rAttr
) )
951 // FORWARD: Point an das Ende, GetMark zum Anfanf vom Node
952 // BACKWARD: Point zum Anfang, GetMark an das Ende vom Node
953 // und immer nach der Logik: inkl. Start, exkl. End !!!
954 *GetPoint() = *pPam
->GetPoint();
956 pNode
->MakeEndIndex( &GetPoint()->nContent
);
962 // beim rueckwaerts Suchen noch Point und Mark vertauschen
963 if( bFound
&& !bSrchForward
)
971 typedef int (*FnSearchAttr
)( const SwTxtNode
&, SwAttrCheckArr
&, SwPaM
& );
973 BOOL
SwPaM::Find( const SfxItemSet
& rSet
, BOOL bNoColls
, SwMoveFn fnMove
,
974 const SwPaM
*pRegion
, BOOL bInReadOnly
, BOOL bMoveFirst
)
976 SwPaM
* pPam
= MakeRegion( fnMove
, pRegion
);
980 BOOL bSrchForward
= fnMove
== fnMoveForward
;
984 // teste doch mal welche Text/Char-Attribute gesucht werden
985 SwAttrCheckArr
aCmpArr( rSet
, bSrchForward
, bNoColls
);
986 SfxItemSet
aOtherSet( GetDoc()->GetAttrPool(),
987 RES_PARATR_BEGIN
, RES_GRFATR_END
-1 );
988 aOtherSet
.Put( rSet
, FALSE
); // alle Invalid-Items erhalten!
990 FnSearchAttr fnSearch
= bSrchForward
991 ? (&::lcl_SearchForward
)
992 : (&::lcl_SearchBackward
);
994 // Wenn am Anfang/Ende, aus dem Node moven
995 // Wenn am Anfang/Ende, aus dem Node moven
998 ? pPam
->GetPoint()->nContent
.GetIndex() == pPam
->GetCntntNode()->Len()
999 : !pPam
->GetPoint()->nContent
.GetIndex() ) )
1001 if( !(*fnMove
->fnNds
)( &pPam
->GetPoint()->nNode
, FALSE
))
1006 SwCntntNode
*pNd
= pPam
->GetCntntNode();
1007 xub_StrLen nTmpPos
= bSrchForward
? 0 : pNd
->Len();
1008 pPam
->GetPoint()->nContent
.Assign( pNd
, nTmpPos
);
1012 while( 0 != ( pNode
= ::GetNode( *pPam
, bFirst
, fnMove
, bInReadOnly
) ) )
1014 if( aCmpArr
.Count() )
1016 if( !pNode
->IsTxtNode() ) // CharAttr sind nur in TextNodes
1019 if( (!aOtherSet
.Count() ||
1020 lcl_Search( *pNode
, aOtherSet
, bNoColls
)) &&
1021 (*fnSearch
)( *(SwTxtNode
*)pNode
, aCmpArr
, *pPam
))
1023 // setze auf die Werte vom Attribut
1025 *GetPoint() = *pPam
->GetPoint();
1026 *GetMark() = *pPam
->GetMark();
1030 continue; // TextAttribute
1033 if( !aOtherSet
.Count() )
1036 // keine harte Attributierung, dann pruefe, ob die Vorlage schon
1037 // mal nach dem Attribut befragt wurde
1038 if( !pNode
->HasSwAttrSet() )
1040 const SwFmt
* pTmpFmt
= pNode
->GetFmtColl();
1041 if( aFmtArr
.Count() && aFmtArr
.Seek_Entry( pTmpFmt
))
1042 continue; // die Collection wurde schon mal befragt
1043 aFmtArr
.Insert( pTmpFmt
);
1046 if( lcl_Search( *pNode
, aOtherSet
, bNoColls
))
1048 // FORWARD: Point an das Ende, GetMark zum Anfanf vom Node
1049 // BACKWARD: Point zum Anfang, GetMark an das Ende vom Node
1050 // und immer nach der Logik: inkl. Start, exkl. End !!!
1051 *GetPoint() = *pPam
->GetPoint();
1053 pNode
->MakeEndIndex( &GetPoint()->nContent
);
1059 // beim rueckwaerts Suchen noch Point und Mark vertauschen
1060 if( bFound
&& !bSrchForward
)
1067 //------------------ Methoden vom SwCursor ---------------------------
1069 // Parameter fuer das Suchen vom Attributen
1070 struct SwFindParaAttr
: public SwFindParas
1073 const SfxItemSet
*pSet
, *pReplSet
;
1074 const SearchOptions
*pSearchOpt
;
1076 utl::TextSearch
* pSTxt
;
1078 SwFindParaAttr( const SfxItemSet
& rSet
, BOOL bNoCollection
,
1079 const SearchOptions
* pOpt
, const SfxItemSet
* pRSet
,
1081 : bValue( bNoCollection
), pSet( &rSet
), pReplSet( pRSet
),
1082 pSearchOpt( pOpt
), rCursor( rCrsr
),pSTxt( 0 ) {}
1084 virtual ~SwFindParaAttr() { delete pSTxt
; }
1086 virtual int Find( SwPaM
* , SwMoveFn
, const SwPaM
*, BOOL bInReadOnly
);
1087 virtual int IsReplaceMode() const;
1091 int SwFindParaAttr::Find( SwPaM
* pCrsr
, SwMoveFn fnMove
, const SwPaM
* pRegion
,
1094 // String ersetzen ?? (nur wenn Text angegeben oder nicht attributiert
1096 BOOL bReplaceTxt
= pSearchOpt
&& ( pSearchOpt
->replaceString
.getLength() ||
1098 BOOL bReplaceAttr
= pReplSet
&& pReplSet
->Count();
1099 BOOL bMoveFirst
= !bReplaceAttr
;
1100 if( bInReadOnly
&& (bReplaceAttr
|| bReplaceTxt
))
1101 bInReadOnly
= FALSE
;
1103 // wir suchen nach Attributen, soll zusaetzlich Text gesucht werden ?
1105 SwPaM
aRegion( *pRegion
->GetMark(), *pRegion
->GetPoint() );
1106 SwPaM
* pTextRegion
= &aRegion
;
1107 SwPaM
aSrchPam( *pCrsr
->GetPoint() );
1111 if( pSet
->Count() ) // gibts ueberhaupt Attributierung?
1113 // zuerst die Attributierung
1114 if( !aSrchPam
.Find( *pSet
, bValue
, fnMove
, &aRegion
, bInReadOnly
, bMoveFirst
) )
1115 //JP 17.11.95: was ist mit Attributen in leeren Absaetzen !!
1116 // || *pCrsr->GetMark() == *pCrsr->GetPoint() ) // kein Bereich ??
1117 return FIND_NOT_FOUND
;
1121 break; // ok, nur Attribute, also gefunden
1123 pTextRegion
= &aSrchPam
;
1125 else if( !pSearchOpt
)
1126 return FIND_NOT_FOUND
;
1128 // dann darin den Text
1131 SearchOptions
aTmp( *pSearchOpt
);
1133 // search in selection
1134 aTmp
.searchFlag
|= (SearchFlags::REG_NOT_BEGINOFLINE
|
1135 SearchFlags::REG_NOT_ENDOFLINE
);
1137 MsLangId::convertLanguageToLocale( LANGUAGE_SYSTEM
, aTmp
.Locale
);
1139 pSTxt
= new utl::TextSearch( aTmp
);
1142 // todo/mba: searching for attributes in Outliner text?!
1143 BOOL bSearchInNotes
= FALSE
;
1145 // Bug 24665: suche im richtigen Bereich weiter (pTextRegion!)
1146 if( aSrchPam
.Find( *pSearchOpt
, bSearchInNotes
, *pSTxt
, fnMove
, pTextRegion
, bInReadOnly
) &&
1147 *aSrchPam
.GetMark() != *aSrchPam
.GetPoint() ) // gefunden ?
1149 else if( !pSet
->Count() )
1150 return FIND_NOT_FOUND
; // nur Text und nicht gefunden
1152 /* // --> FME 2007-4-12 #i74765 # Why should we move the position?
1153 Moving the position results in bugs when there are two adjacent
1154 portions which both have the requested attributes set. I suspect this
1155 should be only be an optimization. Therefore I boldly remove it now!
1157 // JP: und wieder neu aufsetzen, aber eine Position weiter
1158 //JP 04.11.97: Bug 44897 - aber den Mark wieder aufheben, damit
1159 // weiterbewegt werden kann!
1161 BOOL bCheckRegion = TRUE;
1162 SwPosition* pPos = aSrchPam.GetPoint();
1163 if( !(*fnMove->fnNd)( &pPos->nNode.GetNode(),
1164 &pPos->nContent, CRSR_SKIP_CHARS ))
1166 if( (*fnMove->fnNds)( &pPos->nNode, FALSE ))
1168 SwCntntNode *pNd = pPos->nNode.GetNode().GetCntntNode();
1170 if( fnMove == fnMoveForward )
1174 pPos->nContent.Assign( pNd, nCPos );
1177 bCheckRegion = FALSE;
1179 if( !bCheckRegion || *aRegion.GetPoint() <= *pPos )
1180 return FIND_NOT_FOUND; // nicht gefunden
1182 *aRegion
.GetMark() = *aSrchPam
.GetPoint();
1185 *pCrsr
->GetPoint() = *aSrchPam
.GetPoint();
1187 *pCrsr
->GetMark() = *aSrchPam
.GetMark();
1193 SearchAlgorithms_REGEXP
== pSearchOpt
->algorithmType
);
1194 SwIndex
& rSttCntIdx
= pCrsr
->Start()->nContent
;
1195 xub_StrLen nSttCnt
= rSttCntIdx
.GetIndex();
1197 // damit die Region auch verschoben wird, in den Shell-Cursr-Ring
1199 Ring
*pPrevRing
= 0;
1202 pPrevRing
= pRegion
->GetPrev();
1203 ((Ring
*)pRegion
)->MoveRingTo( &rCursor
);
1206 ::std::auto_ptr
<String
> pRepl( (bRegExp
) ?
1207 ReplaceBackReferences( *pSearchOpt
, pCrsr
) : 0 );
1208 rCursor
.GetDoc()->ReplaceRange( *pCrsr
,
1209 (pRepl
.get()) ? *pRepl
: String(pSearchOpt
->replaceString
),
1211 rCursor
.SaveTblBoxCntnt( pCrsr
->GetPoint() );
1215 // und die Region wieder herausnehmen:
1216 Ring
*p
, *pNext
= (Ring
*)pRegion
;
1219 pNext
= p
->GetNext();
1220 p
->MoveTo( (Ring
*)pRegion
);
1221 } while( p
!= pPrevRing
);
1223 rSttCntIdx
= nSttCnt
;
1228 // --- Ist die Selection noch da ??????
1230 // und noch die Attribute setzen
1232 pCrsr
->GetDoc()->Insert( *pCrsr
, *pReplSet
, 0 );
1234 //JP 13.07.95: alle gesuchten Attribute werden, wenn nicht im
1235 // ReplaceSet angegeben, auf Default zurueck gesetzt
1237 if( !pSet
->Count() )
1239 pCrsr
->GetDoc()->InsertItemSet( *pCrsr
, *pReplSet
, 0 );
1243 SfxItemPool
* pPool
= pReplSet
->GetPool();
1244 SfxItemSet
aSet( *pPool
, pReplSet
->GetRanges() );
1246 SfxItemIter
aIter( *pSet
);
1247 const SfxPoolItem
* pItem
= aIter
.GetCurItem();
1250 // alle die nicht gesetzt sind mit Pool-Defaults aufuellen
1251 if( !IsInvalidItem( pItem
) && SFX_ITEM_SET
!=
1252 pReplSet
->GetItemState( pItem
->Which(), FALSE
))
1253 aSet
.Put( pPool
->GetDefaultItem( pItem
->Which() ));
1255 if( aIter
.IsAtEnd() )
1257 pItem
= aIter
.NextItem();
1259 aSet
.Put( *pReplSet
);
1260 pCrsr
->GetDoc()->InsertItemSet( *pCrsr
, aSet
, 0 );
1263 return FIND_NO_RING
;
1271 int SwFindParaAttr::IsReplaceMode() const
1273 return ( pSearchOpt
&& pSearchOpt
->replaceString
.getLength() ) ||
1274 ( pReplSet
&& pReplSet
->Count() );
1277 // Suchen nach Attributen
1280 ULONG
SwCursor::Find( const SfxItemSet
& rSet
, BOOL bNoCollections
,
1281 SwDocPositions nStart
, SwDocPositions nEnde
, BOOL
& bCancel
,
1282 FindRanges eFndRngs
,
1283 const SearchOptions
* pSearchOpt
, const SfxItemSet
* pReplSet
)
1285 // OLE-Benachrichtigung abschalten !!
1286 SwDoc
* pDoc
= GetDoc();
1287 Link
aLnk( pDoc
->GetOle2Link() );
1288 pDoc
->SetOle2Link( Link() );
1290 BOOL bReplace
= ( pSearchOpt
&& ( pSearchOpt
->replaceString
.getLength() ||
1291 !rSet
.Count() ) ) ||
1292 (pReplSet
&& pReplSet
->Count());
1293 BOOL bSttUndo
= pDoc
->DoesUndo() && bReplace
;
1295 pDoc
->StartUndo( UNDO_REPLACE
, NULL
);
1297 SwFindParaAttr
aSwFindParaAttr( rSet
, bNoCollections
, pSearchOpt
,
1300 ULONG nRet
= FindAll(aSwFindParaAttr
, nStart
, nEnde
, eFndRngs
, bCancel
);
1301 pDoc
->SetOle2Link( aLnk
);
1302 if( nRet
&& bReplace
)
1303 pDoc
->SetModified();
1306 pDoc
->EndUndo( UNDO_REPLACE
, NULL
);