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