Line data Source code
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/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>
35 : #include <doc.hxx>
36 : #include <IDocumentUndoRedo.hxx>
37 : #include <swcrsr.hxx>
38 : #include <editsh.hxx>
39 : #include <ndtxt.hxx>
40 : #include <pamtyp.hxx>
41 : #include <swundo.hxx>
42 : #include <crsskip.hxx>
43 :
44 :
45 : using namespace ::com::sun::star;
46 : using namespace ::com::sun::star::lang;
47 : using namespace ::com::sun::star::util;
48 :
49 : typedef std::set<SwFmt*> SwpFmts;
50 :
51 : // Special case for SvxFontItem: only compare the name
52 0 : int CmpAttr( const SfxPoolItem& rItem1, const SfxPoolItem& rItem2 )
53 : {
54 0 : switch( rItem1.Which() )
55 : {
56 : case RES_CHRATR_FONT:
57 0 : return ((SvxFontItem&)rItem1).GetFamilyName() ==
58 0 : ((SvxFontItem&)rItem2).GetFamilyName();
59 :
60 : case RES_CHRATR_COLOR:
61 0 : return ((SvxColorItem&)rItem1).GetValue().IsRGBEqual(
62 0 : ((SvxColorItem&)rItem2).GetValue() );
63 : case RES_PAGEDESC:
64 0 : return ((SwFmtPageDesc&)rItem1).GetNumOffset() ==
65 0 : ((SwFmtPageDesc&)rItem2).GetNumOffset() &&
66 0 : ((SwFmtPageDesc&)rItem1).GetPageDesc() ==
67 0 : ((SwFmtPageDesc&)rItem2).GetPageDesc();
68 : }
69 0 : return rItem1 == rItem2;
70 : }
71 :
72 :
73 0 : const SwTxtAttr* GetFrwrdTxtHint( const SwpHints& rHtsArr, sal_uInt16& rPos,
74 : xub_StrLen nCntntPos )
75 : {
76 0 : while( rPos < rHtsArr.Count() )
77 : {
78 0 : const SwTxtAttr *pTxtHt = rHtsArr.GetStart( rPos++ );
79 : // the start of an attribute has to be in the section
80 0 : if( *pTxtHt->GetStart() >= nCntntPos )
81 0 : return pTxtHt; // valid text attribute
82 : }
83 0 : return 0; // invalid text attribute
84 : }
85 :
86 :
87 0 : const SwTxtAttr* GetBkwrdTxtHint( const SwpHints& rHtsArr, sal_uInt16& rPos,
88 : xub_StrLen nCntntPos )
89 : {
90 0 : while( rPos > 0 )
91 : {
92 0 : const SwTxtAttr *pTxtHt = rHtsArr.GetStart( --rPos );
93 : // the start of an attribute has to be in the section
94 0 : if( *pTxtHt->GetStart() < nCntntPos )
95 0 : return pTxtHt; // valid text attribute
96 : }
97 0 : return 0; // invalid text attribute
98 : }
99 :
100 0 : static void lcl_SetAttrPam( SwPaM& rPam, xub_StrLen nStart, const xub_StrLen* pEnd,
101 : const sal_Bool bSaveMark )
102 : {
103 : xub_StrLen nCntntPos;
104 0 : if( bSaveMark )
105 0 : nCntntPos = rPam.GetMark()->nContent.GetIndex();
106 : else
107 0 : nCntntPos = rPam.GetPoint()->nContent.GetIndex();
108 0 : bool bTstEnd = rPam.GetPoint()->nNode == rPam.GetMark()->nNode;
109 :
110 0 : SwCntntNode* pCNd = rPam.GetCntntNode();
111 0 : rPam.GetPoint()->nContent.Assign( pCNd, nStart );
112 0 : rPam.SetMark(); // Point == GetMark
113 :
114 : // Point points to end of search area or end of attribute
115 0 : if( pEnd )
116 : {
117 0 : if( bTstEnd && *pEnd > nCntntPos )
118 0 : rPam.GetPoint()->nContent = nCntntPos;
119 : else
120 0 : rPam.GetPoint()->nContent = *pEnd;
121 : }
122 0 : }
123 :
124 : // TODO: provide documentation
125 : /** search for a text attribute
126 :
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).
130 :
131 : @param rTxtNd Text node to search in.
132 : @param rPam ???
133 : @param rCmpItem ???
134 : @param fnMove ???
135 : @param bValue ???
136 : @return Returns <true> if found, <false> otherwise.
137 : */
138 0 : static sal_Bool lcl_Search( const SwTxtNode& rTxtNd, SwPaM& rPam,
139 : const SfxPoolItem& rCmpItem,
140 : SwMoveFn fnMove, sal_Bool bValue )
141 : {
142 0 : if ( !rTxtNd.HasHints() )
143 0 : return sal_False;
144 0 : const SwTxtAttr *pTxtHt = 0;
145 0 : sal_Bool bForward = fnMove == fnMoveForward;
146 0 : sal_uInt16 nPos = bForward ? 0 : rTxtNd.GetSwpHints().Count();
147 0 : xub_StrLen nCntntPos = rPam.GetPoint()->nContent.GetIndex();
148 :
149 0 : while( 0 != ( pTxtHt=(*fnMove->fnGetHint)(rTxtNd.GetSwpHints(),nPos,nCntntPos)))
150 0 : if( pTxtHt->Which() == rCmpItem.Which() &&
151 0 : ( !bValue || CmpAttr( pTxtHt->GetAttr(), rCmpItem )))
152 : {
153 0 : lcl_SetAttrPam( rPam, *pTxtHt->GetStart(), pTxtHt->GetEnd(), bForward );
154 0 : return sal_True;
155 : }
156 0 : return sal_False;
157 : }
158 :
159 : /// search for multiple text attributes
160 : struct _SwSrchChrAttr
161 : {
162 : sal_uInt16 nWhich;
163 : xub_StrLen nStt, nEnd;
164 :
165 0 : _SwSrchChrAttr( const SfxPoolItem& rItem,
166 : xub_StrLen nStart, xub_StrLen nAnyEnd )
167 0 : : nWhich( rItem.Which() ), nStt( nStart ), nEnd( nAnyEnd )
168 0 : {}
169 : };
170 :
171 : class SwAttrCheckArr
172 : {
173 : _SwSrchChrAttr *pFndArr, *pStackArr;
174 : xub_StrLen nNdStt, nNdEnd;
175 : sal_uInt16 nArrStart, nArrLen;
176 : sal_uInt16 nFound, nStackCnt;
177 : SfxItemSet aCmpSet;
178 : sal_Bool bNoColls;
179 : sal_Bool bForward;
180 :
181 : public:
182 : SwAttrCheckArr( const SfxItemSet& rSet, int bForward, int bNoCollections );
183 : ~SwAttrCheckArr();
184 :
185 : void SetNewSet( const SwTxtNode& rTxtNd, const SwPaM& rPam );
186 :
187 : /// how many attributes are there in total?
188 0 : sal_uInt16 Count() const { return aCmpSet.Count(); }
189 0 : int Found() const { return nFound == aCmpSet.Count(); }
190 : int CheckStack();
191 :
192 : xub_StrLen Start() const;
193 : xub_StrLen End() const;
194 :
195 0 : xub_StrLen GetNdStt() const { return nNdStt; }
196 0 : xub_StrLen GetNdEnd() const { return nNdEnd; }
197 :
198 : int SetAttrFwd( const SwTxtAttr& rAttr );
199 : int SetAttrBwd( const SwTxtAttr& rAttr );
200 : };
201 :
202 :
203 :
204 0 : SwAttrCheckArr::SwAttrCheckArr( const SfxItemSet& rSet, int bFwd,
205 : int bNoCollections )
206 0 : : aCmpSet( *rSet.GetPool(), RES_CHRATR_BEGIN, RES_TXTATR_END-1 )
207 : {
208 0 : aCmpSet.Put( rSet, sal_False );
209 0 : bNoColls = 0 != bNoCollections;
210 :
211 0 : bForward = 0 != bFwd;
212 :
213 : // determine area of Fnd/Stack array (Min/Max)
214 0 : SfxItemIter aIter( aCmpSet );
215 0 : nArrStart = aCmpSet.GetWhichByPos( aIter.GetFirstPos() );
216 0 : nArrLen = aCmpSet.GetWhichByPos( aIter.GetLastPos() ) - nArrStart+1;
217 :
218 0 : char* pFndChar = new char[ nArrLen * sizeof(_SwSrchChrAttr) ];
219 0 : char* pStackChar = new char[ nArrLen * sizeof(_SwSrchChrAttr) ];
220 :
221 0 : pFndArr = (_SwSrchChrAttr*)pFndChar;
222 0 : pStackArr = (_SwSrchChrAttr*)pStackChar;
223 0 : }
224 :
225 0 : SwAttrCheckArr::~SwAttrCheckArr()
226 : {
227 0 : delete[] (char*)pFndArr;
228 0 : delete[] (char*)pStackArr;
229 0 : }
230 :
231 0 : void SwAttrCheckArr::SetNewSet( const SwTxtNode& rTxtNd, const SwPaM& rPam )
232 : {
233 0 : memset( pFndArr, 0, nArrLen * sizeof(_SwSrchChrAttr) );
234 0 : memset( pStackArr, 0, nArrLen * sizeof(_SwSrchChrAttr) );
235 0 : nFound = 0;
236 0 : nStackCnt = 0;
237 :
238 0 : if( bForward )
239 : {
240 0 : nNdStt = rPam.GetPoint()->nContent.GetIndex();
241 0 : nNdEnd = rPam.GetPoint()->nNode == rPam.GetMark()->nNode
242 0 : ? rPam.GetMark()->nContent.GetIndex()
243 0 : : rTxtNd.GetTxt().Len();
244 : }
245 : else
246 : {
247 0 : nNdEnd = rPam.GetPoint()->nContent.GetIndex();
248 0 : nNdStt = rPam.GetPoint()->nNode == rPam.GetMark()->nNode
249 0 : ? rPam.GetMark()->nContent.GetIndex()
250 0 : : 0;
251 : }
252 :
253 0 : if( bNoColls && !rTxtNd.HasSwAttrSet() )
254 0 : return ;
255 :
256 0 : const SfxItemSet& rSet = rTxtNd.GetSwAttrSet();
257 :
258 0 : SfxItemIter aIter( aCmpSet );
259 0 : const SfxPoolItem* pItem = aIter.GetCurItem();
260 : const SfxPoolItem* pFndItem;
261 : sal_uInt16 nWhich;
262 :
263 0 : while( sal_True )
264 : {
265 0 : if( IsInvalidItem( pItem ) )
266 : {
267 0 : nWhich = aCmpSet.GetWhichByPos( aIter.GetCurPos() );
268 0 : if( RES_TXTATR_END <= nWhich )
269 0 : break; // end of text attributes
270 :
271 0 : if( SFX_ITEM_SET == rSet.GetItemState( nWhich, !bNoColls, &pFndItem )
272 0 : && !CmpAttr( *pFndItem, rSet.GetPool()->GetDefaultItem( nWhich ) ))
273 : {
274 : pFndArr[ nWhich - nArrStart ] =
275 0 : _SwSrchChrAttr( *pFndItem, nNdStt, nNdEnd );
276 0 : nFound++;
277 : }
278 : }
279 : else
280 : {
281 0 : if( RES_TXTATR_END <= (nWhich = pItem->Which() ))
282 0 : break; // end of text attributes
283 :
284 0 : if( CmpAttr( rSet.Get( nWhich, !bNoColls ), *pItem ) )
285 : {
286 : pFndArr[ nWhich - nArrStart ] =
287 0 : _SwSrchChrAttr( *pItem, nNdStt, nNdEnd );
288 0 : nFound++;
289 : }
290 : }
291 :
292 0 : if( aIter.IsAtEnd() )
293 0 : break;
294 0 : pItem = aIter.NextItem();
295 0 : }
296 : }
297 :
298 : static bool
299 0 : lcl_IsAttributeIgnorable(xub_StrLen const nNdStart, xub_StrLen const nNdEnd,
300 : _SwSrchChrAttr const& rTmp)
301 : {
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 0 : : ((rTmp.nEnd <= nNdStart) || (nNdEnd <= rTmp.nStt)));
311 : }
312 :
313 0 : int SwAttrCheckArr::SetAttrFwd( const SwTxtAttr& rAttr )
314 : {
315 0 : _SwSrchChrAttr aTmp( rAttr.GetAttr(), *rAttr.GetStart(), *rAttr.GetAnyEnd() );
316 :
317 : // ignore all attributes not in search range
318 0 : if (lcl_IsAttributeIgnorable(nNdStt, nNdEnd, aTmp))
319 : {
320 0 : return Found();
321 : }
322 :
323 : const SfxPoolItem* pItem;
324 : // here we explicitly also search in character templates
325 0 : sal_uInt16 nWhch = rAttr.Which();
326 0 : SfxWhichIter* pIter = NULL;
327 0 : const SfxPoolItem* pTmpItem = NULL;
328 0 : const SfxItemSet* pSet = NULL;
329 0 : if( RES_TXTATR_CHARFMT == nWhch || RES_TXTATR_AUTOFMT == nWhch )
330 : {
331 0 : if( bNoColls && RES_TXTATR_CHARFMT == nWhch )
332 0 : return Found();
333 0 : pTmpItem = NULL;
334 0 : pSet = CharFmt::GetItemSet( rAttr.GetAttr() );
335 0 : if ( pSet )
336 : {
337 0 : pIter = new SfxWhichIter( *pSet );
338 0 : nWhch = pIter->FirstWhich();
339 0 : while( nWhch &&
340 0 : SFX_ITEM_SET != pSet->GetItemState( nWhch, sal_True, &pTmpItem ) )
341 0 : nWhch = pIter->NextWhich();
342 0 : if( !nWhch )
343 0 : pTmpItem = NULL;
344 : }
345 : }
346 : else
347 0 : pTmpItem = &rAttr.GetAttr();
348 0 : while( pTmpItem )
349 : {
350 0 : SfxItemState eState = aCmpSet.GetItemState( nWhch, sal_False, &pItem );
351 0 : if( SFX_ITEM_DONTCARE == eState || SFX_ITEM_SET == eState )
352 : {
353 : sal_uInt16 n;
354 : _SwSrchChrAttr* pCmp;
355 :
356 : // first delete all up to start position that are already invalid
357 : _SwSrchChrAttr* pArrPtr;
358 0 : if( nFound )
359 0 : for( pArrPtr = pFndArr, n = 0; n < nArrLen;
360 : ++n, ++pArrPtr )
361 0 : if( pArrPtr->nWhich && pArrPtr->nEnd <= aTmp.nStt )
362 : {
363 0 : pArrPtr->nWhich = 0; // deleted
364 0 : nFound--;
365 : }
366 :
367 : // delete all up to start position that are already invalid and
368 : // move all "open" ones (= stick out over start position) from stack
369 : // into FndSet
370 0 : if( nStackCnt )
371 0 : for( pArrPtr = pStackArr, n=0; n < nArrLen; ++n, ++pArrPtr )
372 : {
373 0 : if( !pArrPtr->nWhich )
374 0 : continue;
375 :
376 0 : if( pArrPtr->nEnd <= aTmp.nStt )
377 : {
378 0 : pArrPtr->nWhich = 0; // deleted
379 0 : if( !--nStackCnt )
380 0 : break;
381 : }
382 0 : else if( pArrPtr->nStt <= aTmp.nStt )
383 : {
384 0 : if( ( pCmp = &pFndArr[ n ])->nWhich )
385 : {
386 0 : if( pCmp->nEnd < pArrPtr->nEnd ) // extend
387 0 : pCmp->nEnd = pArrPtr->nEnd;
388 : }
389 : else
390 : {
391 0 : *pCmp = *pArrPtr;
392 0 : nFound++;
393 : }
394 0 : pArrPtr->nWhich = 0;
395 0 : if( !--nStackCnt )
396 0 : break;
397 : }
398 : }
399 :
400 0 : bool bContinue = false;
401 :
402 0 : if( SFX_ITEM_DONTCARE == eState )
403 : {
404 : // Will the attribute become valid?
405 0 : if( !CmpAttr( aCmpSet.GetPool()->GetDefaultItem( nWhch ),
406 0 : *pTmpItem ))
407 : {
408 : // search attribute and extend if needed
409 0 : if( !( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich )
410 : {
411 0 : *pCmp = aTmp; // not found, insert
412 0 : nFound++;
413 : }
414 0 : else if( pCmp->nEnd < aTmp.nEnd ) // extend?
415 0 : pCmp->nEnd = aTmp.nEnd;
416 :
417 0 : bContinue = true;
418 : }
419 : }
420 : // Will the attribute become valid?
421 0 : else if( CmpAttr( *pItem, *pTmpItem ) )
422 : {
423 0 : pFndArr[ nWhch - nArrStart ] = aTmp;
424 0 : ++nFound;
425 0 : bContinue = true;
426 : }
427 :
428 : // then is has to go on the stack
429 0 : if( !bContinue && ( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich )
430 : {
431 : // exists on stack, only if it is even bigger
432 0 : if( pCmp->nEnd > aTmp.nEnd )
433 : {
434 : OSL_ENSURE( !pStackArr[ nWhch - nArrStart ].nWhich,
435 : "slot on stack is still in use" );
436 :
437 0 : if( aTmp.nStt <= pCmp->nStt )
438 0 : pCmp->nStt = aTmp.nEnd;
439 : else
440 0 : pCmp->nEnd = aTmp.nStt;
441 :
442 0 : pStackArr[ nWhch - nArrStart ] = *pCmp;
443 0 : nStackCnt++;
444 : }
445 0 : pCmp->nWhich = 0;
446 0 : nFound--;
447 : }
448 : }
449 0 : if( pIter )
450 : {
451 0 : nWhch = pIter->NextWhich();
452 0 : while( nWhch &&
453 0 : SFX_ITEM_SET != pSet->GetItemState( nWhch, sal_True, &pTmpItem ) )
454 0 : nWhch = pIter->NextWhich();
455 0 : if( !nWhch )
456 0 : break;
457 : }
458 : else
459 0 : break;
460 : }
461 0 : return Found();
462 : }
463 :
464 :
465 0 : int SwAttrCheckArr::SetAttrBwd( const SwTxtAttr& rAttr )
466 : {
467 0 : _SwSrchChrAttr aTmp( rAttr.GetAttr(), *rAttr.GetStart(), *rAttr.GetAnyEnd() );
468 :
469 : // ignore all attributes not in search range
470 0 : if (lcl_IsAttributeIgnorable(nNdStt, nNdEnd, aTmp))
471 : {
472 0 : return Found();
473 : }
474 :
475 : const SfxPoolItem* pItem;
476 : // here we explicitly also search in character templates
477 0 : sal_uInt16 nWhch = rAttr.Which();
478 0 : SfxWhichIter* pIter = NULL;
479 0 : const SfxPoolItem* pTmpItem = NULL;
480 0 : const SfxItemSet* pSet = NULL;
481 0 : if( RES_TXTATR_CHARFMT == nWhch || RES_TXTATR_AUTOFMT == nWhch )
482 : {
483 0 : if( bNoColls && RES_TXTATR_CHARFMT == nWhch )
484 0 : return Found();
485 :
486 0 : pSet = CharFmt::GetItemSet( rAttr.GetAttr() );
487 0 : if ( pSet )
488 : {
489 0 : pIter = new SfxWhichIter( *pSet );
490 0 : nWhch = pIter->FirstWhich();
491 0 : while( nWhch &&
492 0 : SFX_ITEM_SET != pSet->GetItemState( nWhch, sal_True, &pTmpItem ) )
493 0 : nWhch = pIter->NextWhich();
494 0 : if( !nWhch )
495 0 : pTmpItem = NULL;
496 : }
497 : }
498 : else
499 0 : pTmpItem = &rAttr.GetAttr();
500 0 : while( pTmpItem )
501 : {
502 0 : SfxItemState eState = aCmpSet.GetItemState( nWhch, sal_False, &pItem );
503 0 : if( SFX_ITEM_DONTCARE == eState || SFX_ITEM_SET == eState )
504 : {
505 : sal_uInt16 n;
506 : _SwSrchChrAttr* pCmp;
507 :
508 : // first delete all up to start position that are already invalid
509 : _SwSrchChrAttr* pArrPtr;
510 0 : if( nFound )
511 0 : for( pArrPtr = pFndArr, n = 0; n < nArrLen; ++n, ++pArrPtr )
512 0 : if( pArrPtr->nWhich && pArrPtr->nStt >= aTmp.nEnd )
513 : {
514 0 : pArrPtr->nWhich = 0; // deleted
515 0 : nFound--;
516 : }
517 :
518 : // delete all up to start position that are already invalid and
519 : // move all "open" ones (= stick out over start position) from stack
520 : // into FndSet
521 0 : if( nStackCnt )
522 0 : for( pArrPtr = pStackArr, n = 0; n < nArrLen; ++n, ++pArrPtr )
523 : {
524 0 : if( !pArrPtr->nWhich )
525 0 : continue;
526 :
527 0 : if( pArrPtr->nStt >= aTmp.nEnd )
528 : {
529 0 : pArrPtr->nWhich = 0; // deleted
530 0 : if( !--nStackCnt )
531 0 : break;
532 : }
533 0 : else if( pArrPtr->nEnd >= aTmp.nEnd )
534 : {
535 0 : if( ( pCmp = &pFndArr[ n ])->nWhich )
536 : {
537 0 : if( pCmp->nStt > pArrPtr->nStt ) // extend
538 0 : pCmp->nStt = pArrPtr->nStt;
539 : }
540 : else
541 : {
542 0 : *pCmp = *pArrPtr;
543 0 : nFound++;
544 : }
545 0 : pArrPtr->nWhich = 0;
546 0 : if( !--nStackCnt )
547 0 : break;
548 : }
549 : }
550 :
551 0 : bool bContinue = false;
552 0 : if( SFX_ITEM_DONTCARE == eState )
553 : {
554 : // Will the attribute become valid?
555 0 : if( !CmpAttr( aCmpSet.GetPool()->GetDefaultItem( nWhch ),
556 0 : *pTmpItem ) )
557 : {
558 : // search attribute and extend if needed
559 0 : if( !( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich )
560 : {
561 0 : *pCmp = aTmp; // not found, insert
562 0 : nFound++;
563 : }
564 0 : else if( pCmp->nStt > aTmp.nStt ) // extend?
565 0 : pCmp->nStt = aTmp.nStt;
566 :
567 0 : bContinue = true;
568 : }
569 : }
570 : // Will the attribute become valid?
571 0 : else if( CmpAttr( *pItem, *pTmpItem ))
572 : {
573 0 : pFndArr[ nWhch - nArrStart ] = aTmp;
574 0 : ++nFound;
575 0 : bContinue = true;
576 : }
577 :
578 : // then is has to go on the stack
579 0 : if( !bContinue && ( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich )
580 : {
581 : // exists on stack, only if it is even bigger
582 0 : if( pCmp->nStt < aTmp.nStt )
583 : {
584 : OSL_ENSURE( !pStackArr[ nWhch - nArrStart ].nWhich,
585 : "slot on stack is still in use" );
586 :
587 0 : if( aTmp.nEnd <= pCmp->nEnd )
588 0 : pCmp->nEnd = aTmp.nStt;
589 : else
590 0 : pCmp->nStt = aTmp.nEnd;
591 :
592 0 : pStackArr[ nWhch - nArrStart ] = *pCmp;
593 0 : nStackCnt++;
594 : }
595 0 : pCmp->nWhich = 0;
596 0 : nFound--;
597 : }
598 : }
599 0 : if( pIter )
600 : {
601 0 : nWhch = pIter->NextWhich();
602 0 : while( nWhch &&
603 0 : SFX_ITEM_SET != pSet->GetItemState( nWhch, sal_True, &pTmpItem ) )
604 0 : nWhch = pIter->NextWhich();
605 0 : if( !nWhch )
606 0 : break;
607 : }
608 : else
609 0 : break;
610 : }
611 0 : return Found();
612 : }
613 :
614 :
615 0 : xub_StrLen SwAttrCheckArr::Start() const
616 : {
617 0 : xub_StrLen nStart = nNdStt;
618 0 : _SwSrchChrAttr* pArrPtr = pFndArr;
619 0 : for( sal_uInt16 n = 0; n < nArrLen; ++n, ++pArrPtr )
620 0 : if( pArrPtr->nWhich && pArrPtr->nStt > nStart )
621 0 : nStart = pArrPtr->nStt;
622 :
623 0 : return nStart;
624 : }
625 :
626 :
627 0 : xub_StrLen SwAttrCheckArr::End() const
628 : {
629 0 : _SwSrchChrAttr* pArrPtr = pFndArr;
630 0 : xub_StrLen nEnd = nNdEnd;
631 0 : for( sal_uInt16 n = 0; n < nArrLen; ++n, ++pArrPtr )
632 0 : if( pArrPtr->nWhich && pArrPtr->nEnd < nEnd )
633 0 : nEnd = pArrPtr->nEnd;
634 :
635 0 : return nEnd;
636 : }
637 :
638 :
639 0 : int SwAttrCheckArr::CheckStack()
640 : {
641 0 : if( !nStackCnt )
642 0 : return sal_False;
643 :
644 : sal_uInt16 n;
645 0 : xub_StrLen nSttPos = Start(), nEndPos = End();
646 : _SwSrchChrAttr* pArrPtr;
647 0 : for( pArrPtr = pStackArr, n = 0; n < nArrLen; ++n, ++pArrPtr )
648 : {
649 0 : if( !pArrPtr->nWhich )
650 0 : continue;
651 :
652 0 : if( bForward ? pArrPtr->nEnd <= nSttPos : pArrPtr->nStt >= nEndPos )
653 : {
654 0 : pArrPtr->nWhich = 0; // deleted
655 0 : if( !--nStackCnt )
656 0 : return nFound == aCmpSet.Count();
657 : }
658 0 : else if( bForward ? pArrPtr->nStt < nEndPos : pArrPtr->nEnd > nSttPos )
659 : {
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 0 : pFndArr[ n ] = *pArrPtr;
663 0 : pArrPtr->nWhich = 0;
664 0 : nFound++;
665 0 : if( !--nStackCnt )
666 0 : return nFound == aCmpSet.Count();
667 : }
668 : }
669 0 : return nFound == aCmpSet.Count();
670 : }
671 :
672 :
673 :
674 0 : static int lcl_SearchForward( const SwTxtNode& rTxtNd, SwAttrCheckArr& rCmpArr,
675 : SwPaM& rPam )
676 : {
677 : xub_StrLen nEndPos, nSttPos;
678 0 : rCmpArr.SetNewSet( rTxtNd, rPam );
679 0 : if( !rTxtNd.HasHints() )
680 : {
681 0 : if( !rCmpArr.Found() )
682 0 : return sal_False;
683 0 : nEndPos = rCmpArr.GetNdEnd();
684 0 : lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, sal_True );
685 0 : return sal_True;
686 : }
687 :
688 0 : const SwpHints& rHtArr = rTxtNd.GetSwpHints();
689 : const SwTxtAttr* pAttr;
690 0 : sal_uInt16 nPos = 0;
691 :
692 : // if everything is already there then check with which it will be ended
693 0 : if( rCmpArr.Found() )
694 : {
695 0 : for( ; nPos < rHtArr.Count(); ++nPos )
696 0 : if( !rCmpArr.SetAttrFwd( *( pAttr = rHtArr.GetStart( nPos )) ) )
697 : {
698 0 : if( rCmpArr.GetNdStt() < *pAttr->GetStart() )
699 : {
700 : // found end
701 0 : lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(),
702 0 : pAttr->GetStart(), sal_True );
703 0 : return sal_True;
704 : }
705 : // continue search
706 0 : break;
707 : }
708 :
709 0 : if( nPos == rHtArr.Count() && rCmpArr.Found() )
710 : {
711 : // found
712 0 : nEndPos = rCmpArr.GetNdEnd();
713 0 : lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, sal_True );
714 0 : return sal_True;
715 : }
716 : }
717 :
718 0 : for( ; nPos < rHtArr.Count(); ++nPos )
719 0 : if( rCmpArr.SetAttrFwd( *( pAttr = rHtArr.GetStart( nPos )) ) )
720 : {
721 : // Do multiple start at that position? Do also check those:
722 0 : nSttPos = *pAttr->GetStart();
723 0 : while( ++nPos < rHtArr.Count() && nSttPos ==
724 0 : *( pAttr = rHtArr.GetStart( nPos ))->GetStart() &&
725 0 : rCmpArr.SetAttrFwd( *pAttr ) )
726 : ;
727 0 : if( !rCmpArr.Found() )
728 0 : continue;
729 :
730 : // then we have our search area
731 0 : if( (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
732 0 : return sal_False;
733 0 : lcl_SetAttrPam( rPam, nSttPos, &nEndPos, sal_True );
734 0 : return sal_True;
735 : }
736 :
737 0 : if( !rCmpArr.CheckStack() ||
738 0 : (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
739 0 : return sal_False;
740 0 : lcl_SetAttrPam( rPam, nSttPos, &nEndPos, sal_True );
741 0 : return sal_True;
742 : }
743 :
744 :
745 0 : static int lcl_SearchBackward( const SwTxtNode& rTxtNd, SwAttrCheckArr& rCmpArr,
746 : SwPaM& rPam )
747 : {
748 : xub_StrLen nEndPos, nSttPos;
749 0 : rCmpArr.SetNewSet( rTxtNd, rPam );
750 0 : if( !rTxtNd.HasHints() )
751 : {
752 0 : if( !rCmpArr.Found() )
753 0 : return sal_False;
754 0 : nEndPos = rCmpArr.GetNdEnd();
755 0 : lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, sal_False );
756 0 : return sal_True;
757 : }
758 :
759 0 : const SwpHints& rHtArr = rTxtNd.GetSwpHints();
760 : const SwTxtAttr* pAttr;
761 0 : sal_uInt16 nPos = rHtArr.Count();
762 :
763 : // if everything is already there then check with which it will be ended
764 0 : if( rCmpArr.Found() )
765 : {
766 0 : while( nPos )
767 0 : if( !rCmpArr.SetAttrBwd( *( pAttr = rHtArr.GetEnd( --nPos )) ) )
768 : {
769 0 : nSttPos = *pAttr->GetAnyEnd();
770 0 : if( nSttPos < rCmpArr.GetNdEnd() )
771 : {
772 : // found end
773 0 : nEndPos = rCmpArr.GetNdEnd();
774 0 : lcl_SetAttrPam( rPam, nSttPos, &nEndPos, sal_False );
775 0 : return sal_True;
776 : }
777 :
778 : // continue search
779 0 : break;
780 : }
781 :
782 0 : if( !nPos && rCmpArr.Found() )
783 : {
784 : // found
785 0 : nEndPos = rCmpArr.GetNdEnd();
786 0 : lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, sal_False );
787 0 : return sal_True;
788 : }
789 : }
790 :
791 0 : while( nPos )
792 0 : if( rCmpArr.SetAttrBwd( *( pAttr = rHtArr.GetEnd( --nPos )) ) )
793 : {
794 : // Do multiple start at that position? Do also check those:
795 0 : if( nPos )
796 : {
797 0 : nEndPos = *pAttr->GetAnyEnd();
798 0 : while( --nPos && nEndPos ==
799 0 : *( pAttr = rHtArr.GetEnd( nPos ))->GetAnyEnd() &&
800 0 : rCmpArr.SetAttrBwd( *pAttr ) )
801 : ;
802 : }
803 0 : if( !rCmpArr.Found() )
804 0 : continue;
805 :
806 : // then we have our search area
807 0 : if( (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
808 0 : return sal_False;
809 0 : lcl_SetAttrPam( rPam, nSttPos, &nEndPos, sal_False );
810 0 : return sal_True;
811 : }
812 :
813 0 : if( !rCmpArr.CheckStack() ||
814 0 : (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
815 0 : return sal_False;
816 0 : lcl_SetAttrPam( rPam, nSttPos, &nEndPos, sal_False );
817 0 : return sal_True;
818 : }
819 :
820 :
821 0 : static int lcl_Search( const SwCntntNode& rCNd, const SfxItemSet& rCmpSet, sal_Bool bNoColls )
822 : {
823 : // search only hard attribution?
824 0 : if( bNoColls && !rCNd.HasSwAttrSet() )
825 0 : return sal_False;
826 :
827 0 : const SfxItemSet& rNdSet = rCNd.GetSwAttrSet();
828 0 : SfxItemIter aIter( rCmpSet );
829 0 : const SfxPoolItem* pItem = aIter.GetCurItem();
830 : const SfxPoolItem* pNdItem;
831 : sal_uInt16 nWhich;
832 :
833 0 : while( sal_True )
834 : {
835 0 : if( IsInvalidItem( pItem ))
836 : {
837 0 : nWhich = rCmpSet.GetWhichByPos( aIter.GetCurPos() );
838 0 : if( SFX_ITEM_SET != rNdSet.GetItemState( nWhich, !bNoColls, &pNdItem )
839 0 : || CmpAttr( *pNdItem, rNdSet.GetPool()->GetDefaultItem( nWhich ) ))
840 0 : return sal_False;
841 : }
842 : else
843 : {
844 0 : nWhich = pItem->Which();
845 :
846 0 : if( !CmpAttr( rNdSet.Get( nWhich, !bNoColls ), *pItem ))
847 0 : return sal_False;
848 : }
849 :
850 0 : if( aIter.IsAtEnd() )
851 0 : break;
852 0 : pItem = aIter.NextItem();
853 : }
854 0 : return sal_True; // found
855 : }
856 :
857 :
858 0 : sal_Bool SwPaM::Find( const SfxPoolItem& rAttr, sal_Bool bValue, SwMoveFn fnMove,
859 : const SwPaM *pRegion, sal_Bool bInReadOnly )
860 : {
861 : // determine which attribute is searched:
862 0 : sal_uInt16 nWhich = rAttr.Which();
863 0 : int bCharAttr = isCHRATR(nWhich) || isTXTATR(nWhich);
864 :
865 0 : SwPaM* pPam = MakeRegion( fnMove, pRegion );
866 :
867 0 : sal_Bool bFound = sal_False;
868 0 : sal_Bool bFirst = sal_True;
869 0 : sal_Bool bSrchForward = fnMove == fnMoveForward;
870 : SwCntntNode * pNode;
871 : const SfxPoolItem* pItem;
872 0 : SwpFmts aFmtArr;
873 :
874 : // if at beginning/end then move it out of the node
875 0 : if( bSrchForward
876 0 : ? pPam->GetPoint()->nContent.GetIndex() == pPam->GetCntntNode()->Len()
877 0 : : !pPam->GetPoint()->nContent.GetIndex() )
878 : {
879 0 : if( !(*fnMove->fnNds)( &pPam->GetPoint()->nNode, sal_False ))
880 : {
881 0 : delete pPam;
882 0 : return sal_False;
883 : }
884 0 : SwCntntNode *pNd = pPam->GetCntntNode();
885 0 : xub_StrLen nTmpPos = bSrchForward ? 0 : pNd->Len();
886 0 : pPam->GetPoint()->nContent.Assign( pNd, nTmpPos );
887 : }
888 :
889 0 : while( 0 != ( pNode = ::GetNode( *pPam, bFirst, fnMove, bInReadOnly ) ) )
890 : {
891 0 : if( bCharAttr )
892 : {
893 0 : if( !pNode->IsTxtNode() ) // CharAttr are only in text nodes
894 0 : continue;
895 :
896 0 : if( ((SwTxtNode*)pNode)->HasHints() &&
897 0 : lcl_Search( *(SwTxtNode*)pNode, *pPam, rAttr, fnMove, bValue ))
898 : {
899 : // set to the values of the attribute
900 0 : SetMark();
901 0 : *GetPoint() = *pPam->GetPoint();
902 0 : *GetMark() = *pPam->GetMark();
903 0 : bFound = sal_True;
904 0 : break;
905 : }
906 0 : else if (isTXTATR(nWhich))
907 0 : continue;
908 : }
909 :
910 : // no hard attribution, so check if node was asked for this attr before
911 0 : if( !pNode->HasSwAttrSet() )
912 : {
913 0 : SwFmt* pTmpFmt = pNode->GetFmtColl();
914 0 : if( aFmtArr.find( pTmpFmt ) != aFmtArr.end() )
915 0 : continue; // collection was requested earlier
916 0 : aFmtArr.insert( pTmpFmt );
917 : }
918 :
919 0 : if( SFX_ITEM_SET == pNode->GetSwAttrSet().GetItemState( nWhich,
920 0 : sal_True, &pItem ) && ( !bValue || *pItem == rAttr ) )
921 : {
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 0 : *GetPoint() = *pPam->GetPoint();
926 0 : SetMark();
927 0 : pNode->MakeEndIndex( &GetPoint()->nContent );
928 0 : bFound = sal_True;
929 0 : break;
930 : }
931 : }
932 :
933 : // if backward search, switch point and mark
934 0 : if( bFound && !bSrchForward )
935 0 : Exchange();
936 :
937 0 : delete pPam;
938 0 : return bFound;
939 : }
940 :
941 :
942 : typedef int (*FnSearchAttr)( const SwTxtNode&, SwAttrCheckArr&, SwPaM& );
943 :
944 0 : sal_Bool SwPaM::Find( const SfxItemSet& rSet, sal_Bool bNoColls, SwMoveFn fnMove,
945 : const SwPaM *pRegion, sal_Bool bInReadOnly, sal_Bool bMoveFirst )
946 : {
947 0 : SwPaM* pPam = MakeRegion( fnMove, pRegion );
948 :
949 0 : sal_Bool bFound = sal_False;
950 0 : sal_Bool bFirst = sal_True;
951 0 : sal_Bool bSrchForward = fnMove == fnMoveForward;
952 : SwCntntNode * pNode;
953 0 : SwpFmts aFmtArr;
954 :
955 : // check which text/char attributes are searched
956 0 : SwAttrCheckArr aCmpArr( rSet, bSrchForward, bNoColls );
957 0 : SfxItemSet aOtherSet( GetDoc()->GetAttrPool(),
958 0 : RES_PARATR_BEGIN, RES_GRFATR_END-1 );
959 0 : aOtherSet.Put( rSet, sal_False ); // got all invalid items
960 :
961 : FnSearchAttr fnSearch = bSrchForward
962 : ? (&::lcl_SearchForward)
963 0 : : (&::lcl_SearchBackward);
964 :
965 : // if at beginning/end then move it out of the node
966 0 : if( bMoveFirst &&
967 : ( bSrchForward
968 0 : ? pPam->GetPoint()->nContent.GetIndex() == pPam->GetCntntNode()->Len()
969 0 : : !pPam->GetPoint()->nContent.GetIndex() ) )
970 : {
971 0 : if( !(*fnMove->fnNds)( &pPam->GetPoint()->nNode, sal_False ))
972 : {
973 0 : delete pPam;
974 0 : return sal_False;
975 : }
976 0 : SwCntntNode *pNd = pPam->GetCntntNode();
977 0 : xub_StrLen nTmpPos = bSrchForward ? 0 : pNd->Len();
978 0 : pPam->GetPoint()->nContent.Assign( pNd, nTmpPos );
979 : }
980 :
981 :
982 0 : while( 0 != ( pNode = ::GetNode( *pPam, bFirst, fnMove, bInReadOnly ) ) )
983 : {
984 0 : if( aCmpArr.Count() )
985 : {
986 0 : if( !pNode->IsTxtNode() ) // CharAttr are only in text nodes
987 0 : continue;
988 :
989 0 : if( (!aOtherSet.Count() ||
990 0 : lcl_Search( *pNode, aOtherSet, bNoColls )) &&
991 0 : (*fnSearch)( *(SwTxtNode*)pNode, aCmpArr, *pPam ))
992 : {
993 : // set to the values of the attribute
994 0 : SetMark();
995 0 : *GetPoint() = *pPam->GetPoint();
996 0 : *GetMark() = *pPam->GetMark();
997 0 : bFound = sal_True;
998 0 : break;
999 : }
1000 0 : continue; // text attribute
1001 : }
1002 :
1003 0 : if( !aOtherSet.Count() )
1004 0 : continue;
1005 :
1006 : // no hard attribution, so check if node was asked for this attr before
1007 0 : if( !pNode->HasSwAttrSet() )
1008 : {
1009 0 : SwFmt* pTmpFmt = pNode->GetFmtColl();
1010 0 : if( aFmtArr.find( pTmpFmt ) != aFmtArr.end() )
1011 0 : continue; // collection was requested earlier
1012 0 : aFmtArr.insert( pTmpFmt );
1013 : }
1014 :
1015 0 : if( lcl_Search( *pNode, aOtherSet, bNoColls ))
1016 : {
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 0 : *GetPoint() = *pPam->GetPoint();
1021 0 : SetMark();
1022 0 : pNode->MakeEndIndex( &GetPoint()->nContent );
1023 0 : bFound = sal_True;
1024 0 : break;
1025 : }
1026 : }
1027 :
1028 : // if backward search, switch point and mark
1029 0 : if( bFound && !bSrchForward )
1030 0 : Exchange();
1031 :
1032 0 : delete pPam;
1033 0 : return bFound;
1034 : }
1035 :
1036 : /// parameters for search for attributes
1037 : struct SwFindParaAttr : public SwFindParas
1038 : {
1039 : sal_Bool bValue;
1040 : const SfxItemSet *pSet, *pReplSet;
1041 : const SearchOptions *pSearchOpt;
1042 : SwCursor& rCursor;
1043 : utl::TextSearch* pSTxt;
1044 :
1045 0 : SwFindParaAttr( const SfxItemSet& rSet, sal_Bool bNoCollection,
1046 : const SearchOptions* pOpt, const SfxItemSet* pRSet,
1047 : SwCursor& rCrsr )
1048 : : bValue( bNoCollection ), pSet( &rSet ), pReplSet( pRSet ),
1049 0 : pSearchOpt( pOpt ), rCursor( rCrsr ),pSTxt( 0 ) {}
1050 :
1051 0 : virtual ~SwFindParaAttr() { delete pSTxt; }
1052 :
1053 : virtual int Find( SwPaM* , SwMoveFn , const SwPaM*, sal_Bool bInReadOnly );
1054 : virtual int IsReplaceMode() const;
1055 : };
1056 :
1057 :
1058 0 : int SwFindParaAttr::Find( SwPaM* pCrsr, SwMoveFn fnMove, const SwPaM* pRegion,
1059 : sal_Bool bInReadOnly )
1060 : {
1061 : // replace string (only if text given and search is not parameterized)?
1062 0 : sal_Bool bReplaceTxt = pSearchOpt && ( !pSearchOpt->replaceString.isEmpty() ||
1063 0 : !pSet->Count() );
1064 0 : sal_Bool bReplaceAttr = pReplSet && pReplSet->Count();
1065 0 : sal_Bool bMoveFirst = !bReplaceAttr;
1066 0 : if( bInReadOnly && (bReplaceAttr || bReplaceTxt ))
1067 0 : bInReadOnly = sal_False;
1068 :
1069 : // We search for attributes, should we search for text as well?
1070 : {
1071 0 : SwPaM aRegion( *pRegion->GetMark(), *pRegion->GetPoint() );
1072 0 : SwPaM* pTextRegion = &aRegion;
1073 0 : SwPaM aSrchPam( *pCrsr->GetPoint() );
1074 :
1075 0 : while( sal_True )
1076 : {
1077 0 : if( pSet->Count() ) // any attributes?
1078 : {
1079 : // first attributes
1080 0 : if( !aSrchPam.Find( *pSet, bValue, fnMove, &aRegion, bInReadOnly, bMoveFirst ) )
1081 0 : return FIND_NOT_FOUND;
1082 0 : bMoveFirst = sal_True;
1083 :
1084 0 : if( !pSearchOpt )
1085 0 : break; // ok, only attributes, so found
1086 :
1087 0 : pTextRegion = &aSrchPam;
1088 : }
1089 0 : else if( !pSearchOpt )
1090 0 : return FIND_NOT_FOUND;
1091 :
1092 : // then search in text of it
1093 0 : if( !pSTxt )
1094 : {
1095 0 : SearchOptions aTmp( *pSearchOpt );
1096 :
1097 : // search in selection
1098 : aTmp.searchFlag |= (SearchFlags::REG_NOT_BEGINOFLINE |
1099 0 : SearchFlags::REG_NOT_ENDOFLINE);
1100 :
1101 0 : aTmp.Locale = SvtSysLocale().GetLanguageTag().getLocale();
1102 :
1103 0 : pSTxt = new utl::TextSearch( aTmp );
1104 : }
1105 :
1106 : // TODO: searching for attributes in Outliner text?!
1107 0 : sal_Bool bSearchInNotes = sal_False;
1108 :
1109 : // continue search in correct section (pTextRegion)
1110 0 : if( aSrchPam.Find( *pSearchOpt, bSearchInNotes, *pSTxt, fnMove, pTextRegion, bInReadOnly ) &&
1111 0 : *aSrchPam.GetMark() != *aSrchPam.GetPoint() )
1112 0 : break; // found
1113 0 : else if( !pSet->Count() )
1114 0 : return FIND_NOT_FOUND; // only text and nothing found
1115 :
1116 0 : *aRegion.GetMark() = *aSrchPam.GetPoint();
1117 : }
1118 :
1119 0 : *pCrsr->GetPoint() = *aSrchPam.GetPoint();
1120 0 : pCrsr->SetMark();
1121 0 : *pCrsr->GetMark() = *aSrchPam.GetMark();
1122 : }
1123 :
1124 0 : if( bReplaceTxt )
1125 : {
1126 : const bool bRegExp(
1127 0 : SearchAlgorithms_REGEXP == pSearchOpt->algorithmType);
1128 0 : SwIndex& rSttCntIdx = pCrsr->Start()->nContent;
1129 0 : xub_StrLen nSttCnt = rSttCntIdx.GetIndex();
1130 :
1131 : // add to shell-cursor-ring so that the regions will be moved enventually
1132 0 : Ring *pPrevRing = 0;
1133 0 : if( bRegExp )
1134 : {
1135 0 : pPrevRing = pRegion->GetPrev();
1136 0 : ((Ring*)pRegion)->MoveRingTo( &rCursor );
1137 : }
1138 :
1139 : ::std::auto_ptr<String> pRepl( (bRegExp) ?
1140 0 : ReplaceBackReferences( *pSearchOpt, pCrsr ) : 0 );
1141 0 : rCursor.GetDoc()->ReplaceRange( *pCrsr,
1142 0 : (pRepl.get()) ? *pRepl : String(pSearchOpt->replaceString),
1143 0 : bRegExp );
1144 0 : rCursor.SaveTblBoxCntnt( pCrsr->GetPoint() );
1145 :
1146 0 : if( bRegExp )
1147 : {
1148 : // and remove region again
1149 0 : Ring *p, *pNext = (Ring*)pRegion;
1150 0 : do {
1151 0 : p = pNext;
1152 0 : pNext = p->GetNext();
1153 0 : p->MoveTo( (Ring*)pRegion );
1154 : } while( p != pPrevRing );
1155 : }
1156 0 : rSttCntIdx = nSttCnt;
1157 : }
1158 :
1159 0 : if( bReplaceAttr )
1160 : {
1161 : // is the selection still existent?
1162 : // all searched attributes are reset to default if
1163 : // they are not in ReplaceSet
1164 0 : if( !pSet->Count() )
1165 : {
1166 0 : pCrsr->GetDoc()->InsertItemSet( *pCrsr, *pReplSet, 0 );
1167 : }
1168 : else
1169 : {
1170 0 : SfxItemPool* pPool = pReplSet->GetPool();
1171 0 : SfxItemSet aSet( *pPool, pReplSet->GetRanges() );
1172 :
1173 0 : SfxItemIter aIter( *pSet );
1174 0 : const SfxPoolItem* pItem = aIter.GetCurItem();
1175 0 : while( sal_True )
1176 : {
1177 : // reset all that are not set with pool defaults
1178 0 : if( !IsInvalidItem( pItem ) && SFX_ITEM_SET !=
1179 0 : pReplSet->GetItemState( pItem->Which(), sal_False ))
1180 0 : aSet.Put( pPool->GetDefaultItem( pItem->Which() ));
1181 :
1182 0 : if( aIter.IsAtEnd() )
1183 0 : break;
1184 0 : pItem = aIter.NextItem();
1185 : }
1186 0 : aSet.Put( *pReplSet );
1187 0 : pCrsr->GetDoc()->InsertItemSet( *pCrsr, aSet, 0 );
1188 : }
1189 :
1190 0 : return FIND_NO_RING;
1191 : }
1192 :
1193 : else
1194 0 : return FIND_FOUND;
1195 : }
1196 :
1197 :
1198 0 : int SwFindParaAttr::IsReplaceMode() const
1199 : {
1200 0 : return ( pSearchOpt && !pSearchOpt->replaceString.isEmpty() ) ||
1201 0 : ( pReplSet && pReplSet->Count() );
1202 : }
1203 :
1204 : /// search for attributes
1205 0 : 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 )
1210 : {
1211 : // switch off OLE-notifications
1212 0 : SwDoc* pDoc = GetDoc();
1213 0 : Link aLnk( pDoc->GetOle2Link() );
1214 0 : pDoc->SetOle2Link( Link() );
1215 :
1216 0 : sal_Bool bReplace = ( pSearchOpt && ( !pSearchOpt->replaceString.isEmpty() ||
1217 0 : !rSet.Count() ) ) ||
1218 0 : (pReplSet && pReplSet->Count());
1219 0 : bool const bStartUndo = pDoc->GetIDocumentUndoRedo().DoesUndo() && bReplace;
1220 0 : if (bStartUndo)
1221 : {
1222 0 : pDoc->GetIDocumentUndoRedo().StartUndo( UNDO_REPLACE, NULL );
1223 : }
1224 :
1225 : SwFindParaAttr aSwFindParaAttr( rSet, bNoCollections, pSearchOpt,
1226 0 : pReplSet, *this );
1227 :
1228 0 : sal_uLong nRet = FindAll( aSwFindParaAttr, nStart, nEnd, eFndRngs, bCancel );
1229 0 : pDoc->SetOle2Link( aLnk );
1230 0 : if( nRet && bReplace )
1231 0 : pDoc->SetModified();
1232 :
1233 0 : if (bStartUndo)
1234 : {
1235 0 : pDoc->GetIDocumentUndoRedo().EndUndo( UNDO_REPLACE, NULL );
1236 : }
1237 :
1238 0 : return nRet;
1239 : }
1240 :
1241 :
1242 :
1243 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|