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